989d921f5d
I'm very pleased to announce the release of our new website and documentation using the new toolchain with Hugo and AsciiDoctor. To get more information about the new toolchain please read the FreeBSD Documentation Project Primer[1], Hugo docs[2] and AsciiDoctor docs[3]. Acknowledgment: Benedict Reuschling <bcr@> Glen Barber <gjb@> Hiroki Sato <hrs@> Li-Wen Hsu <lwhsu@> Sean Chittenden <seanc@> The FreeBSD Foundation [1] https://docs.FreeBSD.org/en/books/fdp-primer/ [2] https://gohugo.io/documentation/ [3] https://docs.asciidoctor.org/home/ Approved by: doceng, core
219 lines
6.5 KiB
Diff
219 lines
6.5 KiB
Diff
--- stand/efi/loader/bootinfo.c.orig
|
|
+++ stand/efi/loader/bootinfo.c
|
|
@@ -287,12 +287,12 @@
|
|
bi_load_efi_data(struct preloaded_file *kfp)
|
|
{
|
|
EFI_MEMORY_DESCRIPTOR *mm;
|
|
- EFI_PHYSICAL_ADDRESS addr;
|
|
+ EFI_PHYSICAL_ADDRESS addr = 0;
|
|
EFI_STATUS status;
|
|
const char *efi_novmap;
|
|
size_t efisz;
|
|
UINTN efi_mapkey;
|
|
- UINTN mmsz, pages, retry, sz;
|
|
+ UINTN dsz, pages, retry, sz;
|
|
UINT32 mmver;
|
|
struct efi_map_header *efihdr;
|
|
bool do_vmap;
|
|
@@ -323,76 +323,94 @@
|
|
efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
|
|
|
|
/*
|
|
- * Assgin size of EFI_MEMORY_DESCRIPTOR to keep compatible with
|
|
+ * Assign size of EFI_MEMORY_DESCRIPTOR to keep compatible with
|
|
* u-boot which doesn't fill this value when buffer for memory
|
|
* descriptors is too small (eg. 0 to obtain memory map size)
|
|
*/
|
|
- mmsz = sizeof(EFI_MEMORY_DESCRIPTOR);
|
|
+ dsz = sizeof(EFI_MEMORY_DESCRIPTOR);
|
|
|
|
/*
|
|
- * 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.
|
|
+ * 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, so that one is marked as being loader
|
|
+ * data.
|
|
+ */
|
|
+
|
|
+ sz = 0;
|
|
+
|
|
+ /*
|
|
+ * Matthew Garrett has observed at least one system changing the
|
|
+ * memory map when calling ExitBootServices, causing it to return an
|
|
+ * error, probably because callbacks are allocating memory.
|
|
+ * So we need to retry calling it at least once.
|
|
*/
|
|
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__,
|
|
- EFI_ERROR_CODE(status));
|
|
- return (ENOMEM);
|
|
- }
|
|
+ for (;;) {
|
|
+ status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &dsz, &mmver);
|
|
+ if (!EFI_ERROR(status))
|
|
+ break;
|
|
+
|
|
+ if (status != EFI_BUFFER_TOO_SMALL) {
|
|
+ printf("%s: GetMemoryMap error %lu\n", __func__,
|
|
+ EFI_ERROR_CODE(status));
|
|
+ return (EINVAL);
|
|
+ }
|
|
+
|
|
+ if (addr != 0)
|
|
+ BS->FreePages(addr, pages);
|
|
+
|
|
+ /* Add 10 descriptors to the size to allow for
|
|
+ * fragmentation caused by calling AllocatePages */
|
|
+ sz += (10 * dsz);
|
|
+ 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__,
|
|
+ EFI_ERROR_CODE(status));
|
|
+ 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 *)(uintptr_t)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__,
|
|
- EFI_ERROR_CODE(status));
|
|
- return (EINVAL);
|
|
- }
|
|
- status = BS->ExitBootServices(IH, efi_mapkey);
|
|
- if (EFI_ERROR(status) == 0) {
|
|
/*
|
|
- * This may be disabled by setting efi_disable_vmap in
|
|
- * loader.conf(5). By default we will setup the virtual
|
|
- * map entries.
|
|
+ * Read the memory map and stash it after bootinfo. Align the
|
|
+ * memory map on a 16-byte boundary (the bootinfo block is page
|
|
+ * aligned).
|
|
*/
|
|
- if (do_vmap)
|
|
- efi_do_vmap(mm, sz, mmsz, mmver);
|
|
- efihdr->memory_size = sz;
|
|
- efihdr->descriptor_size = mmsz;
|
|
- efihdr->descriptor_version = mmver;
|
|
- file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz,
|
|
- efihdr);
|
|
- return (0);
|
|
+ efihdr = (struct efi_map_header *)(uintptr_t)addr;
|
|
+ mm = (void *)((uint8_t *)efihdr + efisz);
|
|
+ sz = (EFI_PAGE_SIZE * pages) - efisz;
|
|
}
|
|
+
|
|
+ status = BS->ExitBootServices(IH, efi_mapkey);
|
|
+ if (!EFI_ERROR(status))
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (retry == 0) {
|
|
BS->FreePages(addr, pages);
|
|
+ printf("ExitBootServices error %lu\n", EFI_ERROR_CODE(status));
|
|
+ return (EINVAL);
|
|
}
|
|
- printf("ExitBootServices error %lu\n", EFI_ERROR_CODE(status));
|
|
- return (EINVAL);
|
|
+
|
|
+ /*
|
|
+ * This may be disabled by setting efi_disable_vmap in
|
|
+ * loader.conf(5). By default we will setup the virtual
|
|
+ * map entries.
|
|
+ */
|
|
+
|
|
+ if (do_vmap)
|
|
+ efi_do_vmap(mm, sz, dsz, mmver);
|
|
+ efihdr->memory_size = sz;
|
|
+ efihdr->descriptor_size = dsz;
|
|
+ efihdr->descriptor_version = mmver;
|
|
+ file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz,
|
|
+ efihdr);
|
|
+
|
|
+ return (0);
|
|
}
|
|
|
|
/*
|
|
--- stand/efi/loader/copy.c.orig
|
|
+++ stand/efi/loader/copy.c
|
|
@@ -95,7 +95,7 @@
|
|
efi_verify_staging_size(unsigned long *nr_pages)
|
|
{
|
|
UINTN sz;
|
|
- EFI_MEMORY_DESCRIPTOR *map, *p;
|
|
+ EFI_MEMORY_DESCRIPTOR *map = NULL, *p;
|
|
EFI_PHYSICAL_ADDRESS start, end;
|
|
UINTN key, dsz;
|
|
UINT32 dver;
|
|
@@ -104,17 +104,28 @@
|
|
unsigned long available_pages = 0;
|
|
|
|
sz = 0;
|
|
- status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
|
|
- if (status != EFI_BUFFER_TOO_SMALL) {
|
|
- printf("Can't determine memory map size\n");
|
|
- return;
|
|
- }
|
|
|
|
- map = malloc(sz);
|
|
- status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
|
|
- if (EFI_ERROR(status)) {
|
|
- printf("Can't read memory map\n");
|
|
- goto out;
|
|
+ for (;;) {
|
|
+ status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
|
|
+ if (!EFI_ERROR(status))
|
|
+ break;
|
|
+
|
|
+ if (status != EFI_BUFFER_TOO_SMALL) {
|
|
+ printf("Can't read memory map: %lu\n",
|
|
+ EFI_ERROR_CODE(status));
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ free(map);
|
|
+
|
|
+ /* Allocate 10 descriptors more than the size reported,
|
|
+ * to allow for any fragmentation caused by calling
|
|
+ * malloc */
|
|
+ map = malloc(sz + (10 * dsz));
|
|
+ if (map == NULL) {
|
|
+ printf("Unable to allocate memory\n");
|
|
+ goto out;
|
|
+ }
|
|
}
|
|
|
|
ndesc = sz / dsz;
|