mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-16 16:00:30 +02:00
Require interrupt handlers to be registered.
This allows it to be save stated sanely.
This commit is contained in:
1 parent
3ed2045f6b
commit
db787d266d
4 files changed
+183
-63
No files matched your search
+124
-35
@@ -28,11 +28,6 @@
|
||||
#include "sceKernelInterrupt.h"
|
||||
#include "sceKernelMutex.h"
|
||||
|
||||
struct Interrupt
|
||||
{
|
||||
PSPInterrupt intno;
|
||||
};
|
||||
|
||||
void __DisableInterrupts();
|
||||
void __EnableInterrupts();
|
||||
bool __InterruptsEnabled();
|
||||
@@ -92,9 +87,21 @@ void sceKernelCpuResumeIntrWithSync(u32 enable)
|
||||
|
||||
class IntrHandler {
|
||||
public:
|
||||
void add(int subIntrNum, SubIntrHandler *handler)
|
||||
IntrHandler()
|
||||
: subIntrCreator(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
SubIntrHandler *add(int subIntrNum)
|
||||
{
|
||||
SubIntrHandler *handler;
|
||||
if (subIntrCreator != NULL)
|
||||
handler = subIntrCreator();
|
||||
else
|
||||
handler = new SubIntrHandler();
|
||||
|
||||
subIntrHandlers[subIntrNum] = handler;
|
||||
return handler;
|
||||
}
|
||||
void remove(int subIntrNum)
|
||||
{
|
||||
@@ -113,8 +120,7 @@ public:
|
||||
if (has(subIntrNum))
|
||||
return subIntrHandlers[subIntrNum];
|
||||
else
|
||||
return 0;
|
||||
// what to do, what to do...
|
||||
return NULL;
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
@@ -146,7 +152,49 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void setCreator(SubIntrCreator creator)
|
||||
{
|
||||
subIntrCreator = creator;
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
// We assume that the same creator has already been registered.
|
||||
bool hasCreator = subIntrCreator != NULL;
|
||||
p.Do(hasCreator);
|
||||
if (hasCreator != (subIntrCreator != NULL))
|
||||
{
|
||||
ERROR_LOG(HLE, "Savestate failure: incompatible sub interrupt handler.");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t n = subIntrHandlers.size();
|
||||
p.Do(n);
|
||||
|
||||
if (p.mode == p.MODE_READ)
|
||||
{
|
||||
clear();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
int subIntrNum;
|
||||
p.Do(subIntrNum);
|
||||
SubIntrHandler *handler = add(subIntrNum);
|
||||
handler->DoState(p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::map<int, SubIntrHandler *>::iterator it, end;
|
||||
for (it = subIntrHandlers.begin(), end = subIntrHandlers.end(); it != end; ++it)
|
||||
{
|
||||
p.Do(it->first);
|
||||
it->second->DoState(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SubIntrCreator subIntrCreator;
|
||||
std::map<int, SubIntrHandler *> subIntrHandlers;
|
||||
};
|
||||
|
||||
@@ -157,6 +205,13 @@ public:
|
||||
void restore();
|
||||
void clear();
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(insideInterrupt);
|
||||
p.Do(savedCpu);
|
||||
p.DoMarker("InterruptState");
|
||||
}
|
||||
|
||||
bool insideInterrupt;
|
||||
ThreadContext savedCpu;
|
||||
// Action afterInterruptAction;
|
||||
@@ -181,6 +236,25 @@ void __InterruptsInit()
|
||||
intState.clear();
|
||||
}
|
||||
|
||||
void __InterruptsDoState(PointerWrap &p)
|
||||
{
|
||||
int numInterrupts = PSP_NUMBER_INTERRUPTS;
|
||||
p.Do(numInterrupts);
|
||||
if (numInterrupts != PSP_NUMBER_INTERRUPTS)
|
||||
{
|
||||
ERROR_LOG(HLE, "Savestate failure: wrong number of interrupts, can't load.");
|
||||
return;
|
||||
}
|
||||
|
||||
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 __InterruptsShutdown()
|
||||
{
|
||||
for (int i = 0; i < PSP_NUMBER_INTERRUPTS; ++i)
|
||||
@@ -238,25 +312,16 @@ void SubIntrHandler::queueUp()
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
PendingInterrupt pend;
|
||||
pend.handler = this;
|
||||
pend.hasArg = false;
|
||||
pend.intr = intrNumber;
|
||||
pend.subintr = number;
|
||||
pendingInterrupts.push_back(pend);
|
||||
|
||||
pendingInterrupts.push_back(PendingInterrupt(intrNumber, number));
|
||||
};
|
||||
|
||||
void SubIntrHandler::queueUpWithArg(int arg)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
PendingInterrupt pend;
|
||||
pend.handler = this;
|
||||
pend.arg = arg;
|
||||
pend.hasArg = true;
|
||||
pend.intr = intrNumber;
|
||||
pend.subintr = number;
|
||||
pendingInterrupts.push_back(pend);
|
||||
|
||||
pendingInterrupts.push_back(PendingInterrupt(intrNumber, number, arg));
|
||||
}
|
||||
|
||||
void SubIntrHandler::copyArgsToCPU(const PendingInterrupt &pend)
|
||||
@@ -278,6 +343,7 @@ bool __RunOnePendingInterrupt()
|
||||
return false;
|
||||
}
|
||||
// Can easily prioritize between different kinds of interrupts if necessary.
|
||||
retry:
|
||||
if (pendingInterrupts.size())
|
||||
{
|
||||
// If we came from CoreTiming::Advance(), we might've come from a waiting thread's callback.
|
||||
@@ -285,8 +351,16 @@ bool __RunOnePendingInterrupt()
|
||||
__KernelSwitchOffThread("interrupt");
|
||||
|
||||
PendingInterrupt pend = pendingInterrupts.front();
|
||||
SubIntrHandler *handler = intrHandlers[pend.intr].get(pend.subintr);
|
||||
if (handler == NULL)
|
||||
{
|
||||
WARN_LOG(HLE, "Ignoring interrupt, already been released.");
|
||||
pendingInterrupts.pop_front();
|
||||
goto retry;
|
||||
}
|
||||
|
||||
intState.save();
|
||||
pend.handler->copyArgsToCPU(pend);
|
||||
handler->copyArgsToCPU(pend);
|
||||
|
||||
currentMIPS->r[MIPS_REG_RA] = __KernelInterruptReturnAddress();
|
||||
inInterrupt = true;
|
||||
@@ -340,7 +414,12 @@ void __KernelReturnFromInterrupt()
|
||||
// This is what we just ran.
|
||||
PendingInterrupt pend = pendingInterrupts.front();
|
||||
pendingInterrupts.pop_front();
|
||||
pend.handler->handleResult(currentMIPS->r[MIPS_REG_V0]);
|
||||
|
||||
SubIntrHandler *handler = intrHandlers[pend.intr].get(pend.subintr);
|
||||
if (handler != NULL)
|
||||
handler->handleResult(currentMIPS->r[MIPS_REG_V0]);
|
||||
else
|
||||
ERROR_LOG(HLE, "Interrupt released itself? Should not happen.");
|
||||
|
||||
// Restore context after running the interrupt.
|
||||
intState.restore();
|
||||
@@ -351,15 +430,21 @@ void __KernelReturnFromInterrupt()
|
||||
__KernelReSchedule("return from interrupt");
|
||||
}
|
||||
|
||||
u32 __RegisterSubInterruptHandler(u32 intrNumber, u32 subIntrNumber, SubIntrHandler *subIntrHandler)
|
||||
void __RegisterSubIntrCreator(u32 intrNumber, SubIntrCreator creator)
|
||||
{
|
||||
subIntrHandler->number = subIntrNumber;
|
||||
subIntrHandler->intrNumber = intrNumber;
|
||||
intrHandlers[intrNumber].add(subIntrNumber, subIntrHandler);
|
||||
return 0;
|
||||
intrHandlers[intrNumber].setCreator(creator);
|
||||
}
|
||||
|
||||
u32 __ReleaseSubInterruptHandler(u32 intrNumber, u32 subIntrNumber)
|
||||
SubIntrHandler *__RegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32 &error)
|
||||
{
|
||||
SubIntrHandler *subIntrHandler = intrHandlers[intrNumber].add(subIntrNumber);
|
||||
subIntrHandler->number = subIntrNumber;
|
||||
subIntrHandler->intrNumber = intrNumber;
|
||||
error = 0;
|
||||
return subIntrHandler;
|
||||
}
|
||||
|
||||
u32 __ReleaseSubIntrHandler(u32 intrNumber, u32 subIntrNumber)
|
||||
{
|
||||
if (!intrHandlers[intrNumber].has(subIntrNumber))
|
||||
return -1;
|
||||
@@ -383,11 +468,15 @@ u32 sceKernelRegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32 handl
|
||||
if (intrNumber >= PSP_NUMBER_INTERRUPTS)
|
||||
return -1;
|
||||
|
||||
SubIntrHandler *subIntrHandler = new SubIntrHandler();
|
||||
subIntrHandler->enabled = false;
|
||||
subIntrHandler->handlerAddress = handler;
|
||||
subIntrHandler->handlerArg = handlerArg;
|
||||
return __RegisterSubInterruptHandler(intrNumber, subIntrNumber, subIntrHandler);
|
||||
u32 error;
|
||||
SubIntrHandler *subIntrHandler = __RegisterSubIntrHandler(intrNumber, subIntrNumber, error);
|
||||
if (subIntrHandler)
|
||||
{
|
||||
subIntrHandler->enabled = false;
|
||||
subIntrHandler->handlerAddress = handler;
|
||||
subIntrHandler->handlerArg = handlerArg;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
u32 sceKernelReleaseSubIntrHandler(u32 intrNumber, u32 subIntrNumber)
|
||||
@@ -397,7 +486,7 @@ u32 sceKernelReleaseSubIntrHandler(u32 intrNumber, u32 subIntrNumber)
|
||||
if (intrNumber >= PSP_NUMBER_INTERRUPTS)
|
||||
return -1;
|
||||
|
||||
return __ReleaseSubInterruptHandler(intrNumber, subIntrNumber);
|
||||
return __ReleaseSubIntrHandler(intrNumber, subIntrNumber);
|
||||
}
|
||||
|
||||
u32 sceKernelEnableSubIntr(u32 intrNumber, u32 subIntrNumber)
|
||||
|
||||
Reference in new issue
Block a user