mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
More reworking of Callbacks, plus some other little fixes.
This commit is contained in:
parent
cf098dfd67
commit
aea0580297
@ -56,9 +56,9 @@
|
||||
//zlibdec
|
||||
const HLEFunction FakeSysCalls[] =
|
||||
{
|
||||
{NID_THREADRETURN, _sceKernelReturnFromThread, "_sceKernelReturnFromThread"},
|
||||
{NID_CALLBACKRETURN, _sceKernelReturnFromCallback, "_sceKernelReturnFromCallback"},
|
||||
{NID_INTERRUPTRETURN, _sceKernelReturnFromInterrupt, "_sceKernelReturnFromInterrupt"},
|
||||
{NID_THREADRETURN, __KernelReturnFromThread, "__KernelReturnFromThread"},
|
||||
{NID_CALLBACKRETURN, __KernelReturnFromMipsCall, "__KernelReturnFromMipsCall"},
|
||||
{NID_INTERRUPTRETURN, __KernelReturnFromInterrupt, "__KernelReturnFromInterrupt"},
|
||||
{NID_IDLE, _sceKernelIdle, "_sceKernelIdle"},
|
||||
};
|
||||
|
||||
|
@ -255,7 +255,7 @@ void sceDisplayGetVcount()
|
||||
// Too spammy
|
||||
// DEBUG_LOG(HLE,"%i=sceDisplayGetVcount()", vCount);
|
||||
// Games like Puyo Puyo call this in a tight loop at end-of-frame. We could have it consume some time from CoreTiming?
|
||||
CoreTiming::Idle(100000);
|
||||
CoreTiming::Idle(1000000);
|
||||
RETURN(vCount);
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,10 @@ u32 sceGeEdramGetSize()
|
||||
|
||||
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId, u32 optParamAddr)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceGeListEnQueue(addr=%08x, stall=%08x, cbid=%08x, param=%08x)",
|
||||
listAddress,stallAddress,callbackId,optParamAddr);
|
||||
//if (!stallAddress)
|
||||
// stallAddress = listAddress;
|
||||
u32 listID = gpu->EnqueueList(listAddress, stallAddress);
|
||||
// HACKY
|
||||
if (listID)
|
||||
@ -67,8 +71,6 @@ u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId, u32 optP
|
||||
else
|
||||
state = SCE_GE_LIST_COMPLETED;
|
||||
|
||||
DEBUG_LOG(HLE,"%i=sceGeListEnQueue(addr=%08x, stall=%08x, cbid=%08x, param=%08x)",listID,
|
||||
listAddress,stallAddress,callbackId,optParamAddr);
|
||||
DEBUG_LOG(HLE,"List enqueued.");
|
||||
//return display list ID
|
||||
return listID;
|
||||
@ -76,6 +78,8 @@ u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId, u32 optP
|
||||
|
||||
u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, u32 callbackId, u32 optParamAddr)
|
||||
{
|
||||
if (!stallAddress)
|
||||
stallAddress = listAddress;
|
||||
u32 listID = gpu->EnqueueList(listAddress,stallAddress);
|
||||
// HACKY
|
||||
if (listID)
|
||||
|
@ -379,13 +379,12 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0x72F3C145,0,"sceKernelReleaseThreadEventHandler"},
|
||||
{0x369EEB6B,0,"sceKernelReferThreadEventHandlerStatus"},
|
||||
|
||||
{0x349d6d6c,&WrapU_V<sceKernelCheckCallback>,"sceKernelCheckCallback"},
|
||||
{0x349d6d6c,sceKernelCheckCallback,"sceKernelCheckCallback"},
|
||||
{0xE81CAF8F,sceKernelCreateCallback,"sceKernelCreateCallback"},
|
||||
{0xEDBA5844,sceKernelDeleteCallback,"sceKernelDeleteCallback"},
|
||||
{0xC11BA8C4,sceKernelNotifyCallback,"sceKernelNotifyCallback"},
|
||||
{0xBA4051D6,sceKernelCancelCallback,"sceKernelCancelCallback"},
|
||||
{0x2A3D44FF,sceKernelGetCallbackCount,"sceKernelGetCallbackCount"},
|
||||
{0x349D6D6C,&WrapU_V<sceKernelCheckCallback>,"sceKernelCheckCallback"},
|
||||
{0x730ED8BC,sceKernelReferCallbackStatus,"sceKernelReferCallbackStatus"},
|
||||
|
||||
{0x8125221D,sceKernelCreateMbx,"sceKernelCreateMbx"},
|
||||
@ -426,6 +425,7 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0xA8AA591F,sceKernelCancelFpl,"sceKernelCancelFpl"},
|
||||
{0xD8199E4C,sceKernelReferFplStatus,"sceKernelReferFplStatus"},
|
||||
|
||||
// Not sure if these should be hooked up. See below.
|
||||
{0x0E927AED, _sceKernelReturnFromTimerHandler, "_sceKernelReturnFromTimerHandler"},
|
||||
{0x532A522E, _sceKernelExitThread,"_sceKernelExitThread"},
|
||||
|
||||
|
@ -171,7 +171,7 @@ retry:
|
||||
EventFlagTh *t = &e->waitingThreads[i];
|
||||
if (__KernelEventFlagMatches(&e->nef.currentPattern, t->bits, t->wait, t->outAddr))
|
||||
{
|
||||
__KernelResumeThread(t->tid);
|
||||
__KernelResumeThreadFromWait(t->tid);
|
||||
wokeThreads = true;
|
||||
e->nef.numWaitThreads--;
|
||||
e->waitingThreads.erase(e->waitingThreads.begin() + i);
|
||||
@ -216,8 +216,8 @@ void sceKernelWaitEventFlag()
|
||||
timeout = Memory::Read_U32(timeoutPtr);
|
||||
|
||||
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, 0, false);
|
||||
// MUST NOT return a value after __KernelWaitCurThread as we may have been rescheduled!
|
||||
}
|
||||
RETURN(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -255,8 +255,8 @@ void sceKernelWaitEventFlagCB()
|
||||
timeout = Memory::Read_U32(timeoutPtr);
|
||||
|
||||
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, 0, true);
|
||||
__KernelCheckCallbacks();
|
||||
}
|
||||
RETURN(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -303,7 +303,7 @@ void __TriggerInterruptWithArg(PSPInterrupt intno, int subintr, int arg)
|
||||
__RunOnePendingInterrupt();
|
||||
}
|
||||
|
||||
void _sceKernelReturnFromInterrupt()
|
||||
void __KernelReturnFromInterrupt()
|
||||
{
|
||||
DEBUG_LOG(CPU, "Left interrupt handler at %08x", currentMIPS->pc);
|
||||
inInterrupt = false;
|
||||
@ -424,6 +424,7 @@ const HLEFunction Kernel_Library[] =
|
||||
{0xa089eca4,sceKernelMemset, "sceKernelMemset"},
|
||||
{0xDC692EE3,0, "sceKernelTryLockLwMutex"},
|
||||
{0xbea46419,0, "sceKernelLockLwMutex"},
|
||||
{0x1FC64E09,0, "sceKernelLockLwMutexCB"},
|
||||
{0x15b6446b,0, "sceKernelUnlockLwMutex"},
|
||||
{0x293b45b8,sceKernelGetThreadId, "sceKernelGetThreadId"},
|
||||
{0x1839852A,0,"sce_paf_private_memcpy"},
|
||||
|
@ -60,8 +60,8 @@ void __InterruptsShutdown();
|
||||
void __TriggerInterrupt(PSPInterrupt intno, int subInterrupts = -1);
|
||||
void __TriggerInterruptWithArg(PSPInterrupt intno, int subintr, int arg); // For GE "callbacks"
|
||||
bool __RunOnePendingInterrupt();
|
||||
void __KernelReturnFromInterrupt();
|
||||
|
||||
void _sceKernelReturnFromInterrupt();
|
||||
u32 sceKernelRegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32 handler, u32 handlerArg);
|
||||
|
||||
void Register_Kernel_Library();
|
||||
|
@ -229,11 +229,9 @@ void sceKernelAllocateFplCB()
|
||||
} else {
|
||||
// TODO: Should block and process callbacks!
|
||||
__KernelCheckCallbacks();
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE,"sceKernelAllocateFpl(%i, %08x, %i)", id, PARAM(1), timeOut);
|
||||
RETURN(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -620,6 +618,35 @@ void sceKernelReferVplStatus()
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void AllocMemoryBlock() {
|
||||
const char *pname = Memory::GetCharPointer(PARAM(0));
|
||||
int type = PARAM(1);
|
||||
u32 size = PARAM(2);
|
||||
int paramsAddr = PARAM(3);
|
||||
|
||||
DEBUG_LOG(HLE,"AllocMemoryBlock(SysMemUserForUser_FE707FDF)(%s, %i, %i, %08x)", pname, type, size, paramsAddr);
|
||||
|
||||
// Just support allocating a block in the user region.
|
||||
|
||||
u32 blockPtr = userMemory.Alloc(size, false, pname);
|
||||
|
||||
// Create a UID object??? Nah, let's just us the UID itself (hack!)
|
||||
|
||||
RETURN(blockPtr);
|
||||
}
|
||||
|
||||
void FreeMemoryBlock() {
|
||||
SceUID uid = PARAM(0);
|
||||
DEBUG_LOG(HLE, "FreeMemoryBlock(%i)", uid);
|
||||
userMemory.Free(uid);
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void GetMemoryBlockPtr() {
|
||||
SceUID uid = PARAM(0);
|
||||
DEBUG_LOG(HLE, "GetMemoryBlockPtr(%i)", uid);
|
||||
RETURN(uid);
|
||||
}
|
||||
|
||||
const HLEFunction SysMemUserForUser[] =
|
||||
{
|
||||
@ -637,10 +664,12 @@ const HLEFunction SysMemUserForUser[] =
|
||||
{0xf77d77cb,sceKernelSetCompilerVersion,"sceKernelSetCompilerVersion"},
|
||||
{0x35669d4c,0,"sceKernelSetCompiledSdkVersion600_602"}, //??
|
||||
{0x1b4217bc,0,"sceKernelSetCompiledSdkVersion603_605"},
|
||||
{0xDB83A952,0,"SysMemUserForUser_DB83A952"},
|
||||
|
||||
// Obscure raw block API
|
||||
{0xDB83A952,GetMemoryBlockPtr,"SysMemUserForUser_DB83A952"}, // GetMemoryBlockAddr
|
||||
{0x91DE343C,0,"SysMemUserForUser_91DE343C"},
|
||||
{0x50F61D8A,0,"SysMemUserForUser_50F61D8A"},
|
||||
{0xFE707FDF,0,"SysMemUserForUser_FE707FDF"},
|
||||
{0x50F61D8A,FreeMemoryBlock,"SysMemUserForUser_50F61D8A"}, // FreeMemoryBlock
|
||||
{0xFE707FDF,AllocMemoryBlock,"SysMemUserForUser_FE707FDF"}, // AllocMemoryBlock
|
||||
};
|
||||
|
||||
|
||||
|
@ -567,6 +567,8 @@ u32 sceKernelLoadModule(const char *name, u32 flags)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_OBJECT;
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOADER, "sceKernelLoadModule(%s, %08x)", name, flags);
|
||||
|
||||
SceKernelLMOption *lmoption = 0;
|
||||
int position = 0;
|
||||
// TODO: Use position to decide whether to load high or low
|
||||
@ -633,8 +635,8 @@ void sceKernelUnloadModule()
|
||||
|
||||
void sceKernelGetModuleIdByAddress()
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelGetModuleIdByAddress(%08x)", PARAM(0));
|
||||
if (PARAM(0) == 0x08800000)
|
||||
ERROR_LOG(HLE,"HACKIMPL sceKernelGetModuleIdByAddress(%08x)", PARAM(0));
|
||||
if ((PARAM(0) & 0xFFFF0000) == 0x08800000)
|
||||
RETURN(mainModuleID);
|
||||
else
|
||||
RETURN(0);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "HLE.h"
|
||||
#include "sceKernel.h"
|
||||
#include "sceKernelMsgPipe.h"
|
||||
#include "sceKernelThread.h"
|
||||
|
||||
struct NativeMsgPipe
|
||||
{
|
||||
@ -44,6 +45,8 @@ struct MsgPipe : public KernelObject
|
||||
|
||||
// Ring buffer
|
||||
u8 *buffer;
|
||||
int writePos;
|
||||
int readPos;
|
||||
};
|
||||
|
||||
void sceKernelCreateMsgPipe()
|
||||
@ -66,6 +69,9 @@ void sceKernelCreateMsgPipe()
|
||||
m->nmp.numReceiveWaitThreads = 0;
|
||||
|
||||
m->buffer = new u8[size];
|
||||
m->writePos = 0;
|
||||
m->readPos = 0;
|
||||
|
||||
RETURN(id);
|
||||
}
|
||||
|
||||
@ -93,6 +99,35 @@ void sceKernelSendMsgPipe()
|
||||
u32 resultAddr = PARAM(4);
|
||||
u32 timeoutPtr = PARAM(5);
|
||||
|
||||
u32 error;
|
||||
MsgPipe *pipe = kernelObjects.Get<MsgPipe>(uid, error);
|
||||
if (!pipe) {
|
||||
ERROR_LOG(HLE, "sceKernelSendMsgPipe(%i) - ERROR %08x", uid, error);
|
||||
RETURN(error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sendSize > pipe->nmp.freeSize) {
|
||||
// TODO: Block
|
||||
ERROR_LOG(HLE, "sceKernelSendMsgPipe(%i) - Message won't fit", uid, error);
|
||||
RETURN(SCE_KERNEL_ERROR_MPP_FULL);
|
||||
return;
|
||||
}
|
||||
|
||||
const u8 *source = Memory::GetPointer(sendBufAddr);
|
||||
|
||||
int destIndex = pipe->writePos;
|
||||
if (pipe->writePos + sendSize > pipe->nmp.size) {
|
||||
// Split in two
|
||||
int firstCopySize = pipe->nmp.size - pipe->writePos;
|
||||
memcpy(pipe->buffer + pipe->writePos, source, firstCopySize);
|
||||
memcpy(pipe->buffer, source + firstCopySize, sendSize - firstCopySize);
|
||||
} else {
|
||||
memcpy(pipe->buffer + pipe->writePos, source, sendSize);
|
||||
}
|
||||
pipe->writePos += sendSize;
|
||||
pipe->writePos %= pipe->nmp.size;
|
||||
|
||||
ERROR_LOG(HLE, "UNIMPL sceKernelSendMsgPipe(%i, %08x, %i, %i, %08x, %08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr);
|
||||
RETURN(0);
|
||||
}
|
||||
@ -106,8 +141,38 @@ void sceKernelSendMsgPipeCB()
|
||||
u32 resultAddr = PARAM(4);
|
||||
u32 timeoutPtr = PARAM(5);
|
||||
|
||||
ERROR_LOG(HLE, "UNIMPL sceKernelSendMsgPipeCB(%i, %08x, %i, %i, %08x, %08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr);
|
||||
u32 error;
|
||||
MsgPipe *pipe = kernelObjects.Get<MsgPipe>(uid, error);
|
||||
if (!pipe) {
|
||||
ERROR_LOG(HLE, "sceKernelSendMsgPipe(%i) - ERROR %08x", uid, error);
|
||||
RETURN(error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sendSize > pipe->nmp.freeSize) {
|
||||
// TODO: Block
|
||||
ERROR_LOG(HLE, "sceKernelSendMsgPipe(%i) - Message won't fit", uid, error);
|
||||
RETURN(SCE_KERNEL_ERROR_MPP_FULL);
|
||||
return;
|
||||
}
|
||||
|
||||
const u8 *source = Memory::GetPointer(sendBufAddr);
|
||||
|
||||
int destIndex = pipe->writePos;
|
||||
if (pipe->writePos + sendSize > pipe->nmp.size) {
|
||||
// Split in two
|
||||
int firstCopySize = pipe->nmp.size - pipe->writePos;
|
||||
memcpy(pipe->buffer + pipe->writePos, source, firstCopySize);
|
||||
memcpy(pipe->buffer, source + firstCopySize, sendSize - firstCopySize);
|
||||
} else {
|
||||
memcpy(pipe->buffer + pipe->writePos, source, sendSize);
|
||||
}
|
||||
pipe->writePos += sendSize;
|
||||
pipe->writePos %= pipe->nmp.size;
|
||||
|
||||
ERROR_LOG(HLE, "UNIMPL sceKernelSendMsgPipe(%i, %08x, %i, %i, %08x, %08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr);
|
||||
RETURN(0);
|
||||
__KernelCheckCallbacks();
|
||||
}
|
||||
|
||||
void sceKernelTrySendMsgPipe()
|
||||
@ -117,8 +182,38 @@ void sceKernelTrySendMsgPipe()
|
||||
u32 sendSize = PARAM(2);
|
||||
int waitMode = PARAM(3);
|
||||
u32 resultAddr = PARAM(4);
|
||||
u32 timeoutPtr = PARAM(5);
|
||||
|
||||
ERROR_LOG(HLE, "UNIMPL sceKernelTrySendMsgPipe(%i, %08x, %i, %i, %08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr);
|
||||
u32 error;
|
||||
MsgPipe *pipe = kernelObjects.Get<MsgPipe>(uid, error);
|
||||
if (!pipe) {
|
||||
ERROR_LOG(HLE, "sceKernelSendMsgPipe(%i) - ERROR %08x", uid, error);
|
||||
RETURN(error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sendSize > pipe->nmp.freeSize) {
|
||||
// TODO: Block
|
||||
ERROR_LOG(HLE, "sceKernelSendMsgPipe(%i) - Message won't fit", uid, error);
|
||||
RETURN(SCE_KERNEL_ERROR_MPP_FULL);
|
||||
return;
|
||||
}
|
||||
|
||||
const u8 *source = Memory::GetPointer(sendBufAddr);
|
||||
|
||||
int destIndex = pipe->writePos;
|
||||
if (pipe->writePos + sendSize > pipe->nmp.size) {
|
||||
// Split in two
|
||||
int firstCopySize = pipe->nmp.size - pipe->writePos;
|
||||
memcpy(pipe->buffer + pipe->writePos, source, firstCopySize);
|
||||
memcpy(pipe->buffer, source + firstCopySize, sendSize - firstCopySize);
|
||||
} else {
|
||||
memcpy(pipe->buffer + pipe->writePos, source, sendSize);
|
||||
}
|
||||
pipe->writePos += sendSize;
|
||||
pipe->writePos %= pipe->nmp.size;
|
||||
|
||||
ERROR_LOG(HLE, "UNIMPL sceKernelSendMsgPipe(%i, %08x, %i, %i, %08x, %08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr);
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
@ -132,7 +227,7 @@ void sceKernelReceiveMsgPipe()
|
||||
u32 timeoutPtr = PARAM(5);
|
||||
|
||||
ERROR_LOG(HLE, "UNIMPL sceKernelReceiveMsgPipe(%i, %08x, %i, %i, %08x, %08x)", uid, receiveBufAddr, receiveSize, waitMode, resultAddr, timeoutPtr);
|
||||
RETURN(0);
|
||||
RETURN(SCE_KERNEL_ERROR_MPP_EMPTY);
|
||||
}
|
||||
|
||||
void sceKernelReceiveMsgPipeCB()
|
||||
@ -145,7 +240,7 @@ void sceKernelReceiveMsgPipeCB()
|
||||
u32 timeoutPtr = PARAM(5);
|
||||
|
||||
ERROR_LOG(HLE, "UNIMPL sceKernelReceiveMsgPipeCB(%i, %08x, %i, %i, %08x, %08x)", uid, receiveBufAddr, receiveSize, waitMode, resultAddr, timeoutPtr);
|
||||
RETURN(0);
|
||||
RETURN(SCE_KERNEL_ERROR_MPP_EMPTY);
|
||||
}
|
||||
|
||||
void sceKernelTryReceiveMsgPipe()
|
||||
@ -157,7 +252,7 @@ void sceKernelTryReceiveMsgPipe()
|
||||
u32 resultAddr = PARAM(4);
|
||||
|
||||
ERROR_LOG(HLE, "UNIMPL sceKernelTryReceiveMsgPipe(%i, %08x, %i, %i, %08x)", uid, receiveBufAddr, receiveSize, waitMode, resultAddr);
|
||||
RETURN(0);
|
||||
RETURN(SCE_KERNEL_ERROR_MPP_EMPTY);
|
||||
}
|
||||
|
||||
void sceKernelCancelMsgPipe()
|
||||
|
@ -110,13 +110,14 @@ u32 sceKernelLockMutex(u32 id, u32 count, u32 timeoutPtr)
|
||||
else
|
||||
{
|
||||
// Yeah, we need to block. Somehow.
|
||||
ERROR_LOG(HLE,"Mutex should block!");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceKernelLockMutexCB(u32 id, u32 count, u32 timeoutPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE,"UNIMPL sceKernelLockMutexCB(%i, %i, %08x)", id, count, timeoutPtr);
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelLockMutexCB(%i, %i, %08x)", id, count, timeoutPtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -148,30 +149,36 @@ struct NativeLwMutex
|
||||
|
||||
void sceKernelCreateLwMutex()
|
||||
{
|
||||
DEBUG_LOG(HLE,"UNIMPL sceKernelCreateLwMutex()");
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelCreateLwMutex()");
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void sceKernelDeleteLwMutex()
|
||||
{
|
||||
DEBUG_LOG(HLE,"UNIMPL sceKernelDeleteLwMutex()");
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelDeleteLwMutex()");
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void sceKernelTryLockLwMutex()
|
||||
{
|
||||
DEBUG_LOG(HLE,"UNIMPL sceKernelTryLockLwMutex()");
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelTryLockLwMutex()");
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void sceKernelLockLwMutex()
|
||||
{
|
||||
DEBUG_LOG(HLE,"UNIMPL sceKernelLockLwMutex()");
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelLockLwMutex()");
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void sceKernelLockLwMutexCB()
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelLockLwMutexCB()");
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void sceKernelUnlockLwMutex()
|
||||
{
|
||||
DEBUG_LOG(HLE,"UNIMPL void sceKernelUnlockLwMutex()");
|
||||
ERROR_LOG(HLE,"UNIMPL void sceKernelUnlockLwMutex()");
|
||||
RETURN(0);
|
||||
}
|
@ -28,4 +28,5 @@ void sceKernelCreateLwMutex();
|
||||
void sceKernelDeleteLwMutex();
|
||||
void sceKernelTryLockLwMutex();
|
||||
void sceKernelLockLwMutex();
|
||||
void sceKernelLockLwMutexCB();
|
||||
void sceKernelUnlockLwMutex();
|
@ -137,7 +137,7 @@ retry:
|
||||
int wVal = (int)__KernelGetWaitValue(id, error);
|
||||
if (wVal <= s->ns.currentCount)
|
||||
{
|
||||
__KernelResumeThread(id);
|
||||
__KernelResumeThreadFromWait(id);
|
||||
s->ns.currentCount -= wVal;
|
||||
wokeThreads = true;
|
||||
s->waitingThreads.erase(iter);
|
||||
|
@ -34,15 +34,6 @@
|
||||
#include "sceKernelModule.h"
|
||||
#include "sceKernelInterrupt.h"
|
||||
|
||||
enum ThreadStatus
|
||||
{
|
||||
THREADSTATUS_RUNNING = 1,
|
||||
THREADSTATUS_READY = 2,
|
||||
THREADSTATUS_WAIT = 4,
|
||||
THREADSTATUS_SUSPEND = 8,
|
||||
THREADSTATUS_DORMANT = 16,
|
||||
THREADSTATUS_DEAD = 32,
|
||||
};
|
||||
|
||||
enum {
|
||||
ERROR_KERNEL_THREAD_ALREADY_DORMANT = 0x800201a2,
|
||||
@ -87,106 +78,6 @@ struct SceKernelSysClock {
|
||||
u32 hi;
|
||||
};
|
||||
|
||||
// Real PSP struct, don't change the fields
|
||||
struct NativeThread
|
||||
{
|
||||
u32 nativeSize;
|
||||
char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
|
||||
|
||||
// Threading stuff
|
||||
u32 attr;
|
||||
u32 status;
|
||||
u32 entrypoint;
|
||||
u32 initialStack;
|
||||
u32 stackSize;
|
||||
u32 gpreg;
|
||||
|
||||
int initialPriority;
|
||||
int currentPriority;
|
||||
WaitType waitType;
|
||||
SceUID waitID;
|
||||
int wakeupCount;
|
||||
int exitStatus;
|
||||
SceKernelSysClock runForClocks;
|
||||
int numInterruptPreempts;
|
||||
int numThreadPreempts;
|
||||
int numReleases;
|
||||
};
|
||||
|
||||
class Thread : public KernelObject
|
||||
{
|
||||
public:
|
||||
const char *GetName() {return nt.name;}
|
||||
const char *GetTypeName() {return "Thread";}
|
||||
void GetQuickInfo(char *ptr, int size)
|
||||
{
|
||||
sprintf(ptr, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )",
|
||||
context.pc, context.r[MIPS_REG_SP],
|
||||
(nt.status & THREADSTATUS_RUNNING) ? "RUN" : "",
|
||||
(nt.status & THREADSTATUS_READY) ? "READY" : "",
|
||||
(nt.status & THREADSTATUS_WAIT) ? "WAIT" : "",
|
||||
(nt.status & THREADSTATUS_SUSPEND) ? "SUSPEND" : "",
|
||||
(nt.status & THREADSTATUS_DORMANT) ? "DORMANT" : "",
|
||||
(nt.status & THREADSTATUS_DEAD) ? "DEAD" : "",
|
||||
nt.waitType,
|
||||
nt.waitID,
|
||||
waitValue);
|
||||
}
|
||||
|
||||
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; }
|
||||
|
||||
int GetIDType() const { return SCE_KERNEL_TMID_Thread; }
|
||||
|
||||
bool AllocateStack(u32 &stackSize)
|
||||
{
|
||||
if (nt.attr & PSP_THREAD_ATTR_KERNEL)
|
||||
{
|
||||
// Allocate stacks for kernel threads (idle) in kernel RAM
|
||||
stackBlock = kernelMemory.Alloc(stackSize, true, (std::string("stack/") + nt.name).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
stackBlock = userMemory.Alloc(stackSize, true, (std::string("stack/") + nt.name).c_str());
|
||||
}
|
||||
if (stackBlock == (u32)-1)
|
||||
{
|
||||
ERROR_LOG(HLE, "Failed to allocate stack for thread");
|
||||
return false;
|
||||
}
|
||||
// Fill the stack.
|
||||
Memory::Memset(stackBlock, 0xFF, stackSize);
|
||||
context.r[MIPS_REG_SP] = stackBlock + stackSize;
|
||||
nt.initialStack = context.r[MIPS_REG_SP];
|
||||
nt.stackSize = stackSize;
|
||||
// What's this 512?
|
||||
context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP] - 512;
|
||||
context.r[MIPS_REG_SP] -= 512;
|
||||
return true;
|
||||
}
|
||||
|
||||
~Thread()
|
||||
{
|
||||
if (nt.attr & PSP_THREAD_ATTR_KERNEL) {
|
||||
kernelMemory.Free(stackBlock);
|
||||
} else {
|
||||
userMemory.Free(stackBlock);
|
||||
}
|
||||
}
|
||||
|
||||
NativeThread nt;
|
||||
|
||||
u32 waitValue;
|
||||
bool sleeping;
|
||||
|
||||
bool isProcessingCallbacks;
|
||||
|
||||
ThreadContext context;
|
||||
|
||||
std::set<SceUID> registeredCallbacks[THREAD_CALLBACK_NUM_TYPES];
|
||||
std::list<SceUID> readyCallbacks[THREAD_CALLBACK_NUM_TYPES];
|
||||
|
||||
u32 stackBlock;
|
||||
};
|
||||
|
||||
struct NativeCallback
|
||||
{
|
||||
@ -239,6 +130,123 @@ public:
|
||||
bool forceDelete;
|
||||
};
|
||||
|
||||
// Real PSP struct, don't change the fields
|
||||
struct NativeThread
|
||||
{
|
||||
u32 nativeSize;
|
||||
char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
|
||||
|
||||
// Threading stuff
|
||||
u32 attr;
|
||||
u32 status;
|
||||
u32 entrypoint;
|
||||
u32 initialStack;
|
||||
u32 stackSize;
|
||||
u32 gpreg;
|
||||
|
||||
int initialPriority;
|
||||
int currentPriority;
|
||||
WaitType waitType;
|
||||
SceUID waitID;
|
||||
int wakeupCount;
|
||||
int exitStatus;
|
||||
SceKernelSysClock runForClocks;
|
||||
int numInterruptPreempts;
|
||||
int numThreadPreempts;
|
||||
int numReleases;
|
||||
};
|
||||
|
||||
struct ThreadWaitInfo {
|
||||
u32 waitValue;
|
||||
};
|
||||
|
||||
class Thread : public KernelObject
|
||||
{
|
||||
public:
|
||||
const char *GetName() {return nt.name;}
|
||||
const char *GetTypeName() {return "Thread";}
|
||||
void GetQuickInfo(char *ptr, int size)
|
||||
{
|
||||
sprintf(ptr, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )",
|
||||
context.pc, context.r[MIPS_REG_SP],
|
||||
(nt.status & THREADSTATUS_RUNNING) ? "RUN" : "",
|
||||
(nt.status & THREADSTATUS_READY) ? "READY" : "",
|
||||
(nt.status & THREADSTATUS_WAIT) ? "WAIT" : "",
|
||||
(nt.status & THREADSTATUS_SUSPEND) ? "SUSPEND" : "",
|
||||
(nt.status & THREADSTATUS_DORMANT) ? "DORMANT" : "",
|
||||
(nt.status & THREADSTATUS_DEAD) ? "DEAD" : "",
|
||||
nt.waitType,
|
||||
nt.waitID,
|
||||
waitInfo.waitValue);
|
||||
}
|
||||
|
||||
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; }
|
||||
|
||||
int GetIDType() const { return SCE_KERNEL_TMID_Thread; }
|
||||
|
||||
bool AllocateStack(u32 &stackSize)
|
||||
{
|
||||
if (nt.attr & PSP_THREAD_ATTR_KERNEL)
|
||||
{
|
||||
// Allocate stacks for kernel threads (idle) in kernel RAM
|
||||
stackBlock = kernelMemory.Alloc(stackSize, true, (std::string("stack/") + nt.name).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
stackBlock = userMemory.Alloc(stackSize, true, (std::string("stack/") + nt.name).c_str());
|
||||
}
|
||||
if (stackBlock == (u32)-1)
|
||||
{
|
||||
ERROR_LOG(HLE, "Failed to allocate stack for thread");
|
||||
return false;
|
||||
}
|
||||
// Fill the stack.
|
||||
Memory::Memset(stackBlock, 0xFF, stackSize);
|
||||
context.r[MIPS_REG_SP] = stackBlock + stackSize;
|
||||
nt.initialStack = context.r[MIPS_REG_SP];
|
||||
nt.stackSize = stackSize;
|
||||
// What's this 512?
|
||||
context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP] - 512;
|
||||
context.r[MIPS_REG_SP] -= 512;
|
||||
return true;
|
||||
}
|
||||
|
||||
~Thread()
|
||||
{
|
||||
if (nt.attr & PSP_THREAD_ATTR_KERNEL) {
|
||||
kernelMemory.Free(stackBlock);
|
||||
} else {
|
||||
userMemory.Free(stackBlock);
|
||||
}
|
||||
}
|
||||
|
||||
// Utils
|
||||
bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; }
|
||||
bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
|
||||
bool isReady() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
|
||||
bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
|
||||
bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
|
||||
|
||||
NativeThread nt;
|
||||
|
||||
ThreadWaitInfo waitInfo;
|
||||
bool sleeping;
|
||||
|
||||
bool isProcessingCallbacks;
|
||||
|
||||
ThreadContext context;
|
||||
|
||||
std::set<SceUID> registeredCallbacks[THREAD_CALLBACK_NUM_TYPES];
|
||||
std::list<SceUID> readyCallbacks[THREAD_CALLBACK_NUM_TYPES];
|
||||
|
||||
std::list<int> pendingMipsCalls;
|
||||
|
||||
u32 stackBlock;
|
||||
};
|
||||
|
||||
void __KernelExecuteMipsCallOnCurrentThread(int callId);
|
||||
|
||||
|
||||
int g_inCbCount = 0;
|
||||
|
||||
Thread *__KernelCreateThread(SceUID &id, SceUID moduleID, const char *name, u32 entryPoint, u32 priority, int stacksize, u32 attr);
|
||||
@ -257,7 +265,7 @@ SceUID threadIdleID[2];
|
||||
|
||||
int eventScheduledWakeup;
|
||||
|
||||
bool dispatchSuspended = false;
|
||||
bool dispatchEnabled = true;
|
||||
|
||||
|
||||
// This seems nasty
|
||||
@ -273,7 +281,7 @@ Thread *__GetCurrentThread() {
|
||||
return currentThread;
|
||||
}
|
||||
|
||||
u32 __KernelCallbackReturnAddress()
|
||||
u32 __KernelMipsCallReturnAddress()
|
||||
{
|
||||
return cbReturnHackAddr;
|
||||
}
|
||||
@ -289,7 +297,7 @@ void __KernelThreadingInit()
|
||||
{
|
||||
u32 blockSize = 4 * 4 + 4 * 2 * 3; // One 16-byte thread plus 3 8-byte "hacks"
|
||||
|
||||
dispatchSuspended = false;
|
||||
dispatchEnabled = true;
|
||||
|
||||
idleThreadHackAddr = kernelMemory.Alloc(blockSize, false, "threadrethack");
|
||||
// Make sure it got allocated where we expect it... at the very start of kernel RAM
|
||||
@ -362,7 +370,7 @@ u32 __KernelGetWaitValue(SceUID threadID, u32 &error)
|
||||
Thread *t = kernelObjects.Get<Thread>(threadID, error);
|
||||
if (t)
|
||||
{
|
||||
return t->waitValue;
|
||||
return t->waitInfo.waitValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -529,7 +537,7 @@ bool __KernelTriggerWait(WaitType type, int id, bool dontSwitch)
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 __KernelResumeThread(SceUID threadID)
|
||||
u32 __KernelResumeThreadFromWait(SceUID threadID)
|
||||
{
|
||||
u32 error;
|
||||
Thread *t = kernelObjects.Get<Thread>(threadID, error);
|
||||
@ -538,11 +546,12 @@ u32 __KernelResumeThread(SceUID threadID)
|
||||
t->nt.status &= ~THREADSTATUS_WAIT;
|
||||
if (!(t->nt.status & (THREADSTATUS_SUSPEND | THREADSTATUS_WAIT)))
|
||||
t->nt.status |= THREADSTATUS_READY;
|
||||
t->isProcessingCallbacks = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE, "__KernelResumeThread(%d): bad thread: %08x", threadID, error);
|
||||
ERROR_LOG(HLE, "__KernelResumeThreadFromWait(%d): bad thread: %08x", threadID, error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
@ -550,12 +559,11 @@ u32 __KernelResumeThread(SceUID threadID)
|
||||
// makes the current thread wait for an event
|
||||
void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, int timeout, bool processCallbacks)
|
||||
{
|
||||
currentThread->nt.status = THREADSTATUS_WAIT;
|
||||
currentThread->nt.waitID = waitID;
|
||||
currentThread->nt.waitType = type;
|
||||
__KernelChangeThreadState(currentThread, THREADSTATUS_WAIT);
|
||||
currentThread->nt.numReleases++;
|
||||
currentThread->waitValue = waitValue;
|
||||
currentThread->isProcessingCallbacks = processCallbacks;
|
||||
currentThread->waitInfo.waitValue = waitValue;
|
||||
if (timeout)
|
||||
{
|
||||
// TODO:
|
||||
@ -566,7 +574,8 @@ void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, int time
|
||||
// TODO: time waster
|
||||
char temp[256];
|
||||
sprintf(temp, "started wait %s", waitTypeStrings[(int)type]);
|
||||
__KernelReSchedule(temp);
|
||||
|
||||
__KernelReSchedule(processCallbacks, temp);
|
||||
// TODO: Remove thread from Ready queue?
|
||||
}
|
||||
|
||||
@ -594,23 +603,15 @@ void __KernelRemoveFromThreadQueue(Thread *t)
|
||||
}
|
||||
}
|
||||
|
||||
void __KernelReSchedule(const char *reason)
|
||||
{
|
||||
// cancel rescheduling when in interrupt or callback, otherwise everything will be fucked up
|
||||
if (__IsInInterrupt() || __KernelInCallback())
|
||||
{
|
||||
reason = "WTF";
|
||||
return;
|
||||
}
|
||||
Thread *__KernelNextThread() {
|
||||
// round-robin scheduler
|
||||
// seems to work ?
|
||||
// not accurate!
|
||||
retry:
|
||||
int bestthread = -1;
|
||||
int prio=0xffffff;
|
||||
int prio = 0xffffff;
|
||||
|
||||
int next = 0;
|
||||
for (size_t i=0; i<threadqueue.size(); i++)
|
||||
for (size_t i = 0; i < threadqueue.size(); i++)
|
||||
{
|
||||
if (currentThread == threadqueue[i])
|
||||
{
|
||||
@ -619,7 +620,7 @@ retry:
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i=0; i<threadqueue.size(); i++)
|
||||
for (size_t i = 0; i < threadqueue.size(); i++)
|
||||
{
|
||||
next = (next + 1) % threadqueue.size();
|
||||
|
||||
@ -635,30 +636,55 @@ retry:
|
||||
}
|
||||
|
||||
if (bestthread != -1)
|
||||
return threadqueue[bestthread];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __KernelReSchedule(const char *reason)
|
||||
{
|
||||
// cancel rescheduling when in interrupt or callback, otherwise everything will be fucked up
|
||||
if (__IsInInterrupt() || __KernelInCallback())
|
||||
{
|
||||
reason = "In Interrupt Or Callback";
|
||||
return;
|
||||
}
|
||||
|
||||
retry:
|
||||
Thread *nextThread = __KernelNextThread();
|
||||
|
||||
if (nextThread)
|
||||
{
|
||||
if (currentThread) // It might just have been deleted.
|
||||
{
|
||||
__KernelSaveContext(¤tThread->context);
|
||||
DEBUG_LOG(HLE,"Context saved (%s): %i - %s - pc: %08x", reason, currentThread->GetUID(), currentThread->GetName(), currentMIPS->pc);
|
||||
}
|
||||
currentThread = threadqueue[bestthread];
|
||||
__KernelLoadContext(¤tThread->context);
|
||||
DEBUG_LOG(HLE,"Context loaded (%s): %i - %s - pc: %08x", reason, currentThread->GetUID(), currentThread->GetName(), currentMIPS->pc);
|
||||
__KernelSwitchContext(nextThread, reason);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbg_assert_msg_(HLE,0,"No threads available to schedule! There should be at least one idle thread available.");
|
||||
// This shouldn't happen anymore now that we have idle threads.
|
||||
|
||||
// No threads want to run : increase timers, skip time in general
|
||||
// MessageBox(0,"Error: no thread to transition to",0,0);
|
||||
|
||||
// DEBUG_LOG(HLE,"No thread to transition to, idling");
|
||||
_dbg_assert_msg_(HLE,0,"No threads available to schedule! There should be at least one idle thread available.");
|
||||
CoreTiming::Idle();
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
void __KernelReSchedule(bool doCallbacks, const char *reason)
|
||||
{
|
||||
Thread *thread = currentThread;
|
||||
if (doCallbacks)
|
||||
{
|
||||
if (thread)
|
||||
thread->isProcessingCallbacks = doCallbacks;
|
||||
__KernelCheckCallbacks();
|
||||
}
|
||||
__KernelReSchedule(reason);
|
||||
if (doCallbacks && thread == currentThread) {
|
||||
if (thread->isRunning()) {
|
||||
thread->isProcessingCallbacks = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Thread Management
|
||||
@ -729,7 +755,7 @@ Thread *__KernelCreateThread(SceUID &id, SceUID moduleID, const char *name, u32
|
||||
t->nt.status = THREADSTATUS_DORMANT;
|
||||
t->nt.waitType = WAITTYPE_NONE;
|
||||
t->nt.waitID = 0;
|
||||
t->waitValue = 0;
|
||||
memset(&t->waitInfo, 0, sizeof(t->waitInfo));
|
||||
t->nt.exitStatus = 0;
|
||||
t->nt.numInterruptPreempts = 0;
|
||||
t->nt.numReleases = 0;
|
||||
@ -737,6 +763,7 @@ Thread *__KernelCreateThread(SceUID &id, SceUID moduleID, const char *name, u32
|
||||
t->nt.runForClocks.low = 0;
|
||||
t->nt.runForClocks.hi = 0;
|
||||
t->nt.wakeupCount = 0;
|
||||
t->isProcessingCallbacks = false;
|
||||
if (moduleID)
|
||||
t->nt.gpreg = __KernelGetModuleGP(moduleID);
|
||||
else
|
||||
@ -863,10 +890,10 @@ void sceKernelGetThreadStackFreeSize()
|
||||
RETURN(sz & ~3);
|
||||
}
|
||||
|
||||
|
||||
void _sceKernelReturnFromThread()
|
||||
// Internal function
|
||||
void __KernelReturnFromThread()
|
||||
{
|
||||
INFO_LOG(HLE,"_sceKernelReturnFromThread : %s", currentThread->GetName());
|
||||
INFO_LOG(HLE,"__KernelReturnFromThread : %s", currentThread->GetName());
|
||||
currentThread->nt.exitStatus = currentThread->context.r[2];
|
||||
currentThread->nt.status = THREADSTATUS_DORMANT;
|
||||
|
||||
@ -935,17 +962,17 @@ void sceKernelExitDeleteThread()
|
||||
|
||||
u32 sceKernelSuspendDispatchThread()
|
||||
{
|
||||
u32 oldDispatchSuspended = dispatchSuspended;
|
||||
dispatchSuspended = true;
|
||||
u32 oldDispatchSuspended = !dispatchEnabled;
|
||||
dispatchEnabled = false;
|
||||
DEBUG_LOG(HLE,"%i=sceKernelSuspendDispatchThread()", oldDispatchSuspended);
|
||||
return oldDispatchSuspended;
|
||||
}
|
||||
|
||||
u32 sceKernelResumeDispatchThread(u32 suspended)
|
||||
{
|
||||
u32 oldDispatchSuspended = dispatchSuspended;
|
||||
dispatchSuspended = suspended;
|
||||
DEBUG_LOG(HLE,"%i=sceKernelResumeDispatchThread(%i)",oldDispatchSuspended, suspended);
|
||||
u32 oldDispatchSuspended = !dispatchEnabled;
|
||||
dispatchEnabled = !suspended;
|
||||
DEBUG_LOG(HLE,"%i=sceKernelResumeDispatchThread(%i)", oldDispatchSuspended, suspended);
|
||||
return oldDispatchSuspended;
|
||||
}
|
||||
|
||||
@ -1063,6 +1090,7 @@ void sceKernelDelayThreadCB()
|
||||
__KernelScheduleWakeup(curThread, usec);
|
||||
__KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, true);
|
||||
__KernelCheckCallbacks();
|
||||
__KernelExecutePendingMipsCalls();
|
||||
}
|
||||
|
||||
void sceKernelDelayThread()
|
||||
@ -1080,48 +1108,45 @@ void sceKernelDelayThread()
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void sceKernelWakeupThread()
|
||||
{
|
||||
SceUID id = PARAM(0);
|
||||
SceUID uid = PARAM(0);
|
||||
u32 error;
|
||||
Thread *t = kernelObjects.Get<Thread>(id, error);
|
||||
Thread *t = kernelObjects.Get<Thread>(uid, error);
|
||||
if (t)
|
||||
{
|
||||
t->nt.wakeupCount++;
|
||||
DEBUG_LOG(HLE,"sceKernelWakeupThread(%i) - wakeupCount incremented to %i",id,t->nt.wakeupCount);
|
||||
if (t->nt.waitType == WAITTYPE_SLEEP && t->nt.wakeupCount>=0)
|
||||
{
|
||||
__KernelResumeThread(id);
|
||||
if (t->nt.waitType != WAITTYPE_SLEEP) {
|
||||
t->nt.wakeupCount++;
|
||||
DEBUG_LOG(HLE,"sceKernelWakeupThread(%i) - wakeupCount incremented to %i", uid, t->nt.wakeupCount);
|
||||
RETURN(0);
|
||||
} else {
|
||||
__KernelResumeThreadFromWait(uid);
|
||||
__KernelReSchedule("wakeup");
|
||||
}
|
||||
}
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
static void __KernelSleepThread(bool doCallbacks) {
|
||||
DEBUG_LOG(HLE,"sceKernelSleepThread() - wakeupCount decremented to %i", currentThread->nt.wakeupCount);
|
||||
if (currentThread->nt.wakeupCount > 0) {
|
||||
currentThread->nt.wakeupCount--;
|
||||
RETURN(0);
|
||||
} else {
|
||||
RETURN(0);
|
||||
__KernelWaitCurThread(WAITTYPE_SLEEP, 0, 0, 0, doCallbacks);
|
||||
}
|
||||
}
|
||||
|
||||
void sceKernelSleepThread()
|
||||
{
|
||||
currentThread->nt.wakeupCount--;
|
||||
DEBUG_LOG(HLE,"sceKernelSleepThread() - wakeupCount decremented to %i", currentThread->nt.wakeupCount);
|
||||
if (currentThread->nt.wakeupCount < 0)
|
||||
__KernelWaitCurThread(WAITTYPE_SLEEP, 0, 0, 0, false);
|
||||
else
|
||||
{
|
||||
RETURN(0);
|
||||
}
|
||||
__KernelSleepThread(false);
|
||||
}
|
||||
|
||||
//the homebrew PollCallbacks
|
||||
void sceKernelSleepThreadCB()
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelSleepThreadCB()");
|
||||
//set it to waiting
|
||||
currentThread->nt.wakeupCount--;
|
||||
DEBUG_LOG(HLE,"sceKernelSleepThreadCB() - wakeupCount decremented to %i", currentThread->nt.wakeupCount);
|
||||
if (currentThread->nt.wakeupCount < 0) {
|
||||
__KernelWaitCurThread(WAITTYPE_SLEEP, 0, 0, 0, true);
|
||||
__KernelCheckCallbacks();
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN(0);
|
||||
}
|
||||
DEBUG_LOG(HLE, "sceKernelSleepThreadCB()");
|
||||
__KernelSleepThread(true);
|
||||
__KernelCheckCallbacks();
|
||||
__KernelExecutePendingMipsCalls();
|
||||
}
|
||||
|
||||
void sceKernelWaitThreadEnd()
|
||||
@ -1179,6 +1204,8 @@ void sceKernelResumeThread()
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CALLBACKS
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -1287,84 +1314,280 @@ void sceKernelReferCallbackStatus()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Context switches to the thread and executes the callback.
|
||||
u32 __KernelRunCallbackOnThread(SceUID cbId, Thread *thread)
|
||||
{
|
||||
if (g_inCbCount > 0) {
|
||||
WARN_LOG(HLE, "__KernelRunCallbackOnThread: Already in a callback!");
|
||||
// Owns outstanding MIPS calls and provides a way to get them by ID.
|
||||
// TODO: MipsCall structs are kinda big, try to cut down on the copying by owning pointers instead.
|
||||
class MipsCallManager {
|
||||
public:
|
||||
MipsCallManager() : idGen_(0) {}
|
||||
int add(MipsCall *call) {
|
||||
int id = genId();
|
||||
calls_.insert(std::pair<int, MipsCall *>(id, call));
|
||||
return id;
|
||||
}
|
||||
MipsCall *get(int id) {
|
||||
return calls_[id];
|
||||
}
|
||||
MipsCall *pop(int id) {
|
||||
MipsCall *temp = calls_[id];
|
||||
calls_.erase(id);
|
||||
return temp;
|
||||
}
|
||||
|
||||
private:
|
||||
int genId() { return ++idGen_; }
|
||||
std::map<int, MipsCall *> calls_;
|
||||
int idGen_;
|
||||
};
|
||||
|
||||
MipsCallManager mipsCalls;
|
||||
|
||||
|
||||
class ActionAfterMipsCall : public Action
|
||||
{
|
||||
public:
|
||||
virtual void run();
|
||||
Thread *thread;
|
||||
|
||||
// Saved thread state
|
||||
int status;
|
||||
WaitType waitType;
|
||||
int waitId;
|
||||
ThreadWaitInfo waitInfo;
|
||||
bool isProcessingCallbacks;
|
||||
|
||||
Action *chainedAction;
|
||||
};
|
||||
|
||||
void ActionAfterMipsCall::run() {
|
||||
thread->nt.status = status;
|
||||
thread->nt.waitType = waitType;
|
||||
thread->nt.waitID = waitId;
|
||||
thread->waitInfo = waitInfo;
|
||||
thread->isProcessingCallbacks = isProcessingCallbacks;
|
||||
|
||||
if (chainedAction) {
|
||||
chainedAction->run();
|
||||
delete chainedAction;
|
||||
}
|
||||
}
|
||||
|
||||
void __KernelSwitchContext(Thread *target, const char *reason)
|
||||
{
|
||||
if (currentThread) // It might just have been deleted.
|
||||
{
|
||||
__KernelSaveContext(¤tThread->context);
|
||||
DEBUG_LOG(HLE,"Context saved (%s): %i - %s - pc: %08x", reason, currentThread->GetUID(), currentThread->GetName(), currentMIPS->pc);
|
||||
}
|
||||
currentThread = target;
|
||||
__KernelLoadContext(¤tThread->context);
|
||||
DEBUG_LOG(HLE,"Context loaded (%s): %i - %s - pc: %08x", reason, currentThread->GetUID(), currentThread->GetName(), currentMIPS->pc);
|
||||
|
||||
__KernelExecutePendingMipsCalls();
|
||||
}
|
||||
|
||||
void __KernelChangeThreadState(Thread *thread, ThreadStatus newStatus) {
|
||||
if (!thread || thread->nt.status == newStatus)
|
||||
return;
|
||||
|
||||
if (!dispatchEnabled && thread == currentThread && newStatus != THREADSTATUS_RUNNING) {
|
||||
ERROR_LOG(HLE, "Dispatching suspended, not changing thread state");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: JPSCP has many conditions here, like removing wait timeout actions etc.
|
||||
// if (thread->nt.status == THREADSTATUS_WAIT && newStatus != THREADSTATUS_WAITSUSPEND) {
|
||||
|
||||
thread->nt.status = newStatus;
|
||||
|
||||
if (newStatus == THREADSTATUS_WAIT) {
|
||||
if (thread->nt.waitType == WAITTYPE_NONE) {
|
||||
ERROR_LOG(HLE, "Waittype none not allowed here");
|
||||
}
|
||||
|
||||
// Schedule deletion of stopped threads here. if (thread->isStopped())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool __CanExecuteCallbackNow(Thread *thread) {
|
||||
return g_inCbCount == 0;
|
||||
}
|
||||
|
||||
void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bool returnVoid, std::vector<int> args) {
|
||||
if (thread) {
|
||||
ActionAfterMipsCall *after = new ActionAfterMipsCall();
|
||||
after->chainedAction = afterAction;
|
||||
after->thread = thread;
|
||||
after->status = thread->nt.status;
|
||||
after->waitType = thread->nt.waitType;
|
||||
after->waitId = thread->nt.waitID;
|
||||
after->waitInfo = thread->waitInfo;
|
||||
|
||||
afterAction = after;
|
||||
|
||||
// Release thread from waiting
|
||||
thread->nt.waitType = WAITTYPE_NONE;
|
||||
|
||||
__KernelChangeThreadState(thread, THREADSTATUS_READY);
|
||||
}
|
||||
|
||||
MipsCall *call = new MipsCall();
|
||||
call->entryPoint = entryPoint;
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
call->args[i] = args[i];
|
||||
}
|
||||
call->numArgs = args.size();
|
||||
call->doAfter = afterAction;
|
||||
call->tag = "callAddress";
|
||||
|
||||
int callId = mipsCalls.add(call);
|
||||
|
||||
bool called = false;
|
||||
if (!thread || thread == currentThread) {
|
||||
if (__CanExecuteCallbackNow(thread)) {
|
||||
thread = currentThread;
|
||||
__KernelChangeThreadState(thread, THREADSTATUS_RUNNING);
|
||||
__KernelExecuteMipsCallOnCurrentThread(callId);
|
||||
called = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!called) {
|
||||
DEBUG_LOG(HLE, "Making mipscall pending on thread");
|
||||
thread->pendingMipsCalls.push_back(callId);
|
||||
}
|
||||
}
|
||||
|
||||
void __KernelExecuteMipsCallOnCurrentThread(int callId)
|
||||
{
|
||||
if (g_inCbCount > 0) {
|
||||
WARN_LOG(HLE, "__KernelExecuteMipsCallOnCurrentThread: Already in a callback!");
|
||||
}
|
||||
DEBUG_LOG(HLE, "Executing mipscall %i", callId);
|
||||
MipsCall *call = mipsCalls.get(callId);
|
||||
|
||||
// Save the few regs that need saving
|
||||
call->savedPc = currentMIPS->pc;
|
||||
call->savedRa = currentMIPS->r[MIPS_REG_RA];
|
||||
call->savedV0 = currentMIPS->r[MIPS_REG_V0];
|
||||
call->savedV1 = currentMIPS->r[MIPS_REG_V1];
|
||||
call->savedIdRegister = currentMIPS->r[MIPS_REG_CALL_ID];
|
||||
call->returnVoid = false;
|
||||
|
||||
// Set up the new state
|
||||
currentMIPS->pc = call->entryPoint;
|
||||
currentMIPS->r[MIPS_REG_RA] = __KernelMipsCallReturnAddress();
|
||||
currentMIPS->r[MIPS_REG_CALL_ID] = callId;
|
||||
for (int i = 0; i < call->numArgs; i++) {
|
||||
currentMIPS->r[MIPS_REG_A0 + i] = call->args[i];
|
||||
}
|
||||
|
||||
g_inCbCount++;
|
||||
}
|
||||
|
||||
void __KernelReturnFromMipsCall()
|
||||
{
|
||||
int callId = currentMIPS->r[MIPS_REG_CALL_ID];
|
||||
|
||||
MipsCall *call = mipsCalls.pop(callId);
|
||||
|
||||
// Value returned by the callback function
|
||||
u32 retVal = currentMIPS->r[MIPS_REG_V0];
|
||||
DEBUG_LOG(HLE,"__KernelReturnFromMipsCall(), returned %08x", retVal);
|
||||
|
||||
// Should also save/restore wait state here.
|
||||
if (call->doAfter)
|
||||
call->doAfter->run();
|
||||
|
||||
currentMIPS->pc = call->savedPc;
|
||||
currentMIPS->r[MIPS_REG_RA] = call->savedRa;
|
||||
currentMIPS->r[MIPS_REG_V0] = call->savedV0;
|
||||
currentMIPS->r[MIPS_REG_V1] = call->savedV1;
|
||||
currentMIPS->r[MIPS_REG_CALL_ID] = call->savedIdRegister;
|
||||
|
||||
g_inCbCount--;
|
||||
|
||||
// yeah! back in the real world, let's keep going. Should we process more callbacks?
|
||||
__KernelCheckCallbacks();
|
||||
if (!__KernelExecutePendingMipsCalls())
|
||||
{
|
||||
// We should definitely reschedule as we might still be asleep. - except if we came from checkcallbacks?
|
||||
__KernelReSchedule("return from callback");
|
||||
}
|
||||
}
|
||||
|
||||
bool __KernelExecutePendingMipsCalls()
|
||||
{
|
||||
Thread *thread = __GetCurrentThread();
|
||||
|
||||
if (thread->pendingMipsCalls.empty()) {
|
||||
// Nothing to do
|
||||
return false;
|
||||
}
|
||||
|
||||
if (__CanExecuteCallbackNow(thread))
|
||||
{
|
||||
// Pop off the first pending mips call
|
||||
int callId = thread->pendingMipsCalls.front();
|
||||
thread->pendingMipsCalls.pop_front();
|
||||
__KernelExecuteMipsCallOnCurrentThread(callId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
class ActionAfterCallback : public Action
|
||||
{
|
||||
public:
|
||||
ActionAfterCallback(SceUID cbId_) : cbId(cbId_) {}
|
||||
virtual void run();
|
||||
SceUID cbId;
|
||||
};
|
||||
|
||||
// Executes the callback, when it next is context switched to.
|
||||
void __KernelRunCallbackOnThread(SceUID cbId, Thread *thread)
|
||||
{
|
||||
u32 error;
|
||||
Callback *cb = kernelObjects.Get<Callback>(cbId, error);
|
||||
if (!cb) {
|
||||
return error;
|
||||
ERROR_LOG(HLE, "__KernelRunCallbackOnThread: Bad cbId %i", cbId);
|
||||
return;
|
||||
}
|
||||
|
||||
// First, context switch to the thread.
|
||||
Thread *curThread = __GetCurrentThread();
|
||||
if (thread != curThread) {
|
||||
__KernelSaveContext(&curThread->context);
|
||||
__KernelLoadContext(&thread->context);
|
||||
}
|
||||
|
||||
//Alright, we're on the right thread
|
||||
DEBUG_LOG(HLE, "__KernelRunCallbackOnThread: Turning callback %i into pending mipscall", cbId);
|
||||
|
||||
// Save the few regs that need saving
|
||||
cb->savedPC = currentMIPS->pc;
|
||||
cb->savedRA = currentMIPS->r[MIPS_REG_RA];
|
||||
cb->savedV0 = currentMIPS->r[MIPS_REG_V0];
|
||||
cb->savedV1 = currentMIPS->r[MIPS_REG_V1];
|
||||
cb->savedIdRegister = currentMIPS->r[MIPS_REG_CB_ID];
|
||||
// Alright, we're on the right thread
|
||||
// Should save/restore wait state?
|
||||
|
||||
// Set up the new state
|
||||
// TODO: check?
|
||||
currentMIPS->r[MIPS_REG_A0] = cb->nc.notifyCount;
|
||||
currentMIPS->r[MIPS_REG_A1] = cb->nc.notifyArg;
|
||||
currentMIPS->r[MIPS_REG_A2] = cb->nc.commonArgument;
|
||||
currentMIPS->pc = cb->nc.entrypoint;
|
||||
currentMIPS->r[MIPS_REG_RA] = __KernelCallbackReturnAddress();
|
||||
currentMIPS->r[MIPS_REG_CB_ID] = cbId;
|
||||
std::vector<int> args;
|
||||
args.push_back(cb->nc.notifyCount);
|
||||
args.push_back(cb->nc.notifyArg);
|
||||
args.push_back(cb->nc.commonArgument);
|
||||
|
||||
// Clear the notify count / arg
|
||||
cb->nc.notifyCount = 0;
|
||||
cb->nc.notifyArg = 0;
|
||||
|
||||
g_inCbCount++;
|
||||
return 0;
|
||||
Action *action = new ActionAfterCallback(cbId);
|
||||
__KernelCallAddress(thread, cb->nc.entrypoint, action, false, args);
|
||||
}
|
||||
|
||||
void _sceKernelReturnFromCallback()
|
||||
{
|
||||
SceUID cbId = currentMIPS->r[MIPS_REG_CB_ID];
|
||||
// Value returned by the callback function
|
||||
u32 retVal = currentMIPS->r[MIPS_REG_V0];
|
||||
DEBUG_LOG(HLE,"_sceKernelReturnFromCallback(cbId=%i), returned %08x", cbId, retVal);
|
||||
|
||||
u32 error;
|
||||
Callback *cb = kernelObjects.Get<Callback>(cbId, error);
|
||||
if (!cb)
|
||||
{
|
||||
ERROR_LOG(HLE, "_sceKernelReturnFromCallback(): INVALID CBID %i in register! we're screwed", cbId);
|
||||
return;
|
||||
void ActionAfterCallback::run() {
|
||||
if (cbId != -1) {
|
||||
u32 error;
|
||||
Callback *cb = kernelObjects.Get<Callback>(cbId, error);
|
||||
if (cb)
|
||||
{
|
||||
DEBUG_LOG(HLE, "Left callback %i - %s", cbId, cb->nc.name);
|
||||
// Callbacks that don't return 0 are deleted. But should this be done here?
|
||||
if (currentMIPS->r[MIPS_REG_V0] != 0 || cb->forceDelete)
|
||||
{
|
||||
DEBUG_LOG(HLE, "ActionAfterCallback::run(): Callback returned non-zero, gets deleted!");
|
||||
kernelObjects.Destroy<Callback>(cbId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentMIPS->pc = cb->savedPC;
|
||||
currentMIPS->r[MIPS_REG_RA] = cb->savedRA;
|
||||
currentMIPS->r[MIPS_REG_V0] = cb->savedV0;
|
||||
currentMIPS->r[MIPS_REG_V1] = cb->savedV1;
|
||||
currentMIPS->r[MIPS_REG_CB_ID] = cb->savedIdRegister;
|
||||
|
||||
// Callbacks that don't return 0 are deleted. But should this be done here?
|
||||
if (retVal != 0 || cb->forceDelete)
|
||||
{
|
||||
DEBUG_LOG(HLE, "_sceKernelReturnFromCallback(): Callback returned non-zero, gets deleted!");
|
||||
kernelObjects.Destroy<Callback>(cbId);
|
||||
}
|
||||
|
||||
g_inCbCount--;
|
||||
|
||||
// yeah! back in the real world, let's keep going. Should we process more callbacks?
|
||||
}
|
||||
|
||||
// Check callbacks on the current thread only.
|
||||
@ -1377,7 +1600,7 @@ bool __KernelCheckThreadCallbacks(Thread *thread) {
|
||||
if (thread->readyCallbacks[i].size()) {
|
||||
SceUID readyCallback = thread->readyCallbacks[i].front();
|
||||
thread->readyCallbacks[i].pop_front();
|
||||
__KernelRunCallbackOnThread(readyCallback, thread);
|
||||
__KernelRunCallbackOnThread(readyCallback, thread); // makes pending
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1386,7 +1609,8 @@ bool __KernelCheckThreadCallbacks(Thread *thread) {
|
||||
|
||||
// Checks for callbacks on all threads
|
||||
bool __KernelCheckCallbacks() {
|
||||
SceUID currentThread = __KernelGetCurThread();
|
||||
// SceUID currentThread = __KernelGetCurThread();
|
||||
// currentThread->isProcessingCallbacks = true;
|
||||
// do {
|
||||
bool processed = false;
|
||||
|
||||
@ -1400,25 +1624,25 @@ bool __KernelCheckCallbacks() {
|
||||
return processed;
|
||||
}
|
||||
|
||||
u32 sceKernelCheckCallback()
|
||||
{
|
||||
void sceKernelCheckCallback() {
|
||||
Thread *curThread = __GetCurrentThread();
|
||||
|
||||
// This thread can now process callbacks.
|
||||
curThread->isProcessingCallbacks = true;
|
||||
|
||||
int callbacksProcessed = __KernelCheckThreadCallbacks(curThread) ? 1 : 0;
|
||||
bool callbacksProcessed = __KernelCheckThreadCallbacks(curThread);
|
||||
|
||||
// Note - same thread as above - checking callbacks may switch threads.
|
||||
curThread->isProcessingCallbacks = false;
|
||||
|
||||
if (callbacksProcessed) {
|
||||
RETURN(1);
|
||||
ERROR_LOG(HLE,"sceKernelCheckCallback() - processed a callback.");
|
||||
__KernelExecutePendingMipsCalls();
|
||||
} else {
|
||||
RETURN(0);
|
||||
DEBUG_LOG(HLE,"sceKernelCheckCallback() - no callbacks to process, doing nothing");
|
||||
}
|
||||
|
||||
return callbacksProcessed;
|
||||
}
|
||||
|
||||
bool __KernelInCallback()
|
||||
|
@ -106,8 +106,7 @@ u32 __KernelResumeThread(SceUID threadID); // can return an error value
|
||||
u32 __KernelGetWaitValue(SceUID threadID, u32 &error);
|
||||
void __KernelWaitCurThread(WaitType type, SceUID waitId, u32 waitValue, int timeout, bool processCallbacks);
|
||||
void __KernelReSchedule(const char *reason = "no reason");
|
||||
|
||||
|
||||
void __KernelReSchedule(bool doCallbacks, const char *reason);
|
||||
|
||||
// Registered callback types
|
||||
enum RegisteredCallbackType {
|
||||
@ -133,12 +132,12 @@ u32 __KernelNotifyCallbackType(RegisteredCallbackType type, SceUID cbId, int not
|
||||
SceUID __KernelGetCurThread();
|
||||
void __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();
|
||||
void __KernelReturnFromThread(); // Called as HLE function
|
||||
|
||||
void _sceKernelReturnFromThread();
|
||||
void _sceKernelIdle();
|
||||
|
||||
u32 __KernelCallbackReturnAddress();
|
||||
u32 __KernelInterruptReturnAddress();
|
||||
u32 __KernelMipsCallReturnAddress();
|
||||
u32 __KernelInterruptReturnAddress(); // TODO: remove
|
||||
|
||||
// Internal access - used by sceSetGeCallback
|
||||
u32 __KernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg);
|
||||
@ -148,11 +147,46 @@ void sceKernelDeleteCallback();
|
||||
void sceKernelNotifyCallback();
|
||||
void sceKernelCancelCallback();
|
||||
void sceKernelGetCallbackCount();
|
||||
void _sceKernelReturnFromCallback();
|
||||
u32 sceKernelCheckCallback();
|
||||
void sceKernelCheckCallback();
|
||||
void sceKernelGetCallbackCount();
|
||||
void sceKernelReferCallbackStatus();
|
||||
void __KernelReturnFromMipsCall(); // Called as HLE function
|
||||
bool __KernelInCallback();
|
||||
|
||||
// Should be called by (nearly) all ...CB functions.
|
||||
bool __KernelCheckCallbacks();
|
||||
class Thread;
|
||||
void __KernelSwitchContext(Thread *target, const char *reason);
|
||||
u32 __KernelResumeThreadFromWait(SceUID threadID);
|
||||
bool __KernelExecutePendingMipsCalls();
|
||||
|
||||
// A call into game code. These can be pending on a thread.
|
||||
// Similar to Callback-s (NOT CallbackInfos) in JPCSP.
|
||||
class Action;
|
||||
struct MipsCall {
|
||||
u32 entryPoint;
|
||||
u32 cbId;
|
||||
u32 args[6];
|
||||
int numArgs;
|
||||
Action *doAfter;
|
||||
u32 savedIdRegister;
|
||||
u32 savedRa;
|
||||
u32 savedPc;
|
||||
u32 savedV0;
|
||||
u32 savedV1;
|
||||
bool returnVoid;
|
||||
const char *tag;
|
||||
};
|
||||
enum ThreadStatus
|
||||
{
|
||||
THREADSTATUS_RUNNING = 1,
|
||||
THREADSTATUS_READY = 2,
|
||||
THREADSTATUS_WAIT = 4,
|
||||
THREADSTATUS_SUSPEND = 8,
|
||||
THREADSTATUS_DORMANT = 16,
|
||||
THREADSTATUS_DEAD = 32,
|
||||
|
||||
THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
|
||||
};
|
||||
|
||||
void __KernelChangeThreadState(Thread *thread, ThreadStatus newStatus);
|
||||
|
@ -70,5 +70,6 @@ void sceKernelSetVTimerHandler()
|
||||
// Not sure why this is exposed...
|
||||
void _sceKernelReturnFromTimerHandler()
|
||||
{
|
||||
DEBUG_LOG(HLE,"_sceKernelReturnFromTimerHandler");
|
||||
|
||||
}
|
||||
|
@ -53,6 +53,12 @@ void sceMpegRingbufferConstruct()
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void sceMpegRegistStream()
|
||||
{
|
||||
DEBUG_LOG(HLE, "HACK sceMpegRegistStream(...)");
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
const HLEFunction sceMpeg[] =
|
||||
{
|
||||
{0xe1ce83a7,0,"sceMpegGetAtracAu"},
|
||||
@ -62,7 +68,7 @@ const HLEFunction sceMpeg[] =
|
||||
{0xc132e22f,sceMpegQueryMemSize,"sceMpegQueryMemSize"},
|
||||
{0x21ff80e4,0,"sceMpegQueryStreamOffset"},
|
||||
{0x611e9e11,0,"sceMpegQueryStreamSize"},
|
||||
{0x42560f23,0,"sceMpegRegistStream"},
|
||||
{0x42560f23,sceMpegRegistStream,"sceMpegRegistStream"},
|
||||
{0x591a4aa2,0,"sceMpegUnRegistStream"},
|
||||
{0x707b7629,0,"sceMpegFlushAllStream"},
|
||||
{0xa780cf7e,0,"sceMpegMallocAvcEsBuf"},
|
||||
|
@ -464,6 +464,14 @@ const HLEFunction sceUtility[] =
|
||||
{0xAB083EA9, 0, "sceUtilityScreenshotUpdate"},
|
||||
{0xD81957B7, 0, "sceUtilityScreenshotGetStatus"},
|
||||
{0x86A03A27, 0, "sceUtilityScreenshotContStart"},
|
||||
|
||||
{0x0D5BC6D2, 0, "sceUtilityLoadUsbModule"},
|
||||
{0xF64910F0, 0, "sceUtilityUnloadUsbModule"},
|
||||
|
||||
{0x24AC31EB, 0, "sceUtilityGamedataInstallInitStart"},
|
||||
{0x32E32DCB, 0, "sceUtilityGamedataInstallShutdownStart"},
|
||||
{0x4AECD179, 0, "sceUtilityGamedataInstallUpdate"},
|
||||
{0xB57E95D9, 0, "sceUtilityGamedataInstallGetStatus"},
|
||||
};
|
||||
|
||||
void Register_sceUtility()
|
||||
|
@ -50,8 +50,8 @@ enum
|
||||
MIPS_REG_FP=30,
|
||||
MIPS_REG_RA=31,
|
||||
|
||||
// ID for callback is stored here - from JPCSP
|
||||
MIPS_REG_CB_ID=MIPS_REG_S0,
|
||||
// ID for mipscall "callback" is stored here - from JPCSP
|
||||
MIPS_REG_CALL_ID=MIPS_REG_S0,
|
||||
};
|
||||
|
||||
enum
|
||||
|
Loading…
Reference in New Issue
Block a user