if ( ret < 0 )
goto err;
+ /* Actual new size */
+ new_size = fdt_totalsize(kinfo->fdt);
+
/*
- * DTB must be load below 4GiB and far enough from linux (Linux uses
- * the space after it to decompress)
- * Load the DTB at the end of the first bank, while ensuring it is
- * also below 4G
+ * DTB must be loaded such that it does not conflict with the
+ * kernel decompressor. For 32-bit Linux Documentation/arm/Booting
+ * recommends just after the 128MB boundary while for 64-bit Linux
+ * the recommendation in Documentation/arm64/booting.txt is below
+ * 512MB. Place at 128MB, (or, if we have less RAM, as high as
+ * possible) in order to satisfy both.
*/
end = kinfo->mem.bank[0].start + kinfo->mem.bank[0].size;
- end = MIN(1ull << 32, end);
- kinfo->dtb_paddr = end - fdt_totalsize(kinfo->fdt);
+ end = MIN(kinfo->mem.bank[0].start + (128<<20) + new_size, end);
+
+ kinfo->dtb_paddr = end - new_size;
+
/* Align the address to 2Mb. Linux only requires 4 byte alignment */
kinfo->dtb_paddr &= ~((2 << 20) - 1);
- if ( fdt_totalsize(kinfo->fdt) > end )
+ if ( kinfo->dtb_paddr < kinfo->mem.bank[0].start ||
+ kinfo->mem.bank[0].start + new_size > end )
{
printk(XENLOG_ERR "Not enough memory in the first bank for "
"the device tree.");
goto err;
}
-
return 0;
err:
info->zimage.kernel_addr = addr;
/*
- * If start is zero, the zImage is position independent -- load it
- * at 32k from start of RAM.
+ * If start is zero, the zImage is position independent, in this
+ * case Documentation/arm/Booting recommends loading below 128MiB
+ * and above 32MiB. Load it as high as possible within these
+ * constraints, while also avoiding the DTB.
*/
if (start == 0)
- info->zimage.load_addr = info->mem.bank[0].start + 0x8000;
+ {
+ paddr_t load_end;
+
+ load_end = info->mem.bank[0].start + info->mem.bank[0].size;
+ load_end = MIN(info->mem.bank[0].start + (128<<20), load_end);
+
+ /*
+ * FDT is loaded above 128M or as high as possible, so the
+ * only way we can clash is if we have <=128MB, in which case
+ * FDT will be right at the end and so dtb_paddr will be below
+ * the proposed kernel load address. Move the kernel down if
+ * necessary.
+ */
+ if ( load_end >= info->dtb_paddr )
+ load_end = info->dtb_paddr;
+
+ info->zimage.load_addr = load_end - end;
+ /* Align to 2MB */
+ info->zimage.load_addr &= ~((2 << 20) - 1);
+ }
else
info->zimage.load_addr = start;
info->zimage.len = end - start;