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. 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); + + /* + * 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 -- 2.52.0
