Module Name: src Committed By: riastradh Date: Tue Aug 30 11:03:36 UTC 2022
Modified Files: src/sys/arch/x86/conf: files.x86 Added Files: src/sys/arch/x86/x86: efi_machdep.c Removed Files: src/sys/arch/x86/x86: efi.c Log Message: x86: Rename x86/efi.c -> x86/efi_machdep.c. Avoid collision with dev/efi.c. To generate a diff of this commit: cvs rdiff -u -r1.122 -r1.123 src/sys/arch/x86/conf/files.x86 cvs rdiff -u -r1.22 -r0 src/sys/arch/x86/x86/efi.c cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/x86/efi_machdep.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/x86/conf/files.x86 diff -u src/sys/arch/x86/conf/files.x86:1.122 src/sys/arch/x86/conf/files.x86:1.123 --- src/sys/arch/x86/conf/files.x86:1.122 Wed Jul 21 23:26:15 2021 +++ src/sys/arch/x86/conf/files.x86 Tue Aug 30 11:03:36 2022 @@ -1,4 +1,4 @@ -# $NetBSD: files.x86,v 1.122 2021/07/21 23:26:15 jmcneill Exp $ +# $NetBSD: files.x86,v 1.123 2022/08/30 11:03:36 riastradh Exp $ # options for MP configuration through the MP spec defflag opt_mpbios.h MPBIOS MPDEBUG MPBIOS_SCANPCI @@ -89,7 +89,7 @@ file arch/x86/x86/core_machdep.c coredum file arch/x86/x86/cpu_topology.c machdep file arch/x86/x86/db_memrw.c ddb | kgdb file arch/x86/x86/db_trace.c ddb -file arch/x86/x86/efi.c machdep +file arch/x86/x86/efi_machdep.c machdep file arch/x86/x86/errata.c machdep file arch/x86/x86/genfb_machdep.c machdep file arch/x86/x86/identcpu.c machdep Added files: Index: src/sys/arch/x86/x86/efi_machdep.c diff -u /dev/null src/sys/arch/x86/x86/efi_machdep.c:1.1 --- /dev/null Tue Aug 30 11:03:36 2022 +++ src/sys/arch/x86/x86/efi_machdep.c Tue Aug 30 11:03:36 2022 @@ -0,0 +1,550 @@ +/* $NetBSD: efi_machdep.c,v 1.1 2022/08/30 11:03:36 riastradh Exp $ */ + +/*- + * Copyright (c) 2016 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: efi_machdep.c,v 1.1 2022/08/30 11:03:36 riastradh Exp $"); + +#include <sys/kmem.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/uuid.h> + +#include <uvm/uvm_extern.h> + +#include <machine/bootinfo.h> +#include <x86/bus_defs.h> +#include <x86/bus_funcs.h> +#include <x86/efi.h> + +#include <dev/mm.h> +#if NPCI > 0 +#include <dev/pci/pcivar.h> /* for pci_mapreg_map_enable_decode */ +#endif + +const struct uuid EFI_UUID_ACPI20 = EFI_TABLE_ACPI20; +const struct uuid EFI_UUID_ACPI10 = EFI_TABLE_ACPI10; +const struct uuid EFI_UUID_SMBIOS = EFI_TABLE_SMBIOS; +const struct uuid EFI_UUID_SMBIOS3 = EFI_TABLE_SMBIOS3; + +static vaddr_t efi_getva(paddr_t); +static void efi_relva(paddr_t, vaddr_t); +struct efi_cfgtbl *efi_getcfgtblhead(void); +void efi_aprintcfgtbl(void); +void efi_aprintuuid(const struct uuid *); +bool efi_uuideq(const struct uuid *, const struct uuid *); + +static bool efi_is32x64 = false; +static paddr_t efi_systbl_pa; +static struct efi_systbl *efi_systbl_va = NULL; +static struct efi_cfgtbl *efi_cfgtblhead_va = NULL; +static struct efi_e820memmap { + struct btinfo_memmap bim; + struct bi_memmap_entry entry[VM_PHYSSEG_MAX - 1]; +} efi_e820memmap; + +/* + * Map a physical address (PA) to a newly allocated virtual address (VA). + * The VA must be freed using efi_relva(). + */ +static vaddr_t +efi_getva(paddr_t pa) +{ + vaddr_t va; + int rv; + + rv = _x86_memio_map(x86_bus_space_mem, pa, + PAGE_SIZE, 0, (bus_space_handle_t *)&va); + if (rv != 0) { + aprint_debug("efi: unable to allocate va\n"); + return 0; + } + + return va; +} + +/* + * Free a virtual address (VA) allocated using efi_getva(). + */ +static void +efi_relva(paddr_t pa, vaddr_t va) +{ + (void)_x86_memio_unmap(x86_bus_space_mem, (bus_space_handle_t)va, + PAGE_SIZE, NULL); +} + +/* + * Test if 2 UUIDs matches. + */ +bool +efi_uuideq(const struct uuid * a, const struct uuid * b) +{ + return !memcmp(a, b, sizeof(struct uuid)); +} + +/* + * Print an UUID in a human-readable manner. + */ +void +efi_aprintuuid(const struct uuid * uuid) +{ + int i; + + aprint_debug(" %08" PRIx32 "", uuid->time_low); + aprint_debug("-%04" PRIx16 "", uuid->time_mid); + aprint_debug("-%04" PRIx16 "", uuid->time_hi_and_version); + aprint_debug("-%02" PRIx8 "", uuid->clock_seq_hi_and_reserved); + aprint_debug("-%02" PRIx8 "", uuid->clock_seq_low); + aprint_debug("-"); + for (i = 0; i < _UUID_NODE_LEN; i++) { + aprint_debug("%02" PRIx8 "", uuid->node[i]); + } + /* If known, also print the human-readable name */ + if (efi_uuideq(uuid, &EFI_UUID_ACPI20)) { + aprint_debug(" ACPI 2.0"); + } else if (efi_uuideq(uuid, &EFI_UUID_ACPI10)) { + aprint_debug(" ACPI 1.0"); + } else if (efi_uuideq(uuid, &EFI_UUID_SMBIOS)) { + aprint_debug(" SMBIOS"); + } else if (efi_uuideq(uuid, &EFI_UUID_SMBIOS3)) { + aprint_debug(" SMBIOS3"); + } +} + +/* + * Return the VA of the cfgtbl. Must be freed using efi_relva(). + */ +struct efi_cfgtbl * +efi_getcfgtblhead(void) +{ + paddr_t pa; + vaddr_t va; + + if (efi_cfgtblhead_va != NULL) + return efi_cfgtblhead_va; + + if (efi_is32x64) { +#if defined(__amd64__) + struct efi_systbl32 *systbl32 = (void *) efi_systbl_va; + pa = systbl32->st_cfgtbl; +#elif defined(__i386__) + struct efi_systbl64 *systbl64 = (void *) efi_systbl_va; + if (systbl64->st_cfgtbl & 0xffffffff00000000ULL) + return NULL; + pa = (paddr_t) systbl64->st_cfgtbl; +#endif + } else + pa = (paddr_t)(u_long) efi_systbl_va->st_cfgtbl; + aprint_debug("efi: cfgtbl at pa %" PRIxPADDR "\n", pa); + va = efi_getva(pa); + aprint_debug("efi: cfgtbl mapped at va %" PRIxVADDR "\n", va); + efi_cfgtblhead_va = (struct efi_cfgtbl *) va; + efi_aprintcfgtbl(); + + return efi_cfgtblhead_va; +} + +/* + * Print the config tables. + */ +void +efi_aprintcfgtbl(void) +{ + struct efi_cfgtbl *ct; + unsigned long count; + + if (efi_is32x64) { +#if defined(__amd64__) + struct efi_systbl32 *systbl32 = (void *) efi_systbl_va; + struct efi_cfgtbl32 *ct32 = (void *) efi_cfgtblhead_va; + + count = systbl32->st_entries; + aprint_debug("efi: %lu cfgtbl entries:\n", count); + for (; count; count--, ct32++) { + aprint_debug("efi: %08" PRIx32, ct32->ct_data); + efi_aprintuuid(&ct32->ct_uuid); + aprint_debug("\n"); + } +#elif defined(__i386__) + struct efi_systbl64 *systbl64 = (void *) efi_systbl_va; + struct efi_cfgtbl64 *ct64 = (void *) efi_cfgtblhead_va; + uint64_t count64 = systbl64->st_entries; + + aprint_debug("efi: %" PRIu64 " cfgtbl entries:\n", count64); + for (; count64; count64--, ct64++) { + aprint_debug("efi: %016" PRIx64, ct64->ct_data); + efi_aprintuuid(&ct64->ct_uuid); + aprint_debug("\n"); + } +#endif + return; + } + + ct = efi_cfgtblhead_va; + count = efi_systbl_va->st_entries; + aprint_debug("efi: %lu cfgtbl entries:\n", count); + for (; count; count--, ct++) { + aprint_debug("efi: %p", ct->ct_data); + efi_aprintuuid(&ct->ct_uuid); + aprint_debug("\n"); + } +} + +/* + * Return the VA of the config table with the given UUID if found. + * The VA must be freed using efi_relva(). + */ +void * +efi_getcfgtbl(const struct uuid * uuid) +{ + paddr_t pa; + vaddr_t va; + + pa = efi_getcfgtblpa(uuid); + if (pa == 0) + return NULL; + va = efi_getva(pa); + return (void *) va; +} + +/* + * Return the PA of the first config table. + */ +paddr_t +efi_getcfgtblpa(const struct uuid * uuid) +{ + struct efi_cfgtbl *ct; + unsigned long count; + + if (efi_is32x64) { +#if defined(__amd64__) + struct efi_systbl32 *systbl32 = (void *) efi_systbl_va; + struct efi_cfgtbl32 *ct32 = (void *) efi_cfgtblhead_va; + + count = systbl32->st_entries; + for (; count; count--, ct32++) + if (efi_uuideq(&ct32->ct_uuid, uuid)) + return ct32->ct_data; +#elif defined(__i386__) + struct efi_systbl64 *systbl64 = (void *) efi_systbl_va; + struct efi_cfgtbl64 *ct64 = (void *) efi_cfgtblhead_va; + uint64_t count64 = systbl64->st_entries; + + for (; count64; count64--, ct64++) + if (efi_uuideq(&ct64->ct_uuid, uuid)) + if (!(ct64->ct_data & 0xffffffff00000000ULL)) + return ct64->ct_data; +#endif + return 0; /* Not found. */ + } + + ct = efi_cfgtblhead_va; + count = efi_systbl_va->st_entries; + for (; count; count--, ct++) + if (efi_uuideq(&ct->ct_uuid, uuid)) + return (paddr_t)(u_long) ct->ct_data; + + return 0; /* Not found. */ +} + +/* Return the PA of the EFI System Table. */ +paddr_t +efi_getsystblpa(void) +{ + struct btinfo_efi *bi; + paddr_t pa; + + bi = lookup_bootinfo(BTINFO_EFI); + if (bi == NULL) { + /* Unable to locate the EFI System Table. */ + return 0; + } + if (sizeof(paddr_t) == 4 && /* XXX i386 with PAE */ + (bi->systblpa & 0xffffffff00000000ULL)) { + /* Unable to access EFI System Table. */ + return 0; + } + if (bi->common.len > 16 && (bi->flags & BI_EFI_32BIT)) { + /* boot from 32bit UEFI */ +#if defined(__amd64__) + efi_is32x64 = true; +#endif + } else { + /* boot from 64bit UEFI */ +#if defined(__i386__) + efi_is32x64 = true; +#endif + } + pa = (paddr_t) bi->systblpa; + return pa; +} + +/* + * Return a pointer to the EFI System Table. The pointer must be freed using + * efi_relva(). + */ +struct efi_systbl * +efi_getsystbl(void) +{ + paddr_t pa; + vaddr_t va; + struct efi_systbl *systbl; + + if (efi_systbl_va) + return efi_systbl_va; + + pa = efi_getsystblpa(); + if (pa == 0) + return NULL; + + aprint_normal("efi: systbl at pa %" PRIxPADDR "\n", pa); + efi_systbl_pa = pa; + va = efi_getva(pa); + aprint_debug("efi: systbl mapped at va %" PRIxVADDR "\n", va); + + if (efi_is32x64) { +#if defined(__amd64__) + struct efi_systbl32 *systbl32 = (struct efi_systbl32 *) va; + + /* XXX Check the signature and the CRC32 */ + aprint_debug("efi: signature %" PRIx64 " revision %" PRIx32 + " crc32 %" PRIx32 "\n", systbl32->st_hdr.th_sig, + systbl32->st_hdr.th_rev, systbl32->st_hdr.th_crc32); + aprint_debug("efi: firmware revision %" PRIx32 "\n", + systbl32->st_fwrev); + /* + * XXX Also print fwvendor, which is an UCS-2 string (use + * some UTF-16 routine?) + */ + aprint_debug("efi: runtime services at pa 0x%08" PRIx32 "\n", + systbl32->st_rt); + aprint_debug("efi: boot services at pa 0x%08" PRIx32 "\n", + systbl32->st_bs); + + efi_systbl_va = (struct efi_systbl *) systbl32; +#elif defined(__i386__) + struct efi_systbl64 *systbl64 = (struct efi_systbl64 *) va; + + /* XXX Check the signature and the CRC32 */ + aprint_debug("efi: signature %" PRIx64 " revision %" PRIx32 + " crc32 %" PRIx32 "\n", systbl64->st_hdr.th_sig, + systbl64->st_hdr.th_rev, systbl64->st_hdr.th_crc32); + aprint_debug("efi: firmware revision %" PRIx32 "\n", + systbl64->st_fwrev); + /* + * XXX Also print fwvendor, which is an UCS-2 string (use + * some UTF-16 routine?) + */ + aprint_debug("efi: runtime services at pa 0x%016" PRIx64 "\n", + systbl64->st_rt); + aprint_debug("efi: boot services at pa 0x%016" PRIx64 "\n", + systbl64->st_bs); + + efi_systbl_va = (struct efi_systbl *) systbl64; +#endif + return efi_systbl_va; + } + + systbl = (struct efi_systbl *) va; + /* XXX Check the signature and the CRC32 */ + aprint_debug("efi: signature %" PRIx64 " revision %" PRIx32 + " crc32 %" PRIx32 "\n", systbl->st_hdr.th_sig, + systbl->st_hdr.th_rev, systbl->st_hdr.th_crc32); + aprint_debug("efi: firmware revision %" PRIx32 "\n", systbl->st_fwrev); + /* + * XXX Also print fwvendor, which is an UCS-2 string (use + * some UTF-16 routine?) + */ + aprint_debug("efi: runtime services at pa %p\n", systbl->st_rt); + aprint_debug("efi: boot services at pa %p\n", systbl->st_bs); + + efi_systbl_va = systbl; + return efi_systbl_va; +} + +/* + * EFI is available if we are able to locate the EFI System Table. + */ +void +efi_init(void) +{ + + if (efi_getsystbl() == NULL) { + aprint_debug("efi: missing or invalid systbl\n"); + bootmethod_efi = false; + return; + } + if (efi_getcfgtblhead() == NULL) { + aprint_debug("efi: missing or invalid cfgtbl\n"); + efi_relva(efi_systbl_pa, (vaddr_t) efi_systbl_va); + bootmethod_efi = false; + return; + } + bootmethod_efi = true; +#if NPCI > 0 + pci_mapreg_map_enable_decode = true; /* PR port-amd64/53286 */ +#endif +} + +bool +efi_probe(void) +{ + + return bootmethod_efi; +} + +int +efi_getbiosmemtype(uint32_t type, uint64_t attr) +{ + + switch (type) { + case EFI_MD_TYPE_CODE: + case EFI_MD_TYPE_DATA: + case EFI_MD_TYPE_BS_CODE: + case EFI_MD_TYPE_BS_DATA: + case EFI_MD_TYPE_FREE: + return (attr & EFI_MD_ATTR_WB) ? BIM_Memory : BIM_Reserved; + + case EFI_MD_TYPE_RECLAIM: + return BIM_ACPI; + + case EFI_MD_TYPE_FIRMWARE: + return BIM_NVS; + + case EFI_MD_TYPE_PMEM: + return BIM_PMEM; + + case EFI_MD_TYPE_NULL: + case EFI_MD_TYPE_RT_CODE: + case EFI_MD_TYPE_RT_DATA: + case EFI_MD_TYPE_BAD: + case EFI_MD_TYPE_IOMEM: + case EFI_MD_TYPE_IOPORT: + case EFI_MD_TYPE_PALCODE: + default: + return BIM_Reserved; + } +} + +const char * +efi_getmemtype_str(uint32_t type) +{ + static const char *efimemtypes[] = { + "Reserved", + "LoaderCode", + "LoaderData", + "BootServicesCode", + "BootServicesData", + "RuntimeServicesCode", + "RuntimeServicesData", + "ConventionalMemory", + "UnusableMemory", + "ACPIReclaimMemory", + "ACPIMemoryNVS", + "MemoryMappedIO", + "MemoryMappedIOPortSpace", + "PalCode", + "PersistentMemory", + }; + + if (type < __arraycount(efimemtypes)) + return efimemtypes[type]; + return "unknown"; +} + +struct btinfo_memmap * +efi_get_e820memmap(void) +{ + struct btinfo_efimemmap *efimm; + struct bi_memmap_entry *entry; + struct efi_md *md; + uint64_t addr, size; + uint64_t start_addr = 0; /* XXX gcc -Os: maybe-uninitialized */ + uint64_t end_addr = 0; /* XXX gcc -Os: maybe-uninitialized */ + uint32_t i; + int n, type, seg_type = -1; + + if (efi_e820memmap.bim.common.type == BTINFO_MEMMAP) + return &efi_e820memmap.bim; + + efimm = lookup_bootinfo(BTINFO_EFIMEMMAP); + if (efimm == NULL) + return NULL; + + for (n = 0, i = 0; i < efimm->num; i++) { + md = (struct efi_md *)(efimm->memmap + efimm->size * i); + addr = md->md_phys; + size = md->md_pages * EFI_PAGE_SIZE; + type = efi_getbiosmemtype(md->md_type, md->md_attr); + +#ifdef DEBUG_MEMLOAD + printf("MEMMAP: p0x%016" PRIx64 "-0x%016" PRIx64 + ", v0x%016" PRIx64 "-0x%016" PRIx64 + ", size=0x%016" PRIx64 ", attr=0x%016" PRIx64 + ", type=%d(%s)\n", + addr, addr + size - 1, + md->md_virt, md->md_virt + size - 1, + size, md->md_attr, md->md_type, + efi_getmemtype_str(md->md_type)); +#endif + + if (seg_type == -1) { + /* first entry */ + } else if (seg_type == type && end_addr == addr) { + /* continuous region */ + end_addr = addr + size; + continue; + } else { + entry = &efi_e820memmap.bim.entry[n]; + entry->addr = start_addr; + entry->size = end_addr - start_addr; + entry->type = seg_type; + if (++n == VM_PHYSSEG_MAX) + break; + } + + start_addr = addr; + end_addr = addr + size; + seg_type = type; + } + if (i > 0 && n < VM_PHYSSEG_MAX) { + entry = &efi_e820memmap.bim.entry[n]; + entry->addr = start_addr; + entry->size = end_addr - start_addr; + entry->type = seg_type; + ++n; + } else if (n == VM_PHYSSEG_MAX) { + printf("WARNING: too many memory segments" + "(increase VM_PHYSSEG_MAX)\n"); + } + + efi_e820memmap.bim.num = n; + efi_e820memmap.bim.common.len = + (intptr_t)&efi_e820memmap.bim.entry[n] - (intptr_t)&efi_e820memmap; + efi_e820memmap.bim.common.type = BTINFO_MEMMAP; + return &efi_e820memmap.bim; +}