Commit e96b1c50e8 for qemu.org

commit e96b1c50e8dc71731705f9b81e708b18a2527e70
Author: Eric Auger <eric.auger@redhat.com>
Date:   Fri Oct 30 14:13:12 2026 +0100

    target/arm: Enforce MPIDR into isar.idregs[] storage

    At the moment MPIDR_EL1 has no real storage. Instead cpu
    mp_affinity field stores the Aff0-Aff2 bits only and the
    ID register is reconstructed when needed. There is also
    an mp-affinity property used for TCG only.

    Keep the mp-affinity property and its associated storage
    while making sure the MPIDR_EL1 full register is stored
    in cpu->isar.idregs[] as other ID registers.

    Signed-off-by: Eric Auger <eric.auger@redhat.com>
    Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
    Reviewed-by: Sebastian Ott <sebott@redhat.com>
    Reviewed-by: Khushit Shah <khushit.shah@nutanix.com>
    Message-id: 20261030131406.461599-5-eric.auger@redhat.com
    Suggested-by: Khushit Shah <khushit.shah@nutanix.com>
    Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
    Reviewed-by: Sebastian Ott <sebott@redhat.com>
    Reviewed-by: Khushit Shah <khushit.shah@nutanix.com>
    Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

diff --git a/target/arm/cpu-sysregs.h.inc b/target/arm/cpu-sysregs.h.inc
index 709dc8fc97..f148f6f565 100644
--- a/target/arm/cpu-sysregs.h.inc
+++ b/target/arm/cpu-sysregs.h.inc
@@ -42,6 +42,7 @@ DEF(ID_PFR0_EL1, 3, 0, 0, 1, 0)
 DEF(ID_PFR1_EL1, 3, 0, 0, 1, 1)
 DEF(ID_PFR2_EL1, 3, 0, 0, 3, 4)
 DEF(MIDR_EL1, 3, 0, 0, 0, 0)
+DEF(MPIDR_EL1, 3, 0, 0, 0, 5)
 DEF(MVFR0_EL1, 3, 0, 0, 3, 0)
 DEF(MVFR1_EL1, 3, 0, 0, 3, 1)
 DEF(MVFR2_EL1, 3, 0, 0, 3, 2)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 5c8a11f482..b9e4734de8 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2174,6 +2174,23 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
                                                  ARM_DEFAULT_CPUS_PER_CLUSTER);
     }

+    /* Consistently update MPIDR_EL1 in isar.idregs[] by adding feature bits */
+    {
+        uint64_t mpidr = cpu->mp_affinity;
+
+        if (arm_feature(env, ARM_FEATURE_V7MP)) {
+            mpidr |= (1U << 31);
+            /*
+             * Uniprocessor (non-coherent) cores that still implement the MP
+             * extensions set U (bit 30), e.g. Cortex-R5.
+             */
+            if (cpu->mp_is_up) {
+                mpidr |= (1u << 30);
+            }
+        }
+        SET_IDREG(&cpu->isar, MPIDR, mpidr);
+    }
+
     if (cpu->reset_hivecs) {
             cpu->reset_sctlr |= (1 << 13);
     }
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index e6b4000127..5c5f551dac 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1130,7 +1130,13 @@ struct ArchCPU {
     uint32_t reset_sctlr;
     uint64_t pmceid0;
     uint64_t pmceid1;
-    uint64_t mp_affinity; /* MP ID without feature bits */
+    /*
+     * MP ID without feature bits, ie. Aff0..Aff3 only
+     * used to store the corresponding property value for TCG vcpus.
+     * The MPIDR_EL1 value (affinity + feature bits) is stored in a
+     * consistent manner in isar.idregs[MPIDR_EL1_IDX].
+     */
+    uint64_t mp_affinity;
     uint64_t reset_cbar;
     uint32_t reset_auxcr;
     bool reset_hivecs;
diff --git a/target/arm/helper.c b/target/arm/helper.c
index afaac33f2a..f413b15eb7 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3180,20 +3180,8 @@ static uint64_t midr_read(CPUARMState *env, const ARMCPRegInfo *ri)
 static uint64_t mpidr_read_val(CPUARMState *env)
 {
     ARMCPU *cpu = env_archcpu(env);
-    uint64_t mpidr = cpu->mp_affinity;

-    if (arm_feature(env, ARM_FEATURE_V7MP)) {
-        mpidr |= (1U << 31);
-        /*
-         * Cores which are uniprocessor (non-coherent)
-         * but still implement the MP extensions set
-         * bit 30. (For instance, Cortex-R5).
-         */
-        if (cpu->mp_is_up) {
-            mpidr |= (1u << 30);
-        }
-    }
-    return mpidr;
+    return GET_IDREG(&cpu->isar, MPIDR);
 }

 static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 46443fb9fb..34a7f4636a 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -1488,7 +1488,7 @@ int hvf_arch_init_vcpu(CPUState *cpu)
     assert_hvf_ok(ret);

     ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_MPIDR_EL1,
-                              arm_cpu->mp_affinity);
+                              GET_IDREG(&arm_cpu->isar, MPIDR));
     assert_hvf_ok(ret);

     pfr = GET_IDREG(&arm_cpu->isar, ID_AA64PFR0);
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index de09d63d2e..724bc08edf 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -2103,6 +2103,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
     if (ret) {
         return ret;
     }
+    SET_IDREG(&cpu->isar, MPIDR, mpidr);
     cpu->mp_affinity = mpidr & ARM64_AFFINITY_MASK;

     return kvm_arm_init_cpreg_list(cpu);
diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c
index 18009d6c8d..024d18df04 100644
--- a/target/arm/whpx/whpx-all.c
+++ b/target/arm/whpx/whpx-all.c
@@ -842,7 +842,7 @@ int whpx_init_vcpu(CPUState *cpu)

     clean_whv_register_value(&val);

-    val.Reg64 = deposit64(arm_cpu->mp_affinity, 31, 1, 1 /* RES1 */);
+    val.Reg64 = GET_IDREG(&arm_cpu->isar, MPIDR);
     whpx_set_reg(cpu, WHvArm64RegisterMpidrEl1, val);

     clamp_id_aa64mmfr0_parange_to_ipa_size(&arm_cpu->isar);