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));
Attachment:
signature.asc
Description: Digital signature