This revision was automatically updated to reflect the committed changes.
Closed by commit rS314547: loader.efi: reduce the size of the staging area if 
necessary (authored by dexuan).

CHANGED PRIOR TO COMMIT
  https://reviews.freebsd.org/D9686?vs=25505&id=25869#toc

REPOSITORY
  rS FreeBSD src repository

CHANGES SINCE LAST UPDATE
  https://reviews.freebsd.org/D9686?vs=25505&id=25869

REVISION DETAIL
  https://reviews.freebsd.org/D9686

AFFECTED FILES
  head/sys/boot/efi/loader/copy.c

EMAIL PREFERENCES
  https://reviews.freebsd.org/settings/panel/emailpreferences/

To: decui_microsoft.com, imp, jhb, will, kib, delphij, emaste, 
honzhan_microsoft.com, howard0su_gmail.com, marcel, tsoome, gonzo, manu, 
andrew, sbruno, ambrisko, allanjude, bapt, cem, smh, ian, sepherosa_gmail.com
Cc: freebsd-virtualization-list
diff --git a/head/sys/boot/efi/loader/copy.c b/head/sys/boot/efi/loader/copy.c
--- a/head/sys/boot/efi/loader/copy.c
+++ b/head/sys/boot/efi/loader/copy.c
@@ -39,12 +39,71 @@
 
 #include "loader_efi.h"
 
+#if defined(__i386__) || defined(__amd64__)
+
+#define KERNEL_PHYSICAL_BASE (2*1024*1024)
+
+static void
+efi_verify_staging_size(unsigned long *nr_pages)
+{
+	UINTN sz;
+	EFI_MEMORY_DESCRIPTOR *map, *p;
+	EFI_PHYSICAL_ADDRESS start, end;
+	UINTN key, dsz;
+	UINT32 dver;
+	EFI_STATUS status;
+	int i, ndesc;
+	unsigned long available_pages;
+
+	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;
+	}
+
+	ndesc = sz / dsz;
+
+	for (i = 0, p = map; i < ndesc;
+	     i++, p = NextMemoryDescriptor(p, dsz)) {
+		start = p->PhysicalStart;
+		end = start + p->NumberOfPages * EFI_PAGE_SIZE;
+
+		if (KERNEL_PHYSICAL_BASE < start ||
+		    KERNEL_PHYSICAL_BASE >= end)
+			continue;
+
+		if (p->Type != EfiConventionalMemory)
+			continue;
+
+		available_pages = p->NumberOfPages -
+			((KERNEL_PHYSICAL_BASE - start) >> EFI_PAGE_SHIFT);
+
+		if (*nr_pages > available_pages) {
+			printf("staging area size is reduced: %ld -> %ld!\n",
+			    *nr_pages, available_pages);
+			*nr_pages = available_pages;
+		}
+
+		break;
+	}
+
+out:
+	free(map);
+}
+#endif
+
 #ifndef EFI_STAGING_SIZE
 #define	EFI_STAGING_SIZE	64
 #endif
 
-#define	STAGE_PAGES	EFI_SIZE_TO_PAGES((EFI_STAGING_SIZE) * 1024 * 1024)
-
 EFI_PHYSICAL_ADDRESS	staging, staging_end;
 int			stage_offset_set = 0;
 ssize_t			stage_offset;
@@ -54,14 +113,32 @@
 {
 	EFI_STATUS	status;
 
+	unsigned long nr_pages;
+
+	nr_pages = EFI_SIZE_TO_PAGES((EFI_STAGING_SIZE) * 1024 * 1024);
+
+#if defined(__i386__) || defined(__amd64__)
+	/* We'll decrease nr_pages, if it's too big. */
+	efi_verify_staging_size(&nr_pages);
+
+	/*
+	 * The staging area must reside in the the first 1GB physical
+	 * memory: see elf64_exec() in
+	 * boot/efi/loader/arch/amd64/elf64_freebsd.c.
+	 */
+	staging = 1024*1024*1024;
+	status = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData,
+	    nr_pages, &staging);
+#else
 	status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
-	    STAGE_PAGES, &staging);
+	    nr_pages, &staging);
+#endif
 	if (EFI_ERROR(status)) {
 		printf("failed to allocate staging area: %lu\n",
 		    EFI_ERROR_CODE(status));
 		return (status);
 	}
-	staging_end = staging + STAGE_PAGES * EFI_PAGE_SIZE;
+	staging_end = staging + nr_pages * EFI_PAGE_SIZE;
 
 #if defined(__aarch64__) || defined(__arm__)
 	/*

_______________________________________________
freebsd-virtualization@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-virtualization
To unsubscribe, send any mail to 
"freebsd-virtualization-unsubscr...@freebsd.org"

Reply via email to