diff options
-rw-r--r-- | target/riscv/cpu_helper.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 9ff0952e46..e7e23b34f4 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -1032,13 +1032,29 @@ restart: prot |= PAGE_WRITE; } if (pte & PTE_X) { - bool mxr; + bool mxr = false; - if (first_stage == true) { + /* + * Use mstatus for first stage or for the second stage without + * virt_enabled (MPRV+MPV) + */ + if (first_stage || !env->virt_enabled) { mxr = get_field(env->mstatus, MSTATUS_MXR); - } else { - mxr = get_field(env->vsstatus, MSTATUS_MXR); } + + /* MPRV+MPV case, check VSSTATUS */ + if (first_stage && two_stage && !env->virt_enabled) { + mxr |= get_field(env->vsstatus, MSTATUS_MXR); + } + + /* + * Setting MXR at HS-level overrides both VS-stage and G-stage + * execute-only permissions + */ + if (env->virt_enabled) { + mxr |= get_field(env->mstatus_hs, MSTATUS_MXR); + } + if (mxr) { prot |= PAGE_READ; } |