Port-prep archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

GENERIC is too large and breaks stack in bootloader


I'm trying to netboot NetBSD/prep GENERIC 6.0 and 6.1-RC1 kernels on my
IBM 7248-120 (PReP) with 96 megabytes of memory. The machine has been
running NetBSD-5.0 for a while. On 6.0 and 6.1-RC1, the gzipped kernel
size is larger than the space between the load address and the stack in
the bootloader, so it breaks the bootloader, and no error message is

With GENERIC kernel in 6.1-RC1, the values when the control reaches the
loops at init_in(u_long) in src/sys/arch/prep/stand/boot/inkernel.c is:

kern_len        0x21dae3
ladr            0x480410
KERNENTRY       0x600000
&i (the address of a value in the stack) = 0x808048

The kernel (which is 0x21dae3 bytes long) is then moved to address
0x600000, breaking the stack. INSTALL kernel is smaller and free of
this problem.

My proposal is to display a error message when the size of gzipped
kernel is larger than the space between stack and KERNENTRY.
At least this tells the user what is happening, instead of displaying
nothing. The attached patch is against inkernel.c, and implements this.
If someone knows more elegant way to get the SP, please replace mine
with that.

Other things that are nice to have include mkbootimage that warns
large kernels, and GENERIC_SMALL configuration. However, as the
absolute maximum image size that can be loaded can be determined
only after it is actually booted and the address of stack is specified,
whether these are `not too ad-hoc' needs to be discussed.

Best regards,
Hisanobu Tomari
Index: inkernel.c
RCS file: /cvs/cvsroot/src/sys/arch/prep/stand/boot/inkernel.c,v
retrieving revision 1.9
diff -c -r1.9 inkernel.c
*** inkernel.c  28 Apr 2008 20:23:33 -0000      1.9
--- inkernel.c  6 Mar 2013 02:16:18 -0000
*** 43,52 ****
--- 43,59 ----
        extern char _start[], _edata[];
        char *p = (char *)(ladr + (_edata - _start));
        u_int i;
+       u_long sp;
        for (i = 0; i < 4096; i++, p++) {
                if (memcmp(p, prep_magic, PREP_MAGICSIZE) == 0) {
                        kern_len = *(int *)(p + PREP_MAGICSIZE);
+                       /* check compressed kernel size against stack */
+                       asm("mr %0,%%r1" : "=r"(sp));
+                       if( (KERNENTRY<sp) && (sp<KERNENTRY+kern_len)) {
+                               printf("Compressed kernel image is too 
+                               return;
+                       }
                        memmove((char *)KERNENTRY,
                                p + PREP_MAGICSIZE + KERNLENSIZE, kern_len);

Home | Main Index | Thread Index | Old Index