summaryrefslogtreecommitdiffstats
path: root/sys/boot/efi/loader
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2015-12-16 16:19:18 +0000
committeremaste <emaste@FreeBSD.org>2015-12-16 16:19:18 +0000
commit2fca0caf45275f1f3821f9e7095ed671a7f5b9b5 (patch)
treed3412c4a42a51d15be7200562dfac09597da2d94 /sys/boot/efi/loader
parent41d1b59ed4536ae4d941d1bf307b8f9afcb241e4 (diff)
downloadFreeBSD-src-2fca0caf45275f1f3821f9e7095ed671a7f5b9b5.zip
FreeBSD-src-2fca0caf45275f1f3821f9e7095ed671a7f5b9b5.tar.gz
UEFI: combine GetMemoryMap and ExitBootServices and retry on error
The EFI memory map may change before or during the first ExitBootServices call. In that case ExitBootServices returns an error, and GetMemoryMap and ExitBootServices must be retried. Glue together calls to GetMemoryMap(), ExitBootServices() and storage of (now up-to-date) MODINFOMD_EFI_MAP metadata within a single function. That new function - bi_add_efi_data_and_exit() - uses space previously allocated in bi_load_efi_data() to store the memory map (it will fail if that space is too short). It handles re-calling GetMemoryMap() once to update the map key if necessary. Finally, if ExitBootServices() is successful, it stores the memory map and its header as MODINFOMD_EFI_MAP metadata. ExitBootServices() calls are now done earlier, from within arch- independent bi_load() code. PR: 202455 Submitted by: Ganael LAPLANCHE Reviewed by: kib MFC after: 2 weeks Relnotes: Yes Differential Revision: https://reviews.freebsd.org/D4296
Diffstat (limited to 'sys/boot/efi/loader')
-rw-r--r--sys/boot/efi/loader/arch/amd64/elf64_freebsd.c7
-rw-r--r--sys/boot/efi/loader/arch/arm/exec.c7
-rw-r--r--sys/boot/efi/loader/arch/arm64/exec.c7
-rw-r--r--sys/boot/efi/loader/bootinfo.c54
-rw-r--r--sys/boot/efi/loader/loader_efi.h2
5 files changed, 39 insertions, 38 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/arch/arm/exec.c b/sys/boot/efi/loader/arch/arm/exec.c
index 1cbbce5..7c51e6e 100644
--- a/sys/boot/efi/loader/arch/arm/exec.c
+++ b/sys/boot/efi/loader/arch/arm/exec.c
@@ -82,13 +82,6 @@ __elfN(arm_exec)(struct preloaded_file *fp)
printf("modulep: %#x\n", modulep);
printf("relocation_offset %llx\n", __elfN(relocation_offset));
- status = BS->ExitBootServices(IH, efi_mapkey);
- if (EFI_ERROR(status)) {
- printf("%s: ExitBootServices() returned 0x%lx\n", __func__,
- (long)status);
- return (EINVAL);
- }
-
dev_cleanup();
(*entry)((void *)modulep);
diff --git a/sys/boot/efi/loader/arch/arm64/exec.c b/sys/boot/efi/loader/arch/arm64/exec.c
index d13e97b..0746c05 100644
--- a/sys/boot/efi/loader/arch/arm64/exec.c
+++ b/sys/boot/efi/loader/arch/arm64/exec.c
@@ -118,13 +118,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);
- }
-
/* Clean D-cache under kernel area and invalidate whole I-cache */
clean_addr = efi_translate(fp->f_addr);
clean_size = efi_translate(kernendp) - clean_addr;
diff --git a/sys/boot/efi/loader/bootinfo.c b/sys/boot/efi/loader/bootinfo.c
index 6ef83a8..c9dbe8d 100644
--- a/sys/boot/efi/loader/bootinfo.c
+++ b/sys/boot/efi/loader/bootinfo.c
@@ -55,8 +55,6 @@ __FBSDID("$FreeBSD$");
#include <fdt_platform.h>
#endif
-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,
@@ -234,12 +232,50 @@ 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() returned 0x%lx\n", __func__,
+ (long)status);
+ 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() returned 0x%lx\n", (long)status);
+ return (EINVAL);
+}
+
+static int
bi_load_efi_data(struct preloaded_file *kfp)
{
EFI_MEMORY_DESCRIPTOR *mm;
EFI_PHYSICAL_ADDRESS addr;
EFI_STATUS status;
size_t efisz;
+ UINTN efi_mapkey;
UINTN mmsz, pages, sz;
UINT32 mmver;
struct efi_map_header *efihdr;
@@ -294,20 +330,8 @@ bi_load_efi_data(struct preloaded_file *kfp)
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);
- }
-
- efihdr->memory_size = sz;
- efihdr->descriptor_size = mmsz;
- efihdr->descriptor_version = mmver;
- file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, efihdr);
-
- return (0);
+ return (bi_add_efi_data_and_exit(kfp, efihdr, efisz, mm, sz));
}
/*
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