[RFC PATCH v3 09/19] target/arm: Add named cpu model infra + graviton3 named model
Khushit Shah <[email protected]>
| Newsgroups | org.nongnu.qemu-arm,dev.linux.lists.kvmarm,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
From: Shaju Abraham <[email protected]> Introduce a small named-CPU-model layer on top of the field-backed property infrastructure. Each model is a flat table of (name, value) overrides and a parent pointer. At instance-init, the parent chain is walked root-first and every level's properties are applied via QOM, so a child entry overrides its ancestors for the same name. For example, the graviton3-v1 named model hierarchy is: non-zero-defaults-v1 Known non-zero default ID regs field values arm-v8_4-a-v1 ARMv8.4-A architectural mandate neoverse-v1-v1 Neoverse V1 graviton3-v1 AWS Graviton3 non-zero-defaults-v1: Field that should be populated with some non zero value by default. arm-v8_4-a-v1: Only features mandated by the ARM ARM. neoverse-v1-v1: Reference manual derived feature values for the reference core. Values differ from TRM values based on what was exposed to the guest with -cpu host. graviton3-v1: SoC integration choices (crypto pin, cache hints, PAuth alg). The model values are figured out from ID register dump visible to QEMU with -cpu host on Graviton3 machine. Model realization: 1. Zero out ID regs array. 2. Add all properties to the CPU Object 3. arm_realize_model_chain: Walk the parent chain from root first and apply all the properties. Co-authored-by: Shaju Abraham <[email protected]> Signed-off-by: Khushit Shah <[email protected]> --- hw/arm/virt.c | 5 + target/arm/arm-cpu-models.c | 336 ++++++++++++++++++++++++++++++++++++ target/arm/arm-cpu-models.h | 35 ++++ target/arm/meson.build | 7 +- 4 files changed, 381 insertions(+), 2 deletions(-) create mode 100644 target/arm/arm-cpu-models.c create mode 100644 target/arm/arm-cpu-models.h diff --git a/hw/arm/virt.c b/hw/arm/virt.c index fe19030886..34e56dc1f1 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -3812,6 +3812,11 @@ static GPtrArray *virt_get_valid_cpu_types(const MachineState *ms) g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("host"))); } } + if (kvm_enabled() && target_aarch64()) { + g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("arm-v8_4-a-v1"))); + g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v1-v1"))); + g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("graviton3-v1"))); + } g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("max"))); return vct; diff --git a/target/arm/arm-cpu-models.c b/target/arm/arm-cpu-models.c new file mode 100644 index 0000000000..747e0df010 --- /dev/null +++ b/target/arm/arm-cpu-models.c @@ -0,0 +1,336 @@ +/* + * ARM named CPU model definitions. + * + * Each model is defined as an array of MODEL_PROP macro, listing only + * the properties that DIFFER from the parent model. + * + * At realisation the parent chain is walked root-first and + * every level's props are applied via QOM, so the leaf's values + * naturally override its ancestors. + * + * Hierarchy: + * + * non-zero-defaults-v1 Known non-zero default ID reg field values + * arm-v8_4-a-v1 ARMv8.4-A architectural mandate + * neoverse-v1-v1 Neoverse V1 (TRM 102649) + * graviton3-v1 AWS Graviton3 + * + * 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 "arm-cpu-models.h" +#include "cpu-idregs.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 } + +/* + * These fields should be populated with some non-zero default values. + */ +static const ArmModelPropValue non_zero_defaults_v1_props[] = { + /* ID_AA64PFR0_EL1 */ + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_EL0", NUM, 0b0001), + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_EL1", NUM, 0b0001), + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_FP", NUM, 0b1111), + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_AdvSIMD", NUM, 0b1111), + + /* ID_AA64PFR1_EL1 */ + MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_MTE_frac", NUM, 0b1111), + + /* ID_AA64MMFR0_EL1 */ + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64", NUM, 0b1111), + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4", NUM, 0b1111), + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran16_2", NUM, 0b0001), + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64_2", NUM, 0b0001), + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4_2", NUM, 0b0001), + + /* ID_AA64DFR0_EL1 */ + MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_DebugVer", NUM, 0x6), + MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_DoubleLock", NUM, 0b1111), + + /* CTR_EL0 */ + MODEL_PROP("SYSREG_CTR_EL0_L1Ip", NUM, 0b10), + MODEL_PROP("SYSREG_CTR_EL0_RES1_31", NUM, 1), + + /* ID_AA64MMFR4_EL1 */ + MODEL_PROP("SYSREG_ID_AA64MMFR4_EL1_E2H0", NUM, 0b1111), + + MODEL_PROP_END, +}; + +static const ArmModelPropValue armv8_4_a_v1_props[] = { + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_CRC32", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_Atomic", NUM, 2), + MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_HPDS", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_LO", NUM, 1), + + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_DPB", NUM, 1), + + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_RAS", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_RAS_frac", NUM, 0), + + MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_PAN", NUM, 2), + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_UAO", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_CnP", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_IESB", NUM, 1), + + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_DIT", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_DebugVer", NUM, 9), + MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_PMUVer", NUM, 5), + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_TS", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_LRCPC", NUM, 2), + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_AT", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_IDS", NUM, 1), + /* KVM zeroes out these field when MTE is not enabled. */ + MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_MTE_frac", NUM, 0), + MODEL_PROP_END, +}; + +static const ArmModelPropValue neoverse_v1_v1_props[] = { + MODEL_PROP("SYSREG_MIDR_EL1_Implementer", NUM, 0x41), + MODEL_PROP("SYSREG_MIDR_EL1_Variant", NUM, 0x1), + MODEL_PROP("SYSREG_MIDR_EL1_Architecture", NUM, 0xF), + MODEL_PROP("SYSREG_MIDR_EL1_PartNum", NUM, 0xD40), + MODEL_PROP("SYSREG_MIDR_EL1_Revision", NUM, 0x1), + + MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_BRPs", NUM, 0x5), + MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_WRPs", NUM, 0x3), + MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_CTX_CMPs", NUM, 0x1), + MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_DoubleLock", NUM, 0xF), + + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_RDM", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_DP", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_FHM", NUM, 1), + + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_DPB", NUM, 2), + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_JSCVT", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_FCMA", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_BF16", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_DGH", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_I8MM", NUM, 1), + + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_FP", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_AdvSIMD", NUM, 1), + + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_RAS", NUM, 2), + MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_RAS_frac", NUM, 0), + + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_CSV2", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_CSV2_frac", NUM, 0), + + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_CSV3", NUM, 1), + + MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_SSBS", NUM, 2), + + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_PARange", NUM, 5), + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_ASIDBits", NUM, 2), + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_BigEnd", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_SNSMem", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4", NUM, 0), + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran16", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64", NUM, 0), + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4_2", NUM, 0), + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran16_2", NUM, 0), + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64_2", NUM, 0), + MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_HAFDBS", NUM, 2), + MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_VMIDBits", NUM, 2), + MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_VH", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_HPDS", NUM, 2), + MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_XNX", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_SpecSEI", NUM, 0), + + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_FWB", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_BBM", NUM, 2), + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_EVT", NUM, 2), + + MODEL_PROP("SYSREG_ID_AA64MMFR4_EL1_E2H0", NUM, 0), + + MODEL_PROP("SYSREG_CTR_EL0_IminLine", NUM, 4), + MODEL_PROP("SYSREG_CTR_EL0_L1Ip", NUM, 3), + MODEL_PROP("SYSREG_CTR_EL0_DminLine", NUM, 4), + MODEL_PROP("SYSREG_CTR_EL0_ERG", NUM, 4), + MODEL_PROP("SYSREG_CTR_EL0_CWG", NUM, 4), + + MODEL_PROP("SYSREG_DCZID_EL0_BS", NUM, 0x4), + + /* pauth */ + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_APA", NUM, 3), + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_GPA", NUM, 1), + + /* sve */ + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_SVE", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_BF16", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_I8MM", NUM, 1), + MODEL_PROP("sve128", BOOL, true), + + MODEL_PROP_END, +}; + +static const ArmModelPropValue graviton3_v1_props[] = { + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_AES", NUM, 2), + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA1", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA2", NUM, 2), + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA3", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SM3", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SM4", NUM, 1), + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_RNDR", NUM, 1), + + MODEL_PROP("SYSREG_CTR_EL0_IDC", NUM, 1), + MODEL_PROP("SYSREG_CTR_EL0_DIC", NUM, 1), + + MODEL_PROP("SYSREG_REVIDR_EL1_VAL", NUM, 1), + + MODEL_PROP_END, +}; + +static const ArmNamedCpuModel arm_cpu_models[] = { + { + .name = "non-zero-defaults-v1", + .parent = NULL, + .props = non_zero_defaults_v1_props, + }, + { + .name = "arm-v8_4-a-v1", + .parent = "non-zero-defaults-v1", + .props = armv8_4_a_v1_props, + }, + { + .name = "neoverse-v1-v1", + .parent = "arm-v8_4-a-v1", + .props = neoverse_v1_v1_props, + }, + { + .name = "graviton3-v1", + .parent = "neoverse-v1-v1", + .props = graviton3_v1_props, + }, +}; + +static ARMCPUInfo arm_named_cpu_infos[ARRAY_SIZE(arm_cpu_models)]; +const ArmNamedCpuModel *arm_find_model(const char *name) +{ + size_t i; + for (i = 0; i < ARRAY_SIZE(arm_cpu_models); i++) { + if (g_str_equal(arm_cpu_models[i].name, name)) { + return &arm_cpu_models[i]; + } + } + return NULL; +} + +static 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; + } + } +} + +static void arm_realize_model_chain(Object *obj, const ArmNamedCpuModel *model, + Error **errp) +{ + const ArmNamedCpuModel *cur, *parent; + const ArmNamedCpuModel *chain[ARRAY_SIZE(arm_cpu_models)]; + size_t depth = 0; + for (cur = model; cur; ) { + if (depth >= ARRAY_SIZE(chain)) { + error_setg(errp, "model '%s': parent chain too deep " + "(possible cycle)", model->name); + return; + } + chain[depth++] = cur; + + if (!cur->parent) { + break; + } + parent = arm_find_model(cur->parent); + 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 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. Reset ID regs to 0 */ + memset(cpu->isar.idregs, 0, sizeof(cpu->isar.idregs)); + + /* 2. Add sveNNNN and SYSREG_ properties */ + aarch64_add_sve_properties(obj); + aarch64_add_idregs_properties(obj); + + /* 3. Realize the model chain. */ + arm_realize_model_chain(obj, model, &error_abort); +} + +void arm_register_named_cpu_models(void) +{ + size_t i; + for (i = 0; i < ARRAY_SIZE(arm_cpu_models); i++) { + 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/arm-cpu-models.h b/target/arm/arm-cpu-models.h new file mode 100644 index 0000000000..ac4e510499 --- /dev/null +++ b/target/arm/arm-cpu-models.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * ARM named CPU model definitions - public API. + */ +#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; + const ArmModelPropValue *props; +} ArmNamedCpuModel; + +void arm_register_named_cpu_models(void); + +const ArmNamedCpuModel *arm_find_model(const char *name); + +#endif /* ARM_CPU_MODELS_H */ diff --git a/target/arm/meson.build b/target/arm/meson.build index 64d1ec63ab..72eed1bcc6 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -10,7 +10,7 @@ arm_user_ss.add(files('gdbstub.c')) arm_ss.add(when: 'TARGET_AARCH64', if_true: files( 'cpu64.c', - 'gdbstub64.c' + 'gdbstub64.c', )) arm_common_ss.add(files( @@ -21,7 +21,10 @@ arm_common_system_ss.add(files( 'arm-qmp-cmds.c', 'cpu-idregs.c', )) -arm_system_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c')) +arm_system_ss.add(when: 'TARGET_AARCH64', if_true: files('arm-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')) arm_user_ss.add(files('cpu.c')) -- 2.52.0