First cut at full blown SPARC faults. There are a few details that are missing.
--HG-- extra : convert_revision : 8023db1479cb9bf99fc9edfeb521c4e5b581f895
This commit is contained in:
parent
67b9a2ebd8
commit
63bbc8929d
1 changed files with 212 additions and 30 deletions
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#include "arch/sparc/faults.hh"
|
#include "arch/sparc/faults.hh"
|
||||||
#include "arch/sparc/isa_traits.hh"
|
#include "arch/sparc/isa_traits.hh"
|
||||||
|
#include "arch/sparc/types.hh"
|
||||||
#include "base/bitfield.hh"
|
#include "base/bitfield.hh"
|
||||||
#include "base/trace.hh"
|
#include "base/trace.hh"
|
||||||
#include "config/full_system.hh"
|
#include "config/full_system.hh"
|
||||||
|
@ -269,25 +270,132 @@ template<> SparcFaultBase::FaultVals
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This sets everything up for a normal trap except for actually jumping to
|
* This causes the thread context to enter RED state. This causes the side
|
||||||
* the handler. It will need to be expanded to include the state machine in
|
* effects which go with entering RED state because of a trap.
|
||||||
* the manual. Right now it assumes that traps will always be to the
|
|
||||||
* privileged level.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void doNormalFault(ThreadContext *tc, TrapType tt)
|
void enterREDState(ThreadContext *tc)
|
||||||
{
|
{
|
||||||
uint64_t TL = tc->readMiscReg(MISCREG_TL);
|
//@todo Disable the mmu?
|
||||||
uint64_t TSTATE = tc->readMiscReg(MISCREG_TSTATE);
|
//@todo Disable watchpoints?
|
||||||
uint64_t PSTATE = tc->readMiscReg(MISCREG_PSTATE);
|
MiscReg HPSTATE = tc->readMiscReg(MISCREG_HPSTATE);
|
||||||
uint64_t HPSTATE = tc->readMiscReg(MISCREG_HPSTATE);
|
//HPSTATE.red = 1
|
||||||
uint64_t CCR = tc->readMiscReg(MISCREG_CCR);
|
HPSTATE |= (1 << 5);
|
||||||
uint64_t ASI = tc->readMiscReg(MISCREG_ASI);
|
//HPSTATE.hpriv = 1
|
||||||
uint64_t CWP = tc->readMiscReg(MISCREG_CWP);
|
HPSTATE |= (1 << 2);
|
||||||
uint64_t CANSAVE = tc->readMiscReg(MISCREG_CANSAVE);
|
tc->setMiscReg(MISCREG_HPSTATE, HPSTATE);
|
||||||
uint64_t GL = tc->readMiscReg(MISCREG_GL);
|
}
|
||||||
uint64_t PC = tc->readPC();
|
|
||||||
uint64_t NPC = tc->readNextPC();
|
/**
|
||||||
|
* This sets everything up for a RED state trap except for actually jumping to
|
||||||
|
* the handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void doREDFault(ThreadContext *tc, TrapType tt)
|
||||||
|
{
|
||||||
|
MiscReg TL = tc->readMiscReg(MISCREG_TL);
|
||||||
|
MiscReg TSTATE = tc->readMiscReg(MISCREG_TSTATE);
|
||||||
|
MiscReg PSTATE = tc->readMiscReg(MISCREG_PSTATE);
|
||||||
|
MiscReg HPSTATE = tc->readMiscReg(MISCREG_HPSTATE);
|
||||||
|
MiscReg CCR = tc->readMiscReg(MISCREG_CCR);
|
||||||
|
MiscReg ASI = tc->readMiscReg(MISCREG_ASI);
|
||||||
|
MiscReg CWP = tc->readMiscReg(MISCREG_CWP);
|
||||||
|
MiscReg CANSAVE = tc->readMiscReg(MISCREG_CANSAVE);
|
||||||
|
MiscReg GL = tc->readMiscReg(MISCREG_GL);
|
||||||
|
MiscReg PC = tc->readPC();
|
||||||
|
MiscReg NPC = tc->readNextPC();
|
||||||
|
|
||||||
|
TL++;
|
||||||
|
|
||||||
|
//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 GL
|
||||||
|
tc->setMiscRegWithEffect(MISCREG_GL, min<int>(GL+1, MaxGL));
|
||||||
|
|
||||||
|
//set PSTATE.mm to 00
|
||||||
|
//set PSTATE.pef to 1
|
||||||
|
PSTATE |= (1 << 4);
|
||||||
|
//set PSTATE.am to 0
|
||||||
|
PSTATE &= ~(1 << 3);
|
||||||
|
//set PSTATE.priv to 0
|
||||||
|
PSTATE &= ~(1 << 2);
|
||||||
|
//set PSTATE.ie to 0
|
||||||
|
PSTATE &= ~(1 << 1);
|
||||||
|
//set PSTATE.cle to 0
|
||||||
|
PSTATE &= ~(1 << 9);
|
||||||
|
//PSTATE.tle is unchanged
|
||||||
|
//XXX Where is the tct bit?
|
||||||
|
//set PSTATE.tct to 0
|
||||||
|
tc->setMiscReg(MISCREG_PSTATE, PSTATE);
|
||||||
|
|
||||||
|
//set HPSTATE.red to 1
|
||||||
|
HPSTATE |= (1 << 5);
|
||||||
|
//set HPSTATE.hpriv to 1
|
||||||
|
HPSTATE |= (1 << 2);
|
||||||
|
//set HPSTATE.ibe to 0
|
||||||
|
HPSTATE &= ~(1 << 10);
|
||||||
|
//set HPSTATE.tlz to 0
|
||||||
|
HPSTATE &= ~(1 << 0);
|
||||||
|
tc->setMiscReg(MISCREG_HPSTATE, HPSTATE);
|
||||||
|
|
||||||
|
bool changedCWP = true;
|
||||||
|
if(tt == 0x24)
|
||||||
|
CWP++;
|
||||||
|
else if(0x80 <= tt && tt <= 0xbf)
|
||||||
|
CWP += (CANSAVE + 2);
|
||||||
|
else if(0xc0 <= tt && tt <= 0xff)
|
||||||
|
CWP--;
|
||||||
|
else
|
||||||
|
changedCWP = false;
|
||||||
|
|
||||||
|
if(changedCWP)
|
||||||
|
{
|
||||||
|
CWP = (CWP + NWindows) % NWindows;
|
||||||
|
tc->setMiscRegWithEffect(MISCREG_CWP, CWP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This sets everything up for a normal trap except for actually jumping to
|
||||||
|
* the handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv)
|
||||||
|
{
|
||||||
|
MiscReg TL = tc->readMiscReg(MISCREG_TL);
|
||||||
|
MiscReg TSTATE = tc->readMiscReg(MISCREG_TSTATE);
|
||||||
|
MiscReg PSTATE = tc->readMiscReg(MISCREG_PSTATE);
|
||||||
|
MiscReg HPSTATE = tc->readMiscReg(MISCREG_HPSTATE);
|
||||||
|
MiscReg CCR = tc->readMiscReg(MISCREG_CCR);
|
||||||
|
MiscReg ASI = tc->readMiscReg(MISCREG_ASI);
|
||||||
|
MiscReg CWP = tc->readMiscReg(MISCREG_CWP);
|
||||||
|
MiscReg CANSAVE = tc->readMiscReg(MISCREG_CANSAVE);
|
||||||
|
MiscReg GL = tc->readMiscReg(MISCREG_GL);
|
||||||
|
MiscReg PC = tc->readPC();
|
||||||
|
MiscReg NPC = tc->readNextPC();
|
||||||
|
|
||||||
//Increment the trap level
|
//Increment the trap level
|
||||||
TL++;
|
TL++;
|
||||||
|
@ -321,10 +429,10 @@ void doNormalFault(ThreadContext *tc, TrapType tt)
|
||||||
tc->setMiscReg(MISCREG_TT, tt);
|
tc->setMiscReg(MISCREG_TT, tt);
|
||||||
|
|
||||||
//Update the global register level
|
//Update the global register level
|
||||||
if(1/*We're delivering the trap in priveleged mode*/)
|
if(!gotoHpriv)
|
||||||
tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxGL));
|
tc->setMiscRegWithEffect(MISCREG_GL, min<int>(GL+1, MaxPGL));
|
||||||
else
|
else
|
||||||
tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxPGL));
|
tc->setMiscRegWithEffect(MISCREG_GL, min<int>(GL+1, MaxGL));
|
||||||
|
|
||||||
//PSTATE.mm is unchanged
|
//PSTATE.mm is unchanged
|
||||||
//PSTATE.pef = whether or not an fpu is present
|
//PSTATE.pef = whether or not an fpu is present
|
||||||
|
@ -333,7 +441,7 @@ void doNormalFault(ThreadContext *tc, TrapType tt)
|
||||||
PSTATE |= (1 << 4);
|
PSTATE |= (1 << 4);
|
||||||
//PSTATE.am = 0
|
//PSTATE.am = 0
|
||||||
PSTATE &= ~(1 << 3);
|
PSTATE &= ~(1 << 3);
|
||||||
if(1/*We're delivering the trap in priveleged mode*/)
|
if(!gotoHpriv)
|
||||||
{
|
{
|
||||||
//PSTATE.priv = 1
|
//PSTATE.priv = 1
|
||||||
PSTATE |= (1 << 2);
|
PSTATE |= (1 << 2);
|
||||||
|
@ -354,7 +462,7 @@ void doNormalFault(ThreadContext *tc, TrapType tt)
|
||||||
//XXX Where exactly is this field?
|
//XXX Where exactly is this field?
|
||||||
tc->setMiscReg(MISCREG_PSTATE, PSTATE);
|
tc->setMiscReg(MISCREG_PSTATE, PSTATE);
|
||||||
|
|
||||||
if(0/*We're delivering the trap in hyperprivileged mode*/)
|
if(gotoHpriv)
|
||||||
{
|
{
|
||||||
//HPSTATE.red = 0
|
//HPSTATE.red = 0
|
||||||
HPSTATE &= ~(1 << 5);
|
HPSTATE &= ~(1 << 5);
|
||||||
|
@ -383,6 +491,29 @@ void doNormalFault(ThreadContext *tc, TrapType tt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getREDVector(Addr & PC, Addr & NPC)
|
||||||
|
{
|
||||||
|
const Addr RSTVAddr = 0xFFFFFFFFF0000000ULL;
|
||||||
|
PC = RSTVAddr | 0xA0;
|
||||||
|
NPC = PC + sizeof(MachInst);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getHyperVector(Addr & PC, Addr & NPC, MiscReg TT)
|
||||||
|
{
|
||||||
|
Addr HTBA ;
|
||||||
|
PC = (HTBA & ~mask(14)) | ((TT << 5) & mask(14));
|
||||||
|
NPC = PC + sizeof(MachInst);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getPrivVector(Addr & PC, Addr & NPC, MiscReg TT, MiscReg TL)
|
||||||
|
{
|
||||||
|
Addr TBA ;
|
||||||
|
PC = (TBA & ~mask(15)) |
|
||||||
|
(TL > 1 ? (1 << 14) : 0) |
|
||||||
|
((TT << 5) & mask(14));
|
||||||
|
NPC = PC + sizeof(MachInst);
|
||||||
|
}
|
||||||
|
|
||||||
#if FULL_SYSTEM
|
#if FULL_SYSTEM
|
||||||
|
|
||||||
void SparcFaultBase::invoke(ThreadContext * tc)
|
void SparcFaultBase::invoke(ThreadContext * tc)
|
||||||
|
@ -390,11 +521,64 @@ void SparcFaultBase::invoke(ThreadContext * tc)
|
||||||
FaultBase::invoke(tc);
|
FaultBase::invoke(tc);
|
||||||
countStat()++;
|
countStat()++;
|
||||||
|
|
||||||
//Use the SPARC trap state machine
|
//We can refer to this to see what the trap level -was-, but something
|
||||||
|
//in the middle could change it in the regfile out from under us.
|
||||||
|
MiscReg TL = tc->readMiscReg(MISCREG_TL);
|
||||||
|
MiscReg TT = tc->readMiscReg(MISCREG_TT);
|
||||||
|
MiscReg PSTATE = tc->readMiscReg(MISCREG_PSTATE);
|
||||||
|
MiscReg HPSTATE = tc->readMiscReg(MISCREG_HPSTATE);
|
||||||
|
|
||||||
|
Addr PC, NPC;
|
||||||
|
|
||||||
|
PrivilegeLevel current;
|
||||||
|
if(!(PSTATE & (1 << 2)))
|
||||||
|
current = User;
|
||||||
|
else if(!(HPSTATE & (1 << 2)))
|
||||||
|
current = Privileged;
|
||||||
|
else
|
||||||
|
current = Hyperprivileged;
|
||||||
|
|
||||||
|
PrivilegeLevel level = getNextLevel(current);
|
||||||
|
|
||||||
|
if(HPSTATE & (1 << 5) || TL == MaxTL - 1)
|
||||||
|
{
|
||||||
|
getREDVector(PC, NPC);
|
||||||
|
enterREDState(tc);
|
||||||
|
doREDFault(tc, TT);
|
||||||
|
}
|
||||||
|
else if(TL == MaxTL)
|
||||||
|
{
|
||||||
|
//Do error_state somehow?
|
||||||
|
//Probably inject a WDR fault using the interrupt mechanism.
|
||||||
|
//What should the PC and NPC be set to?
|
||||||
|
}
|
||||||
|
else if(TL > MaxPTL && level == Privileged)
|
||||||
|
{
|
||||||
|
//guest_watchdog fault
|
||||||
|
doNormalFault(tc, trapType(), true);
|
||||||
|
getHyperVector(PC, NPC, 2);
|
||||||
|
}
|
||||||
|
else if(level == Hyperprivileged)
|
||||||
|
{
|
||||||
|
doNormalFault(tc, trapType(), true);
|
||||||
|
getHyperVector(PC, NPC, trapType());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
doNormalFault(tc, trapType(), false);
|
||||||
|
getPrivVector(PC, NPC, trapType(), TL+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
tc->setPC(PC);
|
||||||
|
tc->setNextPC(NPC);
|
||||||
|
tc->setNextNPC(NPC + sizeof(MachInst));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerOnReset::invoke(ThreadContext * tc)
|
void PowerOnReset::invoke(ThreadContext * tc)
|
||||||
{
|
{
|
||||||
|
//First, enter RED state.
|
||||||
|
enterREDState(tc);
|
||||||
|
|
||||||
//For SPARC, when a system is first started, there is a power
|
//For SPARC, when a system is first started, there is a power
|
||||||
//on reset Trap which sets the processor into the following state.
|
//on reset Trap which sets the processor into the following state.
|
||||||
//Bits that aren't set aren't defined on startup.
|
//Bits that aren't set aren't defined on startup.
|
||||||
|
@ -426,17 +610,15 @@ void PowerOnReset::invoke(ThreadContext * tc)
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#else // !FULL_SYSTEM
|
||||||
|
|
||||||
#if !FULL_SYSTEM
|
|
||||||
|
|
||||||
void SpillNNormal::invoke(ThreadContext *tc)
|
void SpillNNormal::invoke(ThreadContext *tc)
|
||||||
{
|
{
|
||||||
doNormalFault(tc, trapType());
|
doNormalFault(tc, trapType(), false);
|
||||||
|
|
||||||
Process *p = tc->getProcessPtr();
|
Process *p = tc->getProcessPtr();
|
||||||
|
|
||||||
//This will only work in faults from a SparcLiveProcess
|
//XXX This will only work in faults from a SparcLiveProcess
|
||||||
SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
|
SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
|
||||||
assert(lp);
|
assert(lp);
|
||||||
|
|
||||||
|
@ -449,15 +631,15 @@ void SpillNNormal::invoke(ThreadContext *tc)
|
||||||
|
|
||||||
void FillNNormal::invoke(ThreadContext *tc)
|
void FillNNormal::invoke(ThreadContext *tc)
|
||||||
{
|
{
|
||||||
doNormalFault(tc, trapType());
|
doNormalFault(tc, trapType(), false);
|
||||||
|
|
||||||
Process * p = tc->getProcessPtr();
|
Process * p = tc->getProcessPtr();
|
||||||
|
|
||||||
//This will only work in faults from a SparcLiveProcess
|
//XXX This will only work in faults from a SparcLiveProcess
|
||||||
SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
|
SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
|
||||||
assert(lp);
|
assert(lp);
|
||||||
|
|
||||||
//The adjust the PC and NPC
|
//Then adjust the PC and NPC
|
||||||
Addr fillStart = lp->readFillStart();
|
Addr fillStart = lp->readFillStart();
|
||||||
tc->setPC(fillStart);
|
tc->setPC(fillStart);
|
||||||
tc->setNextPC(fillStart + sizeof(MachInst));
|
tc->setNextPC(fillStart + sizeof(MachInst));
|
||||||
|
|
Loading…
Reference in a new issue