2025-11-21T13:04:10+08:00, <[email protected]>:
> From: Frank Chang <[email protected]>
>
> 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 <[email protected]>
> Reviewed-by: Daniel Henrique Barboza <[email protected]>
> ---
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> RISCVPmPmm riscv_pm_get_pmm(CPURISCVState *env)
> {
> #ifndef CONFIG_USER_ONLY
> - int priv_mode = cpu_address_mode(env);
> + int priv_mode;
> + bool virt;
>
> - if (get_field(env->mstatus, MSTATUS_MPRV) &&
> - get_field(env->mstatus, MSTATUS_MXR)) {
> + if (get_field(env->mstatus, MSTATUS_MXR)) {
> return PMM_FIELD_DISABLED;
> }
MSTATUS_MXR doesn't disable Pointer masking in M-mode, and we also need
to consider virt, where vsstatus.MXR is in effect as well.
>
> + riscv_cpu_eff_priv(env, &priv_mode, &virt);
I think you could put something like this here:
if ((mode != PRV_M && get_field(env->mstatus, MSTATUS_MXR)) ||
(virt && get_field(env->vsstatus, MSTATUS_MXR))) {
return PMM_FIELD_DISABLED;
}
> /* Get current PMM field */
> switch (priv_mode) {
> case PRV_M:
> @@ -189,22 +222,30 @@ RISCVPmPmm riscv_pm_get_pmm(CPURISCVState *env)
> case PRV_U:
> - if (riscv_has_ext(env, RVS)) {
> + if (!virt) {
> if (riscv_cpu_cfg(env)->ext_ssnpm) {
> return get_field(env->senvcfg, SENVCFG_PMM);
> }
> - } else {
> +
> if (riscv_cpu_cfg(env)->ext_smnpm) {
> - return get_field(env->menvcfg, MENVCFG_PMM);
> + if (!riscv_has_ext(env, RVS)) {
> + return get_field(env->menvcfg, MENVCFG_PMM);
> + }
> + }
> + } else {
> + if (riscv_cpu_cfg(env)->ext_ssnpm) {
> + return get_field(env->senvcfg, SENVCFG_PMM);
> }
> }
virt doesn't really matter, the original code was correct.
Thanks.