Commit 76e2aef3 authored by Alexander Graf's avatar Alexander Graf Committed by Peter Maydell
Browse files

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: default avatarAndreas Schwab <schwab@suse.de>
Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parent e46e1a74
Loading
Loading
Loading
Loading
+22 −6
Original line number Diff line number Diff line
@@ -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 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.
                 */
            hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size,
                                             4096);
                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);
            }