Skip to content

Commit

Permalink
target/riscv: fix wfi exception behavior
Browse files Browse the repository at this point in the history
The wfi exception trigger behavior should take into account user mode,
hstatus.vtw, and the fact the an wfi might raise different types of
exceptions depending on various factors:

If supervisor mode is not present:

- an illegal instruction exception should be generated if user mode
executes and wfi instruction and mstatus.tw = 1.

If supervisor mode is present:

- when a wfi instruction is executed, an illegal exception should be triggered
if either the current mode is user or the mode is supervisor and mstatus.tw is
set.

Plus, if the hypervisor extensions are enabled:

- a virtual instruction exception should be raised when a wfi is executed from
virtual-user or virtual-supervisor and hstatus.vtw is set.

Signed-off-by: Jose Martins <[email protected]>
Reviewed-by: Alistair Francis <[email protected]>
Message-id: [email protected]
Signed-off-by: Alistair Francis <[email protected]>
  • Loading branch information
josecm authored and apparentlymart committed Sep 3, 2024
1 parent 87610ba commit 58f1a61
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 4 deletions.
1 change: 1 addition & 0 deletions qemu/target/riscv/cpu_bits.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@
#define HSTATUS_SP2P 0x00000100
#define HSTATUS_SP2V 0x00000200
#define HSTATUS_VTVM 0x00100000
#define HSTATUS_VTW 0x00200000
#define HSTATUS_VTSR 0x00400000

#define HSTATUS32_WPRI 0xFF8FF87E
Expand Down
12 changes: 8 additions & 4 deletions qemu/target/riscv/op_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,15 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
void helper_wfi(CPURISCVState *env)
{
CPUState *cs = env_cpu(env);
bool rvs = riscv_has_ext(env, RVS);
bool prv_u = env->priv == PRV_U;
bool prv_s = env->priv == PRV_S;

if ((env->priv == PRV_S &&
env->priv_ver >= PRIV_VERSION_1_10_0 &&
get_field(env->mstatus, MSTATUS_TW)) ||
riscv_cpu_virt_enabled(env)) {
if (((prv_s || (!rvs && prv_u)) && get_field(env->mstatus, MSTATUS_TW)) ||
(rvs && prv_u && !riscv_cpu_virt_enabled(env))) {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
} else if (riscv_cpu_virt_enabled(env) && (prv_u ||
(prv_s && get_field(env->hstatus, HSTATUS_VTW)))) {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
} else {
cs->halted = 1;
Expand Down

0 comments on commit 58f1a61

Please sign in to comment.