Only save/restore thread context when servicing interrupts.

This commit is contained in:
Jean-Philip Desjardins 2019-02-09 11:26:48 -05:00
parent 461d436ef7
commit c7cb9b12c7
2 changed files with 106 additions and 66 deletions

View file

@ -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)

View file

@ -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();