svn commit: r254882 - head/sys/dev/pci
John Baldwin
jhb at freebsd.org
Mon Aug 26 18:27:51 UTC 2013
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
More information about the svn-src-head
mailing list