On Fri, Sep 15, 2006 at 11:21:33AM +0200, Christian Aichinger wrote: > The kernel somehow loses the information where the initrd image is > placed in memory. The correct data is there in > arch/powerpc/kernel/prom_init.c:prom_check_initrd(), but in > init/initramfs.c:populate_rootfs() it's wrong, initrd_{start,end} > are both 0.
arch/powerpc/kernel/prom_init.c:prom_check_initrd() is broken. The relevant part of the code is: ,------------------ | unsigned long val; | ... | val = RELOC(prom_initrd_start); | prom_setprop(_prom->chosen, "/chosen", "linux,initrd-start", | &val, sizeof(val)); | val = RELOC(prom_initrd_end); | prom_setprop(_prom->chosen, "/chosen", "linux,initrd-end", | &val, sizeof(val)); `------------------ As you can see it tries to store pointers to initrd start/end in the /chosen node, however in reality it stores the address of val, a local variable. Since that's long gone invalid when the values are read out from /chosen again, the result is undefined. The attached is a patch fixing the problem. It would be nice if the bug submitters could test it to see if it fixes their problems too. Cheers, Christian Aichinger PS: arch/powerpc/platforms/powermac/bootx_init.c does something similar, though it looks saner, as it copies *val into it's own permanent memory block AFAICS.
--- a/arch/powerpc/kernel/prom_init.c 2006-09-15 18:33:50.000000000 +0200 +++ b/arch/powerpc/kernel/prom_init.c 2006-09-15 18:33:44.000000000 +0200 @@ -2141,17 +2141,17 @@ struct prom_t *_prom = &RELOC(prom); if (r3 && r4 && r4 != 0xdeadbeef) { - unsigned long val; + unsigned long *ptr; RELOC(prom_initrd_start) = is_kernel_addr(r3) ? __pa(r3) : r3; RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; - val = RELOC(prom_initrd_start); + ptr = &RELOC(prom_initrd_start); prom_setprop(_prom->chosen, "/chosen", "linux,initrd-start", - &val, sizeof(val)); - val = RELOC(prom_initrd_end); + ptr, sizeof(prom_initrd_start)); + ptr = &RELOC(prom_initrd_end); prom_setprop(_prom->chosen, "/chosen", "linux,initrd-end", - &val, sizeof(val)); + ptr, sizeof(prom_initrd_end)); reserve_mem(RELOC(prom_initrd_start), RELOC(prom_initrd_end) - RELOC(prom_initrd_start));
signature.asc
Description: Digital signature