X86: Define a noop ExtMachInst.
[gem5.git] / src / arch / sparc / faults.cc
index ebd9926b2699685c3bd6a52e9e3a9929af1f75c0..9c189d164f61bdef98b7eff03543e87fc722218d 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "arch/sparc/faults.hh"
 #include "arch/sparc/isa_traits.hh"
+#include "arch/sparc/types.hh"
 #include "base/bitfield.hh"
 #include "base/trace.hh"
 #include "config/full_system.hh"
@@ -196,7 +197,7 @@ template<> SparcFaultBase::FaultVals
 
 template<> SparcFaultBase::FaultVals
     SparcFault<InterruptLevelN>::vals =
-    {"interrupt_level_n", 0x041, 0, {P, P, SH}};
+    {"interrupt_level_n", 0x040, 0, {P, P, SH}};
 
 template<> SparcFaultBase::FaultVals
     SparcFault<HstickMatch>::vals =
@@ -206,6 +207,10 @@ template<> SparcFaultBase::FaultVals
     SparcFault<TrapLevelZero>::vals =
     {"trap_level_zero", 0x05F, 202, {H, H, SH}};
 
+template<> SparcFaultBase::FaultVals
+    SparcFault<InterruptVector>::vals =
+    {"interrupt_vector", 0x060, 2630, {H, H, H}};
+
 template<> SparcFaultBase::FaultVals
     SparcFault<PAWatchpoint>::vals =
     {"PA_watchpoint", 0x061, 1209, {H, H, H}};
@@ -239,7 +244,7 @@ template<> SparcFaultBase::FaultVals
     {"dev_mondo", 0x07D, 1611, {P, P, SH}};
 
 template<> SparcFaultBase::FaultVals
-    SparcFault<ResumeableError>::vals =
+    SparcFault<ResumableError>::vals =
     {"resume_error", 0x07E, 3330, {P, P, SH}};
 
 template<> SparcFaultBase::FaultVals
@@ -262,36 +267,144 @@ template<> SparcFaultBase::FaultVals
     SparcFault<TrapInstruction>::vals =
     {"trap_instruction", 0x100, 1602, {P, P, H}};
 
-#if !FULL_SYSTEM
-template<> SparcFaultBase::FaultVals
-    SparcFault<PageTableFault>::vals =
-    {"page_table_fault", 0x0000, 0, {SH, SH, SH}};
-#endif
+/**
+ * This causes the thread context to enter RED state. This causes the side
+ * effects which go with entering RED state because of a trap.
+ */
+
+void enterREDState(ThreadContext *tc)
+{
+    //@todo Disable the mmu?
+    //@todo Disable watchpoints?
+    MiscReg HPSTATE = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
+    //HPSTATE.red = 1
+    HPSTATE |= (1 << 5);
+    //HPSTATE.hpriv = 1
+    HPSTATE |= (1 << 2);
+    tc->setMiscReg(MISCREG_HPSTATE, HPSTATE);
+    //PSTATE.priv is set to 1 here. The manual says it should be 0, but
+    //Legion sets it to 1.
+    MiscReg PSTATE = tc->readMiscRegNoEffect(MISCREG_PSTATE);
+    PSTATE |= (1 << 2);
+    tc->setMiscReg(MISCREG_PSTATE, PSTATE);
+}
+
+/**
+ * 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->readMiscRegNoEffect(MISCREG_TL);
+    MiscReg TSTATE = tc->readMiscRegNoEffect(MISCREG_TSTATE);
+    MiscReg PSTATE = tc->readMiscRegNoEffect(MISCREG_PSTATE);
+    MiscReg HPSTATE = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
+    //MiscReg CCR = tc->readMiscRegNoEffect(MISCREG_CCR);
+    MiscReg CCR = tc->readIntReg(NumIntArchRegs + 2);
+    MiscReg ASI = tc->readMiscRegNoEffect(MISCREG_ASI);
+    MiscReg CWP = tc->readMiscRegNoEffect(MISCREG_CWP);
+    //MiscReg CANSAVE = tc->readMiscRegNoEffect(MISCREG_CANSAVE);
+    MiscReg CANSAVE = tc->readMiscRegNoEffect(NumIntArchRegs + 3);
+    MiscReg GL = tc->readMiscRegNoEffect(MISCREG_GL);
+    MiscReg PC = tc->readPC();
+    MiscReg NPC = tc->readNextPC();
+
+    TL++;
+
+    if (bits(PSTATE, 3,3)) {
+        PC &= mask(32);
+        NPC &= mask(32);
+    }
+
+    //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->setMiscRegNoEffect(MISCREG_TSTATE, TSTATE);
+
+    //set TPC to PC
+    tc->setMiscRegNoEffect(MISCREG_TPC, PC);
+    //set TNPC to NPC
+    tc->setMiscRegNoEffect(MISCREG_TNPC, NPC);
+
+    //set HTSTATE.hpstate to hpstate
+    tc->setMiscRegNoEffect(MISCREG_HTSTATE, HPSTATE);
+
+    //TT = trap type;
+    tc->setMiscRegNoEffect(MISCREG_TT, tt);
+
+    //Update GL
+    tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxGL));
+
+    PSTATE = mbits(PSTATE, 2, 2); // just save the priv bit
+    PSTATE |= (1 << 4); //set PSTATE.pef to 1
+    tc->setMiscRegNoEffect(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->setMiscRegNoEffect(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->setMiscReg(MISCREG_CWP, CWP);
+    }
+}
 
 /**
  * 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.
+ * the handler.
  */
 
-void doNormalFault(ThreadContext *tc, TrapType tt)
+void doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv)
 {
-    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();
+    MiscReg TL = tc->readMiscRegNoEffect(MISCREG_TL);
+    MiscReg TSTATE = tc->readMiscRegNoEffect(MISCREG_TSTATE);
+    MiscReg PSTATE = tc->readMiscRegNoEffect(MISCREG_PSTATE);
+    MiscReg HPSTATE = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
+    //MiscReg CCR = tc->readMiscRegNoEffect(MISCREG_CCR);
+    MiscReg CCR = tc->readIntReg(NumIntArchRegs + 2);
+    MiscReg ASI = tc->readMiscRegNoEffect(MISCREG_ASI);
+    MiscReg CWP = tc->readMiscRegNoEffect(MISCREG_CWP);
+    //MiscReg CANSAVE = tc->readMiscRegNoEffect(MISCREG_CANSAVE);
+    MiscReg CANSAVE = tc->readIntReg(NumIntArchRegs + 3);
+    MiscReg GL = tc->readMiscRegNoEffect(MISCREG_GL);
+    MiscReg PC = tc->readPC();
+    MiscReg NPC = tc->readNextPC();
+
+    if (bits(PSTATE, 3,3)) {
+        PC &= mask(32);
+        NPC &= mask(32);
+    }
 
     //Increment the trap level
     TL++;
-    tc->setMiscReg(MISCREG_TL, TL);
+    tc->setMiscRegNoEffect(MISCREG_TL, TL);
 
     //Save off state
 
@@ -307,90 +420,143 @@ void doNormalFault(ThreadContext *tc, TrapType tt)
     replaceBits(TSTATE, 4, 0, CWP);
 
     //Write back TSTATE
-    tc->setMiscReg(MISCREG_TSTATE, TSTATE);
+    tc->setMiscRegNoEffect(MISCREG_TSTATE, TSTATE);
 
     //set TPC to PC
-    tc->setMiscReg(MISCREG_TPC, PC);
+    tc->setMiscRegNoEffect(MISCREG_TPC, PC);
     //set TNPC to NPC
-    tc->setMiscReg(MISCREG_TNPC, NPC);
+    tc->setMiscRegNoEffect(MISCREG_TNPC, NPC);
 
     //set HTSTATE.hpstate to hpstate
-    tc->setMiscReg(MISCREG_HTSTATE, HPSTATE);
+    tc->setMiscRegNoEffect(MISCREG_HTSTATE, HPSTATE);
 
     //TT = trap type;
-    tc->setMiscReg(MISCREG_TT, tt);
+    tc->setMiscRegNoEffect(MISCREG_TT, tt);
 
     //Update the global register level
-    if(1/*We're delivering the trap in priveleged mode*/)
-        tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxGL));
-    else
+    if (!gotoHpriv)
         tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxPGL));
+    else
+        tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxGL));
 
     //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 |= (1 << 4); //PSTATE.pef = whether or not an fpu is present
+    PSTATE &= ~(1 << 3); //PSTATE.am = 0
+    PSTATE &= ~(1 << 1); //PSTATE.ie = 0
     //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*/)
+    if (gotoHpriv)
     {
-        //HPSTATE.red = 0
-        HPSTATE &= ~(1 << 5);
-        //HPSTATE.hpriv = 1
-        HPSTATE |= (1 << 2);
-        //HPSTATE.ibe = 0
-        HPSTATE &= ~(1 << 10);
+        PSTATE &= ~(1 << 9); // PSTATE.cle = 0
+        //The manual says PSTATE.priv should be 0, but Legion leaves it alone
+        HPSTATE &= ~(1 << 5); //HPSTATE.red = 0
+        HPSTATE |= (1 << 2); //HPSTATE.hpriv = 1
+        HPSTATE &= ~(1 << 10); //HPSTATE.ibe = 0
         //HPSTATE.tlz is unchanged
-        tc->setMiscReg(MISCREG_HPSTATE, HPSTATE);
+        tc->setMiscRegNoEffect(MISCREG_HPSTATE, HPSTATE);
+    } else { // we are going to priv
+        PSTATE |= (1 << 2); //PSTATE.priv = 1
+        replaceBits(PSTATE, 9, 9, PSTATE >> 8); //PSTATE.cle = PSTATE.tle
     }
+    tc->setMiscRegNoEffect(MISCREG_PSTATE, PSTATE);
+
 
     bool changedCWP = true;
-    if(tt == 0x24)
+    if (tt == 0x24)
         CWP++;
-    else if(0x80 <= tt && tt <= 0xbf)
+    else if (0x80 <= tt && tt <= 0xbf)
         CWP += (CANSAVE + 2);
-    else if(0xc0 <= tt && tt <= 0xff)
+    else if (0xc0 <= tt && tt <= 0xff)
         CWP--;
     else
         changedCWP = false;
 
-    if(changedCWP)
+    if (changedCWP)
     {
         CWP = (CWP + NWindows) % NWindows;
-        tc->setMiscRegWithEffect(MISCREG_CWP, CWP);
+        tc->setMiscReg(MISCREG_CWP, CWP);
     }
 }
 
+void getREDVector(MiscReg TT, Addr & PC, Addr & NPC)
+{
+    //XXX The following constant might belong in a header file.
+    const Addr RSTVAddr = 0xFFF0000000ULL;
+    PC = RSTVAddr | ((TT << 5) & 0xFF);
+    NPC = PC + sizeof(MachInst);
+}
+
+void getHyperVector(ThreadContext * tc, Addr & PC, Addr & NPC, MiscReg TT)
+{
+    Addr HTBA = tc->readMiscRegNoEffect(MISCREG_HTBA);
+    PC = (HTBA & ~mask(14)) | ((TT << 5) & mask(14));
+    NPC = PC + sizeof(MachInst);
+}
+
+void getPrivVector(ThreadContext * tc, Addr & PC, Addr & NPC, MiscReg TT, MiscReg TL)
+{
+    Addr TBA = tc->readMiscRegNoEffect(MISCREG_TBA);
+    PC = (TBA & ~mask(15)) |
+        (TL > 1 ? (1 << 14) : 0) |
+        ((TT << 5) & mask(14));
+    NPC = PC + sizeof(MachInst);
+}
+
 #if FULL_SYSTEM
 
 void SparcFaultBase::invoke(ThreadContext * tc)
 {
+    //panic("Invoking a second fault!\n");
     FaultBase::invoke(tc);
     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->readMiscRegNoEffect(MISCREG_TL);
+    MiscReg tt = tc->readMiscRegNoEffect(MISCREG_TT);
+    MiscReg pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);
+    MiscReg hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
+
+    Addr PC, NPC;
+
+    PrivilegeLevel current;
+    if (hpstate & HPSTATE::hpriv)
+        current = Hyperprivileged;
+    else if (pstate & PSTATE::priv)
+        current = Privileged;
+    else
+        current = User;
+
+    PrivilegeLevel level = getNextLevel(current);
+
+    if ((hpstate & HPSTATE::red) || (tl == MaxTL - 1)) {
+        getREDVector(5, PC, NPC);
+        doREDFault(tc, tt);
+        //This changes the hpstate and pstate, so we need to make sure we
+        //save the old version on the trap stack in doREDFault.
+        enterREDState(tc);
+    } else if (tl == MaxTL) {
+        panic("Should go to error state here.. crap\n");
+        //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(tc, PC, NPC, 2);
+    } else if (level == Hyperprivileged ||
+               (level == Privileged && trapType() >= 384)) {
+        doNormalFault(tc, trapType(), true);
+        getHyperVector(tc, PC, NPC, trapType());
+    } else {
+        doNormalFault(tc, trapType(), false);
+        getPrivVector(tc, PC, NPC, trapType(), tl+1);
+    }
+
+    tc->setPC(PC);
+    tc->setNextPC(NPC);
+    tc->setNextNPC(NPC + sizeof(MachInst));
 }
 
 void PowerOnReset::invoke(ThreadContext * tc)
@@ -398,45 +564,101 @@ void PowerOnReset::invoke(ThreadContext * tc)
     //For SPARC, when a system is first started, there is a power
     //on reset Trap which sets the processor into the following state.
     //Bits that aren't set aren't defined on startup.
-    /*
-    tl = MaxTL;
-    gl = MaxGL;
 
-    tickFields.counter = 0; //The TICK register is unreadable bya
-    tickFields.npt = 1; //The TICK register is unreadable by by !priv
-
-    softint = 0; // Clear all the soft interrupt bits
-    tick_cmprFields.int_dis = 1; // disable timer compare interrupts
+    tc->setMiscRegNoEffect(MISCREG_TL, MaxTL);
+    tc->setMiscRegNoEffect(MISCREG_TT, trapType());
+    tc->setMiscReg(MISCREG_GL, MaxGL);
+
+    //Turn on pef and priv, set everything else to 0
+    tc->setMiscRegNoEffect(MISCREG_PSTATE, (1 << 4) | (1 << 2));
+
+    //Turn on red and hpriv, set everything else to 0
+    MiscReg HPSTATE = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
+    //HPSTATE.red = 1
+    HPSTATE |= (1 << 5);
+    //HPSTATE.hpriv = 1
+    HPSTATE |= (1 << 2);
+    //HPSTATE.ibe = 0
+    HPSTATE &= ~(1 << 10);
+    //HPSTATE.tlz = 0
+    HPSTATE &= ~(1 << 0);
+    tc->setMiscRegNoEffect(MISCREG_HPSTATE, HPSTATE);
+
+    //The tick register is unreadable by nonprivileged software
+    tc->setMiscRegNoEffect(MISCREG_TICK, 1ULL << 63);
+
+    //Enter RED state. We do this last so that the actual state preserved in
+    //the trap stack is the state from before this fault.
+    enterREDState(tc);
+
+    Addr PC, NPC;
+    getREDVector(trapType(), PC, NPC);
+    tc->setPC(PC);
+    tc->setNextPC(NPC);
+    tc->setNextNPC(NPC + sizeof(MachInst));
+
+    //These registers are specified as "undefined" after a POR, and they
+    //should have reasonable values after the miscregfile is reset
+    /*
+    // Clear all the soft interrupt bits
+    softint = 0;
+    // disable timer compare interrupts, reset tick_cmpr
+    tc->setMiscRegNoEffect(MISCREG_
+    tick_cmprFields.int_dis = 1;
     tick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
     stickFields.npt = 1; //The TICK register is unreadable by by !priv
     stick_cmprFields.int_dis = 1; // disable timer compare interrupts
     stick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
 
     tt[tl] = _trapType;
-    pstate = 0; // fields 0 but pef
-    pstateFields.pef = 1;
 
-    hpstate = 0;
-    hpstateFields.red = 1;
-    hpstateFields.hpriv = 1;
-    hpstateFields.tlz = 0; // this is a guess
     hintp = 0; // no interrupts pending
     hstick_cmprFields.int_dis = 1; // disable timer compare interrupts
     hstick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
     */
 }
 
-#endif
+#else // !FULL_SYSTEM
 
-#if !FULL_SYSTEM
+void FastInstructionAccessMMUMiss::invoke(ThreadContext *tc)
+{
+    Process *p = tc->getProcessPtr();
+    TlbEntry entry;
+    bool success = p->pTable->lookup(vaddr, entry);
+    if(!success) {
+        panic("Tried to execute unmapped address %#x.\n", vaddr);
+    } else {
+        Addr alignedVaddr = p->pTable->pageAlign(vaddr);
+        tc->getITBPtr()->insert(alignedVaddr, 0 /*partition id*/,
+                p->M5_pid /*context id*/, false, entry.pte);
+    }
+}
+
+void FastDataAccessMMUMiss::invoke(ThreadContext *tc)
+{
+    Process *p = tc->getProcessPtr();
+    TlbEntry entry;
+    bool success = p->pTable->lookup(vaddr, entry);
+    if(!success) {
+        p->checkAndAllocNextPage(vaddr);
+        success = p->pTable->lookup(vaddr, entry);
+    }
+    if(!success) {
+        panic("Tried to access unmapped address %#x.\n", vaddr);
+    } else {
+        Addr alignedVaddr = p->pTable->pageAlign(vaddr);
+        tc->getDTBPtr()->insert(alignedVaddr, 0 /*partition id*/,
+                p->M5_pid /*context id*/, false, entry.pte);
+    }
+}
 
 void SpillNNormal::invoke(ThreadContext *tc)
 {
-    doNormalFault(tc, trapType());
+    doNormalFault(tc, trapType(), false);
 
     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);
     assert(lp);
 
@@ -449,39 +671,39 @@ void SpillNNormal::invoke(ThreadContext *tc)
 
 void FillNNormal::invoke(ThreadContext *tc)
 {
-    doNormalFault(tc, trapType());
+    doNormalFault(tc, trapType(), false);
 
     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);
     assert(lp);
 
-    //The adjust the PC and NPC
+    //Then 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 TrapInstruction::invoke(ThreadContext *tc)
 {
+    //In SE, this mechanism is how the process requests a service from the
+    //operating system. We'll get the process object from the thread context
+    //and let it service the request.
+
     Process *p = tc->getProcessPtr();
 
-    // address is higher than the stack region or in the current stack region
-    if (vaddr > p->stack_base || vaddr > p->stack_min)
-        FaultBase::invoke(tc);
-
-    // We've accessed the next page
-    if (vaddr > p->stack_min - PageBytes) {
-        p->stack_min -= PageBytes;
-        if (p->stack_base - p->stack_min > 8*1024*1024)
-            fatal("Over max stack size for one thread\n");
-        p->pTable->allocate(p->stack_min, PageBytes);
-        warn("Increasing stack size by one page.");
-    } else {
-        FaultBase::invoke(tc);
-    }
+    SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
+    assert(lp);
+
+    lp->handleTrap(_n, tc);
+
+    //We need to explicitly advance the pc, since that's not done for us
+    //on a faulting instruction
+    tc->setPC(tc->readNextPC());
+    tc->setNextPC(tc->readNextNPC());
+    tc->setNextNPC(tc->readNextNPC() + sizeof(MachInst));
 }
 
 #endif