From 96a8b92ed8f02d5e86ad380d3299d9f41f99b072 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 7 Nov 2017 15:01:38 +0000 Subject: [PATCH 1/5] target/arm: Report GICv3 sysregs present in ID registers if needed The CPU ID registers ID_AA64PFR0_EL1, ID_PFR1_EL1 and ID_PFR1 have a field for reporting presence of GICv3 system registers. We need to report this field correctly in order for Xen to work as a guest inside QEMU emulation. We mustn't incorrectly claim the sysregs exist when they don't, though, or Linux will crash. Unfortunately the way we've designed the GICv3 emulation in QEMU puts the system registers as part of the GICv3 device, which may be created after the CPU proper has been realized. This means that we don't know at the point when we define the ID registers what the correct value is. Handle this by switching them to calling a function at runtime to read the value, where we can fill in the GIC field appropriately. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Stefano Stabellini Message-id: 1510066898-3725-1-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index f61fb3ef68..35c5bd693b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4549,6 +4549,33 @@ static void define_debug_regs(ARMCPU *cpu) } } +/* We don't know until after realize whether there's a GICv3 + * attached, and that is what registers the gicv3 sysregs. + * So we have to fill in the GIC fields in ID_PFR/ID_PFR1_EL1/ID_AA64PFR0_EL1 + * at runtime. + */ +static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + uint64_t pfr1 = cpu->id_pfr1; + + if (env->gicv3state) { + pfr1 |= 1 << 28; + } + return pfr1; +} + +static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + uint64_t pfr0 = cpu->id_aa64pfr0; + + if (env->gicv3state) { + pfr0 |= 1 << 24; + } + return pfr0; +} + void register_cp_regs_for_features(ARMCPU *cpu) { /* Register all the coprocessor registers based on feature bits */ @@ -4573,10 +4600,14 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->id_pfr0 }, + /* ID_PFR1 is not a plain ARM_CP_CONST because we don't know + * the value of the GIC field until after we define these regs. + */ { .name = "ID_PFR1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 1, - .access = PL1_R, .type = ARM_CP_CONST, - .resetvalue = cpu->id_pfr1 }, + .access = PL1_R, .type = ARM_CP_NO_RAW, + .readfn = id_pfr1_read, + .writefn = arm_cp_write_ignore }, { .name = "ID_DFR0", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, @@ -4692,10 +4723,15 @@ void register_cp_regs_for_features(ARMCPU *cpu) * define new registers here. */ ARMCPRegInfo v8_idregs[] = { + /* ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST because we don't + * know the right value for the GIC field until after we + * define these regs. + */ { .name = "ID_AA64PFR0_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 0, - .access = PL1_R, .type = ARM_CP_CONST, - .resetvalue = cpu->id_aa64pfr0 }, + .access = PL1_R, .type = ARM_CP_NO_RAW, + .readfn = id_aa64pfr0_read, + .writefn = arm_cp_write_ignore }, { .name = "ID_AA64PFR1_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, From 2b75ef01caf74be5af964f97e37f07ff9034fe0b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Nov 2017 18:13:33 +0000 Subject: [PATCH 2/5] nvic: Fix ARMv7M MPU_RBAR reads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix an incorrect mask expression in the handling of v7M MPU_RBAR reads that meant that we would always report the ADDR field as zero. Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée Message-id: 1509732813-22957-1-git-send-email-peter.maydell@linaro.org --- hw/intc/armv7m_nvic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index be46639b63..5d9c8834ad 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -977,7 +977,7 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) if (region >= cpu->pmsav7_dregion) { return 0; } - return (cpu->env.pmsav7.drbar[region] & 0x1f) | (region & 0xf); + return (cpu->env.pmsav7.drbar[region] & ~0x1f) | (region & 0xf); } case 0xda0: /* MPU_RASR (v7M), MPU_RLAR (v8M) */ case 0xda8: /* MPU_RASR_A1 (v7M), MPU_RLAR_A1 (v8M) */ From 50cd71b0d347c74517dcb7da447fe657fca57d9c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Nov 2017 14:36:54 +0000 Subject: [PATCH 3/5] arm: check regime, not current state, for ATS write PAR format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In do_ats_write(), rather than using extended_addresses_enabled() to decide whether the value we get back from get_phys_addr() is a 64-bit format PAR or a 32-bit one, use arm_s1_regime_using_lpae_format(). This is not really the correct answer, because the PAR format depends on the AT instruction being used, not just on the translation regime. However getting this correct requires a significant refactoring, so that get_phys_addr() returns raw information about the fault which the caller can then assemble into a suitable FSR/PAR/syndrome for its purposes, rather than get_phys_addr() returning a pre-formatted FSR. However this change at least improves the situation by making the PAR work correctly for address translation operations done at AArch64 EL2 on the EL2 translation regime. In particular, this is necessary for Xen to be able to run in our emulation, so this seems like a safer interim fix given that we are in freeze. Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias Reviewed-by: Alex Bennée Tested-by: Stefano Stabellini Message-id: 1509719814-6191-1-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 35c5bd693b..91a9300f11 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2169,7 +2169,7 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, ret = get_phys_addr(env, value, access_type, mmu_idx, &phys_addr, &attrs, &prot, &page_size, &fsr, &fi, &cacheattrs); - if (extended_addresses_enabled(env)) { + if (arm_s1_regime_using_lpae_format(env, mmu_idx)) { /* fsr is a DFSR/IFSR value for the long descriptor * translation table format, but with WnR always clear. * Convert it to a 64-bit PAR. From b6e70d1d7fea681306a3c8e74934b66dc9524969 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 14 Nov 2017 22:50:18 +1030 Subject: [PATCH 4/5] hw/arm/aspeed: Unlock SCU when running kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ASPEED hardware contains a lock register for the SCU that disables any writes to the SCU when it is locked. The machine comes up with the lock enabled, but on all known hardware u-boot will unlock it and leave it unlocked when loading the kernel. This means the kernel expects the SCU to be unlocked. When booting from an emulated ROM the normal u-boot unlock path is executed. Things don't go well when booting using the -kernel command line, as u-boot does not run first. Change behaviour so that when a kernel is passed to the machine, set the reset value of the SCU to be unlocked. Signed-off-by: Joel Stanley Reviewed-by: Cédric Le Goater Message-id: 20171114122018.12204-1-joel@jms.id.au Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 9 +++++++++ hw/arm/aspeed_soc.c | 2 ++ hw/misc/aspeed_scu.c | 5 +++-- include/hw/misc/aspeed_scu.h | 3 +++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index ab895ad490..7088c907bd 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -186,6 +186,15 @@ static void aspeed_board_init(MachineState *machine, &error_abort); object_property_set_int(OBJECT(&bmc->soc), cfg->num_cs, "num-cs", &error_abort); + if (machine->kernel_filename) { + /* + * When booting with a -kernel command line there is no u-boot + * that runs to unlock the SCU. In this case set the default to + * be unlocked as the kernel expects + */ + object_property_set_int(OBJECT(&bmc->soc), ASPEED_SCU_PROT_KEY, + "hw-prot-key", &error_abort); + } object_property_set_bool(OBJECT(&bmc->soc), true, "realized", &error_abort); diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 5aa3d2ddd9..c83b7e207b 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -154,6 +154,8 @@ static void aspeed_soc_init(Object *obj) "hw-strap1", &error_abort); object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), "hw-strap2", &error_abort); + object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu), + "hw-prot-key", &error_abort); object_initialize(&s->fmc, sizeof(s->fmc), sc->info->fmc_typename); object_property_add_child(obj, "fmc", OBJECT(&s->fmc), NULL); diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index 95022d3607..74537ce975 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -85,7 +85,6 @@ #define BMC_REV TO_REG(0x19C) #define BMC_DEV_ID TO_REG(0x1A4) -#define PROT_KEY_UNLOCK 0x1688A8A8 #define SCU_IO_REGION_SIZE 0x1000 static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = { @@ -192,7 +191,7 @@ static void aspeed_scu_write(void *opaque, hwaddr offset, uint64_t data, } if (reg > PROT_KEY && reg < CPU2_BASE_SEG1 && - s->regs[PROT_KEY] != PROT_KEY_UNLOCK) { + s->regs[PROT_KEY] != ASPEED_SCU_PROT_KEY) { qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); return; } @@ -246,6 +245,7 @@ static void aspeed_scu_reset(DeviceState *dev) s->regs[SILICON_REV] = s->silicon_rev; s->regs[HW_STRAP1] = s->hw_strap1; s->regs[HW_STRAP2] = s->hw_strap2; + s->regs[PROT_KEY] = s->hw_prot_key; } static uint32_t aspeed_silicon_revs[] = { @@ -299,6 +299,7 @@ static Property aspeed_scu_properties[] = { DEFINE_PROP_UINT32("silicon-rev", AspeedSCUState, silicon_rev, 0), DEFINE_PROP_UINT32("hw-strap1", AspeedSCUState, hw_strap1, 0), DEFINE_PROP_UINT32("hw-strap2", AspeedSCUState, hw_strap2, 0), + DEFINE_PROP_UINT32("hw-prot-key", AspeedSCUState, hw_prot_key, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h index bd4ac013f9..d70cc0aeca 100644 --- a/include/hw/misc/aspeed_scu.h +++ b/include/hw/misc/aspeed_scu.h @@ -29,6 +29,7 @@ typedef struct AspeedSCUState { uint32_t silicon_rev; uint32_t hw_strap1; uint32_t hw_strap2; + uint32_t hw_prot_key; } AspeedSCUState; #define AST2400_A0_SILICON_REV 0x02000303U @@ -38,6 +39,8 @@ typedef struct AspeedSCUState { extern bool is_supported_silicon_rev(uint32_t silicon_rev); +#define ASPEED_SCU_PROT_KEY 0x1688A8A8 + /* * Extracted from Aspeed SDK v00.03.21. Fixes and extra definitions * were added. From b350ae138fcb062f49904f5115cc5fe188a02906 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 16 Nov 2017 16:29:43 +0100 Subject: [PATCH 5/5] hw/arm: Silence xlnx-ep108 deprecation warning during tests The new deprecation warning for the xlnx-ep108 machine also pops up during "make check" which is kind of confusing. Silence it if testing mode is enabled. Signed-off-by: Thomas Huth Reviewed-by: Alistair Francis Acked-by: Wei Huang Message-id: 1510846183-756-1-git-send-email-thuth@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/xlnx-zcu102.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index 9631a53847..bbe7d046e4 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -24,6 +24,7 @@ #include "qemu/error-report.h" #include "exec/address-spaces.h" #include "qemu/log.h" +#include "sysemu/qtest.h" typedef struct XlnxZCU102 { MachineState parent_obj; @@ -164,8 +165,10 @@ static void xlnx_ep108_init(MachineState *machine) { XlnxZCU102 *s = EP108_MACHINE(machine); - info_report("The Xilinx EP108 machine is deprecated, please use the " - "ZCU102 machine instead. It has the same features supported."); + if (!qtest_enabled()) { + info_report("The Xilinx EP108 machine is deprecated, please use the " + "ZCU102 machine (which has the same features) instead."); + } xlnx_zynqmp_init(s, machine); }