On 7/22/25 06:19, Smail AIDER via wrote:
Trap PMCR_EL0 or PMCR accesses to EL2 when MDCR_EL2.TPMCR is set.
Similar to MDCR_EL2.TPM, MDCR_EL2.TPMCR allows trapping EL0 and EL1
accesses to the PMCR register to EL2.

Signed-off-by: Smail AIDER <smail.ai...@huawei.com>
---
  target/arm/cpregs-pmu.c | 24 ++++++++++++++++++++++--
  1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/target/arm/cpregs-pmu.c b/target/arm/cpregs-pmu.c
index 0f295b1376..3aacd4f652 100644
--- a/target/arm/cpregs-pmu.c
+++ b/target/arm/cpregs-pmu.c
@@ -252,6 +252,26 @@ static CPAccessResult pmreg_access(CPUARMState *env, const 
ARMCPRegInfo *ri,
      return CP_ACCESS_OK;
  }
+/*
+ * Check for traps to PMCR register, which are controlled by PMUSERENR.EN
+ * for EL1, MDCR_EL2.TPM/TPMCR for EL2 and MDCR_EL3.TPM for EL3.
+ */
+static CPAccessResult pmreg_access_pmcr(CPUARMState *env, const ARMCPRegInfo 
*ri,
+                                   bool isread)
+{
+    int el = arm_current_el(env);
+    uint64_t mdcr_el2 = arm_mdcr_el2_eff(env);
+

This could be improved by not computing these until they're needed.

+    CPAccessResult ret = pmreg_access(env, ri, isread);
+
+    /* Check MDCR_TPMCR if not already trapped to EL1 */
+    if (ret != CP_ACCESS_TRAP_EL1 && el < 2 && (mdcr_el2 & MDCR_TPMCR)) {
+        ret = CP_ACCESS_TRAP_EL2;
+    }

Or by creating a common helper for pmreg_access and pmreg_access_pmcr such that those values only need computing once within the common helper. That could make the code more obvious as well.

E.g.

static CPAccessResult do_pmreg_access(CPUARMState *env, bool with_tpmcr)
{
    int el = arm_current_el(env);

    if (el == 0 && !(env->cp15.c9_pmuserenr & 1)) {
        return CP_ACCESS_TRAP_EL1;
    }

    if (el < 2) {
        uint64_t mdcr_el2 = arm_mdcr_el2_eff(env);

        if (mdcr_el2 & MDCR_TPM) {
            return CP_ACCESS_TRAP_EL2;
        }
        if (with_tpmcr && (mdcr_el2 & MDCR_TPMCR)) {
            return CP_ACCESS_TRAP_EL2;
        }
    }

    if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TPM)) {
        return CP_ACCESS_TRAP_EL3;
    }
    return CP_ACCESS_OK;
}

static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri,
                                   bool isread)
{
    return do_pmreg_access(env, false);
}

static CPAccessResult pmreg_access_pmcr(CPUARMState *env, const ARMCPRegInfo 
*ri,
                                        bool isread)
{
    return do_pmreg_access(env, true);
}


r~

Reply via email to