]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Support long command lines as per 2.06 Linux boot protocol
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 13 Nov 2010 20:27:08 +0000 (21:27 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 13 Nov 2010 20:27:08 +0000 (21:27 +0100)
grub-core/loader/i386/linux.c
grub-core/loader/i386/pc/linux.c
include/grub/i386/linux.h

index de4bec1063572d205c7b6de12bd81b4b74fcefba..bdf66c6f65ee8a90fa4adfe0d74fe89f623351e8 100644 (file)
@@ -54,7 +54,6 @@
 #endif
 
 #define GRUB_LINUX_CL_OFFSET           0x1000
-#define GRUB_LINUX_CL_END_OFFSET       0x2000
 
 static grub_dl_t my_mod;
 
@@ -71,6 +70,7 @@ static grub_uint32_t prot_mode_pages;
 static grub_uint32_t initrd_pages;
 static struct grub_relocator *relocator = NULL;
 static void *efi_mmap_buf;
+static grub_size_t maximal_cmdline_size;
 #ifdef GRUB_MACHINE_EFI
 static grub_efi_uintn_t efi_mmap_size;
 #else
@@ -185,7 +185,7 @@ allocate_pages (grub_size_t prot_size)
   grub_err_t err;
 
   /* Make sure that each size is aligned to a page boundary.  */
-  real_size = GRUB_LINUX_CL_END_OFFSET;
+  real_size = GRUB_LINUX_CL_OFFSET + maximal_cmdline_size;
   prot_size = page_align (prot_size);
   mmap_size = find_mmap_size ();
 
@@ -630,6 +630,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
       goto fail;
     }
 
+  if (grub_le_to_cpu16 (lh.version) >= 0x0206)
+    maximal_cmdline_size = grub_le_to_cpu32 (lh.cmdline_size) + 1;
+  else
+    maximal_cmdline_size = 256;
+
+  if (maximal_cmdline_size < 128)
+    maximal_cmdline_size = 128;
+
   setup_sects = lh.setup_sects;
 
   /* If SETUP_SECTS is not set, set it to the default (4).  */
@@ -643,7 +651,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
     goto fail;
 
   params = (struct linux_kernel_params *) real_mode_mem;
-  grub_memset (params, 0, GRUB_LINUX_CL_END_OFFSET);
+  grub_memset (params, 0, GRUB_LINUX_CL_OFFSET + maximal_cmdline_size);
   grub_memcpy (&params->setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
 
   params->ps_mouse = params->padding10 =  0;
@@ -845,8 +853,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   /* Copy kernel parameters.  */
   for (i = 1;
        i < argc
-        && dest + grub_strlen (argv[i]) + 1 < ((char *) real_mode_mem
-                                               + GRUB_LINUX_CL_END_OFFSET);
+        && dest + grub_strlen (argv[i]) + 2 < ((char *) real_mode_mem
+                                               + GRUB_LINUX_CL_OFFSET
+                                               + maximal_cmdline_size);
        i++)
     {
       *dest++ = ' ';
index 90de70f66478552bda3b4196db393e2f2fc25d21..44da0ad9004d7431a64271f57d21d86acebbadff 100644 (file)
@@ -36,7 +36,6 @@
 #include <grub/i386/floppy.h>
 
 #define GRUB_LINUX_CL_OFFSET           0x9000
-#define GRUB_LINUX_CL_END_OFFSET       0x90FF
 
 static grub_dl_t my_mod;
 
@@ -46,6 +45,7 @@ static struct grub_relocator *relocator = NULL;
 static grub_addr_t grub_linux_real_target;
 static char *grub_linux_real_chunk;
 static grub_size_t grub_linux16_prot_size;
+static grub_size_t maximal_cmdline_size;
 
 static grub_err_t
 grub_linux16_boot (void)
@@ -126,15 +126,20 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   setup_sects = lh.setup_sects;
   linux_mem_size = 0;
 
+  maximal_cmdline_size = 256;
+
   if (lh.header == grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
       && grub_le_to_cpu16 (lh.version) >= 0x0200)
     {
       grub_linux_is_bzimage = (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL);
       lh.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
 
+      if (grub_le_to_cpu16 (lh.version) >= 0x0206)
+       maximal_cmdline_size = grub_le_to_cpu32 (lh.cmdline_size) + 1;
+
       /* Put the real mode part at as a high location as possible.  */
       grub_linux_real_target = grub_mmap_get_lower () 
-       - GRUB_LINUX_SETUP_MOVE_SIZE;
+       - (GRUB_LINUX_CL_OFFSET + maximal_cmdline_size);
       /* But it must not exceed the traditional area.  */
       if (grub_linux_real_target > GRUB_LINUX_OLD_REAL_MODE_ADDR)
        grub_linux_real_target = GRUB_LINUX_OLD_REAL_MODE_ADDR;
@@ -151,7 +156,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
        {
          lh.cl_magic = grub_cpu_to_le16 (GRUB_LINUX_CL_MAGIC);
          lh.cl_offset = grub_cpu_to_le16 (GRUB_LINUX_CL_OFFSET);
-         lh.setup_move_size = grub_cpu_to_le16 (GRUB_LINUX_SETUP_MOVE_SIZE);
+         lh.setup_move_size = grub_cpu_to_le16 (GRUB_LINUX_CL_OFFSET
+                                                + maximal_cmdline_size);
        }
     }
   else
@@ -183,12 +189,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
       goto fail;
     }
 
-  if (grub_linux_real_target + GRUB_LINUX_SETUP_MOVE_SIZE
+  if (grub_linux_real_target + GRUB_LINUX_CL_OFFSET + maximal_cmdline_size
       > grub_mmap_get_lower ())
     {
       grub_error (GRUB_ERR_OUT_OF_RANGE,
                 "too small lower memory (0x%x > 0x%x)",
-                 grub_linux_real_target + GRUB_LINUX_SETUP_MOVE_SIZE,
+                 grub_linux_real_target + GRUB_LINUX_CL_OFFSET
+                 + maximal_cmdline_size,
                  (int) grub_mmap_get_lower ());
       goto fail;
     }
@@ -261,7 +268,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
     grub_relocator_chunk_t ch;
     err = grub_relocator_alloc_chunk_addr (relocator, &ch,
                                           grub_linux_real_target,
-                                          GRUB_LINUX_SETUP_MOVE_SIZE);
+                                          GRUB_LINUX_CL_OFFSET
+                                          + maximal_cmdline_size);
     if (err)
       return err;
     grub_linux_real_chunk = get_virtual_current_address (ch);
@@ -294,8 +302,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   /* Copy kernel parameters.  */
   for (i = 1;
        i < argc
-        && dest + grub_strlen (argv[i]) + 1 < (grub_linux_real_chunk
-                                               + GRUB_LINUX_CL_END_OFFSET);
+        && dest + grub_strlen (argv[i]) + 2 < (grub_linux_real_chunk
+                                               + GRUB_LINUX_CL_OFFSET
+                                               + maximal_cmdline_size);
        i++)
     {
       *dest++ = ' ';
index 63f99db62d37ad203906a987cdcba10aa680c00b..ad59b34528c0dc3e61b48d68f7a83feb8beeba13 100644 (file)
@@ -41,7 +41,6 @@
 #define GRUB_LINUX_VID_MODE_ASK                0xFFFD
 #define GRUB_LINUX_VID_MODE_VESA_START 0x0300
 
-#define GRUB_LINUX_SETUP_MOVE_SIZE     0x9100
 #define GRUB_LINUX_CL_MAGIC            0xA33F
 
 #ifdef __x86_64__
@@ -126,6 +125,10 @@ struct linux_kernel_header
   grub_uint16_t pad1;                  /* Unused */
   grub_uint32_t cmd_line_ptr;          /* Points to the kernel command line */
   grub_uint32_t initrd_addr_max;        /* Highest address for initrd */
+  grub_uint32_t kernel_alignment;
+  grub_uint8_t relocatable;
+  grub_uint8_t pad[3];
+  grub_uint32_t cmdline_size;
 } __attribute__ ((packed));
 
 /* Boot parameters for Linux based on 2.6.12. This is used by the setup