X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Farch%2Fsparc%2Ffaults.cc;h=3859b30ecca95b8b9c8f83e3c5e0b3f2024262f6;hb=ddcc0ab2b4eb301d4e31800736590e4315b1b6b1;hp=e67b8c50e16c54f1ff08e831ce68be3d026b86ba;hpb=dc0e629ea1f074691d307cde3ab7dd51a5e2102f;p=gem5.git diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc index e67b8c50e..3859b30ec 100644 --- a/src/arch/sparc/faults.cc +++ b/src/arch/sparc/faults.cc @@ -29,20 +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 "sim/full_system.hh" #include "cpu/base.hh" #include "cpu/thread_context.hh" #include "mem/page_table.hh" -#include "sim/process.hh" #include "sim/full_system.hh" +#include "sim/process.hh" using namespace std; @@ -50,221 +51,227 @@ 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}}; + 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_exception_ieee_754", 0x021, 1110, {P, P, H}}; + SparcFault::vals +("fp_disabled", 0x020, 800, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fp_exception_other", 0x022, 1110, {P, P, H}}; + SparcFault::vals +("fp_exception_ieee_754", 0x021, 1110, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"tag_overflow", 0x023, 1400, {P, P, H}}; + SparcFault::vals +("fp_exception_other", 0x022, 1110, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"clean_window", 0x024, 1010, {P, P, H}}; + SparcFault::vals +("tag_overflow", 0x023, 1400, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"division_by_zero", 0x028, 1500, {P, P, H}}; + SparcFault::vals +("clean_window", 0x024, 1010, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"internal_processor_error", 0x029, 4, {H, H, H}}; + SparcFault::vals +("division_by_zero", 0x028, 1500, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"instruction_invalid_tsb_entry", 0x02A, 210, {H, H, SH}}; + SparcFault::vals +("internal_processor_error", 0x029, 4, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"data_invalid_tsb_entry", 0x02B, 1203, {H, H, H}}; + SparcFault::vals +("instruction_invalid_tsb_entry", 0x02A, 210, {{H, H, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"data_access_exception", 0x030, 1201, {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}}); //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", 0x040, 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 = - {"interrupt_vector", 0x060, 2630, {H, H, H}}; + SparcFault::vals +("interrupt_vector", 0x060, 2630, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"PA_watchpoint", 0x061, 1209, {H, H, H}}; + SparcFault::vals +("PA_watchpoint", 0x061, 1209, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"VA_watchpoint", 0x062, 1120, {P, P, SH}}; + SparcFault::vals +("VA_watchpoint", 0x062, 1120, {{P, P, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fast_instruction_access_MMU_miss", 0x064, 208, {H, H, SH}}; + SparcFault::vals +("fast_instruction_access_MMU_miss", 0x064, 208, {{H, H, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fast_data_access_MMU_miss", 0x068, 1203, {H, H, H}}; + SparcFault::vals +("fast_data_access_MMU_miss", 0x068, 1203, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fast_data_access_protection", 0x06C, 1207, {H, H, H}}; + SparcFault::vals +("fast_data_access_protection", 0x06C, 1207, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"instruction_break", 0x076, 610, {H, H, H}}; + SparcFault::vals +("instruction_break", 0x076, 610, {{H, H, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"cpu_mondo", 0x07C, 1608, {P, P, SH}}; + SparcFault::vals +("cpu_mondo", 0x07C, 1608, {{P, P, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"dev_mondo", 0x07D, 1611, {P, P, SH}}; + SparcFault::vals +("dev_mondo", 0x07D, 1611, {{P, P, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"resume_error", 0x07E, 3330, {P, P, SH}}; + SparcFault::vals +("resume_error", 0x07E, 3330, {{P, P, SH}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"spill_n_normal", 0x080, 900, {P, P, H}}; + SparcFault::vals +("spill_n_normal", 0x080, 900, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"spill_n_other", 0x0A0, 900, {P, P, H}}; + SparcFault::vals +("spill_n_other", 0x0A0, 900, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fill_n_normal", 0x0C0, 900, {P, P, H}}; + SparcFault::vals +("fill_n_normal", 0x0C0, 900, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"fill_n_other", 0x0E0, 900, {P, P, H}}; + SparcFault::vals +("fill_n_other", 0x0E0, 900, {{P, P, H}}); template<> SparcFaultBase::FaultVals - SparcFault::vals = - {"trap_instruction", 0x100, 1602, {P, P, H}}; + SparcFault::vals +("trap_instruction", 0x100, 1602, {{P, P, H}}); /** * This causes the thread context to enter RED state. This causes the side @@ -276,17 +283,15 @@ 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); + 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. - MiscReg PSTATE = tc->readMiscRegNoEffect(MISCREG_PSTATE); - PSTATE |= (1 << 2); - tc->setMiscReg(MISCREG_PSTATE, PSTATE); + PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE); + pstate.priv = 1; + tc->setMiscReg(MISCREG_PSTATE, pstate); } /** @@ -297,20 +302,20 @@ enterREDState(ThreadContext *tc) 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->readIntReg(NumIntArchRegs + 2); - MiscReg ASI = tc->readMiscRegNoEffect(MISCREG_ASI); - MiscReg CWP = tc->readMiscRegNoEffect(MISCREG_CWP); - MiscReg CANSAVE = tc->readMiscRegNoEffect(NumIntArchRegs + 3); - MiscReg GL = tc->readMiscRegNoEffect(MISCREG_GL); + 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++; - Addr pcMask = bits(PSTATE, 3) ? mask(32) : mask(64); + Addr pcMask = pstate.am ? mask(32) : mask(64); // set TSTATE.gl to gl replaceBits(TSTATE, 42, 40, GL); @@ -319,7 +324,7 @@ doREDFault(ThreadContext *tc, TrapType tt) // set TSTATE.asi to asi replaceBits(TSTATE, 31, 24, ASI); // set TSTATE.pstate to pstate - replaceBits(TSTATE, 20, 8, PSTATE); + replaceBits(TSTATE, 20, 8, pstate); // set TSTATE.cwp to cwp replaceBits(TSTATE, 4, 0, CWP); @@ -332,7 +337,7 @@ doREDFault(ThreadContext *tc, TrapType tt) tc->setMiscRegNoEffect(MISCREG_TNPC, pc.npc() & pcMask); // set HTSTATE.hpstate to hpstate - tc->setMiscRegNoEffect(MISCREG_HTSTATE, HPSTATE); + tc->setMiscRegNoEffect(MISCREG_HTSTATE, hpstate); // TT = trap type; tc->setMiscRegNoEffect(MISCREG_TT, tt); @@ -340,19 +345,17 @@ doREDFault(ThreadContext *tc, TrapType tt) // Update GL tc->setMiscReg(MISCREG_GL, min(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); + bool priv = pstate.priv; // just save the priv bit + pstate = 0; + pstate.priv = priv; + pstate.pef = 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); + hpstate.red = 1; + hpstate.hpriv = 1; + hpstate.ibe = 0; + hpstate.tlz = 0; + tc->setMiscRegNoEffect(MISCREG_HPSTATE, hpstate); bool changedCWP = true; if (tt == 0x24) @@ -378,22 +381,22 @@ doREDFault(ThreadContext *tc, TrapType tt) void doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv) { - 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->readIntReg(NumIntArchRegs + 2); - MiscReg ASI = tc->readMiscRegNoEffect(MISCREG_ASI); - MiscReg CWP = tc->readMiscRegNoEffect(MISCREG_CWP); - MiscReg CANSAVE = tc->readIntReg(NumIntArchRegs + 3); - MiscReg GL = tc->readMiscRegNoEffect(MISCREG_GL); + 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->setMiscRegNoEffect(MISCREG_TL, TL); - Addr pcMask = bits(PSTATE, 3) ? mask(32) : mask(64); + Addr pcMask = pstate.am ? mask(32) : mask(64); // Save off state @@ -404,7 +407,7 @@ doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv) // set TSTATE.asi to asi replaceBits(TSTATE, 31, 24, ASI); // set TSTATE.pstate to pstate - replaceBits(TSTATE, 20, 8, PSTATE); + replaceBits(TSTATE, 20, 8, pstate); // set TSTATE.cwp to cwp replaceBits(TSTATE, 4, 0, CWP); @@ -417,7 +420,7 @@ doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv) tc->setMiscRegNoEffect(MISCREG_TNPC, pc.npc() & pcMask); // set HTSTATE.hpstate to hpstate - tc->setMiscRegNoEffect(MISCREG_HTSTATE, HPSTATE); + tc->setMiscRegNoEffect(MISCREG_HTSTATE, hpstate); // TT = trap type; tc->setMiscRegNoEffect(MISCREG_TT, tt); @@ -428,26 +431,26 @@ doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv) else tc->setMiscReg(MISCREG_GL, min(GL + 1, MaxGL)); - // PSTATE.mm is unchanged - 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 + // 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 &= ~(1 << 9); // PSTATE.cle = 0 + 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->setMiscRegNoEffect(MISCREG_HPSTATE, HPSTATE); + 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 |= (1 << 2); // PSTATE.priv = 1 - replaceBits(PSTATE, 9, 9, PSTATE >> 8); // PSTATE.cle = PSTATE.tle + pstate.priv = 1; + pstate.cle = pstate.tle; } - tc->setMiscRegNoEffect(MISCREG_PSTATE, PSTATE); + tc->setMiscRegNoEffect(MISCREG_PSTATE, pstate); bool changedCWP = true; @@ -467,7 +470,7 @@ doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv) } void -getREDVector(MiscReg TT, Addr &PC, Addr &NPC) +getREDVector(RegVal TT, Addr &PC, Addr &NPC) { //XXX The following constant might belong in a header file. const Addr RSTVAddr = 0xFFF0000000ULL; @@ -476,7 +479,7 @@ getREDVector(MiscReg TT, Addr &PC, Addr &NPC) } void -getHyperVector(ThreadContext * tc, Addr &PC, Addr &NPC, MiscReg TT) +getHyperVector(ThreadContext * tc, Addr &PC, Addr &NPC, RegVal TT) { Addr HTBA = tc->readMiscRegNoEffect(MISCREG_HTBA); PC = (HTBA & ~mask(14)) | ((TT << 5) & mask(14)); @@ -484,7 +487,7 @@ getHyperVector(ThreadContext * tc, Addr &PC, Addr &NPC, MiscReg TT) } void -getPrivVector(ThreadContext *tc, Addr &PC, Addr &NPC, MiscReg TT, MiscReg TL) +getPrivVector(ThreadContext *tc, Addr &PC, Addr &NPC, RegVal TT, RegVal TL) { Addr TBA = tc->readMiscRegNoEffect(MISCREG_TBA); PC = (TBA & ~mask(15)) | @@ -494,7 +497,7 @@ getPrivVector(ThreadContext *tc, Addr &PC, Addr &NPC, MiscReg TT, MiscReg TL) } void -SparcFaultBase::invoke(ThreadContext * tc, StaticInstPtr inst) +SparcFaultBase::invoke(ThreadContext * tc, const StaticInstPtr &inst) { FaultBase::invoke(tc); if (!FullSystem) @@ -504,24 +507,24 @@ SparcFaultBase::invoke(ThreadContext * tc, StaticInstPtr inst) // 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); + 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 & HPSTATE::hpriv) + if (hpstate.hpriv) current = Hyperprivileged; - else if (pstate & PSTATE::priv) + else if (pstate.priv) current = Privileged; else current = User; PrivilegeLevel level = getNextLevel(current); - if ((hpstate & HPSTATE::red) || (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 @@ -555,7 +558,7 @@ SparcFaultBase::invoke(ThreadContext * tc, StaticInstPtr inst) } void -PowerOnReset::invoke(ThreadContext *tc, StaticInstPtr inst) +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. @@ -565,20 +568,18 @@ PowerOnReset::invoke(ThreadContext *tc, StaticInstPtr inst) 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)); + PSTATE pstate = 0; + pstate.pef = 1; + pstate.priv = 1; + tc->setMiscRegNoEffect(MISCREG_PSTATE, pstate); // 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); + 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); @@ -620,7 +621,8 @@ PowerOnReset::invoke(ThreadContext *tc, StaticInstPtr inst) } void -FastInstructionAccessMMUMiss::invoke(ThreadContext *tc, StaticInstPtr inst) +FastInstructionAccessMMUMiss::invoke(ThreadContext *tc, + const StaticInstPtr &inst) { if (FullSystem) { SparcFaultBase::invoke(tc, inst); @@ -628,19 +630,54 @@ FastInstructionAccessMMUMiss::invoke(ThreadContext *tc, StaticInstPtr inst) } 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); - } + 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, StaticInstPtr inst) +FastDataAccessMMUMiss::invoke(ThreadContext *tc, const StaticInstPtr &inst) { if (FullSystem) { SparcFaultBase::invoke(tc, inst); @@ -648,23 +685,86 @@ FastDataAccessMMUMiss::invoke(ThreadContext *tc, StaticInstPtr inst) } Process *p = tc->getProcessPtr(); - TlbEntry entry; - bool success = p->pTable->lookup(vaddr, entry); - if (!success) { - if (p->fixupStackFault(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); - } + 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, StaticInstPtr inst) +SpillNNormal::invoke(ThreadContext *tc, const StaticInstPtr &inst) { if (FullSystem) { SparcFaultBase::invoke(tc, inst); @@ -675,16 +775,15 @@ SpillNNormal::invoke(ThreadContext *tc, StaticInstPtr inst) 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 - tc->pcState(lp->readSpillStart()); + tc->pcState(sp->readSpillStart()); } void -FillNNormal::invoke(ThreadContext *tc, StaticInstPtr inst) +FillNNormal::invoke(ThreadContext *tc, const StaticInstPtr &inst) { if (FullSystem) { SparcFaultBase::invoke(tc, inst); @@ -695,16 +794,15 @@ FillNNormal::invoke(ThreadContext *tc, StaticInstPtr inst) 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 - tc->pcState(lp->readFillStart()); + tc->pcState(sp->readFillStart()); } void -TrapInstruction::invoke(ThreadContext *tc, StaticInstPtr inst) +TrapInstruction::invoke(ThreadContext *tc, const StaticInstPtr &inst) { if (FullSystem) { SparcFaultBase::invoke(tc, inst); @@ -717,10 +815,11 @@ TrapInstruction::invoke(ThreadContext *tc, StaticInstPtr inst) Process *p = tc->getProcessPtr(); - SparcLiveProcess *lp = dynamic_cast(p); - assert(lp); + SparcProcess *sp = dynamic_cast(p); + assert(sp); - lp->handleTrap(_n, tc); + Fault fault; + sp->handleTrap(_n, tc, &fault); // We need to explicitly advance the pc, since that's not done for us // on a faulting instruction