aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target/riscv/cpu_helper.c24
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;
}