summaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorJose Martins <josemartins90@gmail.com>2021-04-20 22:36:56 +0100
committerAlistair Francis <alistair.francis@wdc.com>2021-06-08 09:59:42 +1000
commit719f0f603c2289f438b8d6ef4358d9407b4c2905 (patch)
treedc5a7e257b094da89f5f740c4021d2294694115b /target
parent143897b50140cfd7540f867edca5d658e76aa9bf (diff)
downloadqemu-719f0f603c2289f438b8d6ef4358d9407b4c2905.zip
target/riscv: fix wfi exception behavior
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 <josemartins90@gmail.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-id: 20210420213656.85148-1-josemartins90@gmail.com Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Diffstat (limited to 'target')
-rw-r--r--target/riscv/cpu_bits.h1
-rw-r--r--target/riscv/op_helper.c11
2 files changed, 9 insertions, 3 deletions
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 52640e6856..7330ff5a19 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -390,6 +390,7 @@
#define HSTATUS_HU 0x00000200
#define HSTATUS_VGEIN 0x0003F000
#define HSTATUS_VTVM 0x00100000
+#define HSTATUS_VTW 0x00200000
#define HSTATUS_VTSR 0x00400000
#define HSTATUS_VSXL 0x300000000
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 170b494227..3c48e739ac 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -177,10 +177,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 &&
- 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_VIRT_INSTRUCTION_FAULT, GETPC());
} else {
cs->halted = 1;