/**
 * Read a VGA rom using the 0xc0000 mapping.
 *
 * This function should be extended to handle access through PCI resources,
 * which should be more reliable when available.
 */
static int
pci_device_freebsd_read_rom( struct pci_device * dev, void * buffer )
{
    struct pci_device_private *priv = (struct pci_device_private *) dev;
    void *bios;
    pciaddr_t rom_base;
    uint32_t rom;
    uint16_t reg;
    int pci_rom, memfd;

    if ( ( dev->device_class & 0x00ffff00 ) !=
	 ( ( PCIC_DISPLAY << 16 ) | ( PCIS_DISPLAY_VGA << 8 ) ) )
    {
	return ENOSYS;
    }

    if (priv->rom_base == 0) {
#if defined(__amd64__) || defined(__i386__)
	rom_base = 0xc0000;
	pci_rom = 0;
#else
	return ENOSYS;
#endif
    } else {
	rom_base = priv->rom_base;
	pci_rom = 1;

	pci_device_cfg_read_u16( dev, &reg, PCIR_COMMAND );
	pci_device_cfg_write_u16( dev, reg | PCIM_CMD_MEMEN, PCIR_COMMAND );
	pci_device_cfg_read_u32( dev, &rom, PCIR_BIOS );
	pci_device_cfg_write_u32( dev, rom | PCIM_BIOS_ENABLE, PCIR_BIOS );
    }

    printf("Using rom_base = 0x%lx\n", (long)rom_base);
    memfd = open( "/dev/mem", O_RDONLY | O_CLOEXEC );
    if ( memfd == -1 )
	return errno;

    bios = mmap( NULL, dev->rom_size, PROT_READ, 0, memfd, rom_base );
    if ( bios == MAP_FAILED ) {
	close( memfd );
	return errno;
    }

    memcpy( buffer, bios, dev->rom_size );

    munmap( bios, dev->rom_size );
    close( memfd );

    if (pci_rom) {
	pci_device_cfg_write_u32( dev, PCIR_BIOS, rom );
	pci_device_cfg_write_u16( dev, PCIR_COMMAND, reg );
    }

    return 0;
}
static int
pci_device_freebsd_probe( struct pci_device * dev )
{
    struct pci_device_private *priv = (struct pci_device_private *) dev;
    uint32_t reg, size;
    uint8_t irq;
    int err, i, bar;

    /* Many of the fields were filled in during initial device enumeration.
     * At this point, we need to fill in regions, rom_size, and irq.
     */

    err = pci_device_cfg_read_u8( dev, &irq, 60 );
    if (err)
	return errno;
    dev->irq = irq;

    bar = 0x10;
    for (i = 0; i < pci_device_freebsd_get_num_regions( dev ); i++) {
	pci_device_freebsd_get_region_info( dev, i, bar );
	if (dev->regions[i].is_64) {
	    bar += 0x08;
	    i++;
	} else
	    bar += 0x04;
    }

    /* If it's a VGA device, set up the rom size for read_rom */
    if ((dev->device_class & 0x00ffff00) ==
	((PCIC_DISPLAY << 16) | (PCIS_DISPLAY_VGA << 8)))
    {
	err = pci_device_cfg_read_u32( dev, &reg, PCIR_BIOS );
	if (err)
	    return errno;

	if (reg == 0) {
	    dev->rom_size = 0x10000;
	    return 0;
	}

	err = pci_device_cfg_write_u32( dev, ~PCIM_BIOS_ENABLE, PCIR_BIOS );
	if (err)
	    return errno;
	pci_device_cfg_read_u32( dev, &size, PCIR_BIOS );
	pci_device_cfg_write_u32( dev, reg, PCIR_BIOS );

	if ((reg & PCIM_BIOS_ADDR_MASK) != 0) {
	    priv->rom_base = (reg & PCIM_BIOS_ADDR_MASK);
	    dev->rom_size = -(size & PCIM_BIOS_ADDR_MASK);
	}
    }

    return 0;
}
int
rumpcomp_pci_confwrite(unsigned bus, unsigned dev, unsigned fun,
	int reg, unsigned int v)
{
	assert(bus == 0 && fun == 0);

	if (dev >= NUMDEVS)
		return 1;

	pci_userspace_init();

	pci_device_cfg_write_u32(pci_devices[dev], v, reg);

	return 0;
}
int
pci_device_cfg_write_bits( struct pci_device * dev, uint32_t mask,
			   uint32_t data, pciaddr_t offset )
{
    uint32_t  temp;
    int err;

    err = pci_device_cfg_read_u32( dev, & temp, offset );
    if ( ! err ) {
	temp &= ~mask;
	temp |= data;

	err = pci_device_cfg_write_u32(dev, temp, offset);
    }

    return err;
}
/**
 * Sets the address and size information for the region from config space
 * registers.
 *
 * This would be much better provided by a kernel interface.
 *
 * \return 0 on success, or an errno value.
 */
static int
pci_device_freebsd_get_region_info( struct pci_device * dev, int region,
				    int bar )
{
    uint32_t addr, testval;
    uint16_t cmd;
    int err;

    /* Get the base address */
    err = pci_device_cfg_read_u32( dev, &addr, bar );
    if (err != 0)
	return err;

    /*
     * We are going to be doing evil things to the registers here
     * so disable them via the command register first.
     */
    err = pci_device_cfg_read_u16( dev, &cmd, PCIR_COMMAND );
    if (err != 0)
	return err;

    err = pci_device_cfg_write_u16( dev,
	cmd & ~(PCI_BAR_MEM(addr) ? PCIM_CMD_MEMEN : PCIM_CMD_PORTEN),
	PCIR_COMMAND );
    if (err != 0)
	return err;

    /* Test write all ones to the register, then restore it. */
    err = pci_device_cfg_write_u32( dev, 0xffffffff, bar );
    if (err != 0)
	return err;
    err = pci_device_cfg_read_u32( dev, &testval, bar );
    if (err != 0)
	return err;
    err = pci_device_cfg_write_u32( dev, addr, bar );
    if (err != 0)
	return err;

    /* Restore the command register */
    err = pci_device_cfg_write_u16( dev, cmd, PCIR_COMMAND );
    if (err != 0)
	return err;

    if (addr & 0x01)
	dev->regions[region].is_IO = 1;
    if (addr & 0x04)
	dev->regions[region].is_64 = 1;
    if (addr & 0x08)
	dev->regions[region].is_prefetchable = 1;

    /* Set the size */
    dev->regions[region].size = get_test_val_size( testval );
	printf("size = 0x%lx\n", (long)dev->regions[region].size);

    /* Set the base address value */
    if (dev->regions[region].is_64) {
	uint32_t top;

	err = pci_device_cfg_read_u32( dev, &top, bar + 4 );
	if (err != 0)
	    return err;

	dev->regions[region].base_addr = ((uint64_t)top << 32) |
					  get_map_base(addr);
    } else {
	dev->regions[region].base_addr = get_map_base(addr);
    }

    return 0;
}
Beispiel #6
0
/**
 * Read a device's expansion ROM using /dev/mem.
 *
 * \note
 * This function could probably be used, as-is, on other platforms that have
 * a /dev/mem interface.
 *
 * \bugs
 * Before using the VGA special case code, this function should check that
 * VGA access are routed to the device.  Right?
 */
_pci_hidden int
pci_device_linux_devmem_read_rom(struct pci_device *dev, void *buffer)
{
    struct pci_device_private *priv = (struct pci_device_private *) dev;
    int fd;
    int err = 0;
    uint32_t rom_base_tmp;
    pciaddr_t rom_base;
    pciaddr_t rom_size;
    int PCI_ROM;


    /* Handle some special cases of legacy devices.
     */
    if (priv->base.rom_size == 0) {
	/* VGA ROMs are supposed to be at 0xC0000.
	 */
	if ((priv->base.device_class & 0x00ffff00) == 0x000030000) {
	    rom_base = 0x000C0000;
	    rom_size = 0x00010000;
	    PCI_ROM = 0;
	}
	else {
	    /* "Function not implemented."
	     */
	    return ENOSYS;
	}
    }
    else {
	rom_base = priv->rom_base;
	rom_size = priv->base.rom_size;
	PCI_ROM = 1;
    }



    /* Enable the device's ROM.
     */
    if (PCI_ROM) {
	err = pci_device_cfg_read_u32(& priv->base, & rom_base_tmp, 48);
	if (err) {
	    return err;
	}

	if ((rom_base_tmp & 0x000000001) == 0) {
	    err = pci_device_cfg_write_u32(& priv->base,
					   rom_base_tmp | 1, 48);
	    if (err) {
		return err;
	    }
	}
    }


    /* Read the portion of /dev/mem that corresponds to the device's ROM.
     */
    fd = open("/dev/mem", O_RDONLY, 0);
    if (fd < 0) {
	err = errno;
    }
    else {
	size_t bytes;

	for (bytes = 0; bytes < rom_size; /* empty */) {
	    const ssize_t got = pread(fd, buffer, rom_size - bytes,
				      rom_base + bytes);
	    if (got == -1) {
		err = errno;
		break;
	    }

	    bytes += got;
	}

	close(fd);
    }


    /* Disable the device's ROM.
     */
    if (PCI_ROM && ((rom_base_tmp & 0x000000001) == 0)) {
	const int tmp_err = pci_device_cfg_write_u32(& priv->base,
						     rom_base_tmp, 48);

	/* Prefer to return the first error that occurred.
	 */
	if (err == 0) {
	    err = tmp_err;
	}
    }

    return err;
}