@samitouri / QOSamiQemu / commits / 95146de5d2

target/arm: Clear AArch64 ID regs from ARMISARegisters if AArch64 disabled

If we create a normally-AArch64 CPU and configure it with aarch64=off, this will by default leave all the AArch64 ID register values in its ARMISARegisters struct untouched. That in turn means that tests of cpu_isar_feature(aa64_something, cpu) will return true. Until now we have had a design policy that you shouldn't check an aa64_ feature unless you know that the CPU has AArch64; but this is quite fragile as it's easy to forget and only causes a problem in the corner case where AArch64 was turned off. In particular, when we extend the ability to disable AArch64 from only KVM to also TCG there are many more aa64 feature check points which we would otherwise have to audit for whether they needed to be guarded with a check on ARM_FEATURE_AARCH64. Instead, make the CPU realize function zero out all the 64-bit ID registers if a TCG CPU doesn't have AArch64; this will make aa64_ feature tests generally return false. We only do this for TCG because only TCG really needs it, and for KVM it might be confusing to have QEMU's idea of the ID registers be different from KVM's. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260416165353.589569-2-peter.maydell@linaro.org

Peter Maydell committed Apr 16, 2026 at 17:53 UTC 95146de5d20ecfa7104b8bd632c717b3bbd8e151
2 files changed +37 -1
target/arm/cpu.c
+35
@@ -1606,6 +1606,27 @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
1606 }
1607 }
1608
1609 +static void arm_clear_aarch64_idregs(ARMCPU *cpu)
1610 +{
1611 + /* Zero out all the AArch64 ID registers in ARMISARegisters */
1612 + SET_IDREG(&cpu->isar, ID_AA64ISAR0, 0);
1613 + SET_IDREG(&cpu->isar, ID_AA64ISAR1, 0);
1614 + SET_IDREG(&cpu->isar, ID_AA64ISAR2, 0);
1615 + SET_IDREG(&cpu->isar, ID_AA64PFR0, 0);
1616 + SET_IDREG(&cpu->isar, ID_AA64PFR1, 0);
1617 + SET_IDREG(&cpu->isar, ID_AA64PFR2, 0);
1618 + SET_IDREG(&cpu->isar, ID_AA64MMFR0, 0);
1619 + SET_IDREG(&cpu->isar, ID_AA64MMFR1, 0);
1620 + SET_IDREG(&cpu->isar, ID_AA64MMFR2, 0);
1621 + SET_IDREG(&cpu->isar, ID_AA64MMFR3, 0);
1622 + SET_IDREG(&cpu->isar, ID_AA64DFR0, 0);
1623 + SET_IDREG(&cpu->isar, ID_AA64DFR1, 0);
1624 + SET_IDREG(&cpu->isar, ID_AA64AFR0, 0);
1625 + SET_IDREG(&cpu->isar, ID_AA64AFR1, 0);
1626 + SET_IDREG(&cpu->isar, ID_AA64ZFR0, 0);
1627 + SET_IDREG(&cpu->isar, ID_AA64SMFR0, 0);
1628 +}
1629 +
1630 static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
1631 {
1632 CPUState *cs = CPU(dev);
@@ -1733,6 +1754,20 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
1754 }
1755 #endif
1756
1757 + /*
1758 + * A TCG aarch64=off CPU has no AArch64 at all, so we clear out the
1759 + * ID registers to avoid cpu_isar_feature(aa64_something, cpu) tests
1760 + * incorrectly returning true. We don't do this for other accelerators
1761 + * (which in practice means "for KVM", since no others have AArch32
1762 + * guest support) because from KVM's point of view the AArch64 ID
1763 + * registers still exist and must have their correct values. So we
1764 + * avoid clearing them out so that we don't have QEMU and KVM with
1765 + * different ideas of the ID registers.
1766 + */
1767 + if (tcg_enabled() && !arm_feature(env, ARM_FEATURE_AARCH64)) {
1768 + arm_clear_aarch64_idregs(cpu);
1769 + }
1770 +
1771 #ifdef CONFIG_USER_ONLY
1772 /*
1773 * User mode relies on IC IVAU instructions to catch modification of
target/arm/cpu.h
+2 -1
@@ -1080,7 +1080,8 @@ struct ArchCPU {
1080 * Note that if you add an ID register to the ARMISARegisters struct
1081 * you need to also update the 32-bit and 64-bit versions of the
1082 * kvm_arm_get_host_cpu_features() function to correctly populate the
1083 - * field by reading the value from the KVM vCPU.
1083 + * field by reading the value from the KVM vCPU. If it is an AArch64
1084 + * ID register then you also must update arm_clear_aarch64_idregs().
1085 */
1086 struct ARMISARegisters {
1087 uint32_t mvfr0;