Add a registry for actions so they can be stated.

Also add late loaders to ensure things are hooked up properly.
This commit is contained in:
Unknown W. Brackets 2012-12-27 19:30:36 -08:00
parent f5dd7f03e8
commit a8c9c31e16
7 changed files with 257 additions and 35 deletions

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include "ChunkFile.h"
// Sometimes you want to set something to happen later, without that later place really needing // Sometimes you want to set something to happen later, without that later place really needing
// to know about all the things that might happen. That's when you use an Action, and add it // to know about all the things that might happen. That's when you use an Action, and add it
@ -17,4 +18,6 @@ class Action
public: public:
virtual ~Action() {} virtual ~Action() {}
virtual void run() = 0; virtual void run() = 0;
virtual void DoState(PointerWrap &p) = 0;
int actionTypeID;
}; };

View file

@ -143,10 +143,9 @@ void __KernelDoState(PointerWrap &p)
kernelObjects.DoState(p); kernelObjects.DoState(p);
p.DoMarker("KernelObjects"); p.DoMarker("KernelObjects");
// TODO: Put these in the correct order...
__InterruptsDoState(p); __InterruptsDoState(p);
__KernelMemoryDoState(p); __KernelMemoryDoState(p);
// TODO: __KernelThreadingDoState(p); __KernelThreadingDoState(p);
__KernelAlarmDoState(p); __KernelAlarmDoState(p);
__KernelEventFlagDoState(p); __KernelEventFlagDoState(p);
__KernelMbxDoState(p); __KernelMbxDoState(p);
@ -155,6 +154,9 @@ void __KernelDoState(PointerWrap &p)
__KernelSemaDoState(p); __KernelSemaDoState(p);
// TODO: non-kernel modules // TODO: non-kernel modules
// TODO: PPGe // TODO: PPGe
__InterruptsDoStateLate(p);
__KernelThreadingDoStateLate(p);
} }
bool __KernelIsRunning() { bool __KernelIsRunning() {

View file

@ -247,14 +247,20 @@ void __InterruptsDoState(PointerWrap &p)
} }
intState.DoState(p); intState.DoState(p);
for (int i = 0; i < PSP_NUMBER_INTERRUPTS; ++i)
intrHandlers[i].DoState(p);
p.Do(pendingInterrupts, PendingInterrupt(0, 0)); p.Do(pendingInterrupts, PendingInterrupt(0, 0));
p.Do(interruptsEnabled); p.Do(interruptsEnabled);
p.Do(inInterrupt); p.Do(inInterrupt);
p.DoMarker("sceKernelInterrupt"); p.DoMarker("sceKernelInterrupt");
} }
void __InterruptsDoStateLate(PointerWrap &p)
{
// We do these later to ensure the handlers have been registered.
for (int i = 0; i < PSP_NUMBER_INTERRUPTS; ++i)
intrHandlers[i].DoState(p);
p.DoMarker("sceKernelInterrupt Late");
}
void __InterruptsShutdown() void __InterruptsShutdown()
{ {
for (int i = 0; i < PSP_NUMBER_INTERRUPTS; ++i) for (int i = 0; i < PSP_NUMBER_INTERRUPTS; ++i)

View file

@ -109,6 +109,7 @@ typedef SubIntrHandler *(*SubIntrCreator)();
bool __IsInInterrupt(); bool __IsInInterrupt();
void __InterruptsInit(); void __InterruptsInit();
void __InterruptsDoState(PointerWrap &p); void __InterruptsDoState(PointerWrap &p);
void __InterruptsDoStateLate(PointerWrap &p);
void __InterruptsShutdown(); void __InterruptsShutdown();
void __TriggerInterrupt(int type, PSPInterrupt intno, int subInterrupts = -1); void __TriggerInterrupt(int type, PSPInterrupt intno, int subInterrupts = -1);
void __TriggerInterruptWithArg(int type, PSPInterrupt intno, int subintr, int arg); // For GE "callbacks" void __TriggerInterruptWithArg(int type, PSPInterrupt intno, int subintr, int arg); // For GE "callbacks"

View file

@ -136,6 +136,25 @@ KernelObject *__KernelModuleObject()
return new Module; return new Module;
} }
class AfterModuleEntryCall : public Action {
public:
AfterModuleEntryCall() {}
SceUID moduleID_;
u32 retValAddr;
virtual void run();
virtual void DoState(PointerWrap &p) {
p.Do(moduleID_);
p.Do(retValAddr);
}
static Action *Create() {
return new AfterModuleEntryCall;
}
};
void AfterModuleEntryCall::run() {
Memory::Write_U32(retValAddr, currentMIPS->r[2]);
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// MODULES // MODULES
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -168,13 +187,21 @@ struct SceKernelSMOption {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// STATE BEGIN // STATE BEGIN
static int actionAfterModule;
static SceUID mainModuleID; // hack static SceUID mainModuleID; // hack
// STATE END // STATE END
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void __KernelModuleInit()
{
actionAfterModule = __KernelRegisterActionType(AfterModuleEntryCall::Create);
}
void __KernelModuleDoState(PointerWrap &p) void __KernelModuleDoState(PointerWrap &p)
{ {
p.Do(mainModuleID); p.Do(mainModuleID);
p.Do(actionAfterModule);
__KernelRestoreActionType(actionAfterModule, AfterModuleEntryCall::Create);
p.DoMarker("sceKernelModule"); p.DoMarker("sceKernelModule");
} }
@ -533,6 +560,7 @@ bool __KernelLoadExec(const char *filename, SceKernelLoadExecParam *param, std::
if (__KernelIsRunning()) if (__KernelIsRunning())
__KernelShutdown(); __KernelShutdown();
__KernelModuleInit();
__KernelInit(); __KernelInit();
PSPFileInfo info = pspFileSystem.GetFileInfo(filename); PSPFileInfo info = pspFileSystem.GetFileInfo(filename);
@ -657,18 +685,6 @@ u32 sceKernelLoadModule(const char *name, u32 flags)
return module->GetUID(); return module->GetUID();
} }
class AfterModuleEntryCall : public Action {
public:
AfterModuleEntryCall() {}
SceUID moduleID_;
u32 retValAddr;
virtual void run();
};
void AfterModuleEntryCall::run() {
Memory::Write_U32(retValAddr, currentMIPS->r[2]);
}
void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, u32 optionAddr) void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, u32 optionAddr)
{ {
ERROR_LOG(HLE,"UNIMPL sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)", ERROR_LOG(HLE,"UNIMPL sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)",

View file

@ -193,13 +193,62 @@ public:
return temp; return temp;
} }
void clear() { void clear() {
// TODO: Should this delete them? (it should probably just own them.)
calls_.clear(); calls_.clear();
idGen_ = 0; idGen_ = 0;
} }
int registerType(ActionCreator creator) {
types_.push_back(creator);
return types_.size() - 1;
}
void restoreType(int actionType, ActionCreator creator) {
if (actionType >= (int) types_.size())
types_.resize(actionType + 1, NULL);
types_[actionType] = creator;
}
Action *createByType(int actionType) {
if (actionType < (int) types_.size() && types_[actionType] != NULL) {
Action *a = types_[actionType]();
a->actionTypeID = actionType;
return a;
}
return NULL;
}
void DoState(PointerWrap &p) {
p.Do(idGen_);
size_t n = (int) calls_.size();
p.Do(n);
if (p.mode == p.MODE_READ) {
// TODO: Delete them?
calls_.clear();
for (size_t i = 0; i < n; ++i) {
int k;
p.Do(k);
// TODO: Presumably leaks? MipsCallManager may need to own these.
MipsCall *call = new MipsCall();
call->DoState(p);
calls_[k] = call;
}
} else {
std::map<int, MipsCall *>::iterator it, end;
for (it = calls_.begin(), end = calls_.end(); it != end; ++it) {
p.Do(it->first);
it->second->DoState(p);
}
}
p.DoMarker("MipsCallManager");
}
private: private:
int genId() { return ++idGen_; } int genId() { return ++idGen_; }
std::map<int, MipsCall *> calls_; std::map<int, MipsCall *> calls_;
std::vector<ActionCreator> types_;
int idGen_; int idGen_;
}; };
@ -207,7 +256,37 @@ class ActionAfterMipsCall : public Action
{ {
public: public:
virtual void run(); virtual void run();
Thread *thread;
static Action *Create()
{
return new ActionAfterMipsCall;
}
virtual void DoState(PointerWrap &p)
{
p.Do(threadID);
p.Do(status);
p.Do(waitType);
p.Do(waitID);
p.Do(waitInfo);
p.Do(isProcessingCallbacks);
p.DoMarker("ActionAfterMipsCall");
int chainedActionType = 0;
if (chainedAction != NULL)
chainedActionType = chainedAction->actionTypeID;
p.Do(chainedActionType);
if (chainedActionType != 0)
{
if (p.mode == p.MODE_READ)
chainedAction = __KernelCreateAction(chainedActionType);
chainedAction->DoState(p);
}
}
SceUID threadID;
// Saved thread state // Saved thread state
int status; int status;
@ -219,6 +298,31 @@ public:
Action *chainedAction; Action *chainedAction;
}; };
class ActionAfterCallback : public Action
{
public:
ActionAfterCallback() {}
virtual void run();
static Action *Create()
{
return new ActionAfterCallback;
}
void setCallback(SceUID cbId_)
{
cbId = cbId_;
}
void DoState(PointerWrap &p)
{
p.Do(cbId);
p.DoMarker("ActionAfterCallback");
}
SceUID cbId;
};
class Thread : public KernelObject class Thread : public KernelObject
{ {
public: public:
@ -383,6 +487,8 @@ int eventScheduledWakeup;
bool dispatchEnabled = true; bool dispatchEnabled = true;
MipsCallManager mipsCalls; MipsCallManager mipsCalls;
int actionAfterCallback;
int actionAfterMipsCall;
// This seems nasty // This seems nasty
SceUID curModule; SceUID curModule;
@ -391,6 +497,50 @@ SceUID curModule;
//STATE END //STATE END
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
int __KernelRegisterActionType(ActionCreator creator)
{
return mipsCalls.registerType(creator);
}
void __KernelRestoreActionType(int actionType, ActionCreator creator)
{
mipsCalls.restoreType(actionType, creator);
}
Action *__KernelCreateAction(int actionType)
{
return mipsCalls.createByType(actionType);
}
void MipsCall::DoState(PointerWrap &p)
{
p.Do(entryPoint);
p.Do(cbId);
p.DoArray(args, ARRAY_SIZE(args));
p.Do(numArgs);
p.Do(savedIdRegister);
p.Do(savedRa);
p.Do(savedPc);
p.Do(savedV0);
p.Do(savedV1);
p.Do(returnVoid);
p.Do(tag);
p.Do(savedId);
p.Do(reschedAfter);
p.DoMarker("MipsCall");
int actionTypeID = 0;
if (doAfter != NULL)
actionTypeID = doAfter->actionTypeID;
p.Do(actionTypeID);
if (actionTypeID != 0)
{
if (p.mode == p.MODE_READ)
doAfter = __KernelCreateAction(actionTypeID);
doAfter->DoState(p);
}
}
// TODO: Should move to this wrapper so we can keep the current thread as a SceUID instead // TODO: Should move to this wrapper so we can keep the current thread as a SceUID instead
// of a dangerous raw pointer. // of a dangerous raw pointer.
@ -443,6 +593,8 @@ void __KernelThreadingInit()
WriteSyscall("FakeSysCalls", NID_INTERRUPTRETURN, intReturnHackAddr); WriteSyscall("FakeSysCalls", NID_INTERRUPTRETURN, intReturnHackAddr);
eventScheduledWakeup = CoreTiming::RegisterEvent("ScheduledWakeup", &hleScheduledWakeup); eventScheduledWakeup = CoreTiming::RegisterEvent("ScheduledWakeup", &hleScheduledWakeup);
actionAfterMipsCall = __KernelRegisterActionType(ActionAfterMipsCall::Create);
actionAfterCallback = __KernelRegisterActionType(ActionAfterCallback::Create);
// Create the two idle threads, as well. With the absolute minimal possible priority. // Create the two idle threads, as well. With the absolute minimal possible priority.
// 4096 stack size - don't know what the right value is. Hm, if callbacks are ever to run on these threads... // 4096 stack size - don't know what the right value is. Hm, if callbacks are ever to run on these threads...
@ -453,6 +605,37 @@ void __KernelThreadingInit()
__KernelListenThreadEnd(__KernelCancelWakeup); __KernelListenThreadEnd(__KernelCancelWakeup);
} }
void __KernelThreadingDoState(PointerWrap &p)
{
p.Do(g_inCbCount);
p.Do(idleThreadHackAddr);
p.Do(threadReturnHackAddr);
p.Do(cbReturnHackAddr);
p.Do(intReturnHackAddr);
p.Do(currentThread);
p.Do(threadqueue);
p.DoArray(threadIdleID, ARRAY_SIZE(threadIdleID));
p.Do(dispatchEnabled);
p.Do(curModule);
p.Do(eventScheduledWakeup);
CoreTiming::RestoreRegisterEvent(eventScheduledWakeup, "ScheduledWakeup", &hleScheduledWakeup);
p.Do(actionAfterMipsCall);
__KernelRestoreActionType(actionAfterMipsCall, ActionAfterMipsCall::Create);
p.Do(actionAfterCallback);
__KernelRestoreActionType(actionAfterCallback, ActionAfterCallback::Create);
p.DoMarker("sceKernelThread");
}
void __KernelThreadingDoStateLate(PointerWrap &p)
{
// We do this late to give modules time to register actions.
mipsCalls.DoState(p);
p.DoMarker("sceKernelThread Late");
}
KernelObject *__KernelThreadObject() KernelObject *__KernelThreadObject()
{ {
return new Thread; return new Thread;
@ -1698,11 +1881,15 @@ void sceKernelReferCallbackStatus()
} }
void ActionAfterMipsCall::run() { void ActionAfterMipsCall::run() {
thread->nt.status = status; u32 error;
thread->nt.waitType = waitType; Thread *thread = kernelObjects.Get<Thread>(threadID, error);
thread->nt.waitID = waitID; if (thread) {
thread->waitInfo = waitInfo; thread->nt.status = status;
thread->isProcessingCallbacks = isProcessingCallbacks; thread->nt.waitType = waitType;
thread->nt.waitID = waitID;
thread->waitInfo = waitInfo;
thread->isProcessingCallbacks = isProcessingCallbacks;
}
if (chainedAction) { if (chainedAction) {
chainedAction->run(); chainedAction->run();
@ -1877,9 +2064,9 @@ bool __CanExecuteCallbackNow(Thread *thread) {
void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bool returnVoid, std::vector<int> args, bool reschedAfter) void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bool returnVoid, std::vector<int> args, bool reschedAfter)
{ {
if (thread) { if (thread) {
ActionAfterMipsCall *after = new ActionAfterMipsCall(); ActionAfterMipsCall *after = (ActionAfterMipsCall *) __KernelCreateAction(actionAfterMipsCall);
after->chainedAction = afterAction; after->chainedAction = afterAction;
after->thread = thread; after->threadID = thread->GetUID();
after->status = thread->nt.status; after->status = thread->nt.status;
after->waitType = thread->nt.waitType; after->waitType = thread->nt.waitType;
after->waitID = thread->nt.waitID; after->waitID = thread->nt.waitID;
@ -1986,6 +2173,7 @@ void __KernelReturnFromMipsCall()
// Should also save/restore wait state here. // Should also save/restore wait state here.
if (call->doAfter) if (call->doAfter)
call->doAfter->run(); call->doAfter->run();
// TODO: Do we need to delete call->doAfter?
currentMIPS->pc = call->savedPc; currentMIPS->pc = call->savedPc;
currentMIPS->r[MIPS_REG_RA] = call->savedRa; currentMIPS->r[MIPS_REG_RA] = call->savedRa;
@ -2005,6 +2193,8 @@ void __KernelReturnFromMipsCall()
if (call->reschedAfter || threadReady == 0) if (call->reschedAfter || threadReady == 0)
__KernelReSchedule("return from callback"); __KernelReSchedule("return from callback");
} }
// TODO: Do we need to delete call?
} }
bool __KernelExecutePendingMipsCalls(bool reschedAfter) bool __KernelExecutePendingMipsCalls(bool reschedAfter)
@ -2027,15 +2217,6 @@ bool __KernelExecutePendingMipsCalls(bool reschedAfter)
return false; 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. // Executes the callback, when it next is context switched to.
void __KernelRunCallbackOnThread(SceUID cbId, Thread *thread, bool reschedAfter) void __KernelRunCallbackOnThread(SceUID cbId, Thread *thread, bool reschedAfter)
{ {
@ -2060,7 +2241,12 @@ void __KernelRunCallbackOnThread(SceUID cbId, Thread *thread, bool reschedAfter)
cb->nc.notifyCount = 0; cb->nc.notifyCount = 0;
cb->nc.notifyArg = 0; cb->nc.notifyArg = 0;
Action *action = new ActionAfterCallback(cbId); ActionAfterCallback *action = (ActionAfterCallback *) __KernelCreateAction(actionAfterCallback);
if (action != NULL)
action->setCallback(cbId);
else
ERROR_LOG(HLE, "Something went wrong creating a restore action for a callback.");
__KernelCallAddress(thread, cb->nc.entrypoint, action, false, args, reschedAfter); __KernelCallAddress(thread, cb->nc.entrypoint, action, false, args, reschedAfter);
} }

View file

@ -97,6 +97,8 @@ struct ThreadContext
// Internal API, used by implementations of kernel functions // Internal API, used by implementations of kernel functions
void __KernelThreadingInit(); void __KernelThreadingInit();
void __KernelThreadingDoState(PointerWrap &p);
void __KernelThreadingDoStateLate(PointerWrap &p);
void __KernelThreadingShutdown(); void __KernelThreadingShutdown();
KernelObject *__KernelThreadObject(); KernelObject *__KernelThreadObject();
KernelObject *__KernelCallbackObject(); KernelObject *__KernelCallbackObject();
@ -184,6 +186,10 @@ bool __KernelSwitchOffThread(const char *reason);
// A call into game code. These can be pending on a thread. // A call into game code. These can be pending on a thread.
// Similar to Callback-s (NOT CallbackInfos) in JPCSP. // Similar to Callback-s (NOT CallbackInfos) in JPCSP.
class Action; class Action;
typedef Action *(*ActionCreator)();
Action *__KernelCreateAction(int actionType);
int __KernelRegisterActionType(ActionCreator creator);
void __KernelRestoreActionType(int actionType, ActionCreator creator);
struct MipsCall { struct MipsCall {
u32 entryPoint; u32 entryPoint;
u32 cbId; u32 cbId;
@ -196,9 +202,11 @@ struct MipsCall {
u32 savedV0; u32 savedV0;
u32 savedV1; u32 savedV1;
bool returnVoid; bool returnVoid;
const char *tag; std::string tag;
u32 savedId; u32 savedId;
bool reschedAfter; bool reschedAfter;
void DoState(PointerWrap &p);
}; };
enum ThreadStatus enum ThreadStatus
{ {