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@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 --- a/arch/ppc/qemu/ofmem.c +++ b/arch/ppc/qemu/ofmem.c @@ -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);