> On 16 Oct 2026, at 7:24 PM, Eric Auger <[email protected]> wrote: > > !-------------------------------------------------------------------| > CAUTION: External Email > > |-------------------------------------------------------------------! > > Hi, > > On 9/21/26 2:32 PM, Khushit Shah wrote: >> Report blockers for named CPU models in query-cpu-definitions. >> >> Efficiently do this by validating the realized ID register values >> against the host values. sveNNNN properties need special handling >> because they are not stored in ID registers. >> >> This way, we need not instantiate each model to check if it can be >> realized on the host, and we also get granular information about the ID >> register fields blocking realization. >> >> Introduce arm_cpu_class_check_missing_features() and >> kvm_arm_idregs_get_blockers() to achieve this. > > I would recommend to show an excerpt of the output Cover letter already has one… Will add to commit message.
Thanks, Khushit >> >> Signed-off-by: Khushit Shah <[email protected]> >> --- >> target/arm/arm-qmp-cmds.c | 12 +++++++++ >> target/arm/cpu-models-stub.c | 5 ++++ >> target/arm/cpu-models.c | 35 +++++++++++++++++++++++++ >> target/arm/cpu-models.h | 2 ++ >> target/arm/kvm.c | 50 ++++++++++++++++++++++++++++++++++++ >> target/arm/kvm_arm.h | 13 ++++++++++ >> 6 files changed, 117 insertions(+) >> >> diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c >> index ba488d5c01..d837ec6653 100644 >> --- a/target/arm/arm-qmp-cmds.c >> +++ b/target/arm/arm-qmp-cmds.c >> @@ -379,6 +379,18 @@ static void arm_cpu_add_definition(gpointer data, >> gpointer user_data) >> info->name = cpu_model_from_type(typename); >> info->q_typename = g_strdup(typename); >> >> + /* calculate blockers */ >> + if (kvm_enabled() >> + && !g_str_equal(info->name, "host") >> + && !g_str_equal(info->name, "max") >> + && arm_find_model(info->name) != NULL) { >> + arm_cpu_class_check_missing_features(ARM_CPU_CLASS(oc), >> + &info->unavailable_features); >> + if (info->unavailable_features) { >> + info->has_unavailable_features = true; >> + } >> + } >> + >> QAPI_LIST_PREPEND(*cpu_list, info); >> } >> >> diff --git a/target/arm/cpu-models-stub.c b/target/arm/cpu-models-stub.c >> index 48f712d648..2d1be49e0a 100644 >> --- a/target/arm/cpu-models-stub.c >> +++ b/target/arm/cpu-models-stub.c >> @@ -11,3 +11,8 @@ const ArmNamedCpuModel *arm_find_model(const char *name) >> { >> return NULL; >> } >> + >> +void arm_cpu_class_check_missing_features(ARMCPUClass *acc, strList >> **blockers) >> +{ >> + return; >> +} >> diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c >> index 855eb5ee6b..9591b6dbfc 100644 >> --- a/target/arm/cpu-models.c >> +++ b/target/arm/cpu-models.c >> @@ -477,6 +477,41 @@ static void arm_named_cpu_initfn(Object *obj) >> arm_named_cpu_zero_unknown_feature_ids(cpu, &error_abort); >> } >> >> +void arm_cpu_class_check_missing_features(ARMCPUClass *acc, strList >> **blockers) >> +{ >> + Error *err = NULL; >> + Object *obj = object_new_with_class(OBJECT_CLASS(acc)); >> + ARMCPU *cpu = ARM_CPU(obj); >> + >> + if (!kvm_enabled() || !arm_find_model(acc->info->name)) { >> + goto out; >> + } >> + >> + if (cpu_isar_feature(aa64_sve, cpu)) { >> + aarch64_cpu_sve_finalize(cpu, &err); >> + if (err) { >> + error_free(err); >> + err = NULL; >> + uint32_t host_vq_map = cpu->sve_vq.supported; >> + uint32_t model_vq_map = cpu->sve_vq.map; >> + >> + if ((model_vq_map & host_vq_map) != model_vq_map) { >> + for (int vq = 1; vq <= ARM_MAX_VQ; vq++) { >> + uint32_t vq_bit = (1 << (vq - 1)); >> + if ((model_vq_map & vq_bit) && !(host_vq_map & vq_bit)) >> { >> + QAPI_LIST_PREPEND(*blockers, >> + g_strdup_printf("sve%d", vq * 128)); >> + } >> + } >> + } >> + } >> + } >> + >> + kvm_arm_idregs_get_blockers(cpu, kvm_arm_get_host_isar(), blockers); >> +out: >> + object_unref(obj); >> +} >> + >> void arm_register_named_cpu_models(void) >> { >> static ARMCPUInfo *arm_named_cpu_infos; >> diff --git a/target/arm/cpu-models.h b/target/arm/cpu-models.h >> index 144778744e..41bb15d928 100644 >> --- a/target/arm/cpu-models.h >> +++ b/target/arm/cpu-models.h >> @@ -4,6 +4,7 @@ >> >> #include "qapi/error.h" >> #include "qom/object.h" >> +#include "cpu.h" >> >> typedef enum ArmModelPropType { >> ARM_MODEL_PROP_BOOL, >> @@ -32,5 +33,6 @@ void arm_apply_model_props(Object *obj, const >> ArmModelPropValue *props, >> Error **errp); >> void arm_realize_model_chain(Object *obj, const ArmNamedCpuModel *model, >> Error **errp); >> +void arm_cpu_class_check_missing_features(ARMCPUClass *acc, strList >> **blockers); >> >> #endif /* ARM_CPU_MODELS_H */ >> diff --git a/target/arm/kvm.c b/target/arm/kvm.c >> index bb74f8c274..ca3da80262 100644 >> --- a/target/arm/kvm.c >> +++ b/target/arm/kvm.c >> @@ -1485,6 +1485,56 @@ arm_field_skip_writeback_if_not_writable(const >> ARM64SysRegField *field) >> return field_matches(field, ID_DFR0_EL1_IDX, "PerfMon"); >> } >> >> +void kvm_arm_idregs_get_blockers(ARMCPU *cpu, >> + const ARMISARegisters *host_isar, >> + strList **blockers) >> +{ >> + for (int i = 0; i < NUM_ID_IDX; i++) { >> + ARM64SysReg *reg = &arm64_id_regs[i]; >> + >> + if (!reg->name) { >> + continue; >> + } >> + >> + for (uint32_t j = 0; j < reg->fields_count; j++) { >> + const ARM64SysRegField *field = ®->fields[j]; >> + ArmFieldValueSet *vs = NULL; >> + bool supported = false; >> + uint64_t model_val; >> + >> + /* Not a blocker if the field is never written back to KVM. */ >> + if (arm_field_skip_writeback_always(field) || >> + (!arm_field_is_writable(field) && >> + arm_field_skip_writeback_if_not_writable(field))) { >> + continue; >> + } >> + >> + model_val = extract64(cpu->isar.idregs[field->index], >> + field->shift, field->length); > nit I see you use that several times, you could introduce a helper >> + >> + /* >> + * If the field is written back, make sure a "supported" value >> + * is requested. >> + */ >> + kvm_arm_field_get_supported_values(field, host_isar, &vs); >> + for (size_t k = 0; k < vs->n_ranges; k++) { >> + if (model_val >= vs->ranges[k].min && >> + model_val <= vs->ranges[k].max) { >> + supported = true; >> + break; >> + } >> + } >> + g_free(vs->ranges); >> + g_free(vs); >> + >> + if (!supported) { >> + QAPI_LIST_PREPEND(*blockers, >> + g_strdup_printf("SYSREG_%s_%s", reg->name, >> field->name)); >> + } >> + } >> + } >> +} >> + >> /* >> * Copy writable ID reg fields from isar.idregs[] into the KVM cpreg list, >> * so the subsequent write_list_to_kvmstate() pushes them to KVM. >> diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h >> index ab01ce8665..59832d8063 100644 >> --- a/target/arm/kvm_arm.h >> +++ b/target/arm/kvm_arm.h >> @@ -205,6 +205,19 @@ void kvm_arm_field_get_supported_values(const >> ARM64SysRegField *field, >> const ARMISARegisters *host_isar, >> ArmFieldValueSet **value_set); >> >> +/** >> + * kvm_arm_idregs_get_blockers: >> + * @cpu: ARMCPU >> + * @host_isar: The host ISAR registers >> + * @blockers: The list of blockers >> + * >> + * Get the list of "blockers" in @cpu's idregs state for the given >> + * @host_isar. >> + */ >> +void kvm_arm_idregs_get_blockers(ARMCPU *cpu, >> + const ARMISARegisters *host_isar, >> + strList **blockers); >> + >> /** >> * kvm_arm_steal_time_finalize: >> * @cpu: ARMCPU for which to finalize kvm-steal-time > Thanks > > Eric
