RISC-V: mret sets mstatus.MPP=U on harts without U-mode
Affected revision
- Unicorn current master as of 2026-08-12 (RISC-V backend at a QEMU 7.2.22-era snapshot)
Summary
helper_mret unconditionally writes mstatus.MPP = PRV_U. On a hart whose MISA does not include U, the least-privileged supported mode is M, so after mret the MPP field must read 3, not 0. The reproducer runs on a locally built no-U model library (default riscv_any with RVU cleared; stock E51/U54 keep U as the control).
Reproducer
The attached freestanding RV64 assembly exercises the affected CSR field and reports the observed value in a0/a1 before the terminal ebreak. The attached runner builds it into a static ELF and executes it on the affected and fixed libraries.
Expected and observed behavior
| Executor |
Result |
Repeats |
| affected Unicorn (no-U model) |
a0=0 (MPP read back 0 after mret; must be 3) |
2/2 |
| fixed Unicorn (no-U model) |
a0=3 (MPP stays M) |
2/2 |
| affected/fixed Unicorn (U54 with-U control) |
a0=0 on both (MPP=U is correct with U) |
2/2 each |
| QEMU linux-user (11.0.50) |
SIGILL, exit 132 (M-mode CSR privilege boundary) |
3/3 |
| native RISC-V hardware |
SIGILL, exit 132 (M-mode CSR privilege boundary) |
3/3 |
Root cause
qemu/target/riscv/op_helper.c helper_mret writes MSTATUS_MPP = PRV_U unconditionally. The fix selects PRV_U only when riscv_has_ext(env, RVU), otherwise PRV_M, mirroring upstream QEMU's mret implementation.
Scope
This is one root in the CSR field/WARL translation surface (one file (op_helper.c), 14 lines) and is not split into separate issues. Qiling is a downstream consumer of this Unicorn backend and does not receive a second report.
Specification and duplicate check
Upstream QEMU's mret sets MPP to the least-privileged supported mode (U if U-mode is implemented, else M). I searched the issue tracker and found no existing report for this defect.
RISC-V: mret sets mstatus.MPP=U on harts without U-mode
Affected revision
Summary
helper_mretunconditionally writesmstatus.MPP = PRV_U. On a hart whose MISA does not include U, the least-privileged supported mode is M, so aftermretthe MPP field must read 3, not 0. The reproducer runs on a locally built no-U model library (defaultriscv_anywith RVU cleared; stock E51/U54 keep U as the control).Reproducer
The attached freestanding RV64 assembly exercises the affected CSR field and reports the observed value in
a0/a1before the terminalebreak. The attached runner builds it into a static ELF and executes it on the affected and fixed libraries.Expected and observed behavior
a0=0(MPP read back 0 after mret; must be 3)a0=3(MPP stays M)a0=0on both (MPP=U is correct with U)SIGILL, exit 132 (M-mode CSR privilege boundary)SIGILL, exit 132 (M-mode CSR privilege boundary)Root cause
qemu/target/riscv/op_helper.chelper_mretwritesMSTATUS_MPP = PRV_Uunconditionally. The fix selectsPRV_Uonly whenriscv_has_ext(env, RVU), otherwisePRV_M, mirroring upstream QEMU'smretimplementation.Scope
This is one root in the CSR field/WARL translation surface (one file (
op_helper.c), 14 lines) and is not split into separate issues. Qiling is a downstream consumer of this Unicorn backend and does not receive a second report.Specification and duplicate check
Upstream QEMU's
mretsets MPP to the least-privileged supported mode (U if U-mode is implemented, else M). I searched the issue tracker and found no existing report for this defect.