Handle MRET - return from machine-mode trap. Restores MIE from MPIE, privilege from MPP, returns PC from MEPC.
(regs: &mut Registers, csrs: &mut CsrFile)
| 143 | /// Handle SRET - restore SIE from SPIE, privilege from SPP, return PC from SEPC. Err if illegal. |
| 144 | pub fn handle_sret(regs: &mut Registers, csrs: &mut CsrFile) -> Result<u64, VmError> { |
| 145 | // SRET is illegal from U-mode. |
| 146 | if regs.priv_mode == PrivilegeMode::User { |
| 147 | return Err(VmError::IllegalInstruction(0x1020_0073)); |
| 148 | } |
| 149 | // TSR bit (mstatus[22]): if set while in S-mode, SRET raises illegal instruction. |
| 150 | if regs.priv_mode == PrivilegeMode::Supervisor && (csrs.mstatus >> 22) & 1 == 1 { |
| 151 | return Err(VmError::IllegalInstruction(0x1020_0073)); |
| 152 | } |
| 153 | |
| 154 | // SIE = old SPIE; SPIE = 1 |
| 155 | let spie = (csrs.mstatus >> 5) & 1; |
| 156 | csrs.mstatus = (csrs.mstatus & !(1u64 << 1)) | (spie << 1); // SIE = old SPIE |
| 157 | csrs.mstatus |= 1u64 << 5; // SPIE = 1 |
| 158 | |
| 159 | // Restore privilege from SPP (mstatus[8]), then set SPP = User (0). |
| 160 | let spp = (csrs.mstatus >> 8) & 1; |
| 161 | let prev_priv = if spp == 0 { |
| 162 | PrivilegeMode::User |
| 163 | } else { |
| 164 | PrivilegeMode::Supervisor |
| 165 | }; |
| 166 | regs.priv_mode = prev_priv; |
| 167 | csrs.mstatus &= !(1u64 << 8); // SPP = User (0) |
| 168 | |
| 169 | // Clear MPRV (not returning to M-mode). |
| 170 | csrs.mstatus &= !(1u64 << 17); |
| 171 |
no outgoing calls