This is the first patch for adding PCI passthrough support to VMD.  
I am splitting up the necessary changes into smaller patches.

This code fixes the pci device union for accessing PCI config space >= 0x40
pcidump -xxx would return garbage data due to union overlap

pci_add_bar now requires specifying the BAR area size to allocate

Extra cookie argument added to pci_add_device

---
 usr.sbin/vmd/pci.c    | 50 +++++++++++++++++++--------
 usr.sbin/vmd/pci.h    | 80 ++++++++++++++++++++++---------------------
 usr.sbin/vmd/virtio.c | 25 +++++++-------
 3 files changed, 89 insertions(+), 66 deletions(-)

diff --git a/usr.sbin/vmd/pci.c b/usr.sbin/vmd/pci.c
index 954235eb6..4ce393237 100644
--- a/usr.sbin/vmd/pci.c
+++ b/usr.sbin/vmd/pci.c
@@ -39,28 +39,47 @@ extern char *__progname;
 const uint8_t pci_pic_irqs[PCI_MAX_PIC_IRQS] = {3, 5, 6, 7, 9, 10, 11, 12,
     14, 15};
 
+/*
+ * pci_mkbar
+ *
+ * Calculates BAR address given a size and alignment.
+ * Returns allocated address and updates next address
+ * Returns zero if address is out of range
+ */
+static uint64_t
+pci_mkbar(uint64_t *base, uint32_t size, uint32_t align, uint64_t maxbase)
+{
+       uint64_t mask = size - 1;
+       uint64_t cbase;
+
+       if (*base >= maxbase)
+               return (0);
+       cbase = *base;
+       *base = (*base + size + mask) & ~mask;
+       return cbase;
+}
+
 /*
  * pci_add_bar
  *
  * Adds a BAR for the PCI device 'id'. On access, 'barfn' will be
  * called, and passed 'cookie' as an identifier.
  *
- * BARs are fixed size, meaning all I/O BARs requested have the
- * same size and all MMIO BARs have the same size.
- *
  * Parameters:
  *  id: PCI device to add the BAR to (local count, eg if id == 4,
  *      this BAR is to be added to the VM's 5th PCI device)
  *  type: type of the BAR to add (PCI_MAPREG_TYPE_xxx)
+ *  size: Size of BAR area
  *  barfn: callback function invoked on BAR access
  *  cookie: cookie passed to barfn on access
  *
  * Returns 0 if the BAR was added successfully, 1 otherwise.
  */
 int
-pci_add_bar(uint8_t id, uint32_t type, void *barfn, void *cookie)
+pci_add_bar(uint8_t id, uint32_t type, uint32_t size, void *barfn, void 
*cookie)
 {
        uint8_t bar_reg_idx, bar_ct;
+       uint64_t base = 0;
 
        /* Check id */
        if (id >= pci.pci_dev_ct)
@@ -74,31 +93,31 @@ pci_add_bar(uint8_t id, uint32_t type, void *barfn, void 
*cookie)
        /* Compute BAR address and add */
        bar_reg_idx = (PCI_MAPREG_START + (bar_ct * 4)) / 4;
        if (type == PCI_MAPREG_TYPE_MEM) {
-               if (pci.pci_next_mmio_bar >= VMM_PCI_MMIO_BAR_END)
+               base = pci_mkbar(&pci.pci_next_mmio_bar, size, 4096, 
VMM_PCI_MMIO_BAR_END);
+               if (base == 0)
                        return (1);
 
                pci.pci_devices[id].pd_cfg_space[bar_reg_idx] =
-                   PCI_MAPREG_MEM_ADDR(pci.pci_next_mmio_bar);
-               pci.pci_next_mmio_bar += VMM_PCI_MMIO_BAR_SIZE;
+                   PCI_MAPREG_MEM_ADDR(base);
                pci.pci_devices[id].pd_barfunc[bar_ct] = barfn;
                pci.pci_devices[id].pd_bar_cookie[bar_ct] = cookie;
                pci.pci_devices[id].pd_bartype[bar_ct] = PCI_BAR_TYPE_MMIO;
-               pci.pci_devices[id].pd_barsize[bar_ct] = VMM_PCI_MMIO_BAR_SIZE;
+               pci.pci_devices[id].pd_barsize[bar_ct] = size;
                pci.pci_devices[id].pd_bar_ct++;
        } else if (type == PCI_MAPREG_TYPE_IO) {
-               if (pci.pci_next_io_bar >= VMM_PCI_IO_BAR_END)
+               base = pci_mkbar(&pci.pci_next_io_bar, size, 4, 
VMM_PCI_IO_BAR_END);
+               if (base == 0)
                        return (1);
 
                pci.pci_devices[id].pd_cfg_space[bar_reg_idx] =
-                   PCI_MAPREG_IO_ADDR(pci.pci_next_io_bar) |
+                   PCI_MAPREG_IO_ADDR(base) |
                    PCI_MAPREG_TYPE_IO;
-               pci.pci_next_io_bar += VMM_PCI_IO_BAR_SIZE;
                pci.pci_devices[id].pd_barfunc[bar_ct] = barfn;
                pci.pci_devices[id].pd_bar_cookie[bar_ct] = cookie;
                DPRINTF("%s: adding pci bar cookie for dev %d bar %d = %p",
                    __progname, id, bar_ct, cookie);
                pci.pci_devices[id].pd_bartype[bar_ct] = PCI_BAR_TYPE_IO;
-               pci.pci_devices[id].pd_barsize[bar_ct] = VMM_PCI_IO_BAR_SIZE;
+               pci.pci_devices[id].pd_barsize[bar_ct] = size;
                pci.pci_devices[id].pd_bar_ct++;
        }
 
@@ -165,7 +184,7 @@ pci_get_dev_irq(uint8_t id)
 int
 pci_add_device(uint8_t *id, uint16_t vid, uint16_t pid, uint8_t class,
     uint8_t subclass, uint16_t subsys_vid, uint16_t subsys_id,
-    uint8_t irq_needed, pci_cs_fn_t csfunc)
+    uint8_t irq_needed, pci_cs_fn_t csfunc, void *cookie)
 {
        /* Exceeded max devices? */
        if (pci.pci_dev_ct >= PCI_CONFIG_MAX_DEV)
@@ -186,6 +205,7 @@ pci_add_device(uint8_t *id, uint16_t vid, uint16_t pid, 
uint8_t class,
        pci.pci_devices[*id].pd_subsys_id = subsys_id;
 
        pci.pci_devices[*id].pd_csfunc = csfunc;
+       pci.pci_devices[*id].pd_cookie = cookie;
 
        if (irq_needed) {
                pci.pci_devices[*id].pd_irq =
@@ -219,7 +239,7 @@ pci_init(void)
 
        if (pci_add_device(&id, PCI_VENDOR_OPENBSD, PCI_PRODUCT_OPENBSD_PCHB,
            PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_HOST,
-           PCI_VENDOR_OPENBSD, 0, 0, NULL)) {
+           PCI_VENDOR_OPENBSD, 0, 0, NULL, NULL)) {
                log_warnx("%s: can't add PCI host bridge", __progname);
                return;
        }
@@ -330,7 +350,7 @@ pci_handle_data_reg(struct vm_run_params *vrp)
 
        csfunc = pci.pci_devices[d].pd_csfunc;
        if (csfunc != NULL) {
-               ret = csfunc(vei->vei.vei_dir, (o / 4), &vei->vei.vei_data);
+               ret = csfunc(vei->vei.vei_dir, (o / 4), sz, &vei->vei.vei_data, 
pci.pci_devices[d].pd_cookie);
                if (ret)
                        log_warnx("cfg space access function failed for "
                            "pci device %d", d);
diff --git a/usr.sbin/vmd/pci.h b/usr.sbin/vmd/pci.h
index 01902d77d..a9d7336ed 100644
--- a/usr.sbin/vmd/pci.h
+++ b/usr.sbin/vmd/pci.h
@@ -27,48 +27,50 @@
 
 #define PCI_MAX_PIC_IRQS       10
 
-typedef int (*pci_cs_fn_t)(int dir, uint8_t reg, uint32_t *data);
+typedef int (*pci_cs_fn_t)(int dir, uint8_t reg, uint8_t sz, uint32_t *data, 
void *cookie);
 typedef int (*pci_iobar_fn_t)(int dir, uint16_t reg, uint32_t *data, uint8_t *,
     void *, uint8_t);
 typedef int (*pci_mmiobar_fn_t)(int dir, uint32_t ofs, uint32_t *data);
 
-union pci_dev {
-       uint32_t pd_cfg_space[PCI_CONFIG_SPACE_SIZE / 4];
 
-       struct {
-               uint16_t pd_vid;
-               uint16_t pd_did;
-               uint16_t pd_cmd;
-               uint16_t pd_status;
-               uint8_t pd_rev;
-               uint8_t pd_prog_if;
-               uint8_t pd_subclass;
-               uint8_t pd_class;
-               uint8_t pd_cache_size;
-               uint8_t pd_lat_timer;
-               uint8_t pd_header_type;
-               uint8_t pd_bist;
-               uint32_t pd_bar[PCI_MAX_BARS];
-               uint32_t pd_cardbus_cis;
-               uint16_t pd_subsys_vid;
-               uint16_t pd_subsys_id;
-               uint32_t pd_exp_rom_addr;
-               uint8_t pd_cap;
-               uint32_t pd_reserved0 : 24;
-               uint32_t pd_reserved1;
-               uint8_t pd_irq;
-               uint8_t pd_int;
-               uint8_t pd_min_grant;
-               uint8_t pd_max_grant;
+struct pci_dev {
+       union {
+               uint32_t pd_cfg_space[PCI_CONFIG_SPACE_SIZE / 4];
+               struct {
+                       uint16_t pd_vid;
+                       uint16_t pd_did;
+                       uint16_t pd_cmd;
+                       uint16_t pd_status;
+                       uint8_t pd_rev;
+                       uint8_t pd_prog_if;
+                       uint8_t pd_subclass;
+                       uint8_t pd_class;
+                       uint8_t pd_cache_size;
+                       uint8_t pd_lat_timer;
+                       uint8_t pd_header_type;
+                       uint8_t pd_bist;
+                       uint32_t pd_bar[PCI_MAX_BARS];
+                       uint32_t pd_cardbus_cis;
+                       uint16_t pd_subsys_vid;
+                       uint16_t pd_subsys_id;
+                       uint32_t pd_exp_rom_addr;
+                       uint8_t pd_cap;
+                       uint32_t pd_reserved0 : 24;
+                       uint32_t pd_reserved1;
+                       uint8_t pd_irq;
+                       uint8_t pd_int;
+                       uint8_t pd_min_grant;
+                       uint8_t pd_max_grant;
+               } __packed;
+       };
+       uint8_t pd_bar_ct;
+       pci_cs_fn_t pd_csfunc;
 
-               uint8_t pd_bar_ct;
-               pci_cs_fn_t pd_csfunc;
-
-               uint8_t pd_bartype[PCI_MAX_BARS];
-               uint32_t pd_barsize[PCI_MAX_BARS];
-               void *pd_barfunc[PCI_MAX_BARS];
-               void *pd_bar_cookie[PCI_MAX_BARS];
-       } __packed;
+       uint8_t pd_bartype[PCI_MAX_BARS];
+       uint32_t pd_barsize[PCI_MAX_BARS];
+       void *pd_barfunc[PCI_MAX_BARS];
+       void *pd_bar_cookie[PCI_MAX_BARS];
+       void *pd_cookie;
 };
 
 struct pci {
@@ -79,7 +81,7 @@ struct pci {
        uint32_t pci_addr_reg;
        uint32_t pci_data_reg;
 
-       union pci_dev pci_devices[PCI_CONFIG_MAX_DEV];
+       struct pci_dev pci_devices[PCI_CONFIG_MAX_DEV];
 };
 
 void pci_handle_address_reg(struct vm_run_params *);
@@ -87,8 +89,8 @@ void pci_handle_data_reg(struct vm_run_params *);
 uint8_t pci_handle_io(struct vm_run_params *);
 void pci_init(void);
 int pci_add_device(uint8_t *, uint16_t, uint16_t, uint8_t, uint8_t, uint16_t,
-    uint16_t, uint8_t, pci_cs_fn_t);
-int pci_add_bar(uint8_t, uint32_t, void *, void *);
+    uint16_t, uint8_t, pci_cs_fn_t, void *);
+int pci_add_bar(uint8_t, uint32_t, uint32_t, void *, void *);
 int pci_set_bar_fn(uint8_t, uint8_t, void *, void *);
 uint8_t pci_get_dev_irq(uint8_t);
 int pci_dump(int);
diff --git a/usr.sbin/vmd/virtio.c b/usr.sbin/vmd/virtio.c
index 8800594fc..430f41995 100644
--- a/usr.sbin/vmd/virtio.c
+++ b/usr.sbin/vmd/virtio.c
@@ -1797,13 +1797,13 @@ virtio_init(struct vmd_vm *vm, int child_cdrom,
            PCI_PRODUCT_QUMRANET_VIO_RNG, PCI_CLASS_SYSTEM,
            PCI_SUBCLASS_SYSTEM_MISC,
            PCI_VENDOR_OPENBSD,
-           PCI_PRODUCT_VIRTIO_ENTROPY, 1, NULL)) {
+           PCI_PRODUCT_VIRTIO_ENTROPY, 1, NULL, NULL)) {
                log_warnx("%s: can't add PCI virtio rng device",
                    __progname);
                return;
        }
 
-       if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, virtio_rnd_io, NULL)) {
+       if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, VMM_PCI_IO_BAR_SIZE, 
virtio_rnd_io, NULL)) {
                log_warnx("%s: can't add bar for virtio rng device",
                    __progname);
                return;
@@ -1835,14 +1835,14 @@ virtio_init(struct vmd_vm *vm, int child_cdrom,
                            PCI_PRODUCT_QUMRANET_VIO_NET, PCI_CLASS_SYSTEM,
                            PCI_SUBCLASS_SYSTEM_MISC,
                            PCI_VENDOR_OPENBSD,
-                           PCI_PRODUCT_VIRTIO_NETWORK, 1, NULL)) {
+                           PCI_PRODUCT_VIRTIO_NETWORK, 1, NULL, NULL)) {
                                log_warnx("%s: can't add PCI virtio net device",
                                    __progname);
                                return;
                        }
 
-                       if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, virtio_net_io,
-                           &vionet[i])) {
+                       if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, 
VMM_PCI_IO_BAR_SIZE,
+                           virtio_net_io, &vionet[i])) {
                                log_warnx("%s: can't add bar for virtio net "
                                    "device", __progname);
                                return;
@@ -1923,13 +1923,13 @@ virtio_init(struct vmd_vm *vm, int child_cdrom,
                            PCI_CLASS_MASS_STORAGE,
                            PCI_SUBCLASS_MASS_STORAGE_SCSI,
                            PCI_VENDOR_OPENBSD,
-                           PCI_PRODUCT_VIRTIO_BLOCK, 1, NULL)) {
+                           PCI_PRODUCT_VIRTIO_BLOCK, 1, NULL, NULL)) {
                                log_warnx("%s: can't add PCI virtio block "
                                    "device", __progname);
                                return;
                        }
-                       if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, virtio_blk_io,
-                           &vioblk[i])) {
+                       if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, 
VMM_PCI_IO_BAR_SIZE,
+                           virtio_blk_io, &vioblk[i])) {
                                log_warnx("%s: can't add bar for virtio block "
                                    "device", __progname);
                                return;
@@ -1971,13 +1971,14 @@ virtio_init(struct vmd_vm *vm, int child_cdrom,
                    PCI_CLASS_MASS_STORAGE,
                    PCI_SUBCLASS_MASS_STORAGE_SCSI,
                    PCI_VENDOR_OPENBSD,
-                   PCI_PRODUCT_VIRTIO_SCSI, 1, NULL)) {
+                   PCI_PRODUCT_VIRTIO_SCSI, 1, NULL, NULL)) {
                        log_warnx("%s: can't add PCI vioscsi device",
                            __progname);
                        return;
                }
 
-               if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, vioscsi_io, vioscsi)) {
+               if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, VMM_PCI_IO_BAR_SIZE,
+                   vioscsi_io, vioscsi)) {
                        log_warnx("%s: can't add bar for vioscsi device",
                            __progname);
                        return;
@@ -2013,13 +2014,13 @@ virtio_init(struct vmd_vm *vm, int child_cdrom,
            PCI_CLASS_COMMUNICATIONS,
            PCI_SUBCLASS_COMMUNICATIONS_MISC,
            PCI_VENDOR_OPENBSD,
-           PCI_PRODUCT_VIRTIO_VMMCI, 1, NULL)) {
+           PCI_PRODUCT_VIRTIO_VMMCI, 1, NULL, NULL)) {
                log_warnx("%s: can't add PCI vmm control device",
                    __progname);
                return;
        }
 
-       if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, vmmci_io, NULL)) {
+       if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, VMM_PCI_IO_BAR_SIZE, vmmci_io, 
NULL)) {
                log_warnx("%s: can't add bar for vmm control device",
                    __progname);
                return;
-- 
2.26.2

Reply via email to