Hi Khushit,
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Add scaffolding for named CPU models on Arm on top of the property
> layer. A model is a list of (property, value) overrides plus an
> optional parent; a child inherits its parent's property values and may
> override them.
>
> Instance init steps:
> - host feature discovery.
> - zero out isar.idregs[] and restore RES1 fields.
> - install SYSREG_ and sve* properties.
> - walk the parent chain root-first and apply each level's
> properties.
you should explain about prop types. I see they are either bool or uint.
Given the parent series bool usage is not obvious.
>
> This assumes that each property is idempotent. `pauth` is intentionally
> not installed because the model's ID register view is authoritative
> and can be configured through SYSREG_ properties.
>
> No models are defined yet.
>
> Signed-off-by: Khushit Shah <[email protected]>
> ---
> target/arm/cpu-models.c | 191 ++++++++++++++++++++++++++++++++++++++++
> target/arm/cpu-models.h | 36 ++++++++
> target/arm/meson.build | 1 +
> 3 files changed, 228 insertions(+)
> create mode 100644 target/arm/cpu-models.c
> create mode 100644 target/arm/cpu-models.h
>
> diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
> new file mode 100644
> index 0000000000..fed3197186
> --- /dev/null
> +++ b/target/arm/cpu-models.c
> @@ -0,0 +1,191 @@
> +/*
> + * ARM named CPU models.
> + *
> + * Each model is defined as an array of MODEL_PROP macros, listing only
> + * the properties that DIFFER from the parent model.
> + *
> + * Initialization starts with a zeroed idregs[] array.
> + *
> + * During initialization, the parent chain is walked root-first and every
> + * level's properties are applied via QOM, so the leaf's values naturally
> + * override its ancestors.
> + *
> + * Assumptions:
> + * - All named CPU model properties are idempotent.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/error-report.h"
> +#include "system/kvm.h"
> +#include "cpu.h"
> +#include "internals.h"
> +#include "kvm_arm.h"
> +#include "cpu-idregs.h"
> +#include "cpu-models.h"
> +
> +#define MODEL_PROP_FIELD_STR str
> +#define MODEL_PROP_FIELD_BOOL b
> +#define MODEL_PROP_FIELD_NUM num
> +
> +#define MODEL_PROP(_name, _type, _value) \
> + { .name = (_name), .type = ARM_MODEL_PROP_##_type, \
> + .u.MODEL_PROP_FIELD_##_type = (_value) }
> +
> +#define MODEL_PROP_END { .name = NULL }
> +
> +/* Maximum parent-chain depth for named CPU models. */
inheritence depth?
> +#define ARM_NAMED_CPU_MODEL_MAX_DEPTH 16
> +
> +static const ArmNamedCpuModel arm_cpu_models[] = {
> + {NULL, NULL, NULL}
> +};
> +
> +const ArmNamedCpuModel *arm_find_model(const char *name)
> +{
> + for (size_t i = 0; i < ARRAY_SIZE(arm_cpu_models); i++) {
> + if (!arm_cpu_models[i].name) {
> + break;
> + }
> +
> + if (g_str_equal(arm_cpu_models[i].name, name)) {
> + return &arm_cpu_models[i];
> + }
> + }
> + return NULL;
> +}
> +
> +void arm_apply_model_props(Object *obj, const ArmModelPropValue *props,
> + Error **errp)
> +{
> + const ArmModelPropValue *pv;
> + ERRP_GUARD();
> +
> + for (pv = props; pv->name; pv++) {
> + switch (pv->type) {
> + case ARM_MODEL_PROP_BOOL:
> + object_property_set_bool(obj, pv->name, pv->u.b, errp);
> + break;
> + case ARM_MODEL_PROP_NUM:
> + object_property_set_uint(obj, pv->name, pv->u.num, errp);
> + break;
> + default:
> + g_assert_not_reached();
> + }
> +
> + if (*errp) {
> + error_prepend(errp, "property '%s': ", pv->name);
> + return;
> + }
> + }
> +}
> +
> +void arm_realize_model_chain(Object *obj, const ArmNamedCpuModel *model,
> + Error **errp)
> +{
> + const ArmNamedCpuModel *cur, *parent;
> + const ArmNamedCpuModel *chain[ARM_NAMED_CPU_MODEL_MAX_DEPTH];
> + size_t depth = 0;
> +
> + for (cur = model; cur; ) {
> + if (depth >= ARRAY_SIZE(chain)) {
> + error_setg(errp, "model '%s': parent chain too deep",
> model->name);
> + return;
> + }
> + chain[depth++] = cur;
Please add a comment about the so-called chain and especially describing
that chain[0] is the child and high-level eindex lements are the parents
it derives from.
> +
> + if (!cur->parent) {
> + break;
> + }
> + parent = arm_find_model(cur->parent);
I guess you directly assert
> + if (!parent) {
> + error_setg(errp, "model '%s': unknown parent '%s'", cur->name,
> + cur->parent);
> + return;
> + }
> + cur = parent;
> + }
> +
> + while (depth--) {
> + arm_apply_model_props(obj, chain[depth]->props, errp);
> + if (*errp) {
> + return;
> + }
> + }
> +}
> +
> +static void reset_res1_fields(ARMCPU *cpu)
> +{
> + for (size_t i = 0; i < NUM_ID_IDX; i++) {
> + for (size_t j = 0; j < arm64_id_regs[i].fields_count; j++) {
> + if (strcmp(arm64_id_regs[i].fields[j].name, "RES1") == 0) {
> + cpu->isar.idregs[i] = deposit64(cpu->isar.idregs[i],
> + arm64_id_regs[i].fields[j].shift,
> + arm64_id_regs[i].fields[j].length,
> + MAKE_64BIT_MASK(0, arm64_id_regs[i].fields[j].length));
> + }
> + }
> + }
> +}
> +
> +static void arm_named_cpu_initfn(Object *obj)
> +{
> + ARMCPU *cpu = ARM_CPU(obj);
> + ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj);
> + const ArmNamedCpuModel *model = arm_find_model(acc->info->name);
> +
> + if (!model) {
> + error_report("'%s' CPU model entry not found",
> + acc->info->name);
> + return;
> + }
> +
> + if (!kvm_enabled()) {
> + error_report("'%s' CPU model requires KVM (-accel kvm)",
> + acc->info->name);
> + return;
> + }
> +
> + kvm_arm_set_cpu_features_from_host(cpu);
> + if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
> + return;
> + }
> +
> + /* 1.a Reset ID regs to 0 */
> + memset(cpu->isar.idregs, 0, sizeof(cpu->isar.idregs));
> +
> + /* 1.b Properly set RES1 fields. */
> + reset_res1_fields(cpu);
> +
> + /* 2. Add sveNNNN and SYSREG_ properties */
> + aarch64_add_sve_properties(obj);
> + aarch64_add_idregs_properties(obj);
Can you give more explanations about why we don't have
aarch64_add_pauth_properties()
kvm_arm_set_cpreg_mig_tolerances()
at least.
By the way it is not clear what will become legacy compositive options
with named vcpu models. I see you keep sve but what about the others.
> +
> + /* 3. Realize the model chain. */
> + arm_realize_model_chain(obj, model, &error_abort);
> +}
> +
> +void arm_register_named_cpu_models(void)
> +{
> + static ARMCPUInfo *arm_named_cpu_infos;
> + size_t i, n = ARRAY_SIZE(arm_cpu_models);
> +
> + if (!n) {
> + return;
> + }
> +
> + arm_named_cpu_infos = g_new0(ARMCPUInfo, n);
> + for (i = 0; i < n; i++) {
> + if (!arm_cpu_models[i].name) {
> + break;
> + }
> +
> + arm_named_cpu_infos[i].name = arm_cpu_models[i].name;
> + arm_named_cpu_infos[i].initfn = arm_named_cpu_initfn;
> + arm_cpu_register(&arm_named_cpu_infos[i]);
> + }
> +}
> +
> +type_init(arm_register_named_cpu_models)
> diff --git a/target/arm/cpu-models.h b/target/arm/cpu-models.h
> new file mode 100644
> index 0000000000..144778744e
> --- /dev/null
> +++ b/target/arm/cpu-models.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +#ifndef ARM_CPU_MODELS_H
> +#define ARM_CPU_MODELS_H
> +
> +#include "qapi/error.h"
> +#include "qom/object.h"
> +
> +typedef enum ArmModelPropType {
> + ARM_MODEL_PROP_BOOL,
> + ARM_MODEL_PROP_NUM,
> +} ArmModelPropType;
> +
> +typedef struct ArmModelPropValue {
> + const char *name;
> + ArmModelPropType type;
> + union {
> + bool b;
> + uint64_t num;
> + } u;
> +} ArmModelPropValue;
> +
> +typedef struct ArmNamedCpuModel {
> + const char *name;
> + const char *parent;
any reason why you don't point to the patent ArmNamedCpuModel pointer
instead?
> + const ArmModelPropValue *props;
> +} ArmNamedCpuModel;
> +
> +void arm_register_named_cpu_models(void);
> +
> +const ArmNamedCpuModel *arm_find_model(const char *name);
> +void arm_apply_model_props(Object *obj, const ArmModelPropValue *props,
> + Error **errp);
> +void arm_realize_model_chain(Object *obj, const ArmNamedCpuModel *model,
> + Error **errp);
> +
> +#endif /* ARM_CPU_MODELS_H */
> diff --git a/target/arm/meson.build b/target/arm/meson.build
> index 384d90c530..dd28146c52 100644
> --- a/target/arm/meson.build
> +++ b/target/arm/meson.build
> @@ -32,6 +32,7 @@ arm_common_system_ss.add(files(
> 'arm-qmp-cmds.c',
> 'cpu-idregs.c',
> ))
> +arm_system_ss.add(when: 'TARGET_AARCH64', if_true: files('cpu-models.c'))
> arm_system_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c',
> 'kvm.c'))
> arm_system_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c'))
>
Eric