--- ./arch/ppc64/kernel/prom.c.orig 2004-03-17 14:28:46.000000000 -0500 +++ ./arch/ppc64/kernel/prom.c 2004-03-24 08:09:02.000000000 -0500 @@ -155,6 +155,15 @@ char *bootdevice = 0; int boot_cpuid = 0; #define MAX_CPU_THREADS 2 +/* + * 'ramdisk_start' is used to ensure the initrd image is not overwritten + * when the device tree is constructed in memory. + */ +#ifdef CONFIG_BLK_DEV_INITRD +static unsigned long ramdisk_start = 0; +#endif + + struct device_node *allnodes = 0; /* use when traversing tree through the allnext, child, sibling, * or parent members of struct device_node. @@ -1796,6 +1805,9 @@ copy_device_tree(unsigned long mem_start unsigned long offset = reloc_offset(); unsigned long mem_end = mem_start + (8<<20); +#ifdef CONFIG_BLK_DEV_INITRD + mem_end = RELOC(ramdisk_start) - 1; +#endif root = call_prom(RELOC("peer"), 1, 1, (phandle)0); if (root == (phandle)0) { prom_panic(RELOC("couldn't get device tree root\n")); @@ -1804,6 +1816,15 @@ copy_device_tree(unsigned long mem_start mem_start = DOUBLEWORD_ALIGN(mem_start); new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp); *allnextp = 0; + if (new_start > mem_end) { + prom_print(RELOC("Insufficient space for device tree:")); + prom_print(RELOC(" size allocated = 0x")); + prom_print_hex(mem_end - mem_start); + prom_print(RELOC(", size required = 0x")); + prom_print_hex(new_start - mem_start); + prom_print_nl(); + prom_exit(); + } return new_start; } @@ -3242,6 +3263,7 @@ prom_bi_rec_reserve(unsigned long mem) switch (rec->tag) { #ifdef CONFIG_BLK_DEV_INITRD case BI_INITRD: + RELOC(ramdisk_start) = rec->data[0]; lmb_reserve(rec->data[0], rec->data[1]); break; #endif /* CONFIG_BLK_DEV_INITRD */