From e46e1a74ef482f1ef773e750df9654ef4442ca29 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 15 Jul 2015 17:16:26 +0100 Subject: [PATCH 1/2] target-arm: Fix broken SCTLR_EL3 reset The SCTLR_EL3 cpreg definition was implicitly resetting the register state to 0, which is both wrong and clashes with the reset done via the SCTLR definition (since sctlr[3] is unioned with sctlr_s). This went unnoticed until recently, when an unrelated change (commit a903c449b41f105aa) happened to perturb the order of enumeration through the cpregs hashtable for reset such that the erroneous reset happened after the correct one rather than before it. Fix this by marking SCTLR_EL3 as an alias, so its reset is left up to the AArch32 view. Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias --- target-arm/helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-arm/helper.c b/target-arm/helper.c index b87afe7cde..01f0d0dac9 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2752,6 +2752,7 @@ static const ARMCPRegInfo el3_cp_reginfo[] = { .access = PL3_RW, .writefn = vbar_write, .resetvalue = 0, .fieldoffset = offsetof(CPUARMState, cp15.mvbar) }, { .name = "SCTLR_EL3", .state = ARM_CP_STATE_AA64, + .type = ARM_CP_ALIAS, /* reset handled by AArch32 view */ .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 0, .opc2 = 0, .access = PL3_RW, .raw_writefn = raw_write, .writefn = sctlr_write, .fieldoffset = offsetof(CPUARMState, cp15.sctlr_el[3]) }, From 76e2aef392629f2b2a468f5158d5c397cc5beed2 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 15 Jul 2015 17:16:26 +0100 Subject: [PATCH 2/2] hw/arm/boot: Increase fdt alignment The Linux kernel on aarch64 creates a page table entry at early bootup that spans the 2MB range on memory spanning the fdt start address: [ ALIGN_DOWN(fdt, 2MB) ... ALIGN_DOWN(fdt, 2MB) + 2MB ] This means that when our current 4k alignment happens to fall at the end of the aligned region, Linux tries to access memory that is not mapped. The easy fix is to instead increase the alignment to 2MB, making Linux's logic always succeed. We leave the existing 4k alignment for 32bit kernels to not cause any regressions due to space constraints. Reported-by: Andreas Schwab Signed-off-by: Alexander Graf Signed-off-by: Peter Maydell --- hw/arm/boot.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index f48ed2d34d..5b969cda1c 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -735,12 +735,28 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) * we point to the kernel args. */ if (have_dtb(info)) { - /* Place the DTB after the initrd in memory. Note that some - * kernels will trash anything in the 4K page the initrd - * ends in, so make sure the DTB isn't caught up in that. - */ - hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, - 4096); + hwaddr align; + hwaddr dtb_start; + + if (elf_machine == EM_AARCH64) { + /* + * Some AArch64 kernels on early bootup map the fdt region as + * + * [ ALIGN_DOWN(fdt, 2MB) ... ALIGN_DOWN(fdt, 2MB) + 2MB ] + * + * Let's play safe and prealign it to 2MB to give us some space. + */ + align = 2 * 1024 * 1024; + } else { + /* + * Some 32bit kernels will trash anything in the 4K page the + * initrd ends in, so make sure the DTB isn't caught up in that. + */ + align = 4096; + } + + /* Place the DTB after the initrd in memory with alignment. */ + dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, align); if (load_dtb(dtb_start, info, 0) < 0) { exit(1); }