Date: Mon, 26 Aug 2013 10:55:17 -0400 From: John Baldwin <jhb@freebsd.org> To: "Jean-Sebastien Pedron" <dumbbell@freebsd.org> Cc: svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org Subject: Re: svn commit: r254882 - head/sys/dev/pci Message-ID: <201308261055.17964.jhb@freebsd.org> In-Reply-To: <201308251809.r7PI9CsE052978@svn.freebsd.org> References: <201308251809.r7PI9CsE052978@svn.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Sunday, August 25, 2013 2:09:12 pm Jean-Sebastien Pedron wrote: > Author: dumbbell > Date: Sun Aug 25 18:09:11 2013 > New Revision: 254882 > URL: http://svnweb.freebsd.org/changeset/base/254882 > > Log: > vga_pci: Add API to map the Video BIOS > > Here are two new functions to map and unmap the Video BIOS: > void * vga_pci_map_bios(device_t dev, size_t *size); > void vga_pci_unmap_bios(device_t dev, void *bios); > > The BIOS is either taken from the shadow copy made by the System BIOS at > boot time if the given device was used for the default display (i386, > amd64 and ia64 only), or from the PCI expansion ROM. > > Additionally, one can determine if a given device was the default > display at boot time using the following new function: > void vga_pci_unmap_bios(device_t dev, void *bios); > > Modified: > head/sys/dev/pci/pcivar.h > head/sys/dev/pci/vga_pci.c > > Modified: head/sys/dev/pci/pcivar.h > ============================================================================== > --- head/sys/dev/pci/pcivar.h Sun Aug 25 17:26:05 2013 (r254881) > +++ head/sys/dev/pci/pcivar.h Sun Aug 25 18:09:11 2013 (r254882) > @@ -517,4 +517,11 @@ extern uint32_t pci_generation; > struct pci_map *pci_find_bar(device_t dev, int reg); > int pci_bar_enabled(device_t dev, struct pci_map *pm); > > +#define VGA_PCI_BIOS_SHADOW_ADDR 0xC0000 > +#define VGA_PCI_BIOS_SHADOW_SIZE 131072 > + > +int vga_pci_is_boot_display(device_t dev); > +void * vga_pci_map_bios(device_t dev, size_t *size); > +void vga_pci_unmap_bios(device_t dev, void *bios); > + > #endif /* _PCIVAR_H_ */ > > Modified: head/sys/dev/pci/vga_pci.c > ============================================================================== > --- head/sys/dev/pci/vga_pci.c Sun Aug 25 17:26:05 2013 (r254881) > +++ head/sys/dev/pci/vga_pci.c Sun Aug 25 18:09:11 2013 (r254882) > @@ -46,6 +46,11 @@ __FBSDID("$FreeBSD$"); > #include <sys/sysctl.h> > #include <sys/systm.h> > > +#if defined(__amd64__) || defined(__i386__) || defined(__ia64__) > +#include <vm/vm.h> > +#include <vm/pmap.h> > +#endif > + > #include <dev/pci/pcireg.h> > #include <dev/pci/pcivar.h> > > @@ -67,6 +72,99 @@ TUNABLE_INT("hw.pci.default_vgapci_unit" > SYSCTL_INT(_hw_pci, OID_AUTO, default_vgapci_unit, CTLFLAG_RDTUN, > &vga_pci_default_unit, -1, "Default VGA-compatible display"); > > +int > +vga_pci_is_boot_display(device_t dev) > +{ > + > + /* > + * Return true if the given device is the default display used > + * at boot time. > + */ > + > + return ( > + (pci_get_class(dev) == PCIC_DISPLAY || > + (pci_get_class(dev) == PCIC_OLD && > + pci_get_subclass(dev) == PCIS_OLD_VGA)) && > + device_get_unit(dev) == vga_pci_default_unit); > +} > + > +void * > +vga_pci_map_bios(device_t dev, size_t *size) > +{ > + int rid; > + struct resource *res; > + > +#if defined(__amd64__) || defined(__i386__) || defined(__ia64__) > + if (vga_pci_is_boot_display(dev)) { > + /* > + * On x86, the System BIOS copy the default display > + * device's Video BIOS at a fixed location in system > + * memory (0xC0000, 128 kBytes long) at boot time. > + * > + * We use this copy for the default boot device, because > + * the original ROM may not be valid after boot. > + */ > + > + printf("%s: Mapping BIOS shadow\n", __func__); > + *size = VGA_PCI_BIOS_SHADOW_SIZE; > + return (pmap_mapbios(VGA_PCI_BIOS_SHADOW_ADDR, *size)); > + } > +#endif > + > + printf("%s: Mapping PCI expansion ROM\n", __func__); > + rid = PCIR_BIOS; > + res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); > + if (res == NULL) { > + return (NULL); > + } > + > + *size = rman_get_size(res); > + return (rman_get_virtual(res)); > +} > + > +void > +vga_pci_unmap_bios(device_t dev, void *bios) > +{ > + int rid; > + struct resource *res; > + > + if (bios == NULL) { > + return; > + } > + > +#if defined(__amd64__) || defined(__i386__) || defined(__ia64__) > + if (vga_pci_is_boot_display(dev)) { > + /* We mapped the BIOS shadow copy located at 0xC0000. */ > + printf("%s: Unmapping BIOS shadow\n", __func__); > + pmap_unmapdev((vm_offset_t)bios, VGA_PCI_BIOS_SHADOW_SIZE); > + > + return; > + } > +#endif > + > + /* > + * FIXME: We returned only the virtual address of the resource > + * to the caller. Now, to get the resource struct back, we > + * allocate it again: the struct exists once in memory in > + * device softc. Therefore, we release twice now to release the > + * reference we just obtained to get the structure back and the > + * caller's reference. > + */ This won't actually work (the PCI bus will panic when you do the duplicate alloc). Why not put this in the softc of the vga_pci device? In fact, it is already there. You just need to bump the vr_refs on the vga_bios resource similar to what vga_pci_alloc_resource() does. Also, returning a void * for this API seems rather hacky. Have you considered returning a struct resource * instead (and requiring the caller to use bus_space_* on it)? That would be more consistent with new-bus. I can help with getting the right bus_alloc_resource() incantation to alloc a struct resource * for the shadow copy if so. -- John Baldwin
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201308261055.17964.jhb>