svn commit: r246337 - projects/uefi/sys/amd64/amd64

Benno Rice benno at FreeBSD.org
Mon Feb 4 23:24:05 UTC 2013


Author: benno
Date: Mon Feb  4 23:24:04 2013
New Revision: 246337
URL: http://svnweb.freebsd.org/changeset/base/246337

Log:
  Add code to parse the EFI memory map if present.
  
  With this change we can now boot under qemu using the OVMF UEFI firmware
  image with the limitation that a serial console is required as syscons
  isn't yet working.
  
  Sponsored by:	FreeBSD Foundation

Modified:
  projects/uefi/sys/amd64/amd64/machdep.c

Modified: projects/uefi/sys/amd64/amd64/machdep.c
==============================================================================
--- projects/uefi/sys/amd64/amd64/machdep.c	Mon Feb  4 23:21:20 2013	(r246336)
+++ projects/uefi/sys/amd64/amd64/machdep.c	Mon Feb  4 23:24:04 2013	(r246337)
@@ -114,6 +114,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/clock.h>
 #include <machine/cpu.h>
 #include <machine/cputypes.h>
+#include <machine/efi.h>
 #include <machine/intr_machdep.h>
 #include <x86/mca.h>
 #include <machine/md_var.h>
@@ -142,6 +143,39 @@ __FBSDID("$FreeBSD$");
 #include <isa/isareg.h>
 #include <isa/rtc.h>
 
+enum EFI_MEMORY_TYPE {
+    EfiReservedMemoryType,
+    EfiLoaderCode,
+    EfiLoaderData,
+    EfiBootServicesCode,
+    EfiBootServicesData,
+    EfiRuntimeServicesCode,
+    EfiRuntimeServicesData,
+    EfiConventionalMemory,
+    EfiUnusableMemory,
+    EfiACPIReclaimMemory,
+    EfiACPIMemoryNVS,
+    EfiMemoryMappedIO,
+    EfiMemoryMappedIOPortSpace,
+    EfiPalCode,
+    EfiMaxMemoryType
+};
+
+// possible caching types for the memory range
+#define EFI_MEMORY_UC           0x0000000000000001
+#define EFI_MEMORY_WC           0x0000000000000002
+#define EFI_MEMORY_WT           0x0000000000000004
+#define EFI_MEMORY_WB           0x0000000000000008
+#define EFI_MEMORY_UCE          0x0000000000000010  
+
+// physical memory protection on range 
+#define EFI_MEMORY_WP           0x0000000000001000
+#define EFI_MEMORY_RP           0x0000000000002000
+#define EFI_MEMORY_XP           0x0000000000004000
+
+// range requires a runtime mapping
+#define EFI_MEMORY_RUNTIME      0x8000000000000000
+
 /* Sanity check for __curthread() */
 CTASSERT(offsetof(struct pcpu, pc_curthread) == 0);
 
@@ -1299,20 +1333,14 @@ isa_irq_pending(void)
 u_int basemem;
 
 static int
-add_smap_entry(struct bios_smap *smap, vm_paddr_t *physmap, int *physmap_idxp)
+add_physmap_entry(uint64_t base, uint64_t length, vm_paddr_t *physmap,
+    int *physmap_idxp)
 {
 	int i, insert_idx, physmap_idx;
 
 	physmap_idx = *physmap_idxp;
 
-	if (boothowto & RB_VERBOSE)
-		printf("SMAP type=%02x base=%016lx len=%016lx\n",
-		    smap->type, smap->base, smap->length);
-
-	if (smap->type != SMAP_TYPE_MEMORY)
-		return (1);
-
-	if (smap->length == 0)
+	if (length == 0)
 		return (0);
 
 	/*
@@ -1321,8 +1349,8 @@ add_smap_entry(struct bios_smap *smap, v
 	 */
 	insert_idx = physmap_idx + 2;
 	for (i = 0; i <= physmap_idx; i += 2) {
-		if (smap->base < physmap[i + 1]) {
-			if (smap->base + smap->length <= physmap[i]) {
+		if (base < physmap[i + 1]) {
+			if (base + length <= physmap[i]) {
 				insert_idx = i;
 				break;
 			}
@@ -1334,15 +1362,14 @@ add_smap_entry(struct bios_smap *smap, v
 	}
 
 	/* See if we can prepend to the next entry. */
-	if (insert_idx <= physmap_idx &&
-	    smap->base + smap->length == physmap[insert_idx]) {
-		physmap[insert_idx] = smap->base;
+	if (insert_idx <= physmap_idx && base + length == physmap[insert_idx]) {
+		physmap[insert_idx] = base;
 		return (1);
 	}
 
 	/* See if we can append to the previous entry. */
-	if (insert_idx > 0 && smap->base == physmap[insert_idx - 1]) {
-		physmap[insert_idx - 1] += smap->length;
+	if (insert_idx > 0 && base == physmap[insert_idx - 1]) {
+		physmap[insert_idx - 1] += length;
 		return (1);
 	}
 
@@ -1364,11 +1391,130 @@ add_smap_entry(struct bios_smap *smap, v
 	}
 
 	/* Insert the new entry. */
-	physmap[insert_idx] = smap->base;
-	physmap[insert_idx + 1] = smap->base + smap->length;
+	physmap[insert_idx] = base;
+	physmap[insert_idx + 1] = base + length;
 	return (1);
 }
 
+static void
+add_smap_entries(struct bios_smap *smapbase, vm_paddr_t *physmap,
+    int *physmap_idx)
+{
+	struct bios_smap *smap, *smapend;
+	u_int32_t smapsize;
+
+	/*
+	 * Memory map from INT 15:E820.
+	 *
+	 * subr_module.c says:
+	 * "Consumer may safely assume that size value precedes data."
+	 * ie: an int32_t immediately precedes smap.
+	 */
+	smapsize = *((u_int32_t *)smapbase - 1);
+	smapend = (struct bios_smap *)((uintptr_t)smapbase + smapsize);
+
+	for (smap = smapbase; smap < smapend; smap++) {
+		if (boothowto & RB_VERBOSE)
+			printf("SMAP type=%02x base=%016lx "
+			    "len=%016lx\n",
+			    smap->type, smap->base, smap->length);
+
+		if (smap->type != SMAP_TYPE_MEMORY)
+			continue;
+
+		if (!add_physmap_entry(smap->base, smap->length,
+		    physmap, physmap_idx))
+			break;
+	}
+}
+
+static void
+add_efi_map_entries(struct efi_header *efihdr, vm_paddr_t *physmap,
+    int *physmap_idx)
+{
+	struct efi_descriptor *map, *p;
+	size_t efisz;
+	int ndesc, i;
+
+	static char *types[] = {
+		"Reserved",
+		"LoaderCode",
+		"LoaderData",
+		"BootServicesCode",
+		"BootServicesData",
+		"RuntimeServicesCode",
+		"RuntimeServicesData",
+		"ConventionalMemory",
+		"UnusableMemory",
+		"ACPIReclaimMemory",
+		"ACPIMemoryNVS",
+		"MemoryMappedIO",
+		"MemoryMappedIOPortSpace",
+		"PalCode"
+	};
+
+	/*
+	 * Memory map data provided by UEFI via the GetMemoryMap
+	 * Boot Services API.
+	 */
+	efisz = (sizeof(struct efi_header) + 0xf) & ~0xf;
+	map = (struct efi_descriptor *)((uint8_t *)efihdr + efisz); 
+
+	ndesc = efihdr->memory_size / efihdr->descriptor_size;
+
+	if (boothowto & RB_VERBOSE)
+		printf("%23s %12s %12s %8s %4s\n",
+		    "Type", "Physical", "Virtual", "#Pages", "Attr");
+
+	for (i = 0, p = map; i < ndesc; i++,
+	    p = efi_next_descriptor(p, efihdr->descriptor_size)) {
+		if (boothowto & RB_VERBOSE) {
+			printf("%23s %012lx %012lx %08lx ",
+			   types[p->type],
+			   p->physical_start,
+			   p->virtual_start,
+			   p->pages);
+			if (p->attribute & EFI_MEMORY_UC)
+			    printf("UC ");
+			if (p->attribute & EFI_MEMORY_WC)
+			    printf("WC ");
+			if (p->attribute & EFI_MEMORY_WT)
+			    printf("WT ");
+			if (p->attribute & EFI_MEMORY_WB)
+			    printf("WB ");
+			if (p->attribute & EFI_MEMORY_UCE)
+			    printf("UCE ");
+			if (p->attribute & EFI_MEMORY_WP)
+			    printf("WP ");
+			if (p->attribute & EFI_MEMORY_RP)
+			    printf("RP ");
+			if (p->attribute & EFI_MEMORY_XP)
+			    printf("XP ");
+			if (p->attribute & EFI_MEMORY_RUNTIME)
+			    printf("RUNTIME");
+			printf("\n");
+		}
+
+		switch (p->type) {
+		case EfiLoaderCode:
+		case EfiLoaderData:
+		case EfiBootServicesCode:
+		case EfiBootServicesData:
+		case EfiConventionalMemory:
+			/*
+			 * We're allowed to use any entry with these types.
+			 */
+			break;
+		default:
+			continue;
+		}
+
+		if (!add_physmap_entry(p->physical_start,
+		    (p->pages * PAGE_SIZE), physmap, physmap_idx))
+			break;
+	}
+}
+
 /*
  * Populate the (physmap) array with base/bound pairs describing the
  * available physical memory in the system, then test this memory and
@@ -1386,32 +1532,30 @@ getmemsize(caddr_t kmdp, u_int64_t first
 	vm_paddr_t pa, physmap[PHYSMAP_SIZE];
 	u_long physmem_start, physmem_tunable, memtest;
 	pt_entry_t *pte;
-	struct bios_smap *smapbase, *smap, *smapend;
-	u_int32_t smapsize;
+	struct bios_smap *smapbase;
+	struct efi_header *efihdr;
 	quad_t dcons_addr, dcons_size;
 
 	bzero(physmap, sizeof(physmap));
 	basemem = 0;
 	physmap_idx = 0;
 
-	/*
-	 * get memory map from INT 15:E820, kindly supplied by the loader.
-	 *
-	 * subr_module.c says:
-	 * "Consumer may safely assume that size value precedes data."
-	 * ie: an int32_t immediately precedes smap.
-	 */
+	efihdr = (struct efi_header *)preload_search_info(kmdp,
+	    MODINFO_METADATA | MODINFOMD_EFI);
 	smapbase = (struct bios_smap *)preload_search_info(kmdp,
 	    MODINFO_METADATA | MODINFOMD_SMAP);
-	if (smapbase == NULL)
-		panic("No BIOS smap info from loader!");
-
-	smapsize = *((u_int32_t *)smapbase - 1);
-	smapend = (struct bios_smap *)((uintptr_t)smapbase + smapsize);
+	if (efihdr == NULL && smapbase == NULL)
+		panic("No BIOS smap or EFI map info from loader!");
 
-	for (smap = smapbase; smap < smapend; smap++)
-		if (!add_smap_entry(smap, physmap, &physmap_idx))
-			break;
+	if (efihdr != NULL) {
+		if (boothowto & RB_VERBOSE)
+			printf("Using EFI memory map.\n");
+		add_efi_map_entries(efihdr, physmap, &physmap_idx);
+	} else {
+		if (boothowto & RB_VERBOSE)
+			printf("Using BIOS SMAP memory map.\n");
+		add_smap_entries(smapbase, physmap, &physmap_idx);
+	}
 
 	/*
 	 * Find the 'base memory' segment for SMP


More information about the svn-src-projects mailing list