diff --git a/sys/bus/pci/vga_pci.c b/sys/bus/pci/vga_pci.c index 1111111..2222222 100644 --- a/sys/bus/pci/vga_pci.c +++ b/sys/bus/pci/vga_pci.c @@ -58,6 +58,7 @@ device_t vga_msi_child; /* Child driver using MSI. */ struct vga_resource vga_bars[PCIR_MAX_BAR_0 + 1]; struct vga_resource vga_bios; + int vga_bios_shadow; /* BIOS mapped via C0000 shadow copy. */ }; SYSCTL_DECL(_hw_pci); @@ -183,8 +184,10 @@ */ *size = VGA_PCI_BIOS_SHADOW_SIZE; + ((struct vga_pci_softc *)device_get_softc(dev))->vga_bios_shadow = 1; return (pmap_mapbios(VGA_PCI_BIOS_SHADOW_ADDR, *size)); } + ((struct vga_pci_softc *)device_get_softc(dev))->vga_bios_shadow = 0; #endif pcib = device_get_parent(device_get_parent(dev)); @@ -285,11 +288,25 @@ } #if defined(__amd64__) || defined(__i386__) - if (vga_pci_is_boot_display(dev)) { - /* We mapped the BIOS shadow copy located at 0xC0000. */ - pmap_unmapdev((vm_offset_t)bios, VGA_PCI_BIOS_SHADOW_SIZE); + { + struct vga_pci_softc *sc = device_get_softc(dev); - return; + /* + * Unmap the mapping kind that map_bios() actually created, + * NOT what a fresh is_boot_display() evaluation says now: + * map_bios() itself flips that predicate (it sets + * PCIB_BCR_VGA_ENABLE on the parent bridge), so re-evaluating + * it here can unmap a ROM-BAR mapping with the 128KB shadow + * size and corrupt the kernel page tables / kernel_map. + */ + if (sc->vga_bios_shadow) { + /* We mapped the BIOS shadow copy located at 0xC0000. */ + sc->vga_bios_shadow = 0; + pmap_unmapdev((vm_offset_t)bios, + VGA_PCI_BIOS_SHADOW_SIZE); + + return; + } } #endif switch(pci_read_config(dev, PCIR_HDRTYPE, 1)) {