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
