From owner-svn-src-projects@FreeBSD.ORG Mon Feb 4 23:24:05 2013 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 6DA96100; Mon, 4 Feb 2013 23:24:05 +0000 (UTC) (envelope-from benno@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 4D2368A6; Mon, 4 Feb 2013 23:24:05 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id r14NO52N031249; Mon, 4 Feb 2013 23:24:05 GMT (envelope-from benno@svn.freebsd.org) Received: (from benno@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id r14NO5ta031248; Mon, 4 Feb 2013 23:24:05 GMT (envelope-from benno@svn.freebsd.org) Message-Id: <201302042324.r14NO5ta031248@svn.freebsd.org> From: Benno Rice Date: Mon, 4 Feb 2013 23:24:05 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r246337 - projects/uefi/sys/amd64/amd64 X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 04 Feb 2013 23:24:05 -0000 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 #include #include +#include #include #include #include @@ -142,6 +143,39 @@ __FBSDID("$FreeBSD$"); #include #include +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