Hi,

reading the UEFI specification (and also FreeBSD code) it turns out that
to make EFI properly exit, we need to prove that we know the state of
the current memory mappings.  Otherwise EFI can opt to only do a partial
shutdown of its services.

It would be nice to eventually parse and use the EFI memory descriptors
in the kernel, but for now on arm64 it would be good enough to simply
make EFI exit properly.

Since the memory map, and thus the mapkey, can change between the
GetMemoryMap and ExitBootServices, we need to try reading/exiting a few
times.

ok?

Patrick

diff --git a/sys/arch/arm64/stand/efiboot/efiboot.c 
b/sys/arch/arm64/stand/efiboot/efiboot.c
index a9e7ea38d0b..64bb6f618cf 100644
--- a/sys/arch/arm64/stand/efiboot/efiboot.c
+++ b/sys/arch/arm64/stand/efiboot/efiboot.c
@@ -292,9 +292,35 @@ machdep(void)
 void
 efi_cleanup(void)
 {
+       EFI_STATUS               status;
+       UINTN                    mapkey, mmsiz, siz;
+       UINT32                   mmver;
+       EFI_MEMORY_DESCRIPTOR   *mm;
+       int                      i;
+
        efi_timer_cleanup();
 
-       BS->ExitBootServices(NULL, 0);
+       for (i = 3; i > 0; i--) {
+               siz = 0;
+               status = EFI_CALL(BS->GetMemoryMap, &siz, NULL, &mapkey, &mmsiz,
+                   &mmver);
+               if (status != EFI_BUFFER_TOO_SMALL)
+                       continue;
+               mm = alloc(siz);
+               status = EFI_CALL(BS->GetMemoryMap, &siz, mm, &mapkey, &mmsiz, 
&mmver);
+               if (status != EFI_SUCCESS) {
+                       free(mm, siz);
+                       continue;
+               }
+
+               status = BS->ExitBootServices(IH, mapkey);
+               if (status != EFI_SUCCESS) {
+                       free(mm, siz);
+                       continue;
+               }
+
+               break;
+       }
 }
 
 void

Reply via email to