diff options
author | neel <neel@FreeBSD.org> | 2014-09-17 18:46:51 +0000 |
---|---|---|
committer | neel <neel@FreeBSD.org> | 2014-09-17 18:46:51 +0000 |
commit | c9b7ad126a69df6d747aa31e822ad6ae3ea9c900 (patch) | |
tree | c99380d1a0386a2472762670318cd92cfcb5b65a /usr.sbin/bhyve | |
parent | eefb10a1843c72b46fee9c11a6cde4146031ea4d (diff) | |
parent | 65bccd5b546490ed3e9ef43ce93d5a573d366801 (diff) | |
download | FreeBSD-src-c9b7ad126a69df6d747aa31e822ad6ae3ea9c900.zip FreeBSD-src-c9b7ad126a69df6d747aa31e822ad6ae3ea9c900.tar.gz |
IFC @r271694
Diffstat (limited to 'usr.sbin/bhyve')
-rw-r--r-- | usr.sbin/bhyve/block_if.c | 1 | ||||
-rw-r--r-- | usr.sbin/bhyve/pci_virtio_block.c | 1 | ||||
-rw-r--r-- | usr.sbin/bhyve/pci_virtio_net.c | 85 | ||||
-rw-r--r-- | usr.sbin/bhyve/pci_virtio_rnd.c | 1 | ||||
-rw-r--r-- | usr.sbin/bhyve/task_switch.c | 18 | ||||
-rw-r--r-- | usr.sbin/bhyve/virtio.c | 11 | ||||
-rw-r--r-- | usr.sbin/bhyve/virtio.h | 2 |
7 files changed, 96 insertions, 23 deletions
diff --git a/usr.sbin/bhyve/block_if.c b/usr.sbin/bhyve/block_if.c index 1ec0344..b038228 100644 --- a/usr.sbin/bhyve/block_if.c +++ b/usr.sbin/bhyve/block_if.c @@ -278,6 +278,7 @@ blockif_open(const char *optstr, const char *ident) bc->bc_magic = BLOCKIF_SIG; bc->bc_fd = fd; + bc->bc_rdonly = ro; bc->bc_size = size; bc->bc_sectsz = sectsz; pthread_mutex_init(&bc->bc_mtx, NULL); diff --git a/usr.sbin/bhyve/pci_virtio_block.c b/usr.sbin/bhyve/pci_virtio_block.c index cf1c655..394b116 100644 --- a/usr.sbin/bhyve/pci_virtio_block.c +++ b/usr.sbin/bhyve/pci_virtio_block.c @@ -133,6 +133,7 @@ static struct virtio_consts vtblk_vi_consts = { pci_vtblk_notify, /* device-wide qnotify */ pci_vtblk_cfgread, /* read PCI config */ pci_vtblk_cfgwrite, /* write PCI config */ + NULL, /* apply negotiated features */ VTBLK_S_HOSTCAPS, /* our capabilities */ }; diff --git a/usr.sbin/bhyve/pci_virtio_net.c b/usr.sbin/bhyve/pci_virtio_net.c index c3b8690..5ac9ecd 100644 --- a/usr.sbin/bhyve/pci_virtio_net.c +++ b/usr.sbin/bhyve/pci_virtio_net.c @@ -135,11 +135,14 @@ struct pci_vtnet_softc { int vsc_rx_ready; volatile int resetting; /* set and checked outside lock */ - uint32_t vsc_features; + uint64_t vsc_features; /* negotiated features */ + struct virtio_net_config vsc_config; pthread_mutex_t rx_mtx; int rx_in_progress; + int rx_vhdrlen; + int rx_merge; /* merged rx bufs in use */ pthread_t tx_tid; pthread_mutex_t tx_mtx; @@ -151,6 +154,7 @@ static void pci_vtnet_reset(void *); /* static void pci_vtnet_notify(void *, struct vqueue_info *); */ static int pci_vtnet_cfgread(void *, int, int, uint32_t *); static int pci_vtnet_cfgwrite(void *, int, int, uint32_t); +static void pci_vtnet_neg_features(void *, uint64_t); static struct virtio_consts vtnet_vi_consts = { "vtnet", /* our name */ @@ -160,6 +164,7 @@ static struct virtio_consts vtnet_vi_consts = { NULL, /* device-wide qnotify -- not used */ pci_vtnet_cfgread, /* read PCI config */ pci_vtnet_cfgwrite, /* write PCI config */ + pci_vtnet_neg_features, /* apply negotiated features */ VTNET_S_HOSTCAPS, /* our capabilities */ }; @@ -212,6 +217,8 @@ pci_vtnet_reset(void *vsc) pci_vtnet_rxwait(sc); sc->vsc_rx_ready = 0; + sc->rx_merge = 1; + sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr); /* now reset rings, MSI-X vectors, and negotiated capabilities */ vi_reset_dev(&sc->vsc_vs); @@ -253,14 +260,34 @@ pci_vtnet_tap_tx(struct pci_vtnet_softc *sc, struct iovec *iov, int iovcnt, */ static uint8_t dummybuf[2048]; +static __inline struct iovec * +rx_iov_trim(struct iovec *iov, int *niov, int tlen) +{ + struct iovec *riov; + + /* XXX short-cut: assume first segment is >= tlen */ + assert(iov[0].iov_len >= tlen); + + iov[0].iov_len -= tlen; + if (iov[0].iov_len == 0) { + assert(*niov > 1); + *niov -= 1; + riov = &iov[1]; + } else { + iov[0].iov_base = (void *)((uintptr_t)iov[0].iov_base + tlen); + riov = &iov[0]; + } + + return (riov); +} + static void pci_vtnet_tap_rx(struct pci_vtnet_softc *sc) { + struct iovec iov[VTNET_MAXSEGS], *riov; struct vqueue_info *vq; - struct virtio_net_rxhdr *vrx; - uint8_t *buf; - int len; - struct iovec iov; + void *vrx; + int len, n; /* * Should never be called without a valid tap fd @@ -296,21 +323,19 @@ pci_vtnet_tap_rx(struct pci_vtnet_softc *sc) do { /* - * Get descriptor chain, which should have just - * one descriptor in it. - * ??? allow guests to use multiple descs? + * Get descriptor chain. */ - assert(vq_getchain(vq, &iov, 1, NULL) == 1); + n = vq_getchain(vq, iov, VTNET_MAXSEGS, NULL); + assert(n >= 1 && n <= VTNET_MAXSEGS); /* * Get a pointer to the rx header, and use the * data immediately following it for the packet buffer. */ - vrx = iov.iov_base; - buf = (uint8_t *)(vrx + 1); + vrx = iov[0].iov_base; + riov = rx_iov_trim(iov, &n, sc->rx_vhdrlen); - len = read(sc->vsc_tapfd, buf, - iov.iov_len - sizeof(struct virtio_net_rxhdr)); + len = readv(sc->vsc_tapfd, riov, n); if (len < 0 && errno == EWOULDBLOCK) { /* @@ -323,16 +348,21 @@ pci_vtnet_tap_rx(struct pci_vtnet_softc *sc) /* * The only valid field in the rx packet header is the - * number of buffers, which is always 1 without TSO - * support. + * number of buffers if merged rx bufs were negotiated. */ - memset(vrx, 0, sizeof(struct virtio_net_rxhdr)); - vrx->vrh_bufs = 1; + memset(vrx, 0, sc->rx_vhdrlen); + + if (sc->rx_merge) { + struct virtio_net_rxhdr *vrxh; + + vrxh = vrx; + vrxh->vrh_bufs = 1; + } /* * Release this chain and handle more chains. */ - vq_relchain(vq, len + sizeof(struct virtio_net_rxhdr)); + vq_relchain(vq, len + sc->rx_vhdrlen); } while (vq_has_descs(vq)); /* Interrupt if needed, including for NOTIFY_ON_EMPTY. */ @@ -623,6 +653,8 @@ pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) sc->resetting = 0; + sc->rx_merge = 1; + sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr); sc->rx_in_progress = 0; pthread_mutex_init(&sc->rx_mtx, NULL); @@ -656,9 +688,10 @@ pci_vtnet_cfgwrite(void *vsc, int offset, int size, uint32_t value) ptr = &sc->vsc_config.mac[offset]; memcpy(ptr, &value, size); } else { + /* silently ignore other writes */ DPRINTF(("vtnet: write to readonly reg %d\n\r", offset)); - return (1); } + return (0); } @@ -673,6 +706,20 @@ pci_vtnet_cfgread(void *vsc, int offset, int size, uint32_t *retval) return (0); } +static void +pci_vtnet_neg_features(void *vsc, uint64_t negotiated_features) +{ + struct pci_vtnet_softc *sc = vsc; + + sc->vsc_features = negotiated_features; + + if (!(sc->vsc_features & VIRTIO_NET_F_MRG_RXBUF)) { + sc->rx_merge = 0; + /* non-merge rx header is 2 bytes shorter */ + sc->rx_vhdrlen -= 2; + } +} + struct pci_devemu pci_de_vnet = { .pe_emu = "virtio-net", .pe_init = pci_vtnet_init, diff --git a/usr.sbin/bhyve/pci_virtio_rnd.c b/usr.sbin/bhyve/pci_virtio_rnd.c index 4d53183..0a31080 100644 --- a/usr.sbin/bhyve/pci_virtio_rnd.c +++ b/usr.sbin/bhyve/pci_virtio_rnd.c @@ -80,6 +80,7 @@ static struct virtio_consts vtrnd_vi_consts = { pci_vtrnd_notify, /* device-wide qnotify */ NULL, /* read virtio config */ NULL, /* write virtio config */ + NULL, /* apply negotiated features */ 0, /* our capabilities */ }; diff --git a/usr.sbin/bhyve/task_switch.c b/usr.sbin/bhyve/task_switch.c index 0002da8..b939c1a 100644 --- a/usr.sbin/bhyve/task_switch.c +++ b/usr.sbin/bhyve/task_switch.c @@ -725,6 +725,21 @@ vmexit_task_switch(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) assert(paging->cpu_mode == CPU_MODE_PROTECTED); /* + * Calculate the %eip to store in the old TSS before modifying the + * 'inst_length'. + */ + eip = vmexit->rip + vmexit->inst_length; + + /* + * Set the 'inst_length' to '0'. + * + * If an exception is triggered during emulation of the task switch + * then the exception handler should return to the instruction that + * caused the task switch as opposed to the subsequent instruction. + */ + vmexit->inst_length = 0; + + /* * Section 4.6, "Access Rights" in Intel SDM Vol 3. * The following page table accesses are implicitly supervisor mode: * - accesses to GDT or LDT to load segment descriptors @@ -839,7 +854,6 @@ vmexit_task_switch(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) } /* Save processor state in old TSS */ - eip = vmexit->rip + vmexit->inst_length; tss32_save(ctx, vcpu, task_switch, eip, &oldtss, ot_iov); /* @@ -870,7 +884,7 @@ vmexit_task_switch(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) * the saved instruction pointer will belong to the new task. */ vmexit->rip = newtss.tss_eip; - vmexit->inst_length = 0; + assert(vmexit->inst_length == 0); /* Load processor state from new TSS */ error = tss32_restore(ctx, vcpu, task_switch, ot_sel, &newtss, nt_iov); diff --git a/usr.sbin/bhyve/virtio.c b/usr.sbin/bhyve/virtio.c index 1f27300..19c0d47 100644 --- a/usr.sbin/bhyve/virtio.c +++ b/usr.sbin/bhyve/virtio.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <stdint.h> #include <pthread.h> +#include <pthread_np.h> #include "bhyverun.h" #include "pci_emul.h" @@ -89,6 +90,9 @@ vi_reset_dev(struct virtio_softc *vs) struct vqueue_info *vq; int i, nvq; + if (vs->vs_mtx) + assert(pthread_mutex_isowned_np(vs->vs_mtx)); + nvq = vs->vs_vc->vc_nvq; for (vq = vs->vs_queues, i = 0; i < nvq; vq++, i++) { vq->vq_flags = 0; @@ -99,11 +103,9 @@ vi_reset_dev(struct virtio_softc *vs) vs->vs_negotiated_caps = 0; vs->vs_curq = 0; /* vs->vs_status = 0; -- redundant */ - VS_LOCK(vs); if (vs->vs_isr) pci_lintr_deassert(vs->vs_pi); vs->vs_isr = 0; - VS_UNLOCK(vs); vs->vs_msix_cfg_idx = VIRTIO_MSI_NO_VECTOR; } @@ -137,7 +139,9 @@ vi_intr_init(struct virtio_softc *vs, int barnum, int use_msix) if (use_msix) { vs->vs_flags |= VIRTIO_USE_MSIX; + VS_LOCK(vs); vi_reset_dev(vs); /* set all vectors to NO_VECTOR */ + VS_UNLOCK(vs); nvec = vs->vs_vc->vc_nvq + 1; if (pci_emul_add_msixcap(vs->vs_pi, nvec, barnum)) return (1); @@ -694,6 +698,9 @@ bad: switch (offset) { case VTCFG_R_GUESTCAP: vs->vs_negotiated_caps = value & vc->vc_hv_caps; + if (vc->vc_apply_features) + (*vc->vc_apply_features)(DEV_SOFTC(vs), + vs->vs_negotiated_caps); break; case VTCFG_R_PFN: if (vs->vs_curq >= vc->vc_nvq) diff --git a/usr.sbin/bhyve/virtio.h b/usr.sbin/bhyve/virtio.h index 1f29dfa..6f655f3 100644 --- a/usr.sbin/bhyve/virtio.h +++ b/usr.sbin/bhyve/virtio.h @@ -352,6 +352,8 @@ struct virtio_consts { /* called to read config regs */ int (*vc_cfgwrite)(void *, int, int, uint32_t); /* called to write config regs */ + void (*vc_apply_features)(void *, uint64_t); + /* called to apply negotiated features */ uint64_t vc_hv_caps; /* hypervisor-provided capabilities */ }; |