mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-24 05:49:58 +00:00
Merge pull request #1935 from unknownbrackets/modules
Get sceKernelStopModule() sorta working
This commit is contained in:
commit
315559afe6
@ -79,6 +79,7 @@ const HLEFunction FakeSysCalls[] = {
|
||||
{NID_CALLBACKRETURN, __KernelReturnFromMipsCall, "__KernelReturnFromMipsCall"},
|
||||
{NID_INTERRUPTRETURN, __KernelReturnFromInterrupt, "__KernelReturnFromInterrupt"},
|
||||
{NID_EXTENDRETURN, __KernelReturnFromExtendStack, "__KernelReturnFromExtendStack"},
|
||||
{NID_MODULERETURN, __KernelReturnFromModuleFunc, "__KernelReturnFromModuleFunc"},
|
||||
{NID_IDLE, __KernelIdle, "_sceKernelIdle"},
|
||||
};
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#define NID_CALLBACKRETURN 0xbadc0fee
|
||||
#define NID_INTERRUPTRETURN 0xbadd00d5
|
||||
#define NID_EXTENDRETURN 0xbad0b0c9
|
||||
#define NID_MODULERETURN 0xbad0d318
|
||||
#define NID_IDLE 0x1d7e1d7e
|
||||
|
||||
void RegisterAllModules();
|
@ -687,7 +687,7 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0x809ce29b,WrapV_I<sceKernelExitDeleteThread>,"sceKernelExitDeleteThread"},
|
||||
{0x94aa61ee,sceKernelGetThreadCurrentPriority,"sceKernelGetThreadCurrentPriority"},
|
||||
{0x293b45b8,WrapI_V<sceKernelGetThreadId>,"sceKernelGetThreadId"},
|
||||
{0x3B183E26,sceKernelGetThreadExitStatus,"sceKernelGetThreadExitStatus"},
|
||||
{0x3B183E26,WrapI_I<sceKernelGetThreadExitStatus>,"sceKernelGetThreadExitStatus"},
|
||||
{0x52089CA1,sceKernelGetThreadStackFreeSize,"sceKernelGetThreadStackFreeSize"},
|
||||
{0xFFC36A14,WrapU_UU<sceKernelReferThreadRunStatus>,"sceKernelReferThreadRunStatus"},
|
||||
{0x17c1684e,WrapU_UU<sceKernelReferThreadStatus>,"sceKernelReferThreadStatus"},
|
||||
|
@ -19,7 +19,8 @@
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "HLE.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HLE/HLETables.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "../Host.h"
|
||||
@ -161,11 +162,16 @@ struct ModuleInfo {
|
||||
char name[28];
|
||||
};
|
||||
|
||||
struct ModuleWaitingThread
|
||||
{
|
||||
SceUID threadID;
|
||||
u32 statusPtr;
|
||||
};
|
||||
|
||||
class Module : public KernelObject
|
||||
{
|
||||
public:
|
||||
Module() : memoryBlockAddr(0), isFake(false) {}
|
||||
Module() : memoryBlockAddr(0), isFake(false), isStarted(false) {}
|
||||
~Module() {
|
||||
if (memoryBlockAddr) {
|
||||
userMemory.Free(memoryBlockAddr);
|
||||
@ -190,14 +196,21 @@ public:
|
||||
p.Do(nm);
|
||||
p.Do(memoryBlockAddr);
|
||||
p.Do(memoryBlockSize);
|
||||
p.Do(isFake);
|
||||
p.Do(isStarted);
|
||||
ModuleWaitingThread mwt = {0};
|
||||
p.Do(waitingThreads, mwt);
|
||||
p.DoMarker("Module");
|
||||
}
|
||||
|
||||
NativeModule nm;
|
||||
std::vector<ModuleWaitingThread> waitingThreads;
|
||||
|
||||
u32 memoryBlockAddr;
|
||||
u32 memoryBlockSize;
|
||||
bool isFake;
|
||||
// Probably one of the NativeModule fields, but not sure...
|
||||
bool isStarted;
|
||||
};
|
||||
|
||||
KernelObject *__KernelModuleObject()
|
||||
@ -863,14 +876,15 @@ Module *__KernelLoadModule(u8 *fileptr, SceKernelLMOption *options, std::string
|
||||
|
||||
void __KernelStartModule(Module *m, int args, const char *argp, SceKernelSMOption *options)
|
||||
{
|
||||
m->isStarted = true;
|
||||
if (m->nm.module_start_func != 0 && m->nm.module_start_func != (u32)-1)
|
||||
{
|
||||
if (m->nm.module_start_func != m->nm.entry_addr)
|
||||
WARN_LOG_REPORT(LOADER, "Main module has start func (%08x) different from entry (%08x)?", m->nm.module_start_func, m->nm.entry_addr);
|
||||
}
|
||||
|
||||
__KernelSetupRootThread(m->GetUID(), args, argp, options->priority, options->stacksize, options->attribute);
|
||||
//TODO: if current thread, put it in wait state, waiting for the new thread
|
||||
SceUID threadID = __KernelSetupRootThread(m->GetUID(), args, argp, options->priority, options->stacksize, options->attribute);
|
||||
__KernelSetThreadRA(threadID, NID_MODULERETURN);
|
||||
}
|
||||
|
||||
|
||||
@ -1053,7 +1067,7 @@ void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValu
|
||||
int stackPartition = 0;
|
||||
SceKernelSMOption smoption;
|
||||
if (optionAddr) {
|
||||
Memory::ReadStruct(optionAddr, &smoption);;
|
||||
Memory::ReadStruct(optionAddr, &smoption);
|
||||
}
|
||||
u32 error;
|
||||
Module *module = kernelObjects.Get<Module>(moduleId, error);
|
||||
@ -1063,8 +1077,17 @@ void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValu
|
||||
} else if (module->isFake) {
|
||||
INFO_LOG(HLE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): faked (undecryptable module)",
|
||||
moduleId,argsize,argAddr,returnValueAddr,optionAddr);
|
||||
if (returnValueAddr)
|
||||
Memory::Write_U32(0, returnValueAddr);
|
||||
RETURN(moduleId);
|
||||
return;
|
||||
} else if (module->isStarted) {
|
||||
ERROR_LOG(HLE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x) : already started",
|
||||
moduleId,argsize,argAddr,returnValueAddr,optionAddr);
|
||||
// TODO: Maybe should be SCE_KERNEL_ERROR_ALREADY_STARTED, but I get SCE_KERNEL_ERROR_ERROR.
|
||||
// But I also get crashes...
|
||||
RETURN(SCE_KERNEL_ERROR_ERROR);
|
||||
return;
|
||||
} else {
|
||||
INFO_LOG(HLE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)",
|
||||
moduleId,argsize,argAddr,returnValueAddr,optionAddr);
|
||||
@ -1085,7 +1108,8 @@ void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValu
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Fix, check return value? Or do we call nothing?
|
||||
// TODO: Why are we just returning the module ID in this case?
|
||||
ERROR_LOG_REPORT(HLE, "sceKernelStartModule(): doing nothing for some reason?");
|
||||
RETURN(moduleId);
|
||||
return;
|
||||
}
|
||||
@ -1106,39 +1130,104 @@ void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValu
|
||||
}
|
||||
|
||||
SceUID threadID = __KernelCreateThread(module->nm.name, moduleId, entryAddr, priority, stacksize, attribute, 0);
|
||||
|
||||
sceKernelStartThread(threadID, argsize, argAddr);
|
||||
// TODO: This will probably return the wrong value?
|
||||
sceKernelWaitThreadEnd(threadID, 0);
|
||||
__KernelSetThreadRA(threadID, NID_MODULERETURN);
|
||||
__KernelWaitCurThread(WAITTYPE_MODULE, moduleId, 1, 0, false, "started module");
|
||||
|
||||
const ModuleWaitingThread mwt = {__KernelGetCurThread(), returnValueAddr};
|
||||
module->waitingThreads.push_back(mwt);
|
||||
}
|
||||
else if (entryAddr == 0)
|
||||
{
|
||||
INFO_LOG(HLE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)",
|
||||
INFO_LOG(HLE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): no entry address",
|
||||
moduleId,argsize,argAddr,returnValueAddr,optionAddr);
|
||||
WARN_LOG(HLE, "No Entry Address");
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)",
|
||||
ERROR_LOG(HLE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): invalid entry address",
|
||||
moduleId,argsize,argAddr,returnValueAddr,optionAddr);
|
||||
ERROR_LOG(HLE, "Invalid Entry Address");
|
||||
RETURN(-1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Is this the correct return value?
|
||||
// JPCSP returns this value as well.
|
||||
RETURN(moduleId);
|
||||
}
|
||||
|
||||
u32 sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 returnValueAddr, u32 optionAddr)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelStopModule(%08x, %08x, %08x, %08x, %08x)", moduleId, argSize, argAddr, returnValueAddr, optionAddr);
|
||||
u32 priority = 0x20;
|
||||
u32 stacksize = 0x40000;
|
||||
u32 attr = 0;
|
||||
|
||||
// TODO: In a lot of cases (even for errors), this should resched. Needs testing.
|
||||
|
||||
u32 error;
|
||||
Module *module = kernelObjects.Get<Module>(moduleId, error);
|
||||
if (!module)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): invalid module id", moduleId, argSize, argAddr, returnValueAddr, optionAddr);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (module->isFake)
|
||||
{
|
||||
INFO_LOG(HLE, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x) - faking", moduleId, argSize, argAddr, returnValueAddr, optionAddr);
|
||||
if (returnValueAddr)
|
||||
Memory::Write_U32(0, returnValueAddr);
|
||||
return 0;
|
||||
}
|
||||
if (!module->isStarted)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): already stopped", moduleId, argSize, argAddr, returnValueAddr, optionAddr);
|
||||
return SCE_KERNEL_ERROR_ALREADY_STOPPED;
|
||||
}
|
||||
|
||||
u32 stopFunc = module->nm.module_stop_func;
|
||||
if (module->nm.module_stop_thread_priority != 0)
|
||||
priority = module->nm.module_stop_thread_priority;
|
||||
if (module->nm.module_stop_thread_stacksize != 0)
|
||||
stacksize = module->nm.module_stop_thread_stacksize;
|
||||
if (module->nm.module_stop_thread_attr != 0)
|
||||
attr = module->nm.module_stop_thread_attr;
|
||||
|
||||
// TODO: Need to test how this really works. Let's assume it's an override.
|
||||
if (Memory::IsValidAddress(optionAddr))
|
||||
{
|
||||
auto options = Memory::GetStruct<SceKernelSMOption>(optionAddr);
|
||||
// TODO: Check how size handling actually works.
|
||||
if (options->size != 0 && options->priority != 0)
|
||||
priority = options->priority;
|
||||
if (options->size != 0 && options->stacksize != 0)
|
||||
stacksize = options->stacksize;
|
||||
if (options->size != 0 && options->attribute != 0)
|
||||
attr = options->attribute;
|
||||
// TODO: Maybe based on size?
|
||||
else if (attr != 0)
|
||||
WARN_LOG_REPORT(HLE, "Stopping module with attr=%x, but options specify 0", attr);
|
||||
}
|
||||
|
||||
if (Memory::IsValidAddress(stopFunc))
|
||||
{
|
||||
SceUID threadID = __KernelCreateThread(module->nm.name, moduleId, stopFunc, priority, stacksize, attr, 0);
|
||||
sceKernelStartThread(threadID, argSize, argAddr);
|
||||
__KernelSetThreadRA(threadID, NID_MODULERETURN);
|
||||
__KernelWaitCurThread(WAITTYPE_MODULE, moduleId, 1, 0, false, "stopped module");
|
||||
|
||||
const ModuleWaitingThread mwt = {__KernelGetCurThread(), returnValueAddr};
|
||||
module->waitingThreads.push_back(mwt);
|
||||
}
|
||||
else if (stopFunc == 0)
|
||||
{
|
||||
INFO_LOG(HLE, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): no stop func, skipping", moduleId, argSize, argAddr, returnValueAddr, optionAddr);
|
||||
module->isStarted = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG_REPORT(HLE, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): bad stop func address", moduleId, argSize, argAddr, returnValueAddr, optionAddr);
|
||||
module->isStarted = false;
|
||||
}
|
||||
|
||||
// We should call the "stop" entry point and return the value in returnValueAddr. See StartModule.
|
||||
// Possibly also kill all its threads?
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1162,6 +1251,43 @@ u32 sceKernelStopUnloadSelfModuleWithStatus(u32 exitCode, u32 argSize, u32 argp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __KernelReturnFromModuleFunc()
|
||||
{
|
||||
// Return from the thread as normal.
|
||||
__KernelReturnFromThread();
|
||||
|
||||
SceUID leftModuleID = __KernelGetCurThreadModuleId();
|
||||
SceUID leftThreadID = __KernelGetCurThread();
|
||||
int exitStatus = sceKernelGetThreadExitStatus(leftThreadID);
|
||||
|
||||
// Reschedule immediately (to leave the thread) and delete it and its stack.
|
||||
__KernelReSchedule("returned from module");
|
||||
sceKernelDeleteThread(leftThreadID);
|
||||
|
||||
u32 error;
|
||||
Module *module = kernelObjects.Get<Module>(leftModuleID, error);
|
||||
if (!module)
|
||||
{
|
||||
ERROR_LOG_REPORT(HLE, "Returned from deleted module start/stop func");
|
||||
return;
|
||||
}
|
||||
|
||||
// We can't be starting and stopping at the same time, so no need to differentiate.
|
||||
module->isStarted = !module->isStarted;
|
||||
for (auto it = module->waitingThreads.begin(), end = module->waitingThreads.end(); it < end; ++it)
|
||||
{
|
||||
// Still waiting?
|
||||
SceUID waitingModuleID = __KernelGetWaitID(it->threadID, WAITTYPE_MODULE, error);
|
||||
if (waitingModuleID == leftModuleID)
|
||||
{
|
||||
if (it->statusPtr != 0)
|
||||
Memory::Write_U32(exitStatus, it->statusPtr);
|
||||
__KernelResumeThreadFromWait(it->threadID, 0);
|
||||
}
|
||||
}
|
||||
module->waitingThreads.clear();
|
||||
}
|
||||
|
||||
struct GetModuleIdByAddressArg
|
||||
{
|
||||
u32 addr;
|
||||
|
@ -26,5 +26,6 @@ void __KernelModuleShutdown();
|
||||
|
||||
u32 __KernelGetModuleGP(SceUID module);
|
||||
bool __KernelLoadExec(const char *filename, SceKernelLoadExecParam *param, std::string *error_string);
|
||||
void __KernelReturnFromModuleFunc();
|
||||
|
||||
void Register_ModuleMgrForUser();
|
||||
|
@ -746,6 +746,7 @@ u32 threadReturnHackAddr;
|
||||
u32 cbReturnHackAddr;
|
||||
u32 intReturnHackAddr;
|
||||
u32 extendReturnHackAddr;
|
||||
u32 moduleReturnHackAddr;
|
||||
std::vector<ThreadCallback> threadEndListeners;
|
||||
|
||||
// Lists all thread ids that aren't deleted/etc.
|
||||
@ -844,18 +845,52 @@ u32 __KernelInterruptReturnAddress()
|
||||
return intReturnHackAddr;
|
||||
}
|
||||
|
||||
u32 __KernelSetThreadRA(SceUID threadID, int nid)
|
||||
{
|
||||
u32 newRA;
|
||||
switch (nid)
|
||||
{
|
||||
case NID_MODULERETURN:
|
||||
newRA = moduleReturnHackAddr;
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG_REPORT(HLE, "__KernelSetThreadRA(): invalid RA address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (threadID == currentThread)
|
||||
currentMIPS->r[MIPS_REG_RA] = newRA;
|
||||
else
|
||||
{
|
||||
u32 error;
|
||||
Thread *thread = kernelObjects.Get<Thread>(threadID, error);
|
||||
if (!thread)
|
||||
return error;
|
||||
|
||||
thread->context.r[MIPS_REG_RA] = newRA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hleScheduledWakeup(u64 userdata, int cyclesLate);
|
||||
void hleThreadEndTimeout(u64 userdata, int cyclesLate);
|
||||
|
||||
void __KernelWriteFakeSysCall(u32 nid, u32 &ptr, u32 &pos)
|
||||
void __KernelWriteFakeSysCall(u32 nid, u32 *ptr, u32 &pos)
|
||||
{
|
||||
ptr = pos;
|
||||
*ptr = pos;
|
||||
pos += 8;
|
||||
WriteSyscall("FakeSysCalls", nid, ptr);
|
||||
WriteSyscall("FakeSysCalls", nid, *ptr);
|
||||
}
|
||||
|
||||
void __KernelThreadingInit()
|
||||
{
|
||||
struct ThreadHack
|
||||
{
|
||||
u32 nid;
|
||||
u32 *addr;
|
||||
};
|
||||
|
||||
// Yeah, this is straight out of JPCSP, I should be ashamed.
|
||||
const static u32 idleThreadCode[] = {
|
||||
MIPS_MAKE_ADDIU(MIPS_REG_A0, MIPS_REG_ZERO, 0),
|
||||
@ -865,7 +900,16 @@ void __KernelThreadingInit()
|
||||
MIPS_MAKE_SYSCALL("FakeSysCalls", "_sceKernelIdle"),
|
||||
MIPS_MAKE_BREAK(),
|
||||
};
|
||||
u32 blockSize = sizeof(idleThreadCode) + 4 * 2 * 4; // The thread code above plus 4 8-byte "hacks"
|
||||
|
||||
// If you add another func here, don't forget __KernelThreadingDoState() below.
|
||||
static ThreadHack threadHacks[] = {
|
||||
{NID_THREADRETURN, &threadReturnHackAddr},
|
||||
{NID_CALLBACKRETURN, &cbReturnHackAddr},
|
||||
{NID_INTERRUPTRETURN, &intReturnHackAddr},
|
||||
{NID_EXTENDRETURN, &extendReturnHackAddr},
|
||||
{NID_MODULERETURN, &moduleReturnHackAddr},
|
||||
};
|
||||
u32 blockSize = sizeof(idleThreadCode) + ARRAY_SIZE(threadHacks) * 2 * 4; // The thread code above plus 8 bytes per "hack"
|
||||
|
||||
dispatchEnabled = true;
|
||||
memset(waitTypeFuncs, 0, sizeof(waitTypeFuncs));
|
||||
@ -879,11 +923,9 @@ void __KernelThreadingInit()
|
||||
Memory::Memcpy(idleThreadHackAddr, idleThreadCode, sizeof(idleThreadCode));
|
||||
|
||||
u32 pos = idleThreadHackAddr + sizeof(idleThreadCode);
|
||||
// IF you add another func here, add it to the allocation above, and also to DoState below.
|
||||
__KernelWriteFakeSysCall(NID_THREADRETURN, threadReturnHackAddr, pos);
|
||||
__KernelWriteFakeSysCall(NID_CALLBACKRETURN, cbReturnHackAddr, pos);
|
||||
__KernelWriteFakeSysCall(NID_INTERRUPTRETURN, intReturnHackAddr, pos);
|
||||
__KernelWriteFakeSysCall(NID_EXTENDRETURN, extendReturnHackAddr, pos);
|
||||
for (int i = 0; i < ARRAY_SIZE(threadHacks); ++i) {
|
||||
__KernelWriteFakeSysCall(threadHacks[i].nid, threadHacks[i].addr, pos);
|
||||
}
|
||||
|
||||
eventScheduledWakeup = CoreTiming::RegisterEvent("ScheduledWakeup", &hleScheduledWakeup);
|
||||
eventThreadEndTimeout = CoreTiming::RegisterEvent("ThreadEndTimeout", &hleThreadEndTimeout);
|
||||
@ -910,6 +952,7 @@ void __KernelThreadingDoState(PointerWrap &p)
|
||||
p.Do(cbReturnHackAddr);
|
||||
p.Do(intReturnHackAddr);
|
||||
p.Do(extendReturnHackAddr);
|
||||
p.Do(moduleReturnHackAddr);
|
||||
|
||||
p.Do(currentThread);
|
||||
SceUID dv = 0;
|
||||
@ -1256,9 +1299,8 @@ u32 sceKernelReferThreadRunStatus(u32 threadID, u32 statusPtr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceKernelGetThreadExitStatus()
|
||||
int sceKernelGetThreadExitStatus(SceUID threadID)
|
||||
{
|
||||
SceUID threadID = PARAM(0);
|
||||
if (threadID == 0)
|
||||
threadID = __KernelGetCurThread();
|
||||
|
||||
@ -1269,17 +1311,17 @@ void sceKernelGetThreadExitStatus()
|
||||
if (t->nt.status == THREADSTATUS_DORMANT) // TODO: can be dormant before starting, too, need to avoid that
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelGetThreadExitStatus(%i)", threadID);
|
||||
RETURN(t->nt.exitStatus);
|
||||
return t->nt.exitStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN(SCE_KERNEL_ERROR_NOT_DORMANT);
|
||||
return SCE_KERNEL_ERROR_NOT_DORMANT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE,"sceKernelGetThreadExitStatus Error %08x", error);
|
||||
RETURN(SCE_KERNEL_ERROR_UNKNOWN_THID);
|
||||
return SCE_KERNEL_ERROR_UNKNOWN_THID;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1770,7 +1812,7 @@ Thread *__KernelCreateThread(SceUID &id, SceUID moduleId, const char *name, u32
|
||||
return t;
|
||||
}
|
||||
|
||||
void __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int prio, int stacksize, int attr)
|
||||
SceUID __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int prio, int stacksize, int attr)
|
||||
{
|
||||
//grab mips regs
|
||||
SceUID id;
|
||||
@ -1795,6 +1837,8 @@ void __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int pr
|
||||
mipsr4k.r[MIPS_REG_A1] = location;
|
||||
for (int i = 0; i < args; i++)
|
||||
Memory::Write_U8(argp[i], location + i);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr)
|
||||
@ -1966,10 +2010,6 @@ void __KernelReturnFromThread()
|
||||
_dbg_assert_msg_(HLE, thread != NULL, "Returned from a NULL thread.");
|
||||
|
||||
INFO_LOG(HLE,"__KernelReturnFromThread: %d", exitStatus);
|
||||
// TEMPORARY HACK: kill the stack of the root thread early:
|
||||
if (!strcmp(thread->GetName(), "root")) {
|
||||
thread->FreeStack();
|
||||
}
|
||||
|
||||
thread->nt.exitStatus = exitStatus;
|
||||
__KernelChangeReadyState(thread, currentThread, false);
|
||||
|
@ -56,7 +56,7 @@ int sceKernelSleepThreadCB();
|
||||
int sceKernelTerminateDeleteThread(int threadno);
|
||||
int sceKernelTerminateThread(SceUID threadID);
|
||||
int sceKernelWaitThreadEndCB(SceUID threadID, u32 timeoutPtr);
|
||||
void sceKernelGetThreadExitStatus();
|
||||
int sceKernelGetThreadExitStatus(SceUID threadID);
|
||||
u32 sceKernelGetThreadmanIdType(u32);
|
||||
u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 idCountPtr);
|
||||
u32 sceKernelExtendThreadStack(u32 size, u32 entryAddr, u32 entryParameter);
|
||||
@ -89,6 +89,7 @@ enum WaitType
|
||||
WAITTYPE_IO = 16,
|
||||
WAITTYPE_GEDRAWSYNC = 17,
|
||||
WAITTYPE_GELISTSYNC = 18,
|
||||
WAITTYPE_MODULE = 19,
|
||||
|
||||
NUM_WAITTYPES
|
||||
};
|
||||
@ -186,7 +187,7 @@ u32 __KernelNotifyCallbackType(RegisteredCallbackType type, SceUID cbId, int not
|
||||
|
||||
SceUID __KernelGetCurThread();
|
||||
SceUID __KernelGetCurThreadModuleId();
|
||||
void __KernelSetupRootThread(SceUID moduleId, int args, const char *argp, int prio, int stacksize, int attr); //represents the real PSP elf loader, run before execution
|
||||
SceUID __KernelSetupRootThread(SceUID moduleId, int args, const char *argp, int prio, int stacksize, int attr); //represents the real PSP elf loader, run before execution
|
||||
void __KernelStartIdleThreads(SceUID moduleId);
|
||||
void __KernelReturnFromThread(); // Called as HLE function
|
||||
u32 __KernelGetThreadPrio(SceUID id);
|
||||
@ -232,6 +233,10 @@ void __KernelNotifyCallback(RegisteredCallbackType type, SceUID cbId, int notify
|
||||
bool __KernelSwitchOffThread(const char *reason);
|
||||
bool __KernelSwitchToThread(SceUID threadID, const char *reason);
|
||||
|
||||
// Set a thread's return address to a specific FakeSyscall nid.
|
||||
// Discards old RA. Only useful for special threads that do special things on exit.
|
||||
u32 __KernelSetThreadRA(SceUID threadID, int nid);
|
||||
|
||||
// A call into game code. These can be pending on a thread.
|
||||
// Similar to Callback-s (NOT CallbackInfos) in JPCSP.
|
||||
typedef Action *(*ActionCreator)();
|
||||
|
Loading…
Reference in New Issue
Block a user