diff --git a/src/pci.c b/src/pci.c index 2b59ded..0ee38be 100644 --- a/src/pci.c +++ b/src/pci.c @@ -52,8 +52,9 @@ static void pci_command_bar(struct pci_dev *dev) bool enable_mem = PCI_HDR_READ(dev->hdr, PCI_COMMAND, 16) & PCI_COMMAND_MEMORY; for (int i = 0; i < PCI_STD_NUM_BARS; i++) { - struct bus *bus = dev->bar_is_io_space[i] ? dev->io_bus : dev->mmio_bus; - bool enable = dev->bar_is_io_space[i] ? enable_io : enable_mem; + bool is_io = dev->bar_layout[i] & PCI_BASE_ADDRESS_SPACE_IO; + struct bus *bus = is_io ? dev->io_bus : dev->mmio_bus; + bool enable = is_io ? enable_io : enable_mem; if (enable) pci_activate_bar(dev, i, bus); @@ -71,9 +72,9 @@ static void pci_config_bar(struct pci_dev *dev, uint8_t bar) { uint32_t mask = ~(dev->bar_size[bar] - 1); uint32_t old_bar = PCI_HDR_READ(dev->hdr, PCI_BAR_OFFSET(bar), 32); - uint32_t new_bar = (old_bar & mask) | dev->bar_is_io_space[bar]; + uint32_t new_bar = (old_bar & mask) | (dev->bar_layout[bar] & ~mask); PCI_HDR_WRITE(dev->hdr, PCI_BAR_OFFSET(bar), new_bar, 32); - dev->space_dev[bar].base = new_bar; + dev->space_dev[bar].base = new_bar & mask; } static void pci_config_write(struct pci_dev *dev, @@ -145,14 +146,17 @@ static void pci_mmio_io(void *owner, void pci_set_bar(struct pci_dev *dev, uint8_t bar, uint32_t bar_size, - bool is_io_space, + uint32_t layout, dev_io_fn do_io) { - /* TODO: mem type, prefetch */ - /* FIXME: bar_size must be power of 2 */ - PCI_HDR_WRITE(dev->hdr, PCI_BAR_OFFSET(bar), is_io_space, 32); + /* + * FIXME: bar_size must be a power of two. + * TODO: 64-bit BARs need a second adjacent slot for the upper dword; + * only 32-bit memory and I/O BARs are wired up here. + */ + PCI_HDR_WRITE(dev->hdr, PCI_BAR_OFFSET(bar), layout, 32); dev->bar_size[bar] = bar_size; - dev->bar_is_io_space[bar] = is_io_space; + dev->bar_layout[bar] = layout; dev_init(&dev->space_dev[bar], 0, bar_size, dev, do_io); } diff --git a/src/pci.h b/src/pci.h index ff37be7..17d73bc 100644 --- a/src/pci.h +++ b/src/pci.h @@ -30,7 +30,7 @@ struct pci_dev { void *hdr; uint32_t bar_size[6]; bool bar_active[6]; - bool bar_is_io_space[6]; + uint32_t bar_layout[6]; struct dev space_dev[6]; struct dev config_dev; struct bus *io_bus; @@ -46,10 +46,15 @@ struct pci { struct dev pci_mmio_dev; }; +/* + * Configure a PCI BAR. @layout is a bitmask of PCI_BASE_ADDRESS_* flags + * from (space, mem type, prefetch). The non-address + * bits are preserved across guest BAR sizing probes. + */ void pci_set_bar(struct pci_dev *dev, uint8_t bar, uint32_t bar_size, - bool is_io_space, + uint32_t layout, dev_io_fn do_io); void pci_set_status(struct pci_dev *dev, uint16_t status); void pci_dev_register(struct pci_dev *dev); diff --git a/src/virtio-pci.c b/src/virtio-pci.c index 7dede78..ea25027 100644 --- a/src/virtio-pci.c +++ b/src/virtio-pci.c @@ -268,7 +268,8 @@ void virtio_pci_init(struct virtio_pci_dev *dev, PCI_HDR_WRITE(dev->pci_dev.hdr, PCI_HEADER_TYPE, PCI_HEADER_TYPE_NORMAL, 8); PCI_HDR_WRITE(dev->pci_dev.hdr, PCI_INTERRUPT_PIN, 1, 8); pci_set_status(&dev->pci_dev, PCI_STATUS_CAP_LIST | PCI_STATUS_INTERRUPT); - pci_set_bar(&dev->pci_dev, 0, 0x100, PCI_BASE_ADDRESS_SPACE_MEMORY, + pci_set_bar(&dev->pci_dev, 0, 0x100, + PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32, virtio_pci_space_io); virtio_pci_set_cap(dev, cap_list); dev->device_feature |=