]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
EFI requests support for newreloc
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 20 Apr 2010 16:08:26 +0000 (18:08 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 20 Apr 2010 16:08:26 +0000 (18:08 +0200)
12 files changed:
conf/i386.rmk
include/grub/efi/efi.h
include/grub/relocator_private.h
kern/efi/efi.c
kern/efi/mm.c
lib/efi/relocator.c [new file with mode: 0644]
lib/relocator.c
loader/i386/bsd.c
loader/i386/linux.c
loader/i386/xnu.c
loader/multiboot.c
term/efi/console.c

index e223694df7bb8aeaf839eb4fb74d4ce791205674..e04d73d61de02cc122a6d69a11256924504d2e8c 100644 (file)
@@ -22,10 +22,17 @@ relocator_mod_SOURCES = lib/relocator.c lib/i386/relocator32.S \
        lib/$(target_cpu)/relocator_asm.S lib/i386/relocator.c \
        lib/ieee1275/relocator.c
 else
+ifeq ($(platform), efi)
+relocator_mod_SOURCES = lib/relocator.c lib/i386/relocator32.S \
+       lib/i386/relocator64.S lib/i386/relocator16.S \
+       lib/$(target_cpu)/relocator_asm.S lib/i386/relocator.c \
+       lib/efi/relocator.c
+else
 relocator_mod_SOURCES = lib/relocator.c lib/i386/relocator32.S \
        lib/i386/relocator64.S lib/i386/relocator16.S \
        lib/$(target_cpu)/relocator_asm.S lib/i386/relocator.c
 endif
+endif
 relocator_mod_CFLAGS = $(COMMON_CFLAGS)
 relocator_mod_ASFLAGS = $(COMMON_ASFLAGS)
 relocator_mod_LDFLAGS = $(COMMON_LDFLAGS)
index 5852a476f033808a55e99657299bdf4695b9b79a..a56b3f56b6fe33019557bd0dac3888736f3d2060 100644 (file)
@@ -53,8 +53,10 @@ void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp);
 char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp);
 grub_efi_device_path_t *
 EXPORT_FUNC(grub_efi_get_device_path) (grub_efi_handle_t handle);
-int EXPORT_FUNC(grub_efi_exit_boot_services) (grub_efi_uintn_t map_key);
-int EXPORT_FUNC (grub_efi_finish_boot_services) (void);
+grub_err_t EXPORT_FUNC (grub_efi_finish_boot_services) (grub_size_t *outbuf_size, void *outbuf,
+                                                       grub_efi_uintn_t *map_key,
+                                                       grub_efi_uintn_t *efi_desc_size,
+                                                       grub_efi_uint32_t *efi_desc_version);
 grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memory_map_size,
                                                           grub_efi_uintn_t descriptor_size,
                                                           grub_efi_uint32_t descriptor_version,
@@ -70,4 +72,6 @@ void grub_efi_set_prefix (void);
 extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table);
 extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle);
 
+extern int EXPORT_VAR(grub_efi_is_finished);
+
 #endif /* ! GRUB_EFI_EFI_HEADER */
index c526b0b0c8d44b68367d29fcb16faca7342c44b4..8398defbda9fe9205bd9cc3b7dd7b9d6ce29c3bf 100644 (file)
@@ -41,10 +41,18 @@ void grub_cpu_relocator_jumper (void *rels, grub_addr_t addr);
 
 #ifdef GRUB_MACHINE_IEEE1275
 #define GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS 1
+#define GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT_LOG 0
+#elif defined (GRUB_MACHINE_EFI)
+#define GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS 1
+#define GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT_LOG 12
 #else
 #define GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS 0
 #endif
 
+#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
+#define GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT (1 << GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT_LOG)
+#endif
+
 struct grub_relocator_mmap_event
 {
   enum {
index d8b22553545ee4afdd1d32a9f444da15f337ba5b..4916a0d1868dde1a3dae2fb72c3c2759b17938ca 100644 (file)
@@ -181,17 +181,6 @@ grub_halt (void)
               GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL);
 }
 
-int
-grub_efi_exit_boot_services (grub_efi_uintn_t map_key)
-{
-  grub_efi_boot_services_t *b;
-  grub_efi_status_t status;
-
-  b = grub_efi_system_table->boot_services;
-  status = efi_call_2 (b->exit_boot_services, grub_efi_image_handle, map_key);
-  return status == GRUB_EFI_SUCCESS;
-}
-
 grub_err_t
 grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
                                  grub_efi_uintn_t descriptor_size,
@@ -758,26 +747,3 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
       dp = (grub_efi_device_path_t *) ((char *) dp + len);
     }
 }
-
-int
-grub_efi_finish_boot_services (void)
-{
-  grub_efi_uintn_t mmap_size = 0;
-  grub_efi_uintn_t map_key;
-  grub_efi_uintn_t desc_size;
-  grub_efi_uint32_t desc_version;
-  void *mmap_buf = 0;
-
-  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
-                              &desc_size, &desc_version) < 0)
-    return 0;
-
-  mmap_buf = grub_malloc (mmap_size);
-
-  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
-                              &desc_size, &desc_version) <= 0)
-    return 0;
-
-  return grub_efi_exit_boot_services (map_key);
-}
-
index ceb8fc9baf2f90e9646f7eafa4afaabfd8708cba..4db0e7e928ef754f7d5c1276c47fc148cccd7493 100644 (file)
@@ -49,6 +49,12 @@ static struct allocated_page *allocated_pages = 0;
 #define MIN_HEAP_SIZE  0x100000
 #define MAX_HEAP_SIZE  (1600 * 0x100000)
 
+static void *finish_mmap_buf = 0;
+static grub_efi_uintn_t finish_mmap_size = 0;
+static grub_efi_uintn_t finish_key = 0;
+static grub_efi_uintn_t finish_desc_size;
+static grub_efi_uint32_t finish_desc_version;
+int grub_efi_is_finished = 0;
 
 /* Allocate pages. Return the pointer to the first of allocated pages.  */
 void *
@@ -140,6 +146,51 @@ grub_efi_free_pages (grub_efi_physical_address_t address,
   efi_call_2 (b->free_pages, address, pages);
 }
 
+grub_err_t
+grub_efi_finish_boot_services (grub_size_t *outbuf_size, void *outbuf,
+                              grub_efi_uintn_t *map_key,
+                              grub_efi_uintn_t *efi_desc_size,
+                              grub_efi_uint32_t *efi_desc_version)
+{
+  grub_efi_boot_services_t *b;
+  grub_efi_status_t status;
+
+  if (grub_efi_get_memory_map (&finish_mmap_size, finish_mmap_buf, &finish_key,
+                              &finish_desc_size, &finish_desc_version) < 0)
+    return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map");
+
+  if (outbuf && *outbuf_size < finish_mmap_size)
+    return grub_error (GRUB_ERR_IO, "memory map buffer is too small");
+
+  finish_mmap_buf = grub_malloc (finish_mmap_size);
+  if (!finish_mmap_buf)
+    return grub_errno;
+
+  if (grub_efi_get_memory_map (&finish_mmap_size, finish_mmap_buf, &finish_key,
+                              &finish_desc_size, &finish_desc_version) <= 0)
+    return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map");
+
+  b = grub_efi_system_table->boot_services;
+  status = efi_call_2 (b->exit_boot_services, grub_efi_image_handle,
+                      finish_key);
+  if (status != GRUB_EFI_SUCCESS)
+    return grub_error (GRUB_ERR_IO, "couldn't terminate EFI services");
+
+  grub_efi_is_finished = 1;
+  if (outbuf_size)
+    *outbuf_size = finish_mmap_size;
+  if (outbuf)
+    grub_memcpy (outbuf, finish_mmap_buf, finish_mmap_size);
+  if (map_key)
+    *map_key = finish_key;
+  if (efi_desc_size)
+    *efi_desc_size = finish_desc_size;
+  if (efi_desc_version)
+    *efi_desc_version = finish_desc_version;
+
+  return GRUB_ERR_NONE;
+}
+
 /* Get the memory map as defined in the EFI spec. Return 1 if successful,
    return 0 if partial, or return -1 if an error occurs.  */
 int
@@ -154,6 +205,29 @@ grub_efi_get_memory_map (grub_efi_uintn_t *memory_map_size,
   grub_efi_uintn_t key;
   grub_efi_uint32_t version;
 
+  if (grub_efi_is_finished)
+    {
+      int ret = 1;
+      if (*memory_map_size < finish_mmap_size)
+       {
+         grub_memcpy (memory_map, finish_mmap_buf, *memory_map_size);
+         ret = 0;
+       }
+      else
+       {
+         grub_memcpy (memory_map, finish_mmap_buf, finish_mmap_size);
+         ret = 1;
+       }
+      *memory_map_size = finish_mmap_size;
+      if (map_key)
+       *map_key = finish_key;
+      if (descriptor_size)
+       *descriptor_size = finish_desc_size;
+      if (descriptor_version)
+       *descriptor_version = finish_desc_version;
+      return ret;
+    }
+
   /* Allow some parameters to be missing.  */
   if (! map_key)
     map_key = &key;
diff --git a/lib/efi/relocator.c b/lib/efi/relocator.c
new file mode 100644 (file)
index 0000000..fc4de83
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2010  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/relocator.h>
+#include <grub/relocator_private.h>
+#include <grub/memory.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+#include <grub/term.h>
+
+#define NEXT_MEMORY_DESCRIPTOR(desc, size)     \
+  ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
+
+unsigned 
+grub_relocator_firmware_get_max_events (void)
+{
+  grub_efi_uintn_t mmapsize = 0, descriptor_size = 0;
+  grub_efi_uint32_t descriptor_version = 0;
+  grub_efi_uintn_t key;
+  grub_efi_get_memory_map (&mmapsize, NULL, &key, &descriptor_size,
+                          &descriptor_version);
+  /* Since grub_relocator_firmware_fill_events uses malloc
+     we need some reserve. Hence +10.  */
+  return 2 * (mmapsize / descriptor_size + 10);
+}
+
+unsigned 
+grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events)
+{
+  grub_efi_uintn_t mmapsize = 0, desc_size = 0;
+  grub_efi_uint32_t descriptor_version = 0;
+  grub_efi_memory_descriptor_t *descs = NULL;
+  grub_efi_uintn_t key;
+  int counter = 0;
+  grub_efi_memory_descriptor_t *desc;
+
+  grub_efi_get_memory_map (&mmapsize, NULL, &key, &desc_size,
+                          &descriptor_version);
+  descs = grub_malloc (mmapsize);
+  if (!descs)
+    return 0;
+
+  grub_efi_get_memory_map (&mmapsize, descs, &key, &desc_size,
+                          &descriptor_version);
+
+  for (desc = descs;
+       (char *) desc < ((char *) descs + mmapsize);
+       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
+    {
+      if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY)
+       continue;
+      events[counter].type = REG_FIRMWARE_START;
+      events[counter].pos = desc->physical_start;
+      counter++;
+      events[counter].type = REG_FIRMWARE_END;
+      events[counter].pos = desc->physical_start + (desc->num_pages << 12);
+      counter++;      
+    }
+
+  return counter;
+}
+
+int
+grub_relocator_firmware_alloc_region (grub_addr_t start, grub_size_t size)
+{
+  grub_efi_boot_services_t *b;
+  grub_efi_physical_address_t address = start;
+  grub_efi_status_t status;
+
+  if (grub_efi_is_finished)
+    return 1;
+
+  b = grub_efi_system_table->boot_services;
+  status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ADDRESS,
+                      GRUB_EFI_LOADER_DATA, size >> 12, &address);
+  return (status == GRUB_EFI_SUCCESS);
+}
+
+void
+grub_relocator_firmware_free_region (grub_addr_t start, grub_size_t size)
+{
+  grub_efi_boot_services_t *b;
+
+  if (grub_efi_is_finished)
+    return;
+
+  b = grub_efi_system_table->boot_services;
+  efi_call_2 (b->free_pages, start, size >> 12);
+}
index 4f37fb43520f855d4b94486cc0040b3ce0a3dfbe..de4cca6264a289a8036cf6014d15021ff65394d7 100644 (file)
@@ -42,6 +42,7 @@ struct grub_relocator_subchunk
   grub_addr_t start;
   grub_size_t size;
   struct grub_relocator_extra_block *extra;
+  struct grub_relocator_fw_leftover *pre, *post;
 };
 
 struct grub_relocator_chunk
@@ -62,6 +63,15 @@ struct grub_relocator_extra_block
   grub_addr_t end;
 };
 
+struct grub_relocator_fw_leftover
+{
+  struct grub_relocator_fw_leftover *next;
+  struct grub_relocator_fw_leftover **prev;
+  grub_addr_t quantstart;
+  grub_uint8_t freebytes[GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT / 8];
+};
+
+struct grub_relocator_fw_leftover *leftovers;
 struct grub_relocator_extra_block *extra_blocks;
 
 struct grub_relocator *
@@ -159,7 +169,6 @@ allocate_regstart (grub_addr_t addr, grub_size_t size, grub_mm_region_t rb,
       while (h != newreg->first);
     }
   }
-
 }
 
 static void
@@ -211,6 +220,20 @@ allocate_inreg (grub_addr_t addr, grub_size_t size,
     }
 }
 
+static void
+check_leftover (struct grub_relocator_fw_leftover *lo)
+{
+  unsigned i;
+  for (i = 0; i < sizeof (lo->freebytes); i++)
+    if (lo->freebytes[i] != 0xff)
+      return;
+  grub_relocator_firmware_free_region (lo->quantstart,
+                                      GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT);
+  *lo->prev = lo->next;
+  if (lo->next)
+    lo->next->prev = lo->prev;
+}
+
 static void
 free_subchunk (const struct grub_relocator_subchunk *subchu)
 {
@@ -311,9 +334,34 @@ free_subchunk (const struct grub_relocator_subchunk *subchu)
       }
 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
     case CHUNK_TYPE_FIRMWARE:
-      grub_relocator_firmware_free_region (subchu->start, subchu->size);
-      *curschu->extra->prev = curschu->extra->next;
-      grub_free (curschu->extra);
+      {
+       grub_addr_t fstart, fend;
+       fstart = ALIGN_UP (subchu->start,
+                          GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT);
+       fend = ALIGN_DOWN (subchu->start + subchu->size,
+                          GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT);
+       if (fstart < fend)
+         grub_relocator_firmware_free_region (fstart, fend - fstart);
+       if (subchu->pre)
+         {
+           int off = subchu->start - fstart
+             - GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT;
+           grub_memset (subchu->pre->freebytes + off / 8 + 1,
+                        0xff, sizeof (subchu->pre->freebytes) - off / 8 - 1);
+           subchu->pre->freebytes[off / 8] |= ~((1 << (off % 8)) - 1);
+           check_leftover (subchu->pre);
+         }
+       if (subchu->post)
+         {
+           int off = subchu->start + subchu->size - fend;
+           grub_memset (subchu->pre->freebytes,
+                        0xff, sizeof (subchu->pre->freebytes) - off / 8);
+           subchu->pre->freebytes[off / 8] |= ((1 << (8 - (off % 8))) - 1);
+           check_leftover (subchu->post);
+         }
+       *subchu->extra->prev = subchu->extra->next;
+       grub_free (subchu->extra);
+      }
       break;
 #endif
     }  
@@ -406,7 +454,7 @@ malloc_in_range (struct grub_relocator *rel,
 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
   for (r = grub_mm_base; r; r = r->next)
     {
-      grub_dprintf ("relocator", "Blocking at 0x%x-0x%x\n",
+      grub_dprintf ("relocator", "Blocking at 0x%lx-0x%lx\n",
                    (grub_addr_t) r - r->pre_size, 
                    (grub_addr_t) (r + 1) + r->size);
       events[N].type = FIRMWARE_BLOCK_START;
@@ -420,7 +468,7 @@ malloc_in_range (struct grub_relocator *rel,
     struct grub_relocator_extra_block *cur;
     for (cur = extra_blocks; cur; cur = cur->next)
       {
-       grub_dprintf ("relocator", "Blocking at 0x%x-0x%x\n",
+       grub_dprintf ("relocator", "Blocking at 0x%lx-0x%lx\n",
                      cur->start, cur->end);
        events[N].type = FIRMWARE_BLOCK_START;
        events[N].pos = cur->start;
@@ -432,6 +480,10 @@ malloc_in_range (struct grub_relocator *rel,
   }
 #endif
 
+#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
+  N += grub_relocator_firmware_fill_events (events + N);
+#endif
+
   /* No malloc from this point.  */
   base_saved = grub_mm_base;
   grub_mm_base = NULL;
@@ -475,10 +527,6 @@ malloc_in_range (struct grub_relocator *rel,
       while (pa != r->first);
     }
 
-#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
-  N += grub_relocator_firmware_fill_events (events + N);
-#endif
-
   /* Put ending events after starting events.  */
   {
     int st = 0, e = N / 2;
@@ -654,17 +702,26 @@ malloc_in_range (struct grub_relocator *rel,
                    break;
 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
                  case CHUNK_TYPE_FIRMWARE:
-                   /* The failure here can be very expensive.  */
-                   if (!grub_relocator_firmware_alloc_region (alloc_start, 
-                                                              alloc_end - alloc_start))
-                     {
-                       if (from_low_priv)
-                         start = alloc_end;
-                       else
-                         end = alloc_start;
-                       goto retry;
-                     }
-                   break;
+                   {
+                     grub_addr_t fstart, fend;
+                     fstart
+                       = ALIGN_DOWN (alloc_start,
+                                     GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT);
+                     fend
+                       = ALIGN_UP (alloc_end,
+                                   GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT);
+                     /* The failure here can be very expensive.  */
+                     if (!grub_relocator_firmware_alloc_region (fstart, 
+                                                                fend - fstart))
+                       {
+                         if (from_low_priv)
+                           start = fend;
+                         else
+                           end = fstart;
+                         goto retry;
+                       }
+                     break;
+                   }
 #endif
                  }
                nallocs++;
@@ -736,7 +793,6 @@ malloc_in_range (struct grub_relocator *rel,
   /* Malloc is available again.  */
   grub_mm_base = base_saved;
 
-
   {
     int last_start = 0;
     int inreg = 0, regbeg = 0, ncol = 0;
@@ -784,8 +840,6 @@ malloc_in_range (struct grub_relocator *rel,
                curschu->start = alloc_start;
                curschu->size = alloc_end - alloc_start;
                if (typepre == CHUNK_TYPE_REGION_START)
-                 curschu->host_start = (grub_addr_t) events[last_start].reg;
-#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
                if (!oom && (typepre == CHUNK_TYPE_REGION_START
                             || typepre == CHUNK_TYPE_FIRMWARE))
                  {
@@ -807,6 +861,76 @@ malloc_in_range (struct grub_relocator *rel,
                        curschu->extra = ne;
                      }
                  }
+#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
+               if (!oom && typepre == CHUNK_TYPE_FIRMWARE)
+                   {
+                     grub_addr_t fstart, fend;
+                     struct grub_relocator_fw_leftover *lo1 = NULL;
+                     struct grub_relocator_fw_leftover *lo2 = NULL;
+
+                     fstart
+                       = ALIGN_DOWN (alloc_start,
+                                     GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT);
+                     fend
+                       = ALIGN_UP (alloc_end,
+                                   GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT);
+
+                     if (fstart != alloc_start)
+                       lo1 = grub_malloc (sizeof (*lo1));
+                     if (fend != alloc_end)
+                       lo2 = grub_malloc (sizeof (*lo2));
+                     if ((!lo1 && fstart != alloc_start)
+                         || (!lo2 && fend != alloc_end))
+                       {
+                         struct grub_relocator_extra_block *ne;
+                         grub_free (lo1);
+                         grub_free (lo2);
+                         lo1 = NULL;
+                         lo2 = NULL;
+                         oom = 1;
+                         grub_memcpy (&tofree, curschu, sizeof (tofree));
+                         ne = extra_blocks;
+                         extra_blocks = extra_blocks->next;
+                         grub_free (ne);
+                       }
+                     if (lo1)
+                       {
+                         lo1->quantstart = fstart;
+                         grub_memset (lo1->freebytes, 0xff,
+                                      (alloc_start - fstart) / 8);
+                         lo1->freebytes[(alloc_start - fstart) / 8]
+                           = (1 << ((alloc_start - fstart) % 8)) - 1;
+                         grub_memset (lo1->freebytes
+                                      + ((alloc_start - fstart) / 8) + 1, 0,
+                                      sizeof (lo1->freebytes)
+                                      - (alloc_start - fstart) / 8 - 1);
+                         lo1->next = leftovers;
+                         lo1->prev = &leftovers;
+                         if (leftovers)
+                           leftovers->prev = &lo1->next;
+                         leftovers = lo1;
+                       }
+                     if (lo2)
+                       {
+                         lo2->quantstart
+                           = fend - GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT;
+                         grub_memset (lo2->freebytes, 0,
+                                      (alloc_end - lo2->quantstart) / 8);
+                         lo2->freebytes[(alloc_end - lo2->quantstart) / 8]
+                           = ~((1 << ((alloc_end - lo2->quantstart) % 8)) - 1);
+                         grub_memset (lo2->freebytes
+                                      + ((alloc_end - lo2->quantstart) / 8)
+                                      + 1, 0, sizeof (lo2->freebytes)
+                                      - (alloc_end - lo2->quantstart) / 8 - 1);
+                         lo2->prev = &leftovers;
+                         if (leftovers)
+                           leftovers->prev = &lo2->next;
+                         lo2->next = leftovers;
+                         leftovers = lo2;
+                       }
+                     curschu->pre = lo1;
+                     curschu->post = lo2;
+                   }
 #endif
                if (!oom)
                  cural++;
@@ -814,7 +938,7 @@ malloc_in_range (struct grub_relocator *rel,
                  free_subchunk (&tofree);
              }
          }
-         
+
        switch (events[j].type)
          {
          case REG_BEG_START:
index f50e94f987c7afaf676c73ca5e65cfb3964bcc69..cfd10713de5439f20e8f4b9c639ba238251b4ef6 100644 (file)
@@ -692,8 +692,9 @@ grub_freebsd_boot (void)
        return err;
 
 #ifdef GRUB_MACHINE_EFI
-      if (! grub_efi_finish_boot_services ())
-       grub_fatal ("cannot exit boot services");
+      err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
+      if (err)
+       return err;
 #endif
 
       pagetable = p;
@@ -723,8 +724,9 @@ grub_freebsd_boot (void)
        return err;
 
 #ifdef GRUB_MACHINE_EFI
-      if (! grub_efi_finish_boot_services ())
-       grub_fatal ("cannot exit boot services");
+      err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
+      if (err)
+       return err;
 #endif
 
       grub_memcpy (&stack[9], &bi, sizeof (bi));
@@ -804,8 +806,9 @@ grub_openbsd_boot (void)
   grub_video_set_mode ("text", 0, 0);
 
 #ifdef GRUB_MACHINE_EFI
-  if (! grub_efi_finish_boot_services ())
-    grub_fatal ("cannot exit boot services");
+  err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
+  if (err)
+    return err;
 #endif
 
   state.eip = entry;
@@ -1009,8 +1012,9 @@ grub_netbsd_boot (void)
     return err;
 
 #ifdef GRUB_MACHINE_EFI
-  if (! grub_efi_finish_boot_services ())
-    grub_fatal ("cannot exit boot services");
+  err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
+  if (err)
+    return err;
 #endif
 
   state.eip = entry;
index 4a1068070484882732a17a028fb4889ff2a9c418..ef1b8309e9a950f8cc94a2ca19f415a1ad0df222 100644 (file)
@@ -681,15 +681,13 @@ grub_linux_boot (void)
 
 #ifdef GRUB_MACHINE_EFI
   {
-    grub_efi_uintn_t efi_map_key, efi_desc_size;
+    grub_efi_uintn_t efi_desc_size;
     grub_efi_uint32_t efi_desc_version;
-    if (grub_efi_get_memory_map (&efi_mmap_size, efi_mmap_buf, &efi_map_key,
-                                &efi_desc_size, &efi_desc_version) <= 0)
-      grub_fatal ("cannot get memory map");
+    err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL,
+                                        &efi_desc_size, &efi_desc_version);
+    if (err)
+      return err;
     
-    if (! grub_efi_exit_boot_services (efi_map_key))
-      grub_fatal ("cannot exit boot services");
-
     /* Note that no boot services are available from here.  */
 
     /* Pass EFI parameters.  */
index bdcd383c52ab47c329ecb1eedbeac009da75c5df..dcec3554ffa8e94b986053a93f39ff0a1d9b419e 100644 (file)
@@ -1038,10 +1038,11 @@ grub_xnu_boot (void)
   bootparams->devtree = devtree_target;
   bootparams->devtreelen = devtreelen;
 
-  if (grub_autoefi_get_memory_map (&memory_map_size, memory_map,
-                                  &map_key, &descriptor_size,
-                                  &descriptor_version) <= 0)
-    return grub_errno;
+  err = grub_efi_finish_boot_services (&memory_map_size, memory_map,
+                                      &map_key, &descriptor_size,
+                                      &descriptor_version);
+  if (err)
+    return err;
 
   bootparams->efi_system_table = PTR_TO_UINT32 (grub_autoefi_system_table);
 
@@ -1096,9 +1097,6 @@ grub_xnu_boot (void)
     + bootparams->heap_size + GRUB_XNU_PAGESIZE;
   grub_xnu_arg1 = bootparams_target;
 
-  if (! grub_autoefi_exit_boot_services (map_key))
-    return grub_error (GRUB_ERR_IO, "can't exit boot services");
-
   grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size,
                                        descriptor_version,memory_map);
 
index 53dc42abb42260a2852aa36aebe8e2b86fb3ba25..a3ca6266f5c913a0175f1329894e47a6d3469000 100644 (file)
@@ -126,8 +126,9 @@ grub_multiboot_boot (void)
     return err;
 
 #ifdef GRUB_MACHINE_EFI
-  if (! grub_efi_finish_boot_services ())
-     grub_fatal ("cannot exit boot services");
+  err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
+  if (err)
+    return err;
 #endif
 
   grub_relocator32_boot (grub_multiboot_relocator, state);
index 6648613983af7ef83295c9f2ddb36d254f7455d0..eac2275618cbece4fc164523b1ac1e38d0c9be69 100644 (file)
@@ -90,6 +90,9 @@ grub_console_putchar (grub_uint32_t c)
   grub_efi_char16_t str[2];
   grub_efi_simple_text_output_interface_t *o;
 
+  if (grub_efi_is_finished)
+    return;
+
   o = grub_efi_system_table->con_out;
 
   /* For now, do not try to use a surrogate pair.  */
@@ -120,6 +123,9 @@ grub_console_checkkey (void)
   grub_efi_input_key_t key;
   grub_efi_status_t status;
 
+  if (grub_efi_is_finished)
+    return 0;
+
   if (read_key >= 0)
     return 1;
 
@@ -217,6 +223,9 @@ grub_console_getkey (void)
   grub_efi_status_t status;
   int key;
 
+  if (grub_efi_is_finished)
+    return 0;
+
   if (read_key >= 0)
     {
       key = read_key;
@@ -249,7 +258,8 @@ grub_console_getwh (void)
   grub_efi_uintn_t columns, rows;
 
   o = grub_efi_system_table->con_out;
-  if (efi_call_4 (o->query_mode, o, o->mode->mode, &columns, &rows) != GRUB_EFI_SUCCESS)
+  if (grub_efi_is_finished || efi_call_4 (o->query_mode, o, o->mode->mode,
+                                         &columns, &rows) != GRUB_EFI_SUCCESS)
     {
       /* Why does this fail?  */
       columns = 80;
@@ -264,6 +274,9 @@ grub_console_getxy (void)
 {
   grub_efi_simple_text_output_interface_t *o;
 
+  if (grub_efi_is_finished)
+    return 0;
+
   o = grub_efi_system_table->con_out;
   return ((o->mode->cursor_column << 8) | o->mode->cursor_row);
 }
@@ -273,6 +286,9 @@ grub_console_gotoxy (grub_uint8_t x, grub_uint8_t y)
 {
   grub_efi_simple_text_output_interface_t *o;
 
+  if (grub_efi_is_finished)
+    return;
+
   o = grub_efi_system_table->con_out;
   efi_call_3 (o->set_cursor_position, o, x, y);
 }
@@ -283,6 +299,9 @@ grub_console_cls (void)
   grub_efi_simple_text_output_interface_t *o;
   grub_efi_int32_t orig_attr;
 
+  if (grub_efi_is_finished)
+    return;
+
   o = grub_efi_system_table->con_out;
   orig_attr = o->mode->attribute;
   efi_call_2 (o->set_attributes, o, GRUB_EFI_BACKGROUND_BLACK);
@@ -295,6 +314,9 @@ grub_console_setcolorstate (grub_term_color_state state)
 {
   grub_efi_simple_text_output_interface_t *o;
 
+  if (grub_efi_is_finished)
+    return;
+
   o = grub_efi_system_table->con_out;
 
   switch (state) {
@@ -331,6 +353,9 @@ grub_console_setcursor (int on)
 {
   grub_efi_simple_text_output_interface_t *o;
 
+  if (grub_efi_is_finished)
+    return;
+
   o = grub_efi_system_table->con_out;
   efi_call_2 (o->enable_cursor, o, on);
 }