@@ -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;
+ }
}
}