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 = &reg->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


Reply via email to