summaryrefslogtreecommitdiffstats
path: root/sys/boot/efi/loader
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2015-12-20 16:07:09 +0000
committeremaste <emaste@FreeBSD.org>2015-12-20 16:07:09 +0000
commit68c345265bbdb53395a7c7510b9df586dabb0a22 (patch)
tree93fa84471ea1ede2634827ed9500bc87d992893f /sys/boot/efi/loader
parent33741c0d9ada9a85f36241592179ac7ca0b53436 (diff)
downloadFreeBSD-src-68c345265bbdb53395a7c7510b9df586dabb0a22.zip
FreeBSD-src-68c345265bbdb53395a7c7510b9df586dabb0a22.tar.gz
loader.efi: refresh size in GetMemoryMap retry loop
If ExitBootServices fails due to a changed efi_mapkey then GetMemoryMap must be called again. In this case it is also possible for the memory map to grow, so repeat the initial GetMemoryMap call to fetch the new size. Also roll bi_add_efi_data_and_exit into bi_load_efi_data as there's no need for it to be a separate function. PR: 202455 Reported by: Berislav Purgar <bpurgar@gmail.com> Tested by: Berislav Purgar <bpurgar@gmail.com> Reviewed by: kib MFC after: 1 week MFC with: r292338 Relnotes: Yes Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D4621
Diffstat (limited to 'sys/boot/efi/loader')
-rw-r--r--sys/boot/efi/loader/bootinfo.c122
1 files changed, 55 insertions, 67 deletions
diff --git a/sys/boot/efi/loader/bootinfo.c b/sys/boot/efi/loader/bootinfo.c
index 0b7b7ef..622f4c6 100644
--- a/sys/boot/efi/loader/bootinfo.c
+++ b/sys/boot/efi/loader/bootinfo.c
@@ -234,44 +234,6 @@ bi_copymodules(vm_offset_t addr)
}
static int
-bi_add_efi_data_and_exit(struct preloaded_file *kfp,
- struct efi_map_header *efihdr, size_t efisz, EFI_MEMORY_DESCRIPTOR *mm,
- UINTN sz)
-{
- UINTN efi_mapkey;
- UINTN mmsz;
- UINT32 mmver;
- EFI_STATUS status;
- UINTN retry;
-
- /*
- * 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.
- */
- for (retry = 2; retry > 0; retry--) {
- 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);
- }
- }
- printf("ExitBootServices error %lu\n",
- (unsigned long)(status & ~EFI_ERROR_MASK));
- return (EINVAL);
-}
-
-static int
bi_load_efi_data(struct preloaded_file *kfp)
{
EFI_MEMORY_DESCRIPTOR *mm;
@@ -279,7 +241,7 @@ bi_load_efi_data(struct preloaded_file *kfp)
EFI_STATUS status;
size_t efisz;
UINTN efi_mapkey;
- UINTN mmsz, pages, sz;
+ UINTN mmsz, pages, retry, sz;
UINT32 mmver;
struct efi_map_header *efihdr;
@@ -304,37 +266,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 error %lu\n", __func__,
- (unsigned long)(status & ~EFI_ERROR_MASK));
- 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;
+ /*
+ * 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;
- return (bi_add_efi_data_and_exit(kfp, efihdr, efisz, mm, sz));
+ 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);
+ }
+ printf("ExitBootServices error %lu\n",
+ (unsigned long)(status & ~EFI_ERROR_MASK));
+ return (EINVAL);
}
/*
OpenPOWER on IntegriCloud