summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Roelke <alec.roelke@gmail.com>2018-06-10 18:41:34 -0400
committerAlec Roelke <alec.roelke@gmail.com>2018-07-28 18:49:16 +0000
commita27ce59a39ec8fa20a3c4e9fa53e9b3db1199e91 (patch)
treed230b106cca136fba2b559ceb8f17843798eaa69
parent76e7aec54256696dfdc9567c7ea325fb07c48ef1 (diff)
downloadgem5-a27ce59a39ec8fa20a3c4e9fa53e9b3db1199e91.tar.xz
arch-riscv: Add xret instructions
This patch adds the uret, sret, and mret instructions for use with returning from user-, supervisor-, and machine-level code, respectively. These instructions read the STATUS register to determine the previous privilege level and modify it to re-enable interrupts at the old privilege level. These instructions can only be executed at the corresponding privilege level or higher. Change-Id: I6125c31cb2fdcc3f83eca86910519e81ffbbbfc9 Reviewed-on: https://gem5-review.googlesource.com/11136 Maintainer: Alec Roelke <alec.roelke@gmail.com> Reviewed-by: Jason Lowe-Power <jason@lowepower.com> Reviewed-by: Robert Scheffel <robert.scheffel1@tu-dresden.de>
-rw-r--r--src/arch/riscv/faults.hh77
-rw-r--r--src/arch/riscv/isa/decoder.isa44
-rw-r--r--src/arch/riscv/registers.hh47
3 files changed, 110 insertions, 58 deletions
diff --git a/src/arch/riscv/faults.hh b/src/arch/riscv/faults.hh
index 6d3fdebbe..d9cb44c3d 100644
--- a/src/arch/riscv/faults.hh
+++ b/src/arch/riscv/faults.hh
@@ -34,8 +34,10 @@
#ifndef __ARCH_RISCV_FAULTS_HH__
#define __ARCH_RISCV_FAULTS_HH__
+#include <map>
#include <string>
+#include "arch/riscv/isa.hh"
#include "arch/riscv/registers.hh"
#include "cpu/thread_context.hh"
#include "sim/faults.hh"
@@ -71,59 +73,12 @@ enum ExceptionCode : MiscReg {
AMO_PAGE = 15
};
-/**
- * These fields are specified in the RISC-V Instruction Set Manual, Volume II,
- * v1.10, accessible at www.riscv.org. in Figure 3.7. The main register that
- * uses these fields is the MSTATUS register, which is shadowed by two others
- * accessible at lower privilege levels (SSTATUS and USTATUS) that can't see
- * the fields for higher privileges.
- */
-BitUnion64(STATUS)
- Bitfield<63> sd;
- Bitfield<35, 34> sxl;
- Bitfield<33, 32> uxl;
- Bitfield<22> tsr;
- Bitfield<21> tw;
- Bitfield<20> tvm;
- Bitfield<19> mxr;
- Bitfield<18> sum;
- Bitfield<17> mprv;
- Bitfield<16, 15> xs;
- Bitfield<14, 13> fs;
- Bitfield<12, 11> mpp;
- Bitfield<8> spp;
- Bitfield<7> mpie;
- Bitfield<5> spie;
- Bitfield<4> upie;
- Bitfield<3> mie;
- Bitfield<1> sie;
- Bitfield<0> uie;
-EndBitUnion(STATUS)
-
-/**
- * These fields are specified in the RISC-V Instruction Set Manual, Volume II,
- * v1.10 in Figures 3.11 and 3.12, accessible at www.riscv.org. Both the MIP
- * and MIE registers have the same fields, so accesses to either should use
- * this bit union.
- */
-BitUnion64(INTERRUPT)
- Bitfield<11> mei;
- Bitfield<9> sei;
- Bitfield<8> uei;
- Bitfield<7> mti;
- Bitfield<5> sti;
- Bitfield<4> uti;
- Bitfield<3> msi;
- Bitfield<1> ssi;
- Bitfield<0> usi;
-EndBitUnion(INTERRUPT)
-
class RiscvFault : public FaultBase
{
protected:
const FaultName _name;
- bool _interrupt;
- const ExceptionCode _code;
+ const bool _interrupt;
+ ExceptionCode _code;
RiscvFault(FaultName n, bool i, ExceptionCode c)
: _name(n), _interrupt(i), _code(c)
@@ -254,12 +209,28 @@ class BreakpointFault : public RiscvFault
class SyscallFault : public RiscvFault
{
public:
- // TODO: replace ECALL_USER with the appropriate privilege level of the
- // caller
- SyscallFault() : RiscvFault("System call", false, ECALL_USER) {}
+ SyscallFault(PrivilegeMode prv)
+ : RiscvFault("System call", false, ECALL_USER)
+ {
+ switch (prv) {
+ case PRV_U:
+ _code = ECALL_USER;
+ break;
+ case PRV_S:
+ _code = ECALL_SUPER;
+ break;
+ case PRV_M:
+ _code = ECALL_MACHINE;
+ break;
+ default:
+ panic("Unknown privilege mode %d.", prv);
+ break;
+ }
+ }
+
void invokeSE(ThreadContext *tc, const StaticInstPtr &inst) override;
};
} // namespace RiscvISA
-#endif // __ARCH_RISCV_FAULTS_HH__ \ No newline at end of file
+#endif // __ARCH_RISCV_FAULTS_HH__
diff --git a/src/arch/riscv/isa/decoder.isa b/src/arch/riscv/isa/decoder.isa
index a0e3ad19d..0c1d7726c 100644
--- a/src/arch/riscv/isa/decoder.isa
+++ b/src/arch/riscv/isa/decoder.isa
@@ -1708,16 +1708,50 @@ decode QUADRANT default Unknown::unknown() {
format SystemOp {
0x0: decode FUNCT12 {
0x0: ecall({{
- fault = make_shared<SyscallFault>();
+ fault = make_shared<SyscallFault>(
+ (PrivilegeMode)xc->readMiscReg(MISCREG_PRV));
}}, IsSerializeAfter, IsNonSpeculative, IsSyscall,
No_OpClass);
0x1: ebreak({{
fault = make_shared<BreakpointFault>(xc->pcState());
}}, IsSerializeAfter, IsNonSpeculative, No_OpClass);
- 0x100: eret({{
- fault = make_shared<UnimplementedFault>("eret",
- machInst);
- }}, No_OpClass);
+ 0x2: uret({{
+ STATUS status = xc->readMiscReg(MISCREG_STATUS);
+ status.uie = status.upie;
+ status.upie = 1;
+ xc->setMiscReg(MISCREG_STATUS, status);
+ NPC = xc->readMiscReg(MISCREG_UEPC);
+ }}, IsReturn);
+ 0x102: sret({{
+ if (xc->readMiscReg(MISCREG_PRV) == PRV_U) {
+ fault = make_shared<IllegalInstFault>(
+ "sret in user mode", machInst);
+ NPC = NPC;
+ } else {
+ STATUS status = xc->readMiscReg(MISCREG_STATUS);
+ xc->setMiscReg(MISCREG_PRV, status.spp);
+ status.sie = status.spie;
+ status.spie = 1;
+ status.spp = PRV_U;
+ xc->setMiscReg(MISCREG_STATUS, status);
+ NPC = xc->readMiscReg(MISCREG_SEPC);
+ }
+ }}, IsReturn);
+ 0x302: mret({{
+ if (xc->readMiscReg(MISCREG_PRV) != PRV_M) {
+ fault = make_shared<IllegalInstFault>(
+ "mret at lower privilege", machInst);
+ NPC = NPC;
+ } else {
+ STATUS status = xc->readMiscReg(MISCREG_STATUS);
+ xc->setMiscReg(MISCREG_PRV, status.mpp);
+ status.mie = status.mpie;
+ status.mpie = 1;
+ status.mpp = PRV_U;
+ xc->setMiscReg(MISCREG_STATUS, status);
+ NPC = xc->readMiscReg(MISCREG_MEPC);
+ }
+ }}, IsReturn);
}
}
format CSROp {
diff --git a/src/arch/riscv/registers.hh b/src/arch/riscv/registers.hh
index e1d57ee53..bd95cf821 100644
--- a/src/arch/riscv/registers.hh
+++ b/src/arch/riscv/registers.hh
@@ -583,6 +583,53 @@ const std::map<int, CSRMetadata> CSRData = {
{CSR_DSCRATCH, {"dscratch", MISCREG_DSCRATCH}}
};
+/**
+ * These fields are specified in the RISC-V Instruction Set Manual, Volume II,
+ * v1.10, accessible at www.riscv.org. in Figure 3.7. The main register that
+ * uses these fields is the MSTATUS register, which is shadowed by two others
+ * accessible at lower privilege levels (SSTATUS and USTATUS) that can't see
+ * the fields for higher privileges.
+ */
+BitUnion64(STATUS)
+ Bitfield<63> sd;
+ Bitfield<35, 34> sxl;
+ Bitfield<33, 32> uxl;
+ Bitfield<22> tsr;
+ Bitfield<21> tw;
+ Bitfield<20> tvm;
+ Bitfield<19> mxr;
+ Bitfield<18> sum;
+ Bitfield<17> mprv;
+ Bitfield<16, 15> xs;
+ Bitfield<14, 13> fs;
+ Bitfield<12, 11> mpp;
+ Bitfield<8> spp;
+ Bitfield<7> mpie;
+ Bitfield<5> spie;
+ Bitfield<4> upie;
+ Bitfield<3> mie;
+ Bitfield<1> sie;
+ Bitfield<0> uie;
+EndBitUnion(STATUS)
+
+/**
+ * These fields are specified in the RISC-V Instruction Set Manual, Volume II,
+ * v1.10 in Figures 3.11 and 3.12, accessible at www.riscv.org. Both the MIP
+ * and MIE registers have the same fields, so accesses to either should use
+ * this bit union.
+ */
+BitUnion64(INTERRUPT)
+ Bitfield<11> mei;
+ Bitfield<9> sei;
+ Bitfield<8> uei;
+ Bitfield<7> mti;
+ Bitfield<5> sti;
+ Bitfield<4> uti;
+ Bitfield<3> msi;
+ Bitfield<1> ssi;
+ Bitfield<0> usi;
+EndBitUnion(INTERRUPT)
+
const off_t MXL_OFFSET = (sizeof(MiscReg) * 8 - 2);
const off_t SXL_OFFSET = 34;
const off_t UXL_OFFSET = 32;