diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 0b2b55ae74..47961a04e4 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -1541,6 +1541,27 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load return module; } +SceUID KernelLoadModule(const std::string &filename, std::string *error_string) { + PSPFileInfo info = pspFileSystem.GetFileInfo(filename); + if (!info.exists) + return SCE_KERNEL_ERROR_NOFILE; + + std::vector buffer; + buffer.resize((size_t)info.size); + + u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ); + pspFileSystem.ReadFile(handle, &buffer[0], info.size); + pspFileSystem.CloseFile(handle); + + u32 error = SCE_KERNEL_ERROR_ILLEGAL_OBJECT; + u32 magic; + PSPModule *module = __KernelLoadELFFromPtr(&buffer[0], buffer.size(), 0, false, error_string, &magic, error); + + if (module == nullptr) + return error; + return module->GetUID(); +} + static PSPModule *__KernelLoadModule(u8 *fileptr, size_t fileSize, SceKernelLMOption *options, std::string *error_string) { PSPModule *module = nullptr; // Check for PBP @@ -1960,12 +1981,71 @@ static u32 sceKernelLoadModuleNpDrm(const char *name, u32 flags, u32 optionAddr) return sceKernelLoadModule(name, flags, optionAddr); } +int KernelStartModule(SceUID moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, SceKernelSMOption *smoption, bool *needsWait) { + if (needsWait) { + *needsWait = false; + } + + u32 error; + PSPModule *module = kernelObjects.Get(moduleId, error); + if (!module) { + return error; + } + + u32 priority = 0x20; + u32 stacksize = 0x40000; + int attribute = module->nm.attribute; + u32 entryAddr = module->nm.entry_addr; + + if (module->nm.module_start_func != 0 && module->nm.module_start_func != (u32)-1) { + entryAddr = module->nm.module_start_func; + if (module->nm.module_start_thread_attr != 0) + attribute = module->nm.module_start_thread_attr; + } else if (entryAddr == (u32)-1 || entryAddr == module->memoryBlockAddr - 1) { + if (smoption) { + // TODO: Does sceKernelStartModule() really give an error when no entry only if you pass options? + attribute = smoption->attribute; + } else { + // TODO: Why are we just returning the module ID in this case? + WARN_LOG(SCEMODULE, "sceKernelStartModule(): module has no start or entry func"); + module->nm.status = MODULE_STATUS_STARTED; + return moduleId; + } + } + + if (Memory::IsValidAddress(entryAddr)) { + if (smoption && smoption->priority > 0) { + priority = smoption->priority; + } else if (module->nm.module_start_thread_priority > 0) { + priority = module->nm.module_start_thread_priority; + } + + if (smoption && smoption->stacksize > 0) { + stacksize = smoption->stacksize; + } else if (module->nm.module_start_thread_stacksize > 0) { + stacksize = module->nm.module_start_thread_stacksize; + } + + SceUID threadID = __KernelCreateThread(module->nm.name, moduleId, entryAddr, priority, stacksize, attribute, 0, (module->nm.attribute & 0x1000) != 0); + __KernelStartThreadValidate(threadID, argsize, argAddr); + __KernelSetThreadRA(threadID, NID_MODULERETURN); + + if (needsWait) { + *needsWait = true; + } + } else if (entryAddr == 0) { + INFO_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x): no entry address", moduleId, argsize, argAddr, returnValueAddr); + module->nm.status = MODULE_STATUS_STARTED; + } else { + ERROR_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x): invalid entry address", moduleId, argsize, argAddr, returnValueAddr); + return -1; + } + + return moduleId; +} + static void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, u32 optionAddr) { - u32 priority = 0x20; - u32 stacksize = 0x40000; - u32 attr = 0; - int stackPartition = 0; SceKernelSMOption smoption = {0}; if (optionAddr) { Memory::ReadStruct(optionAddr, &smoption); @@ -1994,71 +2074,19 @@ static void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 ret INFO_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)", moduleId,argsize,argAddr,returnValueAddr,optionAddr); - int attribute = module->nm.attribute; - u32 entryAddr = module->nm.entry_addr; + bool needsWait; + int ret = KernelStartModule(moduleId, argsize, argAddr, returnValueAddr, optionAddr ? &smoption : nullptr, &needsWait); - if (module->nm.module_start_func != 0 && module->nm.module_start_func != (u32)-1) - { - entryAddr = module->nm.module_start_func; - if (module->nm.module_start_thread_attr != 0) - attribute = module->nm.module_start_thread_attr; - } - else if ((entryAddr == (u32)-1) || entryAddr == module->memoryBlockAddr - 1) - { - if (optionAddr) - { - // TODO: Does sceKernelStartModule() really give an error when no entry only if you pass options? - attribute = smoption.attribute; - } - else - { - // TODO: Why are we just returning the module ID in this case? - WARN_LOG(SCEMODULE, "sceKernelStartModule(): module has no start or entry func"); - module->nm.status = MODULE_STATUS_STARTED; - RETURN(moduleId); - return; - } - } - - if (Memory::IsValidAddress(entryAddr)) - { - if ((optionAddr) && smoption.priority > 0) { - priority = smoption.priority; - } else if (module->nm.module_start_thread_priority > 0) { - priority = module->nm.module_start_thread_priority; - } - - if ((optionAddr) && (smoption.stacksize > 0)) { - stacksize = smoption.stacksize; - } else if (module->nm.module_start_thread_stacksize > 0) { - stacksize = module->nm.module_start_thread_stacksize; - } - - SceUID threadID = __KernelCreateThread(module->nm.name, moduleId, entryAddr, priority, stacksize, attribute, 0, (module->nm.attribute & 0x1000) != 0); - __KernelStartThreadValidate(threadID, argsize, argAddr); - __KernelSetThreadRA(threadID, NID_MODULERETURN); + if (needsWait) { __KernelWaitCurThread(WAITTYPE_MODULE, moduleId, 1, 0, false, "started module"); const ModuleWaitingThread mwt = {__KernelGetCurThread(), returnValueAddr}; module->nm.status = MODULE_STATUS_STARTING; module->waitingThreads.push_back(mwt); } - else if (entryAddr == 0) - { - INFO_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): no entry address", - moduleId,argsize,argAddr,returnValueAddr,optionAddr); - module->nm.status = MODULE_STATUS_STARTED; - } - else - { - ERROR_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): invalid entry address", - moduleId,argsize,argAddr,returnValueAddr,optionAddr); - RETURN(-1); - return; - } - } - RETURN(moduleId); + RETURN(ret); + } } static u32 sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 returnValueAddr, u32 optionAddr) diff --git a/Core/HLE/sceKernelModule.h b/Core/HLE/sceKernelModule.h index 99e5473b05..a227153477 100644 --- a/Core/HLE/sceKernelModule.h +++ b/Core/HLE/sceKernelModule.h @@ -33,6 +33,7 @@ struct PspModuleInfo { }; class PointerWrap; +struct SceKernelSMOption; KernelObject *__KernelModuleObject(); void __KernelModuleDoState(PointerWrap &p); @@ -44,6 +45,8 @@ bool __KernelLoadGEDump(const std::string &base_filename, std::string *error_str bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string); void __KernelGPUReplay(); void __KernelReturnFromModuleFunc(); +SceUID KernelLoadModule(const std::string &filename, std::string *error_string); +int KernelStartModule(SceUID moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, SceKernelSMOption *smoption, bool *needsWait); u32 hleKernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, u32 argp, u32 statusAddr, u32 optionAddr, bool WithStatus); u32 sceKernelFindModuleByUID(u32 uid);