diff options
author | Mike Larkin <mlarkin@cvs.openbsd.org> | 2015-07-17 21:36:57 +0000 |
---|---|---|
committer | Mike Larkin <mlarkin@cvs.openbsd.org> | 2015-07-17 21:36:57 +0000 |
commit | 89d278d7fc97dc41c3878adce3f703cda41a32b1 (patch) | |
tree | b68d76414acb9f8d907e7f704d330afb5013772c | |
parent | 55aa389fb6be51c59d1cb9d28361af2c4e8e38c5 (diff) |
Include executable mapping for BIOS32 pages. Fixes a problem where mappings
done in this region using PAE w/NX caused #PFs (as they lacked the exec
permission previously).
Also unmap the region when we're finished. No sense in leaving extra
executable regions lying around.
Fixes non-ACPI uniprocessor i386 machines that have NX/PAE (these would
previously panic in pcibiosattach).
ok deraadt@
-rw-r--r-- | sys/arch/i386/i386/bios.c | 35 | ||||
-rw-r--r-- | sys/arch/i386/include/biosvar.h | 3 | ||||
-rw-r--r-- | sys/arch/i386/pci/pcibios.c | 4 |
3 files changed, 34 insertions, 8 deletions
diff --git a/sys/arch/i386/i386/bios.c b/sys/arch/i386/i386/bios.c index f4dd2b8c0d4..e40cab7f276 100644 --- a/sys/arch/i386/i386/bios.c +++ b/sys/arch/i386/i386/bios.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bios.c,v 1.109 2015/01/21 18:39:54 tedu Exp $ */ +/* $OpenBSD: bios.c,v 1.110 2015/07/17 21:36:56 mlarkin Exp $ */ /* * Copyright (c) 1997-2001 Michael Shalayeff @@ -84,6 +84,7 @@ struct bios_softc { struct device sc_dev; + vaddr_t bios32_service_va; }; int biosprobe(struct device *, void *, void *); @@ -110,6 +111,7 @@ bios_pciinfo_t *bios_pciinfo; #endif bios_diskinfo_t *bios_diskinfo; bios_memmap_t *bios_memmap; +struct bios_softc *bios_softc; u_int32_t bios_cksumlen; struct bios32_entry bios32_entry; struct smbios_entry smbios_entry; @@ -173,6 +175,7 @@ biosattach(struct device *parent, struct device *self, void *aux) int usingacpi = 0; #endif + bios_softc = sc; /* remember flags */ flags = sc->sc_dev.dv_cfdata->cf_flags; @@ -648,13 +651,15 @@ bios32_service(u_int32_t service, bios32_entry_t e, bios32_entry_info_t ei) if (ent <= BIOS32_START || ent >= BIOS32_END) return 0; - endpa = round_page(BIOS32_END); sva = va = uvm_km_valloc(kernel_map, endpa); if (va == 0) return (0); + /* Store bios32 service kva for cleanup later */ + bios_softc->bios32_service_va = sva; + slot = gdt_get_slot(); setgdt(slot, (caddr_t)va, BIOS32_END, SDT_MEMERA, SEL_KPL, 1, 0); @@ -662,14 +667,14 @@ bios32_service(u_int32_t service, bios32_entry_t e, bios32_entry_info_t ei) va += trunc_page(BIOS32_START); pa < endpa; pa += NBPG, va += NBPG) { pmap_enter(pmap_kernel(), va, pa, - PROT_READ | PROT_WRITE, - PROT_READ | PROT_WRITE | PMAP_WIRED); + PROT_READ | PROT_WRITE | PROT_EXEC, + PROT_READ | PROT_WRITE | PROT_EXEC | PMAP_WIRED); /* for all you, broken hearted */ if (pa >= trunc_page(base)) { pmap_enter(pmap_kernel(), sva, pa, - PROT_READ | PROT_WRITE, - PROT_READ | PROT_WRITE | PMAP_WIRED); + PROT_READ | PROT_WRITE | PROT_EXEC, + PROT_READ | PROT_WRITE | PROT_EXEC | PMAP_WIRED); sva += NBPG; } } @@ -684,6 +689,24 @@ bios32_service(u_int32_t service, bios32_entry_t e, bios32_entry_info_t ei) return 1; } +void +bios32_cleanup(void) +{ + u_long pa, size; + vaddr_t va; + + size = round_page(BIOS32_END); + + for (va = bios_softc->bios32_service_va; + va < bios_softc->bios32_service_va + size; + va += NBPG) { + if (pmap_extract(pmap_kernel(), va, &pa)) + pmap_remove(pmap_kernel(), va, va + PAGE_SIZE); + } + + uvm_km_free(kernel_map, bios_softc->bios32_service_va, size); +} + int biosopen(dev_t dev, int flag, int mode, struct proc *p) { diff --git a/sys/arch/i386/include/biosvar.h b/sys/arch/i386/include/biosvar.h index afe03ffe631..9852bd8b45d 100644 --- a/sys/arch/i386/include/biosvar.h +++ b/sys/arch/i386/include/biosvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: biosvar.h,v 1.62 2015/04/12 18:37:54 mlarkin Exp $ */ +/* $OpenBSD: biosvar.h,v 1.63 2015/07/17 21:36:56 mlarkin Exp $ */ /* * Copyright (c) 1997-1999 Michael Shalayeff @@ -268,6 +268,7 @@ void bios_getopt(void); /* bios32.c */ int bios32_service(u_int32_t, bios32_entry_t, bios32_entry_info_t); +void bios32_cleanup(void); extern u_int bootapiver; extern bios_memmap_t *bios_memmap; diff --git a/sys/arch/i386/pci/pcibios.c b/sys/arch/i386/pci/pcibios.c index ddf28cd2b4d..39c824d4824 100644 --- a/sys/arch/i386/pci/pcibios.c +++ b/sys/arch/i386/pci/pcibios.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pcibios.c,v 1.45 2014/07/12 18:44:42 tedu Exp $ */ +/* $OpenBSD: pcibios.c,v 1.46 2015/07/17 21:36:56 mlarkin Exp $ */ /* $NetBSD: pcibios.c,v 1.5 2000/08/01 05:23:59 uch Exp $ */ /* @@ -228,6 +228,8 @@ pcibiosattach(struct device *parent, struct device *self, void *aux) if (!(pcibios_flags & PCIBIOS_ADDR_FIXUP)) pci_addr_fixup(sc, NULL, sc->max_bus); + + bios32_cleanup(); } struct pcibios_intr_routing * |