]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Lift up core size limits on some platforms. Fix potential memory
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 7 Mar 2013 07:17:24 +0000 (08:17 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 7 Mar 2013 07:17:24 +0000 (08:17 +0100)
corruption with big core on small memory systems. Document remaining
limits.

ChangeLog
docs/grub.texi
grub-core/kern/i386/coreboot/init.c
grub-core/kern/i386/pc/init.c
grub-core/kern/main.c
grub-core/kern/mm.c
include/grub/kernel.h
include/grub/offsets.h
util/grub-mkimage.c

index f1ab52aa7e0cc13e1885950be2046d066cbdaaa4..96527dd10d4e4ad8d7f8f7b0aa75b5ea3f7e0dde 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-03-07  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Lift up core size limits on some platforms. Fix potential memory
+       corruption with big core on small memory systems. Document remaining
+       limits.
+
 2013-03-05  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/term/terminfo.c (grub_terminfo_cls): Issue an explicit
index 9941b474283fdbb4eca74302c64216f1063afa44..0b668272cb13d5630badc788d7792ba4e6182e77 100644 (file)
@@ -89,6 +89,7 @@ This edition documents version @value{VERSION}.
 * Serial terminal::             Using GRUB via a serial line
 * Vendor power-on keys::        Changing GRUB behaviour on vendor power-on keys
 * Images::                      GRUB image files
+* Core image size limitation::  GRUB image files size limitations
 * Filesystem::                  Filesystem syntax and semantics
 * Interface::                   The menu and the command-line
 * Environment::                 GRUB environment variables
@@ -2390,6 +2391,43 @@ In GRUB 2, images for PXE network booting are now constructed using
 contains the @samp{pxe} and @samp{pxecmd} modules.  @xref{Network}.
 @end table
 
+@node Core image size limitation
+@chapter Core image size limitation
+
+Heavily limited platforms:
+@itemize
+@item i386-pc (normal and PXE): the core image size (compressed) is limited by 458240 bytes.
+ kernel.img (.text + .data + .bss, uncompressed) is limited by 392704 bytes.
+ module size (uncompressed) + kernel.img (.text + .data, uncompressed) is limited by the size of contiguous chunk at 1M address.
+@item sparc64-ieee1275: kernel.img (.text + .data + .bss) + modules + 256K (stack) + 2M (heap) is limited by space available at 0x4400. On most platforms it's just 3 or 4M since ieee1275 maps only so much.
+@item i386-ieee1275: kernel.img  (.text + .data + .bss) + modules is limited by memory available at 0x10000, at most 596K
+@end itemize
+
+Lightly limited platforms:
+
+@itemize
+@item i386-qemu: kernel.img (.text + .data + .bss) is limited by 392704 bytes.
+                 (core.img would be limited by ROM size but it's unlimited on qemu
+@item All EFI platforms: limited by contiguous RAM size and possibly firmware bugs
+@item Coreboot and multiboot. kernel.img (.text + .data + .bss) is limited by 392704 bytes.
+      module size is limited by the size of contiguous chunk at 1M address.
+@item mipsel-loongson (ELF), mips(el)-qemu_mips (ELF): if uncompressed:
+                kernel.img (.text + .data) + modules is limited by the space from 80200000 forward
+                if compressed:
+                kernel.img (.text + .data, uncompressed) + modules (uncompressed)
+                + (modules + kernel.img (.text + .data)) (compressed)
+                + decompressor is limited by the space from 80200000 forward
+@item mipsel-loongson (Flash), mips(el)-qemu_mips (Flash): kernel.img (.text + .data) + modules is limited by the space from 80200000 forward
+                               core.img (final) is limited by flash size (512K on yeeloong and fulooong)
+@item mips-arc: if uncompressed:
+                kernel.img (.text + .data) is limited by the space from 8bd00000 forward
+                modules + dummy decompressor  is limited by the space from 8bd00000 backward
+                if compressed:
+                kernel.img (.text + .data, uncompressed) is limited by the space from 8bd00000 forward
+                modules (uncompressed) + (modules + kernel.img (.text + .data)) (compressed, aligned to 1M)
+                + 1M (decompressor + scratch space) is limited by the space from 8bd00000 backward
+@item powerpc-ieee1275: kernel.img (.text + .data + .bss) + modules is limited by space available at 0x200000
+@end itemize
 
 @node Filesystem
 @chapter Filesystem syntax and semantics
index 48fd1a6778910d3eed740369e9c49b9047b3a1c5..bfc8f3f1260e15e45249428fc61c9bc57a72a7f7 100644 (file)
@@ -54,7 +54,8 @@ grub_exit (void)
 #ifdef GRUB_MACHINE_QEMU
 grub_addr_t grub_modbase;
 #else
-grub_addr_t grub_modbase = ALIGN_UP((grub_addr_t) _end, GRUB_KERNEL_MACHINE_MOD_ALIGN);
+grub_addr_t grub_modbase = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR;
+static grub_uint64_t modend;
 #endif
 
 /* Helper for grub_machine_init.  */
@@ -62,30 +63,32 @@ static int
 heap_init (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
           void *data __attribute__ ((unused)))
 {
+  grub_uint64_t begin = addr, end = addr + size;
+
 #if GRUB_CPU_SIZEOF_VOID_P == 4
   /* Restrict ourselves to 32-bit memory space.  */
-  if (addr > GRUB_ULONG_MAX)
+  if (begin > GRUB_ULONG_MAX)
     return 0;
-  if (addr + size > GRUB_ULONG_MAX)
-    size = GRUB_ULONG_MAX - addr;
+  if (end > GRUB_ULONG_MAX)
+    end = GRUB_ULONG_MAX;
 #endif
 
   if (type != GRUB_MEMORY_AVAILABLE)
     return 0;
 
   /* Avoid the lower memory.  */
-  if (addr < GRUB_MEMORY_MACHINE_LOWER_SIZE)
-    {
-      if (addr + size <= GRUB_MEMORY_MACHINE_LOWER_SIZE)
-       return 0;
-      else
-       {
-         size -= GRUB_MEMORY_MACHINE_LOWER_SIZE - addr;
-         addr = GRUB_MEMORY_MACHINE_LOWER_SIZE;
-       }
-    }
-
-  grub_mm_init_region ((void *) (grub_addr_t) addr, (grub_size_t) size);
+  if (begin < GRUB_MEMORY_MACHINE_LOWER_SIZE)
+    begin = GRUB_MEMORY_MACHINE_LOWER_SIZE;
+
+#ifndef GRUB_MACHINE_QEMU
+  if (modend && begin < modend)
+    begin = modend;
+#endif
+  
+  if (end <= begin)
+    return 0;
+
+  grub_mm_init_region ((void *) (grub_addr_t) begin, (grub_size_t) (end - begin));
 
   return 0;
 }
@@ -97,6 +100,9 @@ grub_machine_init (void)
   grub_modbase = grub_core_entry_addr + (_edata - _start);
 
   grub_qemu_init_cirrus ();
+#endif
+#ifndef GRUB_MACHINE_QEMU
+  modend = grub_modules_get_end ();
 #endif
   /* Initialize the console as early as possible.  */
   grub_vga_text_init ();
index 7d8b12cf9cc76f982d0232e7d141b4458fe2fb7e..730e04ac461aa15119f8066b46e9f291313bd1e3 100644 (file)
@@ -191,6 +191,7 @@ grub_machine_init (void)
 #if 0
   int grub_lower_mem;
 #endif
+  grub_addr_t modend;
 
   grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start);
 
@@ -222,8 +223,17 @@ grub_machine_init (void)
 
   compact_mem_regions ();
 
+  modend = grub_modules_get_end ();
   for (i = 0; i < num_regions; i++)
-      grub_mm_init_region ((void *) mem_regions[i].addr, mem_regions[i].size);
+    {
+      grub_addr_t beg = mem_regions[i].addr;
+      grub_addr_t fin = mem_regions[i].addr + mem_regions[i].size;
+      if (modend && beg < modend)
+       beg = modend;
+      if (beg >= fin)
+       continue;
+      grub_mm_init_region ((void *) beg, fin - beg);
+    }
 
   grub_tsc_init ();
 }
index c43ac6b7f29dda348c4e7d6b7f9f281e1893e315..e1a200166735eb30f3c29bd3e16936de33a77190 100644 (file)
 #include <grub/reader.h>
 #include <grub/parser.h>
 
-/* This is actualy platform-independant but used only on loongson and sparc.  */
-#if defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) || defined (GRUB_MACHINE_SPARC64)
+#ifdef GRUB_MACHINE_PCBIOS
+#include <grub/machine/memory.h>
+#endif
+
 grub_addr_t
 grub_modules_get_end (void)
 {
@@ -45,7 +47,6 @@ grub_modules_get_end (void)
 
   return grub_modbase + modinfo->size;
 }
-#endif
 
 /* Load all modules in core.  */
 static void
@@ -67,6 +68,8 @@ grub_load_modules (void)
   }
 }
 
+static char *load_config;
+
 static void
 grub_load_config (void)
 {
@@ -76,9 +79,17 @@ grub_load_config (void)
     /* Not an embedded config, skip.  */
     if (header->type != OBJ_TYPE_CONFIG)
       continue;
-    
-    grub_parser_execute ((char *) header +
-                        sizeof (struct grub_module_header));
+
+    load_config = grub_malloc (header->size - sizeof (struct grub_module_header) + 1);
+    if (!load_config)
+      {
+       grub_print_error ();
+       break;
+      }
+    grub_memcpy (load_config, (char *) header +
+                sizeof (struct grub_module_header),
+                header->size - sizeof (struct grub_module_header));
+    load_config[header->size - sizeof (struct grub_module_header)] = 0;
     break;
   }
 }
@@ -212,6 +223,30 @@ grub_load_normal_mode (void)
   grub_command_execute ("normal", 0, 0);
 }
 
+static void
+reclaim_module_space (void)
+{
+  grub_addr_t modstart, modend;
+
+  if (!grub_modbase)
+    return;
+
+#ifdef GRUB_MACHINE_PCBIOS
+  modstart = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR;
+#else
+  modstart = grub_modbase;
+#endif
+  modend = grub_modules_get_end ();
+  grub_modbase = 0;
+
+#if GRUB_KERNEL_PRELOAD_SPACE_REUSABLE
+  grub_mm_init_region ((void *) modstart, modend - modstart);
+#else
+  (void) modstart;
+  (void) modend;
+#endif
+}
+
 /* The main routine.  */
 void __attribute__ ((noreturn))
 grub_main (void)
@@ -224,6 +259,8 @@ grub_main (void)
   grub_printf ("Welcome to GRUB!\n\n");
   grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
 
+  grub_load_config ();
+
   /* Load pre-loaded modules and free the space.  */
   grub_register_exported_symbols ();
 #ifdef GRUB_LINKER_HAVE_INIT
@@ -237,9 +274,14 @@ grub_main (void)
   grub_env_export ("root");
   grub_env_export ("prefix");
 
+  /* Reclaim space used for modules.  */
+  reclaim_module_space ();
+
   grub_register_core_commands ();
 
-  grub_load_config ();
+  if (load_config)
+    grub_parser_execute (load_config);
+
   grub_load_normal_mode ();
   grub_rescue_run ();
 }
index 9f08e05bf5827b662abcdec34bacbe9297cf6eb8..d8690916c987ae55737db1f1aa4c011966a31c3a 100644 (file)
@@ -117,6 +117,27 @@ grub_mm_init_region (void *addr, grub_size_t size)
   grub_printf ("Using memory for heap: start=%p, end=%p\n", addr, addr + (unsigned int) size);
 #endif
 
+  for (p = &grub_mm_base, q = *p; q; p = &(q->next), q = *p)
+    if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q)
+      {
+       r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
+       *r = *q;
+       r->pre_size += size;
+       
+       if (r->pre_size >> GRUB_MM_ALIGN_LOG2)
+         {
+           h = (grub_mm_header_t) (r + 1);
+           h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2);
+           h->magic = GRUB_MM_ALLOC_MAGIC;
+           r->size += h->size << GRUB_MM_ALIGN_LOG2;
+           r->pre_size &= (GRUB_MM_ALIGN - 1);
+           *p = r;
+           grub_free (h + 1);
+         }
+       *p = r;
+       return;
+      }
+
   /* Allocate a region from the head.  */
   r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
   size -= (char *) r - (char *) addr + sizeof (*r);
index 23e4f02c05a05af355f4ce2c8c670bd8f679ce9e..73ea416563c2ec46cba9046d1811a7b887fdb790 100644 (file)
@@ -64,6 +64,29 @@ struct grub_module_info64
   grub_uint64_t size;
 };
 
+#ifndef GRUB_UTIL
+/* Space isn't reusable on some platforms.  */
+/* On Qemu the preload space is readonly.  */
+/* On emu there is no preload space.  */
+/* On ieee1275 our code assumes that heap is p=v which isn't guaranteed for module space.  */
+#if defined (GRUB_MACHINE_QEMU) || defined (GRUB_MACHINE_EMU) \
+  || defined (GRUB_MACHINE_EFI) \
+  || (defined (GRUB_MACHINE_IEEE1275) && !defined (__sparc__))
+#define GRUB_KERNEL_PRELOAD_SPACE_REUSABLE 0
+#endif
+
+#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) \
+  || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) \
+  || defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_ARC) \
+  || defined (__sparc__)
+/* FIXME: stack is between 2 heap regions. Move it.  */
+#define GRUB_KERNEL_PRELOAD_SPACE_REUSABLE 1
+#endif
+
+#ifndef GRUB_KERNEL_PRELOAD_SPACE_REUSABLE
+#error "Please check if preload space is reusable on this platform!"
+#endif
+
 #if GRUB_TARGET_SIZEOF_VOID_P == 8
 #define grub_module_info grub_module_info64
 #else
@@ -82,6 +105,8 @@ extern grub_addr_t EXPORT_VAR (grub_modbase);
 
 grub_addr_t grub_modules_get_end (void);
 
+#endif
+
 /* The start point of the C code.  */
 void grub_main (void) __attribute__ ((noreturn));
 
index d55e308c7b4fce24c927bd6640ef265615c839c7..bce755d985eaf2795de5a571f5f8f529c1caed7c 100644 (file)
@@ -91,6 +91,7 @@
 #define GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE 0x08
 
 #define GRUB_KERNEL_I386_COREBOOT_LINK_ADDR    0x8200
+#define GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR  0x100000
 
 #define GRUB_KERNEL_I386_IEEE1275_LINK_ADDR    0x10000
 
index 29bda1715d7da848b30c9d3c9aa368f1d39f9c6a..845abeda05d3d55286ff35455de3efd5683c33a4 100644 (file)
@@ -995,16 +995,42 @@ generate_image (const char *dir, const char *prefix,
     {
     case IMAGE_I386_PC:
     case IMAGE_I386_PC_PXE:
-      {
-       unsigned num;
-       char *boot_path, *boot_img;
-       size_t boot_size;
-
        if (GRUB_KERNEL_I386_PC_LINK_ADDR + core_size > 0x78000
-           || (core_size > (0xffff << GRUB_DISK_SECTOR_BITS)))
+           || (core_size > (0xffff << GRUB_DISK_SECTOR_BITS))
+           || (kernel_size + bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000))
          grub_util_error (_("core image is too big (0x%x > 0x%x)"),
                           GRUB_KERNEL_I386_PC_LINK_ADDR + core_size,
                           0x78000);
+       /* fallthrough */
+    case IMAGE_COREBOOT:
+    case IMAGE_QEMU:
+       if (kernel_size + bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000)
+         grub_util_error (_("kernel image is too big (0x%x > 0x%x)"),
+                          kernel_size + bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR,
+                          0x68000);
+       break;
+    case IMAGE_LOONGSON_ELF:
+    case IMAGE_YEELOONG_FLASH:
+    case IMAGE_FULOONG2F_FLASH:
+    case IMAGE_EFI:
+    case IMAGE_MIPS_ARC:
+    case IMAGE_QEMU_MIPS_FLASH:
+      break;
+    case IMAGE_SPARC64_AOUT:
+    case IMAGE_SPARC64_RAW:
+    case IMAGE_I386_IEEE1275:
+    case IMAGE_PPC:
+      break;
+    }
+
+  switch (image_target->id)
+    {
+    case IMAGE_I386_PC:
+    case IMAGE_I386_PC_PXE:
+      {
+       unsigned num;
+       char *boot_path, *boot_img;
+       size_t boot_size;
 
        num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
        if (image_target->id == IMAGE_I386_PC_PXE)
@@ -1615,9 +1641,12 @@ generate_image (const char *dir, const char *prefix,
            phdr->p_filesz = phdr->p_memsz
              = grub_host_to_target32 (core_size - kernel_size);
 
-           target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size
-                                        + image_target->mod_gap,
-                                        image_target->mod_align);
+           if (image_target->id == IMAGE_COREBOOT)
+             target_addr_mods = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR;
+           else
+             target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size
+                                          + image_target->mod_gap,
+                                          image_target->mod_align);
            phdr->p_vaddr = grub_host_to_target32 (target_addr_mods);
            phdr->p_paddr = grub_host_to_target32 (target_addr_mods);
            phdr->p_align = grub_host_to_target32 (image_target->link_align);