diff --git a/conf/i386.rmk b/conf/i386.rmk
index e223694df..e04d73d61 100644
--- a/conf/i386.rmk
+++ b/conf/i386.rmk
@@ -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)
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 5852a476f..a56b3f56b 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -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 */
diff --git a/include/grub/relocator_private.h b/include/grub/relocator_private.h
index c526b0b0c..8398defbd 100644
--- a/include/grub/relocator_private.h
+++ b/include/grub/relocator_private.h
@@ -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 {
diff --git a/kern/efi/efi.c b/kern/efi/efi.c
index d8b225535..4916a0d18 100644
--- a/kern/efi/efi.c
+++ b/kern/efi/efi.c
@@ -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);
-}
-
diff --git a/kern/efi/mm.c b/kern/efi/mm.c
index ceb8fc9ba..4db0e7e92 100644
--- a/kern/efi/mm.c
+++ b/kern/efi/mm.c
@@ -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
index 000000000..fc4de834b
--- /dev/null
+++ b/lib/efi/relocator.c
@@ -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 .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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);
+}
diff --git a/lib/relocator.c b/lib/relocator.c
index 4f37fb435..de4cca626 100644
--- a/lib/relocator.c
+++ b/lib/relocator.c
@@ -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:
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
index f50e94f98..cfd10713d 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -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;
diff --git a/loader/i386/linux.c b/loader/i386/linux.c
index 4a1068070..ef1b8309e 100644
--- a/loader/i386/linux.c
+++ b/loader/i386/linux.c
@@ -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. */
diff --git a/loader/i386/xnu.c b/loader/i386/xnu.c
index bdcd383c5..dcec3554f 100644
--- a/loader/i386/xnu.c
+++ b/loader/i386/xnu.c
@@ -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);
diff --git a/loader/multiboot.c b/loader/multiboot.c
index 53dc42abb..a3ca6266f 100644
--- a/loader/multiboot.c
+++ b/loader/multiboot.c
@@ -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);
diff --git a/term/efi/console.c b/term/efi/console.c
index 664861398..eac227561 100644
--- a/term/efi/console.c
+++ b/term/efi/console.c
@@ -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);
}