When QEMU queries the host ISAR via KVM, it uses a scratch vCPU
initialized with all host-supported features (like SVE and PAuth).

KVM exposes the corresponding ID register fields (e.g.,
ID_AA64ISAR1_EL1.APA) as read-only. The supported-values list only
shows the enabled host value (e.g., 5). This falsely flags a model as
blocked, even though the features can be masked by omitting those flags
during vCPU initialization. For these fields, even if KVM reports them as
non-writable, we explicitly append "0" to the list of supported values
if the host value is non-zero.

Signed-off-by: Khushit Shah <[email protected]>
---
 target/arm/kvm.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 77b1bcdf55..0b5fb49dff 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1346,6 +1346,24 @@ static void ranges_add(GArray *ranges, uint64_t min, 
uint64_t max)
     g_array_append_val(ranges, r);
 }
 
+/*
+ * Some fields are reported as non-writable by KVM but can still be
+ * disabled by not requesting the corresponding vCPU init feature flag
+ * (SVE, pauth). The supported values are derived from a scratch vCPU
+ * whose init flags may differ from the real vCPU, so for these fields
+ * "off" (0) is a supported value in addition to the host value.
+ */
+static bool kvm_arm_field_off_via_vcpu_flags(const ARM64SysRegField *field)
+{
+    return field_matches(field, ID_AA64PFR0_EL1_IDX, "SVE")   ||
+           field_matches(field, ID_AA64ISAR1_EL1_IDX, "APA")  ||
+           field_matches(field, ID_AA64ISAR1_EL1_IDX, "API")  ||
+           field_matches(field, ID_AA64ISAR1_EL1_IDX, "GPA")  ||
+           field_matches(field, ID_AA64ISAR1_EL1_IDX, "GPI")  ||
+           field_matches(field, ID_AA64ISAR2_EL1_IDX, "APA3") ||
+           field_matches(field, ID_AA64ISAR2_EL1_IDX, "GPA3");
+}
+
 void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
                                         const ARMISARegisters *host_isar,
                                         ArmFieldValueSet **value_set)
@@ -1358,6 +1376,13 @@ void kvm_arm_field_get_supported_values(const 
ARM64SysRegField *field,
     /* A non-writable field can only ever hold the host value. */
     if (!arm_field_is_writable(field)) {
         ranges_add(ranges, host, host);
+        /*
+         * ...unless it is one of the fields that can still be turned off
+         * via vCPU init flags, in which case "off" (0) is also supported.
+         */
+        if (host != 0 && kvm_arm_field_off_via_vcpu_flags(field)) {
+            ranges_add(ranges, 0, 0);
+        }
         goto done;
     }
 
-- 
2.52.0


Reply via email to