From 34bfe46732e7ddfcc68942f3d41366e147f5cd85 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 26 Apr 2023 15:00:01 -0300 Subject: [PATCH 01/34] target/arm: Move cortex sysregs into a separate file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The file cpu_tcg.c is about to be moved into the tcg/ directory, so move the register definitions into a new file. Also move the function declaration to the more appropriate cpregs.h. Reviewed-by: Richard Henderson Signed-off-by: Fabiano Rosas Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230426180013.14814-2-farosas@suse.de Signed-off-by: Peter Maydell --- target/arm/cortex-regs.c | 69 ++++++++++++++++++++++++++++++++++++++++ target/arm/cpregs.h | 6 ++++ target/arm/cpu64.c | 1 + target/arm/cpu_tcg.c | 59 ---------------------------------- target/arm/internals.h | 6 ---- target/arm/meson.build | 1 + 6 files changed, 77 insertions(+), 65 deletions(-) create mode 100644 target/arm/cortex-regs.c diff --git a/target/arm/cortex-regs.c b/target/arm/cortex-regs.c new file mode 100644 index 0000000000..17708480e7 --- /dev/null +++ b/target/arm/cortex-regs.c @@ -0,0 +1,69 @@ +/* + * ARM Cortex-A registers + * + * This code is licensed under the GNU GPL v2 or later. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "cpregs.h" + + +static uint64_t l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + ARMCPU *cpu = env_archcpu(env); + + /* Number of cores is in [25:24]; otherwise we RAZ */ + return (cpu->core_count - 1) << 24; +} + +static const ARMCPRegInfo cortex_a72_a57_a53_cp_reginfo[] = { + { .name = "L2CTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 2, + .access = PL1_RW, .readfn = l2ctlr_read, + .writefn = arm_cp_write_ignore }, + { .name = "L2CTLR", + .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 2, + .access = PL1_RW, .readfn = l2ctlr_read, + .writefn = arm_cp_write_ignore }, + { .name = "L2ECTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2ECTLR", + .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2ACTLR", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUACTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUACTLR", + .cp = 15, .opc1 = 0, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, + { .name = "CPUECTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 1, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUECTLR", + .cp = 15, .opc1 = 1, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, + { .name = "CPUMERRSR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 2, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUMERRSR", + .cp = 15, .opc1 = 2, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, + { .name = "L2MERRSR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2MERRSR", + .cp = 15, .opc1 = 3, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, +}; + +void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) +{ + define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); +} diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 1ee64e99de..b04d344a9f 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -1071,4 +1071,10 @@ static inline bool arm_cpreg_in_idspace(const ARMCPRegInfo *ri) ri->crn, ri->crm); } +#ifdef CONFIG_USER_ONLY +static inline void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) { } +#else +void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu); +#endif + #endif /* TARGET_ARM_CPREGS_H */ diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 735ca54163..76891c9288 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -30,6 +30,7 @@ #include "qapi/visitor.h" #include "hw/qdev-properties.h" #include "internals.h" +#include "cpregs.h" static void aarch64_a35_initfn(Object *obj) { diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index 1911d7ec47..15aa88e40f 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -93,65 +93,6 @@ void aa32_max_features(ARMCPU *cpu) cpu->isar.id_dfr0 = t; } -#ifndef CONFIG_USER_ONLY -static uint64_t l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - ARMCPU *cpu = env_archcpu(env); - - /* Number of cores is in [25:24]; otherwise we RAZ */ - return (cpu->core_count - 1) << 24; -} - -static const ARMCPRegInfo cortex_a72_a57_a53_cp_reginfo[] = { - { .name = "L2CTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 2, - .access = PL1_RW, .readfn = l2ctlr_read, - .writefn = arm_cp_write_ignore }, - { .name = "L2CTLR", - .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 2, - .access = PL1_RW, .readfn = l2ctlr_read, - .writefn = arm_cp_write_ignore }, - { .name = "L2ECTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "L2ECTLR", - .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "L2ACTLR", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUACTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUACTLR", - .cp = 15, .opc1 = 0, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "CPUECTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 1, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUECTLR", - .cp = 15, .opc1 = 1, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "CPUMERRSR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 2, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUMERRSR", - .cp = 15, .opc1 = 2, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "L2MERRSR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "L2MERRSR", - .cp = 15, .opc1 = 3, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, -}; - -void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) -{ - define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); -} -#endif /* !CONFIG_USER_ONLY */ - /* CPU models. These are not needed for the AArch64 linux-user build. */ #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) diff --git a/target/arm/internals.h b/target/arm/internals.h index c2c70d5918..b73c540e7e 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1376,12 +1376,6 @@ uint32_t arm_v7m_mrs_control(CPUARMState *env, uint32_t secure); uint32_t *arm_v7m_get_sp_ptr(CPUARMState *env, bool secure, bool threadmode, bool spsel); -#ifdef CONFIG_USER_ONLY -static inline void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) { } -#else -void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu); -#endif - bool el_is_in_host(CPUARMState *env, int el); void aa32_max_features(ARMCPU *cpu); diff --git a/target/arm/meson.build b/target/arm/meson.build index 6226098ad5..3469926295 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -21,6 +21,7 @@ arm_softmmu_ss.add(files( 'arch_dump.c', 'arm-powerctl.c', 'arm-qmp-cmds.c', + 'cortex-regs.c', 'machine.c', 'ptw.c', )) From 51e41b236266cc5233eb5296e1f1d126ae11adcd Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 26 Apr 2023 15:00:02 -0300 Subject: [PATCH 02/34] target/arm: Remove dead code from cpu_max_set_sve_max_vq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sve-max-vq property has been removed from the -cpu max used with KVM, so code under kvm_enabled in cpu_max_set_sve_max_vq is not reachable. Fixes: 0baa21be49 ("target/arm: Make KVM -cpu max exactly like -cpu host") Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Fabiano Rosas Message-id: 20230426180013.14814-3-farosas@suse.de Signed-off-by: Peter Maydell --- target/arm/cpu64.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 76891c9288..fb5e1b69db 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -336,12 +336,6 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name, return; } - if (kvm_enabled() && !kvm_arm_sve_supported()) { - error_setg(errp, "cannot set sve-max-vq"); - error_append_hint(errp, "SVE not supported by KVM on this host\n"); - return; - } - if (max_vq == 0 || max_vq > ARM_MAX_VQ) { error_setg(errp, "unsupported SVE vector length"); error_append_hint(errp, "Valid sve-max-vq in range [1-%d]\n", From 25be21059f7562b409bc2253fe2760621e2691bb Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 26 Apr 2023 15:00:03 -0300 Subject: [PATCH 03/34] target/arm: Extract TCG -cpu max code into a function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce aarch64_max_tcg_initfn that contains the TCG-only part of -cpu max configuration. We'll need that to be able to restrict this code to a TCG-only config in the next patches. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Fabiano Rosas Message-id: 20230426180013.14814-4-farosas@suse.de Signed-off-by: Peter Maydell --- target/arm/cpu64.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index fb5e1b69db..e9161522b8 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -1178,27 +1178,17 @@ static void aarch64_host_initfn(Object *obj) #endif } -/* -cpu max: if KVM is enabled, like -cpu host (best possible with this host); - * otherwise, a CPU with as many features enabled as our emulation supports. - * The version of '-cpu max' for qemu-system-arm is defined in cpu.c; +/* + * -cpu max: a CPU with as many features enabled as our emulation supports. + * The version of '-cpu max' for qemu-system-arm is defined in cpu_tcg.c; * this only needs to handle 64 bits. */ -static void aarch64_max_initfn(Object *obj) +static void aarch64_max_tcg_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); uint64_t t; uint32_t u; - if (kvm_enabled() || hvf_enabled()) { - /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */ - aarch64_host_initfn(obj); - return; - } - - /* '-cpu max' for TCG: we currently do this as "A57 with extra things" */ - - 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 @@ -1367,6 +1357,20 @@ static void aarch64_max_initfn(Object *obj) qdev_property_add_static(DEVICE(obj), &arm_cpu_lpa2_property); } +static void aarch64_max_initfn(Object *obj) +{ + if (kvm_enabled() || hvf_enabled()) { + /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */ + aarch64_host_initfn(obj); + return; + } + + /* '-cpu max' for TCG: we currently do this as "A57 with extra things" */ + + aarch64_a57_initfn(obj); + aarch64_max_tcg_initfn(obj); +} + static const ARMCPUInfo aarch64_cpus[] = { { .name = "cortex-a35", .initfn = aarch64_a35_initfn }, { .name = "cortex-a57", .initfn = aarch64_a57_initfn }, From fcab465e264e18ca74f0513b8f5b682c3362ed7f Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 26 Apr 2023 15:00:04 -0300 Subject: [PATCH 04/34] target/arm: Do not expose all -cpu max features to qtests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're about to move the TCG-only -cpu max configuration code under CONFIG_TCG. To be able to do that we need to make sure the qtests still have some cpu configured even when no other accelerator is available. Delineate now what is used with TCG-only and what is also used with qtests to make the subsequent patches cleaner. Signed-off-by: Fabiano Rosas Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230426180013.14814-5-farosas@suse.de Signed-off-by: Peter Maydell --- target/arm/cpu64.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index e9161522b8..6a6a2ece2b 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -25,6 +25,8 @@ #include "qemu/module.h" #include "sysemu/kvm.h" #include "sysemu/hvf.h" +#include "sysemu/qtest.h" +#include "sysemu/tcg.h" #include "kvm_arm.h" #include "hvf_arm.h" #include "qapi/visitor.h" @@ -1365,10 +1367,14 @@ static void aarch64_max_initfn(Object *obj) return; } - /* '-cpu max' for TCG: we currently do this as "A57 with extra things" */ + if (tcg_enabled() || qtest_enabled()) { + aarch64_a57_initfn(obj); + } - aarch64_a57_initfn(obj); - aarch64_max_tcg_initfn(obj); + /* '-cpu max' for TCG: we currently do this as "A57 with extra things" */ + if (tcg_enabled()) { + aarch64_max_tcg_initfn(obj); + } } static const ARMCPUInfo aarch64_cpus[] = { From 39920a04952b67fb1fce8fc3519ac18b7a95f3f3 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 26 Apr 2023 15:00:05 -0300 Subject: [PATCH 05/34] target/arm: Move 64-bit TCG CPUs into tcg/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the 64-bit CPUs that are TCG-only: - cortex-a35 - cortex-a55 - cortex-a72 - cortex-a76 - a64fx - neoverse-n1 Keep the CPUs that can be used with KVM: - cortex-a57 - cortex-a53 - max - host Signed-off-by: Fabiano Rosas Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230426180013.14814-6-farosas@suse.de Signed-off-by: Peter Maydell --- hw/arm/virt.c | 6 +- target/arm/cpu64.c | 687 +---------------------------------- target/arm/internals.h | 4 + target/arm/tcg/cpu64.c | 723 +++++++++++++++++++++++++++++++++++++ target/arm/tcg/meson.build | 1 + 5 files changed, 735 insertions(+), 686 deletions(-) create mode 100644 target/arm/tcg/cpu64.c diff --git a/hw/arm/virt.c b/hw/arm/virt.c index a89d699f0b..1450a9f363 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -208,14 +208,16 @@ static const char *valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-a7"), #endif ARM_CPU_TYPE_NAME("cortex-a15"), +#ifdef CONFIG_TCG ARM_CPU_TYPE_NAME("cortex-a35"), - ARM_CPU_TYPE_NAME("cortex-a53"), ARM_CPU_TYPE_NAME("cortex-a55"), - ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a72"), ARM_CPU_TYPE_NAME("cortex-a76"), ARM_CPU_TYPE_NAME("a64fx"), ARM_CPU_TYPE_NAME("neoverse-n1"), +#endif + ARM_CPU_TYPE_NAME("cortex-a53"), + ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("host"), ARM_CPU_TYPE_NAME("max"), }; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 6a6a2ece2b..6eaf8e32cf 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -34,86 +34,6 @@ #include "internals.h" #include "cpregs.h" -static void aarch64_a35_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,cortex-a35"; - set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); - set_feature(&cpu->env, ARM_FEATURE_AARCH64); - set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); - set_feature(&cpu->env, ARM_FEATURE_EL2); - set_feature(&cpu->env, ARM_FEATURE_EL3); - set_feature(&cpu->env, ARM_FEATURE_PMU); - - /* From B2.2 AArch64 identification registers. */ - cpu->midr = 0x411fd040; - cpu->revidr = 0; - cpu->ctr = 0x84448004; - cpu->isar.id_pfr0 = 0x00000131; - cpu->isar.id_pfr1 = 0x00011011; - cpu->isar.id_dfr0 = 0x03010066; - cpu->id_afr0 = 0; - cpu->isar.id_mmfr0 = 0x10201105; - cpu->isar.id_mmfr1 = 0x40000000; - cpu->isar.id_mmfr2 = 0x01260000; - cpu->isar.id_mmfr3 = 0x02102211; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232042; - cpu->isar.id_isar3 = 0x01112131; - cpu->isar.id_isar4 = 0x00011142; - cpu->isar.id_isar5 = 0x00011121; - cpu->isar.id_aa64pfr0 = 0x00002222; - cpu->isar.id_aa64pfr1 = 0; - cpu->isar.id_aa64dfr0 = 0x10305106; - cpu->isar.id_aa64dfr1 = 0; - cpu->isar.id_aa64isar0 = 0x00011120; - cpu->isar.id_aa64isar1 = 0; - cpu->isar.id_aa64mmfr0 = 0x00101122; - cpu->isar.id_aa64mmfr1 = 0; - cpu->clidr = 0x0a200023; - cpu->dcz_blocksize = 4; - - /* From B2.4 AArch64 Virtual Memory control registers */ - cpu->reset_sctlr = 0x00c50838; - - /* From B2.10 AArch64 performance monitor registers */ - cpu->isar.reset_pmcr_el0 = 0x410a3000; - - /* From B2.29 Cache ID registers */ - cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ - cpu->ccsidr[2] = 0x703fe03a; /* 512KB L2 cache */ - - /* From B3.5 VGIC Type register */ - cpu->gic_num_lrs = 4; - cpu->gic_vpribits = 5; - cpu->gic_vprebits = 5; - cpu->gic_pribits = 5; - - /* From C6.4 Debug ID Register */ - cpu->isar.dbgdidr = 0x3516d000; - /* From C6.5 Debug Device ID Register */ - cpu->isar.dbgdevid = 0x00110f13; - /* From C6.6 Debug Device ID Register 1 */ - cpu->isar.dbgdevid1 = 0x2; - - /* From Cortex-A35 SIMD and Floating-point Support r1p0 */ - /* From 3.2 AArch32 register summary */ - cpu->reset_fpsid = 0x41034043; - - /* From 2.2 AArch64 register summary */ - cpu->isar.mvfr0 = 0x10110222; - cpu->isar.mvfr1 = 0x12111111; - cpu->isar.mvfr2 = 0x00000043; - - /* These values are the same with A53/A57/A72. */ - define_cortex_a72_a57_a53_cp_reginfo(cpu); -} - void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { /* @@ -313,41 +233,6 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) cpu->sve_vq.map = vq_map; } -static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - ARMCPU *cpu = ARM_CPU(obj); - uint32_t value; - - /* All vector lengths are disabled when SVE is off. */ - if (!cpu_isar_feature(aa64_sve, cpu)) { - value = 0; - } else { - value = cpu->sve_max_vq; - } - visit_type_uint32(v, name, &value, errp); -} - -static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - ARMCPU *cpu = ARM_CPU(obj); - uint32_t max_vq; - - if (!visit_type_uint32(v, name, &max_vq, errp)) { - return; - } - - if (max_vq == 0 || max_vq > ARM_MAX_VQ) { - error_setg(errp, "unsupported SVE vector length"); - error_append_hint(errp, "Valid sve-max-vq in range [1-%d]\n", - ARM_MAX_VQ); - return; - } - - cpu->sve_max_vq = max_vq; -} - /* * Note that cpu_arm_{get,set}_vq cannot use the simpler * object_property_add_bool interface because they make use of the @@ -538,7 +423,7 @@ static void cpu_arm_get_default_vec_len(Object *obj, Visitor *v, } #endif -static void aarch64_add_sve_properties(Object *obj) +void aarch64_add_sve_properties(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); uint32_t vq; @@ -561,7 +446,7 @@ static void aarch64_add_sve_properties(Object *obj) #endif } -static void aarch64_add_sme_properties(Object *obj) +void aarch64_add_sme_properties(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); uint32_t vq; @@ -626,7 +511,7 @@ static Property arm_cpu_pauth_property = static Property arm_cpu_pauth_impdef_property = DEFINE_PROP_BOOL("pauth-impdef", ARMCPU, prop_pauth_impdef, false); -static void aarch64_add_pauth_properties(Object *obj) +void aarch64_add_pauth_properties(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -647,9 +532,6 @@ static void aarch64_add_pauth_properties(Object *obj) } } -static Property arm_cpu_lpa2_property = - DEFINE_PROP_BOOL("lpa2", ARMCPU, prop_lpa2, true); - void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp) { uint64_t t; @@ -784,384 +666,6 @@ static void aarch64_a53_initfn(Object *obj) define_cortex_a72_a57_a53_cp_reginfo(cpu); } -static void aarch64_a55_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,cortex-a55"; - set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); - set_feature(&cpu->env, ARM_FEATURE_AARCH64); - set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); - set_feature(&cpu->env, ARM_FEATURE_EL2); - set_feature(&cpu->env, ARM_FEATURE_EL3); - set_feature(&cpu->env, ARM_FEATURE_PMU); - - /* Ordered by B2.4 AArch64 registers by functional group */ - cpu->clidr = 0x82000023; - cpu->ctr = 0x84448004; /* L1Ip = VIPT */ - cpu->dcz_blocksize = 4; /* 64 bytes */ - cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; - cpu->isar.id_aa64isar0 = 0x0000100010211120ull; - cpu->isar.id_aa64isar1 = 0x0000000000100001ull; - cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; - cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; - cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; - cpu->isar.id_aa64pfr0 = 0x0000000010112222ull; - cpu->isar.id_aa64pfr1 = 0x0000000000000010ull; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_dfr0 = 0x04010088; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232042; - cpu->isar.id_isar3 = 0x01112131; - cpu->isar.id_isar4 = 0x00011142; - cpu->isar.id_isar5 = 0x01011121; - cpu->isar.id_isar6 = 0x00000010; - cpu->isar.id_mmfr0 = 0x10201105; - cpu->isar.id_mmfr1 = 0x40000000; - cpu->isar.id_mmfr2 = 0x01260000; - cpu->isar.id_mmfr3 = 0x02122211; - cpu->isar.id_mmfr4 = 0x00021110; - cpu->isar.id_pfr0 = 0x10010131; - cpu->isar.id_pfr1 = 0x00011011; - cpu->isar.id_pfr2 = 0x00000011; - cpu->midr = 0x412FD050; /* r2p0 */ - cpu->revidr = 0; - - /* From B2.23 CCSIDR_EL1 */ - cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ - cpu->ccsidr[1] = 0x200fe01a; /* 32KB L1 icache */ - cpu->ccsidr[2] = 0x703fe07a; /* 512KB L2 cache */ - - /* From B2.96 SCTLR_EL3 */ - cpu->reset_sctlr = 0x30c50838; - - /* From B4.45 ICH_VTR_EL2 */ - cpu->gic_num_lrs = 4; - cpu->gic_vpribits = 5; - cpu->gic_vprebits = 5; - cpu->gic_pribits = 5; - - cpu->isar.mvfr0 = 0x10110222; - cpu->isar.mvfr1 = 0x13211111; - cpu->isar.mvfr2 = 0x00000043; - - /* From D5.4 AArch64 PMU register summary */ - cpu->isar.reset_pmcr_el0 = 0x410b3000; -} - -static void aarch64_a72_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,cortex-a72"; - set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); - set_feature(&cpu->env, ARM_FEATURE_AARCH64); - set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); - set_feature(&cpu->env, ARM_FEATURE_EL2); - set_feature(&cpu->env, ARM_FEATURE_EL3); - set_feature(&cpu->env, ARM_FEATURE_PMU); - cpu->midr = 0x410fd083; - cpu->revidr = 0x00000000; - cpu->reset_fpsid = 0x41034080; - cpu->isar.mvfr0 = 0x10110222; - cpu->isar.mvfr1 = 0x12111111; - cpu->isar.mvfr2 = 0x00000043; - cpu->ctr = 0x8444c004; - cpu->reset_sctlr = 0x00c50838; - cpu->isar.id_pfr0 = 0x00000131; - cpu->isar.id_pfr1 = 0x00011011; - cpu->isar.id_dfr0 = 0x03010066; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_mmfr0 = 0x10201105; - cpu->isar.id_mmfr1 = 0x40000000; - cpu->isar.id_mmfr2 = 0x01260000; - cpu->isar.id_mmfr3 = 0x02102211; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232042; - cpu->isar.id_isar3 = 0x01112131; - cpu->isar.id_isar4 = 0x00011142; - cpu->isar.id_isar5 = 0x00011121; - cpu->isar.id_aa64pfr0 = 0x00002222; - cpu->isar.id_aa64dfr0 = 0x10305106; - cpu->isar.id_aa64isar0 = 0x00011120; - cpu->isar.id_aa64mmfr0 = 0x00001124; - cpu->isar.dbgdidr = 0x3516d000; - cpu->isar.dbgdevid = 0x01110f13; - cpu->isar.dbgdevid1 = 0x2; - cpu->isar.reset_pmcr_el0 = 0x41023000; - cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ - cpu->ccsidr[2] = 0x707fe07a; /* 1MB L2 cache */ - cpu->dcz_blocksize = 4; /* 64 bytes */ - cpu->gic_num_lrs = 4; - cpu->gic_vpribits = 5; - cpu->gic_vprebits = 5; - cpu->gic_pribits = 5; - define_cortex_a72_a57_a53_cp_reginfo(cpu); -} - -static void aarch64_a76_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,cortex-a76"; - set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); - set_feature(&cpu->env, ARM_FEATURE_AARCH64); - set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); - set_feature(&cpu->env, ARM_FEATURE_EL2); - set_feature(&cpu->env, ARM_FEATURE_EL3); - set_feature(&cpu->env, ARM_FEATURE_PMU); - - /* Ordered by B2.4 AArch64 registers by functional group */ - cpu->clidr = 0x82000023; - cpu->ctr = 0x8444C004; - cpu->dcz_blocksize = 4; - cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; - cpu->isar.id_aa64isar0 = 0x0000100010211120ull; - cpu->isar.id_aa64isar1 = 0x0000000000100001ull; - cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; - cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; - cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; - cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ - cpu->isar.id_aa64pfr1 = 0x0000000000000010ull; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_dfr0 = 0x04010088; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232042; - cpu->isar.id_isar3 = 0x01112131; - cpu->isar.id_isar4 = 0x00010142; - cpu->isar.id_isar5 = 0x01011121; - cpu->isar.id_isar6 = 0x00000010; - cpu->isar.id_mmfr0 = 0x10201105; - cpu->isar.id_mmfr1 = 0x40000000; - cpu->isar.id_mmfr2 = 0x01260000; - cpu->isar.id_mmfr3 = 0x02122211; - cpu->isar.id_mmfr4 = 0x00021110; - cpu->isar.id_pfr0 = 0x10010131; - cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ - cpu->isar.id_pfr2 = 0x00000011; - cpu->midr = 0x414fd0b1; /* r4p1 */ - cpu->revidr = 0; - - /* From B2.18 CCSIDR_EL1 */ - cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */ - cpu->ccsidr[2] = 0x707fe03a; /* 512KB L2 cache */ - - /* From B2.93 SCTLR_EL3 */ - cpu->reset_sctlr = 0x30c50838; - - /* From B4.23 ICH_VTR_EL2 */ - cpu->gic_num_lrs = 4; - cpu->gic_vpribits = 5; - cpu->gic_vprebits = 5; - cpu->gic_pribits = 5; - - /* From B5.1 AdvSIMD AArch64 register summary */ - cpu->isar.mvfr0 = 0x10110222; - cpu->isar.mvfr1 = 0x13211111; - cpu->isar.mvfr2 = 0x00000043; - - /* From D5.1 AArch64 PMU register summary */ - cpu->isar.reset_pmcr_el0 = 0x410b3000; -} - -static void aarch64_a64fx_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,a64fx"; - set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); - set_feature(&cpu->env, ARM_FEATURE_AARCH64); - set_feature(&cpu->env, ARM_FEATURE_EL2); - set_feature(&cpu->env, ARM_FEATURE_EL3); - set_feature(&cpu->env, ARM_FEATURE_PMU); - cpu->midr = 0x461f0010; - cpu->revidr = 0x00000000; - cpu->ctr = 0x86668006; - cpu->reset_sctlr = 0x30000180; - cpu->isar.id_aa64pfr0 = 0x0000000101111111; /* No RAS Extensions */ - cpu->isar.id_aa64pfr1 = 0x0000000000000000; - cpu->isar.id_aa64dfr0 = 0x0000000010305408; - cpu->isar.id_aa64dfr1 = 0x0000000000000000; - cpu->id_aa64afr0 = 0x0000000000000000; - cpu->id_aa64afr1 = 0x0000000000000000; - cpu->isar.id_aa64mmfr0 = 0x0000000000001122; - cpu->isar.id_aa64mmfr1 = 0x0000000011212100; - cpu->isar.id_aa64mmfr2 = 0x0000000000001011; - cpu->isar.id_aa64isar0 = 0x0000000010211120; - cpu->isar.id_aa64isar1 = 0x0000000000010001; - cpu->isar.id_aa64zfr0 = 0x0000000000000000; - cpu->clidr = 0x0000000080000023; - cpu->ccsidr[0] = 0x7007e01c; /* 64KB L1 dcache */ - cpu->ccsidr[1] = 0x2007e01c; /* 64KB L1 icache */ - cpu->ccsidr[2] = 0x70ffe07c; /* 8MB L2 cache */ - cpu->dcz_blocksize = 6; /* 256 bytes */ - cpu->gic_num_lrs = 4; - cpu->gic_vpribits = 5; - cpu->gic_vprebits = 5; - cpu->gic_pribits = 5; - - /* The A64FX supports only 128, 256 and 512 bit vector lengths */ - aarch64_add_sve_properties(obj); - cpu->sve_vq.supported = (1 << 0) /* 128bit */ - | (1 << 1) /* 256bit */ - | (1 << 3); /* 512bit */ - - cpu->isar.reset_pmcr_el0 = 0x46014040; - - /* TODO: Add A64FX specific HPC extension registers */ -} - -static const ARMCPRegInfo neoverse_n1_cp_reginfo[] = { - { .name = "ATCR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 7, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "ATCR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 15, .crm = 7, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "ATCR_EL3", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 6, .crn = 15, .crm = 7, .opc2 = 0, - .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "ATCR_EL12", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 5, .crn = 15, .crm = 7, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "AVTCR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 15, .crm = 7, .opc2 = 1, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUACTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 1, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUACTLR2_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 1, .opc2 = 1, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUACTLR3_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 1, .opc2 = 2, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - /* - * Report CPUCFR_EL1.SCU as 1, as we do not implement the DSU - * (and in particular its system registers). - */ - { .name = "CPUCFR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 0, .opc2 = 0, - .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 4 }, - { .name = "CPUECTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 1, .opc2 = 4, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0x961563010 }, - { .name = "CPUPCR_EL3", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 6, .crn = 15, .crm = 8, .opc2 = 1, - .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUPMR_EL3", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 6, .crn = 15, .crm = 8, .opc2 = 3, - .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUPOR_EL3", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 6, .crn = 15, .crm = 8, .opc2 = 2, - .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUPSELR_EL3", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 6, .crn = 15, .crm = 8, .opc2 = 0, - .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUPWRCTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 2, .opc2 = 7, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "ERXPFGCDN_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 2, .opc2 = 2, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "ERXPFGCTL_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 2, .opc2 = 1, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "ERXPFGF_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 2, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, -}; - -static void define_neoverse_n1_cp_reginfo(ARMCPU *cpu) -{ - define_arm_cp_regs(cpu, neoverse_n1_cp_reginfo); -} - -static void aarch64_neoverse_n1_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,neoverse-n1"; - set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); - set_feature(&cpu->env, ARM_FEATURE_AARCH64); - set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); - set_feature(&cpu->env, ARM_FEATURE_EL2); - set_feature(&cpu->env, ARM_FEATURE_EL3); - set_feature(&cpu->env, ARM_FEATURE_PMU); - - /* Ordered by B2.4 AArch64 registers by functional group */ - cpu->clidr = 0x82000023; - cpu->ctr = 0x8444c004; - cpu->dcz_blocksize = 4; - cpu->isar.id_aa64dfr0 = 0x0000000110305408ull; - cpu->isar.id_aa64isar0 = 0x0000100010211120ull; - cpu->isar.id_aa64isar1 = 0x0000000000100001ull; - cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; - cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; - cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; - cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ - cpu->isar.id_aa64pfr1 = 0x0000000000000020ull; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_dfr0 = 0x04010088; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232042; - cpu->isar.id_isar3 = 0x01112131; - cpu->isar.id_isar4 = 0x00010142; - cpu->isar.id_isar5 = 0x01011121; - cpu->isar.id_isar6 = 0x00000010; - cpu->isar.id_mmfr0 = 0x10201105; - cpu->isar.id_mmfr1 = 0x40000000; - cpu->isar.id_mmfr2 = 0x01260000; - cpu->isar.id_mmfr3 = 0x02122211; - cpu->isar.id_mmfr4 = 0x00021110; - cpu->isar.id_pfr0 = 0x10010131; - cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ - cpu->isar.id_pfr2 = 0x00000011; - cpu->midr = 0x414fd0c1; /* r4p1 */ - cpu->revidr = 0; - - /* From B2.23 CCSIDR_EL1 */ - cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */ - cpu->ccsidr[2] = 0x70ffe03a; /* 1MB L2 cache */ - - /* From B2.98 SCTLR_EL3 */ - cpu->reset_sctlr = 0x30c50838; - - /* From B4.23 ICH_VTR_EL2 */ - cpu->gic_num_lrs = 4; - cpu->gic_vpribits = 5; - cpu->gic_vprebits = 5; - cpu->gic_pribits = 5; - - /* From B5.1 AdvSIMD AArch64 register summary */ - cpu->isar.mvfr0 = 0x10110222; - cpu->isar.mvfr1 = 0x13211111; - cpu->isar.mvfr2 = 0x00000043; - - /* From D5.1 AArch64 PMU register summary */ - cpu->isar.reset_pmcr_el0 = 0x410c3000; - - define_neoverse_n1_cp_reginfo(cpu); -} - static void aarch64_host_initfn(Object *obj) { #if defined(CONFIG_KVM) @@ -1180,185 +684,6 @@ static void aarch64_host_initfn(Object *obj) #endif } -/* - * -cpu max: a CPU with as many features enabled as our emulation supports. - * The version of '-cpu max' for qemu-system-arm is defined in cpu_tcg.c; - * this only needs to handle 64 bits. - */ -static void aarch64_max_tcg_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - uint64_t t; - uint32_t u; - - /* - * 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, 0); - t = FIELD_DP64(t, MIDR_EL1, ARCHITECTURE, 0xf); - t = FIELD_DP64(t, MIDR_EL1, PARTNUM, 'Q'); - t = FIELD_DP64(t, MIDR_EL1, VARIANT, 0); - t = FIELD_DP64(t, MIDR_EL1, REVISION, 0); - cpu->midr = t; - - /* - * We're going to set FEAT_S2FWB, which mandates that CLIDR_EL1.{LoUU,LoUIS} - * are zero. - */ - u = cpu->clidr; - u = FIELD_DP32(u, CLIDR_EL1, LOUIS, 0); - u = FIELD_DP32(u, CLIDR_EL1, LOUU, 0); - cpu->clidr = u; - - t = cpu->isar.id_aa64isar0; - t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* FEAT_PMULL */ - t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); /* FEAT_SHA1 */ - t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* FEAT_SHA512 */ - t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); /* FEAT_LSE */ - t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); /* FEAT_RDM */ - t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); /* FEAT_SHA3 */ - t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); /* FEAT_SM3 */ - t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); /* FEAT_SM4 */ - t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); /* FEAT_DotProd */ - t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); /* FEAT_FHM */ - t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* FEAT_FlagM2 */ - t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2); /* FEAT_TLBIRANGE */ - t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); /* FEAT_RNG */ - cpu->isar.id_aa64isar0 = t; - - t = cpu->isar.id_aa64isar1; - t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); /* FEAT_DPB2 */ - t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); /* FEAT_JSCVT */ - t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); /* FEAT_FCMA */ - t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* FEAT_LRCPC2 */ - t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); /* FEAT_FRINTTS */ - t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); /* FEAT_SB */ - t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); /* FEAT_SPECRES */ - t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1); /* FEAT_BF16 */ - t = FIELD_DP64(t, ID_AA64ISAR1, DGH, 1); /* FEAT_DGH */ - t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); /* FEAT_I8MM */ - cpu->isar.id_aa64isar1 = t; - - t = cpu->isar.id_aa64pfr0; - t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* FEAT_FP16 */ - t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); /* FEAT_FP16 */ - t = FIELD_DP64(t, ID_AA64PFR0, RAS, 2); /* FEAT_RASv1p1 + FEAT_DoubleFault */ - t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); - t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */ - t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */ - t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 2); /* FEAT_CSV2_2 */ - t = FIELD_DP64(t, ID_AA64PFR0, CSV3, 1); /* FEAT_CSV3 */ - cpu->isar.id_aa64pfr0 = t; - - t = cpu->isar.id_aa64pfr1; - t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); /* FEAT_BTI */ - t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2); /* FEAT_SSBS2 */ - /* - * Begin with full support for MTE. This will be downgraded to MTE=0 - * during realize if the board provides no tag memory, much like - * we do for EL2 with the virtualization=on property. - */ - t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* FEAT_MTE3 */ - t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0); /* FEAT_RASv1p1 + FEAT_DoubleFault */ - t = FIELD_DP64(t, ID_AA64PFR1, SME, 1); /* FEAT_SME */ - t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */ - cpu->isar.id_aa64pfr1 = t; - - t = cpu->isar.id_aa64mmfr0; - t = FIELD_DP64(t, ID_AA64MMFR0, PARANGE, 6); /* FEAT_LPA: 52 bits */ - t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16, 1); /* 16k pages supported */ - t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16_2, 2); /* 16k stage2 supported */ - t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN64_2, 2); /* 64k stage2 supported */ - t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 2); /* 4k stage2 supported */ - t = FIELD_DP64(t, ID_AA64MMFR0, FGT, 1); /* FEAT_FGT */ - cpu->isar.id_aa64mmfr0 = t; - - t = cpu->isar.id_aa64mmfr1; - t = FIELD_DP64(t, ID_AA64MMFR1, HAFDBS, 2); /* FEAT_HAFDBS */ - t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* FEAT_VMID16 */ - t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); /* FEAT_VHE */ - t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* FEAT_HPDS */ - t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); /* FEAT_LOR */ - t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 3); /* FEAT_PAN3 */ - t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* FEAT_XNX */ - t = FIELD_DP64(t, ID_AA64MMFR1, ETS, 1); /* FEAT_ETS */ - t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1); /* FEAT_HCX */ - cpu->isar.id_aa64mmfr1 = t; - - t = cpu->isar.id_aa64mmfr2; - t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* FEAT_TTCNP */ - t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); /* FEAT_UAO */ - t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* FEAT_IESB */ - t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ - t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* FEAT_TTST */ - t = FIELD_DP64(t, ID_AA64MMFR2, IDS, 1); /* FEAT_IDST */ - t = FIELD_DP64(t, ID_AA64MMFR2, FWB, 1); /* FEAT_S2FWB */ - t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* FEAT_TTL */ - t = FIELD_DP64(t, ID_AA64MMFR2, BBM, 2); /* FEAT_BBM at level 2 */ - t = FIELD_DP64(t, ID_AA64MMFR2, EVT, 2); /* FEAT_EVT */ - t = FIELD_DP64(t, ID_AA64MMFR2, E0PD, 1); /* FEAT_E0PD */ - cpu->isar.id_aa64mmfr2 = t; - - t = cpu->isar.id_aa64zfr0; - t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* FEAT_SVE_PMULL128 */ - t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); /* FEAT_SVE_BitPerm */ - t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 1); /* FEAT_BF16 */ - t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); /* FEAT_SVE_SHA3 */ - t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); /* FEAT_SVE_SM4 */ - t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); /* FEAT_I8MM */ - t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); /* FEAT_F32MM */ - t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); /* FEAT_F64MM */ - cpu->isar.id_aa64zfr0 = t; - - t = cpu->isar.id_aa64dfr0; - t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 9); /* FEAT_Debugv8p4 */ - t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 6); /* FEAT_PMUv3p5 */ - cpu->isar.id_aa64dfr0 = t; - - t = cpu->isar.id_aa64smfr0; - t = FIELD_DP64(t, ID_AA64SMFR0, F32F32, 1); /* FEAT_SME */ - t = FIELD_DP64(t, ID_AA64SMFR0, B16F32, 1); /* FEAT_SME */ - t = FIELD_DP64(t, ID_AA64SMFR0, F16F32, 1); /* FEAT_SME */ - t = FIELD_DP64(t, ID_AA64SMFR0, I8I32, 0xf); /* FEAT_SME */ - t = FIELD_DP64(t, ID_AA64SMFR0, F64F64, 1); /* FEAT_SME_F64F64 */ - t = FIELD_DP64(t, ID_AA64SMFR0, I16I64, 0xf); /* FEAT_SME_I16I64 */ - t = FIELD_DP64(t, ID_AA64SMFR0, FA64, 1); /* FEAT_SME_FA64 */ - cpu->isar.id_aa64smfr0 = t; - - /* Replicate the same data to the 32-bit id registers. */ - aa32_max_features(cpu); - -#ifdef CONFIG_USER_ONLY - /* - * For usermode -cpu max we can use a larger and more efficient DCZ - * blocksize since we don't have to follow what the hardware does. - */ - cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */ - cpu->dcz_blocksize = 7; /* 512 bytes */ -#endif - - cpu->sve_vq.supported = MAKE_64BIT_MASK(0, ARM_MAX_VQ); - cpu->sme_vq.supported = SVE_VQ_POW2_MAP; - - aarch64_add_pauth_properties(obj); - aarch64_add_sve_properties(obj); - aarch64_add_sme_properties(obj); - object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq, - cpu_max_set_sve_max_vq, NULL, NULL); - qdev_property_add_static(DEVICE(obj), &arm_cpu_lpa2_property); -} - static void aarch64_max_initfn(Object *obj) { if (kvm_enabled() || hvf_enabled()) { @@ -1378,14 +703,8 @@ static void aarch64_max_initfn(Object *obj) } static const ARMCPUInfo aarch64_cpus[] = { - { .name = "cortex-a35", .initfn = aarch64_a35_initfn }, { .name = "cortex-a57", .initfn = aarch64_a57_initfn }, { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, - { .name = "cortex-a55", .initfn = aarch64_a55_initfn }, - { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, - { .name = "cortex-a76", .initfn = aarch64_a76_initfn }, - { .name = "a64fx", .initfn = aarch64_a64fx_initfn }, - { .name = "neoverse-n1", .initfn = aarch64_neoverse_n1_initfn }, { .name = "max", .initfn = aarch64_max_initfn }, #if defined(CONFIG_KVM) || defined(CONFIG_HVF) { .name = "host", .initfn = aarch64_host_initfn }, diff --git a/target/arm/internals.h b/target/arm/internals.h index b73c540e7e..0df8f3b8bc 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1361,6 +1361,10 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp); void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp); void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp); void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp); +void aarch64_max_tcg_initfn(Object *obj); +void aarch64_add_pauth_properties(Object *obj); +void aarch64_add_sve_properties(Object *obj); +void aarch64_add_sme_properties(Object *obj); #endif /* Read the CONTROL register as the MRS instruction would. */ diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c new file mode 100644 index 0000000000..646aa46ac9 --- /dev/null +++ b/target/arm/tcg/cpu64.c @@ -0,0 +1,723 @@ +/* + * QEMU AArch64 TCG CPUs + * + * Copyright (c) 2013 Linaro Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "cpu.h" +#include "qemu/module.h" +#include "qapi/visitor.h" +#include "hw/qdev-properties.h" +#include "internals.h" +#include "cpregs.h" + +static void aarch64_a35_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a35"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + + /* From B2.2 AArch64 identification registers. */ + cpu->midr = 0x411fd040; + cpu->revidr = 0; + cpu->ctr = 0x84448004; + cpu->isar.id_pfr0 = 0x00000131; + cpu->isar.id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02102211; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_aa64pfr0 = 0x00002222; + cpu->isar.id_aa64pfr1 = 0; + cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64dfr1 = 0; + cpu->isar.id_aa64isar0 = 0x00011120; + cpu->isar.id_aa64isar1 = 0; + cpu->isar.id_aa64mmfr0 = 0x00101122; + cpu->isar.id_aa64mmfr1 = 0; + cpu->clidr = 0x0a200023; + cpu->dcz_blocksize = 4; + + /* From B2.4 AArch64 Virtual Memory control registers */ + cpu->reset_sctlr = 0x00c50838; + + /* From B2.10 AArch64 performance monitor registers */ + cpu->isar.reset_pmcr_el0 = 0x410a3000; + + /* From B2.29 Cache ID registers */ + cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ + cpu->ccsidr[2] = 0x703fe03a; /* 512KB L2 cache */ + + /* From B3.5 VGIC Type register */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + + /* From C6.4 Debug ID Register */ + cpu->isar.dbgdidr = 0x3516d000; + /* From C6.5 Debug Device ID Register */ + cpu->isar.dbgdevid = 0x00110f13; + /* From C6.6 Debug Device ID Register 1 */ + cpu->isar.dbgdevid1 = 0x2; + + /* From Cortex-A35 SIMD and Floating-point Support r1p0 */ + /* From 3.2 AArch32 register summary */ + cpu->reset_fpsid = 0x41034043; + + /* From 2.2 AArch64 register summary */ + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x12111111; + cpu->isar.mvfr2 = 0x00000043; + + /* These values are the same with A53/A57/A72. */ + define_cortex_a72_a57_a53_cp_reginfo(cpu); +} + +static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + uint32_t value; + + /* All vector lengths are disabled when SVE is off. */ + if (!cpu_isar_feature(aa64_sve, cpu)) { + value = 0; + } else { + value = cpu->sve_max_vq; + } + visit_type_uint32(v, name, &value, errp); +} + +static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + uint32_t max_vq; + + if (!visit_type_uint32(v, name, &max_vq, errp)) { + return; + } + + if (max_vq == 0 || max_vq > ARM_MAX_VQ) { + error_setg(errp, "unsupported SVE vector length"); + error_append_hint(errp, "Valid sve-max-vq in range [1-%d]\n", + ARM_MAX_VQ); + return; + } + + cpu->sve_max_vq = max_vq; +} + +static Property arm_cpu_lpa2_property = + DEFINE_PROP_BOOL("lpa2", ARMCPU, prop_lpa2, true); + +static void aarch64_a55_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a55"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + + /* Ordered by B2.4 AArch64 registers by functional group */ + cpu->clidr = 0x82000023; + cpu->ctr = 0x84448004; /* L1Ip = VIPT */ + cpu->dcz_blocksize = 4; /* 64 bytes */ + cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; + cpu->isar.id_aa64isar0 = 0x0000100010211120ull; + cpu->isar.id_aa64isar1 = 0x0000000000100001ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; + cpu->isar.id_aa64pfr0 = 0x0000000010112222ull; + cpu->isar.id_aa64pfr1 = 0x0000000000000010ull; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x01011121; + cpu->isar.id_isar6 = 0x00000010; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x00021110; + cpu->isar.id_pfr0 = 0x10010131; + cpu->isar.id_pfr1 = 0x00011011; + cpu->isar.id_pfr2 = 0x00000011; + cpu->midr = 0x412FD050; /* r2p0 */ + cpu->revidr = 0; + + /* From B2.23 CCSIDR_EL1 */ + cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x200fe01a; /* 32KB L1 icache */ + cpu->ccsidr[2] = 0x703fe07a; /* 512KB L2 cache */ + + /* From B2.96 SCTLR_EL3 */ + cpu->reset_sctlr = 0x30c50838; + + /* From B4.45 ICH_VTR_EL2 */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; + + /* From D5.4 AArch64 PMU register summary */ + cpu->isar.reset_pmcr_el0 = 0x410b3000; +} + +static void aarch64_a72_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a72"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + cpu->midr = 0x410fd083; + cpu->revidr = 0x00000000; + cpu->reset_fpsid = 0x41034080; + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x12111111; + cpu->isar.mvfr2 = 0x00000043; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50838; + cpu->isar.id_pfr0 = 0x00000131; + cpu->isar.id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02102211; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_aa64pfr0 = 0x00002222; + cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64isar0 = 0x00011120; + cpu->isar.id_aa64mmfr0 = 0x00001124; + cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.dbgdevid = 0x01110f13; + cpu->isar.dbgdevid1 = 0x2; + cpu->isar.reset_pmcr_el0 = 0x41023000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ + cpu->ccsidr[2] = 0x707fe07a; /* 1MB L2 cache */ + cpu->dcz_blocksize = 4; /* 64 bytes */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + define_cortex_a72_a57_a53_cp_reginfo(cpu); +} + +static void aarch64_a76_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a76"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + + /* Ordered by B2.4 AArch64 registers by functional group */ + cpu->clidr = 0x82000023; + cpu->ctr = 0x8444C004; + cpu->dcz_blocksize = 4; + cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; + cpu->isar.id_aa64isar0 = 0x0000100010211120ull; + cpu->isar.id_aa64isar1 = 0x0000000000100001ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; + cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ + cpu->isar.id_aa64pfr1 = 0x0000000000000010ull; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00010142; + cpu->isar.id_isar5 = 0x01011121; + cpu->isar.id_isar6 = 0x00000010; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x00021110; + cpu->isar.id_pfr0 = 0x10010131; + cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ + cpu->isar.id_pfr2 = 0x00000011; + cpu->midr = 0x414fd0b1; /* r4p1 */ + cpu->revidr = 0; + + /* From B2.18 CCSIDR_EL1 */ + cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */ + cpu->ccsidr[2] = 0x707fe03a; /* 512KB L2 cache */ + + /* From B2.93 SCTLR_EL3 */ + cpu->reset_sctlr = 0x30c50838; + + /* From B4.23 ICH_VTR_EL2 */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + + /* From B5.1 AdvSIMD AArch64 register summary */ + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; + + /* From D5.1 AArch64 PMU register summary */ + cpu->isar.reset_pmcr_el0 = 0x410b3000; +} + +static void aarch64_a64fx_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,a64fx"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + cpu->midr = 0x461f0010; + cpu->revidr = 0x00000000; + cpu->ctr = 0x86668006; + cpu->reset_sctlr = 0x30000180; + cpu->isar.id_aa64pfr0 = 0x0000000101111111; /* No RAS Extensions */ + cpu->isar.id_aa64pfr1 = 0x0000000000000000; + cpu->isar.id_aa64dfr0 = 0x0000000010305408; + cpu->isar.id_aa64dfr1 = 0x0000000000000000; + cpu->id_aa64afr0 = 0x0000000000000000; + cpu->id_aa64afr1 = 0x0000000000000000; + cpu->isar.id_aa64mmfr0 = 0x0000000000001122; + cpu->isar.id_aa64mmfr1 = 0x0000000011212100; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011; + cpu->isar.id_aa64isar0 = 0x0000000010211120; + cpu->isar.id_aa64isar1 = 0x0000000000010001; + cpu->isar.id_aa64zfr0 = 0x0000000000000000; + cpu->clidr = 0x0000000080000023; + cpu->ccsidr[0] = 0x7007e01c; /* 64KB L1 dcache */ + cpu->ccsidr[1] = 0x2007e01c; /* 64KB L1 icache */ + cpu->ccsidr[2] = 0x70ffe07c; /* 8MB L2 cache */ + cpu->dcz_blocksize = 6; /* 256 bytes */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + + /* The A64FX supports only 128, 256 and 512 bit vector lengths */ + aarch64_add_sve_properties(obj); + cpu->sve_vq.supported = (1 << 0) /* 128bit */ + | (1 << 1) /* 256bit */ + | (1 << 3); /* 512bit */ + + cpu->isar.reset_pmcr_el0 = 0x46014040; + + /* TODO: Add A64FX specific HPC extension registers */ +} + +static const ARMCPRegInfo neoverse_n1_cp_reginfo[] = { + { .name = "ATCR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 7, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "ATCR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 15, .crm = 7, .opc2 = 0, + .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "ATCR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 15, .crm = 7, .opc2 = 0, + .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "ATCR_EL12", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 5, .crn = 15, .crm = 7, .opc2 = 0, + .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "AVTCR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 15, .crm = 7, .opc2 = 1, + .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUACTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 1, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUACTLR2_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 1, .opc2 = 1, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUACTLR3_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 1, .opc2 = 2, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + /* + * Report CPUCFR_EL1.SCU as 1, as we do not implement the DSU + * (and in particular its system registers). + */ + { .name = "CPUCFR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 0, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 4 }, + { .name = "CPUECTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 1, .opc2 = 4, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0x961563010 }, + { .name = "CPUPCR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 15, .crm = 8, .opc2 = 1, + .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUPMR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 15, .crm = 8, .opc2 = 3, + .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUPOR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 15, .crm = 8, .opc2 = 2, + .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUPSELR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 15, .crm = 8, .opc2 = 0, + .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUPWRCTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 2, .opc2 = 7, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "ERXPFGCDN_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 2, .opc2 = 2, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "ERXPFGCTL_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 2, .opc2 = 1, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "ERXPFGF_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 2, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, +}; + +static void define_neoverse_n1_cp_reginfo(ARMCPU *cpu) +{ + define_arm_cp_regs(cpu, neoverse_n1_cp_reginfo); +} + +static void aarch64_neoverse_n1_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,neoverse-n1"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + + /* Ordered by B2.4 AArch64 registers by functional group */ + cpu->clidr = 0x82000023; + cpu->ctr = 0x8444c004; + cpu->dcz_blocksize = 4; + cpu->isar.id_aa64dfr0 = 0x0000000110305408ull; + cpu->isar.id_aa64isar0 = 0x0000100010211120ull; + cpu->isar.id_aa64isar1 = 0x0000000000100001ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; + cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ + cpu->isar.id_aa64pfr1 = 0x0000000000000020ull; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00010142; + cpu->isar.id_isar5 = 0x01011121; + cpu->isar.id_isar6 = 0x00000010; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x00021110; + cpu->isar.id_pfr0 = 0x10010131; + cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ + cpu->isar.id_pfr2 = 0x00000011; + cpu->midr = 0x414fd0c1; /* r4p1 */ + cpu->revidr = 0; + + /* From B2.23 CCSIDR_EL1 */ + cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */ + cpu->ccsidr[2] = 0x70ffe03a; /* 1MB L2 cache */ + + /* From B2.98 SCTLR_EL3 */ + cpu->reset_sctlr = 0x30c50838; + + /* From B4.23 ICH_VTR_EL2 */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + + /* From B5.1 AdvSIMD AArch64 register summary */ + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; + + /* From D5.1 AArch64 PMU register summary */ + cpu->isar.reset_pmcr_el0 = 0x410c3000; + + define_neoverse_n1_cp_reginfo(cpu); +} + +/* + * -cpu max: a CPU with as many features enabled as our emulation supports. + * The version of '-cpu max' for qemu-system-arm is defined in cpu_tcg.c; + * this only needs to handle 64 bits. + */ +void aarch64_max_tcg_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + uint64_t t; + uint32_t u; + + /* + * 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, 0); + t = FIELD_DP64(t, MIDR_EL1, ARCHITECTURE, 0xf); + t = FIELD_DP64(t, MIDR_EL1, PARTNUM, 'Q'); + t = FIELD_DP64(t, MIDR_EL1, VARIANT, 0); + t = FIELD_DP64(t, MIDR_EL1, REVISION, 0); + cpu->midr = t; + + /* + * We're going to set FEAT_S2FWB, which mandates that CLIDR_EL1.{LoUU,LoUIS} + * are zero. + */ + u = cpu->clidr; + u = FIELD_DP32(u, CLIDR_EL1, LOUIS, 0); + u = FIELD_DP32(u, CLIDR_EL1, LOUU, 0); + cpu->clidr = u; + + t = cpu->isar.id_aa64isar0; + t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* FEAT_PMULL */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); /* FEAT_SHA1 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* FEAT_SHA512 */ + t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); /* FEAT_LSE */ + t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); /* FEAT_RDM */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); /* FEAT_SHA3 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); /* FEAT_SM3 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); /* FEAT_SM4 */ + t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); /* FEAT_DotProd */ + t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); /* FEAT_FHM */ + t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* FEAT_FlagM2 */ + t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2); /* FEAT_TLBIRANGE */ + t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); /* FEAT_RNG */ + cpu->isar.id_aa64isar0 = t; + + t = cpu->isar.id_aa64isar1; + t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); /* FEAT_DPB2 */ + t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); /* FEAT_JSCVT */ + t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); /* FEAT_FCMA */ + t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* FEAT_LRCPC2 */ + t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); /* FEAT_FRINTTS */ + t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); /* FEAT_SB */ + t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); /* FEAT_SPECRES */ + t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1); /* FEAT_BF16 */ + t = FIELD_DP64(t, ID_AA64ISAR1, DGH, 1); /* FEAT_DGH */ + t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); /* FEAT_I8MM */ + cpu->isar.id_aa64isar1 = t; + + t = cpu->isar.id_aa64pfr0; + t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* FEAT_FP16 */ + t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); /* FEAT_FP16 */ + t = FIELD_DP64(t, ID_AA64PFR0, RAS, 2); /* FEAT_RASv1p1 + FEAT_DoubleFault */ + t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); + t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */ + t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */ + t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 2); /* FEAT_CSV2_2 */ + t = FIELD_DP64(t, ID_AA64PFR0, CSV3, 1); /* FEAT_CSV3 */ + cpu->isar.id_aa64pfr0 = t; + + t = cpu->isar.id_aa64pfr1; + t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); /* FEAT_BTI */ + t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2); /* FEAT_SSBS2 */ + /* + * Begin with full support for MTE. This will be downgraded to MTE=0 + * during realize if the board provides no tag memory, much like + * we do for EL2 with the virtualization=on property. + */ + t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* FEAT_MTE3 */ + t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0); /* FEAT_RASv1p1 + FEAT_DoubleFault */ + t = FIELD_DP64(t, ID_AA64PFR1, SME, 1); /* FEAT_SME */ + t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */ + cpu->isar.id_aa64pfr1 = t; + + t = cpu->isar.id_aa64mmfr0; + t = FIELD_DP64(t, ID_AA64MMFR0, PARANGE, 6); /* FEAT_LPA: 52 bits */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16, 1); /* 16k pages supported */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16_2, 2); /* 16k stage2 supported */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN64_2, 2); /* 64k stage2 supported */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 2); /* 4k stage2 supported */ + t = FIELD_DP64(t, ID_AA64MMFR0, FGT, 1); /* FEAT_FGT */ + cpu->isar.id_aa64mmfr0 = t; + + t = cpu->isar.id_aa64mmfr1; + t = FIELD_DP64(t, ID_AA64MMFR1, HAFDBS, 2); /* FEAT_HAFDBS */ + t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* FEAT_VMID16 */ + t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); /* FEAT_VHE */ + t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* FEAT_HPDS */ + t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); /* FEAT_LOR */ + t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 3); /* FEAT_PAN3 */ + t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* FEAT_XNX */ + t = FIELD_DP64(t, ID_AA64MMFR1, ETS, 1); /* FEAT_ETS */ + t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1); /* FEAT_HCX */ + cpu->isar.id_aa64mmfr1 = t; + + t = cpu->isar.id_aa64mmfr2; + t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* FEAT_TTCNP */ + t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); /* FEAT_UAO */ + t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* FEAT_IESB */ + t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ + t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* FEAT_TTST */ + t = FIELD_DP64(t, ID_AA64MMFR2, IDS, 1); /* FEAT_IDST */ + t = FIELD_DP64(t, ID_AA64MMFR2, FWB, 1); /* FEAT_S2FWB */ + t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* FEAT_TTL */ + t = FIELD_DP64(t, ID_AA64MMFR2, BBM, 2); /* FEAT_BBM at level 2 */ + t = FIELD_DP64(t, ID_AA64MMFR2, EVT, 2); /* FEAT_EVT */ + t = FIELD_DP64(t, ID_AA64MMFR2, E0PD, 1); /* FEAT_E0PD */ + cpu->isar.id_aa64mmfr2 = t; + + t = cpu->isar.id_aa64zfr0; + t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* FEAT_SVE_PMULL128 */ + t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); /* FEAT_SVE_BitPerm */ + t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 1); /* FEAT_BF16 */ + t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); /* FEAT_SVE_SHA3 */ + t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); /* FEAT_SVE_SM4 */ + t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); /* FEAT_I8MM */ + t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); /* FEAT_F32MM */ + t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); /* FEAT_F64MM */ + cpu->isar.id_aa64zfr0 = t; + + t = cpu->isar.id_aa64dfr0; + t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 9); /* FEAT_Debugv8p4 */ + t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 6); /* FEAT_PMUv3p5 */ + cpu->isar.id_aa64dfr0 = t; + + t = cpu->isar.id_aa64smfr0; + t = FIELD_DP64(t, ID_AA64SMFR0, F32F32, 1); /* FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, B16F32, 1); /* FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, F16F32, 1); /* FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, I8I32, 0xf); /* FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, F64F64, 1); /* FEAT_SME_F64F64 */ + t = FIELD_DP64(t, ID_AA64SMFR0, I16I64, 0xf); /* FEAT_SME_I16I64 */ + t = FIELD_DP64(t, ID_AA64SMFR0, FA64, 1); /* FEAT_SME_FA64 */ + cpu->isar.id_aa64smfr0 = t; + + /* Replicate the same data to the 32-bit id registers. */ + aa32_max_features(cpu); + +#ifdef CONFIG_USER_ONLY + /* + * For usermode -cpu max we can use a larger and more efficient DCZ + * blocksize since we don't have to follow what the hardware does. + */ + cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */ + cpu->dcz_blocksize = 7; /* 512 bytes */ +#endif + + cpu->sve_vq.supported = MAKE_64BIT_MASK(0, ARM_MAX_VQ); + cpu->sme_vq.supported = SVE_VQ_POW2_MAP; + + aarch64_add_pauth_properties(obj); + aarch64_add_sve_properties(obj); + aarch64_add_sme_properties(obj); + object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq, + cpu_max_set_sve_max_vq, NULL, NULL); + qdev_property_add_static(DEVICE(obj), &arm_cpu_lpa2_property); +} + +static const ARMCPUInfo aarch64_cpus[] = { + { .name = "cortex-a35", .initfn = aarch64_a35_initfn }, + { .name = "cortex-a55", .initfn = aarch64_a55_initfn }, + { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, + { .name = "cortex-a76", .initfn = aarch64_a76_initfn }, + { .name = "a64fx", .initfn = aarch64_a64fx_initfn }, + { .name = "neoverse-n1", .initfn = aarch64_neoverse_n1_initfn }, +}; + +static void aarch64_cpu_register_types(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(aarch64_cpus); ++i) { + aarch64_cpu_register(&aarch64_cpus[i]); + } +} + +type_init(aarch64_cpu_register_types) diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index d27e76af6c..128f782816 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -35,6 +35,7 @@ arm_ss.add(files( )) arm_ss.add(when: 'TARGET_AARCH64', if_true: files( + 'cpu64.c', 'translate-a64.c', 'translate-sve.c', 'translate-sme.c', From 557ed03a281d845b0a73d56204e91b22982c7c95 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 26 Apr 2023 15:00:06 -0300 Subject: [PATCH 06/34] tests/qtest: Adjust and document query-cpu-model-expansion test for arm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're about to move the 32-bit CPUs under CONFIG_TCG, so adjust the query-cpu-model-expansion test to check against the cortex-a7, which is already under CONFIG_TCG. That allows the next patch to contain only code movement. (All the test cares about is that the CPU type it's checking is one which definitely doesn't work under KVM.) While here add comments clarifying what we're testing. Signed-off-by: Fabiano Rosas Acked-by: Thomas Huth Message-id: 20230426180013.14814-7-farosas@suse.de Suggested-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- tests/qtest/arm-cpu-features.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c index 1cb08138ad..3fc33fc24d 100644 --- a/tests/qtest/arm-cpu-features.c +++ b/tests/qtest/arm-cpu-features.c @@ -506,9 +506,23 @@ static void test_query_cpu_model_expansion_kvm(const void *data) QDict *resp; char *error; - assert_error(qts, "cortex-a15", - "We cannot guarantee the CPU type 'cortex-a15' works " - "with KVM on this host", NULL); + /* + * When using KVM, only the 'host' and 'max' CPU models are + * supported. Test that we're emitting a suitable error for + * unsupported CPU models. + */ + if (qtest_has_accel("tcg")) { + assert_error(qts, "cortex-a7", + "We cannot guarantee the CPU type 'cortex-a7' works " + "with KVM on this host", NULL); + } else { + /* + * With a KVM-only build the 32-bit CPUs are not present. + */ + assert_error(qts, "cortex-a7", + "The CPU type 'cortex-a7' is not a " + "recognized ARM CPU type", NULL); + } assert_has_feature_enabled(qts, "host", "aarch64"); From 20cf68efcec25b1d95cfe3659aded5314bd1b819 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Wed, 26 Apr 2023 15:00:07 -0300 Subject: [PATCH 07/34] target/arm: move cpu_tcg to tcg/cpu32.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit move the module containing cpu models definitions for 32bit TCG-only CPUs to tcg/ and rename it for clarity. Signed-off-by: Claudio Fontana Signed-off-by: Fabiano Rosas Reviewed-by: Richard Henderson Acked-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230426180013.14814-8-farosas@suse.de Signed-off-by: Peter Maydell --- hw/arm/virt.c | 2 -- target/arm/meson.build | 1 - target/arm/{cpu_tcg.c => tcg/cpu32.c} | 13 +++---------- target/arm/tcg/cpu64.c | 2 +- target/arm/tcg/meson.build | 1 + 5 files changed, 5 insertions(+), 14 deletions(-) rename target/arm/{cpu_tcg.c => tcg/cpu32.c} (99%) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 1450a9f363..b99ae18501 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -206,9 +206,7 @@ static const int a15irqmap[] = { static const char *valid_cpus[] = { #ifdef CONFIG_TCG ARM_CPU_TYPE_NAME("cortex-a7"), -#endif ARM_CPU_TYPE_NAME("cortex-a15"), -#ifdef CONFIG_TCG ARM_CPU_TYPE_NAME("cortex-a35"), ARM_CPU_TYPE_NAME("cortex-a55"), ARM_CPU_TYPE_NAME("cortex-a72"), diff --git a/target/arm/meson.build b/target/arm/meson.build index 3469926295..359a649eaf 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -5,7 +5,6 @@ arm_ss.add(files( 'gdbstub.c', 'helper.c', 'vfp_helper.c', - 'cpu_tcg.c', )) arm_ss.add(zlib) diff --git a/target/arm/cpu_tcg.c b/target/arm/tcg/cpu32.c similarity index 99% rename from target/arm/cpu_tcg.c rename to target/arm/tcg/cpu32.c index 15aa88e40f..47d2e8e781 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/tcg/cpu32.c @@ -1,5 +1,5 @@ /* - * QEMU ARM TCG CPUs. + * QEMU ARM TCG-only CPUs. * * Copyright (c) 2012 SUSE LINUX Products GmbH * @@ -10,9 +10,7 @@ #include "qemu/osdep.h" #include "cpu.h" -#ifdef CONFIG_TCG #include "hw/core/tcg-cpu-ops.h" -#endif /* CONFIG_TCG */ #include "internals.h" #include "target/arm/idau.h" #if !defined(CONFIG_USER_ONLY) @@ -96,7 +94,7 @@ void aa32_max_features(ARMCPU *cpu) /* CPU models. These are not needed for the AArch64 linux-user build. */ #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) -#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_TCG) +#if !defined(CONFIG_USER_ONLY) static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { CPUClass *cc = CPU_GET_CLASS(cs); @@ -120,7 +118,7 @@ static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request) } return ret; } -#endif /* !CONFIG_USER_ONLY && CONFIG_TCG */ +#endif /* !CONFIG_USER_ONLY */ static void arm926_initfn(Object *obj) { @@ -1014,7 +1012,6 @@ static void pxa270c5_initfn(Object *obj) cpu->reset_sctlr = 0x00000078; } -#ifdef CONFIG_TCG static const struct TCGCPUOps arm_v7m_tcg_ops = { .initialize = arm_translate_init, .synchronize_from_tb = arm_cpu_synchronize_from_tb, @@ -1035,7 +1032,6 @@ static const struct TCGCPUOps arm_v7m_tcg_ops = { .debug_check_breakpoint = arm_debug_check_breakpoint, #endif /* !CONFIG_USER_ONLY */ }; -#endif /* CONFIG_TCG */ static void arm_v7m_class_init(ObjectClass *oc, void *data) { @@ -1043,10 +1039,7 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); acc->info = data; -#ifdef CONFIG_TCG cc->tcg_ops = &arm_v7m_tcg_ops; -#endif /* CONFIG_TCG */ - cc->gdb_core_xml_file = "arm-m-profile.xml"; } diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index 646aa46ac9..886674a443 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -525,7 +525,7 @@ static void aarch64_neoverse_n1_initfn(Object *obj) /* * -cpu max: a CPU with as many features enabled as our emulation supports. - * The version of '-cpu max' for qemu-system-arm is defined in cpu_tcg.c; + * The version of '-cpu max' for qemu-system-arm is defined in cpu32.c; * this only needs to handle 64 bits. */ void aarch64_max_tcg_initfn(Object *obj) diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index 128f782816..4d99f6dacb 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -18,6 +18,7 @@ gen = [ arm_ss.add(gen) arm_ss.add(files( + 'cpu32.c', 'translate.c', 'translate-m-nocp.c', 'translate-mve.c', From 0c1ae3ff9dedd8a77bad5508413ccdcfc2493df6 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 26 Apr 2023 15:00:08 -0300 Subject: [PATCH 08/34] tests/qtest: Fix tests when no KVM or TCG are present MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible to have a build with both TCG and KVM disabled due to Xen requiring the i386 and x86_64 binaries to be present in an aarch64 host. If we build with --disable-tcg on the aarch64 host, we will end-up with a QEMU binary (x86) that does not support TCG nor KVM. Skip tests that crash or hang in the above scenario. Do not include any test cases if TCG and KVM are missing. Make sure that calls to qtest_has_accel are placed after g_test_init in similar fashion to commit ae4b01b349 ("tests: Ensure TAP version is printed before other messages") to avoid TAP parsing errors. Reviewed-by: Juan Quintela Reviewed-by: Thomas Huth Signed-off-by: Fabiano Rosas Reviewed-by: Michael S. Tsirkin Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230426180013.14814-9-farosas@suse.de Signed-off-by: Peter Maydell --- tests/qtest/bios-tables-test.c | 11 +++++++++-- tests/qtest/boot-serial-test.c | 5 +++++ tests/qtest/migration-test.c | 9 ++++++++- tests/qtest/pxe-test.c | 8 +++++++- tests/qtest/vmgenid-test.c | 9 +++++++-- 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 464f87382e..7fd88b0e9c 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -2045,8 +2045,7 @@ static void test_acpi_virt_oem_fields(void) int main(int argc, char *argv[]) { const char *arch = qtest_get_arch(); - const bool has_kvm = qtest_has_accel("kvm"); - const bool has_tcg = qtest_has_accel("tcg"); + bool has_kvm, has_tcg; char *v_env = getenv("V"); int ret; @@ -2056,6 +2055,14 @@ int main(int argc, char *argv[]) g_test_init(&argc, &argv, NULL); + has_kvm = qtest_has_accel("kvm"); + has_tcg = qtest_has_accel("tcg"); + + if (!has_tcg && !has_kvm) { + g_test_skip("No KVM or TCG accelerator available"); + return 0; + } + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { ret = boot_sector_init(disk); if (ret) { diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c index 3aef3a97a9..6dd06aeaf4 100644 --- a/tests/qtest/boot-serial-test.c +++ b/tests/qtest/boot-serial-test.c @@ -287,6 +287,11 @@ int main(int argc, char *argv[]) g_test_init(&argc, &argv, NULL); + if (!qtest_has_accel("tcg") && !qtest_has_accel("kvm")) { + g_test_skip("No KVM or TCG accelerator available"); + return 0; + } + for (i = 0; tests[i].arch != NULL; i++) { if (g_str_equal(arch, tests[i].arch) && qtest_has_machine(tests[i].machine)) { diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 60dd53d3ec..be73ec3c06 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -2477,7 +2477,7 @@ static bool kvm_dirty_ring_supported(void) int main(int argc, char **argv) { - bool has_kvm; + bool has_kvm, has_tcg; bool has_uffd; const char *arch; g_autoptr(GError) err = NULL; @@ -2486,6 +2486,13 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); has_kvm = qtest_has_accel("kvm"); + has_tcg = qtest_has_accel("tcg"); + + if (!has_tcg && !has_kvm) { + g_test_skip("No KVM or TCG accelerator available"); + return 0; + } + has_uffd = ufd_version_check(); arch = qtest_get_arch(); diff --git a/tests/qtest/pxe-test.c b/tests/qtest/pxe-test.c index 62b6eef464..e4b48225a5 100644 --- a/tests/qtest/pxe-test.c +++ b/tests/qtest/pxe-test.c @@ -131,11 +131,17 @@ int main(int argc, char *argv[]) int ret; const char *arch = qtest_get_arch(); + g_test_init(&argc, &argv, NULL); + + if (!qtest_has_accel("tcg") && !qtest_has_accel("kvm")) { + g_test_skip("No KVM or TCG accelerator available"); + return 0; + } + ret = boot_sector_init(disk); if(ret) return ret; - g_test_init(&argc, &argv, NULL); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { test_batch(x86_tests, false); diff --git a/tests/qtest/vmgenid-test.c b/tests/qtest/vmgenid-test.c index efba76e716..324db08c7a 100644 --- a/tests/qtest/vmgenid-test.c +++ b/tests/qtest/vmgenid-test.c @@ -165,13 +165,18 @@ int main(int argc, char **argv) { int ret; + g_test_init(&argc, &argv, NULL); + + if (!qtest_has_accel("tcg") && !qtest_has_accel("kvm")) { + g_test_skip("No KVM or TCG accelerator available"); + return 0; + } + ret = boot_sector_init(disk); if (ret) { return ret; } - g_test_init(&argc, &argv, NULL); - qtest_add_func("/vmgenid/vmgenid/set-guid", vmgenid_set_guid_test); qtest_add_func("/vmgenid/vmgenid/set-guid-auto", From 43dc139c71255953237520e19ba5ebd259d24aae Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 26 Apr 2023 15:00:09 -0300 Subject: [PATCH 09/34] tests/avocado: Pass parameters to migration test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The migration tests are currently broken for an aarch64 host because the tests pass no 'machine' and 'cpu' options on the QEMU command line. Add a separate class to each architecture so that we can specify 'machine' and 'cpu' options instead of relying on defaults. Add a skip decorator to keep the current behavior of only running migration tests when the qemu target matches the host architecture. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Fabiano Rosas Message-id: 20230426180013.14814-10-farosas@suse.de Signed-off-by: Peter Maydell --- tests/avocado/migration.py | 83 +++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 5 deletions(-) diff --git a/tests/avocado/migration.py b/tests/avocado/migration.py index 4b25680c50..8b2ec0e3c4 100644 --- a/tests/avocado/migration.py +++ b/tests/avocado/migration.py @@ -11,6 +11,8 @@ import tempfile +import os + from avocado_qemu import QemuSystemTest from avocado import skipUnless @@ -19,7 +21,7 @@ from avocado.utils import wait from avocado.utils.path import find_command -class Migration(QemuSystemTest): +class MigrationTest(QemuSystemTest): """ :avocado: tags=migration """ @@ -62,20 +64,91 @@ class Migration(QemuSystemTest): self.cancel('Failed to find a free port') return port - - def test_migration_with_tcp_localhost(self): + def migration_with_tcp_localhost(self): dest_uri = 'tcp:localhost:%u' % self._get_free_port() self.do_migrate(dest_uri) - def test_migration_with_unix(self): + def migration_with_unix(self): with tempfile.TemporaryDirectory(prefix='socket_') as socket_path: dest_uri = 'unix:%s/qemu-test.sock' % socket_path self.do_migrate(dest_uri) @skipUnless(find_command('nc', default=False), "'nc' command not found") - def test_migration_with_exec(self): + def migration_with_exec(self): """The test works for both netcat-traditional and netcat-openbsd packages.""" free_port = self._get_free_port() dest_uri = 'exec:nc -l localhost %u' % free_port src_uri = 'exec:nc localhost %u' % free_port self.do_migrate(dest_uri, src_uri) + + +@skipUnless('aarch64' in os.uname()[4], "host != target") +class Aarch64(MigrationTest): + """ + :avocado: tags=arch:aarch64 + :avocado: tags=machine:virt + :avocado: tags=cpu:max + """ + + def test_migration_with_tcp_localhost(self): + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.migration_with_unix() + + def test_migration_with_exec(self): + self.migration_with_exec() + + +@skipUnless('x86_64' in os.uname()[4], "host != target") +class X86_64(MigrationTest): + """ + :avocado: tags=arch:x86_64 + :avocado: tags=machine:pc + :avocado: tags=cpu:qemu64 + """ + + def test_migration_with_tcp_localhost(self): + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.migration_with_unix() + + def test_migration_with_exec(self): + self.migration_with_exec() + + +@skipUnless('ppc64le' in os.uname()[4], "host != target") +class PPC64(MigrationTest): + """ + :avocado: tags=arch:ppc64 + :avocado: tags=machine:pseries + :avocado: tags=cpu:power9_v2.0 + """ + + def test_migration_with_tcp_localhost(self): + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.migration_with_unix() + + def test_migration_with_exec(self): + self.migration_with_exec() + + +@skipUnless('s390x' in os.uname()[4], "host != target") +class S390X(MigrationTest): + """ + :avocado: tags=arch:s390x + :avocado: tags=machine:s390-ccw-virtio + :avocado: tags=cpu:qemu + """ + + def test_migration_with_tcp_localhost(self): + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.migration_with_unix() + + def test_migration_with_exec(self): + self.migration_with_exec() From 99f2f2ad9ee440b50fd33468f234d3287f8a2cfd Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 26 Apr 2023 15:00:10 -0300 Subject: [PATCH 10/34] arm/Kconfig: Always select SEMIHOSTING when TCG is present We are about to enable the build without TCG, so CONFIG_SEMIHOSTING and CONFIG_ARM_COMPATIBLE_SEMIHOSTING cannot be unconditionally set in default.mak anymore. So reflect the change in a Kconfig. Instead of using semihosting/Kconfig, use a target-specific file, so that the change doesn't affect other architectures which might implement semihosting in a way compatible with KVM. The selection from ARM_v7M needs to be removed to avoid a cycle during parsing. Signed-off-by: Fabiano Rosas Reviewed-by: Richard Henderson Message-id: 20230426180013.14814-11-farosas@suse.de Signed-off-by: Peter Maydell --- configs/devices/arm-softmmu/default.mak | 2 -- hw/arm/Kconfig | 1 - target/arm/Kconfig | 7 +++++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/configs/devices/arm-softmmu/default.mak b/configs/devices/arm-softmmu/default.mak index 1b49a7830c..cb3e5aea65 100644 --- a/configs/devices/arm-softmmu/default.mak +++ b/configs/devices/arm-softmmu/default.mak @@ -40,6 +40,4 @@ CONFIG_MICROBIT=y CONFIG_FSL_IMX25=y CONFIG_FSL_IMX7=y CONFIG_FSL_IMX6UL=y -CONFIG_SEMIHOSTING=y -CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y CONFIG_ALLWINNER_H3=y diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index b53bd7f0b2..87c1a29c91 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -317,7 +317,6 @@ config ARM_V7M # currently v7M must be included in a TCG build due to translate.c default y if TCG && (ARM || AARCH64) select PTIMER - select ARM_COMPATIBLE_SEMIHOSTING config ALLWINNER_A10 bool diff --git a/target/arm/Kconfig b/target/arm/Kconfig index 3f3394a22b..39f05b6420 100644 --- a/target/arm/Kconfig +++ b/target/arm/Kconfig @@ -4,3 +4,10 @@ config ARM config AARCH64 bool select ARM + +# This config exists just so we can make SEMIHOSTING default when TCG +# is selected without also changing it for other architectures. +config ARM_SEMIHOSTING + bool + default y if TCG && ARM + select ARM_COMPATIBLE_SEMIHOSTING From 29d9efca16080211f107b540f04d1ed3c12c63b0 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 26 Apr 2023 15:00:11 -0300 Subject: [PATCH 11/34] arm/Kconfig: Do not build TCG-only boards on a KVM-only build Move all the CONFIG_FOO=y from default.mak into "default y if TCG" statements in Kconfig. That way they won't be selected when CONFIG_TCG=n. I'm leaving CONFIG_ARM_VIRT in default.mak because it allows us to keep the two default.mak files not empty and keep aarch64-default.mak including arm-default.mak. That way we don't surprise anyone that's used to altering these files. With this change we can start building with --disable-tcg. Signed-off-by: Fabiano Rosas Reviewed-by: Richard Henderson Message-id: 20230426180013.14814-12-farosas@suse.de Signed-off-by: Peter Maydell --- configs/devices/aarch64-softmmu/default.mak | 4 -- configs/devices/arm-softmmu/default.mak | 37 ------------------ hw/arm/Kconfig | 42 ++++++++++++++++++++- 3 files changed, 41 insertions(+), 42 deletions(-) diff --git a/configs/devices/aarch64-softmmu/default.mak b/configs/devices/aarch64-softmmu/default.mak index cf43ac8da1..70e05a197d 100644 --- a/configs/devices/aarch64-softmmu/default.mak +++ b/configs/devices/aarch64-softmmu/default.mak @@ -2,7 +2,3 @@ # We support all the 32 bit boards so need all their config include ../arm-softmmu/default.mak - -CONFIG_XLNX_ZYNQMP_ARM=y -CONFIG_XLNX_VERSAL=y -CONFIG_SBSA_REF=y diff --git a/configs/devices/arm-softmmu/default.mak b/configs/devices/arm-softmmu/default.mak index cb3e5aea65..647fbce88d 100644 --- a/configs/devices/arm-softmmu/default.mak +++ b/configs/devices/arm-softmmu/default.mak @@ -4,40 +4,3 @@ # CONFIG_TEST_DEVICES=n CONFIG_ARM_VIRT=y -CONFIG_CUBIEBOARD=y -CONFIG_EXYNOS4=y -CONFIG_HIGHBANK=y -CONFIG_INTEGRATOR=y -CONFIG_FSL_IMX31=y -CONFIG_MUSICPAL=y -CONFIG_MUSCA=y -CONFIG_CHEETAH=y -CONFIG_SX1=y -CONFIG_NSERIES=y -CONFIG_STELLARIS=y -CONFIG_STM32VLDISCOVERY=y -CONFIG_REALVIEW=y -CONFIG_VERSATILE=y -CONFIG_VEXPRESS=y -CONFIG_ZYNQ=y -CONFIG_MAINSTONE=y -CONFIG_GUMSTIX=y -CONFIG_SPITZ=y -CONFIG_TOSA=y -CONFIG_Z2=y -CONFIG_NPCM7XX=y -CONFIG_COLLIE=y -CONFIG_ASPEED_SOC=y -CONFIG_NETDUINO2=y -CONFIG_NETDUINOPLUS2=y -CONFIG_OLIMEX_STM32_H405=y -CONFIG_MPS2=y -CONFIG_RASPI=y -CONFIG_DIGIC=y -CONFIG_SABRELITE=y -CONFIG_EMCRAFT_SF2=y -CONFIG_MICROBIT=y -CONFIG_FSL_IMX25=y -CONFIG_FSL_IMX7=y -CONFIG_FSL_IMX6UL=y -CONFIG_ALLWINNER_H3=y diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 87c1a29c91..2d7c457955 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -35,20 +35,24 @@ config ARM_VIRT config CHEETAH bool + default y if TCG && ARM select OMAP select TSC210X config CUBIEBOARD bool + default y if TCG && ARM select ALLWINNER_A10 config DIGIC bool + default y if TCG && ARM select PTIMER select PFLASH_CFI02 config EXYNOS4 bool + default y if TCG && ARM imply I2C_DEVICES select A9MPCORE select I2C @@ -61,6 +65,7 @@ config EXYNOS4 config HIGHBANK bool + default y if TCG && ARM select A9MPCORE select A15MPCORE select AHCI @@ -75,6 +80,7 @@ config HIGHBANK config INTEGRATOR bool + default y if TCG && ARM select ARM_TIMER select INTEGRATOR_DEBUG select PL011 # UART @@ -87,12 +93,14 @@ config INTEGRATOR config MAINSTONE bool + default y if TCG && ARM select PXA2XX select PFLASH_CFI01 select SMC91C111 config MUSCA bool + default y if TCG && ARM select ARMSSE select PL011 select PL031 @@ -104,6 +112,7 @@ config MARVELL_88W8618 config MUSICPAL bool + default y if TCG && ARM select OR_IRQ select BITBANG_I2C select MARVELL_88W8618 @@ -114,18 +123,22 @@ config MUSICPAL config NETDUINO2 bool + default y if TCG && ARM select STM32F205_SOC config NETDUINOPLUS2 bool + default y if TCG && ARM select STM32F405_SOC config OLIMEX_STM32_H405 bool + default y if TCG && ARM select STM32F405_SOC config NSERIES bool + default y if TCG && ARM select OMAP select TMP105 # temperature sensor select BLIZZARD # LCD/TV controller @@ -158,12 +171,14 @@ config PXA2XX config GUMSTIX bool + default y if TCG && ARM select PFLASH_CFI01 select SMC91C111 select PXA2XX config TOSA bool + default y if TCG && ARM select ZAURUS # scoop select MICRODRIVE select PXA2XX @@ -171,6 +186,7 @@ config TOSA config SPITZ bool + default y if TCG && ARM select ADS7846 # touch-screen controller select MAX111X # A/D converter select WM8750 # audio codec @@ -183,6 +199,7 @@ config SPITZ config Z2 bool + default y if TCG && ARM select PFLASH_CFI01 select WM8750 select PL011 # UART @@ -190,6 +207,7 @@ config Z2 config REALVIEW bool + default y if TCG && ARM imply PCI_DEVICES imply PCI_TESTDEV imply I2C_DEVICES @@ -218,6 +236,7 @@ config REALVIEW config SBSA_REF bool + default y if TCG && AARCH64 imply PCI_DEVICES select AHCI select ARM_SMMUV3 @@ -233,11 +252,13 @@ config SBSA_REF config SABRELITE bool + default y if TCG && ARM select FSL_IMX6 select SSI_M25P80 config STELLARIS bool + default y if TCG && ARM imply I2C_DEVICES select ARM_V7M select CMSDK_APB_WATCHDOG @@ -255,6 +276,7 @@ config STELLARIS config STM32VLDISCOVERY bool + default y if TCG && ARM select STM32F100_SOC config STRONGARM @@ -263,16 +285,19 @@ config STRONGARM config COLLIE bool + default y if TCG && ARM select PFLASH_CFI01 select ZAURUS # scoop select STRONGARM config SX1 bool + default y if TCG && ARM select OMAP config VERSATILE bool + default y if TCG && ARM select ARM_TIMER # sp804 select PFLASH_CFI01 select LSI_SCSI_PCI @@ -284,6 +309,7 @@ config VERSATILE config VEXPRESS bool + default y if TCG && ARM select A9MPCORE select A15MPCORE select ARM_MPTIMER @@ -299,6 +325,7 @@ config VEXPRESS config ZYNQ bool + default y if TCG && ARM select A9MPCORE select CADENCE # UART select PFLASH_CFI02 @@ -315,7 +342,7 @@ config ZYNQ config ARM_V7M bool # currently v7M must be included in a TCG build due to translate.c - default y if TCG && (ARM || AARCH64) + default y if TCG && ARM select PTIMER config ALLWINNER_A10 @@ -334,6 +361,7 @@ config ALLWINNER_A10 config ALLWINNER_H3 bool + default y if TCG && ARM select ALLWINNER_A10_PIT select ALLWINNER_SUN8I_EMAC select ALLWINNER_I2C @@ -348,6 +376,7 @@ config ALLWINNER_H3 config RASPI bool + default y if TCG && ARM select FRAMEBUFFER select PL011 # UART select SDHCI @@ -378,6 +407,7 @@ config STM32F405_SOC config XLNX_ZYNQMP_ARM bool + default y if TCG && AARCH64 select AHCI select ARM_GIC select CADENCE @@ -395,6 +425,7 @@ config XLNX_ZYNQMP_ARM config XLNX_VERSAL bool + default y if TCG && AARCH64 select ARM_GIC select PL011 select CADENCE @@ -408,6 +439,7 @@ config XLNX_VERSAL config NPCM7XX bool + default y if TCG && ARM select A9MPCORE select ADM1272 select ARM_GIC @@ -424,6 +456,7 @@ config NPCM7XX config FSL_IMX25 bool + default y if TCG && ARM imply I2C_DEVICES select IMX select IMX_FEC @@ -433,6 +466,7 @@ config FSL_IMX25 config FSL_IMX31 bool + default y if TCG && ARM imply I2C_DEVICES select SERIAL select IMX @@ -453,6 +487,7 @@ config FSL_IMX6 config ASPEED_SOC bool + default y if TCG && ARM select DS1338 select FTGMAC100 select I2C @@ -473,6 +508,7 @@ config ASPEED_SOC config MPS2 bool + default y if TCG && ARM imply I2C_DEVICES select ARMSSE select LAN9118 @@ -488,6 +524,7 @@ config MPS2 config FSL_IMX7 bool + default y if TCG && ARM imply PCI_DEVICES imply TEST_DEVICES imply I2C_DEVICES @@ -506,6 +543,7 @@ config ARM_SMMUV3 config FSL_IMX6UL bool + default y if TCG && ARM imply I2C_DEVICES select A15MPCORE select IMX @@ -517,6 +555,7 @@ config FSL_IMX6UL config MICROBIT bool + default y if TCG && ARM select NRF51_SOC config NRF51_SOC @@ -528,6 +567,7 @@ config NRF51_SOC config EMCRAFT_SF2 bool + default y if TCG && ARM select MSF2 select SSI_M25P80 From aecca1773fa504d90813b6f5e984f64b4b0f6493 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 26 Apr 2023 15:00:12 -0300 Subject: [PATCH 12/34] tests/qtest: Restrict tpm-tis-i2c-test to CONFIG_TCG The test set -accel tcg, so restrict it to when TCG is present. Signed-off-by: Fabiano Rosas Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Message-id: 20230426180013.14814-13-farosas@suse.de Signed-off-by: Peter Maydell --- tests/qtest/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index cfc66ade6f..48cd35b5b2 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -213,7 +213,8 @@ qtests_aarch64 = \ ['tpm-tis-device-test', 'tpm-tis-device-swtpm-test'] : []) + \ (config_all_devices.has_key('CONFIG_XLNX_ZYNQMP_ARM') ? ['xlnx-can-test', 'fuzz-xlnx-dp-test'] : []) + \ (config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test'] : []) + \ - (config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \ + (config_all.has_key('CONFIG_TCG') and \ + config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \ ['arm-cpu-features', 'numa-test', 'boot-serial-test', From 471896381ae895b1c4c2afe1eff2ce13d85e6c2c Mon Sep 17 00:00:00 2001 From: Patrick Venture Date: Mon, 3 Oct 2022 10:38:10 -0700 Subject: [PATCH 13/34] hw/net: npcm7xx_emc: set MAC in register space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MAC address set from Qemu wasn't being saved into the register space. Reviewed-by: Hao Wu Signed-off-by: Patrick Venture Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell [PMM: moved variable declaration to top of function] Signed-off-by: Peter Maydell --- hw/net/npcm7xx_emc.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/hw/net/npcm7xx_emc.c b/hw/net/npcm7xx_emc.c index 7c86bb52e5..8156f701b0 100644 --- a/hw/net/npcm7xx_emc.c +++ b/hw/net/npcm7xx_emc.c @@ -98,6 +98,8 @@ static const char *emc_reg_name(int regno) static void emc_reset(NPCM7xxEMCState *emc) { + uint32_t value; + trace_npcm7xx_emc_reset(emc->emc_num); memset(&emc->regs[0], 0, sizeof(emc->regs)); @@ -112,6 +114,16 @@ static void emc_reset(NPCM7xxEMCState *emc) emc->tx_active = false; emc->rx_active = false; + + /* Set the MAC address in the register space. */ + value = (emc->conf.macaddr.a[0] << 24) | + (emc->conf.macaddr.a[1] << 16) | + (emc->conf.macaddr.a[2] << 8) | + emc->conf.macaddr.a[3]; + emc->regs[REG_CAMM_BASE] = value; + + value = (emc->conf.macaddr.a[4] << 24) | (emc->conf.macaddr.a[5] << 16); + emc->regs[REG_CAML_BASE] = value; } static void npcm7xx_emc_reset(DeviceState *dev) @@ -432,13 +444,25 @@ static bool emc_receive_filter1(NPCM7xxEMCState *emc, const uint8_t *buf, } case ETH_PKT_UCAST: { bool matches; + uint32_t value; + struct MACAddr mac; if (emc->regs[REG_CAMCMR] & REG_CAMCMR_AUP) { return true; } + + value = emc->regs[REG_CAMM_BASE]; + mac.a[0] = value >> 24; + mac.a[1] = value >> 16; + mac.a[2] = value >> 8; + mac.a[3] = value >> 0; + value = emc->regs[REG_CAML_BASE]; + mac.a[4] = value >> 24; + mac.a[5] = value >> 16; + matches = ((emc->regs[REG_CAMCMR] & REG_CAMCMR_ECMP) && /* We only support one CAM register, CAM0. */ (emc->regs[REG_CAMEN] & (1 << 0)) && - memcmp(buf, emc->conf.macaddr.a, ETH_ALEN) == 0); + memcmp(buf, mac.a, ETH_ALEN) == 0); if (emc->regs[REG_CAMCMR] & REG_CAMCMR_CCAM) { *fail_reason = "MACADDR matched, comparison complemented"; return !matches; @@ -661,15 +685,9 @@ static void npcm7xx_emc_write(void *opaque, hwaddr offset, break; case REG_CAMM_BASE + 0: emc->regs[reg] = value; - emc->conf.macaddr.a[0] = value >> 24; - emc->conf.macaddr.a[1] = value >> 16; - emc->conf.macaddr.a[2] = value >> 8; - emc->conf.macaddr.a[3] = value >> 0; break; case REG_CAML_BASE + 0: emc->regs[reg] = value; - emc->conf.macaddr.a[4] = value >> 24; - emc->conf.macaddr.a[5] = value >> 16; break; case REG_MCMDR: { uint32_t prev; From f802ff1e281eac50f2b4b177b180be97e80da21f Mon Sep 17 00:00:00 2001 From: Daniel Bertalan Date: Tue, 25 Apr 2023 10:34:31 +0000 Subject: [PATCH 14/34] hw/arm/bcm2835_property: Implement "get command line" message This query copies the kernel command line into the message buffer. It was previously stubbed out to return empty, this commit makes it reflect the arguments specified with `-append`. I observed the following peculiarities on my Pi 3B+: - If the buffer is shorter than the string, the response header gives the full length, but no data is actually copied. - No NUL terminator is added: even if the buffer is long enough to fit one, the buffer's original contents are preserved past the string's end. - The VC firmware adds the following extra parameters beside the user-supplied ones (via /boot/cmdline.txt): `video`, `vc_mem.mem_base` and `vc_mem.mem_size`. This is currently not implemented in qemu. Signed-off-by: Daniel Bertalan Message-id: 20230425103250.56653-1-dani@danielbertalan.dev Reviewed-by: Peter Maydell [PMM: added comment about NUL and short-buffer behaviour] Signed-off-by: Peter Maydell --- hw/arm/bcm2835_peripherals.c | 2 ++ hw/arm/bcm2836.c | 2 ++ hw/arm/raspi.c | 2 ++ hw/misc/bcm2835_property.c | 13 ++++++++++++- include/hw/misc/bcm2835_property.h | 1 + 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 3c2a4160cd..0233038b95 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -90,6 +90,8 @@ static void bcm2835_peripherals_init(Object *obj) TYPE_BCM2835_PROPERTY); object_property_add_alias(obj, "board-rev", OBJECT(&s->property), "board-rev"); + object_property_add_alias(obj, "command-line", OBJECT(&s->property), + "command-line"); object_property_add_const_link(OBJECT(&s->property), "fb", OBJECT(&s->fb)); diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index f894338fc6..166dc896c0 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -55,6 +55,8 @@ static void bcm2836_init(Object *obj) TYPE_BCM2835_PERIPHERALS); object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals), "board-rev"); + object_property_add_alias(obj, "command-line", OBJECT(&s->peripherals), + "command-line"); object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals), "vcram-size"); } diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index 92d068d1f9..7b9221c924 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -280,6 +280,8 @@ static void raspi_machine_init(MachineState *machine) object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(machine->ram)); object_property_set_int(OBJECT(&s->soc), "board-rev", board_rev, &error_abort); + object_property_set_str(OBJECT(&s->soc), "command-line", + machine->kernel_cmdline, &error_abort); qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); /* Create and plug in the SD cards */ diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c index de056ea2df..251b3d865d 100644 --- a/hw/misc/bcm2835_property.c +++ b/hw/misc/bcm2835_property.c @@ -282,7 +282,17 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) break; case 0x00050001: /* Get command line */ - resplen = 0; + /* + * We follow the firmware behaviour: no NUL terminator is + * written to the buffer, and if the buffer is too short + * we report the required length in the response header + * and copy nothing to the buffer. + */ + resplen = strlen(s->command_line); + if (bufsize >= resplen) + address_space_write(&s->dma_as, value + 12, + MEMTXATTRS_UNSPECIFIED, s->command_line, + resplen); break; default: @@ -420,6 +430,7 @@ static void bcm2835_property_realize(DeviceState *dev, Error **errp) static Property bcm2835_property_props[] = { DEFINE_PROP_UINT32("board-rev", BCM2835PropertyState, board_rev, 0), + DEFINE_PROP_STRING("command-line", BCM2835PropertyState, command_line), DEFINE_PROP_END_OF_LIST() }; diff --git a/include/hw/misc/bcm2835_property.h b/include/hw/misc/bcm2835_property.h index 712b76b7a3..ba8896610c 100644 --- a/include/hw/misc/bcm2835_property.h +++ b/include/hw/misc/bcm2835_property.h @@ -30,6 +30,7 @@ struct BCM2835PropertyState { MACAddr macaddr; uint32_t board_rev; uint32_t addr; + char *command_line; bool pending; }; From 3cfb0456c352288d5104a89cceb25f7dcda5d4c0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Apr 2023 17:40:32 +0100 Subject: [PATCH 15/34] make one-insn-per-tb an accel option This commit adds 'one-insn-per-tb' as a property on the TCG accelerator object, so you can enable it with -accel tcg,one-insn-per-tb=on It has the same behaviour as the existing '-singlestep' command line option. We use a different name because 'singlestep' has always been a confusing choice, because it doesn't have anything to do with single-stepping the CPU. What it does do is force TCG emulation to put one guest instruction in each TB, which can be useful in some situations (such as analysing debug logs). The existing '-singlestep' commandline options are decoupled from the global 'singlestep' variable and instead now are syntactic sugar for setting the accel property. (These can then go away after a deprecation period.) The global variable remains for the moment as: * what the TCG code looks at to change its behaviour * what HMP and QMP use to query and set the behaviour In the following commits we'll clean those up to not directly look at the global variable. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20230417164041.684562-2-peter.maydell@linaro.org --- accel/tcg/tcg-all.c | 21 +++++++++++++++++++++ bsd-user/main.c | 8 ++++++-- linux-user/main.c | 8 ++++++-- qemu-options.hx | 7 +++++++ softmmu/vl.c | 17 +++++++++++++++-- 5 files changed, 55 insertions(+), 6 deletions(-) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 5dab1ae9dd..fcf361c8db 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -42,6 +42,7 @@ struct TCGState { AccelState parent_obj; bool mttcg_enabled; + bool one_insn_per_tb; int splitwx_enabled; unsigned long tb_size; }; @@ -208,6 +209,20 @@ static void tcg_set_splitwx(Object *obj, bool value, Error **errp) s->splitwx_enabled = value; } +static bool tcg_get_one_insn_per_tb(Object *obj, Error **errp) +{ + TCGState *s = TCG_STATE(obj); + return s->one_insn_per_tb; +} + +static void tcg_set_one_insn_per_tb(Object *obj, bool value, Error **errp) +{ + TCGState *s = TCG_STATE(obj); + s->one_insn_per_tb = value; + /* For the moment, set the global also: this changes the behaviour */ + singlestep = value; +} + static int tcg_gdbstub_supported_sstep_flags(void) { /* @@ -245,6 +260,12 @@ static void tcg_accel_class_init(ObjectClass *oc, void *data) tcg_get_splitwx, tcg_set_splitwx); object_class_property_set_description(oc, "split-wx", "Map jit pages into separate RW and RX regions"); + + object_class_property_add_bool(oc, "one-insn-per-tb", + tcg_get_one_insn_per_tb, + tcg_set_one_insn_per_tb); + object_class_property_set_description(oc, "one-insn-per-tb", + "Only put one guest insn in each translation block"); } static const TypeInfo tcg_accel_type = { diff --git a/bsd-user/main.c b/bsd-user/main.c index babc3b009b..09b84da190 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -50,6 +50,7 @@ #include "target_arch_cpu.h" int singlestep; +static bool opt_one_insn_per_tb; uintptr_t guest_base; bool have_guest_base; /* @@ -386,7 +387,7 @@ int main(int argc, char **argv) } else if (!strcmp(r, "seed")) { seed_optarg = optarg; } else if (!strcmp(r, "singlestep")) { - singlestep = 1; + opt_one_insn_per_tb = true; } else if (!strcmp(r, "strace")) { do_strace = 1; } else if (!strcmp(r, "trace")) { @@ -444,9 +445,12 @@ int main(int argc, char **argv) /* init tcg before creating CPUs and to get qemu_host_page_size */ { - AccelClass *ac = ACCEL_GET_CLASS(current_accel()); + AccelState *accel = current_accel(); + AccelClass *ac = ACCEL_GET_CLASS(accel); accel_init_interfaces(ac); + object_property_set_bool(OBJECT(accel), "one-insn-per-tb", + opt_one_insn_per_tb, &error_abort); ac->init_machine(NULL); } cpu = cpu_create(cpu_type); diff --git a/linux-user/main.c b/linux-user/main.c index fe03293516..489694ad65 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -69,6 +69,7 @@ char *exec_path; char real_exec_path[PATH_MAX]; int singlestep; +static bool opt_one_insn_per_tb; static const char *argv0; static const char *gdbstub; static envlist_t *envlist; @@ -411,7 +412,7 @@ static void handle_arg_reserved_va(const char *arg) static void handle_arg_singlestep(const char *arg) { - singlestep = 1; + opt_one_insn_per_tb = true; } static void handle_arg_strace(const char *arg) @@ -777,9 +778,12 @@ int main(int argc, char **argv, char **envp) /* init tcg before creating CPUs and to get qemu_host_page_size */ { - AccelClass *ac = ACCEL_GET_CLASS(current_accel()); + AccelState *accel = current_accel(); + AccelClass *ac = ACCEL_GET_CLASS(accel); accel_init_interfaces(ac); + object_property_set_bool(OBJECT(accel), "one-insn-per-tb", + opt_one_insn_per_tb, &error_abort); ac->init_machine(NULL); } cpu = cpu_create(cpu_type); diff --git a/qemu-options.hx b/qemu-options.hx index 42fc90aae4..b8bc94f370 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -182,6 +182,7 @@ DEF("accel", HAS_ARG, QEMU_OPTION_accel, " igd-passthru=on|off (enable Xen integrated Intel graphics passthrough, default=off)\n" " kernel-irqchip=on|off|split controls accelerated irqchip support (default=on)\n" " kvm-shadow-mem=size of KVM shadow MMU in bytes\n" + " one-insn-per-tb=on|off (one guest instruction per TCG translation block)\n" " split-wx=on|off (enable TCG split w^x mapping)\n" " tb-size=n (TCG translation block cache size)\n" " dirty-ring-size=n (KVM dirty ring GFN count, default 0)\n" @@ -210,6 +211,12 @@ SRST ``kvm-shadow-mem=size`` Defines the size of the KVM shadow MMU. + ``one-insn-per-tb=on|off`` + Makes the TCG accelerator put only one guest instruction into + each translation block. This slows down emulation a lot, but + can be useful in some situations, such as when trying to analyse + the logs produced by the ``-d`` option. + ``split-wx=on|off`` Controls the use of split w^x mapping for the TCG code generation buffer. Some operating systems require this to be enabled, and in diff --git a/softmmu/vl.c b/softmmu/vl.c index fb6c221e8e..6c2427262b 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -182,6 +182,7 @@ static const char *log_file; static bool list_data_dirs; static const char *qtest_chrdev; static const char *qtest_log; +static bool opt_one_insn_per_tb; static int has_defaults = 1; static int default_serial = 1; @@ -2220,7 +2221,19 @@ static int do_configure_accelerator(void *opaque, QemuOpts *opts, Error **errp) qemu_opt_foreach(opts, accelerator_set_property, accel, &error_fatal); - + /* + * If legacy -singlestep option is set, honour it for TCG and + * silently ignore for any other accelerator (which is how this + * option has always behaved). + */ + if (opt_one_insn_per_tb) { + /* + * This will always succeed for TCG, and we want to ignore + * the error from trying to set a nonexistent property + * on any other accelerator. + */ + object_property_set_bool(OBJECT(accel), "one-insn-per-tb", true, NULL); + } ret = accel_init_machine(accel, current_machine); if (ret < 0) { if (!qtest_with_kvm || ret != -ENOENT) { @@ -2955,7 +2968,7 @@ void qemu_init(int argc, char **argv) qdict_put_str(machine_opts_dict, "firmware", optarg); break; case QEMU_OPTION_singlestep: - singlestep = 1; + opt_one_insn_per_tb = true; break; case QEMU_OPTION_S: autostart = 0; From 93cbd6c91db6bb4e44580118865862f716338f14 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Apr 2023 17:40:33 +0100 Subject: [PATCH 16/34] softmmu: Don't use 'singlestep' global in QMP and HMP commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HMP 'singlestep' command, the QMP 'query-status' command and the HMP 'info status' command (which is just wrapping the QMP command implementation) look at the 'singlestep' global variable. Make them access the new TCG accelerator 'one-insn-per-tb' property instead. This leaves the HMP and QMP command/field names and output strings unchanged; we will clean that up later. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230417164041.684562-3-peter.maydell@linaro.org --- softmmu/runstate-hmp-cmds.c | 18 ++++++++++++++++-- softmmu/runstate.c | 10 +++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/softmmu/runstate-hmp-cmds.c b/softmmu/runstate-hmp-cmds.c index d55a7d4db8..127521a483 100644 --- a/softmmu/runstate-hmp-cmds.c +++ b/softmmu/runstate-hmp-cmds.c @@ -20,6 +20,7 @@ #include "qapi/error.h" #include "qapi/qapi-commands-run-state.h" #include "qapi/qmp/qdict.h" +#include "qemu/accel.h" void hmp_info_status(Monitor *mon, const QDict *qdict) { @@ -43,13 +44,26 @@ void hmp_info_status(Monitor *mon, const QDict *qdict) void hmp_singlestep(Monitor *mon, const QDict *qdict) { const char *option = qdict_get_try_str(qdict, "option"); + AccelState *accel = current_accel(); + bool newval; + + if (!object_property_find(OBJECT(accel), "one-insn-per-tb")) { + monitor_printf(mon, + "This accelerator does not support setting one-insn-per-tb\n"); + return; + } + if (!option || !strcmp(option, "on")) { - singlestep = 1; + newval = true; } else if (!strcmp(option, "off")) { - singlestep = 0; + newval = false; } else { monitor_printf(mon, "unexpected option %s\n", option); + return; } + /* If the property exists then setting it can never fail */ + object_property_set_bool(OBJECT(accel), "one-insn-per-tb", + newval, &error_abort); } void hmp_watchdog_action(Monitor *mon, const QDict *qdict) diff --git a/softmmu/runstate.c b/softmmu/runstate.c index d1e04586db..2f2396c819 100644 --- a/softmmu/runstate.c +++ b/softmmu/runstate.c @@ -40,6 +40,7 @@ #include "qapi/error.h" #include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-events-run-state.h" +#include "qemu/accel.h" #include "qemu/error-report.h" #include "qemu/job.h" #include "qemu/log.h" @@ -234,9 +235,16 @@ bool runstate_needs_reset(void) StatusInfo *qmp_query_status(Error **errp) { StatusInfo *info = g_malloc0(sizeof(*info)); + AccelState *accel = current_accel(); + /* + * We ignore errors, which will happen if the accelerator + * is not TCG. "singlestep" is meaningless for other accelerators, + * so we will set the StatusInfo field to false for those. + */ + info->singlestep = object_property_get_bool(OBJECT(accel), + "one-insn-per-tb", NULL); info->running = runstate_is_running(); - info->singlestep = singlestep; info->status = current_run_state; return info; From 0e33928cd9b445b2331122154ebe8679aa2ff86e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Apr 2023 17:40:34 +0100 Subject: [PATCH 17/34] accel/tcg: Use one_insn_per_tb global instead of old singlestep global MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only place left that looks at the old 'singlestep' global variable is the TCG curr_cflags() function. Replace the old global with a new 'one_insn_per_tb' which is defined in tcg-all.c and declared in accel/tcg/internal.h. This keeps it restricted to the TCG code, unlike 'singlestep' which was available to every file in the system and defined in multiple different places for softmmu vs linux-user vs bsd-user. While we're making this change, use qatomic_read() and qatomic_set() on the accesses to the new global, because TCG will read it without holding a lock. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230417164041.684562-4-peter.maydell@linaro.org --- accel/tcg/cpu-exec.c | 2 +- accel/tcg/internal.h | 2 ++ accel/tcg/tcg-all.c | 6 ++++-- bsd-user/main.c | 1 - include/exec/cpu-common.h | 2 -- linux-user/main.c | 1 - softmmu/globals.c | 1 - 7 files changed, 7 insertions(+), 8 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 8370c92c05..bc0e1c3299 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -159,7 +159,7 @@ uint32_t curr_cflags(CPUState *cpu) */ if (unlikely(cpu->singlestep_enabled)) { cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR | CF_SINGLE_STEP | 1; - } else if (singlestep) { + } else if (qatomic_read(&one_insn_per_tb)) { cflags |= CF_NO_GOTO_TB | 1; } else if (qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { cflags |= CF_NO_GOTO_TB; diff --git a/accel/tcg/internal.h b/accel/tcg/internal.h index 96f198b28b..7bb0fdbe14 100644 --- a/accel/tcg/internal.h +++ b/accel/tcg/internal.h @@ -67,4 +67,6 @@ static inline target_ulong log_pc(CPUState *cpu, const TranslationBlock *tb) extern int64_t max_delay; extern int64_t max_advance; +extern bool one_insn_per_tb; + #endif /* ACCEL_TCG_INTERNAL_H */ diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index fcf361c8db..a831f8d7c3 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -31,6 +31,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/accel.h" +#include "qemu/atomic.h" #include "qapi/qapi-builtin-visit.h" #include "qemu/units.h" #if !defined(CONFIG_USER_ONLY) @@ -110,6 +111,7 @@ static void tcg_accel_instance_init(Object *obj) } bool mttcg_enabled; +bool one_insn_per_tb; static int tcg_init_machine(MachineState *ms) { @@ -219,8 +221,8 @@ static void tcg_set_one_insn_per_tb(Object *obj, bool value, Error **errp) { TCGState *s = TCG_STATE(obj); s->one_insn_per_tb = value; - /* For the moment, set the global also: this changes the behaviour */ - singlestep = value; + /* Set the global also: this changes the behaviour */ + qatomic_set(&one_insn_per_tb, value); } static int tcg_gdbstub_supported_sstep_flags(void) diff --git a/bsd-user/main.c b/bsd-user/main.c index 09b84da190..a9e5a127d3 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -49,7 +49,6 @@ #include "host-os.h" #include "target_arch_cpu.h" -int singlestep; static bool opt_one_insn_per_tb; uintptr_t guest_base; bool have_guest_base; diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 565c2030c1..1be4a3117e 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -163,8 +163,6 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, void *ptr, size_t len, bool is_write); /* vl.c */ -extern int singlestep; - void list_cpus(void); #endif /* CPU_COMMON_H */ diff --git a/linux-user/main.c b/linux-user/main.c index 489694ad65..c7020b413b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -68,7 +68,6 @@ char *exec_path; char real_exec_path[PATH_MAX]; -int singlestep; static bool opt_one_insn_per_tb; static const char *argv0; static const char *gdbstub; diff --git a/softmmu/globals.c b/softmmu/globals.c index 39678aa8c5..e83b5428d1 100644 --- a/softmmu/globals.c +++ b/softmmu/globals.c @@ -43,7 +43,6 @@ int vga_interface_type = VGA_NONE; bool vga_interface_created; Chardev *parallel_hds[MAX_PARALLEL_PORTS]; int win2k_install_hack; -int singlestep; int fd_bootchk = 1; int graphic_rotate; QEMUOptionRom option_rom[MAX_OPTION_ROMS]; From e99c1f89b2c9e779f17f3abab48ca78392977741 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Apr 2023 17:40:35 +0100 Subject: [PATCH 18/34] linux-user: Add '-one-insn-per-tb' option equivalent to '-singlestep' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The '-singlestep' option is confusing, because it doesn't actually have anything to do with single-stepping the CPU. What it does do is force TCG emulation to put one guest instruction in each TB, which can be useful in some situations. Create a new command line argument -one-insn-per-tb, so we can document that -singlestep is just a deprecated synonym for it, and eventually perhaps drop it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230417164041.684562-5-peter.maydell@linaro.org --- docs/user/main.rst | 7 ++++++- linux-user/main.c | 9 ++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/user/main.rst b/docs/user/main.rst index 6f2ffa080f..f9ac701f4b 100644 --- a/docs/user/main.rst +++ b/docs/user/main.rst @@ -93,8 +93,13 @@ Debug options: ``-g port`` Wait gdb connection to port +``-one-insn-per-tb`` + Run the emulation with one guest instruction per translation block. + This slows down emulation a lot, but can be useful in some situations, + such as when trying to analyse the logs produced by the ``-d`` option. + ``-singlestep`` - Run the emulation in single step mode. + This is a deprecated synonym for the ``-one-insn-per-tb`` option. Environment variables: diff --git a/linux-user/main.c b/linux-user/main.c index c7020b413b..5defe5a6db 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -409,7 +409,7 @@ static void handle_arg_reserved_va(const char *arg) reserved_va = val ? val - 1 : 0; } -static void handle_arg_singlestep(const char *arg) +static void handle_arg_one_insn_per_tb(const char *arg) { opt_one_insn_per_tb = true; } @@ -500,8 +500,11 @@ static const struct qemu_argument arg_table[] = { "logfile", "write logs to 'logfile' (default stderr)"}, {"p", "QEMU_PAGESIZE", true, handle_arg_pagesize, "pagesize", "set the host page size to 'pagesize'"}, - {"singlestep", "QEMU_SINGLESTEP", false, handle_arg_singlestep, - "", "run in singlestep mode"}, + {"one-insn-per-tb", + "QEMU_ONE_INSN_PER_TB", false, handle_arg_one_insn_per_tb, + "", "run with one guest instruction per emulated TB"}, + {"singlestep", "QEMU_SINGLESTEP", false, handle_arg_one_insn_per_tb, + "", "deprecated synonym for -one-insn-per-tb"}, {"strace", "QEMU_STRACE", false, handle_arg_strace, "", "log system calls"}, {"seed", "QEMU_RAND_SEED", true, handle_arg_seed, From 060e0cd7519ada4019e513fce1af4dc307002b7c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Apr 2023 17:40:36 +0100 Subject: [PATCH 19/34] bsd-user: Add '-one-insn-per-tb' option equivalent to '-singlestep' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The '-singlestep' option is confusing, because it doesn't actually have anything to do with single-stepping the CPU. What it does do is force TCG emulation to put one guest instruction in each TB, which can be useful in some situations. Create a new command line argument -one-insn-per-tb, so we can document that -singlestep is just a deprecated synonym for it, and eventually perhaps drop it. Signed-off-by: Peter Maydell Reviewed-by: Warner Losh Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230417164041.684562-6-peter.maydell@linaro.org --- bsd-user/main.c | 5 +++-- docs/user/main.rst | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index a9e5a127d3..cd8b2a670f 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -162,7 +162,8 @@ static void usage(void) "-d item1[,...] enable logging of specified items\n" " (use '-d help' for a list of log items)\n" "-D logfile write logs to 'logfile' (default stderr)\n" - "-singlestep always run in singlestep mode\n" + "-one-insn-per-tb run with one guest instruction per emulated TB\n" + "-singlestep deprecated synonym for -one-insn-per-tb\n" "-strace log system calls\n" "-trace [[enable=]][,events=][,file=]\n" " specify tracing options\n" @@ -385,7 +386,7 @@ int main(int argc, char **argv) (void) envlist_unsetenv(envlist, "LD_PRELOAD"); } else if (!strcmp(r, "seed")) { seed_optarg = optarg; - } else if (!strcmp(r, "singlestep")) { + } else if (!strcmp(r, "singlestep") || !strcmp(r, "one-insn-per-tb")) { opt_one_insn_per_tb = true; } else if (!strcmp(r, "strace")) { do_strace = 1; diff --git a/docs/user/main.rst b/docs/user/main.rst index f9ac701f4b..f478635396 100644 --- a/docs/user/main.rst +++ b/docs/user/main.rst @@ -247,5 +247,10 @@ Debug options: ``-p pagesize`` Act as if the host page size was 'pagesize' bytes +``-one-insn-per-tb`` + Run the emulation with one guest instruction per translation block. + This slows down emulation a lot, but can be useful in some situations, + such as when trying to analyse the logs produced by the ``-d`` option. + ``-singlestep`` - Run the emulation in single step mode. + This is a deprecated synonym for the ``-one-insn-per-tb`` option. From 12fd0f41d0f1ce44ec67f53c679b19f19810e31c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Apr 2023 17:40:37 +0100 Subject: [PATCH 20/34] Document that -singlestep command line option is deprecated MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document that the -singlestep command line option is now deprecated, as it is replaced by either the TCG accelerator property 'one-insn-per-tb' for system emulation or the new '-one-insn-per-tb' option for usermode emulation, and remove the only use of the deprecated syntax from a README. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230417164041.684562-7-peter.maydell@linaro.org --- docs/about/deprecated.rst | 16 ++++++++++++++++ qemu-options.hx | 5 +++-- tcg/tci/README | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 1ca9dc33d6..3c62671dac 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -111,6 +111,22 @@ Use ``-machine acpi=off`` instead. The HAXM project has been retired (see https://github.com/intel/haxm#status). Use "whpx" (on Windows) or "hvf" (on macOS) instead. +``-singlestep`` (since 8.1) +''''''''''''''''''''''''''' + +The ``-singlestep`` option has been turned into an accelerator property, +and given a name that better reflects what it actually does. +Use ``-accel tcg,one-insn-per-tb=on`` instead. + +User-mode emulator command line arguments +----------------------------------------- + +``-singlestep`` (since 8.1) +''''''''''''''''''''''''''' + +The ``-singlestep`` option has been given a name that better reflects +what it actually does. For both linux-user and bsd-user, use the +new ``-one-insn-per-tb`` option instead. QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/qemu-options.hx b/qemu-options.hx index b8bc94f370..af9e85157d 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4192,10 +4192,11 @@ SRST ERST DEF("singlestep", 0, QEMU_OPTION_singlestep, \ - "-singlestep always run in singlestep mode\n", QEMU_ARCH_ALL) + "-singlestep deprecated synonym for -accel tcg,one-insn-per-tb=on\n", QEMU_ARCH_ALL) SRST ``-singlestep`` - Run the emulation in single step mode. + This is a deprecated synonym for the TCG accelerator property + ``one-insn-per-tb``. ERST DEF("preconfig", 0, QEMU_OPTION_preconfig, \ diff --git a/tcg/tci/README b/tcg/tci/README index f72a40a395..4a8b5b5401 100644 --- a/tcg/tci/README +++ b/tcg/tci/README @@ -49,7 +49,7 @@ The only difference from running QEMU with TCI to running without TCI should be speed. Especially during development of TCI, it was very useful to compare runs with and without TCI. Create /tmp/qemu.log by - qemu-system-i386 -d in_asm,op_opt,cpu -D /tmp/qemu.log -singlestep + qemu-system-i386 -d in_asm,op_opt,cpu -D /tmp/qemu.log -accel tcg,one-insn-per-tb=on once with interpreter and once without interpreter and compare the resulting qemu.log files. This is also useful to see the effects of additional From e726acd5b8e208b8e1fec54294e287f561c8f902 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Apr 2023 17:40:38 +0100 Subject: [PATCH 21/34] accel/tcg: Report one-insn-per-tb in 'info jit', not 'info status' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we report whether the TCG accelerator is in 'one-insn-per-tb' mode in the 'info status' output. This is a pretty minor piece of TCG specific information, and we want to deprecate the 'singlestep' field of the associated QMP command. Move the 'one-insn-per-tb' reporting to 'info jit'. We don't need a deprecate-and-drop period for this because the HMP interface has no stability guarantees. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230417164041.684562-8-peter.maydell@linaro.org --- accel/tcg/monitor.c | 14 ++++++++++++++ softmmu/runstate-hmp-cmds.c | 5 ++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c index 1450e160e9..92fce580f1 100644 --- a/accel/tcg/monitor.c +++ b/accel/tcg/monitor.c @@ -7,6 +7,7 @@ */ #include "qemu/osdep.h" +#include "qemu/accel.h" #include "qapi/error.h" #include "qapi/type-helpers.h" #include "qapi/qapi-commands-machine.h" @@ -36,6 +37,18 @@ static void dump_drift_info(GString *buf) } } +static void dump_accel_info(GString *buf) +{ + AccelState *accel = current_accel(); + bool one_insn_per_tb = object_property_get_bool(OBJECT(accel), + "one-insn-per-tb", + &error_fatal); + + g_string_append_printf(buf, "Accelerator settings:\n"); + g_string_append_printf(buf, "one-insn-per-tb: %s\n\n", + one_insn_per_tb ? "on" : "off"); +} + HumanReadableText *qmp_x_query_jit(Error **errp) { g_autoptr(GString) buf = g_string_new(""); @@ -45,6 +58,7 @@ HumanReadableText *qmp_x_query_jit(Error **errp) return NULL; } + dump_accel_info(buf); dump_exec_info(buf); dump_drift_info(buf); diff --git a/softmmu/runstate-hmp-cmds.c b/softmmu/runstate-hmp-cmds.c index 127521a483..a477838dc5 100644 --- a/softmmu/runstate-hmp-cmds.c +++ b/softmmu/runstate-hmp-cmds.c @@ -28,9 +28,8 @@ void hmp_info_status(Monitor *mon, const QDict *qdict) info = qmp_query_status(NULL); - monitor_printf(mon, "VM status: %s%s", - info->running ? "running" : "paused", - info->singlestep ? " (single step mode)" : ""); + monitor_printf(mon, "VM status: %s", + info->running ? "running" : "paused"); if (!info->running && info->status != RUN_STATE_PAUSED) { monitor_printf(mon, " (%s)", RunState_str(info->status)); From e9ccfdd91d7c7752846812c8cda015eee91e728d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Apr 2023 17:40:39 +0100 Subject: [PATCH 22/34] hmp: Add 'one-insn-per-tb' command equivalent to 'singlestep' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'singlestep' HMP command is confusing, because it doesn't actually have anything to do with single-stepping the CPU. What it does do is force TCG emulation to put one guest instruction in each TB, which can be useful in some situations. Create a new HMP command 'one-insn-per-tb', so we can document that 'singlestep' is just a deprecated synonym for it, and eventually perhaps drop it. We aren't obliged to do deprecate-and-drop for HMP commands, but it's easy enough to do so, so we do. Signed-off-by: Peter Maydell Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230417164041.684562-9-peter.maydell@linaro.org --- docs/about/deprecated.rst | 9 +++++++++ hmp-commands.hx | 25 +++++++++++++++++++++---- include/monitor/hmp.h | 2 +- softmmu/runstate-hmp-cmds.c | 2 +- tests/qtest/test-hmp.c | 1 + 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 3c62671dac..6f5e689aa4 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -199,6 +199,15 @@ accepted incorrect commands will return an error. Users should make sure that all arguments passed to ``device_add`` are consistent with the documented property types. +Human Monitor Protocol (HMP) commands +------------------------------------- + +``singlestep`` (since 8.1) +'''''''''''''''''''''''''' + +The ``singlestep`` command has been replaced by the ``one-insn-per-tb`` +command, which has the same behaviour but a less misleading name. + Host Architectures ------------------ diff --git a/hmp-commands.hx b/hmp-commands.hx index bb85ee1d26..9afbb54a51 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -378,18 +378,35 @@ SRST only *tag* as parameter. ERST + { + .name = "one-insn-per-tb", + .args_type = "option:s?", + .params = "[on|off]", + .help = "run emulation with one guest instruction per translation block", + .cmd = hmp_one_insn_per_tb, + }, + +SRST +``one-insn-per-tb [off]`` + Run the emulation with one guest instruction per translation block. + This slows down emulation a lot, but can be useful in some situations, + such as when trying to analyse the logs produced by the ``-d`` option. + This only has an effect when using TCG, not with KVM or other accelerators. + + If called with option off, the emulation returns to normal mode. +ERST + { .name = "singlestep", .args_type = "option:s?", .params = "[on|off]", - .help = "run emulation in singlestep mode or switch to normal mode", - .cmd = hmp_singlestep, + .help = "deprecated synonym for one-insn-per-tb", + .cmd = hmp_one_insn_per_tb, }, SRST ``singlestep [off]`` - Run the emulation in single step mode. - If called with option off, the emulation returns to normal mode. + This is a deprecated synonym for the one-insn-per-tb command. ERST { diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index fdb69b7f9c..13f9a2dedb 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -158,7 +158,7 @@ void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict); void hmp_human_readable_text_helper(Monitor *mon, HumanReadableText *(*qmp_handler)(Error **)); void hmp_info_stats(Monitor *mon, const QDict *qdict); -void hmp_singlestep(Monitor *mon, const QDict *qdict); +void hmp_one_insn_per_tb(Monitor *mon, const QDict *qdict); void hmp_watchdog_action(Monitor *mon, const QDict *qdict); void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict); void hmp_info_capture(Monitor *mon, const QDict *qdict); diff --git a/softmmu/runstate-hmp-cmds.c b/softmmu/runstate-hmp-cmds.c index a477838dc5..2df670f0c0 100644 --- a/softmmu/runstate-hmp-cmds.c +++ b/softmmu/runstate-hmp-cmds.c @@ -40,7 +40,7 @@ void hmp_info_status(Monitor *mon, const QDict *qdict) qapi_free_StatusInfo(info); } -void hmp_singlestep(Monitor *mon, const QDict *qdict) +void hmp_one_insn_per_tb(Monitor *mon, const QDict *qdict) { const char *option = qdict_get_try_str(qdict, "option"); AccelState *accel = current_accel(); diff --git a/tests/qtest/test-hmp.c b/tests/qtest/test-hmp.c index b4a920df89..6704be239b 100644 --- a/tests/qtest/test-hmp.c +++ b/tests/qtest/test-hmp.c @@ -56,6 +56,7 @@ static const char *hmp_cmds[] = { "o /w 0 0x1234", "object_add memory-backend-ram,id=mem1,size=256M", "object_del mem1", + "one-insn-per-tb on", "pmemsave 0 4096 \"/dev/null\"", "p $pc + 8", "qom-list /", From c27f4b665de57e22ae425a7767dd92a3274663b0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Apr 2023 17:40:40 +0100 Subject: [PATCH 23/34] qapi/run-state.json: Fix missing newline at end of file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The run-state.json file is missing a trailing newline; add it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230417164041.684562-10-peter.maydell@linaro.org --- qapi/run-state.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qapi/run-state.json b/qapi/run-state.json index e5f5d31395..09ea120292 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -666,4 +666,4 @@ # Since: 7.2 ## { 'enum': 'NotifyVmexitOption', - 'data': [ 'run', 'internal-error', 'disable' ] } \ No newline at end of file + 'data': [ 'run', 'internal-error', 'disable' ] } From 34c18203d472c5bf969ebd87dc06c7c3a957efc4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Apr 2023 17:40:41 +0100 Subject: [PATCH 24/34] qmp: Deprecate 'singlestep' member of StatusInfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'singlestep' member of StatusInfo has never done what the QMP documentation claims it does. What it actually reports is whether TCG is working in "one guest instruction per translation block" mode. We no longer need this field for the HMP 'info status' command, as we've moved that information to 'info jit'. It seems unlikely that anybody is monitoring the state of this obscure TCG setting via QMP, especially since QMP provides no means for changing the setting. So simply deprecate the field, without providing any replacement. Until we do eventually delete the member, correct the misstatements in the QAPI documentation about it. If we do find that there are users for this, then the most likely way we would provide replacement access to the information would be to put the accelerator QOM object at a well-known path such as /machine/accel, which could then be used with the existing qom-set and qom-get commands. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Markus Armbruster Message-id: 20230417164041.684562-11-peter.maydell@linaro.org --- docs/about/deprecated.rst | 14 ++++++++++++++ qapi/run-state.json | 14 +++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 6f5e689aa4..d5eda0f566 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -199,6 +199,20 @@ accepted incorrect commands will return an error. Users should make sure that all arguments passed to ``device_add`` are consistent with the documented property types. +``StatusInfo`` member ``singlestep`` (since 8.1) +'''''''''''''''''''''''''''''''''''''''''''''''' + +The ``singlestep`` member of the ``StatusInfo`` returned from the +``query-status`` command is deprecated. This member has a confusing +name and it never did what the documentation claimed or what its name +suggests. We do not believe that anybody is actually using the +information provided in this member. + +The information it reports is whether the TCG JIT is in "one +instruction per translated block" mode (which can be set on the +command line or via the HMP, but not via QMP). The information remains +available via the HMP 'info jit' command. + Human Monitor Protocol (HMP) commands ------------------------------------- diff --git a/qapi/run-state.json b/qapi/run-state.json index 09ea120292..db3cf52c62 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -104,16 +104,24 @@ # # @running: true if all VCPUs are runnable, false if not runnable # -# @singlestep: true if VCPUs are in single-step mode +# @singlestep: true if using TCG with one guest instruction +# per translation block # # @status: the virtual machine @RunState # +# Features: +# @deprecated: Member 'singlestep' is deprecated (with no replacement). +# # Since: 0.14 # -# Notes: @singlestep is enabled through the GDB stub +# Notes: @singlestep is enabled on the command line with +# '-accel tcg,one-insn-per-tb=on', or with the HMP +# 'one-insn-per-tb' command. ## { 'struct': 'StatusInfo', - 'data': {'running': 'bool', 'singlestep': 'bool', 'status': 'RunState'} } + 'data': {'running': 'bool', + 'singlestep': { 'type': 'bool', 'features': [ 'deprecated' ]}, + 'status': 'RunState'} } ## # @query-status: From ac64ebbecf80f6bc764d120f85fe9fa28fbd9e85 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 20 Apr 2023 13:22:56 +0100 Subject: [PATCH 25/34] docs/about/deprecated.rst: Add "since 7.1" tag to dtb-kaslr-seed deprecation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 5242876f37ca we deprecated the dtb-kaslr-seed property of the virt board, but forgot the "since n.n" tag in the documentation of this in deprecated.rst. This deprecation note first appeared in the 7.1 release, so retrospectively add the correct "since 7.1" annotation to it. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-id: 20230420122256.1023709-1-peter.maydell@linaro.org --- docs/about/deprecated.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index d5eda0f566..4c7f08803e 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -258,8 +258,8 @@ Use the more generic event ``DEVICE_UNPLUG_GUEST_ERROR`` instead. System emulator machines ------------------------ -Arm ``virt`` machine ``dtb-kaslr-seed`` property -'''''''''''''''''''''''''''''''''''''''''''''''' +Arm ``virt`` machine ``dtb-kaslr-seed`` property (since 7.1) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' The ``dtb-kaslr-seed`` property on the ``virt`` board has been deprecated; use the new name ``dtb-randomness`` instead. The new name From d565f58b38424e9a390a7ea33ff7477bab693fda Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 24 Apr 2023 16:19:19 +0100 Subject: [PATCH 26/34] hw/net/msf2-emac: Don't modify descriptor in-place in emac_store_desc() The msf2-emac ethernet controller has functions emac_load_desc() and emac_store_desc() which read and write the in-memory descriptor blocks and handle conversion between guest and host endianness. As currently written, emac_store_desc() does the endianness conversion in-place; this means that it effectively consumes the input EmacDesc struct, because on a big-endian host the fields will be overwritten with the little-endian versions of their values. Unfortunately, in all the callsites the code continues to access fields in the EmacDesc struct after it has called emac_store_desc() -- specifically, it looks at the d.next field. The effect of this is that on a big-endian host networking doesn't work because the address of the next descriptor is corrupted. We could fix this by making the callsite avoid using the struct; but it's more robust to have emac_store_desc() leave its input alone. (emac_load_desc() also does an in-place conversion, but here this is fine, because the function is supposed to be initializing the struct.) Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Reviewed-by: Thomas Huth Message-id: 20230424151919.1333299-1-peter.maydell@linaro.org --- hw/net/msf2-emac.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/hw/net/msf2-emac.c b/hw/net/msf2-emac.c index 7ccd3e5142..db3a04deb1 100644 --- a/hw/net/msf2-emac.c +++ b/hw/net/msf2-emac.c @@ -118,14 +118,18 @@ static void emac_load_desc(MSF2EmacState *s, EmacDesc *d, hwaddr desc) d->next = le32_to_cpu(d->next); } -static void emac_store_desc(MSF2EmacState *s, EmacDesc *d, hwaddr desc) +static void emac_store_desc(MSF2EmacState *s, const EmacDesc *d, hwaddr desc) { - /* Convert from host endianness into LE. */ - d->pktaddr = cpu_to_le32(d->pktaddr); - d->pktsize = cpu_to_le32(d->pktsize); - d->next = cpu_to_le32(d->next); + EmacDesc outd; + /* + * Convert from host endianness into LE. We use a local struct because + * calling code may still want to look at the fields afterwards. + */ + outd.pktaddr = cpu_to_le32(d->pktaddr); + outd.pktsize = cpu_to_le32(d->pktsize); + outd.next = cpu_to_le32(d->next); - address_space_write(&s->dma_as, desc, MEMTXATTRS_UNSPECIFIED, d, sizeof *d); + address_space_write(&s->dma_as, desc, MEMTXATTRS_UNSPECIFIED, &outd, sizeof outd); } static void msf2_dma_tx(MSF2EmacState *s) From 0fe43f0abf19bbe24df3dbf0613bb47ed55f1482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 24 Apr 2023 16:27:15 +0100 Subject: [PATCH 27/34] hw/arm/boot: Make write_bootloader() public as arm_write_bootloader() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The arm boot.c code includes a utility function write_bootloader() which assists in writing a boot-code fragment into guest memory, including handling endianness and fixing it up with entry point addresses and similar things. This is useful not just for the boot.c code but also in board model code, so rename it to arm_write_bootloader() and make it globally visible. Since we are making it public, make its API a little neater: move the AddressSpace* argument to be next to the hwaddr argument, and allow the fixupcontext array to be const, since we never modify it in this function. Cc: qemu-stable@nongnu.org Signed-off-by: Cédric Le Goater Tested-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell Message-id: 20230424152717.1333930-2-peter.maydell@linaro.org [PMM: Split out from another patch by Cédric, added doc comment] Signed-off-by: Peter Maydell --- hw/arm/boot.c | 35 +++++++------------------------ include/hw/arm/boot.h | 49 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 54f6a3e0b3..720f22531a 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -60,26 +60,6 @@ AddressSpace *arm_boot_address_space(ARMCPU *cpu, return cpu_get_address_space(cs, asidx); } -typedef enum { - FIXUP_NONE = 0, /* do nothing */ - FIXUP_TERMINATOR, /* end of insns */ - FIXUP_BOARDID, /* overwrite with board ID number */ - FIXUP_BOARD_SETUP, /* overwrite with board specific setup code address */ - FIXUP_ARGPTR_LO, /* overwrite with pointer to kernel args */ - FIXUP_ARGPTR_HI, /* overwrite with pointer to kernel args (high half) */ - FIXUP_ENTRYPOINT_LO, /* overwrite with kernel entry point */ - FIXUP_ENTRYPOINT_HI, /* overwrite with kernel entry point (high half) */ - FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */ - FIXUP_BOOTREG, /* overwrite with boot register address */ - FIXUP_DSB, /* overwrite with correct DSB insn for cpu */ - FIXUP_MAX, -} FixupType; - -typedef struct ARMInsnFixup { - uint32_t insn; - FixupType fixup; -} ARMInsnFixup; - static const ARMInsnFixup bootloader_aarch64[] = { { 0x580000c0 }, /* ldr x0, arg ; Load the lower 32-bits of DTB */ { 0xaa1f03e1 }, /* mov x1, xzr */ @@ -150,9 +130,10 @@ static const ARMInsnFixup smpboot[] = { { 0, FIXUP_TERMINATOR } }; -static void write_bootloader(const char *name, hwaddr addr, - const ARMInsnFixup *insns, uint32_t *fixupcontext, - AddressSpace *as) +void arm_write_bootloader(const char *name, + AddressSpace *as, hwaddr addr, + const ARMInsnFixup *insns, + const uint32_t *fixupcontext) { /* Fix up the specified bootloader fragment and write it into * guest memory using rom_add_blob_fixed(). fixupcontext is @@ -214,8 +195,8 @@ static void default_write_secondary(ARMCPU *cpu, fixupcontext[FIXUP_DSB] = CP15_DSB_INSN; } - write_bootloader("smpboot", info->smp_loader_start, - smpboot, fixupcontext, as); + arm_write_bootloader("smpboot", as, info->smp_loader_start, + smpboot, fixupcontext); } void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu, @@ -1186,8 +1167,8 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, fixupcontext[FIXUP_ENTRYPOINT_LO] = entry; fixupcontext[FIXUP_ENTRYPOINT_HI] = entry >> 32; - write_bootloader("bootloader", info->loader_start, - primary_loader, fixupcontext, as); + arm_write_bootloader("bootloader", as, info->loader_start, + primary_loader, fixupcontext); if (info->write_board_setup) { info->write_board_setup(cpu, info); diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h index f18cc3064f..80c492d742 100644 --- a/include/hw/arm/boot.h +++ b/include/hw/arm/boot.h @@ -183,4 +183,53 @@ void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu, const struct arm_boot_info *info, hwaddr mvbar_addr); +typedef enum { + FIXUP_NONE = 0, /* do nothing */ + FIXUP_TERMINATOR, /* end of insns */ + FIXUP_BOARDID, /* overwrite with board ID number */ + FIXUP_BOARD_SETUP, /* overwrite with board specific setup code address */ + FIXUP_ARGPTR_LO, /* overwrite with pointer to kernel args */ + FIXUP_ARGPTR_HI, /* overwrite with pointer to kernel args (high half) */ + FIXUP_ENTRYPOINT_LO, /* overwrite with kernel entry point */ + FIXUP_ENTRYPOINT_HI, /* overwrite with kernel entry point (high half) */ + FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */ + FIXUP_BOOTREG, /* overwrite with boot register address */ + FIXUP_DSB, /* overwrite with correct DSB insn for cpu */ + FIXUP_MAX, +} FixupType; + +typedef struct ARMInsnFixup { + uint32_t insn; + FixupType fixup; +} ARMInsnFixup; + +/** + * arm_write_bootloader - write a bootloader to guest memory + * @name: name of the bootloader blob + * @as: AddressSpace to write the bootloader + * @addr: guest address to write it + * @insns: the blob to be loaded + * @fixupcontext: context to be used for any fixups in @insns + * + * Write a bootloader to guest memory at address @addr in the address + * space @as. @name is the name to use for the resulting ROM blob, so + * it should be unique in the system and reasonably identifiable for debugging. + * + * @insns must be an array of ARMInsnFixup structs, each of which has + * one 32-bit value to be written to the guest memory, and a fixup to be + * applied to the value. FIXUP_NONE (do nothing) is value 0, so effectively + * the fixup is optional when writing a struct initializer. + * The final entry in the array must be { 0, FIXUP_TERMINATOR }. + * + * All other supported fixup types have the semantics "ignore insn + * and instead use the value from the array element @fixupcontext[fixup]". + * The caller should therefore provide @fixupcontext as an array of + * size FIXUP_MAX whose elements have been initialized for at least + * the entries that @insns refers to. + */ +void arm_write_bootloader(const char *name, + AddressSpace *as, hwaddr addr, + const ARMInsnFixup *insns, + const uint32_t *fixupcontext); + #endif /* HW_ARM_BOOT_H */ From 902bba549fc386b4b9805320ed1a2e5b68478bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 24 Apr 2023 16:27:16 +0100 Subject: [PATCH 28/34] hw/arm/aspeed: Use arm_write_bootloader() to write the bootloader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When writing the secondary-CPU stub boot loader code to the guest, use arm_write_bootloader() instead of directly calling rom_add_blob_fixed(). This fixes a bug on big-endian hosts, because arm_write_bootloader() will correctly byte-swap the host-byte-order array values into the guest-byte-order to write into the guest memory. Cc: qemu-stable@nongnu.org Signed-off-by: Cédric Le Goater Tested-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell Message-id: 20230424152717.1333930-3-peter.maydell@linaro.org [PMM: Moved the "make arm_write_bootloader() function public" part to its own patch; updated commit message to note that this fixes an actual bug; adjust to the API changes noted in previous commit] Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index c1f2b9cfca..0b29028fe1 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -200,33 +200,35 @@ struct AspeedMachineState { static void aspeed_write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info) { - static const uint32_t poll_mailbox_ready[] = { + AddressSpace *as = arm_boot_address_space(cpu, info); + static const ARMInsnFixup poll_mailbox_ready[] = { /* * r2 = per-cpu go sign value * r1 = AST_SMP_MBOX_FIELD_ENTRY * r0 = AST_SMP_MBOX_FIELD_GOSIGN */ - 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 */ - 0xe21000ff, /* ands r0, r0, #255 */ - 0xe59f201c, /* ldr r2, [pc, #28] */ - 0xe1822000, /* orr r2, r2, r0 */ + { 0xee100fb0 }, /* mrc p15, 0, r0, c0, c0, 5 */ + { 0xe21000ff }, /* ands r0, r0, #255 */ + { 0xe59f201c }, /* ldr r2, [pc, #28] */ + { 0xe1822000 }, /* orr r2, r2, r0 */ - 0xe59f1018, /* ldr r1, [pc, #24] */ - 0xe59f0018, /* ldr r0, [pc, #24] */ + { 0xe59f1018 }, /* ldr r1, [pc, #24] */ + { 0xe59f0018 }, /* ldr r0, [pc, #24] */ - 0xe320f002, /* wfe */ - 0xe5904000, /* ldr r4, [r0] */ - 0xe1520004, /* cmp r2, r4 */ - 0x1afffffb, /* bne */ - 0xe591f000, /* ldr pc, [r1] */ - AST_SMP_MBOX_GOSIGN, - AST_SMP_MBOX_FIELD_ENTRY, - AST_SMP_MBOX_FIELD_GOSIGN, + { 0xe320f002 }, /* wfe */ + { 0xe5904000 }, /* ldr r4, [r0] */ + { 0xe1520004 }, /* cmp r2, r4 */ + { 0x1afffffb }, /* bne */ + { 0xe591f000 }, /* ldr pc, [r1] */ + { AST_SMP_MBOX_GOSIGN }, + { AST_SMP_MBOX_FIELD_ENTRY }, + { AST_SMP_MBOX_FIELD_GOSIGN }, + { 0, FIXUP_TERMINATOR } }; + static const uint32_t fixupcontext[FIXUP_MAX] = { 0 }; - rom_add_blob_fixed("aspeed.smpboot", poll_mailbox_ready, - sizeof(poll_mailbox_ready), - info->smp_loader_start); + arm_write_bootloader("aspeed.smpboot", as, info->smp_loader_start, + poll_mailbox_ready, fixupcontext); } static void aspeed_reset_secondary(ARMCPU *cpu, From 0acbdb4c4ab6b0a09f159bae4899b0737cf64242 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 24 Apr 2023 16:27:17 +0100 Subject: [PATCH 29/34] hw/arm/raspi: Use arm_write_bootloader() to write boot code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When writing the secondary-CPU stub boot loader code to the guest, use arm_write_bootloader() instead of directly calling rom_add_blob_fixed(). This fixes a bug on big-endian hosts, because arm_write_bootloader() will correctly byte-swap the host-byte-order array values into the guest-byte-order to write into the guest memory. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Tested-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230424152717.1333930-4-peter.maydell@linaro.org --- hw/arm/raspi.c | 64 +++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index 7b9221c924..cc4c4ec9bf 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -16,6 +16,7 @@ #include "qemu/units.h" #include "qemu/cutils.h" #include "qapi/error.h" +#include "hw/arm/boot.h" #include "hw/arm/bcm2836.h" #include "hw/registerfields.h" #include "qemu/error-report.h" @@ -124,20 +125,22 @@ static const char *board_type(uint32_t board_rev) static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info) { - static const uint32_t smpboot[] = { - 0xe1a0e00f, /* mov lr, pc */ - 0xe3a0fe00 + (BOARDSETUP_ADDR >> 4), /* mov pc, BOARDSETUP_ADDR */ - 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5;get core ID */ - 0xe7e10050, /* ubfx r0, r0, #0, #2 ;extract LSB */ - 0xe59f5014, /* ldr r5, =0x400000CC ;load mbox base */ - 0xe320f001, /* 1: yield */ - 0xe7953200, /* ldr r3, [r5, r0, lsl #4] ;read mbox for our core*/ - 0xe3530000, /* cmp r3, #0 ;spin while zero */ - 0x0afffffb, /* beq 1b */ - 0xe7853200, /* str r3, [r5, r0, lsl #4] ;clear mbox */ - 0xe12fff13, /* bx r3 ;jump to target */ - 0x400000cc, /* (constant: mailbox 3 read/clear base) */ + static const ARMInsnFixup smpboot[] = { + { 0xe1a0e00f }, /* mov lr, pc */ + { 0xe3a0fe00 + (BOARDSETUP_ADDR >> 4) }, /* mov pc, BOARDSETUP_ADDR */ + { 0xee100fb0 }, /* mrc p15, 0, r0, c0, c0, 5;get core ID */ + { 0xe7e10050 }, /* ubfx r0, r0, #0, #2 ;extract LSB */ + { 0xe59f5014 }, /* ldr r5, =0x400000CC ;load mbox base */ + { 0xe320f001 }, /* 1: yield */ + { 0xe7953200 }, /* ldr r3, [r5, r0, lsl #4] ;read mbox for our core */ + { 0xe3530000 }, /* cmp r3, #0 ;spin while zero */ + { 0x0afffffb }, /* beq 1b */ + { 0xe7853200 }, /* str r3, [r5, r0, lsl #4] ;clear mbox */ + { 0xe12fff13 }, /* bx r3 ;jump to target */ + { 0x400000cc }, /* (constant: mailbox 3 read/clear base) */ + { 0, FIXUP_TERMINATOR } }; + static const uint32_t fixupcontext[FIXUP_MAX] = { 0 }; /* check that we don't overrun board setup vectors */ QEMU_BUILD_BUG_ON(SMPBOOT_ADDR + sizeof(smpboot) > MVBAR_ADDR); @@ -145,9 +148,8 @@ static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info) QEMU_BUILD_BUG_ON((BOARDSETUP_ADDR & 0xf) != 0 || (BOARDSETUP_ADDR >> 4) >= 0x100); - rom_add_blob_fixed_as("raspi_smpboot", smpboot, sizeof(smpboot), - info->smp_loader_start, - arm_boot_address_space(cpu, info)); + arm_write_bootloader("raspi_smpboot", arm_boot_address_space(cpu, info), + info->smp_loader_start, smpboot, fixupcontext); } static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info) @@ -161,26 +163,28 @@ static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info) * the primary CPU goes into the kernel. We put these variables inside * a rom blob, so that the reset for ROM contents zeroes them for us. */ - static const uint32_t smpboot[] = { - 0xd2801b05, /* mov x5, 0xd8 */ - 0xd53800a6, /* mrs x6, mpidr_el1 */ - 0x924004c6, /* and x6, x6, #0x3 */ - 0xd503205f, /* spin: wfe */ - 0xf86678a4, /* ldr x4, [x5,x6,lsl #3] */ - 0xb4ffffc4, /* cbz x4, spin */ - 0xd2800000, /* mov x0, #0x0 */ - 0xd2800001, /* mov x1, #0x0 */ - 0xd2800002, /* mov x2, #0x0 */ - 0xd2800003, /* mov x3, #0x0 */ - 0xd61f0080, /* br x4 */ + static const ARMInsnFixup smpboot[] = { + { 0xd2801b05 }, /* mov x5, 0xd8 */ + { 0xd53800a6 }, /* mrs x6, mpidr_el1 */ + { 0x924004c6 }, /* and x6, x6, #0x3 */ + { 0xd503205f }, /* spin: wfe */ + { 0xf86678a4 }, /* ldr x4, [x5,x6,lsl #3] */ + { 0xb4ffffc4 }, /* cbz x4, spin */ + { 0xd2800000 }, /* mov x0, #0x0 */ + { 0xd2800001 }, /* mov x1, #0x0 */ + { 0xd2800002 }, /* mov x2, #0x0 */ + { 0xd2800003 }, /* mov x3, #0x0 */ + { 0xd61f0080 }, /* br x4 */ + { 0, FIXUP_TERMINATOR } }; + static const uint32_t fixupcontext[FIXUP_MAX] = { 0 }; static const uint64_t spintables[] = { 0, 0, 0, 0 }; - rom_add_blob_fixed_as("raspi_smpboot", smpboot, sizeof(smpboot), - info->smp_loader_start, as); + arm_write_bootloader("raspi_smpboot", as, info->smp_loader_start, + smpboot, fixupcontext); rom_add_blob_fixed_as("raspi_spintables", spintables, sizeof(spintables), SPINTABLE_ADDR, as); } From 2c5fa0778c3b4307f9f3af7f27886c46d129c62f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 24 Apr 2023 16:28:33 +0100 Subject: [PATCH 30/34] hw/intc/allwinner-a10-pic: Don't use set_bit()/clear_bit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Allwinner PIC model uses set_bit() and clear_bit() to update the values in its irq_pending[] array when an interrupt arrives. However it is using these functions wrongly: they work on an array of type 'long', and it is passing an array of type 'uint32_t'. Because the code manually figures out the right array element, this works on little-endian hosts and on 32-bit big-endian hosts, where bits 0..31 in a 'long' are in the same place as they are in a 'uint32_t'. However it breaks on 64-bit big-endian hosts. Remove the use of set_bit() and clear_bit() in favour of using deposit32() on the array element. This fixes a bug where on big-endian 64-bit hosts the guest kernel would hang early on in bootup. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230424152833.1334136-1-peter.maydell@linaro.org --- hw/intc/allwinner-a10-pic.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/hw/intc/allwinner-a10-pic.c b/hw/intc/allwinner-a10-pic.c index 8cca124807..4875e68ba6 100644 --- a/hw/intc/allwinner-a10-pic.c +++ b/hw/intc/allwinner-a10-pic.c @@ -49,12 +49,9 @@ static void aw_a10_pic_update(AwA10PICState *s) static void aw_a10_pic_set_irq(void *opaque, int irq, int level) { AwA10PICState *s = opaque; + uint32_t *pending_reg = &s->irq_pending[irq / 32]; - if (level) { - set_bit(irq % 32, (void *)&s->irq_pending[irq / 32]); - } else { - clear_bit(irq % 32, (void *)&s->irq_pending[irq / 32]); - } + *pending_reg = deposit32(*pending_reg, irq % 32, 1, level); aw_a10_pic_update(s); } From 7f3a3d3dc433dc06c0adb480729af80f9c8e3739 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 24 Apr 2023 16:39:08 +0100 Subject: [PATCH 31/34] target/arm: Define and use new load_cpu_field_low32() In several places in the 32-bit Arm translate.c, we try to use load_cpu_field() to load from a CPUARMState field into a TCGv_i32 where the field is actually 64-bit. This works on little-endian hosts, but gives the wrong half of the register on big-endian. Add a new load_cpu_field_low32() which loads the low 32 bits of a 64-bit field into a TCGv_i32. The new macro includes a compile-time check against accidentally using it on a field of the wrong size. Use it to fix the two places in the code where we were using load_cpu_field() on a 64-bit field. This fixes a bug where on big-endian hosts the guest would crash after executing an ERET instruction, and a more corner case one where some UNDEFs for attempted accesses to MSR banked registers from Secure EL1 might go to the wrong EL. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20230424153909.1419369-2-peter.maydell@linaro.org --- target/arm/tcg/translate.c | 4 ++-- target/arm/translate-a32.h | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index 3c8401e908..7468476724 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -2816,7 +2816,7 @@ static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn, if (arm_dc_feature(s, ARM_FEATURE_AARCH64) && dc_isar_feature(aa64_sel2, s)) { /* Target EL is EL<3 minus SCR_EL3.EEL2> */ - tcg_el = load_cpu_field(cp15.scr_el3); + tcg_el = load_cpu_field_low32(cp15.scr_el3); tcg_gen_sextract_i32(tcg_el, tcg_el, ctz32(SCR_EEL2), 1); tcg_gen_addi_i32(tcg_el, tcg_el, 3); } else { @@ -6396,7 +6396,7 @@ static bool trans_ERET(DisasContext *s, arg_ERET *a) } if (s->current_el == 2) { /* ERET from Hyp uses ELR_Hyp, not LR */ - tmp = load_cpu_field(elr_el[2]); + tmp = load_cpu_field_low32(elr_el[2]); } else { tmp = load_reg(s, 14); } diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h index 5339c22f1e..99eea85fa8 100644 --- a/target/arm/translate-a32.h +++ b/target/arm/translate-a32.h @@ -61,6 +61,13 @@ static inline TCGv_i32 load_cpu_offset(int offset) #define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name)) +/* Load from the low half of a 64-bit field to a TCGv_i32 */ +#define load_cpu_field_low32(name) \ + ({ \ + QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, name) != 8); \ + load_cpu_offset(offsetoflow32(CPUARMState, name)); \ + }) + void store_cpu_offset(TCGv_i32 var, int offset, int size); #define store_cpu_field(var, name) \ From 2b67d0ff971cb232c6d3cbb2cc44d9e2b7a7aac2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 24 Apr 2023 16:39:09 +0100 Subject: [PATCH 32/34] target/arm: Add compile time asserts to load/store_cpu_field macros Add some compile-time asserts to the load_cpu_field() and store_cpu_field() macros that the struct field being accessed is the expected size. This lets us catch cases where we incorrectly tried to do a 32-bit load from a 64-bit struct field. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20230424153909.1419369-3-peter.maydell@linaro.org --- target/arm/translate-a32.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h index 99eea85fa8..48a15379d2 100644 --- a/target/arm/translate-a32.h +++ b/target/arm/translate-a32.h @@ -59,7 +59,12 @@ static inline TCGv_i32 load_cpu_offset(int offset) return tmp; } -#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name)) +/* Load from a 32-bit field to a TCGv_i32 */ +#define load_cpu_field(name) \ + ({ \ + QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, name) != 4); \ + load_cpu_offset(offsetof(CPUARMState, name)); \ + }) /* Load from the low half of a 64-bit field to a TCGv_i32 */ #define load_cpu_field_low32(name) \ @@ -70,9 +75,13 @@ static inline TCGv_i32 load_cpu_offset(int offset) void store_cpu_offset(TCGv_i32 var, int offset, int size); -#define store_cpu_field(var, name) \ - store_cpu_offset(var, offsetof(CPUARMState, name), \ - sizeof_field(CPUARMState, name)) +#define store_cpu_field(val, name) \ + ({ \ + QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, name) != 4 \ + && sizeof_field(CPUARMState, name) != 1); \ + store_cpu_offset(val, offsetof(CPUARMState, name), \ + sizeof_field(CPUARMState, name)); \ + }) #define store_cpu_field_constant(val, name) \ store_cpu_field(tcg_constant_i32(val), name) From 3e20d90824c262de6887aa1bc52af94db69e4310 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 24 Apr 2023 17:50:52 +0100 Subject: [PATCH 33/34] hw/sd/allwinner-sdhost: Correctly byteswap descriptor fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In allwinner_sdhost_process_desc() we just read directly from guest memory into a host TransferDescriptor struct and back. This only works on little-endian hosts. Abstract the reading and writing of descriptors into functions that handle the byte-swapping so that TransferDescriptor structs as seen by the rest of the code are always in host-order. This fixes a failure of one of the avocado tests on s390. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Reviewed-by: Thomas Huth Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230424165053.1428857-2-peter.maydell@linaro.org --- hw/sd/allwinner-sdhost.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c index 51e5e90830..92a0f42708 100644 --- a/hw/sd/allwinner-sdhost.c +++ b/hw/sd/allwinner-sdhost.c @@ -302,6 +302,30 @@ static void allwinner_sdhost_auto_stop(AwSdHostState *s) } } +static void read_descriptor(AwSdHostState *s, hwaddr desc_addr, + TransferDescriptor *desc) +{ + uint32_t desc_words[4]; + dma_memory_read(&s->dma_as, desc_addr, &desc_words, sizeof(desc_words), + MEMTXATTRS_UNSPECIFIED); + desc->status = le32_to_cpu(desc_words[0]); + desc->size = le32_to_cpu(desc_words[1]); + desc->addr = le32_to_cpu(desc_words[2]); + desc->next = le32_to_cpu(desc_words[3]); +} + +static void write_descriptor(AwSdHostState *s, hwaddr desc_addr, + const TransferDescriptor *desc) +{ + uint32_t desc_words[4]; + desc_words[0] = cpu_to_le32(desc->status); + desc_words[1] = cpu_to_le32(desc->size); + desc_words[2] = cpu_to_le32(desc->addr); + desc_words[3] = cpu_to_le32(desc->next); + dma_memory_write(&s->dma_as, desc_addr, &desc_words, sizeof(desc_words), + MEMTXATTRS_UNSPECIFIED); +} + static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s, hwaddr desc_addr, TransferDescriptor *desc, @@ -312,9 +336,7 @@ static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s, uint32_t num_bytes = max_bytes; uint8_t buf[1024]; - /* Read descriptor */ - dma_memory_read(&s->dma_as, desc_addr, desc, sizeof(*desc), - MEMTXATTRS_UNSPECIFIED); + read_descriptor(s, desc_addr, desc); if (desc->size == 0) { desc->size = klass->max_desc_size; } else if (desc->size > klass->max_desc_size) { @@ -356,8 +378,7 @@ static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s, /* Clear hold flag and flush descriptor */ desc->status &= ~DESC_STATUS_HOLD; - dma_memory_write(&s->dma_as, desc_addr, desc, sizeof(*desc), - MEMTXATTRS_UNSPECIFIED); + write_descriptor(s, desc_addr, desc); return num_done; } From a4ae17e5ec512862bf73e40dfbb1e7db71f2c1e7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 24 Apr 2023 17:50:53 +0100 Subject: [PATCH 34/34] hw/net/allwinner-sun8i-emac: Correctly byteswap descriptor fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In allwinner-sun8i-emac we just read directly from guest memory into a host FrameDescriptor struct and back. This only works on little-endian hosts. Reading and writing of descriptors is already abstracted into functions; make those functions also handle the byte-swapping so that TransferDescriptor structs as seen by the rest of the code are always in host-order, and fix two places that were doing ad-hoc descriptor reading without using the functions. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Reviewed-by: Thomas Huth Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230424165053.1428857-3-peter.maydell@linaro.org --- hw/net/allwinner-sun8i-emac.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c index b861d8ff35..fac4405f45 100644 --- a/hw/net/allwinner-sun8i-emac.c +++ b/hw/net/allwinner-sun8i-emac.c @@ -350,8 +350,13 @@ static void allwinner_sun8i_emac_get_desc(AwSun8iEmacState *s, FrameDescriptor *desc, uint32_t phys_addr) { - dma_memory_read(&s->dma_as, phys_addr, desc, sizeof(*desc), + uint32_t desc_words[4]; + dma_memory_read(&s->dma_as, phys_addr, &desc_words, sizeof(desc_words), MEMTXATTRS_UNSPECIFIED); + desc->status = le32_to_cpu(desc_words[0]); + desc->status2 = le32_to_cpu(desc_words[1]); + desc->addr = le32_to_cpu(desc_words[2]); + desc->next = le32_to_cpu(desc_words[3]); } static uint32_t allwinner_sun8i_emac_next_desc(AwSun8iEmacState *s, @@ -400,10 +405,15 @@ static uint32_t allwinner_sun8i_emac_tx_desc(AwSun8iEmacState *s, } static void allwinner_sun8i_emac_flush_desc(AwSun8iEmacState *s, - FrameDescriptor *desc, + const FrameDescriptor *desc, uint32_t phys_addr) { - dma_memory_write(&s->dma_as, phys_addr, desc, sizeof(*desc), + uint32_t desc_words[4]; + desc_words[0] = cpu_to_le32(desc->status); + desc_words[1] = cpu_to_le32(desc->status2); + desc_words[2] = cpu_to_le32(desc->addr); + desc_words[3] = cpu_to_le32(desc->next); + dma_memory_write(&s->dma_as, phys_addr, &desc_words, sizeof(desc_words), MEMTXATTRS_UNSPECIFIED); } @@ -638,8 +648,7 @@ static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset, break; case REG_TX_CUR_BUF: /* Transmit Current Buffer */ if (s->tx_desc_curr != 0) { - dma_memory_read(&s->dma_as, s->tx_desc_curr, &desc, sizeof(desc), - MEMTXATTRS_UNSPECIFIED); + allwinner_sun8i_emac_get_desc(s, &desc, s->tx_desc_curr); value = desc.addr; } else { value = 0; @@ -652,8 +661,7 @@ static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset, break; case REG_RX_CUR_BUF: /* Receive Current Buffer */ if (s->rx_desc_curr != 0) { - dma_memory_read(&s->dma_as, s->rx_desc_curr, &desc, sizeof(desc), - MEMTXATTRS_UNSPECIFIED); + allwinner_sun8i_emac_get_desc(s, &desc, s->rx_desc_curr); value = desc.addr; } else { value = 0;