MCPcopy Create free account
hub / github.com/LPC4/Full-Stack / take_trap

Function take_trap

crates/virtual-machine/src/cpu/traps.rs:55–121  ·  view source on GitHub ↗

Enter a trap: saves state, updates CSRs, jumps to the appropriate handler. Delegation: if the current privilege is U or S and the corresponding bit in medeleg (exceptions) or mideleg (interrupts) is set, the trap is delivered to S-mode using sepc/scause/stval/sstatus/stvec. Otherwise it goes to M-mode. Returns the new PC (trap handler entry address).

(regs: &mut Registers, csrs: &mut CsrFile, cause: u64, tval: u64, pc: u64)

Source from the content-addressed store, hash-verified

53 csrs.sepc = pc & !0x3u64;
54 csrs.scause = cause;
55 csrs.stval = tval;
56
57 // sstatus bits live inside mstatus:
58 // SPIE = old SIE; SIE = 0; SPP = current_priv (0=U, 1=S)
59 let sie = (csrs.mstatus >> 1) & 1;
60 csrs.mstatus = (csrs.mstatus & !(1u64 << 5)) | (sie << 5); // SPIE = old SIE
61 csrs.mstatus &= !(1u64 << 1); // SIE = 0
62 let spp: u64 = u64::from(current_priv != PrivilegeMode::User);
63 csrs.mstatus = (csrs.mstatus & !(1u64 << 8)) | (spp << 8); // SPP = current_priv
64
65 regs.priv_mode = PrivilegeMode::Supervisor;
66
67 let stvec = csrs.stvec;
68 let base = stvec & !0x3u64;
69 if (stvec & 0x3) == 1 && is_interrupt {
70 base + 4 * cause_idx
71 } else {
72 base
73 }
74 } else {
75 csrs.mepc = pc & !0x3u64;
76 csrs.mcause = cause;
77 csrs.mtval = tval;
78
79 // mstatus: MPIE = old MIE; MIE = 0; MPP = current_priv
80 let mie = (csrs.mstatus >> 3) & 1;
81 csrs.mstatus = (csrs.mstatus & !(1u64 << 7)) | (mie << 7); // MPIE = old MIE
82 csrs.mstatus &= !(1u64 << 3); // MIE = 0
83 csrs.mstatus = (csrs.mstatus & !(0x3u64 << 11)) | ((current_priv as u64) << 11); // MPP
84
85 regs.priv_mode = PrivilegeMode::Machine;
86
87 let mtvec = csrs.mtvec;
88 let base = mtvec & !0x3u64;
89 if (mtvec & 0x3) == 1 && is_interrupt {
90 base + 4 * cause_idx
91 } else {
92 base
93 }
94 }
95}
96
97// --- Trap dispatch (error to trap mapping) ---
98
99/// `Some((cause, tval))` when the error should trap, `None` when it is fatal and
100/// cannot be trapped.
101pub fn error_to_trap_cause(e: &VmError) -> Option<(u64, u64)> {
102 match e {
103 VmError::InstructionAccessFault(addr) => Some((CAUSE_INSN_ACCESS_FAULT, *addr)),
104 VmError::IllegalInstruction(insn) => Some((CAUSE_ILLEGAL_INSN, *insn as u64)),
105 VmError::LoadAccessFault(addr) | VmError::BusError(addr) => {
106 Some((CAUSE_LOAD_ACCESS_FAULT, *addr))
107 }
108 VmError::StoreAccessFault(addr) => Some((CAUSE_STORE_ACCESS_FAULT, *addr)),
109 VmError::PageFault(addr) => Some((CAUSE_PAGE_FAULT_LOAD, *addr)),
110 _ => None,
111 }
112}

Callers 4

take_trapMethod · 0.85
test_take_trap_sets_csrsFunction · 0.85

Calls

no outgoing calls

Tested by 3

test_take_trap_sets_csrsFunction · 0.68