diff --git a/usr.sbin/bhyve/acpi.c b/usr.sbin/bhyve/acpi.c index 32effdc1e953..cabe75ef59f6 100644 --- a/usr.sbin/bhyve/acpi.c +++ b/usr.sbin/bhyve/acpi.c @@ -683,13 +683,16 @@ static int basl_load(int fd, uint64_t off) { struct stat sb; + void *gaddr; int err; err = 0; - - if (fstat(fd, &sb) < 0 || - read(fd, paddr_guest2host(basl_acpi_base + off), sb.st_size) < 0) + gaddr = paddr_guest2host(basl_acpi_base + off, sb.st_size); + if (gaddr != NULL) { + if (fstat(fd, &sb) < 0 || read(fd, gaddr, sb.st_size) < 0) err = errno; + } else + err = EFAULT; return (err); } diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c index ea4b68c703cb..17d60d6ef9fa 100644 --- a/usr.sbin/bhyve/bhyverun.c +++ b/usr.sbin/bhyve/bhyverun.c @@ -157,17 +157,19 @@ usage(int code) } void * -paddr_guest2host(uintptr_t gaddr) +paddr_guest2host(uintptr_t gaddr, size_t len) { - if (lomem_sz == 0) - return (NULL); - if (gaddr < lomem_sz) { + if (gaddr < lomem_sz && gaddr + len <= lomem_sz) return ((void *)(lomem_addr + gaddr)); - } else if (gaddr >= 4*GB && gaddr < (4*GB + himem_sz)) { - return ((void *)(himem_addr + gaddr - 4*GB)); - } else - return (NULL); + + if (gaddr >= 4*GB) { + gaddr -= 4*GB; + if (gaddr < himem_sz && gaddr + len <= himem_sz) + return ((void *)(himem_addr + gaddr)); + } + + return (NULL); } int diff --git a/usr.sbin/bhyve/bhyverun.h b/usr.sbin/bhyve/bhyverun.h index 45033b8a5e1b..70455bf3ace2 100644 --- a/usr.sbin/bhyve/bhyverun.h +++ b/usr.sbin/bhyve/bhyverun.h @@ -43,7 +43,7 @@ extern char *vmname; extern u_long lomem_sz, himem_sz; -void *paddr_guest2host(uintptr_t); +void *paddr_guest2host(uintptr_t addr, size_t len); void fbsdrun_addcpu(struct vmctx *ctx, int cpu, uint64_t rip); int fbsdrun_muxed(void); diff --git a/usr.sbin/bhyve/mptbl.c b/usr.sbin/bhyve/mptbl.c index 52790f38ab8e..9c68b3d0258d 100644 --- a/usr.sbin/bhyve/mptbl.c +++ b/usr.sbin/bhyve/mptbl.c @@ -41,6 +41,9 @@ __FBSDID("$FreeBSD$"); #define MPTABLE_BASE 0xF0000 +/* floating pointer length + maximum length of configuration table */ +#define MPTABLE_MAX_LENGTH (65536 + 16) + #define LAPIC_PADDR 0xFEE00000 #define LAPIC_VERSION 16 @@ -346,13 +349,13 @@ mptable_build(struct vmctx *ctx, int ncpu, int ioapic) char *curraddr; char *startaddr; - if (paddr_guest2host(0) == NULL) { + startaddr = paddr_guest2host(MPTABLE_BASE, MPTABLE_MAX_LENGTH); + if (startaddr == NULL) { printf("mptable requires mapped mem\n"); return (ENOMEM); } - startaddr = curraddr = paddr_guest2host(MPTABLE_BASE); - + curraddr = startaddr; mpfp = (mpfps_t)curraddr; mpt_build_mpfp(mpfp, MPTABLE_BASE); curraddr += sizeof(*mpfp); diff --git a/usr.sbin/bhyve/pci_virtio_block.c b/usr.sbin/bhyve/pci_virtio_block.c index 62bf801bdcc8..31ff2e62ac76 100644 --- a/usr.sbin/bhyve/pci_virtio_block.c +++ b/usr.sbin/bhyve/pci_virtio_block.c @@ -222,13 +222,13 @@ pci_vtblk_proc(struct pci_vtblk_softc *sc, struct vring_hqueue *hq) assert(nsegs >= 3); assert(nsegs < VTBLK_MAXSEGS + 2); - vid = paddr_guest2host(vd->vd_addr); + vid = paddr_guest2host(vd->vd_addr, vd->vd_len); assert((vid->vd_flags & VRING_DESC_F_INDIRECT) == 0); /* * The first descriptor will be the read-only fixed header */ - vbh = paddr_guest2host(vid[0].vd_addr); + vbh = paddr_guest2host(vid[0].vd_addr, sizeof(struct virtio_blk_hdr)); assert(vid[0].vd_len == sizeof(struct virtio_blk_hdr)); assert(vid[0].vd_flags & VRING_DESC_F_NEXT); assert((vid[0].vd_flags & VRING_DESC_F_WRITE) == 0); @@ -247,7 +247,8 @@ pci_vtblk_proc(struct pci_vtblk_softc *sc, struct vring_hqueue *hq) * Build up the iovec based on the guest's data descriptors */ for (i = 1, iolen = 0; i < nsegs - 1; i++) { - iov[i-1].iov_base = paddr_guest2host(vid[i].vd_addr); + iov[i-1].iov_base = paddr_guest2host(vid[i].vd_addr, + vid[i].vd_len); iov[i-1].iov_len = vid[i].vd_len; iolen += vid[i].vd_len; @@ -265,7 +266,7 @@ pci_vtblk_proc(struct pci_vtblk_softc *sc, struct vring_hqueue *hq) } /* Lastly, get the address of the status byte */ - status = paddr_guest2host(vid[nsegs - 1].vd_addr); + status = paddr_guest2host(vid[nsegs - 1].vd_addr, 1); assert(vid[nsegs - 1].vd_len == 1); assert((vid[nsegs - 1].vd_flags & VRING_DESC_F_NEXT) == 0); assert(vid[nsegs - 1].vd_flags & VRING_DESC_F_WRITE); @@ -341,7 +342,8 @@ pci_vtblk_ring_init(struct pci_vtblk_softc *sc, uint64_t pfn) hq = &sc->vbsc_q; hq->hq_size = VTBLK_RINGSZ; - hq->hq_dtable = paddr_guest2host(pfn << VRING_PFN); + hq->hq_dtable = paddr_guest2host(pfn << VRING_PFN, + vring_size(VTBLK_RINGSZ)); hq->hq_avail_flags = (uint16_t *)(hq->hq_dtable + hq->hq_size); hq->hq_avail_idx = hq->hq_avail_flags + 1; hq->hq_avail_ring = hq->hq_avail_flags + 2; @@ -371,13 +373,6 @@ pci_vtblk_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) return (1); } - /* - * Access to guest memory is required. Fail if - * memory not mapped - */ - if (paddr_guest2host(0) == NULL) - return (1); - /* * The supplied backing file has to exist */ diff --git a/usr.sbin/bhyve/pci_virtio_net.c b/usr.sbin/bhyve/pci_virtio_net.c index 327ebf714416..a5cf8b3c85cd 100644 --- a/usr.sbin/bhyve/pci_virtio_net.c +++ b/usr.sbin/bhyve/pci_virtio_net.c @@ -326,7 +326,7 @@ pci_vtnet_tap_rx(struct pci_vtnet_softc *sc) * Get a pointer to the rx header, and use the * data immediately following it for the packet buffer. */ - vrx = (struct virtio_net_rxhdr *)paddr_guest2host(vd->vd_addr); + vrx = paddr_guest2host(vd->vd_addr, vd->vd_len); buf = (uint8_t *)(vrx + 1); len = read(sc->vsc_tapfd, buf, @@ -434,7 +434,7 @@ pci_vtnet_proctx(struct pci_vtnet_softc *sc, struct vring_hqueue *hq) for (i = 0, plen = 0; i < VTNET_MAXSEGS; i++, vd = &hq->hq_dtable[vd->vd_next]) { - iov[i].iov_base = paddr_guest2host(vd->vd_addr); + iov[i].iov_base = paddr_guest2host(vd->vd_addr, vd->vd_len); iov[i].iov_len = vd->vd_len; plen += vd->vd_len; tlen += vd->vd_len; @@ -517,7 +517,8 @@ pci_vtnet_ring_init(struct pci_vtnet_softc *sc, uint64_t pfn) hq = &sc->vsc_hq[qnum]; hq->hq_size = pci_vtnet_qsize(qnum); - hq->hq_dtable = paddr_guest2host(pfn << VRING_PFN); + hq->hq_dtable = paddr_guest2host(pfn << VRING_PFN, + vring_size(hq->hq_size)); hq->hq_avail_flags = (uint16_t *)(hq->hq_dtable + hq->hq_size); hq->hq_avail_idx = hq->hq_avail_flags + 1; hq->hq_avail_ring = hq->hq_avail_flags + 2; @@ -541,13 +542,6 @@ pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) struct pci_vtnet_softc *sc; const char *env_msi; - /* - * Access to guest memory is required. Fail if - * memory not mapped - */ - if (paddr_guest2host(0) == NULL) - return (1); - sc = malloc(sizeof(struct pci_vtnet_softc)); memset(sc, 0, sizeof(struct pci_vtnet_softc)); diff --git a/usr.sbin/bhyve/virtio.h b/usr.sbin/bhyve/virtio.h index 04ef586afcd7..fe6fb1af3e12 100644 --- a/usr.sbin/bhyve/virtio.h +++ b/usr.sbin/bhyve/virtio.h @@ -85,4 +85,19 @@ struct virtio_used { #define VTCFG_R_CFG1 24 /* With MSI-X */ #define VTCFG_R_MSIX 20 +/* From section 2.3, "Virtqueue Configuration", of the virtio specification */ +static inline u_int +vring_size(u_int qsz) +{ + u_int size; + + size = sizeof(struct virtio_desc) * qsz + sizeof(uint16_t) * (3 + qsz); + size = roundup2(size, VRING_ALIGN); + + size += sizeof(uint16_t) * 3 + sizeof(struct virtio_used) * qsz; + size = roundup2(size, VRING_ALIGN); + + return (size); +} + #endif /* _VIRTIO_H_ */