Sending again with the minor ChangeLog tweak to get it to apply cleanly against current CVS.
The attached patch lets GRUB parse a Linux kernel command line for mem= to use as the upper memory location for an initrd as opposed to the maximum detected memory amount per the Linux/I386 boot protocol. Jeremy
Index: ChangeLog =================================================================== RCS file: /cvsroot/grub/grub/ChangeLog,v retrieving revision 1.477 diff -u -u -r1.477 ChangeLog --- ChangeLog 11 Feb 2002 08:10:57 -0000 1.477 +++ ChangeLog 8 Mar 2002 21:43:01 -0000 @@ -1,3 +1,13 @@ +2002-03-08 Jeremy Katz <[EMAIL PROTECTED]> + + * stage2/boot.c (load_image): Look for mem= on Linux kernel + command line and set max memory for loading the initrd + appropriately. + (load_initrd): Likewise. + * stage2/char_io.c (simple_strtoul): Simple string to unsigned + long function. + * stage2/shared.h (simple_strtoul): Defined. + 2002-02-11 Pavel Roskin <[EMAIL PROTECTED]> * util/grub-install.in (find_device): New function - find block Index: stage2/boot.c =================================================================== RCS file: /cvsroot/grub/grub/stage2/boot.c,v retrieving revision 1.36 diff -u -u -r1.36 boot.c --- stage2/boot.c 12 Nov 2001 06:57:29 -0000 1.36 +++ stage2/boot.c 8 Mar 2002 21:43:01 -0000 @@ -28,6 +28,7 @@ static int cur_addr; entry_func entry_addr; static struct mod_list mll[99]; +static unsigned long kernel_mem_end = 0; /* @@ -308,6 +309,36 @@ 0, (64 - setup_sects - 1) << 9); + /* we need to parse mem= from the command-line so that we can load + the initrd in the right place. bleah */ + { + char *mem; + + mem = grub_strstr (arg, "mem="); + if (mem) + { + /* we handle this identically to the kernel; see memparse + in lib/cmdline.c of the kernel source for the + original location of this code */ + kernel_mem_end = simple_strtoul(mem+4, &mem); + + switch(*mem) + { + case 'G': + case 'g': + kernel_mem_end <<= 10; + case 'M': + case 'm': + kernel_mem_end <<= 10; + case 'K': + case 'k': + kernel_mem_end <<= 10; + default: + break; + } + } + } + /* Copy command-line plus memory hack to staging area. NOTE: Linux has a bug that it doesn't handle multiple spaces between two options and a space after a "mem=" option isn't @@ -720,7 +751,9 @@ goto fail; } - moveto = ((mbi.mem_upper + 0x400) * 0x400 - len) & 0xfffff000; + if (!kernel_mem_end) + kernel_mem_end = (mbi.mem_upper + 0x400) * 0x400; + moveto = (kernel_mem_end - len) & 0xfffff000; if (moveto + len >= LINUX_INITRD_MAX_ADDRESS) moveto = (LINUX_INITRD_MAX_ADDRESS - len) & 0xfffff000; Index: stage2/char_io.c =================================================================== RCS file: /cvsroot/grub/grub/stage2/char_io.c,v retrieving revision 1.45 diff -u -u -r1.45 char_io.c --- stage2/char_io.c 8 Feb 2002 01:14:01 -0000 1.45 +++ stage2/char_io.c 8 Mar 2002 21:43:01 -0000 @@ -967,6 +967,34 @@ return 1; } +/* convert a string to an unsigned long. basically taken straight from + * the Linux kernel (lib/vsprintf.c) but made even simpler due to lack of + * base handling + * str_ptr is the start of the string, + * endp will point to the end of the parsed string when we're done + */ +unsigned long +simple_strtoul(char *str_ptr, char **endp) +{ + unsigned long result = 0; + + while (1) + { + unsigned int digit; + + digit = *str_ptr - '0'; + /* since digit is unsigned, it will wrap */ + if (digit > 9) + break; + result = result * 10 + digit; + str_ptr++; + } + + if (endp) + *endp = (char *)str_ptr; + return result; +} + int grub_tolower (int c) { Index: stage2/shared.h =================================================================== RCS file: /cvsroot/grub/grub/stage2/shared.h,v retrieving revision 1.84 diff -u -u -r1.84 shared.h --- stage2/shared.h 8 Feb 2002 01:14:01 -0000 1.84 +++ stage2/shared.h 8 Mar 2002 21:43:01 -0000 @@ -918,6 +918,9 @@ int grub_strlen (const char *str); char *grub_strcpy (char *dest, const char *src); +/* simple version of string to unsigned long; doesn't handle bases */ +unsigned long simple_strtoul(char *str_ptr, char **endp); + #ifndef GRUB_UTIL typedef unsigned long grub_jmp_buf[6]; #else