When QEMU queries supported CPU properties 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 only shows the
enabled host value (e.g., 5) and omits 0. This will lead into falsely
flagging a model as blocked as the features can be masked by not
passing those flags. 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 042d5fe804..ce77758c87 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1292,6 +1292,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 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 arm_field_get_supported_values(const ARM64SysRegField *field,
                                     const ARMISARegisters *host_isar,
                                     ArmFieldValueSet **value_set)
@@ -1304,6 +1322,13 @@ void 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 && arm_field_off_via_vcpu_flags(field)) {
+            ranges_add(ranges, 0, 0);
+        }
         goto done;
     }
 
-- 
2.52.0


Reply via email to