diff options
Diffstat (limited to 'usr.sbin/bhyve/pci_e82545.c')
-rw-r--r-- | usr.sbin/bhyve/pci_e82545.c | 156 |
1 files changed, 90 insertions, 66 deletions
diff --git a/usr.sbin/bhyve/pci_e82545.c b/usr.sbin/bhyve/pci_e82545.c index 1df2f31be200..1afcb559f2bb 100644 --- a/usr.sbin/bhyve/pci_e82545.c +++ b/usr.sbin/bhyve/pci_e82545.c @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2016 Alexander Motin <mav@FreeBSD.org> * Copyright (c) 2015 Peter Grehan <grehan@freebsd.org> @@ -29,9 +29,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/types.h> #ifndef WITHOUT_CAPSICUM #include <sys/capsicum.h> @@ -46,7 +43,6 @@ __FBSDID("$FreeBSD$"); #ifndef WITHOUT_CAPSICUM #include <capsicum_helpers.h> #endif -#include <machine/vmm_snapshot.h> #include <err.h> #include <errno.h> @@ -68,6 +64,9 @@ __FBSDID("$FreeBSD$"); #include "config.h" #include "debug.h" #include "pci_emul.h" +#ifdef BHYVE_SNAPSHOT +#include "snapshot.h" +#endif #include "mevent.h" #include "net_utils.h" #include "net_backends.h" @@ -233,7 +232,7 @@ struct ck_info { * Debug printf */ static int e82545_debug = 0; -#define WPRINTF(msg,params...) PRINTLN("e82545: " msg, params) +#define WPRINTF(msg,params...) PRINTLN("e82545: " msg, ##params) #define DPRINTF(msg,params...) if (e82545_debug) WPRINTF(msg, params) #define MIN(a,b) (((a)<(b))?(a):(b)) @@ -364,7 +363,7 @@ static void e82545_tx_start(struct e82545_softc *sc); static void e82545_tx_enable(struct e82545_softc *sc); static void e82545_tx_disable(struct e82545_softc *sc); -static inline int +static inline int __unused e82545_size_stat_index(uint32_t size) { if (size <= 64) { @@ -407,15 +406,15 @@ e82545_init_eeprom(struct e82545_softc *sc) } static void -e82545_write_mdi(struct e82545_softc *sc, uint8_t reg_addr, - uint8_t phy_addr, uint32_t data) +e82545_write_mdi(struct e82545_softc *sc __unused, uint8_t reg_addr, + uint8_t phy_addr, uint32_t data) { DPRINTF("Write mdi reg:0x%x phy:0x%x data: 0x%x", reg_addr, phy_addr, data); } static uint32_t -e82545_read_mdi(struct e82545_softc *sc, uint8_t reg_addr, - uint8_t phy_addr) +e82545_read_mdi(struct e82545_softc *sc __unused, uint8_t reg_addr, + uint8_t phy_addr) { //DPRINTF("Read mdi reg:0x%x phy:0x%x", reg_addr, phy_addr); switch (reg_addr) { @@ -554,7 +553,7 @@ e82545_eecd_strobe(struct e82545_softc *sc) } static void -e82545_itr_callback(int fd, enum ev_type type, void *param) +e82545_itr_callback(int fd __unused, enum ev_type type __unused, void *param) { uint32_t new; struct e82545_softc *sc = param; @@ -812,7 +811,7 @@ e82545_tx_ctl(struct e82545_softc *sc, uint32_t val) sc->esc_TCTL = val & ~0xFE800005; } -int +static int e82545_bufsz(uint32_t rctl) { @@ -830,12 +829,13 @@ e82545_bufsz(uint32_t rctl) /* XXX one packet at a time until this is debugged */ static void -e82545_rx_callback(int fd, enum ev_type type, void *param) +e82545_rx_callback(int fd __unused, enum ev_type type __unused, void *param) { struct e82545_softc *sc = param; struct e1000_rx_desc *rxd; struct iovec vec[64]; - int left, len, lim, maxpktsz, maxpktdesc, bufsz, i, n, size; + ssize_t len; + int left, lim, maxpktsz, maxpktdesc, bufsz, i, n, size; uint32_t cause = 0; uint16_t *tp, tag, head; @@ -877,7 +877,7 @@ e82545_rx_callback(int fd, enum ev_type type, void *param) } len = netbe_recv(sc->esc_be, vec, maxpktdesc); if (len <= 0) { - DPRINTF("netbe_recv() returned %d", len); + DPRINTF("netbe_recv() returned %zd", len); goto done; } @@ -892,7 +892,7 @@ e82545_rx_callback(int fd, enum ev_type type, void *param) len += ETHER_CRC_LEN; n = (len + bufsz - 1) / bufsz; - DPRINTF("packet read %d bytes, %d segs, head %d", + DPRINTF("packet read %zd bytes, %d segs, head %d", len, n, head); /* Apply VLAN filter. */ @@ -929,7 +929,7 @@ e82545_rx_callback(int fd, enum ev_type type, void *param) E1000_RXD_STAT_EOP | E1000_RXD_STAT_DD; /* Schedule receive interrupts. */ - if (len <= sc->esc_RSRPD) { + if ((uint32_t)len <= sc->esc_RSRPD) { cause |= E1000_ICR_SRPD | E1000_ICR_RXT0; } else { /* XXX: RDRT and RADV timers should be here. */ @@ -976,7 +976,7 @@ e82545_buf_checksum(uint8_t *buf, int len) uint32_t sum = 0; /* Checksum all the pairs of bytes first... */ - for (i = 0; i < (len & ~1U); i += 2) + for (i = 0; i < (len & ~1); i += 2) sum += *((u_int16_t *)(buf + i)); /* @@ -991,9 +991,10 @@ e82545_buf_checksum(uint8_t *buf, int len) } static uint16_t -e82545_iov_checksum(struct iovec *iov, int iovcnt, int off, int len) +e82545_iov_checksum(struct iovec *iov, int iovcnt, unsigned int off, + unsigned int len) { - int now, odd; + unsigned int now, odd; uint32_t sum = 0, s; /* Skip completely unneeded vectors. */ @@ -1007,7 +1008,7 @@ e82545_iov_checksum(struct iovec *iov, int iovcnt, int off, int len) odd = 0; while (len > 0 && iovcnt > 0) { now = MIN(len, iov->iov_len - off); - s = e82545_buf_checksum(iov->iov_base + off, now); + s = e82545_buf_checksum((uint8_t *)iov->iov_base + off, now); sum += odd ? (s << 8) : s; odd ^= (now & 1); len -= now; @@ -1022,7 +1023,7 @@ e82545_iov_checksum(struct iovec *iov, int iovcnt, int off, int len) /* * Return the transmit descriptor type. */ -int +static int e82545_txdesc_type(uint32_t lower) { int type; @@ -1039,11 +1040,11 @@ static void e82545_transmit_checksum(struct iovec *iov, int iovcnt, struct ck_info *ck) { uint16_t cksum; - int cklen; + unsigned int cklen; DPRINTF("tx cksum: iovcnt/s/off/len %d/%d/%d/%d", iovcnt, ck->ck_start, ck->ck_off, ck->ck_len); - cklen = ck->ck_len ? ck->ck_len - ck->ck_start + 1 : INT_MAX; + cklen = ck->ck_len ? ck->ck_len - ck->ck_start + 1U : UINT_MAX; cksum = e82545_iov_checksum(iov, iovcnt, ck->ck_start, cklen); *(uint16_t *)((uint8_t *)iov[0].iov_base + ck->ck_off) = ~cksum; } @@ -1084,17 +1085,19 @@ e82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail, struct ck_info ckinfo[2]; struct iovec *iov; union e1000_tx_udesc *dsc; - int desc, dtype, len, ntype, iovcnt, tcp, tso; - int mss, paylen, seg, tiovcnt, left, now, nleft, nnow, pv, pvoff; - unsigned hdrlen, vlen; + int desc, dtype, ntype, iovcnt, tcp, tso, paylen, seg, tiovcnt, pv; + unsigned hdrlen, vlen, pktlen, len, left, mss, now, nnow, nleft, pvoff; uint32_t tcpsum, tcpseq; uint16_t ipcs, tcpcs, ipid, ohead; + bool invalid; ckinfo[0].ck_valid = ckinfo[1].ck_valid = 0; iovcnt = 0; ntype = 0; tso = 0; + pktlen = 0; ohead = head; + invalid = false; /* iovb[0/1] may be used for writable copy of headers. */ iov = &iovb[2]; @@ -1144,17 +1147,23 @@ e82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail, len = (dtype == E1000_TXD_TYP_L) ? dsc->td.lower.flags.length : dsc->dd.lower.data & 0xFFFFF; - if (len > 0) { - /* Strip checksum supplied by guest. */ - if ((dsc->td.lower.data & E1000_TXD_CMD_EOP) != 0 && - (dsc->td.lower.data & E1000_TXD_CMD_IFCS) == 0) + /* Strip checksum supplied by guest. */ + if ((dsc->td.lower.data & E1000_TXD_CMD_EOP) != 0 && + (dsc->td.lower.data & E1000_TXD_CMD_IFCS) == 0) { + if (len <= 2) { + WPRINTF("final descriptor too short (%d) -- dropped", + len); + invalid = true; + } else len -= 2; - if (iovcnt < I82545_MAX_TXSEGS) { - iov[iovcnt].iov_base = paddr_guest2host( - sc->esc_ctx, dsc->td.buffer_addr, len); - iov[iovcnt].iov_len = len; - } + } + + if (len > 0 && iovcnt < I82545_MAX_TXSEGS) { + iov[iovcnt].iov_base = paddr_guest2host(sc->esc_ctx, + dsc->td.buffer_addr, len); + iov[iovcnt].iov_len = len; iovcnt++; + pktlen += len; } /* @@ -1202,6 +1211,9 @@ e82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail, } } + if (invalid) + goto done; + if (iovcnt > I82545_MAX_TXSEGS) { WPRINTF("tx too many descriptors (%d > %d) -- dropped", iovcnt, I82545_MAX_TXSEGS); @@ -1218,9 +1230,9 @@ e82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail, if (!tso) { /* Estimate required writable space for checksums. */ if (ckinfo[0].ck_valid) - hdrlen = MAX(hdrlen, ckinfo[0].ck_off + 2); + hdrlen = MAX(hdrlen, ckinfo[0].ck_off + 2U); if (ckinfo[1].ck_valid) - hdrlen = MAX(hdrlen, ckinfo[1].ck_off + 2); + hdrlen = MAX(hdrlen, ckinfo[1].ck_off + 2U); /* Round up writable space to the first vector. */ if (hdrlen != 0 && iov[0].iov_len > hdrlen && iov[0].iov_len < hdrlen + 100) @@ -1269,41 +1281,46 @@ e82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail, * TCP | flags | 13 | 1 * UDP | len | 4 | 4 */ - if (hdrlen < ckinfo[0].ck_start + 6 || - hdrlen < ckinfo[0].ck_off + 2) { + if (hdrlen < ckinfo[0].ck_start + 6U || + hdrlen < ckinfo[0].ck_off + 2U) { WPRINTF("TSO hdrlen too small for IP fields (%d) " "-- dropped", hdrlen); goto done; } if (sc->esc_txctx.cmd_and_length & E1000_TXD_CMD_TCP) { - if (hdrlen < ckinfo[1].ck_start + 14) { + if (hdrlen < ckinfo[1].ck_start + 14U) { WPRINTF("TSO hdrlen too small for TCP fields " "(%d) -- dropped", hdrlen); goto done; } } else { - if (hdrlen < ckinfo[1].ck_start + 8) { + if (hdrlen < ckinfo[1].ck_start + 8U) { WPRINTF("TSO hdrlen too small for UDP fields " "(%d) -- dropped", hdrlen); goto done; } } - if (ckinfo[1].ck_valid && hdrlen < ckinfo[1].ck_off + 2) { + if (ckinfo[1].ck_valid && hdrlen < ckinfo[1].ck_off + 2U) { WPRINTF("TSO hdrlen too small for TCP/UDP fields " "(%d) -- dropped", hdrlen); goto done; } } + if (pktlen < hdrlen + vlen) { + WPRINTF("packet too small for writable header"); + goto done; + } + /* Allocate, fill and prepend writable header vector. */ - if (hdrlen != 0) { + if (hdrlen + vlen != 0) { hdr = __builtin_alloca(hdrlen + vlen); hdr += vlen; for (left = hdrlen, hdrp = hdr; left > 0; left -= now, hdrp += now) { now = MIN(left, iov->iov_len); memcpy(hdrp, iov->iov_base, now); - iov->iov_base += now; + iov->iov_base = (uint8_t *)iov->iov_base + now; iov->iov_len -= now; if (iov->iov_len == 0) { iov++; @@ -1354,7 +1371,7 @@ e82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail, tcp = (sc->esc_txctx.cmd_and_length & E1000_TXD_CMD_TCP) != 0; mss = sc->esc_txctx.tcp_seg_setup.fields.mss; paylen = (sc->esc_txctx.cmd_and_length & 0x000fffff); - DPRINTF("tx %s segmentation offload %d+%d/%d bytes %d iovs", + DPRINTF("tx %s segmentation offload %d+%d/%u bytes %d iovs", tcp ? "TCP" : "UDP", hdrlen, paylen, mss, iovcnt); ipid = ntohs(*(uint16_t *)&hdr[ckinfo[0].ck_start + 4]); tcpseq = 0; @@ -1377,7 +1394,8 @@ e82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail, /* Include respective part of payload IOV. */ for (nleft = now; pv < iovcnt && nleft > 0; nleft -= nnow) { nnow = MIN(nleft, iov[pv].iov_len - pvoff); - tiov[tiovcnt].iov_base = iov[pv].iov_base + pvoff; + tiov[tiovcnt].iov_base = (uint8_t *)iov[pv].iov_base + + pvoff; tiov[tiovcnt++].iov_len = nnow; if (pvoff + nnow == iov[pv].iov_len) { pv++; @@ -1449,9 +1467,12 @@ e82545_tx_run(struct e82545_softc *sc) uint16_t head, rhead, tail, size; int lim, tdwb, sent; - head = sc->esc_TDH; - tail = sc->esc_TDT; size = sc->esc_TDLEN / 16; + if (size == 0) + return; + + head = sc->esc_TDH % size; + tail = sc->esc_TDT % size; DPRINTF("tx_run: head %x, rhead %x, tail %x", sc->esc_TDH, sc->esc_TDHr, sc->esc_TDT); @@ -1717,12 +1738,17 @@ e82545_write_register(struct e82545_softc *sc, uint32_t offset, uint32_t value) e82545_tx_update_tdba(sc); break; case E1000_TDH(0): - //assert(!sc->esc_tx_enabled); - /* XXX should only ever be zero ? Range check ? */ + if (sc->esc_tx_enabled) { + WPRINTF("ignoring write to TDH while transmit enabled"); + break; + } + if (value != 0) { + WPRINTF("ignoring non-zero value written to TDH"); + break; + } sc->esc_TDHr = sc->esc_TDH = value; break; case E1000_TDT(0): - /* XXX range check ? */ sc->esc_TDT = value; if (sc->esc_tx_enabled) e82545_tx_start(sc); @@ -2085,8 +2111,8 @@ e82545_read_register(struct e82545_softc *sc, uint32_t offset) } static void -e82545_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, - uint64_t offset, int size, uint64_t value) +e82545_write(struct pci_devinst *pi, int baridx, uint64_t offset, int size, + uint64_t value) { struct e82545_softc *sc; @@ -2135,8 +2161,7 @@ e82545_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, } static uint64_t -e82545_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, - uint64_t offset, int size) +e82545_read(struct pci_devinst *pi, int baridx, uint64_t offset, int size) { struct e82545_softc *sc; uint64_t retval; @@ -2279,7 +2304,7 @@ e82545_reset(struct e82545_softc *sc, int drvr) } static int -e82545_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) +e82545_init(struct pci_devinst *pi, nvlist_t *nvl) { char nstr[80]; struct e82545_softc *sc; @@ -2291,7 +2316,7 @@ e82545_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) pi->pi_arg = sc; sc->esc_pi = pi; - sc->esc_ctx = ctx; + sc->esc_ctx = pi->pi_vmctx; pthread_mutex_init(&sc->esc_mtx, NULL); pthread_cond_init(&sc->esc_rx_cond, NULL); @@ -2410,11 +2435,11 @@ e82545_snapshot(struct vm_snapshot_meta *meta) SNAPSHOT_VAR_OR_LEAVE(sc->esc_TADV, meta, ret, done); /* Has dependency on esc_TDLEN; reoreder of fields from struct. */ - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->esc_txdesc, sc->esc_TDLEN, - true, meta, ret, done); + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->esc_txdesc, + sc->esc_TDLEN, true, meta, ret, done); /* L2 frame acceptance */ - for (i = 0; i < nitems(sc->esc_uni); i++) { + for (i = 0; i < (int)nitems(sc->esc_uni); i++) { SNAPSHOT_VAR_OR_LEAVE(sc->esc_uni[i].eu_valid, meta, ret, done); SNAPSHOT_VAR_OR_LEAVE(sc->esc_uni[i].eu_addrsel, meta, ret, done); SNAPSHOT_VAR_OR_LEAVE(sc->esc_uni[i].eu_eth, meta, ret, done); @@ -2445,8 +2470,8 @@ e82545_snapshot(struct vm_snapshot_meta *meta) SNAPSHOT_VAR_OR_LEAVE(sc->esc_RXCSUM, meta, ret, done); /* Has dependency on esc_RDLEN; reoreder of fields from struct. */ - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->esc_rxdesc, sc->esc_TDLEN, - true, meta, ret, done); + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->esc_rxdesc, + sc->esc_TDLEN, true, meta, ret, done); /* IO Port register access */ SNAPSHOT_VAR_OR_LEAVE(sc->io_addr, meta, ret, done); @@ -2500,7 +2525,7 @@ done: } #endif -struct pci_devemu pci_de_e82545 = { +static const struct pci_devemu pci_de_e82545 = { .pe_emu = "e1000", .pe_init = e82545_init, .pe_legacy_config = netbe_legacy_config, @@ -2511,4 +2536,3 @@ struct pci_devemu pci_de_e82545 = { #endif }; PCI_EMUL_SET(pci_de_e82545); - |