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
