diff mbox series

[v2,1/2] qemu: Backport support for 'aarch64=off' with TCG

Message ID 20260810-tune-a32-v2-1-52045fd54937@gmail.com
State Under Review
Headers show
Series tune-cortexa32: Add AArch32 QEMU machine | expand

Commit Message

Alex Kiernan Aug. 10, 2026, 5:11 a.m. UTC
Backport the two-commit series from qemu master which allows the
'aarch64' CPU feature to be disabled under TCG for CPUs which support
AArch32 at their highest implemented exception level. This allows an
AArch32-only ARMv8-A guest to be run with qemu-system-aarch64 as e.g.
'-cpu cortex-a35,aarch64=off', matching the '-cpu host,aarch64=off'
invocation used with KVM, and is used by the qemuarmv8a32 machine.

AI-Generated: Claude Code (Claude Fable 5)
Signed-off-by: Alex Kiernan <alex.kiernan@gmail.com>
Signed-off-by: Alex Kiernan <alexk@a-squared-projects.uk>
---
 meta/recipes-devtools/qemu/qemu.inc                |   2 +
 ...lear-AArch64-ID-regs-from-ARMISARegisters.patch | 110 +++++++++++++++++
 ...-Allow-aarch64-off-to-be-set-for-TCG-CPUs.patch | 134 +++++++++++++++++++++
 3 files changed, 246 insertions(+)
diff mbox series

Patch

diff --git a/meta/recipes-devtools/qemu/qemu.inc b/meta/recipes-devtools/qemu/qemu.inc
index 9ec522124cc3..13c73c9ec33c 100644
--- a/meta/recipes-devtools/qemu/qemu.inc
+++ b/meta/recipes-devtools/qemu/qemu.inc
@@ -34,6 +34,8 @@  SRC_URI = "https://download.qemu.org/${BPN}-${PV}.tar.xz \
            file://0011-qemu-Ensure-pip-and-the-python-venv-aren-t-used-for-.patch \
            file://0012-meson-fix-close_range-detection-on-older-glibc.patch \
            file://0013-hw-scsi-vhost-scsi-include-standard-headers-for-vhost-worker-structs.patch \
+           file://0014-target-arm-Clear-AArch64-ID-regs-from-ARMISARegisters.patch \
+           file://0015-target-arm-Allow-aarch64-off-to-be-set-for-TCG-CPUs.patch \
            file://qemu-guest-agent.init \
            file://qemu-guest-agent.udev \
            file://0001-ui-sdl2.c-force-disable-SDL_HINT_VIDEO_X11_FORCE_EGL.patch \
diff --git a/meta/recipes-devtools/qemu/qemu/0014-target-arm-Clear-AArch64-ID-regs-from-ARMISARegisters.patch b/meta/recipes-devtools/qemu/qemu/0014-target-arm-Clear-AArch64-ID-regs-from-ARMISARegisters.patch
new file mode 100644
index 000000000000..3e1ccbfe590b
--- /dev/null
+++ b/meta/recipes-devtools/qemu/qemu/0014-target-arm-Clear-AArch64-ID-regs-from-ARMISARegisters.patch
@@ -0,0 +1,110 @@ 
+From 95146de5d20ecfa7104b8bd632c717b3bbd8e151 Mon Sep 17 00:00:00 2001
+From: Peter Maydell <peter.maydell@linaro.org>
+Date: Thu, 16 Apr 2026 17:53:51 +0100
+Subject: [PATCH] target/arm: Clear AArch64 ID regs from ARMISARegisters if
+ AArch64 disabled
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+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
+Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/95146de5d20ecfa7104b8bd632c717b3bbd8e151]
+Signed-off-by: Alex Kiernan <alex.kiernan@gmail.com>
+
+---
+ target/arm/cpu.c | 35 +++++++++++++++++++++++++++++++++++
+ target/arm/cpu.h |  3 ++-
+ 2 files changed, 37 insertions(+), 1 deletion(-)
+
+diff --git a/target/arm/cpu.c b/target/arm/cpu.c
+index b62de8addff9..6705ee9db7c4 100644
+--- a/target/arm/cpu.c
++++ b/target/arm/cpu.c
+@@ -1606,6 +1606,27 @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
+     }
+ }
+ 
++static void arm_clear_aarch64_idregs(ARMCPU *cpu)
++{
++    /* Zero out all the AArch64 ID registers in ARMISARegisters */
++    SET_IDREG(&cpu->isar, ID_AA64ISAR0, 0);
++    SET_IDREG(&cpu->isar, ID_AA64ISAR1, 0);
++    SET_IDREG(&cpu->isar, ID_AA64ISAR2, 0);
++    SET_IDREG(&cpu->isar, ID_AA64PFR0, 0);
++    SET_IDREG(&cpu->isar, ID_AA64PFR1, 0);
++    SET_IDREG(&cpu->isar, ID_AA64PFR2, 0);
++    SET_IDREG(&cpu->isar, ID_AA64MMFR0, 0);
++    SET_IDREG(&cpu->isar, ID_AA64MMFR1, 0);
++    SET_IDREG(&cpu->isar, ID_AA64MMFR2, 0);
++    SET_IDREG(&cpu->isar, ID_AA64MMFR3, 0);
++    SET_IDREG(&cpu->isar, ID_AA64DFR0, 0);
++    SET_IDREG(&cpu->isar, ID_AA64DFR1, 0);
++    SET_IDREG(&cpu->isar, ID_AA64AFR0, 0);
++    SET_IDREG(&cpu->isar, ID_AA64AFR1, 0);
++    SET_IDREG(&cpu->isar, ID_AA64ZFR0, 0);
++    SET_IDREG(&cpu->isar, ID_AA64SMFR0, 0);
++}
++
+ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
+ {
+     CPUState *cs = CPU(dev);
+@@ -1733,6 +1754,20 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
+     }
+ #endif
+ 
++    /*
++     * A TCG aarch64=off CPU has no AArch64 at all, so we clear out the
++     * ID registers to avoid cpu_isar_feature(aa64_something, cpu) tests
++     * incorrectly returning true. We don't do this for other accelerators
++     * (which in practice means "for KVM", since no others have AArch32
++     * guest support) because from KVM's point of view the AArch64 ID
++     * registers still exist and must have their correct values. So we
++     * avoid clearing them out so that we don't have QEMU and KVM with
++     * different ideas of the ID registers.
++     */
++    if (tcg_enabled() && !arm_feature(env, ARM_FEATURE_AARCH64)) {
++        arm_clear_aarch64_idregs(cpu);
++    }
++
+ #ifdef CONFIG_USER_ONLY
+     /*
+      * User mode relies on IC IVAU instructions to catch modification of
+diff --git a/target/arm/cpu.h b/target/arm/cpu.h
+index 657ff4ab20b3..ab6bacf4aa87 100644
+--- a/target/arm/cpu.h
++++ b/target/arm/cpu.h
+@@ -1080,7 +1080,8 @@ struct ArchCPU {
+      * Note that if you add an ID register to the ARMISARegisters struct
+      * you need to also update the 32-bit and 64-bit versions of the
+      * kvm_arm_get_host_cpu_features() function to correctly populate the
+-     * field by reading the value from the KVM vCPU.
++     * field by reading the value from the KVM vCPU. If it is an AArch64
++     * ID register then you also must update arm_clear_aarch64_idregs().
+      */
+     struct ARMISARegisters {
+         uint32_t mvfr0;
diff --git a/meta/recipes-devtools/qemu/qemu/0015-target-arm-Allow-aarch64-off-to-be-set-for-TCG-CPUs.patch b/meta/recipes-devtools/qemu/qemu/0015-target-arm-Allow-aarch64-off-to-be-set-for-TCG-CPUs.patch
new file mode 100644
index 000000000000..e8afe6464ac8
--- /dev/null
+++ b/meta/recipes-devtools/qemu/qemu/0015-target-arm-Allow-aarch64-off-to-be-set-for-TCG-CPUs.patch
@@ -0,0 +1,134 @@ 
+From 970ea8478c059a7b753b21b60b4d7aa10944f120 Mon Sep 17 00:00:00 2001
+From: Peter Maydell <peter.maydell@linaro.org>
+Date: Thu, 16 Apr 2026 17:53:52 +0100
+Subject: [PATCH] target/arm: Allow 'aarch64=off' to be set for TCG CPUs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Allow the 'aarch64=off' property, which is currently KVM-only, to
+be set for TCG CPUs also.
+
+Note that we don't permit it on the qemu-aarch64 user-mode binary:
+this makes no sense as that executable can only handle AArch64
+syscalls (and it would also assert at startup since it doesn't
+compile in the A32-specific GDB xml files like arm-neon.xml).
+
+Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
+Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
+Tested-by: Clément Chigot <chigot@adacore.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
+Message-id: 20260416165353.589569-3-peter.maydell@linaro.org
+Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/970ea8478c059a7b753b21b60b4d7aa10944f120]
+Signed-off-by: Alex Kiernan <alex.kiernan@gmail.com>
+
+---
+ docs/system/arm/cpu-features.rst | 10 +++++----
+ target/arm/cpu-features.h        |  5 +++++
+ target/arm/cpu.c                 | 36 ++++++++++++++++++++++++++++----
+ tests/qtest/arm-cpu-features.c   |  8 ++-----
+ 4 files changed, 45 insertions(+), 14 deletions(-)
+
+diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst
+index ce19ae6a046c..10b0eff27e54 100644
+--- a/docs/system/arm/cpu-features.rst
++++ b/docs/system/arm/cpu-features.rst
+@@ -23,10 +23,12 @@ not implement ARMv8-A, will not have the ``aarch64`` CPU property.
+ QEMU's support may be limited for some CPU features, only partially
+ supporting the feature or only supporting the feature under certain
+ configurations.  For example, the ``aarch64`` CPU feature, which, when
+-disabled, enables the optional AArch32 CPU feature, is only supported
+-when using the KVM accelerator and when running on a host CPU type that
+-supports the feature.  While ``aarch64`` currently only works with KVM,
+-it could work with TCG.  CPU features that are specific to KVM are
++disabled, enables the optional AArch32 CPU feature, can only be set to
++``off`` on the TCG and KVM accelerators, and it cannot be set to
++``off`` under KVM unless running on a host CPU type that supports
++running guests in AArch32.
++
++CPU features that are inherently specific to KVM are
+ prefixed with "kvm-" and are described in "KVM VCPU Features".
+ 
+ CPU Feature Probing
+diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
+index b683c9551a0e..6e5212ff6cc7 100644
+--- a/target/arm/cpu-features.h
++++ b/target/arm/cpu-features.h
+@@ -1071,6 +1071,11 @@ static inline bool isar_feature_aa64_aa32_el2(const ARMISARegisters *id)
+     return FIELD_EX64_IDREG(id, ID_AA64PFR0, EL2) >= 2;
+ }
+ 
++static inline bool isar_feature_aa64_aa32_el3(const ARMISARegisters *id)
++{
++    return FIELD_EX64_IDREG(id, ID_AA64PFR0, EL3) >= 2;
++}
++
+ static inline bool isar_feature_aa64_ras(const ARMISARegisters *id)
+ {
+     return FIELD_EX64_IDREG(id, ID_AA64PFR0, RAS) != 0;
+diff --git a/target/arm/cpu.c b/target/arm/cpu.c
+index 6705ee9db7c4..9b80dda140ad 100644
+--- a/target/arm/cpu.c
++++ b/target/arm/cpu.c
+@@ -1244,10 +1244,38 @@ static void aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp)
+      * uniform execution state like do_interrupt.
+      */
+     if (value == false) {
+-        if (!kvm_enabled() || !kvm_arm_aarch32_supported()) {
+-            error_setg(errp, "'aarch64' feature cannot be disabled "
+-                             "unless KVM is enabled and 32-bit EL1 "
+-                             "is supported");
++        if (kvm_enabled()) {
++            if (!kvm_arm_aarch32_supported()) {
++                error_setg(errp, "'aarch64' feature cannot be disabled for KVM "
++                           "because this host does not support 32-bit EL1");
++                return;
++            }
++        } else if (tcg_enabled()) {
++#ifdef CONFIG_USER_ONLY
++            error_setg(errp, "'aarch64' feature cannot be disabled for "
++                       "usermode emulator qemu-aarch64; use qemu-arm instead");
++            return;
++#else
++            bool aa32_at_highest_el;
++            if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) {
++                aa32_at_highest_el = cpu_isar_feature(aa64_aa32_el3, cpu);
++            } else if (arm_feature(&cpu->env, ARM_FEATURE_EL2)) {
++                aa32_at_highest_el = cpu_isar_feature(aa64_aa32_el2, cpu);
++            } else {
++                aa32_at_highest_el = cpu_isar_feature(aa64_aa32_el1, cpu);
++            }
++
++            if (!aa32_at_highest_el) {
++                error_setg(errp, "'aarch64' feature cannot be disabled for "
++                           "this TCG CPU because it does not support 32-bit "
++                           "execution at its highest implemented exception "
++                           "level");
++                return;
++            }
++#endif
++        } else {
++            error_setg(errp, "'aarch64' feature cannot be disabled for "
++                       "this accelerator");
+             return;
+         }
+         unset_feature(&cpu->env, ARM_FEATURE_AARCH64);
+diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c
+index bbdd89a81d32..cb4d01fd46ae 100644
+--- a/tests/qtest/arm-cpu-features.c
++++ b/tests/qtest/arm-cpu-features.c
+@@ -493,12 +493,8 @@ static void test_query_cpu_model_expansion(const void *data)
+         sve_tests_default(qts, "max");
+         pauth_tests_default(qts, "max");
+ 
+-        /* Test that features that depend on KVM generate errors without. */
+-        assert_error(qts, "max",
+-                     "'aarch64' feature cannot be disabled "
+-                     "unless KVM is enabled and 32-bit EL1 "
+-                     "is supported",
+-                     "{ 'aarch64': false }");
++        /* TCG allows us to turn off AArch64 on the 'max' CPU type */
++        assert_set_feature(qts, "max", "aarch64", false);
+     }
+ 
+     qtest_quit(qts);