typedef struct e1000e_device {
     QPCIDevice *pci_dev;
-    void *mac_regs;
+    QPCIBar mac_regs;
 
     uint64_t tx_ring;
     uint64_t rx_ring;
 
 static void e1000e_macreg_write(e1000e_device *d, uint32_t reg, uint32_t val)
 {
-    qpci_io_writel(d->pci_dev, d->mac_regs + reg, val);
+    qpci_io_writel(d->pci_dev, d->mac_regs, reg, val);
 }
 
 static uint32_t e1000e_macreg_read(e1000e_device *d, uint32_t reg)
 {
-    return qpci_io_readl(d->pci_dev, d->mac_regs + reg);
+    return qpci_io_readl(d->pci_dev, d->mac_regs, reg);
 }
 
 static void e1000e_device_init(QPCIBus *bus, e1000e_device *d)
 
     /* Map BAR0 (mac registers) */
     d->mac_regs = qpci_iomap(d->pci_dev, 0, NULL);
-    g_assert_nonnull(d->mac_regs);
 
     /* Reset the device */
     val = e1000e_macreg_read(d, E1000E_CTRL);
 
     qtest_end();
 }
 
-static QPCIDevice *get_pci_device(void **bmdma_base, void **ide_base)
+static QPCIDevice *get_pci_device(QPCIBar *bmdma_bar, QPCIBar *ide_bar)
 {
     QPCIDevice *dev;
     uint16_t vendor_id, device_id;
     g_assert(device_id == PCI_DEVICE_ID_INTEL_82371SB_1);
 
     /* Map bmdma BAR */
-    *bmdma_base = qpci_iomap(dev, 4, NULL);
+    *bmdma_bar = qpci_iomap(dev, 4, NULL);
 
-    *ide_base = qpci_legacy_iomap(dev, IDE_BASE);
+    *ide_bar = qpci_legacy_iomap(dev, IDE_BASE);
 
     qpci_device_enable(dev);
 
 
 static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
                             PrdtEntry *prdt, int prdt_entries,
-                            void(*post_exec)(QPCIDevice *dev, void *ide_base,
+                            void(*post_exec)(QPCIDevice *dev, QPCIBar ide_bar,
                                              uint64_t sector, int nb_sectors))
 {
     QPCIDevice *dev;
-    void *bmdma_base;
-    void *ide_base;
+    QPCIBar bmdma_bar, ide_bar;
     uintptr_t guest_prdt;
     size_t len;
     bool from_dev;
     uint8_t status;
     int flags;
 
-    dev = get_pci_device(&bmdma_base, &ide_base);
+    dev = get_pci_device(&bmdma_bar, &ide_bar);
 
     flags = cmd & ~0xff;
     cmd &= 0xff;
     }
 
     /* Select device 0 */
-    qpci_io_writeb(dev, ide_base + reg_device, 0 | LBA);
+    qpci_io_writeb(dev, ide_bar, reg_device, 0 | LBA);
 
     /* Stop any running transfer, clear any pending interrupt */
-    qpci_io_writeb(dev, bmdma_base + bmreg_cmd, 0);
-    qpci_io_writeb(dev, bmdma_base + bmreg_status, BM_STS_INTR);
+    qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
+    qpci_io_writeb(dev, bmdma_bar, bmreg_status, BM_STS_INTR);
 
     /* Setup PRDT */
     len = sizeof(*prdt) * prdt_entries;
     guest_prdt = guest_alloc(guest_malloc, len);
     memwrite(guest_prdt, prdt, len);
-    qpci_io_writel(dev, bmdma_base + bmreg_prdt, guest_prdt);
+    qpci_io_writel(dev, bmdma_bar, bmreg_prdt, guest_prdt);
 
     /* ATA DMA command */
     if (cmd == CMD_PACKET) {
         /* Enables ATAPI DMA; otherwise PIO is attempted */
-        qpci_io_writeb(dev, ide_base + reg_feature, 0x01);
+        qpci_io_writeb(dev, ide_bar, reg_feature, 0x01);
     } else {
-        qpci_io_writeb(dev, ide_base + reg_nsectors, nb_sectors);
-        qpci_io_writeb(dev, ide_base + reg_lba_low,    sector & 0xff);
-        qpci_io_writeb(dev, ide_base + reg_lba_middle, (sector >> 8) & 0xff);
-        qpci_io_writeb(dev, ide_base + reg_lba_high,   (sector >> 16) & 0xff);
+        qpci_io_writeb(dev, ide_bar, reg_nsectors, nb_sectors);
+        qpci_io_writeb(dev, ide_bar, reg_lba_low,    sector & 0xff);
+        qpci_io_writeb(dev, ide_bar, reg_lba_middle, (sector >> 8) & 0xff);
+        qpci_io_writeb(dev, ide_bar, reg_lba_high,   (sector >> 16) & 0xff);
     }
 
-    qpci_io_writeb(dev, ide_base + reg_command, cmd);
+    qpci_io_writeb(dev, ide_bar, reg_command, cmd);
 
     if (post_exec) {
-        post_exec(dev, ide_base, sector, nb_sectors);
+        post_exec(dev, ide_bar, sector, nb_sectors);
     }
 
     /* Start DMA transfer */
-    qpci_io_writeb(dev, bmdma_base + bmreg_cmd,
+    qpci_io_writeb(dev, bmdma_bar, bmreg_cmd,
                    BM_CMD_START | (from_dev ? BM_CMD_WRITE : 0));
 
     if (flags & CMDF_ABORT) {
-        qpci_io_writeb(dev, bmdma_base + bmreg_cmd, 0);
+        qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
     }
 
     /* Wait for the DMA transfer to complete */
     do {
-        status = qpci_io_readb(dev, bmdma_base + bmreg_status);
+        status = qpci_io_readb(dev, bmdma_bar, bmreg_status);
     } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
 
     g_assert_cmpint(get_irq(IDE_PRIMARY_IRQ), ==, !!(status & BM_STS_INTR));
 
     /* Check IDE status code */
-    assert_bit_set(qpci_io_readb(dev, ide_base + reg_status), DRDY);
-    assert_bit_clear(qpci_io_readb(dev, ide_base + reg_status), BSY | DRQ);
+    assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), DRDY);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), BSY | DRQ);
 
     /* Reading the status register clears the IRQ */
     g_assert(!get_irq(IDE_PRIMARY_IRQ));
 
     /* Stop DMA transfer if still active */
     if (status & BM_STS_ACTIVE) {
-        qpci_io_writeb(dev, bmdma_base + bmreg_cmd, 0);
+        qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
     }
 
     free_pci_device(dev);
 static void test_bmdma_simple_rw(void)
 {
     QPCIDevice *dev;
-    void *bmdma_base, *ide_base;
+    QPCIBar bmdma_bar, ide_bar;
     uint8_t status;
     uint8_t *buf;
     uint8_t *cmpbuf;
         },
     };
 
-    dev = get_pci_device(&bmdma_base, &ide_base);
+    dev = get_pci_device(&bmdma_bar, &ide_bar);
 
     buf = g_malloc(len);
     cmpbuf = g_malloc(len);
     status = send_dma_request(CMD_WRITE_DMA, 0, 1, prdt,
                               ARRAY_SIZE(prdt), NULL);
     g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_base + reg_status), DF | ERR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
 
     /* Write 0xaa pattern to sector 1 */
     memset(buf, 0xaa, len);
     status = send_dma_request(CMD_WRITE_DMA, 1, 1, prdt,
                               ARRAY_SIZE(prdt), NULL);
     g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_base + reg_status), DF | ERR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
 
     /* Read and verify 0x55 pattern in sector 0 */
     memset(cmpbuf, 0x55, len);
 
     status = send_dma_request(CMD_READ_DMA, 0, 1, prdt, ARRAY_SIZE(prdt), NULL);
     g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_base + reg_status), DF | ERR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
 
     memread(guest_buf, buf, len);
     g_assert(memcmp(buf, cmpbuf, len) == 0);
 
     status = send_dma_request(CMD_READ_DMA, 1, 1, prdt, ARRAY_SIZE(prdt), NULL);
     g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_base + reg_status), DF | ERR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
 
     memread(guest_buf, buf, len);
     g_assert(memcmp(buf, cmpbuf, len) == 0);
 static void test_bmdma_short_prdt(void)
 {
     QPCIDevice *dev;
-    void *bmdma_base, *ide_base;
+    QPCIBar bmdma_bar, ide_bar;
     uint8_t status;
 
     PrdtEntry prdt[] = {
         },
     };
 
-    dev = get_pci_device(&bmdma_base, &ide_base);
+    dev = get_pci_device(&bmdma_bar, &ide_bar);
 
     /* Normal request */
     status = send_dma_request(CMD_READ_DMA, 0, 1,
                               prdt, ARRAY_SIZE(prdt), NULL);
     g_assert_cmphex(status, ==, 0);
-    assert_bit_clear(qpci_io_readb(dev, ide_base + reg_status), DF | ERR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
 
     /* Abort the request before it completes */
     status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 1,
                               prdt, ARRAY_SIZE(prdt), NULL);
     g_assert_cmphex(status, ==, 0);
-    assert_bit_clear(qpci_io_readb(dev, ide_base + reg_status), DF | ERR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
 }
 
 static void test_bmdma_one_sector_short_prdt(void)
 {
     QPCIDevice *dev;
-    void *bmdma_base, *ide_base;
+    QPCIBar bmdma_bar, ide_bar;
     uint8_t status;
 
     /* Read 2 sectors but only give 1 sector in PRDT */
         },
     };
 
-    dev = get_pci_device(&bmdma_base, &ide_base);
+    dev = get_pci_device(&bmdma_bar, &ide_bar);
 
     /* Normal request */
     status = send_dma_request(CMD_READ_DMA, 0, 2,
                               prdt, ARRAY_SIZE(prdt), NULL);
     g_assert_cmphex(status, ==, 0);
-    assert_bit_clear(qpci_io_readb(dev, ide_base + reg_status), DF | ERR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
 
     /* Abort the request before it completes */
     status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 2,
                               prdt, ARRAY_SIZE(prdt), NULL);
     g_assert_cmphex(status, ==, 0);
-    assert_bit_clear(qpci_io_readb(dev, ide_base + reg_status), DF | ERR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
 }
 
 static void test_bmdma_long_prdt(void)
 {
     QPCIDevice *dev;
-    void *bmdma_base, *ide_base;
+    QPCIBar bmdma_bar, ide_bar;
     uint8_t status;
 
     PrdtEntry prdt[] = {
         },
     };
 
-    dev = get_pci_device(&bmdma_base, &ide_base);
+    dev = get_pci_device(&bmdma_bar, &ide_bar);
 
     /* Normal request */
     status = send_dma_request(CMD_READ_DMA, 0, 1,
                               prdt, ARRAY_SIZE(prdt), NULL);
     g_assert_cmphex(status, ==, BM_STS_ACTIVE | BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_base + reg_status), DF | ERR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
 
     /* Abort the request before it completes */
     status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 1,
                               prdt, ARRAY_SIZE(prdt), NULL);
     g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_base + reg_status), DF | ERR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
 }
 
 static void test_bmdma_no_busmaster(void)
 {
     QPCIDevice *dev;
-    void *bmdma_base, *ide_base;
+    QPCIBar bmdma_bar, ide_bar;
     uint8_t status;
 
-    dev = get_pci_device(&bmdma_base, &ide_base);
+    dev = get_pci_device(&bmdma_bar, &ide_bar);
 
     /* No PRDT_EOT, each entry addr 0/size 64k, and in theory qemu shouldn't be
      * able to access it anyway because the Bus Master bit in the PCI command
     /* Not entirely clear what the expected result is, but this is what we get
      * in practice. At least we want to be aware of any changes. */
     g_assert_cmphex(status, ==, BM_STS_ACTIVE | BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_base + reg_status), DF | ERR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
 }
 
 static void test_bmdma_setup(void)
 static void test_identify(void)
 {
     QPCIDevice *dev;
-    void *bmdma_base, *ide_base;
+    QPCIBar bmdma_bar, ide_bar;
     uint8_t data;
     uint16_t buf[256];
     int i;
         "-global ide-hd.ver=%s",
         tmp_path, "testdisk", "version");
 
-    dev = get_pci_device(&bmdma_base, &ide_base);
+    dev = get_pci_device(&bmdma_bar, &ide_bar);
 
     /* IDENTIFY command on device 0*/
-    qpci_io_writeb(dev, ide_base + reg_device, 0);
-    qpci_io_writeb(dev, ide_base + reg_command, CMD_IDENTIFY);
+    qpci_io_writeb(dev, ide_bar, reg_device, 0);
+    qpci_io_writeb(dev, ide_bar, reg_command, CMD_IDENTIFY);
 
     /* Read in the IDENTIFY buffer and check registers */
-    data = qpci_io_readb(dev, ide_base + reg_device);
+    data = qpci_io_readb(dev, ide_bar, reg_device);
     g_assert_cmpint(data & DEV, ==, 0);
 
     for (i = 0; i < 256; i++) {
-        data = qpci_io_readb(dev, ide_base + reg_status);
+        data = qpci_io_readb(dev, ide_bar, reg_status);
         assert_bit_set(data, DRDY | DRQ);
         assert_bit_clear(data, BSY | DF | ERR);
 
-        buf[i] = qpci_io_readw(dev, ide_base + reg_data);
+        buf[i] = qpci_io_readw(dev, ide_bar, reg_data);
     }
 
-    data = qpci_io_readb(dev, ide_base + reg_status);
+    data = qpci_io_readb(dev, ide_bar, reg_status);
     assert_bit_set(data, DRDY);
     assert_bit_clear(data, BSY | DF | ERR | DRQ);
 
 static void make_dirty(uint8_t device)
 {
     QPCIDevice *dev;
-    void *bmdma_base, *ide_base;
+    QPCIBar bmdma_bar, ide_bar;
     uint8_t status;
     size_t len = 512;
     uintptr_t guest_buf;
     void* buf;
 
-    dev = get_pci_device(&bmdma_base, &ide_base);
+    dev = get_pci_device(&bmdma_bar, &ide_bar);
 
     guest_buf = guest_alloc(guest_malloc, len);
     buf = g_malloc(len);
     status = send_dma_request(CMD_WRITE_DMA, 1, 1, prdt,
                               ARRAY_SIZE(prdt), NULL);
     g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_base + reg_status), DF | ERR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
 
     g_free(buf);
 }
 static void test_flush(void)
 {
     QPCIDevice *dev;
-    void *bmdma_base, *ide_base;
+    QPCIBar bmdma_bar, ide_bar;
     uint8_t data;
 
     ide_test_start(
         "-drive file=blkdebug::%s,if=ide,cache=writeback,format=raw",
         tmp_path);
 
-    dev = get_pci_device(&bmdma_base, &ide_base);
+    dev = get_pci_device(&bmdma_bar, &ide_bar);
 
     qtest_irq_intercept_in(global_qtest, "ioapic");
 
     g_free(hmp("qemu-io ide0-hd0 \"break flush_to_os A\""));
 
     /* FLUSH CACHE command on device 0*/
-    qpci_io_writeb(dev, ide_base + reg_device, 0);
-    qpci_io_writeb(dev, ide_base + reg_command, CMD_FLUSH_CACHE);
+    qpci_io_writeb(dev, ide_bar, reg_device, 0);
+    qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE);
 
     /* Check status while request is in flight*/
-    data = qpci_io_readb(dev, ide_base + reg_status);
+    data = qpci_io_readb(dev, ide_bar, reg_status);
     assert_bit_set(data, BSY | DRDY);
     assert_bit_clear(data, DF | ERR | DRQ);
 
     g_free(hmp("qemu-io ide0-hd0 \"resume A\""));
 
     /* Check registers */
-    data = qpci_io_readb(dev, ide_base + reg_device);
+    data = qpci_io_readb(dev, ide_bar, reg_device);
     g_assert_cmpint(data & DEV, ==, 0);
 
     do {
-        data = qpci_io_readb(dev, ide_base + reg_status);
+        data = qpci_io_readb(dev, ide_bar, reg_status);
     } while (data & BSY);
 
     assert_bit_set(data, DRDY);
 static void test_retry_flush(const char *machine)
 {
     QPCIDevice *dev;
-    void *bmdma_base, *ide_base;
+    QPCIBar bmdma_bar, ide_bar;
     uint8_t data;
     const char *s;
 
         "rerror=stop,werror=stop",
         debug_path, tmp_path);
 
-    dev = get_pci_device(&bmdma_base, &ide_base);
+    dev = get_pci_device(&bmdma_bar, &ide_bar);
 
     qtest_irq_intercept_in(global_qtest, "ioapic");
 
     make_dirty(0);
 
     /* FLUSH CACHE command on device 0*/
-    qpci_io_writeb(dev, ide_base + reg_device, 0);
-    qpci_io_writeb(dev, ide_base + reg_command, CMD_FLUSH_CACHE);
+    qpci_io_writeb(dev, ide_bar, reg_device, 0);
+    qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE);
 
     /* Check status while request is in flight*/
-    data = qpci_io_readb(dev, ide_base + reg_status);
+    data = qpci_io_readb(dev, ide_bar, reg_status);
     assert_bit_set(data, BSY | DRDY);
     assert_bit_clear(data, DF | ERR | DRQ);
 
     qmp_discard_response(s);
 
     /* Check registers */
-    data = qpci_io_readb(dev, ide_base + reg_device);
+    data = qpci_io_readb(dev, ide_bar, reg_device);
     g_assert_cmpint(data & DEV, ==, 0);
 
     do {
-        data = qpci_io_readb(dev, ide_base + reg_status);
+        data = qpci_io_readb(dev, ide_bar, reg_status);
     } while (data & BSY);
 
     assert_bit_set(data, DRDY);
 static void test_flush_nodev(void)
 {
     QPCIDevice *dev;
-    void *bmdma_base, *ide_base;
+    QPCIBar bmdma_bar, ide_bar;
 
     ide_test_start("");
 
-    dev = get_pci_device(&bmdma_base, &ide_base);
+    dev = get_pci_device(&bmdma_bar, &ide_bar);
 
     /* FLUSH CACHE command on device 0*/
-    qpci_io_writeb(dev, ide_base + reg_device, 0);
-    qpci_io_writeb(dev, ide_base + reg_command, CMD_FLUSH_CACHE);
+    qpci_io_writeb(dev, ide_bar, reg_device, 0);
+    qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE);
 
     /* Just testing that qemu doesn't crash... */
 
     uint16_t padding;
 } __attribute__((__packed__)) Read10CDB;
 
-static void send_scsi_cdb_read10(QPCIDevice *dev, void *ide_base,
+static void send_scsi_cdb_read10(QPCIDevice *dev, QPCIBar ide_bar,
                                  uint64_t lba, int nblocks)
 {
     Read10CDB pkt = { .padding = 0 };
 
     /* Send Packet */
     for (i = 0; i < sizeof(Read10CDB)/2; i++) {
-        qpci_io_writew(dev, ide_base + reg_data,
+        qpci_io_writew(dev, ide_bar, reg_data,
                        le16_to_cpu(((uint16_t *)&pkt)[i]));
     }
 }
 static uint8_t ide_wait_clear(uint8_t flag)
 {
     QPCIDevice *dev;
-    void *bmdma_base, *ide_base;
+    QPCIBar bmdma_bar, ide_bar;
     uint8_t data;
     time_t st;
 
-    dev = get_pci_device(&bmdma_base, &ide_base);
+    dev = get_pci_device(&bmdma_bar, &ide_bar);
 
     /* Wait with a 5 second timeout */
     time(&st);
     while (true) {
-        data = qpci_io_readb(dev, ide_base + reg_status);
+        data = qpci_io_readb(dev, ide_bar, reg_status);
         if (!(data & flag)) {
             return data;
         }
 static void cdrom_pio_impl(int nblocks)
 {
     QPCIDevice *dev;
-    void *bmdma_base, *ide_base;
+    QPCIBar bmdma_bar, ide_bar;
     FILE *fh;
     int patt_blocks = MAX(16, nblocks);
     size_t patt_len = ATAPI_BLOCK_SIZE * patt_blocks;
 
     ide_test_start("-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 "
                    "-device ide-cd,drive=sr0,bus=ide.0", tmp_path);
-    dev = get_pci_device(&bmdma_base, &ide_base);
+    dev = get_pci_device(&bmdma_bar, &ide_bar);
     qtest_irq_intercept_in(global_qtest, "ioapic");
 
     /* PACKET command on device 0 */
-    qpci_io_writeb(dev, ide_base + reg_device, 0);
-    qpci_io_writeb(dev, ide_base + reg_lba_middle, BYTE_COUNT_LIMIT & 0xFF);
-    qpci_io_writeb(dev, ide_base + reg_lba_high,
-                   (BYTE_COUNT_LIMIT >> 8 & 0xFF));
-    qpci_io_writeb(dev, ide_base + reg_command, CMD_PACKET);
+    qpci_io_writeb(dev, ide_bar, reg_device, 0);
+    qpci_io_writeb(dev, ide_bar, reg_lba_middle, BYTE_COUNT_LIMIT & 0xFF);
+    qpci_io_writeb(dev, ide_bar, reg_lba_high, (BYTE_COUNT_LIMIT >> 8 & 0xFF));
+    qpci_io_writeb(dev, ide_bar, reg_command, CMD_PACKET);
     /* HP0: Check_Status_A State */
     nsleep(400);
     data = ide_wait_clear(BSY);
     assert_bit_clear(data, ERR | DF | BSY);
 
     /* SCSI CDB (READ10) -- read n*2048 bytes from block 0 */
-    send_scsi_cdb_read10(dev, ide_base, 0, nblocks);
+    send_scsi_cdb_read10(dev, ide_bar, 0, nblocks);
 
     /* Read data back: occurs in bursts of 'BYTE_COUNT_LIMIT' bytes.
      * If BYTE_COUNT_LIMIT is odd, we transfer BYTE_COUNT_LIMIT - 1 bytes.
 
         /* HP4: Transfer_Data */
         for (j = 0; j < MIN((limit / 2), rem); j++) {
-            rx[offset + j] = cpu_to_le16(qpci_io_readw(dev,
-                                                       ide_base + reg_data));
+            rx[offset + j] = cpu_to_le16(qpci_io_readw(dev, ide_bar,
+                                                       reg_data));
         }
     }
 
 
 
 typedef struct _IVState {
     QTestState *qtest;
-    void *reg_base, *mem_base;
+    QPCIBar reg_bar, mem_bar;
     QPCIBus *pcibus;
     QPCIDevice *dev;
 } IVState;
     unsigned res;
 
     global_qtest = s->qtest;
-    res = qpci_io_readl(s->dev, s->reg_base + reg);
+    res = qpci_io_readl(s->dev, s->reg_bar, reg);
     g_test_message("*%s -> %x\n", name, res);
     global_qtest = qtest;
 
 
     global_qtest = s->qtest;
     g_test_message("%x -> *%s\n", v, name);
-    qpci_io_writel(s->dev, s->reg_base + reg, v);
+    qpci_io_writel(s->dev, s->reg_bar, reg, v);
     global_qtest = qtest;
 }
 
     QTestState *qtest = global_qtest;
 
     global_qtest = s->qtest;
-    qpci_memread(s->dev, s->mem_base + off, buf, len);
+    qpci_memread(s->dev, s->mem_bar, off, buf, len);
     global_qtest = qtest;
 }
 
     QTestState *qtest = global_qtest;
 
     global_qtest = s->qtest;
-    qpci_memwrite(s->dev, s->mem_base + off, buf, len);
+    qpci_memwrite(s->dev, s->mem_bar, off, buf, len);
     global_qtest = qtest;
 }
 
     s->pcibus = qpci_init_pc(NULL);
     s->dev = get_device(s->pcibus);
 
-    s->reg_base = qpci_iomap(s->dev, 0, &barsize);
-    g_assert_nonnull(s->reg_base);
+    s->reg_bar = qpci_iomap(s->dev, 0, &barsize);
     g_assert_cmpuint(barsize, ==, 256);
 
     if (msix) {
         qpci_msix_enable(s->dev);
     }
 
-    s->mem_base = qpci_iomap(s->dev, 2, &barsize);
-    g_assert_nonnull(s->mem_base);
+    s->mem_bar = qpci_iomap(s->dev, 2, &barsize);
     g_assert_cmpuint(barsize, ==, TMPSHMSIZE);
 
     qpci_device_enable(s->dev);
 
 void start_ahci_device(AHCIQState *ahci)
 {
     /* Map AHCI's ABAR (BAR5) */
-    ahci->hba_base = qpci_iomap(ahci->dev, 5, &ahci->barsize);
-    g_assert(ahci->hba_base);
+    ahci->hba_bar = qpci_iomap(ahci->dev, 5, &ahci->barsize);
 
     /* turns on pci.cmd.iose, pci.cmd.mse and pci.cmd.bme */
     qpci_device_enable(ahci->dev);
 
 typedef struct AHCIQState {
     QOSState *parent;
     QPCIDevice *dev;
-    void *hba_base;
+    QPCIBar hba_bar;
     uint64_t barsize;
     uint32_t fingerprint;
     uint32_t cap;
 
 static inline uint32_t ahci_mread(AHCIQState *ahci, size_t offset)
 {
-    return qpci_io_readl(ahci->dev, ahci->hba_base + offset);
+    return qpci_io_readl(ahci->dev, ahci->hba_bar, offset);
 }
 
 static inline void ahci_mwrite(AHCIQState *ahci, size_t offset, uint32_t value)
 {
-    qpci_io_writel(ahci->dev, ahci->hba_base + offset, value);
+    qpci_io_writel(ahci->dev, ahci->hba_bar, offset, value);
 }
 
 static inline uint32_t ahci_rreg(AHCIQState *ahci, uint32_t reg_num)
 
     uint32_t table;
     uint8_t bir_table;
     uint8_t bir_pba;
-    void *offset;
 
     addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
     g_assert_cmphex(addr, !=, 0);
 
     table = qpci_config_readl(dev, addr + PCI_MSIX_TABLE);
     bir_table = table & PCI_MSIX_FLAGS_BIRMASK;
-    offset = qpci_iomap(dev, bir_table, NULL);
-    dev->msix_table = offset + (table & ~PCI_MSIX_FLAGS_BIRMASK);
+    dev->msix_table_bar = qpci_iomap(dev, bir_table, NULL);
+    dev->msix_table_off = table & ~PCI_MSIX_FLAGS_BIRMASK;
 
     table = qpci_config_readl(dev, addr + PCI_MSIX_PBA);
     bir_pba = table & PCI_MSIX_FLAGS_BIRMASK;
     if (bir_pba != bir_table) {
-        offset = qpci_iomap(dev, bir_pba, NULL);
+        dev->msix_pba_bar = qpci_iomap(dev, bir_pba, NULL);
     }
-    dev->msix_pba = offset + (table & ~PCI_MSIX_FLAGS_BIRMASK);
+    dev->msix_pba_off = table & ~PCI_MSIX_FLAGS_BIRMASK;
 
-    g_assert(dev->msix_table != NULL);
-    g_assert(dev->msix_pba != NULL);
     dev->msix_enabled = true;
 }
 
     qpci_config_writew(dev, addr + PCI_MSIX_FLAGS,
                                                 val & ~PCI_MSIX_FLAGS_ENABLE);
 
-    qpci_iounmap(dev, dev->msix_table);
-    qpci_iounmap(dev, dev->msix_pba);
+    qpci_iounmap(dev, dev->msix_table_bar);
+    qpci_iounmap(dev, dev->msix_pba_bar);
     dev->msix_enabled = 0;
-    dev->msix_table = NULL;
-    dev->msix_pba = NULL;
+    dev->msix_table_off = 0;
+    dev->msix_pba_off = 0;
 }
 
 bool qpci_msix_pending(QPCIDevice *dev, uint16_t entry)
 {
     uint32_t pba_entry;
     uint8_t bit_n = entry % 32;
-    void *addr = dev->msix_pba + (entry / 32) * PCI_MSIX_ENTRY_SIZE / 4;
+    uint64_t  off = (entry / 32) * PCI_MSIX_ENTRY_SIZE / 4;
 
     g_assert(dev->msix_enabled);
-    pba_entry = qpci_io_readl(dev, addr);
-    qpci_io_writel(dev, addr, pba_entry & ~(1 << bit_n));
+    pba_entry = qpci_io_readl(dev, dev->msix_pba_bar, dev->msix_pba_off + off);
+    qpci_io_writel(dev, dev->msix_pba_bar, dev->msix_pba_off + off,
+                   pba_entry & ~(1 << bit_n));
     return (pba_entry & (1 << bit_n)) != 0;
 }
 
 {
     uint8_t addr;
     uint16_t val;
-    void *vector_addr = dev->msix_table + (entry * PCI_MSIX_ENTRY_SIZE);
+    uint64_t vector_off = dev->msix_table_off + entry * PCI_MSIX_ENTRY_SIZE;
 
     g_assert(dev->msix_enabled);
     addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
     if (val & PCI_MSIX_FLAGS_MASKALL) {
         return true;
     } else {
-        return (qpci_io_readl(dev, vector_addr + PCI_MSIX_ENTRY_VECTOR_CTRL)
-                                            & PCI_MSIX_ENTRY_CTRL_MASKBIT) != 0;
+        return (qpci_io_readl(dev, dev->msix_table_bar,
+                              vector_off + PCI_MSIX_ENTRY_VECTOR_CTRL)
+                & PCI_MSIX_ENTRY_CTRL_MASKBIT) != 0;
     }
 }
 
     dev->bus->config_writel(dev->bus, dev->devfn, offset, value);
 }
 
-
-uint8_t qpci_io_readb(QPCIDevice *dev, void *data)
+uint8_t qpci_io_readb(QPCIDevice *dev, QPCIBar token, uint64_t off)
 {
-    uintptr_t addr = (uintptr_t)data;
-
-    if (addr < QPCI_PIO_LIMIT) {
-        return dev->bus->pio_readb(dev->bus, addr);
+    if (token.addr < QPCI_PIO_LIMIT) {
+        return dev->bus->pio_readb(dev->bus, token.addr + off);
     } else {
         uint8_t val;
-        dev->bus->memread(dev->bus, addr, &val, sizeof(val));
+        dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
         return val;
     }
 }
 
-uint16_t qpci_io_readw(QPCIDevice *dev, void *data)
+uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off)
 {
-    uintptr_t addr = (uintptr_t)data;
-
-    if (addr < QPCI_PIO_LIMIT) {
-        return dev->bus->pio_readw(dev->bus, addr);
+    if (token.addr < QPCI_PIO_LIMIT) {
+        return dev->bus->pio_readw(dev->bus, token.addr + off);
     } else {
         uint16_t val;
-        dev->bus->memread(dev->bus, addr, &val, sizeof(val));
+        dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
         return le16_to_cpu(val);
     }
 }
 
-uint32_t qpci_io_readl(QPCIDevice *dev, void *data)
+uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off)
 {
-    uintptr_t addr = (uintptr_t)data;
-
-    if (addr < QPCI_PIO_LIMIT) {
-        return dev->bus->pio_readl(dev->bus, addr);
+    if (token.addr < QPCI_PIO_LIMIT) {
+        return dev->bus->pio_readl(dev->bus, token.addr + off);
     } else {
         uint32_t val;
-        dev->bus->memread(dev->bus, addr, &val, sizeof(val));
+        dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
         return le32_to_cpu(val);
     }
 }
 
-uint64_t qpci_io_readq(QPCIDevice *dev, void *data)
+uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off)
 {
-    uintptr_t addr = (uintptr_t)data;
-
-    if (addr < QPCI_PIO_LIMIT) {
-        return dev->bus->pio_readq(dev->bus, addr);
+    if (token.addr < QPCI_PIO_LIMIT) {
+        return dev->bus->pio_readq(dev->bus, token.addr + off);
     } else {
         uint64_t val;
-        dev->bus->memread(dev->bus, addr, &val, sizeof(val));
+        dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
         return le64_to_cpu(val);
     }
 }
 
-void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value)
+void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off,
+                    uint8_t value)
 {
-    uintptr_t addr = (uintptr_t)data;
-
-    if (addr < QPCI_PIO_LIMIT) {
-        dev->bus->pio_writeb(dev->bus, addr, value);
+    if (token.addr < QPCI_PIO_LIMIT) {
+        dev->bus->pio_writeb(dev->bus, token.addr + off, value);
     } else {
-        dev->bus->memwrite(dev->bus, addr, &value, sizeof(value));
+        dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
     }
 }
 
-void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value)
+void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off,
+                    uint16_t value)
 {
-    uintptr_t addr = (uintptr_t)data;
-
-    if (addr < QPCI_PIO_LIMIT) {
-        dev->bus->pio_writew(dev->bus, addr, value);
+    if (token.addr < QPCI_PIO_LIMIT) {
+        dev->bus->pio_writew(dev->bus, token.addr + off, value);
     } else {
         value = cpu_to_le16(value);
-        dev->bus->memwrite(dev->bus, addr, &value, sizeof(value));
+        dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
     }
 }
 
-void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value)
+void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off,
+                    uint32_t value)
 {
-    uintptr_t addr = (uintptr_t)data;
-
-    if (addr < QPCI_PIO_LIMIT) {
-        dev->bus->pio_writel(dev->bus, addr, value);
+    if (token.addr < QPCI_PIO_LIMIT) {
+        dev->bus->pio_writel(dev->bus, token.addr + off, value);
     } else {
         value = cpu_to_le32(value);
-        dev->bus->memwrite(dev->bus, addr, &value, sizeof(value));
+        dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
     }
 }
 
-void qpci_io_writeq(QPCIDevice *dev, void *data, uint64_t value)
+void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off,
+                    uint64_t value)
 {
-    uintptr_t addr = (uintptr_t)data;
-
-    if (addr < QPCI_PIO_LIMIT) {
-        dev->bus->pio_writeq(dev->bus, addr, value);
+    if (token.addr < QPCI_PIO_LIMIT) {
+        dev->bus->pio_writeq(dev->bus, token.addr + off, value);
     } else {
         value = cpu_to_le64(value);
-        dev->bus->memwrite(dev->bus, addr, &value, sizeof(value));
+        dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
     }
 }
 
-void qpci_memread(QPCIDevice *dev, void *data, void *buf, size_t len)
+void qpci_memread(QPCIDevice *dev, QPCIBar token, uint64_t off,
+                  void *buf, size_t len)
 {
-    uintptr_t addr = (uintptr_t)data;
-
-    g_assert(addr >= QPCI_PIO_LIMIT);
-    dev->bus->memread(dev->bus, addr, buf, len);
+    g_assert(token.addr >= QPCI_PIO_LIMIT);
+    dev->bus->memread(dev->bus, token.addr + off, buf, len);
 }
 
-void qpci_memwrite(QPCIDevice *dev, void *data, const void *buf, size_t len)
+void qpci_memwrite(QPCIDevice *dev, QPCIBar token, uint64_t off,
+                   const void *buf, size_t len)
 {
-    uintptr_t addr = (uintptr_t)data;
-
-    g_assert(addr >= QPCI_PIO_LIMIT);
-    dev->bus->memwrite(dev->bus, addr, buf, len);
+    g_assert(token.addr >= QPCI_PIO_LIMIT);
+    dev->bus->memwrite(dev->bus, token.addr + off, buf, len);
 }
 
-void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
+QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
 {
     QPCIBus *bus = dev->bus;
     static const int bar_reg_map[] = {
         PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
         PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5,
     };
+    QPCIBar bar;
     int bar_reg;
     uint32_t addr, size;
     uint32_t io_type;
         qpci_config_writel(dev, bar_reg, loc);
     }
 
-    return (void *)(uintptr_t)loc;
+    bar.addr = loc;
+    return bar;
 }
 
-void qpci_iounmap(QPCIDevice *dev, void *data)
+void qpci_iounmap(QPCIDevice *dev, QPCIBar bar)
 {
     /* FIXME */
 }
 
-void *qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
+QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
 {
-    return (void *)(uintptr_t)addr;
+    QPCIBar bar = { .addr = addr };
+    return bar;
 }
 
 void qpci_plug_device_test(const char *driver, const char *id,
 
 
 typedef struct QPCIDevice QPCIDevice;
 typedef struct QPCIBus QPCIBus;
+typedef struct QPCIBar QPCIBar;
 
 struct QPCIBus {
     uint8_t (*pio_readb)(QPCIBus *bus, uint32_t addr);
     uint64_t mmio_alloc_ptr, mmio_limit;
 };
 
+struct QPCIBar {
+    uint64_t addr;
+};
+
 struct QPCIDevice
 {
     QPCIBus *bus;
     int devfn;
     bool msix_enabled;
-    void *msix_table;
-    void *msix_pba;
+    QPCIBar msix_table_bar, msix_pba_bar;
+    uint64_t msix_table_off, msix_pba_off;
 };
 
 void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
 void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value);
 void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value);
 
-uint8_t qpci_io_readb(QPCIDevice *dev, void *data);
-uint16_t qpci_io_readw(QPCIDevice *dev, void *data);
-uint32_t qpci_io_readl(QPCIDevice *dev, void *data);
-uint64_t qpci_io_readq(QPCIDevice *dev, void *data);
-
-void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value);
-void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value);
-void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value);
-void qpci_io_writeq(QPCIDevice *dev, void *data, uint64_t value);
-
-void qpci_memread(QPCIDevice *bus, void *data, void *buf, size_t len);
-void qpci_memwrite(QPCIDevice *bus, void *data, const void *buf, size_t len);
-
-void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr);
-void qpci_iounmap(QPCIDevice *dev, void *data);
-void *qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr);
+uint8_t qpci_io_readb(QPCIDevice *dev, QPCIBar token, uint64_t off);
+uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off);
+uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off);
+uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off);
+
+void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off,
+                    uint8_t value);
+void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off,
+                    uint16_t value);
+void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off,
+                    uint32_t value);
+void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off,
+                    uint64_t value);
+
+void qpci_memread(QPCIDevice *bus, QPCIBar token, uint64_t off,
+                  void *buf, size_t len);
+void qpci_memwrite(QPCIDevice *bus, QPCIBar token, uint64_t off,
+                   const void *buf, size_t len);
+QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr);
+void qpci_iounmap(QPCIDevice *dev, QPCIBar addr);
+QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr);
 
 void qpci_plug_device_test(const char *driver, const char *id,
                            uint8_t slot, const char *opts);
 
     hc->dev = qpci_device_find(pcibus, devfn);
     g_assert(hc->dev != NULL);
     qpci_device_enable(hc->dev);
-    hc->base = qpci_iomap(hc->dev, bar, NULL);
-    g_assert(hc->base != NULL);
+    hc->bar = qpci_iomap(hc->dev, bar, NULL);
 }
 
 void uhci_port_test(struct qhc *hc, int port, uint16_t expect)
 {
-    void *addr = hc->base + 0x10 + 2 * port;
-    uint16_t value = qpci_io_readw(hc->dev, addr);
+    uint16_t value = qpci_io_readw(hc->dev, hc->bar, 0x10 + 2 * port);
     uint16_t mask = ~(UHCI_PORT_WRITE_CLEAR | UHCI_PORT_RSVD1);
 
     g_assert((value & mask) == (expect & mask));
 
 
 struct qhc {
     QPCIDevice *dev;
-    void *base;
+    QPCIBar bar;
 };
 
 void qusb_pci_init_one(QPCIBus *pcibus, struct qhc *hc,
 
     *vpcidev = (QVirtioPCIDevice *)d;
 }
 
-#define CONFIG_BASE(dev) \
-    ((dev)->addr + VIRTIO_PCI_CONFIG_OFF((dev)->pdev->msix_enabled))
+#define CONFIG_BASE(dev) (VIRTIO_PCI_CONFIG_OFF((dev)->pdev->msix_enabled))
 
 static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t off)
 {
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
-    return qpci_io_readb(dev->pdev, CONFIG_BASE(dev) + off);
+    return qpci_io_readb(dev->pdev, dev->bar, CONFIG_BASE(dev) + off);
 }
 
 /* PCI is always read in little-endian order
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
     uint16_t value;
 
-    value = qpci_io_readw(dev->pdev, CONFIG_BASE(dev) + off);
+    value = qpci_io_readw(dev->pdev, dev->bar, CONFIG_BASE(dev) + off);
     if (qvirtio_is_big_endian(d)) {
         value = bswap16(value);
     }
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
     uint32_t value;
 
-    value = qpci_io_readl(dev->pdev, CONFIG_BASE(dev) + off);
+    value = qpci_io_readl(dev->pdev, dev->bar, CONFIG_BASE(dev) + off);
     if (qvirtio_is_big_endian(d)) {
         value = bswap32(value);
     }
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
     uint64_t val;
 
-    val = qpci_io_readq(dev->pdev, CONFIG_BASE(dev) + off);
+    val = qpci_io_readq(dev->pdev, dev->bar, CONFIG_BASE(dev) + off);
     if (qvirtio_is_big_endian(d)) {
         val = bswap64(val);
     }
 static uint32_t qvirtio_pci_get_features(QVirtioDevice *d)
 {
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
-    return qpci_io_readl(dev->pdev, dev->addr + VIRTIO_PCI_HOST_FEATURES);
+    return qpci_io_readl(dev->pdev, dev->bar, VIRTIO_PCI_HOST_FEATURES);
 }
 
 static void qvirtio_pci_set_features(QVirtioDevice *d, uint32_t features)
 {
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
-    qpci_io_writel(dev->pdev, dev->addr + VIRTIO_PCI_GUEST_FEATURES, features);
+    qpci_io_writel(dev->pdev, dev->bar, VIRTIO_PCI_GUEST_FEATURES, features);
 }
 
 static uint32_t qvirtio_pci_get_guest_features(QVirtioDevice *d)
 {
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
-    return qpci_io_readl(dev->pdev, dev->addr + VIRTIO_PCI_GUEST_FEATURES);
+    return qpci_io_readl(dev->pdev, dev->bar, VIRTIO_PCI_GUEST_FEATURES);
 }
 
 static uint8_t qvirtio_pci_get_status(QVirtioDevice *d)
 {
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
-    return qpci_io_readb(dev->pdev, dev->addr + VIRTIO_PCI_STATUS);
+    return qpci_io_readb(dev->pdev, dev->bar, VIRTIO_PCI_STATUS);
 }
 
 static void qvirtio_pci_set_status(QVirtioDevice *d, uint8_t status)
 {
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
-    qpci_io_writeb(dev->pdev, dev->addr + VIRTIO_PCI_STATUS, status);
+    qpci_io_writeb(dev->pdev, dev->bar, VIRTIO_PCI_STATUS, status);
 }
 
 static bool qvirtio_pci_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq)
             }
         }
     } else {
-        return qpci_io_readb(dev->pdev, dev->addr + VIRTIO_PCI_ISR) & 1;
+        return qpci_io_readb(dev->pdev, dev->bar, VIRTIO_PCI_ISR) & 1;
     }
 }
 
             }
         }
     } else {
-        return qpci_io_readb(dev->pdev, dev->addr + VIRTIO_PCI_ISR) & 2;
+        return qpci_io_readb(dev->pdev, dev->bar, VIRTIO_PCI_ISR) & 2;
     }
 }
 
 static void qvirtio_pci_queue_select(QVirtioDevice *d, uint16_t index)
 {
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
-    qpci_io_writeb(dev->pdev, dev->addr + VIRTIO_PCI_QUEUE_SEL, index);
+    qpci_io_writeb(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_SEL, index);
 }
 
 static uint16_t qvirtio_pci_get_queue_size(QVirtioDevice *d)
 {
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
-    return qpci_io_readw(dev->pdev, dev->addr + VIRTIO_PCI_QUEUE_NUM);
+    return qpci_io_readw(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_NUM);
 }
 
 static void qvirtio_pci_set_queue_address(QVirtioDevice *d, uint32_t pfn)
 {
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
-    qpci_io_writel(dev->pdev, dev->addr + VIRTIO_PCI_QUEUE_PFN, pfn);
+    qpci_io_writel(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_PFN, pfn);
 }
 
 static QVirtQueue *qvirtio_pci_virtqueue_setup(QVirtioDevice *d,
 static void qvirtio_pci_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq)
 {
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
-    qpci_io_writew(dev->pdev, dev->addr + VIRTIO_PCI_QUEUE_NOTIFY, vq->index);
+    qpci_io_writew(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_NOTIFY, vq->index);
 }
 
 const QVirtioBus qvirtio_pci = {
 void qvirtio_pci_device_enable(QVirtioPCIDevice *d)
 {
     qpci_device_enable(d->pdev);
-    d->addr = qpci_iomap(d->pdev, 0, NULL);
-    g_assert(d->addr != NULL);
+    d->bar = qpci_iomap(d->pdev, 0, NULL);
 }
 
 void qvirtio_pci_device_disable(QVirtioPCIDevice *d)
 {
-    qpci_iounmap(d->pdev, d->addr);
-    d->addr = NULL;
+    qpci_iounmap(d->pdev, d->bar);
 }
 
 void qvirtqueue_pci_msix_setup(QVirtioPCIDevice *d, QVirtQueuePCI *vqpci,
 {
     uint16_t vector;
     uint32_t control;
-    void *addr;
+    uint64_t off;
 
     g_assert(d->pdev->msix_enabled);
-    addr = d->pdev->msix_table + (entry * 16);
+    off = d->pdev->msix_table_off + (entry * 16);
 
     g_assert_cmpint(entry, >=, 0);
     g_assert_cmpint(entry, <, qpci_msix_table_size(d->pdev));
     vqpci->msix_entry = entry;
 
     vqpci->msix_addr = guest_alloc(alloc, 4);
-    qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_LOWER_ADDR,
-                                                    vqpci->msix_addr & ~0UL);
-    qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_UPPER_ADDR,
-                                            (vqpci->msix_addr >> 32) & ~0UL);
-    qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_DATA, vqpci->msix_data);
-
-    control = qpci_io_readl(d->pdev, addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
-    qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_VECTOR_CTRL,
-                                        control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT);
+    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
+                   off + PCI_MSIX_ENTRY_LOWER_ADDR, vqpci->msix_addr & ~0UL);
+    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
+                   off + PCI_MSIX_ENTRY_UPPER_ADDR,
+                   (vqpci->msix_addr >> 32) & ~0UL);
+    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
+                   off + PCI_MSIX_ENTRY_DATA, vqpci->msix_data);
+
+    control = qpci_io_readl(d->pdev, d->pdev->msix_table_bar,
+                            off + PCI_MSIX_ENTRY_VECTOR_CTRL);
+    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
+                   off + PCI_MSIX_ENTRY_VECTOR_CTRL,
+                   control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT);
 
     qvirtio_pci_queue_select(&d->vdev, vqpci->vq.index);
-    qpci_io_writew(d->pdev, d->addr + VIRTIO_MSI_QUEUE_VECTOR, entry);
-    vector = qpci_io_readw(d->pdev, d->addr + VIRTIO_MSI_QUEUE_VECTOR);
+    qpci_io_writew(d->pdev, d->bar, VIRTIO_MSI_QUEUE_VECTOR, entry);
+    vector = qpci_io_readw(d->pdev, d->bar, VIRTIO_MSI_QUEUE_VECTOR);
     g_assert_cmphex(vector, !=, VIRTIO_MSI_NO_VECTOR);
 }
 
 {
     uint16_t vector;
     uint32_t control;
-    void *addr;
+    uint64_t off;
 
     g_assert(d->pdev->msix_enabled);
-    addr = d->pdev->msix_table + (entry * 16);
+    off = d->pdev->msix_table_off + (entry * 16);
 
     g_assert_cmpint(entry, >=, 0);
     g_assert_cmpint(entry, <, qpci_msix_table_size(d->pdev));
     d->config_msix_data = 0x12345678;
     d->config_msix_addr = guest_alloc(alloc, 4);
 
-    qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_LOWER_ADDR,
-                                                    d->config_msix_addr & ~0UL);
-    qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_UPPER_ADDR,
-                                            (d->config_msix_addr >> 32) & ~0UL);
-    qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_DATA, d->config_msix_data);
-
-    control = qpci_io_readl(d->pdev, addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
-    qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_VECTOR_CTRL,
-                                        control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT);
-
-    qpci_io_writew(d->pdev, d->addr + VIRTIO_MSI_CONFIG_VECTOR, entry);
-    vector = qpci_io_readw(d->pdev, d->addr + VIRTIO_MSI_CONFIG_VECTOR);
+    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
+                   off + PCI_MSIX_ENTRY_LOWER_ADDR, d->config_msix_addr & ~0UL);
+    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
+                   off + PCI_MSIX_ENTRY_UPPER_ADDR,
+                   (d->config_msix_addr >> 32) & ~0UL);
+    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
+                   off + PCI_MSIX_ENTRY_DATA, d->config_msix_data);
+
+    control = qpci_io_readl(d->pdev, d->pdev->msix_table_bar,
+                            off + PCI_MSIX_ENTRY_VECTOR_CTRL);
+    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
+                   off + PCI_MSIX_ENTRY_VECTOR_CTRL,
+                   control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT);
+
+    qpci_io_writew(d->pdev, d->bar, VIRTIO_MSI_CONFIG_VECTOR, entry);
+    vector = qpci_io_readw(d->pdev, d->bar, VIRTIO_MSI_CONFIG_VECTOR);
     g_assert_cmphex(vector, !=, VIRTIO_MSI_NO_VECTOR);
 }
 
 typedef struct QVirtioPCIDevice {
     QVirtioDevice vdev;
     QPCIDevice *pdev;
-    void *addr;
+    QPCIBar bar;
     uint16_t config_msix_entry;
     uint64_t config_msix_addr;
     uint32_t config_msix_data;
 
 
 static QPCIBus *pcibus;
 static QPCIDevice *dev;
-static void *dev_base;
+static QPCIBar dev_bar;
 
 static void save_fn(QPCIDevice *dev, int devfn, void *data)
 {
 #define PORT(name, len, val) \
 static unsigned __attribute__((unused)) in_##name(void) \
 { \
-    unsigned res = qpci_io_read##len(dev, dev_base+(val)); \
+    unsigned res = qpci_io_read##len(dev, dev_bar, (val));     \
     g_test_message("*%s -> %x\n", #name, res); \
     return res; \
 } \
 static void out_##name(unsigned v) \
 { \
     g_test_message("%x -> *%s\n", v, #name); \
-    qpci_io_write##len(dev, dev_base+(val), v); \
+    qpci_io_write##len(dev, dev_bar, (val), v);        \
 }
 
 PORT(Timer, l, 0x48)
 
     dev = get_device();
 
-    dev_base = qpci_iomap(dev, 0, &barsize);
-
-    g_assert(dev_base != NULL);
+    dev_bar = qpci_iomap(dev, 0, &barsize);
 
     qpci_device_enable(dev);
 
 
     const char *args;
     bool noreboot;
     QPCIDevice *dev;
-    void *tco_io_base;
+    QPCIBar tco_io_bar;
 } TestData;
 
 static void test_init(TestData *d)
     /* set Root Complex BAR */
     qpci_config_writel(d->dev, ICH9_LPC_RCBA, RCBA_BASE_ADDR | 0x1);
 
-    d->tco_io_base = qpci_legacy_iomap(d->dev, PM_IO_BASE_ADDR + 0x60);
+    d->tco_io_bar = qpci_legacy_iomap(d->dev, PM_IO_BASE_ADDR + 0x60);
 }
 
 static void stop_tco(const TestData *d)
 {
     uint32_t val;
 
-    val = qpci_io_readw(d->dev, d->tco_io_base + TCO1_CNT);
+    val = qpci_io_readw(d->dev, d->tco_io_bar, TCO1_CNT);
     val |= TCO_TMR_HLT;
-    qpci_io_writew(d->dev, d->tco_io_base + TCO1_CNT, val);
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO1_CNT, val);
 }
 
 static void start_tco(const TestData *d)
 {
     uint32_t val;
 
-    val = qpci_io_readw(d->dev, d->tco_io_base + TCO1_CNT);
+    val = qpci_io_readw(d->dev, d->tco_io_bar, TCO1_CNT);
     val &= ~TCO_TMR_HLT;
-    qpci_io_writew(d->dev, d->tco_io_base + TCO1_CNT, val);
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO1_CNT, val);
 }
 
 static void load_tco(const TestData *d)
 {
-    qpci_io_writew(d->dev, d->tco_io_base + TCO_RLD, 4);
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO_RLD, 4);
 }
 
 static void set_tco_timeout(const TestData *d, uint16_t ticks)
 {
-    qpci_io_writew(d->dev, d->tco_io_base + TCO_TMR, ticks);
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO_TMR, ticks);
 }
 
 static void clear_tco_status(const TestData *d)
 {
-    qpci_io_writew(d->dev, d->tco_io_base + TCO1_STS, 0x0008);
-    qpci_io_writew(d->dev, d->tco_io_base + TCO2_STS, 0x0002);
-    qpci_io_writew(d->dev, d->tco_io_base + TCO2_STS, 0x0004);
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO1_STS, 0x0008);
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO2_STS, 0x0002);
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO2_STS, 0x0004);
 }
 
 static void reset_on_second_timeout(bool enable)
     d.args = NULL;
     d.noreboot = true;
     test_init(&d);
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_base + TCO_RLD), ==,
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD), ==,
                     TCO_RLD_DEFAULT);
     /* TCO_DAT_IN & TCO_DAT_OUT */
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_base + TCO_DAT_IN), ==,
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_DAT_IN), ==,
                     (TCO_DAT_OUT_DEFAULT << 8) | TCO_DAT_IN_DEFAULT);
     /* TCO1_STS & TCO2_STS */
-    g_assert_cmpint(qpci_io_readl(d.dev, d.tco_io_base + TCO1_STS), ==,
+    g_assert_cmpint(qpci_io_readl(d.dev, d.tco_io_bar, TCO1_STS), ==,
                     (TCO2_STS_DEFAULT << 16) | TCO1_STS_DEFAULT);
     /* TCO1_CNT & TCO2_CNT */
-    g_assert_cmpint(qpci_io_readl(d.dev, d.tco_io_base + TCO1_CNT), ==,
+    g_assert_cmpint(qpci_io_readl(d.dev, d.tco_io_bar, TCO1_CNT), ==,
                     (TCO2_CNT_DEFAULT << 16) | TCO1_CNT_DEFAULT);
     /* TCO_MESSAGE1 & TCO_MESSAGE2 */
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_base + TCO_MESSAGE1), ==,
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_MESSAGE1), ==,
                     (TCO_MESSAGE2_DEFAULT << 8) | TCO_MESSAGE1_DEFAULT);
-    g_assert_cmpint(qpci_io_readb(d.dev, d.tco_io_base + TCO_WDCNT), ==,
+    g_assert_cmpint(qpci_io_readb(d.dev, d.tco_io_bar, TCO_WDCNT), ==,
                     TCO_WDCNT_DEFAULT);
-    g_assert_cmpint(qpci_io_readb(d.dev, d.tco_io_base + SW_IRQ_GEN), ==,
+    g_assert_cmpint(qpci_io_readb(d.dev, d.tco_io_bar, SW_IRQ_GEN), ==,
                     SW_IRQ_GEN_DEFAULT);
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_base + TCO_TMR), ==,
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_TMR), ==,
                     TCO_TMR_DEFAULT);
     qtest_end();
 }
     clock_step(ticks * TCO_TICK_NSEC);
 
     /* test first timeout */
-    val = qpci_io_readw(d.dev, d.tco_io_base + TCO1_STS);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
     ret = val & TCO_TIMEOUT ? 1 : 0;
     g_assert(ret == 1);
 
     /* test clearing timeout bit */
     val |= TCO_TIMEOUT;
-    qpci_io_writew(d.dev, d.tco_io_base + TCO1_STS, val);
-    val = qpci_io_readw(d.dev, d.tco_io_base + TCO1_STS);
+    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_STS, val);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
     ret = val & TCO_TIMEOUT ? 1 : 0;
     g_assert(ret == 0);
 
     /* test second timeout */
     clock_step(ticks * TCO_TICK_NSEC);
-    val = qpci_io_readw(d.dev, d.tco_io_base + TCO1_STS);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
     ret = val & TCO_TIMEOUT ? 1 : 0;
     g_assert(ret == 1);
-    val = qpci_io_readw(d.dev, d.tco_io_base + TCO2_STS);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO2_STS);
     ret = val & TCO_SECOND_TO_STS ? 1 : 0;
     g_assert(ret == 1);
 
     start_tco(&d);
     clock_step(((ticks & TCO_TMR_MASK) - 1) * TCO_TICK_NSEC);
 
-    val = qpci_io_readw(d.dev, d.tco_io_base + TCO_RLD);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD);
     g_assert_cmpint(val & TCO_RLD_MASK, ==, 1);
-    val = qpci_io_readw(d.dev, d.tco_io_base + TCO1_STS);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
     ret = val & TCO_TIMEOUT ? 1 : 0;
     g_assert(ret == 0);
     clock_step(TCO_TICK_NSEC);
-    val = qpci_io_readw(d.dev, d.tco_io_base + TCO1_STS);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
     ret = val & TCO_TIMEOUT ? 1 : 0;
     g_assert(ret == 1);
 
     start_tco(&d);
 
     do {
-        rld = qpci_io_readw(d.dev, d.tco_io_base + TCO_RLD) & TCO_RLD_MASK;
+        rld = qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD) & TCO_RLD_MASK;
         g_assert_cmpint(rld, ==, ticks);
         clock_step(TCO_TICK_NSEC);
         ticks--;
-    } while (!(qpci_io_readw(d.dev, d.tco_io_base + TCO1_STS) & TCO_TIMEOUT));
+    } while (!(qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS) & TCO_TIMEOUT));
 
     stop_tco(&d);
     qtest_end();
     test_init(&d);
 
     val = TCO_LOCK;
-    qpci_io_writew(d.dev, d.tco_io_base + TCO1_CNT, val);
+    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_CNT, val);
     val &= ~TCO_LOCK;
-    qpci_io_writew(d.dev, d.tco_io_base + TCO1_CNT, val);
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_base + TCO1_CNT), ==,
+    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_CNT, val);
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO1_CNT), ==,
                     TCO_LOCK);
     qtest_end();
 }
     start_tco(&d);
     clock_step(ticks * TCO_TICK_NSEC);
 
-    qpci_io_writeb(d.dev, d.tco_io_base + TCO_DAT_IN, 0);
-    qpci_io_writeb(d.dev, d.tco_io_base + TCO_DAT_OUT, 0);
-    val = qpci_io_readw(d.dev, d.tco_io_base + TCO1_STS);
+    qpci_io_writeb(d.dev, d.tco_io_bar, TCO_DAT_IN, 0);
+    qpci_io_writeb(d.dev, d.tco_io_bar, TCO_DAT_OUT, 0);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
     ret = val & (TCO_TIMEOUT | SW_TCO_SMI | TCO_INT_STS) ? 1 : 0;
     g_assert(ret == 1);
-    qpci_io_writew(d.dev, d.tco_io_base + TCO1_STS, val);
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_base + TCO1_STS), ==, 0);
+    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_STS, val);
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS), ==, 0);
     qtest_end();
 }
 
     start_tco(&d);
     clock_step(ticks * TCO_TICK_NSEC * 2);
 
-    val = qpci_io_readw(d.dev, d.tco_io_base + TCO2_STS);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO2_STS);
     ret = val & (TCO_SECOND_TO_STS | TCO_BOOT_STS) ? 1 : 0;
     g_assert(ret == 1);
-    qpci_io_writew(d.dev, d.tco_io_base + TCO2_STS, val);
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_base + TCO2_STS), ==, 0);
+    qpci_io_writew(d.dev, d.tco_io_bar, TCO2_STS, val);
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO2_STS), ==, 0);
     qtest_end();
 }
 
 
 
 static void ehci_port_test(struct qhc *hc, int port, uint32_t expect)
 {
-    void *addr = hc->base + 0x64 + 4 * port;
-    uint32_t value = qpci_io_readl(hc->dev, addr);
+    uint32_t value = qpci_io_readl(hc->dev, hc->bar, 0x64 + 4 * port);
     uint16_t mask = ~(PORTSC_CSC | PORTSC_PEDC | PORTSC_OCC);
 
 #if 0
 static void pci_ehci_config(void)
 {
     /* hands over all ports from companion uhci to ehci */
-    qpci_io_writew(ehci1.dev, ehci1.base + 0x60, 1);
+    qpci_io_writew(ehci1.dev, ehci1.bar, 0x60, 1);
 }
 
 static void pci_uhci_port_2(void)