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
#include <vector>
#include "ChunkFile.h"
// 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
@ -17,4 +18,6 @@ class Action
public:
virtual ~Action() {}
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);
p.DoMarker("KernelObjects");
// TODO: Put these in the correct order...
__InterruptsDoState(p);
__KernelMemoryDoState(p);
// TODO: __KernelThreadingDoState(p);
__KernelThreadingDoState(p);
__KernelAlarmDoState(p);
__KernelEventFlagDoState(p);
__KernelMbxDoState(p);
@ -155,6 +154,9 @@ void __KernelDoState(PointerWrap &p)
__KernelSemaDoState(p);
// TODO: non-kernel modules
// TODO: PPGe
__InterruptsDoStateLate(p);
__KernelThreadingDoStateLate(p);
}
bool __KernelIsRunning() {

View File

@ -247,14 +247,20 @@ void __InterruptsDoState(PointerWrap &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(interruptsEnabled);
p.Do(inInterrupt);
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()
{
for (int i = 0; i < PSP_NUMBER_INTERRUPTS; ++i)

View File

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

View File

@ -136,6 +136,25 @@ KernelObject *__KernelModuleObject()
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
//////////////////////////////////////////////////////////////////////////
@ -168,13 +187,21 @@ struct SceKernelSMOption {
//////////////////////////////////////////////////////////////////////////
// STATE BEGIN
static int actionAfterModule;
static SceUID mainModuleID; // hack
// STATE END
//////////////////////////////////////////////////////////////////////////
void __KernelModuleInit()
{
actionAfterModule = __KernelRegisterActionType(AfterModuleEntryCall::Create);
}
void __KernelModuleDoState(PointerWrap &p)
{
p.Do(mainModuleID);
p.Do(actionAfterModule);
__KernelRestoreActionType(actionAfterModule, AfterModuleEntryCall::Create);
p.DoMarker("sceKernelModule");
}
@ -533,6 +560,7 @@ bool __KernelLoadExec(const char *filename, SceKernelLoadExecParam *param, std::
if (__KernelIsRunning())
__KernelShutdown();
__KernelModuleInit();
__KernelInit();
PSPFileInfo info = pspFileSystem.GetFileInfo(filename);
@ -657,18 +685,6 @@ u32 sceKernelLoadModule(const char *name, u32 flags)
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)
{
ERROR_LOG(HLE,"UNIMPL sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)",

View File

@ -193,13 +193,62 @@ public:
return temp;
}
void clear() {
// TODO: Should this delete them? (it should probably just own them.)
calls_.clear();
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:
int genId() { return ++idGen_; }
std::map<int, MipsCall *> calls_;
std::vector<ActionCreator> types_;
int idGen_;
};
@ -207,7 +256,37 @@ class ActionAfterMipsCall : public Action
{
public:
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
int status;
@ -219,6 +298,31 @@ public:
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
{
public:
@ -383,6 +487,8 @@ int eventScheduledWakeup;
bool dispatchEnabled = true;
MipsCallManager mipsCalls;
int actionAfterCallback;
int actionAfterMipsCall;
// This seems nasty
SceUID curModule;
@ -391,6 +497,50 @@ SceUID curModule;
//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
// of a dangerous raw pointer.
@ -443,6 +593,8 @@ void __KernelThreadingInit()
WriteSyscall("FakeSysCalls", NID_INTERRUPTRETURN, intReturnHackAddr);
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.
// 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);
}
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()
{
return new Thread;
@ -1698,11 +1881,15 @@ void sceKernelReferCallbackStatus()
}
void ActionAfterMipsCall::run() {
u32 error;
Thread *thread = kernelObjects.Get<Thread>(threadID, error);
if (thread) {
thread->nt.status = status;
thread->nt.waitType = waitType;
thread->nt.waitID = waitID;
thread->waitInfo = waitInfo;
thread->isProcessingCallbacks = isProcessingCallbacks;
}
if (chainedAction) {
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)
{
if (thread) {
ActionAfterMipsCall *after = new ActionAfterMipsCall();
ActionAfterMipsCall *after = (ActionAfterMipsCall *) __KernelCreateAction(actionAfterMipsCall);
after->chainedAction = afterAction;
after->thread = thread;
after->threadID = thread->GetUID();
after->status = thread->nt.status;
after->waitType = thread->nt.waitType;
after->waitID = thread->nt.waitID;
@ -1986,6 +2173,7 @@ void __KernelReturnFromMipsCall()
// Should also save/restore wait state here.
if (call->doAfter)
call->doAfter->run();
// TODO: Do we need to delete call->doAfter?
currentMIPS->pc = call->savedPc;
currentMIPS->r[MIPS_REG_RA] = call->savedRa;
@ -2005,6 +2193,8 @@ void __KernelReturnFromMipsCall()
if (call->reschedAfter || threadReady == 0)
__KernelReSchedule("return from callback");
}
// TODO: Do we need to delete call?
}
bool __KernelExecutePendingMipsCalls(bool reschedAfter)
@ -2027,15 +2217,6 @@ bool __KernelExecutePendingMipsCalls(bool reschedAfter)
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, bool reschedAfter)
{
@ -2060,7 +2241,12 @@ void __KernelRunCallbackOnThread(SceUID cbId, Thread *thread, bool reschedAfter)
cb->nc.notifyCount = 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);
}

View File

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