diff options
author | Alec Roelke <ar4jc@virginia.edu> | 2018-02-18 22:28:44 -0500 |
---|---|---|
committer | Alec Roelke <ar4jc@virginia.edu> | 2018-07-28 18:42:43 +0000 |
commit | 2595fe6b2834fa0af15baf6f5ad4a8f523c838a6 (patch) | |
tree | 95b61f9c62b0ed8c05f8829daaf303cf6f7d61ad /src/arch/riscv/faults.cc | |
parent | 0a7193c1712ceba021732e4ad2b4dfb0a10394cc (diff) | |
download | gem5-2595fe6b2834fa0af15baf6f5ad4a8f523c838a6.tar.xz |
arch-riscv: Add support for fault handling
This patch adds support for handling RISC-V faults, including tracking
current and previous execution privilege, correctly switching to
the privilege mode specified by CSRs, and setting/storing the PC. It
also includes changes introduced by patch #9821, which disables
interrupts during handling of a fault.
Change-Id: Ie9c0f29719620c20783540d3bdb2db44f6114fc9
Reviewed-on: https://gem5-review.googlesource.com/9161
Maintainer: Alec Roelke <ar4jc@virginia.edu>
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Diffstat (limited to 'src/arch/riscv/faults.cc')
-rw-r--r-- | src/arch/riscv/faults.cc | 86 |
1 files changed, 74 insertions, 12 deletions
diff --git a/src/arch/riscv/faults.cc b/src/arch/riscv/faults.cc index ce4cb3846..efab6c444 100644 --- a/src/arch/riscv/faults.cc +++ b/src/arch/riscv/faults.cc @@ -32,6 +32,8 @@ */ #include "arch/riscv/faults.hh" +#include "arch/riscv/isa.hh" +#include "arch/riscv/registers.hh" #include "arch/riscv/system.hh" #include "arch/riscv/utility.hh" #include "cpu/base.hh" @@ -39,10 +41,11 @@ #include "sim/debug.hh" #include "sim/full_system.hh" -using namespace RiscvISA; +namespace RiscvISA +{ void -RiscvFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst) +RiscvFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { panic("Fault %s encountered at pc 0x%016llx.", name(), tc->pcState().pc()); } @@ -50,14 +53,71 @@ RiscvFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst) void RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst) { + PCState pcState = tc->pcState(); + if (FullSystem) { - panic("Full system mode not supported for RISC-V."); + PrivilegeMode pp = (PrivilegeMode)tc->readMiscReg(MISCREG_PRV); + PrivilegeMode prv = PRV_M; + STATUS status = tc->readMiscReg(MISCREG_STATUS); + + // Set fault handler privilege mode + if (pp != PRV_M && + bits(tc->readMiscReg(MISCREG_MEDELEG), _code) != 0) { + prv = PRV_S; + } + if (pp == PRV_U && + bits(tc->readMiscReg(MISCREG_SEDELEG), _code) != 0) { + prv = PRV_U; + } + + // Set fault registers and status + MiscRegIndex cause, epc, tvec; + switch (prv) { + case PRV_U: + cause = MISCREG_UCAUSE; + epc = MISCREG_UEPC; + tvec = MISCREG_UTVEC; + + status.upie = status.uie; + status.uie = 0; + break; + case PRV_S: + cause = MISCREG_SCAUSE; + epc = MISCREG_SEPC; + tvec = MISCREG_STVEC; + + status.spp = pp; + status.spie = status.sie; + status.sie = 0; + break; + case PRV_M: + cause = MISCREG_MCAUSE; + epc = MISCREG_MEPC; + tvec = MISCREG_MTVEC; + + status.mpp = pp; + status.mpie = status.sie; + status.mie = 0; + break; + default: + panic("Unknown privilege mode %d.", prv); + break; + } + + // Set fault cause, privilege, and return PC + tc->setMiscReg(cause, + (isInterrupt() << (sizeof(MiscReg) * 4 - 1)) | _code); + tc->setMiscReg(epc, tc->instAddr()); + tc->setMiscReg(MISCREG_PRV, prv); + tc->setMiscReg(MISCREG_STATUS, status); + + // Set PC to fault handler address + pcState.set(tc->readMiscReg(tvec) >> 2); } else { - invoke_se(tc, inst); - PCState pcState = tc->pcState(); + invokeSE(tc, inst); advancePC(pcState, inst); - tc->pcState(pcState); } + tc->pcState(pcState); } void Reset::invoke(ThreadContext *tc, const StaticInstPtr &inst) @@ -73,21 +133,21 @@ void Reset::invoke(ThreadContext *tc, const StaticInstPtr &inst) } void -UnknownInstFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst) +UnknownInstFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { panic("Unknown instruction 0x%08x at pc 0x%016llx", inst->machInst, tc->pcState().pc()); } void -IllegalInstFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst) +IllegalInstFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { panic("Illegal instruction 0x%08x at pc 0x%016llx: %s", inst->machInst, tc->pcState().pc(), reason.c_str()); } void -UnimplementedFault::invoke_se(ThreadContext *tc, +UnimplementedFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { panic("Unimplemented instruction %s at pc 0x%016llx", instName, @@ -95,21 +155,23 @@ UnimplementedFault::invoke_se(ThreadContext *tc, } void -IllegalFrmFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst) +IllegalFrmFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { panic("Illegal floating-point rounding mode 0x%x at pc 0x%016llx.", frm, tc->pcState().pc()); } void -BreakpointFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst) +BreakpointFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { schedRelBreak(0); } void -SyscallFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst) +SyscallFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { Fault *fault = NoFault; tc->syscall(tc->readIntReg(SyscallNumReg), fault); } + +} // namespace RiscvISA
\ No newline at end of file |