diff --git a/src/arch/riscv/faults.cc b/src/arch/riscv/faults.cc index 7d4e9f90b6..2e583e3680 100644 --- a/src/arch/riscv/faults.cc +++ b/src/arch/riscv/faults.cc @@ -67,6 +67,7 @@ RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst) if (FullSystem) { PrivilegeMode pp = (PrivilegeMode)tc->readMiscReg(MISCREG_PRV); PrivilegeMode prv = PRV_M; + MISA misa = tc->readMiscRegNoEffect(MISCREG_ISA); STATUS status = tc->readMiscReg(MISCREG_STATUS); // According to riscv-privileged-v1.11, if a NMI occurs at the middle @@ -82,18 +83,18 @@ RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst) } else if (isInterrupt()) { if (pp != PRV_M && bits(tc->readMiscReg(MISCREG_MIDELEG), _code) != 0) { - prv = PRV_S; + prv = (misa.rvs) ? PRV_S : ((misa.rvn) ? PRV_U : PRV_M); } - if (pp == PRV_U && + if (pp == PRV_U && misa.rvs && misa.rvn && bits(tc->readMiscReg(MISCREG_SIDELEG), _code) != 0) { prv = PRV_U; } } else { if (pp != PRV_M && bits(tc->readMiscReg(MISCREG_MEDELEG), _code) != 0) { - prv = PRV_S; + prv = (misa.rvs) ? PRV_S : ((misa.rvn) ? PRV_U : PRV_M); } - if (pp == PRV_U && + if (pp == PRV_U && misa.rvs && misa.rvn && bits(tc->readMiscReg(MISCREG_SEDELEG), _code) != 0) { prv = PRV_U; } diff --git a/src/arch/riscv/interrupts.hh b/src/arch/riscv/interrupts.hh index d6fa374a14..b003b59426 100644 --- a/src/arch/riscv/interrupts.hh +++ b/src/arch/riscv/interrupts.hh @@ -69,21 +69,41 @@ class Interrupts : public BaseInterrupts { INTERRUPT mask = 0; STATUS status = tc->readMiscReg(MISCREG_STATUS); - INTERRUPT mideleg = tc->readMiscReg(MISCREG_MIDELEG); - INTERRUPT sideleg = tc->readMiscReg(MISCREG_SIDELEG); + MISA misa = tc->readMiscRegNoEffect(MISCREG_ISA); + INTERRUPT mideleg = 0; + if (misa.rvs || misa.rvn) { + mideleg = tc->readMiscReg(MISCREG_MIDELEG); + } + INTERRUPT sideleg = 0; + if (misa.rvs && misa.rvn) { + sideleg = tc->readMiscReg(MISCREG_SIDELEG); + } PrivilegeMode prv = (PrivilegeMode)tc->readMiscReg(MISCREG_PRV); switch (prv) { case PRV_U: - mask.mei = (!sideleg.mei) | (sideleg.mei & status.uie); - mask.mti = (!sideleg.mti) | (sideleg.mti & status.uie); - mask.msi = (!sideleg.msi) | (sideleg.msi & status.uie); - mask.sei = (!sideleg.sei) | (sideleg.sei & status.uie); - mask.sti = (!sideleg.sti) | (sideleg.sti & status.uie); - mask.ssi = (!sideleg.ssi) | (sideleg.ssi & status.uie); + // status.uie is always 0 if misa.rvn is disabled + if (misa.rvs) { + mask.mei = (!sideleg.mei) | (sideleg.mei & status.uie); + mask.mti = (!sideleg.mti) | (sideleg.mti & status.uie); + mask.msi = (!sideleg.msi) | (sideleg.msi & status.uie); + mask.sei = (!sideleg.sei) | (sideleg.sei & status.uie); + mask.sti = (!sideleg.sti) | (sideleg.sti & status.uie); + mask.ssi = (!sideleg.ssi) | (sideleg.ssi & status.uie); + } else { + // According to the RISC-V privilege spec v1.10, if the + // S privilege mode is not implemented and user-trap + // support, setting mideleg/medeleg bits will delegate the + // trap to U-mode trap handler + mask.mei = (!mideleg.mei) | (mideleg.mei & status.uie); + mask.mti = (!mideleg.mti) | (mideleg.mti & status.uie); + mask.msi = (!mideleg.msi) | (mideleg.msi & status.uie); + mask.sei = mask.sti = mask.ssi = 0; + } if (status.uie) mask.uei = mask.uti = mask.usi = 1; break; case PRV_S: + // status.sie is always 0 if misa.rvn is disabled mask.mei = (!mideleg.mei) | (mideleg.mei & status.sie); mask.mti = (!mideleg.mti) | (mideleg.mti & status.sie); mask.msi = (!mideleg.msi) | (mideleg.msi & status.sie); diff --git a/src/arch/riscv/isa.cc b/src/arch/riscv/isa.cc index 81fb7f3061..18e9b5fce2 100644 --- a/src/arch/riscv/isa.cc +++ b/src/arch/riscv/isa.cc @@ -528,6 +528,24 @@ ISA::readMiscReg(RegIndex idx) default: panic("%s: Unknown _rvType: %d", name(), (int)_rvType); } + // Check status.mpp + MISA misa = readMiscRegNoEffect(MISCREG_ISA); + switch(status.mpp) { + case PRV_U: + status.mpp = (misa.rvu) ? PRV_U : PRV_M; + break; + case PRV_S: + if (misa.rvs) + status.mpp = PRV_S; + else + status.mpp = (misa.rvu) ? PRV_U : PRV_M; + break; + case PRV_M: + break; + default: + status.mpp = (misa.rvu) ? PRV_U : PRV_M; + } + setMiscRegNoEffect(idx, status); return readMiscRegNoEffect(idx); diff --git a/src/arch/riscv/isa/decoder.isa b/src/arch/riscv/isa/decoder.isa index 3d1d396165..cf2d3491e3 100644 --- a/src/arch/riscv/isa/decoder.isa +++ b/src/arch/riscv/isa/decoder.isa @@ -4595,6 +4595,12 @@ decode QUADRANT default Unknown::unknown() { xc->pcState()); }}, IsSerializeAfter, IsNonSpeculative, No_OpClass); 0x2: uret({{ + MISA misa = xc->readMiscReg(MISCREG_ISA); + if (!misa.rvn) { + return std::make_shared( + "sret can't execute without N systems", + machInst); + } STATUS status = xc->readMiscReg(MISCREG_STATUS); status.uie = status.upie; status.upie = 1; @@ -4604,6 +4610,12 @@ decode QUADRANT default Unknown::unknown() { } 0x8: decode RS2 { 0x2: sret({{ + MISA misa = xc->readMiscReg(MISCREG_ISA); + if (!misa.rvs) { + return std::make_shared( + "sret can't execute without RVS", + machInst); + } STATUS status = xc->readMiscReg(MISCREG_STATUS); auto pm = (PrivilegeMode)xc->readMiscReg( MISCREG_PRV); @@ -4623,11 +4635,12 @@ decode QUADRANT default Unknown::unknown() { } }}, IsSerializeAfter, IsNonSpeculative, IsReturn); 0x5: wfi({{ + MISA misa = xc->readMiscReg(MISCREG_ISA); STATUS status = xc->readMiscReg(MISCREG_STATUS); auto pm = (PrivilegeMode)xc->readMiscReg( MISCREG_PRV); - if (pm == PRV_U || - (pm == PRV_S && status.tw == 1)) { + if (misa.rvs && (pm == PRV_U || + (pm == PRV_S && status.tw == 1))) { return std::make_shared( "wfi in user mode or TW enabled", machInst); @@ -4647,6 +4660,12 @@ decode QUADRANT default Unknown::unknown() { IsSerializeAfter, No_OpClass); } 0x9: sfence_vma({{ + MISA misa = xc->readMiscReg(MISCREG_ISA); + if (!misa.rvs) { + return std::make_shared( + "sfence_vma can't execute without RVS", + machInst); + } STATUS status = xc->readMiscReg(MISCREG_STATUS); auto pm = (PrivilegeMode)xc->readMiscReg(MISCREG_PRV); if (pm == PRV_U || (pm == PRV_S && status.tvm == 1)) {