diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 1d37b3c80278..431870fc4566 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -66,7 +66,8 @@ #include "GPU/GPUState.h" enum { - PSP_THREAD_ATTR_USER = 0x80000000 + PSP_THREAD_ATTR_KERNEL = 0x00001000, + PSP_THREAD_ATTR_USER = 0x80000000, }; enum { @@ -1608,6 +1609,16 @@ u32 __KernelGetModuleGP(SceUID uid) { } } +bool KernelModuleIsKernelMode(SceUID uid) { + u32 error; + PSPModule *module = kernelObjects.Get(uid, error); + if (module) { + return (module->nm.attribute & 0x1000) != 0; + } else { + return false; + } +} + void __KernelLoadReset() { // Wipe kernel here, loadexec should reset the entire system if (__KernelIsRunning()) { diff --git a/Core/HLE/sceKernelModule.h b/Core/HLE/sceKernelModule.h index 232c71d23f11..e6fabd9829d3 100644 --- a/Core/HLE/sceKernelModule.h +++ b/Core/HLE/sceKernelModule.h @@ -39,6 +39,7 @@ void __KernelModuleDoState(PointerWrap &p); void __KernelModuleShutdown(); u32 __KernelGetModuleGP(SceUID module); +bool KernelModuleIsKernelMode(SceUID module); bool __KernelLoadGEDump(const std::string &base_filename, std::string *error_string); bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string); void __KernelGPUReplay(); diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 698b80c44b12..a1518f248e0c 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -1959,9 +1959,13 @@ int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 // Some are USB/VSH specific, probably removes when they are from the wrong module? attr &= ~PSP_THREAD_ATTR_USER_ERASE; - // We're assuming all threads created are user threads. - if ((attr & PSP_THREAD_ATTR_KERNEL) == 0) - attr |= PSP_THREAD_ATTR_USER; + if ((attr & PSP_THREAD_ATTR_KERNEL) == 0) { + if (allowKernel && (attr & PSP_THREAD_ATTR_USER) == 0) { + attr |= PSP_THREAD_ATTR_KERNEL; + } else { + attr |= PSP_THREAD_ATTR_USER; + } + } SceUID id = __KernelCreateThreadInternal(threadName, moduleID, entry, prio, stacksize, attr); if ((u32)id == SCE_KERNEL_ERROR_NO_MEMORY) @@ -1986,8 +1990,9 @@ int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr) { PSPThread *cur = __GetCurrentThread(); - bool allowKernel = cur ? (cur->nt.attr & PSP_THREAD_ATTR_KERNEL) != 0 : false; - return __KernelCreateThread(threadName, __KernelGetCurThreadModuleId(), entry, prio, stacksize, attr, optionAddr, allowKernel); + SceUID module = __KernelGetCurThreadModuleId(); + bool allowKernel = KernelModuleIsKernelMode(module) || hleIsKernelMode() || (cur ? (cur->nt.attr & PSP_THREAD_ATTR_KERNEL) != 0 : false); + return __KernelCreateThread(threadName, module, entry, prio, stacksize, attr, optionAddr, allowKernel); } int __KernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr, bool forceArgs) {