mirror of
https://github.com/libretro/ppsspp.git
synced 2025-02-26 11:45:26 +00:00
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:
parent
f5dd7f03e8
commit
a8c9c31e16
@ -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;
|
||||
};
|
||||
|
@ -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() {
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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)",
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user