From: Gabe Black Date: Wed, 25 Oct 2006 21:49:41 +0000 (-0400) Subject: Implemented the SPARC fill and spill handlers. X-Git-Tag: m5_2.0_beta2~70^2~21^2~13 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e2eef8859b44dbb9d307f6ff50047bdb6b730277;p=gem5.git Implemented the SPARC fill and spill handlers. src/arch/sparc/faults.cc: src/arch/sparc/faults.hh: Added a function to do normal SPARC trap processing, and implemented the spill and fill faults for SE src/arch/sparc/process.cc: src/arch/sparc/process.hh: Added fill and spill handlers which are stuffed into the processes address space. The location of these handlers are stored in fillStart and spillStart. --HG-- extra : convert_revision : 59adb96570cce86f373fbc2c3e4c05abe1742d3b --- diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc index 7b7765935..fd91ccf0f 100644 --- a/src/arch/sparc/faults.cc +++ b/src/arch/sparc/faults.cc @@ -29,15 +29,22 @@ * Kevin Lim */ +#include + #include "arch/sparc/faults.hh" -#include "cpu/thread_context.hh" -#include "cpu/base.hh" +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/process.hh" +#include "base/bitfield.hh" #include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/thread_context.hh" #if !FULL_SYSTEM -#include "sim/process.hh" #include "mem/page_table.hh" +#include "sim/process.hh" #endif +using namespace std; + namespace SparcISA { @@ -229,6 +236,129 @@ FaultPriority PageTableFault::_priority = 0; FaultStat PageTableFault::_count; #endif +/** + * This sets everything up for a normal trap except for actually jumping to + * the handler. It will need to be expanded to include the state machine in + * the manual. Right now it assumes that traps will always be to the + * privileged level. + */ + +void doNormalFault(ThreadContext *tc, TrapType tt) +{ + uint64_t TL = tc->readMiscReg(MISCREG_TL); + uint64_t TSTATE = tc->readMiscReg(MISCREG_TSTATE); + uint64_t PSTATE = tc->readMiscReg(MISCREG_PSTATE); + uint64_t HPSTATE = tc->readMiscReg(MISCREG_HPSTATE); + uint64_t CCR = tc->readMiscReg(MISCREG_CCR); + uint64_t ASI = tc->readMiscReg(MISCREG_ASI); + uint64_t CWP = tc->readMiscReg(MISCREG_CWP); + uint64_t CANSAVE = tc->readMiscReg(MISCREG_CANSAVE); + uint64_t GL = tc->readMiscReg(MISCREG_GL); + uint64_t PC = tc->readPC(); + uint64_t NPC = tc->readNextPC(); + + //Increment the trap level + TL++; + tc->setMiscReg(MISCREG_TL, TL); + + //Save off state + + //set TSTATE.gl to gl + replaceBits(TSTATE, 42, 40, GL); + //set TSTATE.ccr to ccr + replaceBits(TSTATE, 39, 32, CCR); + //set TSTATE.asi to asi + replaceBits(TSTATE, 31, 24, ASI); + //set TSTATE.pstate to pstate + replaceBits(TSTATE, 20, 8, PSTATE); + //set TSTATE.cwp to cwp + replaceBits(TSTATE, 4, 0, CWP); + + //Write back TSTATE + tc->setMiscReg(MISCREG_TSTATE, TSTATE); + + //set TPC to PC + tc->setMiscReg(MISCREG_TPC, PC); + //set TNPC to NPC + tc->setMiscReg(MISCREG_TNPC, NPC); + + //set HTSTATE.hpstate to hpstate + tc->setMiscReg(MISCREG_HTSTATE, HPSTATE); + + //TT = trap type; + tc->setMiscReg(MISCREG_TT, tt); + + //Update the global register level + if(1/*We're delivering the trap in priveleged mode*/) + tc->setMiscReg(MISCREG_GL, max(GL+1, MaxGL)); + else + tc->setMiscReg(MISCREG_GL, max(GL+1, MaxPGL)); + + //PSTATE.mm is unchanged + //PSTATE.pef = whether or not an fpu is present + //XXX We'll say there's one present, even though there aren't + //implementations for a decent number of the instructions + PSTATE |= (1 << 4); + //PSTATE.am = 0 + PSTATE &= ~(1 << 3); + if(1/*We're delivering the trap in priveleged mode*/) + { + //PSTATE.priv = 1 + PSTATE |= (1 << 2); + //PSTATE.cle = PSTATE.tle + replaceBits(PSTATE, 9, 9, PSTATE >> 8); + } + else + { + //PSTATE.priv = 0 + PSTATE &= ~(1 << 2); + //PSTATE.cle = 0 + PSTATE &= ~(1 << 9); + } + //PSTATE.ie = 0 + PSTATE &= ~(1 << 1); + //PSTATE.tle is unchanged + //PSTATE.tct = 0 + //XXX Where exactly is this field? + tc->setMiscReg(MISCREG_PSTATE, PSTATE); + + if(0/*We're delivering the trap in hyperprivileged mode*/) + { + //HPSTATE.red = 0 + HPSTATE &= ~(1 << 5); + //HPSTATE.hpriv = 1 + HPSTATE |= (1 << 2); + //HPSTATE.ibe = 0 + HPSTATE &= ~(1 << 10); + //HPSTATE.tlz is unchanged + tc->setMiscReg(MISCREG_HPSTATE, HPSTATE); + } + + bool changedCWP = true; + if(tt == 0x24) + { + warn("Incrementing the CWP by 1\n"); + CWP++; + } + else if(0x80 <= tt && tt <= 0xbf) + { + warn("Incrementing the CWP by %d\n", CANSAVE + 2); + CWP += (CANSAVE + 2); + } + else if(0xc0 <= tt && tt <= 0xff) + { + warn("Decrementing the CWP by 1\n"); + CWP--; + } + else + changedCWP = false; + if(changedCWP) + { + CWP = (CWP + NWindows) % NWindows; + tc->setMiscRegWithEffect(MISCREG_CWP, CWP); + } +} + #if FULL_SYSTEM void SparcFault::invoke(ThreadContext * tc) @@ -263,6 +393,42 @@ void TrapInstruction::invoke(ThreadContext * tc) // Should be handled in ISA. } +void SpillNNormal::invoke(ThreadContext *tc) +{ + warn("I'm in a spill trap\n"); + doNormalFault(tc, trapType()); + + Process *p = tc->getProcessPtr(); + + //This will only work in faults from a SparcLiveProcess + SparcLiveProcess *lp = dynamic_cast(p); + assert(lp); + + //Then adjust the PC and NPC + Addr spillStart = lp->readSpillStart(); + tc->setPC(spillStart); + tc->setNextPC(spillStart + sizeof(MachInst)); + tc->setNextNPC(spillStart + 2*sizeof(MachInst)); +} + +void FillNNormal::invoke(ThreadContext *tc) +{ + warn("I'm in a fill trap\n"); + doNormalFault(tc, trapType()); + + Process * p = tc->getProcessPtr(); + + //This will only work in faults from a SparcLiveProcess + SparcLiveProcess *lp = dynamic_cast(p); + assert(lp); + + //The adjust the PC and NPC + Addr fillStart = lp->readFillStart(); + tc->setPC(fillStart); + tc->setNextPC(fillStart + sizeof(MachInst)); + tc->setNextNPC(fillStart + 2*sizeof(MachInst)); +} + void PageTableFault::invoke(ThreadContext *tc) { Process *p = tc->getProcessPtr(); @@ -282,6 +448,7 @@ void PageTableFault::invoke(ThreadContext *tc) FaultBase::invoke(tc); } } + #endif } // namespace SparcISA diff --git a/src/arch/sparc/faults.hh b/src/arch/sparc/faults.hh index b279f4911..394a06294 100644 --- a/src/arch/sparc/faults.hh +++ b/src/arch/sparc/faults.hh @@ -39,8 +39,8 @@ namespace SparcISA { -typedef const uint32_t TrapType; -typedef const uint32_t FaultPriority; +typedef uint32_t TrapType; +typedef uint32_t FaultPriority; class SparcFault : public FaultBase { @@ -547,6 +547,7 @@ class SpillNNormal : public EnumeratedFault FaultName name() {return _name;} FaultPriority priority() {return _priority;} FaultStat & countStat() {return _count;} + void invoke(ThreadContext * tc); }; class SpillNOther : public EnumeratedFault @@ -577,6 +578,7 @@ class FillNNormal : public EnumeratedFault FaultName name() {return _name;} FaultPriority priority() {return _priority;} FaultStat & countStat() {return _count;} + void invoke(ThreadContext * tc); }; class FillNOther : public EnumeratedFault diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc index 3323ba7a0..a3b7dde7c 100644 --- a/src/arch/sparc/process.cc +++ b/src/arch/sparc/process.cc @@ -66,6 +66,10 @@ SparcLiveProcess::SparcLiveProcess(const std::string &nm, ObjectFile *objFile, // Set pointer for next thread stack. Reserve 8M for main stack. next_thread_stack_base = stack_base - (8 * 1024 * 1024); + + //Initialize these to 0s + fillStart = 0; + spillStart = 0; } void @@ -88,15 +92,19 @@ SparcLiveProcess::startup() */ //No windows contain info from other programs - threadContexts[0]->setMiscRegWithEffect(MISCREG_OTHERWIN, 0); + threadContexts[0]->setMiscReg(MISCREG_OTHERWIN, 0); //There are no windows to pop - threadContexts[0]->setMiscRegWithEffect(MISCREG_CANRESTORE, 0); + threadContexts[0]->setMiscReg(MISCREG_CANRESTORE, 0); //All windows are available to save into - threadContexts[0]->setMiscRegWithEffect(MISCREG_CANSAVE, NWindows - 2); + threadContexts[0]->setMiscReg(MISCREG_CANSAVE, NWindows - 2); //All windows are "clean" - threadContexts[0]->setMiscRegWithEffect(MISCREG_CLEANWIN, NWindows); + threadContexts[0]->setMiscReg(MISCREG_CLEANWIN, NWindows); //Start with register window 0 - threadContexts[0]->setMiscRegWithEffect(MISCREG_CWP, 0); + threadContexts[0]->setMiscReg(MISCREG_CWP, 0); + //Always use spill and fill traps 0 + threadContexts[0]->setMiscReg(MISCREG_WSTATE, 0); + //Set the trap level to 0 + threadContexts[0]->setMiscReg(MISCREG_TL, 0); } m5_auxv_t buildAuxVect(int64_t type, int64_t val) @@ -107,6 +115,83 @@ m5_auxv_t buildAuxVect(int64_t type, int64_t val) return result; } +//We only use 19 instructions for the trap handlers, but there would be +//space for 32 in a real SPARC trap table. +const int numFillInsts = 32; +const int numSpillInsts = 32; + +MachInst fillHandler[numFillInsts] = +{ + htog(0x87802018), //wr %g0, ASI_AIUP, %asi + htog(0xe0dba7ff), //ldxa [%sp + BIAS + (0*8)] %asi, %l0 + htog(0xe2dba807), //ldxa [%sp + BIAS + (1*8)] %asi, %l1 + htog(0xe4dba80f), //ldxa [%sp + BIAS + (2*8)] %asi, %l2 + htog(0xe6dba817), //ldxa [%sp + BIAS + (3*8)] %asi, %l3 + htog(0xe8dba81f), //ldxa [%sp + BIAS + (4*8)] %asi, %l4 + htog(0xeadba827), //ldxa [%sp + BIAS + (5*8)] %asi, %l5 + htog(0xecdba82f), //ldxa [%sp + BIAS + (6*8)] %asi, %l6 + htog(0xeedba837), //ldxa [%sp + BIAS + (7*8)] %asi, %l7 + htog(0xf0dba83f), //ldxa [%sp + BIAS + (8*8)] %asi, %i0 + htog(0xf2dba847), //ldxa [%sp + BIAS + (9*8)] %asi, %i1 + htog(0xf4dba84f), //ldxa [%sp + BIAS + (10*8)] %asi, %i2 + htog(0xf6dba857), //ldxa [%sp + BIAS + (11*8)] %asi, %i3 + htog(0xf8dba85f), //ldxa [%sp + BIAS + (12*8)] %asi, %i4 + htog(0xfadba867), //ldxa [%sp + BIAS + (13*8)] %asi, %i5 + htog(0xfcdba86f), //ldxa [%sp + BIAS + (14*8)] %asi, %i6 + htog(0xfedba877), //ldxa [%sp + BIAS + (15*8)] %asi, %i7 + htog(0x83880000), //restored + htog(0x83F00000), //retry + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000) //illtrap +}; + +MachInst spillHandler[numSpillInsts] = +{ + htog(0x87802018), //wr %g0, ASI_AIUP, %asi + htog(0xe0f3a7ff), //stxa %l0, [%sp + BIAS + (0*8)] %asi + htog(0xe2f3a807), //stxa %l1, [%sp + BIAS + (1*8)] %asi + htog(0xe4f3a80f), //stxa %l2, [%sp + BIAS + (2*8)] %asi + htog(0xe6f3a817), //stxa %l3, [%sp + BIAS + (3*8)] %asi + htog(0xe8f3a81f), //stxa %l4, [%sp + BIAS + (4*8)] %asi + htog(0xeaf3a827), //stxa %l5, [%sp + BIAS + (5*8)] %asi + htog(0xecf3a82f), //stxa %l6, [%sp + BIAS + (6*8)] %asi + htog(0xeef3a837), //stxa %l7, [%sp + BIAS + (7*8)] %asi + htog(0xf0f3a83f), //stxa %i0, [%sp + BIAS + (8*8)] %asi + htog(0xf2f3a847), //stxa %i1, [%sp + BIAS + (9*8)] %asi + htog(0xf4f3a84f), //stxa %i2, [%sp + BIAS + (10*8)] %asi + htog(0xf6f3a857), //stxa %i3, [%sp + BIAS + (11*8)] %asi + htog(0xf8f3a85f), //stxa %i4, [%sp + BIAS + (12*8)] %asi + htog(0xfaf3a867), //stxa %i5, [%sp + BIAS + (13*8)] %asi + htog(0xfcf3a86f), //stxa %i6, [%sp + BIAS + (14*8)] %asi + htog(0xfef3a877), //stxa %i7, [%sp + BIAS + (15*8)] %asi + htog(0x81880000), //saved + htog(0x83F00000), //retry + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000) //illtrap +}; + void SparcLiveProcess::argsInit(int intSize, int pageSize) { @@ -317,6 +402,17 @@ SparcLiveProcess::argsInit(int intSize, int pageSize) initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); + //Stuff the trap handlers into the processes address space. + //Since the stack grows down and is the highest area in the processes + //address space, we can put stuff above it and stay out of the way. + int fillSize = sizeof(MachInst) * numFillInsts; + int spillSize = sizeof(MachInst) * numSpillInsts; + fillStart = stack_base; + spillStart = fillStart + fillSize; + initVirtMem->writeBlob(fillStart, (uint8_t*)fillHandler, fillSize); + initVirtMem->writeBlob(spillStart, (uint8_t*)spillHandler, spillSize); + + //Set up the thread context to start running the process threadContexts[0]->setIntReg(ArgumentReg0, argc); threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base); threadContexts[0]->setIntReg(StackPointerReg, stack_min - StackBias); diff --git a/src/arch/sparc/process.hh b/src/arch/sparc/process.hh index 7cc52e241..2320810c7 100644 --- a/src/arch/sparc/process.hh +++ b/src/arch/sparc/process.hh @@ -55,6 +55,9 @@ class SparcLiveProcess : public LiveProcess static const Addr StackBias = 2047; + //The locations of the fill and spill handlers + Addr fillStart, spillStart; + std::vector auxv; SparcLiveProcess(const std::string &nm, ObjectFile *objFile, @@ -71,6 +74,12 @@ class SparcLiveProcess : public LiveProcess void argsInit(int intSize, int pageSize); + Addr readFillStart() + { return fillStart; } + + Addr readSpillStart() + { return spillStart; } + }; #endif // __SPARC_PROCESS_HH__