hw/arm/boot: Increase compliance with kernel arm64 boot protocol

"The Image must be placed text_offset bytes from a 2MB aligned base
address anywhere in usable system RAM and called there."

For the virt board, we write our startup bootloader at the very
bottom of RAM, so that bit can't be used for the image. To avoid
overlap in case the image requests to be loaded at an offset
smaller than our bootloader, we increment the load offset to the
next 2MB.

This fixes a boot failure for Xen AArch64.

Signed-off-by: Stewart Hildebrand <stewart.hildebrand@dornerworks.com>
Tested-by: Andre Przywara <andre.przywara@arm.com>
Message-id: b8a89518794b4436af0c151ed10de4fa@dornerworks.com
[PMM: Rephrased a comment a bit]
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Stewart Hildebrand 2018-10-24 07:50:18 +01:00 committed by Peter Maydell
parent 4be42f4013
commit ea358872a6

View File

@ -24,6 +24,7 @@
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "exec/address-spaces.h"
#include "qemu/units.h"
/* Kernel boot protocol is specified in the kernel docs
* Documentation/arm/Booting and Documentation/arm64/booting.txt
@ -36,6 +37,8 @@
#define ARM64_TEXT_OFFSET_OFFSET 8
#define ARM64_MAGIC_OFFSET 56
#define BOOTLOADER_MAX_SIZE (4 * KiB)
AddressSpace *arm_boot_address_space(ARMCPU *cpu,
const struct arm_boot_info *info)
{
@ -184,6 +187,8 @@ static void write_bootloader(const char *name, hwaddr addr,
code[i] = tswap32(insn);
}
assert((len * sizeof(uint32_t)) < BOOTLOADER_MAX_SIZE);
rom_add_blob_fixed_as(name, code, len * sizeof(uint32_t), addr, as);
g_free(code);
@ -919,6 +924,19 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base,
memcpy(&hdrvals, buffer + ARM64_TEXT_OFFSET_OFFSET, sizeof(hdrvals));
if (hdrvals[1] != 0) {
kernel_load_offset = le64_to_cpu(hdrvals[0]);
/*
* We write our startup "bootloader" at the very bottom of RAM,
* so that bit can't be used for the image. Luckily the Image
* format specification is that the image requests only an offset
* from a 2MB boundary, not an absolute load address. So if the
* image requests an offset that might mean it overlaps with the
* bootloader, we can just load it starting at 2MB+offset rather
* than 0MB + offset.
*/
if (kernel_load_offset < BOOTLOADER_MAX_SIZE) {
kernel_load_offset += 2 * MiB;
}
}
}