diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c
index 15ac171..3a71510 100644
--- a/src/hw/virtio-blk.c
+++ b/src/hw/virtio-blk.c
@@ -25,7 +25,7 @@
 struct virtiodrive_s {
     struct drive_s drive;
     struct vring_virtqueue *vq;
-    u16 ioaddr;
+    struct vp_device vp;
 };
 
 static int
@@ -60,7 +60,7 @@ virtio_blk_op(struct disk_op_s *op, int write)
         vring_add_buf(vq, sg, 2, 1, 0, 0);
     else
         vring_add_buf(vq, sg, 1, 2, 0, 0);
-    vring_kick(GET_GLOBALFLAT(vdrive_gf->ioaddr), vq, 1);
+    vring_kick(&vdrive_gf->vp, vq, 1);
 
     /* Wait for reply */
     while (!vring_more_used(vq))
@@ -72,7 +72,7 @@ virtio_blk_op(struct disk_op_s *op, int write)
     /* Clear interrupt status register.  Avoid leaving interrupts stuck if
      * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
      */
-    vp_get_isr(GET_GLOBALFLAT(vdrive_gf->ioaddr));
+    vp_get_isr(&vdrive_gf->vp);
 
     return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
 }
@@ -113,18 +113,17 @@ init_virtio_blk(struct pci_device *pci)
     vdrive->drive.type = DTYPE_VIRTIO_BLK;
     vdrive->drive.cntl_id = bdf;
 
-    u16 ioaddr = vp_init_simple(bdf);
-    vdrive->ioaddr = ioaddr;
-    if (vp_find_vq(ioaddr, 0, &vdrive->vq) < 0 ) {
+    vp_init_simple(&vdrive->vp, bdf);
+    if (vp_find_vq(&vdrive->vp, 0, &vdrive->vq) < 0 ) {
         dprintf(1, "fail to find vq for virtio-blk %x:%x\n",
                 pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
         goto fail;
     }
 
     struct virtio_blk_config cfg;
-    vp_get(ioaddr, 0, &cfg, sizeof(cfg));
+    vp_get(&vdrive->vp, 0, &cfg, sizeof(cfg));
 
-    u32 f = vp_get_features(ioaddr);
+    u32 f = vp_get_features(&vdrive->vp);
     vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ?
         cfg.blk_size : DISK_SECTOR_SIZE;
 
@@ -148,12 +147,12 @@ init_virtio_blk(struct pci_device *pci)
 
     boot_add_hd(&vdrive->drive, desc, bootprio_find_pci_device(pci));
 
-    vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+    vp_set_status(&vdrive->vp, VIRTIO_CONFIG_S_ACKNOWLEDGE |
                   VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
     return;
 
 fail:
-    vp_reset(ioaddr);
+    vp_reset(&vdrive->vp);
     free(vdrive->vq);
     free(vdrive);
 }
diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c
index b9b3ab1..f648328 100644
--- a/src/hw/virtio-pci.c
+++ b/src/hw/virtio-pci.c
@@ -24,9 +24,10 @@
 #include "virtio-pci.h"
 #include "virtio-ring.h"
 
-int vp_find_vq(unsigned int ioaddr, int queue_index,
+int vp_find_vq(struct vp_device *vp, int queue_index,
                struct vring_virtqueue **p_vq)
 {
+   int ioaddr = GET_LOWFLAT(vp->ioaddr);
    u16 num;
 
    ASSERT32FLAT();
@@ -84,14 +85,13 @@ fail:
    return -1;
 }
 
-u16 vp_init_simple(u16 bdf)
+void vp_init_simple(struct vp_device *vp, u16 bdf)
 {
-    u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) &
+    vp->ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) &
         PCI_BASE_ADDRESS_IO_MASK;
 
-    vp_reset(ioaddr);
+    vp_reset(vp);
     pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
-    vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+    vp_set_status(vp, VIRTIO_CONFIG_S_ACKNOWLEDGE |
                   VIRTIO_CONFIG_S_DRIVER );
-    return ioaddr;
 }
diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h
index bc04b03..c1caf67 100644
--- a/src/hw/virtio-pci.h
+++ b/src/hw/virtio-pci.h
@@ -2,6 +2,7 @@
 #define _VIRTIO_PCI_H
 
 #include "x86.h" // inl
+#include "biosvar.h" // GET_LOWFLAT
 
 /* A 32-bit r/o bitmask of the features supported by the host */
 #define VIRTIO_PCI_HOST_FEATURES        0
@@ -39,19 +40,24 @@
 /* Virtio ABI version, this must match exactly */
 #define VIRTIO_PCI_ABI_VERSION          0
 
-static inline u32 vp_get_features(unsigned int ioaddr)
+struct vp_device {
+    unsigned int ioaddr;
+};
+
+static inline u32 vp_get_features(struct vp_device *vp)
 {
-   return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES);
+    return inl(GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_HOST_FEATURES);
 }
 
-static inline void vp_set_features(unsigned int ioaddr, u32 features)
+static inline void vp_set_features(struct vp_device *vp, u32 features)
 {
-        outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES);
+    outl(features, GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_GUEST_FEATURES);
 }
 
-static inline void vp_get(unsigned int ioaddr, unsigned offset,
+static inline void vp_get(struct vp_device *vp, unsigned offset,
                      void *buf, unsigned len)
 {
+   int ioaddr = GET_LOWFLAT(vp->ioaddr);
    u8 *ptr = buf;
    unsigned i;
 
@@ -59,47 +65,49 @@ static inline void vp_get(unsigned int ioaddr, unsigned offset,
            ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i);
 }
 
-static inline u8 vp_get_status(unsigned int ioaddr)
+static inline u8 vp_get_status(struct vp_device *vp)
 {
-   return inb(ioaddr + VIRTIO_PCI_STATUS);
+    return inb(GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_STATUS);
 }
 
-static inline void vp_set_status(unsigned int ioaddr, u8 status)
+static inline void vp_set_status(struct vp_device *vp, u8 status)
 {
    if (status == 0)        /* reset */
            return;
-   outb(status, ioaddr + VIRTIO_PCI_STATUS);
+   outb(status, GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_STATUS);
 }
 
-static inline u8 vp_get_isr(unsigned int ioaddr)
+static inline u8 vp_get_isr(struct vp_device *vp)
 {
-   return inb(ioaddr + VIRTIO_PCI_ISR);
+    return inb(GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_ISR);
 }
 
-static inline void vp_reset(unsigned int ioaddr)
+static inline void vp_reset(struct vp_device *vp)
 {
+   int ioaddr = GET_LOWFLAT(vp->ioaddr);
+
    outb(0, ioaddr + VIRTIO_PCI_STATUS);
    (void)inb(ioaddr + VIRTIO_PCI_ISR);
 }
 
-static inline void vp_notify(unsigned int ioaddr, int queue_index)
+static inline void vp_notify(struct vp_device *vp, int queue_index)
 {
-   outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
+    outw(queue_index, GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_QUEUE_NOTIFY);
 }
 
-static inline void vp_del_vq(unsigned int ioaddr, int queue_index)
+static inline void vp_del_vq(struct vp_device *vp, int queue_index)
 {
+   int ioaddr = GET_LOWFLAT(vp->ioaddr);
+
    /* select the queue */
-
    outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
 
    /* deactivate the queue */
-
    outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN);
 }
 
 struct vring_virtqueue;
-u16 vp_init_simple(u16 bdf);
-int vp_find_vq(unsigned int ioaddr, int queue_index,
+void vp_init_simple(struct vp_device *vp, u16 bdf);
+int vp_find_vq(struct vp_device *vp, int queue_index,
                struct vring_virtqueue **p_vq);
 #endif /* _VIRTIO_PCI_H_ */
diff --git a/src/hw/virtio-ring.c b/src/hw/virtio-ring.c
index 97e0b34..5c6a32e 100644
--- a/src/hw/virtio-ring.c
+++ b/src/hw/virtio-ring.c
@@ -136,7 +136,7 @@ void vring_add_buf(struct vring_virtqueue *vq,
     SET_LOWFLAT(avail->ring[av], head);
 }
 
-void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
+void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added)
 {
     struct vring *vr = &vq->vring;
     struct vring_avail *avail = GET_LOWFLAT(vr->avail);
@@ -145,5 +145,5 @@ void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
     smp_wmb();
     SET_LOWFLAT(avail->idx, GET_LOWFLAT(avail->idx) + num_added);
 
-    vp_notify(ioaddr, GET_LOWFLAT(vq->queue_index));
+    vp_notify(vp, GET_LOWFLAT(vq->queue_index));
 }
diff --git a/src/hw/virtio-ring.h b/src/hw/virtio-ring.h
index b7a7aaf..fe5133b 100644
--- a/src/hw/virtio-ring.h
+++ b/src/hw/virtio-ring.h
@@ -120,12 +120,13 @@ static inline void vring_init(struct vring *vr,
    vr->desc[i].next = 0;
 }
 
+struct vp_device;
 int vring_more_used(struct vring_virtqueue *vq);
 void vring_detach(struct vring_virtqueue *vq, unsigned int head);
 int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len);
 void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[],
                    unsigned int out, unsigned int in,
                    int index, int num_added);
-void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added);
+void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added);
 
 #endif /* _VIRTIO_RING_H_ */
diff --git a/src/hw/virtio-scsi.c b/src/hw/virtio-scsi.c
index 8f96687..eb7eb81 100644
--- a/src/hw/virtio-scsi.c
+++ b/src/hw/virtio-scsi.c
@@ -27,14 +27,15 @@ struct virtio_lun_s {
     struct drive_s drive;
     struct pci_device *pci;
     struct vring_virtqueue *vq;
-    u16 ioaddr;
+    struct vp_device *vp;
     u16 target;
     u16 lun;
 };
 
 static int
-virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
-                void *cdbcmd, u16 target, u16 lun, u16 blocksize)
+virtio_scsi_cmd(struct vp_device *vp, struct vring_virtqueue *vq,
+                struct disk_op_s *op, void *cdbcmd, u16 target, u16 lun,
+                u16 blocksize)
 {
     struct virtio_scsi_req_cmd req;
     struct virtio_scsi_resp_cmd resp;
@@ -66,7 +67,7 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
 
     /* Add to virtqueue and kick host */
     vring_add_buf(vq, sg, out_num, in_num, 0, 0);
-    vring_kick(ioaddr, vq, 1);
+    vring_kick(vp, vq, 1);
 
     /* Wait for reply */
     while (!vring_more_used(vq))
@@ -78,7 +79,7 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
     /* Clear interrupt status register.  Avoid leaving interrupts stuck if
      * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
      */
-    vp_get_isr(ioaddr);
+    vp_get_isr(vp);
 
     if (resp.response == VIRTIO_SCSI_S_OK && resp.status == 0) {
         return DISK_RET_SUCCESS;
@@ -92,7 +93,7 @@ virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
     struct virtio_lun_s *vlun_gf =
         container_of(op->drive_gf, struct virtio_lun_s, drive);
 
-    return virtio_scsi_cmd(GET_GLOBALFLAT(vlun_gf->ioaddr),
+    return virtio_scsi_cmd(GET_GLOBALFLAT(vlun_gf->vp),
                            GET_GLOBALFLAT(vlun_gf->vq), op, cdbcmd,
                            GET_GLOBALFLAT(vlun_gf->target),
                            GET_GLOBALFLAT(vlun_gf->lun),
@@ -100,7 +101,7 @@ virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
 }
 
 static int
-virtio_scsi_add_lun(struct pci_device *pci, u16 ioaddr,
+virtio_scsi_add_lun(struct pci_device *pci, struct vp_device *vp,
                     struct vring_virtqueue *vq, u16 target, u16 lun)
 {
     struct virtio_lun_s *vlun = malloc_fseg(sizeof(*vlun));
@@ -112,7 +113,7 @@ virtio_scsi_add_lun(struct pci_device *pci, u16 ioaddr,
     vlun->drive.type = DTYPE_VIRTIO_SCSI;
     vlun->drive.cntl_id = pci->bdf;
     vlun->pci = pci;
-    vlun->ioaddr = ioaddr;
+    vlun->vp = vp;
     vlun->vq = vq;
     vlun->target = target;
     vlun->lun = lun;
@@ -129,11 +130,11 @@ fail:
 }
 
 static int
-virtio_scsi_scan_target(struct pci_device *pci, u16 ioaddr,
+virtio_scsi_scan_target(struct pci_device *pci, struct vp_device *vp,
                         struct vring_virtqueue *vq, u16 target)
 {
     /* TODO: send REPORT LUNS.  For now, only LUN 0 is recognized.  */
-    int ret = virtio_scsi_add_lun(pci, ioaddr, vq, target, 0);
+    int ret = virtio_scsi_add_lun(pci, vp, vq, target, 0);
     return ret < 0 ? 0 : 1;
 }
 
@@ -144,19 +145,24 @@ init_virtio_scsi(struct pci_device *pci)
     dprintf(1, "found virtio-scsi at %x:%x\n", pci_bdf_to_bus(bdf),
             pci_bdf_to_dev(bdf));
     struct vring_virtqueue *vq = NULL;
-    u16 ioaddr = vp_init_simple(bdf);
-    if (vp_find_vq(ioaddr, 2, &vq) < 0 ) {
+    struct vp_device *vp = malloc_high(sizeof(*vp));
+    if (!vp) {
+        warn_noalloc();
+        return;
+    }
+    vp_init_simple(vp, bdf);
+    if (vp_find_vq(vp, 2, &vq) < 0 ) {
         dprintf(1, "fail to find vq for virtio-scsi %x:%x\n",
                 pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
         goto fail;
     }
 
-    vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+    vp_set_status(vp, VIRTIO_CONFIG_S_ACKNOWLEDGE |
                   VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
 
     int i, tot;
     for (tot = 0, i = 0; i < 256; i++)
-        tot += virtio_scsi_scan_target(pci, ioaddr, vq, i);
+        tot += virtio_scsi_scan_target(pci, vp, vq, i);
 
     if (!tot)
         goto fail;
@@ -164,7 +170,8 @@ init_virtio_scsi(struct pci_device *pci)
     return;
 
 fail:
-    vp_reset(ioaddr);
+    vp_reset(vp);
+    free(vp);
     free(vq);
 }
 
