Commit 0f64c97d23 for qemu.org

commit 0f64c97d23abfe77a70d94319020ca6789aee5a1
Author: Frank Chang <frank.chang@sifive.com>
Date:   Tue Apr 21 17:37:12 2026 +0800

    target/riscv: Fix pointer masking PMM field selection logic

    mstatus.MPV only records the previous virtualization state, and does not
    affect pointer masking according to the Zjpm specification.

    This patch rewrites riscv_pm_get_pmm() to follow the architectural
    definition of Smmpm, Smnpm, and Ssnpm.

    The resulting PMM selection logic for each mode is summarized below:

      * mstatus.MXR = 1: pointer masking disabled

      * Smmpm + Smnpm + Ssnpm:
          M-mode:  mseccfg.PMM
          S-mode:  menvcfg.PMM
          U-mode:  senvcfg.PMM
          VS-mode: henvcfg.PMM
          VU-mode: senvcfg.PMM

      * Smmpm + Smnpm (RVS implemented):
          M-mode:  mseccfg.PMM
          S-mode:  menvcfg.PMM
          U/VS/VU: disabled (Ssnpm not present)

      * Smmpm + Smnpm (RVS not implemented):
          M-mode:  mseccfg.PMM
          U-mode:  menvcfg.PMM
          S/VS/VU: disabled (no S-mode)

      * Smmpm only:
          M-mode:  mseccfg.PMM
          Other existing modes: pointer masking disabled

    Signed-off-by: Frank Chang <frank.chang@sifive.com>
    Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
    Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
    Message-ID: <20260421093715.2995067-4-frank.chang@sifive.com>
    Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 513bad21af..bab4153e53 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -131,13 +131,47 @@ bool riscv_env_smode_dbltrp_enabled(CPURISCVState *env, bool virt)
 #endif
 }

+/*
+ * Returns the effective PMM field.
+ *
+ * @env: CPURISCVState
+ *
+ * The PMM field selection logic for each effective privilege mode
+ * is as follows:
+ *
+ * - mstatus.MXR = 1: disabled
+ *
+ * - Smmpm + Smnpm + Ssnpm:
+ *     M-mode:  mseccfg.PMM
+ *     S-mode:  menvcfg.PMM
+ *     U-mode:  senvcfg.PMM
+ *     VS-mode: henvcfg.PMM
+ *     VU-mode: senvcfg.PMM
+ *
+ * - Smmpm + Smnpm (RVS implemented):
+ *     M-mode:  mseccfg.PMM
+ *     S-mode:  menvcfg.PMM
+ *     U/VS/VU: disabled (Ssnpm not present)
+ *
+ * - Smmpm + Smnpm (RVS not implemented):
+ *     M-mode:  mseccfg.PMM
+ *     U-mode:  menvcfg.PMM
+ *     S/VS/VU: disabled (no S-mode)
+ *
+ * - Smmpm only:
+ *     M-mode:  mseccfg.PMM
+ *     Other existing modes: disabled
+ */
 RISCVPmPmm riscv_pm_get_pmm(CPURISCVState *env)
 {
 #ifndef CONFIG_USER_ONLY
-    int priv_mode = cpu_address_mode(env);
+    int priv_mode;
+    bool virt;
+
+    riscv_cpu_eff_priv(env, &priv_mode, &virt);

-    if (get_field(env->mstatus, MSTATUS_MPRV) &&
-        get_field(env->mstatus, MSTATUS_MXR)) {
+    if ((priv_mode != PRV_M && get_field(env->mstatus, MSTATUS_MXR)) ||
+        (virt && get_field(env->vsstatus, MSTATUS_MXR))) {
         return PMM_FIELD_DISABLED;
     }

@@ -149,12 +183,14 @@ RISCVPmPmm riscv_pm_get_pmm(CPURISCVState *env)
         }
         break;
     case PRV_S:
-        if (riscv_cpu_cfg(env)->ext_smnpm) {
-            if (get_field(env->mstatus, MSTATUS_MPV)) {
-                return get_field(env->henvcfg, HENVCFG_PMM);
-            } else {
+        if (!virt) {
+            if (riscv_cpu_cfg(env)->ext_smnpm) {
                 return get_field(env->menvcfg, MENVCFG_PMM);
             }
+        } else {
+            if (riscv_cpu_cfg(env)->ext_ssnpm) {
+                return get_field(env->henvcfg, HENVCFG_PMM);
+            }
         }
         break;
     case PRV_U:
@@ -171,6 +207,7 @@ RISCVPmPmm riscv_pm_get_pmm(CPURISCVState *env)
     default:
         g_assert_not_reached();
     }
+
     return PMM_FIELD_DISABLED;
 #else
     return PMM_FIELD_DISABLED;