summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/boot/efi/loader/arch/amd64/elf64_freebsd.c7
-rw-r--r--sys/boot/efi/loader/bootinfo.c99
-rw-r--r--sys/boot/efi/loader/loader_efi.h2
3 files changed, 56 insertions, 52 deletions
diff --git a/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c b/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c
index 0c26072..c1dbec2 100644
--- a/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c
+++ b/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c
@@ -174,13 +174,6 @@ elf64_exec(struct preloaded_file *fp)
if (err != 0)
return(err);
- status = BS->ExitBootServices(IH, efi_mapkey);
- if (EFI_ERROR(status)) {
- printf("%s: ExitBootServices() returned 0x%lx\n", __func__,
- (long)status);
- return (EINVAL);
- }
-
dev_cleanup();
trampoline(trampstack, efi_copy_finish, kernend, modulep, PT4,
diff --git a/sys/boot/efi/loader/bootinfo.c b/sys/boot/efi/loader/bootinfo.c
index 599ac5b..f3bb9cc 100644
--- a/sys/boot/efi/loader/bootinfo.c
+++ b/sys/boot/efi/loader/bootinfo.c
@@ -48,8 +48,6 @@ __FBSDID("$FreeBSD$");
#include "framebuffer.h"
#include "loader_efi.h"
-UINTN efi_mapkey;
-
static const char howto_switches[] = "aCdrgDmphsv";
static int howto_masks[] = {
RB_ASKNAME, RB_CDROM, RB_KDB, RB_DFLTROOT, RB_GDB, RB_MULTIPLE,
@@ -230,7 +228,8 @@ bi_load_efi_data(struct preloaded_file *kfp)
EFI_PHYSICAL_ADDRESS addr;
EFI_STATUS status;
size_t efisz;
- UINTN mmsz, pages, sz;
+ UINTN efi_mapkey;
+ UINTN mmsz, pages, retry, sz;
UINT32 mmver;
struct efi_map_header *efihdr;
struct efi_fb efifb;
@@ -252,49 +251,63 @@ bi_load_efi_data(struct preloaded_file *kfp)
efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
/*
- * Allocate enough pages to hold the bootinfo block and the memory
- * map EFI will return to us. The memory map has an unknown size,
- * so we have to determine that first. Note that the AllocatePages
- * call can itself modify the memory map, so we have to take that
- * into account as well. The changes to the memory map are caused
- * by splitting a range of free memory into two (AFAICT), so that
- * one is marked as being loader data.
+ * It is possible that the first call to ExitBootServices may change
+ * the map key. Fetch a new map key and retry ExitBootServices in that
+ * case.
*/
- sz = 0;
- BS->GetMemoryMap(&sz, NULL, &efi_mapkey, &mmsz, &mmver);
- sz += mmsz;
- sz = (sz + 0xf) & ~0xf;
- pages = EFI_SIZE_TO_PAGES(sz + efisz);
- status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, pages,
- &addr);
- if (EFI_ERROR(status)) {
- printf("%s: AllocatePages() returned 0x%lx\n", __func__,
- (long)status);
- return (ENOMEM);
- }
+ for (retry = 2; retry > 0; retry--) {
+ /*
+ * Allocate enough pages to hold the bootinfo block and the
+ * memory map EFI will return to us. The memory map has an
+ * unknown size, so we have to determine that first. Note that
+ * the AllocatePages call can itself modify the memory map, so
+ * we have to take that into account as well. The changes to
+ * the memory map are caused by splitting a range of free
+ * memory into two (AFAICT), so that one is marked as being
+ * loader data.
+ */
+ sz = 0;
+ BS->GetMemoryMap(&sz, NULL, &efi_mapkey, &mmsz, &mmver);
+ sz += mmsz;
+ sz = (sz + 0xf) & ~0xf;
+ pages = EFI_SIZE_TO_PAGES(sz + efisz);
+ status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
+ pages, &addr);
+ if (EFI_ERROR(status)) {
+ printf("%s: AllocatePages error %lu\n", __func__,
+ (unsigned long)(status & ~EFI_ERROR_MASK));
+ return (ENOMEM);
+ }
- /*
- * Read the memory map and stash it after bootinfo. Align the
- * memory map on a 16-byte boundary (the bootinfo block is page
- * aligned).
- */
- efihdr = (struct efi_map_header *)addr;
- mm = (void *)((uint8_t *)efihdr + efisz);
- sz = (EFI_PAGE_SIZE * pages) - efisz;
- status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &mmsz, &mmver);
- if (EFI_ERROR(status)) {
- printf("%s: GetMemoryMap() returned 0x%lx\n", __func__,
- (long)status);
- return (EINVAL);
+ /*
+ * Read the memory map and stash it after bootinfo. Align the
+ * memory map on a 16-byte boundary (the bootinfo block is page
+ * aligned).
+ */
+ efihdr = (struct efi_map_header *)addr;
+ mm = (void *)((uint8_t *)efihdr + efisz);
+ sz = (EFI_PAGE_SIZE * pages) - efisz;
+
+ status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &mmsz, &mmver);
+ if (EFI_ERROR(status)) {
+ printf("%s: GetMemoryMap error %lu\n", __func__,
+ (unsigned long)(status & ~EFI_ERROR_MASK));
+ return (EINVAL);
+ }
+ status = BS->ExitBootServices(IH, efi_mapkey);
+ if (EFI_ERROR(status) == 0) {
+ efihdr->memory_size = sz;
+ efihdr->descriptor_size = mmsz;
+ efihdr->descriptor_version = mmver;
+ file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz,
+ efihdr);
+ return (0);
+ }
+ BS->FreePages(addr, pages);
}
-
- efihdr->memory_size = sz;
- efihdr->descriptor_size = mmsz;
- efihdr->descriptor_version = mmver;
-
- file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, efihdr);
-
- return (0);
+ printf("ExitBootServices error %lu\n",
+ (unsigned long)(status & ~EFI_ERROR_MASK));
+ return (EINVAL);
}
/*
diff --git a/sys/boot/efi/loader/loader_efi.h b/sys/boot/efi/loader/loader_efi.h
index f98f094..5819d78 100644
--- a/sys/boot/efi/loader/loader_efi.h
+++ b/sys/boot/efi/loader/loader_efi.h
@@ -44,8 +44,6 @@ ssize_t efi_copyout(const vm_offset_t src, void *dest, const size_t len);
ssize_t efi_readin(const int fd, vm_offset_t dest, const size_t len);
void * efi_translate(vm_offset_t ptr);
-extern UINTN efi_mapkey;
-
void efi_copy_finish(void);
#endif /* _LOADER_EFI_COPY_H_ */
OpenPOWER on IntegriCloud