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