diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 46c72a961179c5dbb030b28f18646aab8b1f60f6..08bb570dbf1b3275d0a68c99bf6d94f62f225e2d 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -258,9 +258,11 @@ static const char *valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-a53"), ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a72"), + ARM_CPU_TYPE_NAME("Tengyun-S5000C"), ARM_CPU_TYPE_NAME("a64fx"), ARM_CPU_TYPE_NAME("host"), ARM_CPU_TYPE_NAME("max"), + ARM_CPU_TYPE_NAME("phytium-v"), }; static bool cpu_type_valid(const char *cpu) diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index 9884d2e39b9ab938f78e26219054cd04755691df..4a3ca476a020b54cd1ec322fa29958dcb9d2a441 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -87,6 +87,11 @@ static int gicv3_post_load(void *opaque, int version_id) gicv3_gicd_no_migration_shift_bug_post_load(s); if (c->post_load) { + /* load origin value of reg icc_ctrl_el1 when migrate vm */ + for (int ncpu = 0; ncpu < s->num_cpu; ncpu++) { + GICv3CPUState *c = &s->cpu[ncpu]; + c->icc_ctlr_el1[GICV3_NS] = c->icc_ctlr_el1_origin[GICV3_NS]; + } c->post_load(s); } return 0; diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 5ec5ff9ef6e8deecb91c5207d5b5aa1718919faf..f6e2929ede68a29d73d2b549aa674999f40c848a 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -689,6 +689,7 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) &c->icc_ctlr_el1[GICV3_NS], false, &error_abort); c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; + c->icc_ctlr_el1_origin[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; } static void kvm_arm_gicv3_reset(DeviceState *dev) @@ -706,6 +707,11 @@ static void kvm_arm_gicv3_reset(DeviceState *dev) } kvm_arm_gicv3_put(s); + + for (int ncpu = 0; ncpu < s->num_cpu; ncpu++) { + GICv3CPUState *c = &s->cpu[ncpu]; + c->icc_ctlr_el1_origin[GICV3_NS] = c->icc_ctlr_el1[GICV3_NS]; + } } /* diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h index fc38e4b7dca4ac7f4a5e0377a5cc300e9a13feaf..8217aa123a329096e68606fb31d24dd4d1b415a2 100644 --- a/include/hw/intc/arm_gicv3_common.h +++ b/include/hw/intc/arm_gicv3_common.h @@ -178,6 +178,7 @@ struct GICv3CPUState { /* CPU interface */ uint64_t icc_sre_el1; uint64_t icc_ctlr_el1[2]; + uint64_t icc_ctlr_el1_origin[2]; uint64_t icc_pmr_el1; uint64_t icc_bpr[3]; uint64_t icc_apr[3][4]; diff --git a/include/qemu/aarch64-cpuid.h b/include/qemu/aarch64-cpuid.h new file mode 100644 index 0000000000000000000000000000000000000000..ec68e6d575ba8d52a0978c5cfdcdeed0a4e1d847 --- /dev/null +++ b/include/qemu/aarch64-cpuid.h @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * aarch64-cpuid.h: Macros to identify the MIDR of aarch64. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_AARCH64_CPUID_H +#define QEMU_AARCH64_CPUID_H + +#define MIDR_REVISION_MASK 0xf +#define MIDR_REVISION(midr) ((midr) & MIDR_REVISION_MASK) +#define MIDR_PARTNUM_SHIFT 4 +#define MIDR_PARTNUM_MASK (0xfff << MIDR_PARTNUM_SHIFT) +#define MIDR_PARTNUM(midr) \ + (((midr) & MIDR_PARTNUM_MASK) >> MIDR_PARTNUM_SHIFT) +#define MIDR_ARCHITECTURE_SHIFT 16 +#define MIDR_ARCHITECTURE_MASK (0xf << MIDR_ARCHITECTURE_SHIFT) +#define MIDR_ARCHITECTURE(midr) \ + (((midr) & MIDR_ARCHITECTURE_MASK) >> MIDR_ARCHITECTURE_SHIFT) +#define MIDR_VARIANT_SHIFT 20 +#define MIDR_VARIANT_MASK (0xf << MIDR_VARIANT_SHIFT) +#define MIDR_VARIANT(midr) \ + (((midr) & MIDR_VARIANT_MASK) >> MIDR_VARIANT_SHIFT) +#define MIDR_IMPLEMENTOR_SHIFT 24 +#define MIDR_IMPLEMENTOR_MASK (0xffU << MIDR_IMPLEMENTOR_SHIFT) +#define MIDR_IMPLEMENTOR(midr) \ + (((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT) +#define MIDR_CPU_MODEL(imp, partnum) \ + (((imp) << MIDR_IMPLEMENTOR_SHIFT) | \ + (0xf << MIDR_ARCHITECTURE_SHIFT) | \ + ((partnum) << MIDR_PARTNUM_SHIFT)) + +#define MIDR_CPU_VAR_REV(var, rev) \ + (((var) << MIDR_VARIANT_SHIFT) | (rev)) + +#define MIDR_CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \ + MIDR_ARCHITECTURE_MASK) + +#define ARM_CPU_IMP_PHYTIUM 0x70 +#define PHYTIUM_CPU_PART_FTC662 0x662 +#define PHYTIUM_CPU_PART_FTC663 0x663 +#define PHYTIUM_CPU_PART_FTC862 0x862 + +uint64_t qemu_read_cpuid_id(void); +uint8_t qemu_read_cpuid_implementor(void); +uint16_t qemu_read_cpuid_part_number(void); +bool is_phytium_cpu(void); + +#endif diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 8d2f496ef9a07966f6e82f514c1da5d7459daa4d..080d3932972208319b5d8c902627f2e660edce08 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2934,6 +2934,8 @@ typedef struct ARMCPRegUserSpaceInfo { #define REGUSERINFO_SENTINEL { .name = NULL } void modify_arm_cp_regs(ARMCPRegInfo *regs, const ARMCPRegUserSpaceInfo *mods); +int modify_arm_vcpu_regs_for_phytium_v(ARMCPU *cpu); +bool check_compatibility_for_phytium(ARMCPU *cpu); /* CPWriteFn that can be used to implement writes-ignored behaviour */ void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri, diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 15245a60a8c701bf598a0d493e38d859663ecc67..d7284c66d081e0758f564f5112af32450494ad28 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -888,12 +888,84 @@ static void aarch64_a64fx_initfn(Object *obj) /* TODO: Add A64FX specific HPC extension registers */ } +static void aarch64_phytium_v_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + if (kvm_enabled()) { + kvm_arm_set_cpu_features_from_host(cpu); + } else { + uint64_t t; + + aarch64_a57_initfn(obj); + + /* + * Reset MIDR so the guest doesn't mistake our 'max' CPU type for a real + * one and try to apply errata workarounds or use impdef features we + * don't provide. + * An IMPLEMENTER field of 0 means "reserved for software use"; + * ARCHITECTURE must be 0xf indicating "v7 or later, check ID registers + * to see which features are present"; + * the VARIANT, PARTNUM and REVISION fields are all implementation + * defined and we choose to define PARTNUM just in case guest + * code needs to distinguish this QEMU CPU from other software + * implementations, though this shouldn't be needed. + */ + t = FIELD_DP64(0, MIDR_EL1, IMPLEMENTER, 0x70); + t = FIELD_DP64(t, MIDR_EL1, ARCHITECTURE, 0xf); + t = FIELD_DP64(t, MIDR_EL1, PARTNUM, 0x662); + t = FIELD_DP64(t, MIDR_EL1, VARIANT, 0x1); + t = FIELD_DP64(t, MIDR_EL1, REVISION, 2); + cpu->midr = t; + } + + aarch64_add_sve_properties(obj); + object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq, + cpu_max_set_sve_max_vq, NULL, NULL); +} + +static void aarch64_tengyun_s5000c_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + aarch64_a72_initfn(obj); + + cpu->midr = 0x700f8620; + cpu->ctr = 0x9444c004; + cpu->isar.id_isar0 = 0x2101110; + cpu->isar.id_isar1 = 0x1311211; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x1112131; + cpu->isar.id_isar4 = 0x10142; + cpu->isar.id_isar5 = 0x1011121; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x1260000; + cpu->isar.id_mmfr3 = 0x2122211; + cpu->isar.id_mmfr4 = 0x21110; + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x43; + cpu->isar.id_dfr0 = 0x4010088; + cpu->isar.id_pfr0 = 0x10131; + cpu->isar.id_pfr1 = 0x10010000; + cpu->isar.id_aa64pfr0 = 0x1100000011111112; + cpu->isar.id_aa64dfr0 = 0x10305408; + cpu->isar.id_aa64isar0 = 0x111110212120; + cpu->isar.id_aa64isar1 = 0x100001; + cpu->isar.id_aa64mmfr0 = 0x101125; + cpu->isar.id_aa64mmfr1 = 0x10212122; + cpu->isar.id_aa64mmfr2 = 0x1011; +} + static const ARMCPUInfo aarch64_cpus[] = { { .name = "cortex-a57", .initfn = aarch64_a57_initfn }, { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, + { .name = "Tengyun-S5000C", .initfn = aarch64_tengyun_s5000c_initfn }, { .name = "a64fx", .initfn = aarch64_a64fx_initfn }, { .name = "max", .initfn = aarch64_max_initfn }, + { .name = "phytium-v", .initfn = aarch64_phytium_v_initfn }, }; static bool aarch64_cpu_get_aarch64(Object *obj, Error **errp) diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 7bec3e5f4ff82419efb5ddf1755afe68aa0f4933..8ea1b950494cb0528dd708b9b9ef3c2302701496 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -582,11 +582,7 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level) } ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); if (ret) { - /* We might fail for "unknown register" and also for - * "you tried to set a register which is constant with - * a different value from what it actually contains". - */ - ok = false; + ok = check_compatibility_for_phytium(cpu); } } return ok; diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index e790d6c9a5732a58a060760154f8514252f4b38c..cd2ad5044c62acef2604e9e53ec276c6c557b18f 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -23,6 +23,7 @@ #include "qemu/error-report.h" #include "qemu/host-utils.h" #include "qemu/main-loop.h" +#include "qemu/aarch64-cpuid.h" #include "exec/gdbstub.h" #include "sysemu/runstate.h" #include "sysemu/kvm.h" @@ -468,6 +469,34 @@ void kvm_arm_pvtime_init(CPUState *cs, uint64_t ipa) } } +#define SYS_ID_PFR0_EL1 ARM64_SYS_REG(3, 0, 0, 1, 0) +#define SYS_ID_PFR1_EL1 ARM64_SYS_REG(3, 0, 0, 1, 1) +#define SYS_ID_PFR2_EL1 ARM64_SYS_REG(3, 0, 0, 3, 4) +#define SYS_ID_DFR0_EL1 ARM64_SYS_REG(3, 0, 0, 1, 2) +#define SYS_ID_MMFR0_EL1 ARM64_SYS_REG(3, 0, 0, 1, 4) +#define SYS_ID_MMFR1_EL1 ARM64_SYS_REG(3, 0, 0, 1, 5) +#define SYS_ID_MMFR2_EL1 ARM64_SYS_REG(3, 0, 0, 1, 6) +#define SYS_ID_MMFR3_EL1 ARM64_SYS_REG(3, 0, 0, 1, 7) +#define SYS_ID_MMFR4_EL1 ARM64_SYS_REG(3, 0, 0, 2, 6) +#define SYS_ID_ISAR0_EL1 ARM64_SYS_REG(3, 0, 0, 2, 0) +#define SYS_ID_ISAR1_EL1 ARM64_SYS_REG(3, 0, 0, 2, 1) +#define SYS_ID_ISAR2_EL1 ARM64_SYS_REG(3, 0, 0, 2, 2) +#define SYS_ID_ISAR3_EL1 ARM64_SYS_REG(3, 0, 0, 2, 3) +#define SYS_ID_ISAR4_EL1 ARM64_SYS_REG(3, 0, 0, 2, 4) +#define SYS_ID_ISAR5_EL1 ARM64_SYS_REG(3, 0, 0, 2, 5) +#define SYS_ID_ISAR6_EL1 ARM64_SYS_REG(3, 0, 0, 2, 7) +#define SYS_MVFR0_EL1 ARM64_SYS_REG(3, 0, 0, 3, 0) +#define SYS_MVFR1_EL1 ARM64_SYS_REG(3, 0, 0, 3, 1) +#define SYS_MVFR2_EL1 ARM64_SYS_REG(3, 0, 0, 3, 2) +#define SYS_ID_AA64PFR0_EL1 ARM64_SYS_REG(3, 0, 0, 4, 0) +#define SYS_ID_AA64PFR1_EL1 ARM64_SYS_REG(3, 0, 0, 4, 1) +#define SYS_ID_AA64DFR0_EL1 ARM64_SYS_REG(3, 0, 0, 5, 0) +#define SYS_ID_AA64ISAR0_EL1 ARM64_SYS_REG(3, 0, 0, 6, 0) +#define SYS_ID_AA64ISAR1_EL1 ARM64_SYS_REG(3, 0, 0, 6, 1) +#define SYS_ID_AA64MMFR0_EL1 ARM64_SYS_REG(3, 0, 0, 7, 0) +#define SYS_ID_AA64MMFR1_EL1 ARM64_SYS_REG(3, 0, 0, 7, 1) +#define SYS_ID_AA64MMFR2_EL1 ARM64_SYS_REG(3, 0, 0, 7, 2) + static int read_sys_reg32(int fd, uint32_t *pret, uint64_t id) { uint64_t ret; @@ -529,7 +558,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) ahcf->dtb_compatible = "arm,arm-v8"; err = read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr0, - ARM64_SYS_REG(3, 0, 0, 4, 0)); + SYS_ID_AA64PFR0_EL1); if (unlikely(err < 0)) { /* * Before v4.15, the kernel only exposed a limited number of system @@ -551,21 +580,21 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) err = 0; } else { err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1, - ARM64_SYS_REG(3, 0, 0, 4, 1)); + SYS_ID_AA64PFR1_EL1); err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0, - ARM64_SYS_REG(3, 0, 0, 5, 0)); + SYS_ID_AA64DFR0_EL1); err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1, ARM64_SYS_REG(3, 0, 0, 5, 1)); err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar0, - ARM64_SYS_REG(3, 0, 0, 6, 0)); + SYS_ID_AA64ISAR0_EL1); err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar1, - ARM64_SYS_REG(3, 0, 0, 6, 1)); + SYS_ID_AA64ISAR1_EL1); err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr0, - ARM64_SYS_REG(3, 0, 0, 7, 0)); + SYS_ID_AA64MMFR0_EL1); err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr1, - ARM64_SYS_REG(3, 0, 0, 7, 1)); + SYS_ID_AA64MMFR1_EL1); err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr2, - ARM64_SYS_REG(3, 0, 0, 7, 2)); + SYS_ID_AA64MMFR2_EL1); /* * Note that if AArch32 support is not present in the host, @@ -575,44 +604,44 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) * considering the values in every case. */ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr0, - ARM64_SYS_REG(3, 0, 0, 1, 0)); + SYS_ID_PFR0_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr1, - ARM64_SYS_REG(3, 0, 0, 1, 1)); + SYS_ID_PFR1_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr2, - ARM64_SYS_REG(3, 0, 0, 3, 4)); + SYS_ID_PFR2_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0, - ARM64_SYS_REG(3, 0, 0, 1, 2)); + SYS_ID_DFR0_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, - ARM64_SYS_REG(3, 0, 0, 1, 4)); + SYS_ID_MMFR0_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1, - ARM64_SYS_REG(3, 0, 0, 1, 5)); + SYS_ID_MMFR1_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr2, - ARM64_SYS_REG(3, 0, 0, 1, 6)); + SYS_ID_MMFR2_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr3, - ARM64_SYS_REG(3, 0, 0, 1, 7)); + SYS_ID_MMFR3_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar0, - ARM64_SYS_REG(3, 0, 0, 2, 0)); + SYS_ID_ISAR0_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar1, - ARM64_SYS_REG(3, 0, 0, 2, 1)); + SYS_ID_ISAR1_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar2, - ARM64_SYS_REG(3, 0, 0, 2, 2)); + SYS_ID_ISAR2_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar3, - ARM64_SYS_REG(3, 0, 0, 2, 3)); + SYS_ID_ISAR3_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar4, - ARM64_SYS_REG(3, 0, 0, 2, 4)); + SYS_ID_ISAR4_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar5, - ARM64_SYS_REG(3, 0, 0, 2, 5)); + SYS_ID_ISAR5_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr4, - ARM64_SYS_REG(3, 0, 0, 2, 6)); + SYS_ID_MMFR4_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar6, - ARM64_SYS_REG(3, 0, 0, 2, 7)); + SYS_ID_ISAR6_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr0, - ARM64_SYS_REG(3, 0, 0, 3, 0)); + SYS_MVFR0_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr1, - ARM64_SYS_REG(3, 0, 0, 3, 1)); + SYS_MVFR1_EL1); err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2, - ARM64_SYS_REG(3, 0, 0, 3, 2)); + SYS_MVFR2_EL1); /* * DBGDIDR is a bit complicated because the kernel doesn't @@ -824,6 +853,113 @@ static int kvm_arm_sve_set_vls(CPUState *cs) return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); } +struct SysRegInfo { + const char *name; + uint64_t reg; + uint64_t value; +}; + +const struct SysRegInfo sys_regs_info[] = { + { "ID_PFR0_EL1", SYS_ID_PFR0_EL1, 0 }, + { "ID_PFR1_EL1", SYS_ID_PFR1_EL1, 0 }, + { "ID_PFR2_EL1", SYS_ID_PFR2_EL1, 0 }, + { "ID_DFR0_EL1", SYS_ID_DFR0_EL1, 0 }, + { "ID_MMFR0_EL1", SYS_ID_MMFR0_EL1, 0 }, + { "ID_MMFR1_EL1", SYS_ID_MMFR1_EL1, 0 }, + { "ID_MMFR2_EL1", SYS_ID_MMFR2_EL1, 0 }, + { "ID_MMFR3_EL1", SYS_ID_MMFR3_EL1, 0 }, + { "ID_MMFR4_EL1", SYS_ID_MMFR4_EL1, 0 }, + { "ID_ISAR0_EL1", SYS_ID_ISAR0_EL1, 0 }, + { "ID_ISAR1_EL1", SYS_ID_ISAR1_EL1, 0 }, + { "ID_ISAR2_EL1", SYS_ID_ISAR2_EL1, 0 }, + { "ID_ISAR3_EL1", SYS_ID_ISAR3_EL1, 0 }, + { "ID_ISAR4_EL1", SYS_ID_ISAR4_EL1, 0 }, + { "ID_ISAR5_EL1", SYS_ID_ISAR5_EL1, 0 }, + { "ID_ISAR6_EL1", SYS_ID_ISAR6_EL1, 0 }, + { "MVFR0_EL1", SYS_MVFR0_EL1, 0 }, + { "MVFR1_EL1", SYS_MVFR1_EL1, 0 }, + { "MVFR2_EL1", SYS_MVFR2_EL1, 0 }, + { "ID_AA64PFR0_EL1", SYS_ID_AA64PFR0_EL1, 0x01001111 }, + { "ID_AA64PFR1_EL1", SYS_ID_AA64PFR1_EL1, 0 }, + { "ID_AA64DFR0_EL1", SYS_ID_AA64DFR0_EL1, 0x10305106 }, + { "ID_AA64ISAR0_EL1", SYS_ID_AA64ISAR0_EL1, 0x10000 }, + { "ID_AA64ISAR1_EL1", SYS_ID_AA64ISAR1_EL1, 0 }, + { "ID_AA64MMFR0_EL1", SYS_ID_AA64MMFR0_EL1, 0x1124 }, + { "ID_AA64MMFR1_EL1", SYS_ID_AA64MMFR1_EL1, 0 }, + { "ID_AA64MMFR2_EL1", SYS_ID_AA64MMFR2_EL1, 0 }, +}; + +/* PHYTIUM : modify sys_regs for phytium-v. */ +int modify_arm_vcpu_regs_for_phytium_v(ARMCPU *cpu) +{ + int ret = 0; + CPUState *cs = CPU(cpu); + Object *obj = OBJECT(cpu); + ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj); + + if (NULL != acc->info && 0 == strcmp(acc->info->name, "phytium-v")) { + uint64_t val = 0; + for (int i = 0; i < ARRAY_SIZE(sys_regs_info); i++) { + val = sys_regs_info[i].value; + ret = kvm_set_one_reg(cs, sys_regs_info[i].reg, &val); + if (ret) { + break; + } + } + } + + return ret; +} + +bool check_compatibility_for_phytium(ARMCPU *cpu) +{ + Object *obj = OBJECT(cpu); + ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj); + + int i; + bool ret = true; + uint8_t src_impl = 0; + uint16_t src_partnum = 0; + uint64_t src_midr = 0; + + if (NULL != acc->info && 0 == strcmp(acc->info->name, "phytium-v")) { + ret = true; + } else { + for (i = 0; i < cpu->cpreg_array_len; i++) { + uint64_t regidx = cpu->cpreg_indexes[i]; + if (regidx == ARM64_SYS_REG(3, 0, 0, 0, 0)) { + src_midr = cpu->cpreg_values[i]; + src_impl = (src_midr >> 24) & 0xff; + src_partnum = (src_midr >> 4) & 0x0fff; + break; + } + } + + if (src_impl == ARM_CPU_IMP_PHYTIUM) { + if (is_phytium_cpu()) { + if (qemu_read_cpuid_part_number() >= src_partnum) { + ret = true; + } else { + ret = false; + } + } else if (qemu_read_cpuid_implementor() == 0x48) { + if (src_partnum == PHYTIUM_CPU_PART_FTC662 + || src_partnum == PHYTIUM_CPU_PART_FTC663) { + ret = true; + } else { + ret = false; + } + } else { + ret = false; + } + } else { + ret = false; + } + } + + return ret; +} + #define ARM_CPU_ID_MPIDR 3, 0, 0, 0, 5 int kvm_arch_init_vcpu(CPUState *cs) @@ -872,6 +1008,19 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } + /* + * we'll modify registers' value like ID_AA64ISAR0_EL1 + * before the virtual machine used for live-migration is started to ensure + * that the virtual machine is successfully migrated between different + * models of arm servers. + * Of course, the above will only happen if the CPU model "phytium-v" + * is selected during live migration. + */ + ret = modify_arm_vcpu_regs_for_phytium_v(cpu); + if (ret < 0) { + return ret; + } + if (cpu_isar_feature(aa64_sve, cpu)) { ret = kvm_arm_sve_set_vls(cs); if (ret) { diff --git a/util/aarch64-cpuid.c b/util/aarch64-cpuid.c new file mode 100644 index 0000000000000000000000000000000000000000..09067ac138c32b1e20c614f3cb866587d6db60ce --- /dev/null +++ b/util/aarch64-cpuid.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Dealing with arm cpu identification information. + * + * Copyright (C) 2024 Phytium, Inc. + * + * Authors: + * Peng Meng Guang + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 + * or later. See the COPYING.LIB file in the top-level directory. + */ + +#include +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/cutils.h" +#include "qemu/aarch64-cpuid.h" + +#if defined(__aarch64__) +uint64_t qemu_read_cpuid_id(void) +{ +#ifdef CONFIG_LINUX + const char *file = "/sys/devices/system/cpu/cpu0/regs/identification/midr_el1"; + char *buf; + uint64_t midr = 0; + +#define BUF_SIZE 32 + buf = g_malloc0(BUF_SIZE); + if (!buf) { + return 0; + } + + if (!g_file_get_contents(file, &buf, 0, NULL)) { + goto out; + } + + if (qemu_strtoul(buf, NULL, 0, &midr) < 0) { + goto out; + } + +out: + g_free(buf); + + return midr; +#else + return 0; +#endif +} + +uint8_t qemu_read_cpuid_implementor(void) +{ +#ifdef CONFIG_LINUX + uint64_t aarch64_midr = qemu_read_cpuid_id(); + + return MIDR_IMPLEMENTOR(aarch64_midr); +#else + return 0; +#endif +} + +uint16_t qemu_read_cpuid_part_number(void) +{ +#ifdef CONFIG_LINUX + uint64_t aarch64_midr = qemu_read_cpuid_id(); + + return MIDR_PARTNUM(aarch64_midr); +#else + return 0; +#endif +} + +bool is_phytium_cpu(void) +{ + return qemu_read_cpuid_implementor() == ARM_CPU_IMP_PHYTIUM; +} +#endif diff --git a/util/meson.build b/util/meson.build index b5f153b0e8cf7fc0a52894f84d853479eecd3170..26386b85032c43475ce69fedbeba25ce85dfe64d 100644 --- a/util/meson.build +++ b/util/meson.build @@ -49,6 +49,7 @@ util_ss.add(when: 'CONFIG_POSIX', if_true: files('drm.c')) util_ss.add(files('guest-random.c')) util_ss.add(files('yank.c')) util_ss.add(files('lockcnt.c')) +util_ss.add(files('aarch64-cpuid.c')) if have_user util_ss.add(files('selfmap.c'))