]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
boot services avoid code based on the patch by Matthew Garrett
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 3 Mar 2012 19:06:41 +0000 (20:06 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 3 Mar 2012 19:06:41 +0000 (20:06 +0100)
18 files changed:
grub-core/lib/i386/reboot.c
grub-core/lib/i386/relocator.c
grub-core/lib/relocator.c
grub-core/loader/i386/bsd.c
grub-core/loader/i386/coreboot/chainloader.c
grub-core/loader/i386/linux.c
grub-core/loader/i386/multiboot_mbi.c
grub-core/loader/i386/pc/linux.c
grub-core/loader/i386/pc/plan9.c
grub-core/loader/i386/xnu.c
grub-core/loader/multiboot.c
grub-core/loader/multiboot_elfxx.c
grub-core/loader/multiboot_mbi2.c
grub-core/loader/xnu_resume.c
grub-core/mmap/efi/mmap.c
include/grub/efi/efi.h
include/grub/i386/relocator.h
include/grub/relocator.h

index 45a2259cfdb9fed1e05cf7c3716def1142bcb91a..0587f1477984bac4f96e87500e52a1a70b4507b4 100644 (file)
@@ -38,7 +38,8 @@ grub_reboot (void)
     while (1);
   err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000, 0x1000,
                                          grub_reboot_end - grub_reboot_start,
-                                         16, GRUB_RELOCATOR_PREFERENCE_NONE);
+                                         16, GRUB_RELOCATOR_PREFERENCE_NONE,
+                                         0);
   if (err)
     while (1);
   buf = get_virtual_current_address (ch);
index 90af4035a31450005ebfb57380f697cc627fc657..df25b30fadefd642a951b00b2e129c5a3e12882c 100644 (file)
@@ -155,7 +155,8 @@ grub_cpu_relocator_forward (void *ptr, void *src, void *dest,
 
 grub_err_t
 grub_relocator32_boot (struct grub_relocator *rel,
-                      struct grub_relocator32_state state)
+                      struct grub_relocator32_state state,
+                      int avoid_efi_bootservices)
 {
   grub_err_t err;
   void *relst;
@@ -164,7 +165,8 @@ grub_relocator32_boot (struct grub_relocator *rel,
   err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
                                          (0xffffffff - RELOCATOR_SIZEOF (32))
                                          + 1, RELOCATOR_SIZEOF (32), 16,
-                                         GRUB_RELOCATOR_PREFERENCE_NONE);
+                                         GRUB_RELOCATOR_PREFERENCE_NONE,
+                                         avoid_efi_bootservices);
   if (err)
     return err;
 
@@ -207,7 +209,8 @@ grub_relocator16_boot (struct grub_relocator *rel,
                                          - GRUB_RELOCATOR16_STACK_SIZE,
                                          RELOCATOR_SIZEOF (16)
                                          + GRUB_RELOCATOR16_STACK_SIZE, 16,
-                                         GRUB_RELOCATOR_PREFERENCE_NONE);
+                                         GRUB_RELOCATOR_PREFERENCE_NONE,
+                                         0);
   if (err)
     return err;
 
@@ -261,7 +264,8 @@ grub_relocator64_boot (struct grub_relocator *rel,
   err = grub_relocator_alloc_chunk_align (rel, &ch, min_addr,
                                          max_addr - RELOCATOR_SIZEOF (64),
                                          RELOCATOR_SIZEOF (64), 16,
-                                         GRUB_RELOCATOR_PREFERENCE_NONE);
+                                         GRUB_RELOCATOR_PREFERENCE_NONE,
+                                         0);
   if (err)
     return err;
 
index b391f0575f48cb7176c4f7db7e6e39333a0f6807..aa4a39ebcf2b967aa5e6056f1d879aca8d6a0c52 100644 (file)
@@ -1319,7 +1319,8 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel,
                                  grub_phys_addr_t min_addr,
                                  grub_phys_addr_t max_addr,
                                  grub_size_t size, grub_size_t align,
-                                 int preference)
+                                 int preference,
+                                 int avoid_efi_boot_services)
 {
   grub_addr_t min_addr2 = 0, max_addr2;
   struct grub_relocator_chunk *chunk;
@@ -1406,7 +1407,12 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel,
       return 0;
     }
 
-    grub_machine_mmap_iterate (hook);
+#ifdef GRUB_MACHINE_EFI
+    grub_efi_mmap_iterate (hook, avoid_efi_boot_services);
+#else
+    (void) avoid_efi_boot_services;
+    grub_mmap_iterate (hook);
+#endif
     if (!found)
       return grub_error (GRUB_ERR_BAD_OS, "couldn't find suitable memory target");
   }
index dc05c67f5081e08dda6022dbc8d2f37c77ca7310..299cedc489191b32d807b18264794d5c5bcd1df6 100644 (file)
@@ -723,7 +723,8 @@ grub_freebsd_boot (void)
                                                0x10000, 0x90000,
                                                3 * sizeof (grub_uint32_t)
                                                + sizeof (bi), 4,
-                                               GRUB_RELOCATOR_PREFERENCE_NONE);
+                                               GRUB_RELOCATOR_PREFERENCE_NONE,
+                                               0);
        if (err)
          return err;
        stack = get_virtual_current_address (ch);
@@ -760,7 +761,8 @@ grub_freebsd_boot (void)
                                                0x10000, 0x90000,
                                                9 * sizeof (grub_uint32_t)
                                                + sizeof (bi), 4,
-                                               GRUB_RELOCATOR_PREFERENCE_NONE);
+                                               GRUB_RELOCATOR_PREFERENCE_NONE,
+                                               0);
        if (err)
          return err;
        stack = get_virtual_current_address (ch);
@@ -786,7 +788,7 @@ grub_freebsd_boot (void)
       stack[6] = stack_target + 9 * sizeof (grub_uint32_t);
       stack[7] = bi.tags;
       stack[8] = kern_end;
-      return grub_relocator32_boot (relocator, state);
+      return grub_relocator32_boot (relocator, state, 0);
     }
 
   /* Not reached.  */
@@ -873,7 +875,7 @@ grub_openbsd_boot (void)
   stack[7] = (grub_uint8_t *) curarg - (grub_uint8_t *) arg0;
   stack[8] = ((grub_uint8_t *) arg0 - (grub_uint8_t *) buf0) + buf_target;
 
-  return grub_relocator32_boot (relocator, state);
+  return grub_relocator32_boot (relocator, state, 0);
 }
 
 static grub_err_t
@@ -1144,7 +1146,8 @@ grub_netbsd_boot (void)
     grub_relocator_chunk_t ch;
     err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x10000, 0x90000,
                                            7 * sizeof (grub_uint32_t), 4,
-                                           GRUB_RELOCATOR_PREFERENCE_NONE);
+                                           GRUB_RELOCATOR_PREFERENCE_NONE,
+                                           0);
     if (err)
       return err;
     stack = get_virtual_current_address (ch);
@@ -1168,7 +1171,7 @@ grub_netbsd_boot (void)
   stack[5] = grub_mmap_get_upper () >> 10;
   stack[6] = grub_mmap_get_lower () >> 10;
 
-  return grub_relocator32_boot (relocator, state);
+  return grub_relocator32_boot (relocator, state, 0);
 }
 
 static grub_err_t
index a66033b9a0ca7561de0cbf16afced6cf4afb3a68..df4e276fd0eb47485904a100927cffc34d2ffb4d 100644 (file)
@@ -43,7 +43,7 @@ grub_chain_boot (void)
   grub_video_set_mode ("text", 0, 0);
 
   state.eip = entry;
-  return grub_relocator32_boot (relocator, state);
+  return grub_relocator32_boot (relocator, state, 0);
 }
 
 static grub_err_t
index e2a988a50e49c17bff3254b10e39188a02d31d24..15f4bac3a63ea40931c33a78abe3f91d997722c8 100644 (file)
@@ -189,7 +189,9 @@ free_pages (void)
 /* Allocate pages for the real mode code and the protected mode code
    for linux as well as a memory map buffer.  */
 static grub_err_t
-allocate_pages (grub_size_t prot_size)
+allocate_pages (grub_size_t prot_size, grub_size_t *align,
+               grub_size_t min_align, int relocatable,
+               grub_uint64_t prefered_address)
 {
   grub_size_t real_size, mmap_size;
   grub_err_t err;
@@ -254,7 +256,11 @@ allocate_pages (grub_size_t prot_size)
 
       return 0;
     }
+#ifdef GRUB_MACHINE_EFI
+  grub_efi_mmap_iterate (hook, 1);
+#else
   grub_mmap_iterate (hook);
+#endif
   if (! real_mode_target)
     {
       err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
@@ -273,15 +279,36 @@ allocate_pages (grub_size_t prot_size)
   }
   efi_mmap_buf = (grub_uint8_t *) real_mode_mem + real_size + mmap_size;
 
-  prot_mode_target = GRUB_LINUX_BZIMAGE_ADDR;
-
   {
     grub_relocator_chunk_t ch;
-    err = grub_relocator_alloc_chunk_addr (relocator, &ch,
-                                          prot_mode_target, prot_size);
+    if (relocatable)
+      {
+       err = grub_relocator_alloc_chunk_align (relocator, &ch,
+                                               prefered_address,
+                                               prefered_address,
+                                               prot_size, 1,
+                                               GRUB_RELOCATOR_PREFERENCE_LOW,
+                                               1);
+       for (; err && *align >= min_align; (*align)--)
+         {
+           grub_errno = GRUB_ERR_NONE;
+           err = grub_relocator_alloc_chunk_align (relocator, &ch,
+                                                   0x1000000, 0xffffffff,
+                                                   prot_size, 1 << *align,
+                                                   GRUB_RELOCATOR_PREFERENCE_LOW,
+                                                   1);
+         }
+       if (err)
+         goto fail;
+      }
+    else
+      err = grub_relocator_alloc_chunk_addr (relocator, &ch,
+                                            prefered_address,
+                                            prot_size);
     if (err)
       goto fail;
     prot_mode_mem = get_virtual_current_address (ch);
+    prot_mode_target = get_physical_target_address (ch);
   }
 
   grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, "
@@ -612,7 +639,7 @@ grub_linux_boot (void)
   state.esi = real_mode_target;
   state.esp = real_mode_target;
   state.eip = params->code32_start;
-  return grub_relocator32_boot (relocator, state);
+  return grub_relocator32_boot (relocator, state, 0);
 }
 
 static grub_err_t
@@ -634,6 +661,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   grub_size_t real_size, prot_size;
   grub_ssize_t len;
   int i;
+  grub_size_t align, min_align;
+  int relocatable;
+  grub_uint64_t preffered_address = GRUB_LINUX_BZIMAGE_ADDR;
 
   grub_dl_ref (my_mod);
 
@@ -707,7 +737,37 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
   prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
 
-  if (allocate_pages (prot_size))
+  if (grub_le_to_cpu16 (lh.version) >= 0x205
+      && lh.kernel_alignment != 0
+      && ((lh.kernel_alignment - 1) & lh.kernel_alignment) == 0)
+    {
+      for (align = 0; align < 32; align++)
+       if (grub_le_to_cpu32 (lh.kernel_alignment) & (1 << align))
+         break;
+      relocatable = grub_le_to_cpu32 (lh.relocatable);
+    }
+  else
+    {
+      align = 0;
+      relocatable = 0;
+    }
+    
+  if (grub_le_to_cpu16 (lh.version) >= 0x020a)
+    {
+      min_align = lh.min_alignment;
+      prot_size = grub_le_to_cpu32 (lh.init_size);
+      preffered_address = grub_le_to_cpu64 (lh.pref_address);
+    }
+  else
+    {
+      min_align = 0;
+      prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
+      preffered_address = grub_le_to_cpu32 (lh.code32_start);
+    }
+
+  if (allocate_pages (prot_size, &align,
+                     min_align, relocatable,
+                     preffered_address))
     goto fail;
 
   params = (struct linux_kernel_params *) real_mode_mem;
@@ -1021,7 +1081,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
     grub_relocator_chunk_t ch;
     err = grub_relocator_alloc_chunk_align (relocator, &ch,
                                            addr_min, addr, size, 0x1000,
-                                           GRUB_RELOCATOR_PREFERENCE_HIGH);
+                                           GRUB_RELOCATOR_PREFERENCE_HIGH,
+                                           1);
     if (err)
       return err;
     initrd_mem = get_virtual_current_address (ch);
index e41a4d89559f1024c83a252133dd6745ed52f6a2..8fc40d71332c14fc0a50fba30fc1c0c104dc246c 100644 (file)
@@ -454,7 +454,7 @@ grub_multiboot_make_mbi (grub_uint32_t *target)
   err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch,
                                          0x10000, 0x100000 - bufsize,
                                          bufsize, 4,
-                                         GRUB_RELOCATOR_PREFERENCE_NONE);
+                                         GRUB_RELOCATOR_PREFERENCE_NONE, 0);
   if (err)
     return err;
   ptrorig = get_virtual_current_address (ch);
index dfa6e6f30d665ee204533453c679362c9aa5de9c..90497c0ccb59e4b94c98b3203eae468e7becdc07 100644 (file)
@@ -429,7 +429,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
     err = grub_relocator_alloc_chunk_align (relocator, &ch,
                                            addr_min, addr_max - size,
                                            size, 0x1000,
-                                           GRUB_RELOCATOR_PREFERENCE_HIGH);
+                                           GRUB_RELOCATOR_PREFERENCE_HIGH, 0);
     if (err)
       return err;
     initrd_chunk = get_virtual_current_address (ch);
index 1c021b22b8ed35c2166b3dc88fddd95a66556d62..b41dfd29f2ef31c44e0ca74d826fe9c08b6d1c87 100644 (file)
@@ -90,7 +90,7 @@ grub_plan9_boot (void)
   };
   grub_video_set_mode ("text", 0, 0);
 
-  return grub_relocator32_boot (rel, state);
+  return grub_relocator32_boot (rel, state, 0);
 }
 
 static grub_err_t
index 7fcb6e11abc33a15893076cbcfd8ffd82d4c7228..0e4d38f4fc743c4afedbf582a5cc9b0afbd17e6e 100644 (file)
@@ -842,7 +842,7 @@ grub_xnu_boot_resume (void)
   state.eip = grub_xnu_entry_point;
   state.eax = grub_xnu_arg1;
 
-  return grub_relocator32_boot (grub_xnu_relocator, state); 
+  return grub_relocator32_boot (grub_xnu_relocator, state, 0); 
 }
 
 /* Setup video for xnu. */
@@ -1150,7 +1150,7 @@ grub_xnu_boot (void)
   grub_outb (0xff, 0x21);
   grub_outb (0xff, 0xa1);
 
-  return grub_relocator32_boot (grub_xnu_relocator, state);
+  return grub_relocator32_boot (grub_xnu_relocator, state, 0);
 }
 
 static grub_command_t cmd_devprop_load;
index f656cf530285ab3706bac35dd7346cd27d9249d5..dd5057241a0e1145ab9d9c9356ac9551deb51dae 100644 (file)
@@ -134,7 +134,7 @@ grub_multiboot_boot (void)
     return err;
 #endif
 
-  grub_relocator32_boot (grub_multiboot_relocator, state);
+  grub_relocator32_boot (grub_multiboot_relocator, state, 0);
 
   /* Not reached.  */
   return GRUB_ERR_NONE;
@@ -307,7 +307,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
     err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch,
                                            0, (0xffffffff - size) + 1,
                                            size, MULTIBOOT_MOD_ALIGN,
-                                           GRUB_RELOCATOR_PREFERENCE_NONE);
+                                           GRUB_RELOCATOR_PREFERENCE_NONE, 0);
     if (err)
       {
        grub_file_close (file);
index f38f37262243ca337c43e476d9275d48d1fdc1f8..26984f49adcd051c3a3fbb3ac5d347e84914e7e8 100644 (file)
@@ -200,7 +200,8 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, const char *filename, voi
                                                    (0xffffffff - sh->sh_size)
                                                    + 1, sh->sh_size,
                                                    sh->sh_addralign,
-                                                   GRUB_RELOCATOR_PREFERENCE_NONE);
+                                                   GRUB_RELOCATOR_PREFERENCE_NONE,
+                                                   0);
            if (err)
              {
                grub_dprintf ("multiboot_loader", "Error loading shdr %d\n", i);
index 62510288c45b90470834f126d2a2ca5c5b9e4ddb..a48f020761f5ef55c27c02008743ae1700e5ea77 100644 (file)
@@ -588,7 +588,7 @@ grub_multiboot_make_mbi (grub_uint32_t *target)
   err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch,
                                          0, 0xffffffff - bufsize,
                                          bufsize, MULTIBOOT_TAG_ALIGN,
-                                         GRUB_RELOCATOR_PREFERENCE_NONE);
+                                         GRUB_RELOCATOR_PREFERENCE_NONE, 0);
   if (err)
     return err;
 
index d7f9adaafb0252baf2746fc027e6e880c32fc843..e99ea142e4735b23e8deca69e7ca54d56f0b620a 100644 (file)
@@ -125,7 +125,7 @@ grub_xnu_resume (char *imagename)
                                            (0xffffffff - hibhead.image_size) + 1,
                                            hibhead.image_size,
                                            GRUB_XNU_PAGESIZE,
-                                           GRUB_RELOCATOR_PREFERENCE_NONE);
+                                           GRUB_RELOCATOR_PREFERENCE_NONE, 0);
     if (err)
       {
        grub_file_close (file);
index 7735597533e22dff94bf9a56625911eb1724a6e5..a34a7ac5394468b6e50f7cebe66581ae69988f7e 100644 (file)
@@ -29,7 +29,7 @@
   ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
 
 grub_err_t
-grub_machine_mmap_iterate (grub_memory_hook_t hook)
+grub_efi_mmap_iterate (grub_memory_hook_t hook, int avoid_efi_boot_services)
 {
   grub_efi_uintn_t mmap_size = 0;
   grub_efi_memory_descriptor_t *map_buf = 0;
@@ -65,6 +65,13 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook)
                    + desc->num_pages * 4096, desc->type);
       switch (desc->type)
        {
+       case GRUB_EFI_BOOT_SERVICES_CODE:
+         if (!avoid_efi_boot_services)
+           {
+             hook (desc->physical_start, desc->num_pages * 4096,
+                   GRUB_MEMORY_AVAILABLE);
+             break;
+           }
        case GRUB_EFI_RUNTIME_SERVICES_CODE:
          hook (desc->physical_start, desc->num_pages * 4096,
                GRUB_MEMORY_CODE);
@@ -79,6 +86,13 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook)
          grub_printf ("Unknown memory type %d, considering reserved\n",
                       desc->type);
 
+       case GRUB_EFI_BOOT_SERVICES_DATA:
+         if (!avoid_efi_boot_services)
+           {
+             hook (desc->physical_start, desc->num_pages * 4096,
+                   GRUB_MEMORY_AVAILABLE);
+             break;
+           }
        case GRUB_EFI_RESERVED_MEMORY_TYPE:
        case GRUB_EFI_RUNTIME_SERVICES_DATA:
        case GRUB_EFI_MEMORY_MAPPED_IO:
@@ -90,8 +104,6 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook)
 
        case GRUB_EFI_LOADER_CODE:
        case GRUB_EFI_LOADER_DATA:
-       case GRUB_EFI_BOOT_SERVICES_CODE:
-       case GRUB_EFI_BOOT_SERVICES_DATA:
        case GRUB_EFI_CONVENTIONAL_MEMORY:
          hook (desc->physical_start, desc->num_pages * 4096,
                GRUB_MEMORY_AVAILABLE);
@@ -112,6 +124,12 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook)
   return GRUB_ERR_NONE;
 }
 
+grub_err_t
+grub_machine_mmap_iterate (grub_memory_hook_t hook, int avoid_efi_boot_services)
+{
+  return grub_efi_mmap_iterate (hook, 0);
+}
+
 static inline grub_efi_memory_type_t
 make_efi_memtype (int type)
 {
index 067e3bdacc22113c24fd10469a97614548f335c2..811dc3d6c94aa5be462f06ebe71e4c739546d82b 100644 (file)
@@ -85,4 +85,7 @@ extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle);
 
 extern int EXPORT_VAR(grub_efi_is_finished);
 
+grub_err_t
+grub_efi_mmap_iterate (grub_memory_hook_t hook, int avoid_efi_boot_services);
+
 #endif /* ! GRUB_EFI_EFI_HEADER */
index b2fe900b6d0bc3e1c0b22a7be6cf10e163d4ea02..46becb8ea4451de878f31426e25393e7a011b6f4 100644 (file)
@@ -68,7 +68,8 @@ grub_err_t grub_relocator16_boot (struct grub_relocator *rel,
                                  struct grub_relocator16_state state);
 
 grub_err_t grub_relocator32_boot (struct grub_relocator *rel,
-                                 struct grub_relocator32_state state);
+                                 struct grub_relocator32_state state,
+                                 int avoid_efi_bootservices);
 
 grub_err_t grub_relocator64_boot (struct grub_relocator *rel,
                                  struct grub_relocator64_state state,
index 653a00eba7d88202410829093bb272ee705d9015..24d8672d22c4c539a127633fd182adeb6c9b0b9d 100644 (file)
@@ -46,7 +46,8 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel,
                                  grub_phys_addr_t min_addr,
                                  grub_phys_addr_t max_addr,
                                  grub_size_t size, grub_size_t align,
-                                 int preference);
+                                 int preference,
+                                 int avoid_efi_boot_services);
 
 #define GRUB_RELOCATOR_PREFERENCE_NONE 0
 #define GRUB_RELOCATOR_PREFERENCE_LOW 1