The Debian ports images have now switched from using yaboot to grub as their
bootloader. Recent versions of these images will hang rather than boot under
QEMU despite there being no obvious changes to the boot process.
Further investigation reveals that the second stage grub bootloader appears
to use low memory whilst loading the kernel/initrd from disk: unfortunately
the OpenBIOS vector table lives within the first few pages of physical RAM
and so grub writes over the vector table (in particular overwriting the MMU
fault handlers) causing them to fail next time they are executed which
causes the hang.
Fortunately just before this stage of the bootloader executes, it uses the
CIF to request the contents of the /memory node "available" property. It
seems that the low memory locations used by grub are taken from the start
of the available range, so we can simply increase the number of RAM pages
reserved at the bottom of RAM to ensure that the area chosen by the bootloader
doesn't conflict with the vector table.
This patch raises the start of available memory from 0x1000 to 0x4000 which
allows grub to boot successfully in my tests. According to dumps of device trees
taken from real PPC Macs there are already several examples where the start of
available memory is set to 0x3000 or 0x4000, so as this is already present on
real hardware it should not cause any regressions.
Finally it is worth noting that even in the earlier grub images I could see
write accesses to low memory that would overwrite the vector table: I think
that until recently we were lucky that they happened to avoid anything that
was critical to allow the kernel to load and boot.
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland(a)ilande.co.uk>
arch/ppc/qemu/ofmem.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/ppc/qemu/ofmem.c b/arch/ppc/qemu/ofmem.c
index 7a78a1e..4ff0803 100644
@@ -571,9 +571,9 @@ ofmem_init(void)
ofmem_t *ofmem = ofmem_arch_get_private();
- /* Mark the first page as non-free */
- ofmem_claim_phys(0, PAGE_SIZE, 0);
- ofmem_claim_virt(0, PAGE_SIZE, 0);
+ /* Mark the first 4 pages as non-free */
+ ofmem_claim_phys(0, 4 * PAGE_SIZE, 0);
+ ofmem_claim_virt(0, 4 * PAGE_SIZE, 0);
/* Map everything at the top of physical RAM 1:1, minus the OpenBIOS ROM in RAM copy */
ofmem_claim_phys(get_ram_top(), get_hash_base() + HASH_SIZE - get_ram_top(), 0);