diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2017-02-08 09:13:26 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2017-02-08 09:13:26 +0000 |
commit | c401bc1278285bfc99412196f8aba35fbbfcaa8a (patch) | |
tree | c418dd1a5657131ab17f6f710537b8295d0e62ff | |
parent | 52c2c7e851ea2ce7635efc7468f8fd871eab9116 (diff) |
Retry BS->ExitBootServices() if it fails, like on amd64. Also we need
to make sure to pass the current mapkey to prove EFI that we know the
current memory map and its constraints. Otherwise EFI can choose to
only partially exit until we pass the correct key. As we already use
the memory map to allocate memory for the kernel, split the previous
function into one simply retrieving the table and another one who uses
the map to allocate memory. At some point it would be nice to actually
pass the table to the kernel since its data is more reliable than the
FDT only. While there, sync a bit of style with the amd64 version.
-rw-r--r-- | sys/arch/arm64/stand/efiboot/efiboot.c | 79 |
1 files changed, 54 insertions, 25 deletions
diff --git a/sys/arch/arm64/stand/efiboot/efiboot.c b/sys/arch/arm64/stand/efiboot/efiboot.c index b7ec03dc6e5..55de5ac6e1d 100644 --- a/sys/arch/arm64/stand/efiboot/efiboot.c +++ b/sys/arch/arm64/stand/efiboot/efiboot.c @@ -1,4 +1,4 @@ -/* $OpenBSD: efiboot.c,v 1.4 2017/02/04 22:43:46 patrick Exp $ */ +/* $OpenBSD: efiboot.c,v 1.5 2017/02/08 09:13:25 patrick Exp $ */ /* * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> @@ -38,16 +38,23 @@ EFI_SYSTEM_TABLE *ST; EFI_BOOT_SERVICES *BS; EFI_RUNTIME_SERVICES *RS; -EFI_HANDLE IH; +EFI_HANDLE IH, efi_bootdp = NULL; -EFI_HANDLE efi_bootdp; +EFI_PHYSICAL_ADDRESS heap; +UINTN heapsiz = 1 * 1024 * 1024; +EFI_MEMORY_DESCRIPTOR *mmap = NULL; +UINTN mmap_key; +UINTN mmap_ndesc; +UINTN mmap_descsiz; static EFI_GUID imgp_guid = LOADED_IMAGE_PROTOCOL; static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL; -static void efi_timer_init(void); -static void efi_timer_cleanup(void); +static void efi_heap_init(void); +static void efi_memprobe_internal(void); +static void efi_timer_init(void); +static void efi_timer_cleanup(void); static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_PHYSICAL_ADDRESS *); EFI_STATUS @@ -145,9 +152,6 @@ efi_cons_putc(dev_t dev, int c) conout->OutputString(conout, buf); } -EFI_PHYSICAL_ADDRESS heap; -UINTN heapsiz = 1 * 1024 * 1024; - static void efi_heap_init(void) { @@ -291,9 +295,20 @@ machdep(void) void efi_cleanup(void) { + int retry; + EFI_STATUS status; + efi_timer_cleanup(); - BS->ExitBootServices(NULL, 0); + /* retry once in case of failure */ + for (retry = 1; retry >= 0; retry--) { + efi_memprobe_internal(); /* sync the current map */ + status = EFI_CALL(BS->ExitBootServices, IH, mmap_key); + if (status == EFI_SUCCESS) + break; + if (retry == 0) + panic("ExitBootServices failed (%d)", status); + } } void @@ -472,35 +487,51 @@ devopen(struct open_file *f, const char *fname, char **file) return (*dp->dv_open)(f, unit, part); } -/* - * 64-bit ARMs can have a much wider memory mapping, as in somewhere - * after the 32-bit region. To cope with our alignment requirement, - * use the memory table to find a place where we can fit. - */ -static EFI_STATUS -efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr) +static void +efi_memprobe_internal(void) { EFI_STATUS status; UINTN mapkey, mmsiz, siz; UINT32 mmver; - EFI_MEMORY_DESCRIPTOR *mm0, *mm; - int i, j, n; + EFI_MEMORY_DESCRIPTOR *mm; + int n; - if (align < EFI_PAGE_SIZE) - return EFI_INVALID_PARAMETER; + free(mmap, mmap_ndesc * mmap_descsiz); siz = 0; status = EFI_CALL(BS->GetMemoryMap, &siz, NULL, &mapkey, &mmsiz, &mmver); if (status != EFI_BUFFER_TOO_SMALL) panic("cannot get the size of memory map"); - mm0 = alloc(siz); - status = EFI_CALL(BS->GetMemoryMap, &siz, mm0, &mapkey, &mmsiz, &mmver); + mm = alloc(siz); + status = EFI_CALL(BS->GetMemoryMap, &siz, mm, &mapkey, &mmsiz, &mmver); if (status != EFI_SUCCESS) panic("cannot get the memory map"); n = siz / mmsiz; + mmap = mm; + mmap_key = mapkey; + mmap_ndesc = n; + mmap_descsiz = mmsiz; +} + +/* + * 64-bit ARMs can have a much wider memory mapping, as in somewhere + * after the 32-bit region. To cope with our alignment requirement, + * use the memory table to find a place where we can fit. + */ +static EFI_STATUS +efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr) +{ + EFI_MEMORY_DESCRIPTOR *mm; + int i, j; + + if (align < EFI_PAGE_SIZE) + return EFI_INVALID_PARAMETER; + + efi_memprobe_internal(); /* sync the current map */ - for (i = 0, mm = mm0; i < n; i++, mm = NextMemoryDescriptor(mm, mmsiz)) { + for (i = 0, mm = mmap; i < mmap_ndesc; + i++, mm = NextMemoryDescriptor(mm, mmap_descsiz)) { if (mm->Type != EfiConventionalMemory) continue; @@ -520,11 +551,9 @@ efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr) if (EFI_CALL(BS->AllocatePages, AllocateAddress, EfiLoaderData, pages, &paddr) == EFI_SUCCESS) { *addr = paddr; - free(mm0, siz); return EFI_SUCCESS; } } } - free(mm0, siz); return EFI_OUT_OF_RESOURCES; } |