1128760Spjd/* $OpenBSD: efi_machdep.c,v 1.7 2023/07/08 07:18:39 kettenis Exp $ */ 2141994Spjd 3128760Spjd/* 4128760Spjd * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org> 5128760Spjd * 6128760Spjd * Permission to use, copy, modify, and distribute this software for any 7128760Spjd * purpose with or without fee is hereby granted, provided that the above 8128760Spjd * copyright notice and this permission notice appear in all copies. 9128760Spjd * 10128760Spjd * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11128760Spjd * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12128760Spjd * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13128760Spjd * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14128760Spjd * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15128760Spjd * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16128760Spjd * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17128760Spjd */ 18128760Spjd 19128760Spjd#include <sys/param.h> 20128760Spjd#include <sys/device.h> 21128760Spjd#include <sys/proc.h> 22128760Spjd#include <sys/systm.h> 23128760Spjd#include <sys/user.h> 24128760Spjd 25128760Spjd#include <uvm/uvm_extern.h> 26128760Spjd 27128760Spjd#include <machine/biosvar.h> 28128760Spjdextern paddr_t cr3_reuse_pcid; 29128760Spjd 30128760Spjd#include <dev/efi/efi.h> 31128760Spjd#include <machine/efivar.h> 32128760Spjd 33128760Spjdextern EFI_MEMORY_DESCRIPTOR *mmap; 34128760Spjd 35128760Spjdint efi_match(struct device *, void *, void *); 36128760Spjdvoid efi_attach(struct device *, struct device *, void *); 37128760Spjd 38128760Spjdconst struct cfattach efi_ca = { 39128760Spjd sizeof(struct efi_softc), efi_match, efi_attach 40128760Spjd}; 41128760Spjd 42128760Spjdvoid efi_map_runtime(struct efi_softc *); 43128760Spjd 44128760Spjdlabel_t efi_jmpbuf; 45128760Spjd 46128760Spjdint 47128760Spjdefi_match(struct device *parent, void *match, void *aux) 48128760Spjd{ 49128760Spjd struct bios_attach_args *ba = aux; 50128760Spjd struct cfdata *cf = match; 51128760Spjd 52128760Spjd if (strcmp(ba->ba_name, cf->cf_driver->cd_name) == 0 && 53128760Spjd bios_efiinfo->system_table != 0) 54128760Spjd return 1; 55128889Spjd 56128760Spjd return 0; 57128760Spjd} 58128760Spjd 59128760Spjdvoid 60128760Spjdefi_attach(struct device *parent, struct device *self, void *aux) 61128760Spjd{ 62128760Spjd struct efi_softc *sc = (struct efi_softc *)self; 63133318Sphk struct bios_attach_args *ba = aux; 64128760Spjd uint32_t mmap_desc_ver = bios_efiinfo->mmap_desc_ver; 65128760Spjd uint64_t system_table; 66128760Spjd bus_space_handle_t memh; 67130585Sphk EFI_SYSTEM_TABLE *st; 68128760Spjd uint16_t major, minor; 69128760Spjd int i; 70128760Spjd 71128760Spjd if (mmap_desc_ver != EFI_MEMORY_DESCRIPTOR_VERSION) { 72128760Spjd printf(": unsupported memory descriptor version %d\n", 73128760Spjd mmap_desc_ver); 74128760Spjd return; 75128760Spjd } 76128760Spjd 77128760Spjd system_table = bios_efiinfo->system_table; 78128760Spjd KASSERT(system_table); 79128760Spjd 80128760Spjd if (bus_space_map(ba->ba_memt, system_table, sizeof(EFI_SYSTEM_TABLE), 81128760Spjd BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_CACHEABLE, &memh)) { 82128760Spjd printf(": can't map system table\n"); 83128760Spjd return; 84128760Spjd } 85128835Spjd 86128760Spjd st = bus_space_vaddr(ba->ba_memt, memh); 87128760Spjd sc->sc_rs = st->RuntimeServices; 88128760Spjd 89128760Spjd major = st->Hdr.Revision >> 16; 90128760Spjd minor = st->Hdr.Revision & 0xffff; 91128760Spjd printf(": UEFI %d.%d", major, minor / 10); 92128760Spjd if (minor % 10) 93128760Spjd printf(".%d", minor % 10); 94128760Spjd printf("\n"); 95128760Spjd 96128760Spjd /* Early implementations can be buggy. */ 97128760Spjd if (major < 2 || (major == 2 && minor < 10)) 98128760Spjd return; 99128760Spjd 100128760Spjd if ((bios_efiinfo->flags & BEI_64BIT) == 0) 101128760Spjd return; 102128760Spjd 103128760Spjd if (bios_efiinfo->flags & BEI_ESRT) 104128760Spjd sc->sc_esrt = (void *)bios_efiinfo->config_esrt; 105128760Spjd 106141561Spjd efi_map_runtime(sc); 107128760Spjd 108141561Spjd /* 109128760Spjd * Activate our pmap such that we can access the 110128760Spjd * FirmwareVendor and ConfigurationTable fields. 111128760Spjd */ 112128760Spjd efi_enter(sc); 113128760Spjd if (st->FirmwareVendor) { 114141561Spjd printf("%s: ", sc->sc_dev.dv_xname); 115128760Spjd for (i = 0; st->FirmwareVendor[i]; i++) 116128760Spjd printf("%c", st->FirmwareVendor[i]); 117128760Spjd printf(" rev 0x%x\n", st->FirmwareRevision); 118128760Spjd } 119141561Spjd efi_leave(sc); 120128760Spjd} 121128760Spjd 122128760Spjdvoid 123128760Spjdefi_map_runtime(struct efi_softc *sc) 124128760Spjd{ 125128760Spjd uint32_t mmap_size = bios_efiinfo->mmap_size; 126128760Spjd uint32_t mmap_desc_size = bios_efiinfo->mmap_desc_size; 127128760Spjd EFI_MEMORY_DESCRIPTOR *desc; 128128760Spjd int i; 129128760Spjd 130141561Spjd /* 131128760Spjd * We don't really want some random executable non-OpenBSD 132128760Spjd * code lying around in kernel space. So create a separate 133128760Spjd * pmap and only activate it when we call runtime services. 134128760Spjd */ 135128760Spjd sc->sc_pm = pmap_create(); 136128760Spjd 137141561Spjd desc = mmap; 138128760Spjd for (i = 0; i < mmap_size / mmap_desc_size; i++) { 139128760Spjd if (desc->Attribute & EFI_MEMORY_RUNTIME) { 140128760Spjd vaddr_t va = desc->VirtualStart; 141128760Spjd paddr_t pa = desc->PhysicalStart; 142128760Spjd int npages = desc->NumberOfPages; 143128760Spjd vm_prot_t prot = PROT_READ | PROT_WRITE; 144128760Spjd 145128760Spjd#ifdef EFI_DEBUG 146128760Spjd printf("type 0x%x pa 0x%llx va 0x%llx pages 0x%llx attr 0x%llx\n", 147128760Spjd desc->Type, desc->PhysicalStart, 148128760Spjd desc->VirtualStart, desc->NumberOfPages, 149128760Spjd desc->Attribute); 150128760Spjd#endif 151128760Spjd 152128760Spjd /* 153128760Spjd * If the virtual address is still zero, use 154128760Spjd * an identity mapping. 155128760Spjd */ 156128760Spjd if (va == 0) 157128760Spjd va = pa; 158128760Spjd 159128760Spjd /* 160128760Spjd * Normal memory is expected to be "write 161128760Spjd * back" cacheable. Everything else is mapped 162128760Spjd * as device memory. 163128760Spjd */ 164128760Spjd if ((desc->Attribute & EFI_MEMORY_WB) == 0) 165128760Spjd pa |= PMAP_NOCACHE; 166128760Spjd 167128760Spjd /* 168128760Spjd * Only make pages marked as runtime service code 169128760Spjd * executable. This violates the standard but it 170128760Spjd * seems we can get away with it. 171128760Spjd */ 172128760Spjd if (desc->Type == EfiRuntimeServicesCode) 173128760Spjd prot |= PROT_EXEC; 174128760Spjd 175128760Spjd if (desc->Attribute & EFI_MEMORY_RP) 176131188Spjd prot &= ~PROT_READ; 177131188Spjd if (desc->Attribute & EFI_MEMORY_XP) 178128760Spjd prot &= ~PROT_EXEC; 179128760Spjd if (desc->Attribute & EFI_MEMORY_RO) 180131188Spjd prot &= ~PROT_WRITE; 181128760Spjd 182128760Spjd while (npages--) { 183128760Spjd pmap_enter(sc->sc_pm, va, pa, prot, 184128760Spjd prot | PMAP_WIRED | PMAP_EFI); 185128760Spjd va += PAGE_SIZE; 186128760Spjd pa += PAGE_SIZE; 187128760Spjd } 188128760Spjd } 189128760Spjd 190128760Spjd desc = NextMemoryDescriptor(desc, mmap_desc_size); 191128760Spjd } 192128760Spjd} 193128760Spjd 194128760Spjdvoid 195128760Spjdefi_fault(void) 196128760Spjd{ 197128760Spjd longjmp(&efi_jmpbuf); 198128760Spjd} 199131188Spjd__asm(".pushsection .nofault, \"a\"; .quad efi_fault; .popsection"); 200128760Spjd 201128760Spjdvoid 202131188Spjdefi_enter(struct efi_softc *sc) 203131188Spjd{ 204131188Spjd sc->sc_psw = intr_disable(); 205131188Spjd sc->sc_cr3 = rcr3() | cr3_reuse_pcid; 206131188Spjd lcr3(sc->sc_pm->pm_pdirpa | (pmap_use_pcid ? PCID_EFI : 0)); 207128760Spjd 208128760Spjd fpu_kernel_enter(); 209128760Spjd 210128760Spjd curpcb->pcb_onfault = (void *)efi_fault; 211128760Spjd if (curcpu()->ci_feature_sefflags_edx & SEFF0EDX_IBT) 212128760Spjd lcr4(rcr4() & ~CR4_CET); 213128760Spjd} 214128760Spjd 215141561Spjdvoid 216141561Spjdefi_leave(struct efi_softc *sc) 217141742Spjd{ 218128760Spjd if (curcpu()->ci_feature_sefflags_edx & SEFF0EDX_IBT) 219128760Spjd lcr4(rcr4() | CR4_CET); 220128760Spjd curpcb->pcb_onfault = NULL; 221128760Spjd 222141561Spjd fpu_kernel_exit(); 223128760Spjd 224128760Spjd lcr3(sc->sc_cr3); 225141561Spjd intr_restore(sc->sc_psw); 226128760Spjd} 227141312Spjd