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 > > 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
