GENERIC is too large and breaks stack in bootloader
Hisanobu Tomari <[email protected]> Wed, 6 Mar 2013 11:18:06 +0900
| Newsgroups | gmane.os.netbsd.ports.prep |
|---|---|
| Message-ID | <[email protected]> |
Hi, 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 displayed. 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
inkernel.diff
(text/x-patch, 900 B)
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 large.\n");
+ return;
+ }
memmove((char *)KERNENTRY,
p + PREP_MAGICSIZE + KERNLENSIZE, kern_len);
return;