aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/bhyve/pci_e82545.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bhyve/pci_e82545.c')
-rw-r--r--usr.sbin/bhyve/pci_e82545.c156
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);
-