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

Reply via email to