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
This commit is contained in:
Gabe Black 2006-10-25 17:49:41 -04:00
parent 1b1495930c
commit e2eef8859b
4 changed files with 284 additions and 10 deletions

View file

@ -29,15 +29,22 @@
* Kevin Lim * Kevin Lim
*/ */
#include <algorithm>
#include "arch/sparc/faults.hh" #include "arch/sparc/faults.hh"
#include "cpu/thread_context.hh" #include "arch/sparc/isa_traits.hh"
#include "cpu/base.hh" #include "arch/sparc/process.hh"
#include "base/bitfield.hh"
#include "base/trace.hh" #include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#if !FULL_SYSTEM #if !FULL_SYSTEM
#include "sim/process.hh"
#include "mem/page_table.hh" #include "mem/page_table.hh"
#include "sim/process.hh"
#endif #endif
using namespace std;
namespace SparcISA namespace SparcISA
{ {
@ -229,6 +236,129 @@ FaultPriority PageTableFault::_priority = 0;
FaultStat PageTableFault::_count; FaultStat PageTableFault::_count;
#endif #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<int>(GL+1, MaxGL));
else
tc->setMiscReg(MISCREG_GL, max<int>(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 #if FULL_SYSTEM
void SparcFault::invoke(ThreadContext * tc) void SparcFault::invoke(ThreadContext * tc)
@ -263,6 +393,42 @@ void TrapInstruction::invoke(ThreadContext * tc)
// Should be handled in ISA. // 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<SparcLiveProcess *>(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<SparcLiveProcess *>(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) void PageTableFault::invoke(ThreadContext *tc)
{ {
Process *p = tc->getProcessPtr(); Process *p = tc->getProcessPtr();
@ -282,6 +448,7 @@ void PageTableFault::invoke(ThreadContext *tc)
FaultBase::invoke(tc); FaultBase::invoke(tc);
} }
} }
#endif #endif
} // namespace SparcISA } // namespace SparcISA

View file

@ -39,8 +39,8 @@
namespace SparcISA namespace SparcISA
{ {
typedef const uint32_t TrapType; typedef uint32_t TrapType;
typedef const uint32_t FaultPriority; typedef uint32_t FaultPriority;
class SparcFault : public FaultBase class SparcFault : public FaultBase
{ {
@ -547,6 +547,7 @@ class SpillNNormal : public EnumeratedFault
FaultName name() {return _name;} FaultName name() {return _name;}
FaultPriority priority() {return _priority;} FaultPriority priority() {return _priority;}
FaultStat & countStat() {return _count;} FaultStat & countStat() {return _count;}
void invoke(ThreadContext * tc);
}; };
class SpillNOther : public EnumeratedFault class SpillNOther : public EnumeratedFault
@ -577,6 +578,7 @@ class FillNNormal : public EnumeratedFault
FaultName name() {return _name;} FaultName name() {return _name;}
FaultPriority priority() {return _priority;} FaultPriority priority() {return _priority;}
FaultStat & countStat() {return _count;} FaultStat & countStat() {return _count;}
void invoke(ThreadContext * tc);
}; };
class FillNOther : public EnumeratedFault class FillNOther : public EnumeratedFault

View file

@ -66,6 +66,10 @@ SparcLiveProcess::SparcLiveProcess(const std::string &nm, ObjectFile *objFile,
// Set pointer for next thread stack. Reserve 8M for main stack. // Set pointer for next thread stack. Reserve 8M for main stack.
next_thread_stack_base = stack_base - (8 * 1024 * 1024); next_thread_stack_base = stack_base - (8 * 1024 * 1024);
//Initialize these to 0s
fillStart = 0;
spillStart = 0;
} }
void void
@ -88,15 +92,19 @@ SparcLiveProcess::startup()
*/ */
//No windows contain info from other programs //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 //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 //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" //All windows are "clean"
threadContexts[0]->setMiscRegWithEffect(MISCREG_CLEANWIN, NWindows); threadContexts[0]->setMiscReg(MISCREG_CLEANWIN, NWindows);
//Start with register window 0 //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) 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; 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 void
SparcLiveProcess::argsInit(int intSize, int pageSize) SparcLiveProcess::argsInit(int intSize, int pageSize)
{ {
@ -317,6 +402,17 @@ SparcLiveProcess::argsInit(int intSize, int pageSize)
initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); 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(ArgumentReg0, argc);
threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base); threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
threadContexts[0]->setIntReg(StackPointerReg, stack_min - StackBias); threadContexts[0]->setIntReg(StackPointerReg, stack_min - StackBias);

View file

@ -55,6 +55,9 @@ class SparcLiveProcess : public LiveProcess
static const Addr StackBias = 2047; static const Addr StackBias = 2047;
//The locations of the fill and spill handlers
Addr fillStart, spillStart;
std::vector<m5_auxv_t> auxv; std::vector<m5_auxv_t> auxv;
SparcLiveProcess(const std::string &nm, ObjectFile *objFile, SparcLiveProcess(const std::string &nm, ObjectFile *objFile,
@ -71,6 +74,12 @@ class SparcLiveProcess : public LiveProcess
void argsInit(int intSize, int pageSize); void argsInit(int intSize, int pageSize);
Addr readFillStart()
{ return fillStart; }
Addr readSpillStart()
{ return spillStart; }
}; };
#endif // __SPARC_PROCESS_HH__ #endif // __SPARC_PROCESS_HH__