gem5 [DEVELOP-FOR-25.1]
Loading...
Searching...
No Matches
faults.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016 RISC-V Foundation
3 * Copyright (c) 2016 The University of Virginia
4 * Copyright (c) 2018 TU Dresden
5 * Copyright (c) 2020 Barkhausen Institut
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met: redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer;
12 * redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution;
15 * neither the name of the copyright holders nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "arch/riscv/faults.hh"
33
35#include "arch/riscv/isa.hh"
36#include "arch/riscv/mmu.hh"
37#include "arch/riscv/pmp.hh"
39#include "arch/riscv/utility.hh"
40#include "cpu/base.hh"
41#include "cpu/thread_context.hh"
42#include "debug/Faults.hh"
43#include "sim/debug.hh"
44#include "sim/full_system.hh"
45#include "sim/system.hh"
46#include "sim/workload.hh"
47
48namespace gem5
49{
50
51namespace RiscvISA
52{
53
54void
56{
57 panic("Fault %s encountered at pc %s.", name(), tc->pcState());
58}
59
60void
62{
63 auto pc_state = tc->pcState().as<PCState>();
64
65 DPRINTFS(Faults, tc->getCpuPtr(), "Fault (%s, %u) at PC: %s\n",
66 name(), exception(), pc_state);
67
68 if (FullSystem) {
70 PrivilegeMode prv = PRV_M;
71 MISA misa = tc->readMiscRegNoEffect(MISCREG_ISA);
72 STATUS status = tc->readMiscReg(MISCREG_STATUS);
73 NSTATUS nstatus = tc->readMiscReg(MISCREG_MNSTATUS);
74 auto* isa = static_cast<RiscvISA::ISA*>(tc->getIsaPtr());
75 bool is_rnmi = isResumableNonMaskableInterrupt(isa);
76
77 // previous virtualization (H-extension)
78 bool pv = misa.rvh ? virtualizationEnabled(tc) : false;
79
80 // MISCREG_PRV (mirroring mpp) cannot have PRV_HS == 2
81 // it can only be 0 (U), 1 (S), 3 (M).
82 // Consult Table 8.8, 8.9 RISCV Privileged Spec V20211203
83 if (misa.rvh && pp == PRV_HS) {
84 panic("Privilege in MISCREG_PRV is PRV_HS == 2!");
85 }
86
87 // According to riscv-privileged-v1.11, if a NMI occurs at the middle
88 // of a M-mode trap handler, the state (epc/cause) will be overwritten
89 // and is not necessary recoverable unless smrnmi enabled.
90 warn_if(!isa->enableSmrnmi() && isNonMaskableInterrupt() &&
91 pp == PRV_M && status.mie == 0,
92 "NMI overwriting M-mode trap handler state");
93
94 // Set fault handler privilege mode
96 prv = PRV_M;
97 } else if (isInterrupt()) {
98 if (pp != PRV_M && misa.rvs &&
100 prv = PRV_S;
101 // when rvh is true we know rvs is true so prv is S
102 if (misa.rvh) {
103 if (virtualizationEnabled(tc) &&
105 resetV(tc); // No delegation, go to HS (S with V = 0)
106 }
107 // otherwise handled in VS (S with V = 1)
108 }
109 }
110 } else {
111 if (pp != PRV_M && misa.rvs &&
113 prv = PRV_S;
114
115 // when rvh is true we know rvs is true so prv is S
116 if (misa.rvh) {
117 if (virtualizationEnabled(tc) &&
119 resetV(tc); // No delegation, go to HS (S with V = 0)
120 }
121 // otherwise handled in VS (S with V = 1)
122 }
123 }
124 }
125
126 // Set fault registers and status
127 MiscRegIndex cause, epc, tvec, tval;
128 switch (prv) {
129 case PRV_U:
130 panic("Delegating interrupt to user mode is removed.");
131 break;
132 case PRV_S:
133 cause = MISCREG_SCAUSE;
134 epc = MISCREG_SEPC;
135 tvec = MISCREG_STVEC;
136 tval = MISCREG_STVAL;
137
138 status.spp = pp;
139 status.spie = status.sie;
140 status.sie = 0;
141 break;
142 case PRV_M:
143 cause = is_rnmi ? MISCREG_MNCAUSE : MISCREG_MCAUSE;
144 epc = is_rnmi ? MISCREG_MNEPC : MISCREG_MEPC;
146 tval = MISCREG_MTVAL;
147
148 if (is_rnmi) {
149 nstatus.mnpp = pp;
150 } else {
151 status.mpp = pp;
152 status.mpie = status.mie;
153 status.mie = 0;
154 }
155 break;
156 default:
157 panic("Unknown privilege mode %d.", prv);
158 break;
159 }
160
161 // H-extension extra handling for invoke
162 if (misa.rvh) {
163 if (prv == PRV_M) {
164 status.mpv = pv;
165 status.gva = mustSetGva();
166 // Paragraph 8.5.2 RISCV Privileged Spec 20211203
167 if (isGuestPageFault()) {
169 }
170 // Going to M-mode for handling, disable V if it's on
171 if (virtualizationEnabled(tc)) { resetV(tc); }
172 } else if (prv == PRV_S &&
173 !virtualizationEnabled(tc)) { // essentially HS-mode
174 HSTATUS hstatus = tc->readMiscReg(MISCREG_HSTATUS);
175 hstatus.spv = pv;
176 if (pv) { // if V-bit was on
177 hstatus.spvp = status.spp;
178 hstatus.gva = mustSetGva();
179 // Paragraph 8.5.2 RISCV Privileged Spec 20211203
180 if (isGuestPageFault()) {
182 }
183 }
184 // Write changes to hstatus
185 tc->setMiscReg(MISCREG_HSTATUS, hstatus);
186 } else if (prv == PRV_S &&
187 virtualizationEnabled(tc)) { // essentially VS-mode
188 STATUS vsstatus = tc->readMiscReg(MISCREG_VSSTATUS);
189 cause = MISCREG_VSCAUSE;
190 epc = MISCREG_VSEPC;
191 tvec = MISCREG_VSTVEC;
192 tval = MISCREG_VSTVAL;
193 vsstatus.spp = pp;
194 vsstatus.spie = vsstatus.sie;
195 vsstatus.sie = 0;
196 tc->setMiscReg(MISCREG_VSSTATUS, vsstatus);
197
198 // Paragraph 8.2.2 RISCV Privileged Spec 20211203
199 switch (_code) {
202 break;
205 break;
208 break;
209 default:
210 break;
211 }
212 } else {
213 panic("Unknown case in hypervisor fault handler."
214 "prv = %d, V = %d", prv, virtualizationEnabled(tc));
215 }
216 }
217
218 // Set fault cause, privilege, and return PC
219 uint64_t _cause = _code;
220 if (isInterrupt()) {
221 _cause |= CAUSE_INTERRUPT_MASKS[pc_state.rvType()];
222 }
223 tc->setMiscReg(cause, _cause);
224 if (pc_state.zcmtSecondFetch()) {
225 tc->setMiscReg(epc, pc_state.zcmtPc());
226 } else {
227 tc->setMiscReg(epc, pc_state.instAddr());
228 }
229 tc->setMiscReg(tval, trap_value());
230 tc->setMiscReg(MISCREG_PRV, prv);
231 if (is_rnmi) {
232 tc->setMiscReg(MISCREG_MNSTATUS, nstatus);
233 } else {
235 }
236 // Temporarily mask NMI while we're in NMI handler. Otherweise, the
237 // checkNonMaskableInterrupt will always return true and we'll be
238 // stucked in an infinite loop.
240 tc->setMiscReg(MISCREG_NMIE, 0);
241 }
242
243 // Clear load reservation address
244 isa->clearLoadReservation(tc->contextId());
245
246 // Set PC to fault handler address
247 Addr addr = isa->getFaultHandlerAddr(tvec, _code, isInterrupt());
248 if (pc_state.zcmtSecondFetch()) {
249 pc_state.zcmtSecondFetch(false);
250 pc_state.zcmtPc(0);
251 }
252 pc_state.set(isa->rvSext(addr));
253 tc->pcState(pc_state);
254 } else {
255 invokeSE(tc, inst);
256 }
257}
258
259void
261{
263 STATUS status = tc->readMiscReg(MISCREG_STATUS);
264 status.mie = 0;
265 status.mprv = 0;
268
269 // Advance the PC to the implementation-defined reset vector
270 auto workload = dynamic_cast<Workload *>(tc->getSystemPtr()->workload);
271 std::unique_ptr<PCState> new_pc(dynamic_cast<PCState *>(
272 tc->getIsaPtr()->newPCState(workload->getEntry())));
273 panic_if(!new_pc, "Failed create new PCState from ISA pointer");
274 VTYPE vtype = 0;
275 vtype.vill = 1;
276 new_pc->vtype(vtype);
277 new_pc->vl(0);
278 tc->pcState(*new_pc);
279
280 auto* mmu = tc->getMMUPtr();
281 if (mmu != nullptr) {
282 mmu->reset();
283 }
284}
285
286void
288{
289 auto *rsi = static_cast<RiscvStaticInst *>(inst.get());
290 panic("Unknown instruction 0x%08x at pc %s", rsi->machInst,
291 tc->pcState());
292}
293
294void
296{
297 if (! tc->getSystemPtr()->trapToGdb(GDBSignal::ILL, tc->contextId()) ) {
298 auto *rsi = static_cast<RiscvStaticInst *>(inst.get());
299 panic("Illegal instruction 0x%08x at pc %s: %s", rsi->machInst,
300 tc->pcState(), reason.c_str());
301 }
302}
303
304void
306{
307 panic("Unimplemented instruction %s at pc %s", instName, tc->pcState());
308}
309
310void
312{
313 panic("Illegal floating-point rounding mode 0x%x at pc %s.",
314 frm, tc->pcState());
315}
316
317void
319{
320 if (! tc->getSystemPtr()->trapToGdb(GDBSignal::TRAP, tc->contextId()) ) {
321 schedRelBreak(0);
322 }
323}
324
325void
327{
328 /* Advance the PC to next instruction so - once (simulated) syscall
329 is executed - execution continues. */
330 auto pc_state = tc->pcState().as<PCState>();
331 inst->advancePC(pc_state);
332 tc->pcState(pc_state);
333
334 tc->getSystemPtr()->workload->syscall(tc);
335}
336
337bool
339{
340 auto addr_fault = dynamic_cast<AddressFault *>(fault.get());
341 if (addr_fault) {
342 va = addr_fault->trap_value();
343 return true;
344 }
345
346 auto pgt_fault = dynamic_cast<GenericPageTableFault *>(fault.get());
347 if (pgt_fault) {
348 va = pgt_fault->getFaultVAddr();
349 return true;
350 }
351
352 return false;
353}
354
355} // namespace RiscvISA
356} // namespace gem5
#define DPRINTFS(x, s,...)
Definition trace.hh:216
virtual PCStateBase * newPCState(Addr new_inst_addr=0) const =0
Target & as()
Definition pcstate.hh:73
T * get() const
Directly access the pointer itself without taking a reference.
Definition refcnt.hh:229
void invokeSE(ThreadContext *tc, const StaticInstPtr &inst) override
Definition faults.cc:318
void invokeSE(ThreadContext *tc, const StaticInstPtr &inst) override
Definition faults.cc:311
void invokeSE(ThreadContext *tc, const StaticInstPtr &inst) override
Definition faults.cc:295
void invoke(ThreadContext *tc, const StaticInstPtr &inst=nullStaticInstPtr) override
Definition faults.cc:260
bool isResumableNonMaskableInterrupt(ISA *isa) const
Definition faults.hh:75
virtual bool mustSetGva() const
Definition faults.hh:91
virtual RegVal trap_value2() const
Definition faults.hh:90
bool isInterrupt() const
Definition faults.hh:70
bool isGuestPageFault() const
Definition faults.hh:83
virtual void invokeSE(ThreadContext *tc, const StaticInstPtr &inst)
Definition faults.cc:55
ExceptionCode exception() const
Definition faults.hh:88
void invoke(ThreadContext *tc, const StaticInstPtr &inst) override
Definition faults.cc:61
FaultName name() const override
Definition faults.hh:69
bool isNonMaskableInterrupt() const
Definition faults.hh:71
ExceptionCode _code
Definition faults.hh:63
virtual RegVal trap_value() const
Definition faults.hh:89
Base class for all RISC-V static instructions.
void invokeSE(ThreadContext *tc, const StaticInstPtr &inst) override
Definition faults.cc:326
void invokeSE(ThreadContext *tc, const StaticInstPtr &inst) override
Definition faults.cc:305
void invokeSE(ThreadContext *tc, const StaticInstPtr &inst) override
Definition faults.cc:287
virtual void advancePC(PCStateBase &pc_state) const =0
Workload * workload
OS kernel.
Definition system.hh:331
bool trapToGdb(GDBSignal signal, ContextID ctx_id) const
Definition system.cc:407
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual RegVal readMiscReg(RegIndex misc_reg)=0
virtual void setMiscReg(RegIndex misc_reg, RegVal val)=0
virtual System * getSystemPtr()=0
virtual BaseISA * getIsaPtr() const =0
virtual BaseCPU * getCpuPtr()=0
virtual const PCStateBase & pcState() const =0
virtual RegVal readMiscRegNoEffect(RegIndex misc_reg) const =0
virtual BaseMMU * getMMUPtr()=0
virtual ContextID contextId() const =0
virtual void syscall(ThreadContext *tc)
Definition workload.hh:113
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition bitfield.hh:79
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:220
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:246
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
Definition logging.hh:315
Bitfield< 5, 0 > status
Bitfield< 8 > va
const RegVal CAUSE_INTERRUPT_MASKS[enums::Num_RiscvType]
Definition misc.hh:1681
void resetV(ExecContext *xc)
Definition isa.cc:1356
bool getFaultVAddr(Fault fault, Addr &va)
Returns true if the fault passed as a first argument was triggered by a memory access,...
Definition faults.cc:338
bool virtualizationEnabled(ExecContext *xc)
Definition isa.cc:1340
@ MISCREG_HSTATUS
Definition misc.hh:213
@ MISCREG_MNCAUSE
Definition misc.hh:255
@ MISCREG_STATUS
Definition misc.hh:78
@ MISCREG_MEDELEG
Definition misc.hh:150
@ MISCREG_HIDELEG
Definition misc.hh:215
@ MISCREG_MIDELEG
Definition misc.hh:151
@ MISCREG_VSSTATUS
Definition misc.hh:227
@ MISCREG_MNSTATUS
Definition misc.hh:256
@ MISCREG_VSCAUSE
Definition misc.hh:231
@ MISCREG_HEDELEG
Definition misc.hh:214
Bitfield< 3 > addr
Definition types.hh:84
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
std::shared_ptr< FaultBase > Fault
Definition types.hh:249
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
Definition root.cc:220
RefCountingPtr< StaticInst > StaticInstPtr
void schedRelBreak(Tick delta)
Cause the simulator to execute a breakpoint relative to the current tick.
Definition debug.cc:90
PMP header file.

Generated on Mon Oct 27 2025 04:12:55 for gem5 by doxygen 1.14.0