mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 13:47:57 +03:00
Only save/restore thread context when servicing interrupts.
This commit is contained in:
parent
461d436ef7
commit
c7cb9b12c7
2 changed files with 106 additions and 66 deletions
|
@ -62,6 +62,7 @@
|
|||
#define BIOS_ADDRESS_SIFDMA_NEXT_INDEX 0x0000002C
|
||||
#define BIOS_ADDRESS_SIFDMA_TIMES_BASE 0x00000030
|
||||
#define BIOS_ADDRESS_SIFDMA_TIMES_END (BIOS_ADDRESS_SIFDMA_TIMES_BASE + (4 * BIOS_SIFDMA_COUNT))
|
||||
#define BIOS_ADDRESS_INTERRUPT_THREAD_CONTEXT BIOS_ADDRESS_SIFDMA_TIMES_END
|
||||
#define BIOS_ADDRESS_INTCHANDLER_BASE 0x0000A000
|
||||
#define BIOS_ADDRESS_DMACHANDLER_BASE 0x0000C000
|
||||
#define BIOS_ADDRESS_SEMAPHORE_BASE 0x0000E000
|
||||
|
@ -82,6 +83,7 @@
|
|||
#define LOG_NAME ("ps2os")
|
||||
|
||||
#define SYSCALL_CUSTOM_RESCHEDULE 0x666
|
||||
#define SYSCALL_CUSTOM_EXITINTERRUPT 0x667
|
||||
|
||||
#define SYSCALL_NAME_EXIT "osExit"
|
||||
#define SYSCALL_NAME_LOADEXECPS2 "osLoadExecPS2"
|
||||
|
@ -767,15 +769,15 @@ void CPS2OS::AssembleInterruptHandler()
|
|||
assembler.ORI(CMIPS::T0, CMIPS::T0, CMIPS::STATUS_IE);
|
||||
assembler.MTC0(CMIPS::T0, CCOP_SCU::STATUS);
|
||||
|
||||
//Prologue
|
||||
|
||||
//Move back SP into K0 before restoring state
|
||||
assembler.ADDIU(CMIPS::K0, CMIPS::SP, CMIPS::R0);
|
||||
//Read EPC from 0x220
|
||||
assembler.LW(CMIPS::A0, 0x0220, CMIPS::K0);
|
||||
|
||||
//Restore EPC
|
||||
assembler.LW(CMIPS::T0, 0x0220, CMIPS::K0);
|
||||
assembler.MTC0(CMIPS::T0, CCOP_SCU::EPC);
|
||||
|
||||
//Prologue
|
||||
assembler.ERET();
|
||||
assembler.ADDIU(CMIPS::V1, CMIPS::R0, SYSCALL_CUSTOM_EXITINTERRUPT);
|
||||
assembler.SYSCALL();
|
||||
}
|
||||
|
||||
void CPS2OS::AssembleDmacHandler()
|
||||
|
@ -1112,37 +1114,7 @@ void CPS2OS::ThreadSwitchContext(uint32 id)
|
|||
//Idle thread doesn't have a context
|
||||
if(m_currentThreadId != m_idleThreadId)
|
||||
{
|
||||
thread->contextPtr = m_ee.m_State.nGPR[CMIPS::SP].nV0 - STACKRES;
|
||||
assert(thread->contextPtr >= thread->stackBase);
|
||||
|
||||
auto context = reinterpret_cast<THREADCONTEXT*>(GetStructPtr(thread->contextPtr));
|
||||
|
||||
//Save the context
|
||||
for(uint32 i = 0; i < 0x20; i++)
|
||||
{
|
||||
if(i == CMIPS::R0) continue;
|
||||
if(i == CMIPS::K0) continue;
|
||||
if(i == CMIPS::K1) continue;
|
||||
context->gpr[i] = m_ee.m_State.nGPR[i];
|
||||
}
|
||||
for(uint32 i = 0; i < 0x20; i++)
|
||||
{
|
||||
context->cop1[i] = m_ee.m_State.nCOP1[i];
|
||||
}
|
||||
auto& sa = context->gpr[CMIPS::R0].nV0;
|
||||
auto& hi = context->gpr[CMIPS::K0];
|
||||
auto& lo = context->gpr[CMIPS::K1];
|
||||
sa = m_ee.m_State.nSA >> 3; //Act as if MFSA was used
|
||||
hi.nV[0] = m_ee.m_State.nHI[0];
|
||||
hi.nV[1] = m_ee.m_State.nHI[1];
|
||||
hi.nV[2] = m_ee.m_State.nHI1[0];
|
||||
hi.nV[3] = m_ee.m_State.nHI1[1];
|
||||
lo.nV[0] = m_ee.m_State.nLO[0];
|
||||
lo.nV[1] = m_ee.m_State.nLO[1];
|
||||
lo.nV[2] = m_ee.m_State.nLO1[0];
|
||||
lo.nV[3] = m_ee.m_State.nLO1[1];
|
||||
context->cop1a = m_ee.m_State.nCOP1A;
|
||||
context->fcsr = m_ee.m_State.nFCSR;
|
||||
ThreadSaveContext(thread, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1157,40 +1129,88 @@ void CPS2OS::ThreadSwitchContext(uint32 id)
|
|||
//Idle thread doesn't have a context
|
||||
if(id != m_idleThreadId)
|
||||
{
|
||||
assert(thread->contextPtr != 0);
|
||||
auto context = reinterpret_cast<const THREADCONTEXT*>(GetStructPtr(thread->contextPtr));
|
||||
|
||||
for(uint32 i = 0; i < 0x20; i++)
|
||||
{
|
||||
if(i == CMIPS::R0) continue;
|
||||
if(i == CMIPS::K0) continue;
|
||||
if(i == CMIPS::K1) continue;
|
||||
m_ee.m_State.nGPR[i] = context->gpr[i];
|
||||
}
|
||||
for(uint32 i = 0; i < 0x20; i++)
|
||||
{
|
||||
m_ee.m_State.nCOP1[i] = context->cop1[i];
|
||||
}
|
||||
auto& sa = context->gpr[CMIPS::R0].nV0;
|
||||
auto& hi = context->gpr[CMIPS::K0];
|
||||
auto& lo = context->gpr[CMIPS::K1];
|
||||
m_ee.m_State.nSA = (sa & 0x0F) << 3; //Act as if MTSA was used
|
||||
m_ee.m_State.nHI[0] = hi.nV[0];
|
||||
m_ee.m_State.nHI[1] = hi.nV[1];
|
||||
m_ee.m_State.nHI1[0] = hi.nV[2];
|
||||
m_ee.m_State.nHI1[1] = hi.nV[3];
|
||||
m_ee.m_State.nLO[0] = lo.nV[0];
|
||||
m_ee.m_State.nLO[1] = lo.nV[1];
|
||||
m_ee.m_State.nLO1[0] = lo.nV[2];
|
||||
m_ee.m_State.nLO1[1] = lo.nV[3];
|
||||
m_ee.m_State.nCOP1A = context->cop1a;
|
||||
m_ee.m_State.nFCSR = context->fcsr;
|
||||
ThreadLoadContext(thread, false);
|
||||
}
|
||||
}
|
||||
|
||||
CLog::GetInstance().Print(LOG_NAME, "New thread elected (id = %i).\r\n", id);
|
||||
}
|
||||
|
||||
void CPS2OS::ThreadSaveContext(THREAD* thread, bool interrupt)
|
||||
{
|
||||
if(interrupt)
|
||||
{
|
||||
thread->contextPtr = BIOS_ADDRESS_INTERRUPT_THREAD_CONTEXT;
|
||||
}
|
||||
else
|
||||
{
|
||||
thread->contextPtr = m_ee.m_State.nGPR[CMIPS::SP].nV0 - STACKRES;
|
||||
assert(thread->contextPtr >= thread->stackBase);
|
||||
}
|
||||
|
||||
auto context = reinterpret_cast<THREADCONTEXT*>(GetStructPtr(thread->contextPtr));
|
||||
|
||||
//Save the context
|
||||
for(uint32 i = 0; i < 0x20; i++)
|
||||
{
|
||||
if(i == CMIPS::R0) continue;
|
||||
if(i == CMIPS::K0) continue;
|
||||
if(i == CMIPS::K1) continue;
|
||||
context->gpr[i] = m_ee.m_State.nGPR[i];
|
||||
}
|
||||
for(uint32 i = 0; i < 0x20; i++)
|
||||
{
|
||||
context->cop1[i] = m_ee.m_State.nCOP1[i];
|
||||
}
|
||||
auto& sa = context->gpr[CMIPS::R0].nV0;
|
||||
auto& hi = context->gpr[CMIPS::K0];
|
||||
auto& lo = context->gpr[CMIPS::K1];
|
||||
sa = m_ee.m_State.nSA >> 3; //Act as if MFSA was used
|
||||
hi.nV[0] = m_ee.m_State.nHI[0];
|
||||
hi.nV[1] = m_ee.m_State.nHI[1];
|
||||
hi.nV[2] = m_ee.m_State.nHI1[0];
|
||||
hi.nV[3] = m_ee.m_State.nHI1[1];
|
||||
lo.nV[0] = m_ee.m_State.nLO[0];
|
||||
lo.nV[1] = m_ee.m_State.nLO[1];
|
||||
lo.nV[2] = m_ee.m_State.nLO1[0];
|
||||
lo.nV[3] = m_ee.m_State.nLO1[1];
|
||||
context->cop1a = m_ee.m_State.nCOP1A;
|
||||
context->fcsr = m_ee.m_State.nFCSR;
|
||||
}
|
||||
|
||||
void CPS2OS::ThreadLoadContext(THREAD* thread, bool interrupt)
|
||||
{
|
||||
assert(thread->contextPtr != 0);
|
||||
assert(!(interrupt && thread->contextPtr == thread->contextPtr == BIOS_ADDRESS_INTERRUPT_THREAD_CONTEXT));
|
||||
|
||||
auto context = reinterpret_cast<const THREADCONTEXT*>(GetStructPtr(thread->contextPtr));
|
||||
for(uint32 i = 0; i < 0x20; i++)
|
||||
{
|
||||
if(i == CMIPS::R0) continue;
|
||||
if(i == CMIPS::K0) continue;
|
||||
if(i == CMIPS::K1) continue;
|
||||
m_ee.m_State.nGPR[i] = context->gpr[i];
|
||||
}
|
||||
for(uint32 i = 0; i < 0x20; i++)
|
||||
{
|
||||
m_ee.m_State.nCOP1[i] = context->cop1[i];
|
||||
}
|
||||
auto& sa = context->gpr[CMIPS::R0].nV0;
|
||||
auto& hi = context->gpr[CMIPS::K0];
|
||||
auto& lo = context->gpr[CMIPS::K1];
|
||||
m_ee.m_State.nSA = (sa & 0x0F) << 3; //Act as if MTSA was used
|
||||
m_ee.m_State.nHI[0] = hi.nV[0];
|
||||
m_ee.m_State.nHI[1] = hi.nV[1];
|
||||
m_ee.m_State.nHI1[0] = hi.nV[2];
|
||||
m_ee.m_State.nHI1[1] = hi.nV[3];
|
||||
m_ee.m_State.nLO[0] = lo.nV[0];
|
||||
m_ee.m_State.nLO[1] = lo.nV[1];
|
||||
m_ee.m_State.nLO1[0] = lo.nV[2];
|
||||
m_ee.m_State.nLO1[1] = lo.nV[3];
|
||||
m_ee.m_State.nCOP1A = context->cop1a;
|
||||
m_ee.m_State.nFCSR = context->fcsr;
|
||||
}
|
||||
|
||||
void CPS2OS::ThreadReset(uint32 id)
|
||||
{
|
||||
assert(m_currentThreadId != id);
|
||||
|
@ -1347,7 +1367,12 @@ void CPS2OS::HandleInterrupt()
|
|||
return;
|
||||
}
|
||||
|
||||
ThreadSwitchContext(m_idleThreadId);
|
||||
if(m_currentThreadId != m_idleThreadId)
|
||||
{
|
||||
auto thread = m_threads[m_currentThreadId];
|
||||
ThreadSaveContext(thread, true);
|
||||
}
|
||||
|
||||
bool interrupted = m_ee.GenerateInterrupt(BIOS_ADDRESS_INTERRUPTHANDLER);
|
||||
assert(interrupted);
|
||||
}
|
||||
|
@ -2858,6 +2883,19 @@ void CPS2OS::HandleSyscall()
|
|||
//Reschedule
|
||||
ThreadShakeAndBake();
|
||||
}
|
||||
else if(func == SYSCALL_CUSTOM_EXITINTERRUPT)
|
||||
{
|
||||
//Execute ERET
|
||||
m_ee.m_State.nCOP0[CCOP_SCU::STATUS] &= ~(CMIPS::STATUS_EXL);
|
||||
m_ee.m_State.nPC = m_ee.m_State.nGPR[CMIPS::A0].nV0;
|
||||
|
||||
if(m_currentThreadId != m_idleThreadId)
|
||||
{
|
||||
auto thread = m_threads[m_currentThreadId];
|
||||
ThreadLoadContext(thread, true);
|
||||
}
|
||||
ThreadShakeAndBake();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(func & 0x80000000)
|
||||
|
|
|
@ -261,6 +261,8 @@ private:
|
|||
void UnlinkThread(uint32);
|
||||
void ThreadShakeAndBake();
|
||||
void ThreadSwitchContext(uint32);
|
||||
void ThreadSaveContext(THREAD*, bool);
|
||||
void ThreadLoadContext(THREAD*, bool);
|
||||
void ThreadReset(uint32);
|
||||
void CheckLivingThreads();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue