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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to