X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Farch%2Fsparc%2Ffaults.cc;h=3859b30ecca95b8b9c8f83e3c5e0b3f2024262f6;hb=ddcc0ab2b4eb301d4e31800736590e4315b1b6b1;hp=67920a3d18ec239afeb0e8a1d642c2be5d7212ac;hpb=2dcf00bc8b6ca0bdfc8ab9a105f7a7780c763bb4;p=gem5.git diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc index 67920a3d1..3859b30ec 100644 --- a/src/arch/sparc/faults.cc +++ b/src/arch/sparc/faults.cc @@ -29,21 +29,21 @@ * Kevin Lim */ +#include "arch/sparc/faults.hh" + #include -#include "arch/sparc/faults.hh" #include "arch/sparc/isa_traits.hh" +#include "arch/sparc/process.hh" +#include "arch/sparc/tlb.hh" #include "arch/sparc/types.hh" #include "base/bitfield.hh" #include "base/trace.hh" -#include "config/full_system.hh" #include "cpu/base.hh" #include "cpu/thread_context.hh" -#if !FULL_SYSTEM -#include "arch/sparc/process.hh" #include "mem/page_table.hh" +#include "sim/full_system.hh" #include "sim/process.hh" -#endif using namespace std; @@ -51,244 +51,247 @@ namespace SparcISA { template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"power_on_reset", 0x001, 0, {H, H, H}}; + SparcFault::vals +("power_on_reset", 0x001, 0, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"watch_dog_reset", 0x002, 120, {H, H, H}}; + SparcFault::vals +("watch_dog_reset", 0x002, 120, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"externally_initiated_reset", 0x003, 110, {H, H, H}}; + SparcFault::vals +("externally_initiated_reset", 0x003, 110, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"software_initiated_reset", 0x004, 130, {SH, SH, H}}; + SparcFault::vals +("software_initiated_reset", 0x004, 130, {{SH, SH, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"RED_state_exception", 0x005, 1, {H, H, H}}; + SparcFault::vals +("RED_state_exception", 0x005, 1, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"store_error", 0x007, 201, {H, H, H}}; + SparcFault::vals +("store_error", 0x007, 201, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"instruction_access_exception", 0x008, 300, {H, H, H}}; + SparcFault::vals +("instruction_access_exception", 0x008, 300, {{H, H, H}}); //XXX This trap is apparently dropped from ua2005 /*template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"inst_mmu", 0x009, 2, {H, H, H}};*/ + SparcFault::vals + ("inst_mmu", 0x009, 2, {{H, H, H}});*/ template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"instruction_access_error", 0x00A, 400, {H, H, H}}; + SparcFault::vals +("instruction_access_error", 0x00A, 400, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"illegal_instruction", 0x010, 620, {H, H, H}}; + SparcFault::vals +("illegal_instruction", 0x010, 620, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"privileged_opcode", 0x011, 700, {P, SH, SH}}; + SparcFault::vals +("privileged_opcode", 0x011, 700, {{P, SH, SH}}); //XXX This trap is apparently dropped from ua2005 /*template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"unimp_ldd", 0x012, 6, {H, H, H}};*/ + SparcFault::vals + ("unimp_ldd", 0x012, 6, {{H, H, H}});*/ //XXX This trap is apparently dropped from ua2005 /*template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"unimp_std", 0x013, 6, {H, H, H}};*/ + SparcFault::vals + ("unimp_std", 0x013, 6, {{H, H, H}});*/ + +template<> SparcFaultBase::FaultVals + SparcFault::vals +("fp_disabled", 0x020, 800, {{P, P, H}}); +/* SPARCv8 and SPARCv9 define just fp_disabled trap. SIMD is not contemplated + * as a separate part. Therefore, we use the same code and TT */ template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fp_disabled", 0x020, 800, {P, P, H}}; + SparcFault::vals +("fp_disabled", 0x020, 800, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fp_exception_ieee_754", 0x021, 1110, {P, P, H}}; + SparcFault::vals +("fp_exception_ieee_754", 0x021, 1110, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fp_exception_other", 0x022, 1110, {P, P, H}}; + SparcFault::vals +("fp_exception_other", 0x022, 1110, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"tag_overflow", 0x023, 1400, {P, P, H}}; + SparcFault::vals +("tag_overflow", 0x023, 1400, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"clean_window", 0x024, 1010, {P, P, H}}; + SparcFault::vals +("clean_window", 0x024, 1010, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"division_by_zero", 0x028, 1500, {P, P, H}}; + SparcFault::vals +("division_by_zero", 0x028, 1500, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"internal_processor_error", 0x029, 4, {H, H, H}}; + SparcFault::vals +("internal_processor_error", 0x029, 4, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"instruction_invalid_tsb_entry", 0x02A, 210, {H, H, SH}}; + SparcFault::vals +("instruction_invalid_tsb_entry", 0x02A, 210, {{H, H, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"data_invalid_tsb_entry", 0x02B, 1203, {H, H, H}}; + SparcFault::vals +("data_invalid_tsb_entry", 0x02B, 1203, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"data_access_exception", 0x030, 1201, {H, H, H}}; + SparcFault::vals +("data_access_exception", 0x030, 1201, {{H, H, H}}); //XXX This trap is apparently dropped from ua2005 /*template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"data_mmu", 0x031, 12, {H, H, H}};*/ + SparcFault::vals + ("data_mmu", 0x031, 12, {{H, H, H}});*/ template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"data_access_error", 0x032, 1210, {H, H, H}}; + SparcFault::vals +("data_access_error", 0x032, 1210, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"data_access_protection", 0x033, 1207, {H, H, H}}; + SparcFault::vals +("data_access_protection", 0x033, 1207, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"mem_address_not_aligned", 0x034, 1020, {H, H, H}}; + SparcFault::vals +("mem_address_not_aligned", 0x034, 1020, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"LDDF_mem_address_not_aligned", 0x035, 1010, {H, H, H}}; + SparcFault::vals +("LDDF_mem_address_not_aligned", 0x035, 1010, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"STDF_mem_address_not_aligned", 0x036, 1010, {H, H, H}}; + SparcFault::vals +("STDF_mem_address_not_aligned", 0x036, 1010, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"privileged_action", 0x037, 1110, {H, H, SH}}; + SparcFault::vals +("privileged_action", 0x037, 1110, {{H, H, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"LDQF_mem_address_not_aligned", 0x038, 1010, {H, H, H}}; + SparcFault::vals +("LDQF_mem_address_not_aligned", 0x038, 1010, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"STQF_mem_address_not_aligned", 0x039, 1010, {H, H, H}}; + SparcFault::vals +("STQF_mem_address_not_aligned", 0x039, 1010, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"instruction_real_translation_miss", 0x03E, 208, {H, H, SH}}; + SparcFault::vals +("instruction_real_translation_miss", 0x03E, 208, {{H, H, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"data_real_translation_miss", 0x03F, 1203, {H, H, H}}; + SparcFault::vals +("data_real_translation_miss", 0x03F, 1203, {{H, H, H}}); //XXX This trap is apparently dropped from ua2005 /*template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"async_data", 0x040, 2, {H, H, H}};*/ + SparcFault::vals + ("async_data", 0x040, 2, {{H, H, H}});*/ template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"interrupt_level_n", 0x041, 0, {P, P, SH}}; + SparcFault::vals +("interrupt_level_n", 0x040, 0, {{P, P, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"hstick_match", 0x05E, 1601, {H, H, H}}; + SparcFault::vals +("hstick_match", 0x05E, 1601, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"trap_level_zero", 0x05F, 202, {H, H, SH}}; + SparcFault::vals +("trap_level_zero", 0x05F, 202, {{H, H, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"PA_watchpoint", 0x061, 1209, {H, H, H}}; + SparcFault::vals +("interrupt_vector", 0x060, 2630, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"VA_watchpoint", 0x062, 1120, {P, P, SH}}; + SparcFault::vals +("PA_watchpoint", 0x061, 1209, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fast_instruction_access_MMU_miss", 0x064, 208, {H, H, SH}}; + SparcFault::vals +("VA_watchpoint", 0x062, 1120, {{P, P, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fast_data_access_MMU_miss", 0x068, 1203, {H, H, H}}; + SparcFault::vals +("fast_instruction_access_MMU_miss", 0x064, 208, {{H, H, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fast_data_access_protection", 0x06C, 1207, {H, H, H}}; + SparcFault::vals +("fast_data_access_MMU_miss", 0x068, 1203, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"instruction_break", 0x076, 610, {H, H, H}}; + SparcFault::vals +("fast_data_access_protection", 0x06C, 1207, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"cpu_mondo", 0x07C, 1608, {P, P, SH}}; + SparcFault::vals +("instruction_break", 0x076, 610, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"dev_mondo", 0x07D, 1611, {P, P, SH}}; + SparcFault::vals +("cpu_mondo", 0x07C, 1608, {{P, P, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"resume_error", 0x07E, 3330, {P, P, SH}}; + SparcFault::vals +("dev_mondo", 0x07D, 1611, {{P, P, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"spill_n_normal", 0x080, 900, {P, P, H}}; + SparcFault::vals +("resume_error", 0x07E, 3330, {{P, P, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"spill_n_other", 0x0A0, 900, {P, P, H}}; + SparcFault::vals +("spill_n_normal", 0x080, 900, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fill_n_normal", 0x0C0, 900, {P, P, H}}; + SparcFault::vals +("spill_n_other", 0x0A0, 900, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fill_n_other", 0x0E0, 900, {P, P, H}}; + SparcFault::vals +("fill_n_normal", 0x0C0, 900, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"trap_instruction", 0x100, 1602, {P, P, H}}; + SparcFault::vals +("fill_n_other", 0x0E0, 900, {{P, P, H}}); -#if !FULL_SYSTEM template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"page_table_fault", 0x0000, 0, {SH, SH, SH}}; -#endif + SparcFault::vals +("trap_instruction", 0x100, 1602, {{P, P, H}}); /** * 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) +void +enterREDState(ThreadContext *tc) { //@todo Disable the mmu? //@todo Disable watchpoints? - MiscReg HPSTATE = tc->readMiscReg(MISCREG_HPSTATE); - //HPSTATE.red = 1 - HPSTATE |= (1 << 5); - //HPSTATE.hpriv = 1 - HPSTATE |= (1 << 2); - tc->setMiscRegWithEffect(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->readMiscReg(MISCREG_PSTATE); - PSTATE |= (1 << 2); - tc->setMiscRegWithEffect(MISCREG_PSTATE, PSTATE); + HPSTATE hpstate= tc->readMiscRegNoEffect(MISCREG_HPSTATE); + hpstate.red = 1; + hpstate.hpriv = 1; + 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. + PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE); + pstate.priv = 1; + tc->setMiscReg(MISCREG_PSTATE, pstate); } /** @@ -296,94 +299,77 @@ void enterREDState(ThreadContext *tc) * the handler. */ -void doREDFault(ThreadContext *tc, TrapType tt) +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 CCR = tc->readIntReg(NumIntArchRegs + 2); - MiscReg ASI = tc->readMiscReg(MISCREG_ASI); - MiscReg CWP = tc->readMiscReg(MISCREG_CWP); - //MiscReg CANSAVE = tc->readMiscReg(MISCREG_CANSAVE); - MiscReg CANSAVE = tc->readMiscReg(NumIntArchRegs + 3); - MiscReg GL = tc->readMiscReg(MISCREG_GL); - MiscReg PC = tc->readPC(); - MiscReg NPC = tc->readNextPC(); + RegVal TL = tc->readMiscRegNoEffect(MISCREG_TL); + RegVal TSTATE = tc->readMiscRegNoEffect(MISCREG_TSTATE); + PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE); + HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE); + RegVal CCR = tc->readIntReg(NumIntArchRegs + 2); + RegVal ASI = tc->readMiscRegNoEffect(MISCREG_ASI); + RegVal CWP = tc->readMiscRegNoEffect(MISCREG_CWP); + RegVal CANSAVE = tc->readMiscRegNoEffect(NumIntArchRegs + 3); + RegVal GL = tc->readMiscRegNoEffect(MISCREG_GL); + PCState pc = tc->pcState(); TL++; - //set TSTATE.gl to gl + Addr pcMask = pstate.am ? mask(32) : mask(64); + + // set TSTATE.gl to gl replaceBits(TSTATE, 42, 40, GL); - //set TSTATE.ccr to ccr + // set TSTATE.ccr to ccr replaceBits(TSTATE, 39, 32, CCR); - //set TSTATE.asi to asi + // 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 + // 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(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.priv is set to 1 here. The manual says it should be 0, but - //Legion sets it to 1. - PSTATE |= (1 << 2); - //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); + // Write back TSTATE + tc->setMiscRegNoEffect(MISCREG_TSTATE, TSTATE); + + // set TPC to PC + tc->setMiscRegNoEffect(MISCREG_TPC, pc.pc() & pcMask); + // set TNPC to NPC + tc->setMiscRegNoEffect(MISCREG_TNPC, pc.npc() & pcMask); + + // 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(GL+1, MaxGL)); + + bool priv = pstate.priv; // just save the priv bit + pstate = 0; + pstate.priv = priv; + pstate.pef = 1; + tc->setMiscRegNoEffect(MISCREG_PSTATE, pstate); + + hpstate.red = 1; + hpstate.hpriv = 1; + hpstate.ibe = 0; + hpstate.tlz = 0; + tc->setMiscRegNoEffect(MISCREG_HPSTATE, hpstate); 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); } } @@ -392,119 +378,99 @@ void doREDFault(ThreadContext *tc, TrapType tt) * the handler. */ -void doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv) +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 CCR = tc->readIntReg(NumIntArchRegs + 2); - MiscReg ASI = tc->readMiscReg(MISCREG_ASI); - MiscReg CWP = tc->readMiscReg(MISCREG_CWP); - //MiscReg CANSAVE = tc->readMiscReg(MISCREG_CANSAVE); - MiscReg CANSAVE = tc->readIntReg(NumIntArchRegs + 3); - MiscReg GL = tc->readMiscReg(MISCREG_GL); - MiscReg PC = tc->readPC(); - MiscReg NPC = tc->readNextPC(); - - //Increment the trap level + RegVal TL = tc->readMiscRegNoEffect(MISCREG_TL); + RegVal TSTATE = tc->readMiscRegNoEffect(MISCREG_TSTATE); + PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE); + HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE); + RegVal CCR = tc->readIntReg(NumIntArchRegs + 2); + RegVal ASI = tc->readMiscRegNoEffect(MISCREG_ASI); + RegVal CWP = tc->readMiscRegNoEffect(MISCREG_CWP); + RegVal CANSAVE = tc->readIntReg(NumIntArchRegs + 3); + RegVal GL = tc->readMiscRegNoEffect(MISCREG_GL); + PCState pc = tc->pcState(); + + // Increment the trap level TL++; - tc->setMiscReg(MISCREG_TL, TL); + tc->setMiscRegNoEffect(MISCREG_TL, TL); + + Addr pcMask = pstate.am ? mask(32) : mask(64); - //Save off state + // Save off state - //set TSTATE.gl to gl + // set TSTATE.gl to gl replaceBits(TSTATE, 42, 40, GL); - //set TSTATE.ccr to ccr + // set TSTATE.ccr to ccr replaceBits(TSTATE, 39, 32, CCR); - //set TSTATE.asi to asi + // 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 + // 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); + // Write back TSTATE + tc->setMiscRegNoEffect(MISCREG_TSTATE, TSTATE); - //set TPC to PC - tc->setMiscReg(MISCREG_TPC, PC); - //set TNPC to NPC - tc->setMiscReg(MISCREG_TNPC, NPC); + // set TPC to PC + tc->setMiscRegNoEffect(MISCREG_TPC, pc.pc() & pcMask); + // set TNPC to NPC + tc->setMiscRegNoEffect(MISCREG_TNPC, pc.npc() & pcMask); - //set HTSTATE.hpstate to hpstate - tc->setMiscReg(MISCREG_HTSTATE, HPSTATE); + // set HTSTATE.hpstate to hpstate + tc->setMiscRegNoEffect(MISCREG_HTSTATE, hpstate); - //TT = trap type; - tc->setMiscReg(MISCREG_TT, tt); + // TT = trap type; + tc->setMiscRegNoEffect(MISCREG_TT, tt); - //Update the global register level - if(!gotoHpriv) - tc->setMiscRegWithEffect(MISCREG_GL, min(GL+1, MaxPGL)); - else - tc->setMiscRegWithEffect(MISCREG_GL, min(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(!gotoHpriv) - { - //PSTATE.priv = 1 - PSTATE |= (1 << 2); - //PSTATE.cle = PSTATE.tle - replaceBits(PSTATE, 9, 9, PSTATE >> 8); - } + // Update the global register level + if (!gotoHpriv) + tc->setMiscReg(MISCREG_GL, min(GL + 1, MaxPGL)); else - { - //PSTATE.priv = 0 - //PSTATE.priv is set to 1 here. The manual says it should be 0, but - //Legion sets it to 1. - 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(gotoHpriv) - { - //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); + tc->setMiscReg(MISCREG_GL, min(GL + 1, MaxGL)); + + // pstate.mm is unchanged + pstate.pef = 1; // PSTATE.pef = whether or not an fpu is present + pstate.am = 0; + pstate.ie = 0; + // pstate.tle is unchanged + // pstate.tct = 0 + + if (gotoHpriv) { + pstate.cle = 0; + // The manual says PSTATE.priv should be 0, but Legion leaves it alone + hpstate.red = 0; + hpstate.hpriv = 1; + hpstate.ibe = 0; + // hpstate.tlz is unchanged + tc->setMiscRegNoEffect(MISCREG_HPSTATE, hpstate); + } else { // we are going to priv + pstate.priv = 1; + 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) +void +getREDVector(RegVal TT, Addr &PC, Addr &NPC) { //XXX The following constant might belong in a header file. const Addr RSTVAddr = 0xFFF0000000ULL; @@ -512,133 +478,137 @@ void getREDVector(MiscReg TT, Addr & PC, Addr & NPC) NPC = PC + sizeof(MachInst); } -void getHyperVector(ThreadContext * tc, Addr & PC, Addr & NPC, MiscReg TT) +void +getHyperVector(ThreadContext * tc, Addr &PC, Addr &NPC, RegVal TT) { - Addr HTBA = tc->readMiscReg(MISCREG_HTBA); + 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) +void +getPrivVector(ThreadContext *tc, Addr &PC, Addr &NPC, RegVal TT, RegVal TL) { - Addr TBA = tc->readMiscReg(MISCREG_TBA); + 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) +void +SparcFaultBase::invoke(ThreadContext * tc, const StaticInstPtr &inst) { - panic("Invoking a second fault!\n"); FaultBase::invoke(tc); + if (!FullSystem) + return; + countStat()++; - //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); + // 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. + RegVal tl = tc->readMiscRegNoEffect(MISCREG_TL); + RegVal tt = tc->readMiscRegNoEffect(MISCREG_TT); + PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE); + HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE); Addr PC, NPC; PrivilegeLevel current; - if(HPSTATE & (1 << 2)) + if (hpstate.hpriv) current = Hyperprivileged; - else if(PSTATE & (1 << 2)) + else if (pstate.priv) current = Privileged; else current = User; PrivilegeLevel level = getNextLevel(current); - if(HPSTATE & (1 << 5) || TL == MaxTL - 1) - { + if (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. + 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) - { - //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 + } 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) - { + } else if (level == Hyperprivileged || + (level == Privileged && trapType() >= 384)) { doNormalFault(tc, trapType(), true); getHyperVector(tc, PC, NPC, trapType()); - } - else - { + } else { doNormalFault(tc, trapType(), false); - getPrivVector(tc, PC, NPC, trapType(), TL+1); + getPrivVector(tc, PC, NPC, trapType(), tl + 1); } - tc->setPC(PC); - tc->setNextPC(NPC); - tc->setNextNPC(NPC + sizeof(MachInst)); + PCState pc; + pc.pc(PC); + pc.npc(NPC); + pc.nnpc(NPC + sizeof(MachInst)); + pc.upc(0); + pc.nupc(1); + tc->pcState(pc); } -void PowerOnReset::invoke(ThreadContext * tc) +void +PowerOnReset::invoke(ThreadContext *tc, const StaticInstPtr &inst) { - //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. - - tc->setMiscReg(MISCREG_TL, MaxTL); - tc->setMiscReg(MISCREG_TT, trapType()); - tc->setMiscRegWithEffect(MISCREG_GL, MaxGL); - - //Turn on pef and priv, set everything else to 0 - tc->setMiscReg(MISCREG_PSTATE, (1 << 4) | (1 << 2)); - - //Turn on red and hpriv, set everything else to 0 - MiscReg HPSTATE = tc->readMiscReg(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->setMiscReg(MISCREG_HPSTATE, HPSTATE); - - //The tick register is unreadable by nonprivileged software - tc->setMiscReg(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. + // 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. + + tc->setMiscRegNoEffect(MISCREG_TL, MaxTL); + tc->setMiscRegNoEffect(MISCREG_TT, trapType()); + tc->setMiscReg(MISCREG_GL, MaxGL); + + PSTATE pstate = 0; + pstate.pef = 1; + pstate.priv = 1; + tc->setMiscRegNoEffect(MISCREG_PSTATE, pstate); + + // Turn on red and hpriv, set everything else to 0 + HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE); + hpstate.red = 1; + hpstate.hpriv = 1; + hpstate.ibe = 0; + hpstate.tlz = 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 + PCState pc; + pc.pc(PC); + pc.npc(NPC); + pc.nnpc(NPC + sizeof(MachInst)); + pc.upc(0); + pc.nupc(1); + tc->pcState(pc); + + // 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->setMiscReg(MISCREG_ + 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 + 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 @@ -650,63 +620,213 @@ void PowerOnReset::invoke(ThreadContext * tc) */ } -#else // !FULL_SYSTEM +void +FastInstructionAccessMMUMiss::invoke(ThreadContext *tc, + const StaticInstPtr &inst) +{ + if (FullSystem) { + SparcFaultBase::invoke(tc, inst); + return; + } + + Process *p = tc->getProcessPtr(); + const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr); + panic_if(!pte, "Tried to execute unmapped address %#x.\n", vaddr); + + Addr alignedvaddr = p->pTable->pageAlign(vaddr); + + // Grab fields used during instruction translation to figure out + // which context to use. + uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA); + + // Inside a VM, a real address is the address that guest OS would + // interpret to be a physical address. To map to the physical address, + // it still needs to undergo a translation. The instruction + // translation code in the SPARC ITLB code assumes that the context is + // zero (kernel-level) if real addressing is being used. + bool is_real_address = !bits(tlbdata, 4); + + // The SPARC ITLB code assumes that traps are executed in context + // zero so we carry that assumption through here. + bool trapped = bits(tlbdata, 18, 16) > 0; + + // The primary context acts as a PASID. It allows the MMU to + // distinguish between virtual addresses that would alias to the + // same physical address (if two or more processes shared the same + // virtual address mapping). + int primary_context = bits(tlbdata, 47, 32); + + // The partition id distinguishes between virtualized environments. + int const partition_id = 0; + + // Given the assumptions in the translateInst code in the SPARC ITLB, + // the logic works out to the following for the context. + int context_id = (is_real_address || trapped) ? 0 : primary_context; + + TlbEntry entry(p->pTable->pid(), alignedvaddr, pte->paddr, + pte->flags & EmulationPageTable::Uncacheable, + pte->flags & EmulationPageTable::ReadOnly); + + // Insert the TLB entry. + // The entry specifying whether the address is "real" is set to + // false for syscall emulation mode regardless of whether the + // address is real in preceding code. Not sure sure that this is + // correct, but also not sure if it matters at all. + dynamic_cast(tc->getITBPtr())-> + insert(alignedvaddr, partition_id, context_id, false, entry.pte); +} + +void +FastDataAccessMMUMiss::invoke(ThreadContext *tc, const StaticInstPtr &inst) +{ + if (FullSystem) { + SparcFaultBase::invoke(tc, inst); + return; + } + + Process *p = tc->getProcessPtr(); + const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr); + if (!pte && p->fixupStackFault(vaddr)) + pte = p->pTable->lookup(vaddr); + panic_if(!pte, "Tried to access unmapped address %#x.\n", vaddr); + + Addr alignedvaddr = p->pTable->pageAlign(vaddr); + + // Grab fields used during data translation to figure out + // which context to use. + uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA); + + // The primary context acts as a PASID. It allows the MMU to + // distinguish between virtual addresses that would alias to the + // same physical address (if two or more processes shared the same + // virtual address mapping). There's a secondary context used in the + // DTLB translation code, but it should __probably__ be zero for + // syscall emulation code. (The secondary context is used by Solaris + // to allow kernel privilege code to access user space code: + // [ISBN 0-13-022496-0]:PG199.) + int primary_context = bits(tlbdata, 47, 32); + + // "Hyper-Privileged Mode" is in use. There are three main modes of + // operation for Sparc: Hyper-Privileged Mode, Privileged Mode, and + // User Mode. + int hpriv = bits(tlbdata, 0); + + // Reset, Error and Debug state is in use. Something horrible has + // happened or the system is operating in Reset Mode. + int red = bits(tlbdata, 1); + + // Inside a VM, a real address is the address that guest OS would + // interpret to be a physical address. To map to the physical address, + // it still needs to undergo a translation. The instruction + // translation code in the SPARC ITLB code assumes that the context is + // zero (kernel-level) if real addressing is being used. + int is_real_address = !bits(tlbdata, 5); + + // Grab the address space identifier register from the thread context. + // XXX: Inspecting how setMiscReg and setMiscRegNoEffect behave for + // MISCREG_ASI causes me to think that the ASI register implementation + // might be bugged. The NoEffect variant changes the ASI register + // value in the architectural state while the normal variant changes + // the context field in the thread context's currently decoded request + // but does not directly affect the ASI register value in the + // architectural state. The ASI values and the context field in the + // request packet seem to have completely different uses. + RegVal reg_asi = tc->readMiscRegNoEffect(MISCREG_ASI); + ASI asi = static_cast(reg_asi); + + // The SPARC DTLB code assumes that traps are executed in context + // zero if the asi value is ASI_IMPLICIT (which is 0x0). There's also + // an assumption that the nucleus address space is being used, but + // the context is the relevant issue since we need to pass it to TLB. + bool trapped = bits(tlbdata, 18, 16) > 0; + + // Given the assumptions in the translateData code in the SPARC DTLB, + // the logic works out to the following for the context. + int context_id = ((!hpriv && !red && is_real_address) || + asiIsReal(asi) || + (trapped && asi == ASI_IMPLICIT)) + ? 0 : primary_context; + + // The partition id distinguishes between virtualized environments. + int const partition_id = 0; + + TlbEntry entry(p->pTable->pid(), alignedvaddr, pte->paddr, + pte->flags & EmulationPageTable::Uncacheable, + pte->flags & EmulationPageTable::ReadOnly); + + // Insert the TLB entry. + // The entry specifying whether the address is "real" is set to + // false for syscall emulation mode regardless of whether the + // address is real in preceding code. Not sure sure that this is + // correct, but also not sure if it matters at all. + dynamic_cast(tc->getDTBPtr())-> + insert(alignedvaddr, partition_id, context_id, false, entry.pte); +} -void SpillNNormal::invoke(ThreadContext *tc) +void +SpillNNormal::invoke(ThreadContext *tc, const StaticInstPtr &inst) { + if (FullSystem) { + SparcFaultBase::invoke(tc, inst); + return; + } + doNormalFault(tc, trapType(), false); Process *p = tc->getProcessPtr(); - //XXX This will only work in faults from a SparcLiveProcess - SparcLiveProcess *lp = dynamic_cast(p); - assert(lp); + SparcProcess *sp = dynamic_cast(p); + assert(sp); - //Then adjust the PC and NPC - Addr spillStart = lp->readSpillStart(); - tc->setPC(spillStart); - tc->setNextPC(spillStart + sizeof(MachInst)); - tc->setNextNPC(spillStart + 2*sizeof(MachInst)); + // Then adjust the PC and NPC + tc->pcState(sp->readSpillStart()); } -void FillNNormal::invoke(ThreadContext *tc) +void +FillNNormal::invoke(ThreadContext *tc, const StaticInstPtr &inst) { + if (FullSystem) { + SparcFaultBase::invoke(tc, inst); + return; + } + doNormalFault(tc, trapType(), false); - Process * p = tc->getProcessPtr(); + Process *p = tc->getProcessPtr(); - //XXX This will only work in faults from a SparcLiveProcess - SparcLiveProcess *lp = dynamic_cast(p); - assert(lp); + SparcProcess *sp = dynamic_cast(p); + assert(sp); - //Then adjust the PC and NPC - Addr fillStart = lp->readFillStart(); - tc->setPC(fillStart); - tc->setNextPC(fillStart + sizeof(MachInst)); - tc->setNextNPC(fillStart + 2*sizeof(MachInst)); + // Then adjust the PC and NPC + tc->pcState(sp->readFillStart()); } -void PageTableFault::invoke(ThreadContext *tc) +void +TrapInstruction::invoke(ThreadContext *tc, const StaticInstPtr &inst) { + if (FullSystem) { + SparcFaultBase::invoke(tc, inst); + return; + } + + // 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); - } -} + SparcProcess *sp = dynamic_cast(p); + assert(sp); + + Fault fault; + sp->handleTrap(_n, tc, &fault); -#endif + // We need to explicitly advance the pc, since that's not done for us + // on a faulting instruction + PCState pc = tc->pcState(); + pc.advance(); + tc->pcState(pc); +} } // namespace SparcISA