aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--accel/tcg/translate-all.c37
-rwxr-xr-xconfigure116
-rw-r--r--docs/conf.py9
-rw-r--r--hw/arm/orangepi.c2
-rw-r--r--hw/arm/xlnx-zynqmp.c27
-rw-r--r--hw/misc/allwinner-h3-dramc.c4
-rw-r--r--hw/net/allwinner-sun8i-emac.c14
-rw-r--r--hw/net/allwinner_emac.c2
-rw-r--r--hw/net/cadence_gem.c8
-rw-r--r--hw/net/can/can_sja1000.c8
-rw-r--r--hw/net/can/can_sja1000.h2
-rw-r--r--hw/net/dp8393x.c8
-rw-r--r--hw/net/e1000.c2
-rw-r--r--hw/net/e1000e.c4
-rw-r--r--hw/net/e1000e_core.c2
-rw-r--r--hw/net/e1000e_core.h2
-rw-r--r--hw/net/ftgmac100.c6
-rw-r--r--hw/net/i82596.c66
-rw-r--r--hw/net/i82596.h2
-rw-r--r--hw/net/imx_fec.c2
-rw-r--r--hw/net/opencores_eth.c5
-rw-r--r--hw/net/rtl8139.c22
-rw-r--r--hw/net/smc91c111.c10
-rw-r--r--hw/net/spapr_llan.c4
-rw-r--r--hw/net/sungem.c6
-rw-r--r--hw/net/sunhme.c4
-rw-r--r--hw/net/tulip.c36
-rw-r--r--hw/net/virtio-net.c10
-rw-r--r--hw/net/xilinx_ethlite.c2
-rw-r--r--include/net/can_emu.h2
-rw-r--r--include/net/net.h2
-rw-r--r--linux-user/syscall.c140
-rw-r--r--net/can/can_socketcan.c4
-rw-r--r--net/colo-compare.c95
-rw-r--r--net/filter-buffer.c2
-rw-r--r--net/hub.c6
-rw-r--r--qemu-options.hx10
-rwxr-xr-xscripts/decodetree.py4
-rw-r--r--target/arm/helper.c5
-rw-r--r--target/mips/translate.c35
-rw-r--r--tcg/i386/tcg-target.inc.c10
-rw-r--r--tests/qtest/Makefile.include1
-rw-r--r--tests/qtest/tulip-test.c91
44 files changed, 570 insertions, 261 deletions
diff --git a/Makefile b/Makefile
index fc2808fb4b..84ef881600 100644
--- a/Makefile
+++ b/Makefile
@@ -795,7 +795,7 @@ rm -f $(MANUAL_BUILDDIR)/$1/objects.inv $(MANUAL_BUILDDIR)/$1/searchindex.js $(M
endef
distclean: clean
- rm -f config-host.mak config-host.h* config-host.ld $(DOCS)
+ rm -f config-host.mak config-host.h* $(DOCS)
rm -f tests/tcg/config-*.mak
rm -f config-all-devices.mak config-all-disas.mak config.status
rm -f $(SUBDIR_DEVICES_MAK)
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 78914154bf..9924e66d1f 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1043,47 +1043,20 @@ static inline void *alloc_code_gen_buffer(void)
{
int prot = PROT_WRITE | PROT_READ | PROT_EXEC;
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
- uintptr_t start = 0;
size_t size = tcg_ctx->code_gen_buffer_size;
void *buf;
- /* Constrain the position of the buffer based on the host cpu.
- Note that these addresses are chosen in concert with the
- addresses assigned in the relevant linker script file. */
-# if defined(__PIE__) || defined(__PIC__)
- /* Don't bother setting a preferred location if we're building
- a position-independent executable. We're more likely to get
- an address near the main executable if we let the kernel
- choose the address. */
-# elif defined(__x86_64__) && defined(MAP_32BIT)
- /* Force the memory down into low memory with the executable.
- Leave the choice of exact location with the kernel. */
- flags |= MAP_32BIT;
- /* Cannot expect to map more than 800MB in low memory. */
- if (size > 800u * 1024 * 1024) {
- tcg_ctx->code_gen_buffer_size = size = 800u * 1024 * 1024;
- }
-# elif defined(__sparc__)
- start = 0x40000000ul;
-# elif defined(__s390x__)
- start = 0x90000000ul;
-# elif defined(__mips__)
-# if _MIPS_SIM == _ABI64
- start = 0x128000000ul;
-# else
- start = 0x08000000ul;
-# endif
-# endif
-
- buf = mmap((void *)start, size, prot, flags, -1, 0);
+ buf = mmap(NULL, size, prot, flags, -1, 0);
if (buf == MAP_FAILED) {
return NULL;
}
#ifdef __mips__
if (cross_256mb(buf, size)) {
- /* Try again, with the original still mapped, to avoid re-acquiring
- that 256mb crossing. This time don't specify an address. */
+ /*
+ * Try again, with the original still mapped, to avoid re-acquiring
+ * the same 256mb crossing.
+ */
size_t size2;
void *buf2 = mmap(NULL, size, prot, flags, -1, 0);
switch ((int)(buf2 != MAP_FAILED)) {
diff --git a/configure b/configure
index e225a1e3ff..22870f3867 100755
--- a/configure
+++ b/configure
@@ -1067,7 +1067,6 @@ for opt do
;;
--static)
static="yes"
- QEMU_LDFLAGS="-static $QEMU_LDFLAGS"
QEMU_PKG_CONFIG_FLAGS="--static $QEMU_PKG_CONFIG_FLAGS"
;;
--mandir=*) mandir="$optarg"
@@ -2089,11 +2088,6 @@ if test "$static" = "yes" ; then
if test "$modules" = "yes" ; then
error_exit "static and modules are mutually incompatible"
fi
- if test "$pie" = "yes" ; then
- error_exit "static and pie are mutually incompatible"
- else
- pie="no"
- fi
fi
# Unconditional check for compiler __thread support
@@ -2107,51 +2101,52 @@ if ! compile_prog "-Werror" "" ; then
"Thread-Local Storage (TLS). Please upgrade to a version that does."
fi
-if test "$pie" = ""; then
- case "$cpu-$targetos" in
- i386-Linux|x86_64-Linux|x32-Linux|i386-OpenBSD|x86_64-OpenBSD)
- ;;
- *)
- pie="no"
- ;;
- esac
-fi
-
-if test "$pie" != "no" ; then
- cat > $TMPC << EOF
+cat > $TMPC << EOF
#ifdef __linux__
# define THREAD __thread
#else
# define THREAD
#endif
-
static THREAD int tls_var;
-
int main(void) { return tls_var; }
-
EOF
- # check we support --no-pie first...
- if compile_prog "-Werror -fno-pie" "-no-pie"; then
- CFLAGS_NOPIE="-fno-pie"
- LDFLAGS_NOPIE="-nopie"
- fi
- if compile_prog "-fPIE -DPIE" "-pie"; then
+# Check we support --no-pie first; we will need this for building ROMs.
+if compile_prog "-Werror -fno-pie" "-no-pie"; then
+ CFLAGS_NOPIE="-fno-pie"
+ LDFLAGS_NOPIE="-no-pie"
+fi
+
+if test "$static" = "yes"; then
+ if test "$pie" != "no" && compile_prog "-fPIE -DPIE" "-static-pie"; then
QEMU_CFLAGS="-fPIE -DPIE $QEMU_CFLAGS"
- QEMU_LDFLAGS="-pie $QEMU_LDFLAGS"
+ QEMU_LDFLAGS="-static-pie $QEMU_LDFLAGS"
pie="yes"
- if compile_prog "" "-Wl,-z,relro -Wl,-z,now" ; then
- QEMU_LDFLAGS="-Wl,-z,relro -Wl,-z,now $QEMU_LDFLAGS"
- fi
+ elif test "$pie" = "yes"; then
+ error_exit "-static-pie not available due to missing toolchain support"
else
- if test "$pie" = "yes"; then
- error_exit "PIE not available due to missing toolchain support"
- else
- echo "Disabling PIE due to missing toolchain support"
- pie="no"
- fi
+ QEMU_LDFLAGS="-static $QEMU_LDFLAGS"
+ pie="no"
fi
+elif test "$pie" = "no"; then
+ QEMU_CFLAGS="$CFLAGS_NOPIE $QEMU_CFLAGS"
+ QEMU_LDFLAGS="$LDFLAGS_NOPIE $QEMU_LDFLAGS"
+elif compile_prog "-fPIE -DPIE" "-pie"; then
+ QEMU_CFLAGS="-fPIE -DPIE $QEMU_CFLAGS"
+ QEMU_LDFLAGS="-pie $QEMU_LDFLAGS"
+ pie="yes"
+elif test "$pie" = "yes"; then
+ error_exit "PIE not available due to missing toolchain support"
+else
+ echo "Disabling PIE due to missing toolchain support"
+ pie="no"
+fi
+
+# Detect support for PT_GNU_RELRO + DT_BIND_NOW.
+# The combination is known as "full relro", because .got.plt is read-only too.
+if compile_prog "" "-Wl,-z,relro -Wl,-z,now" ; then
+ QEMU_LDFLAGS="-Wl,-z,relro -Wl,-z,now $QEMU_LDFLAGS"
fi
##########################################
@@ -6498,49 +6493,6 @@ if test "$cpu" = "s390x" ; then
fi
fi
-# Probe for the need for relocating the user-only binary.
-if ( [ "$linux_user" = yes ] || [ "$bsd_user" = yes ] ) && [ "$pie" = no ]; then
- textseg_addr=
- case "$cpu" in
- arm | i386 | ppc* | s390* | sparc* | x86_64 | x32)
- # ??? Rationale for choosing this address
- textseg_addr=0x60000000
- ;;
- mips)
- # A 256M aligned address, high in the address space, with enough
- # room for the code_gen_buffer above it before the stack.
- textseg_addr=0x60000000
- ;;
- esac
- if [ -n "$textseg_addr" ]; then
- cat > $TMPC <<EOF
- int main(void) { return 0; }
-EOF
- textseg_ldflags="-Wl,-Ttext-segment=$textseg_addr"
- if ! compile_prog "" "$textseg_ldflags"; then
- # In case ld does not support -Ttext-segment, edit the default linker
- # script via sed to set the .text start addr. This is needed on FreeBSD
- # at least.
- if ! $ld --verbose >/dev/null 2>&1; then
- error_exit \
- "We need to link the QEMU user mode binaries at a" \
- "specific text address. Unfortunately your linker" \
- "doesn't support either the -Ttext-segment option or" \
- "printing the default linker script with --verbose." \
- "If you don't want the user mode binaries, pass the" \
- "--disable-user option to configure."
- fi
-
- $ld --verbose | sed \
- -e '1,/==================================================/d' \
- -e '/==================================================/,$d' \
- -e "s/[.] = [0-9a-fx]* [+] SIZEOF_HEADERS/. = $textseg_addr + SIZEOF_HEADERS/" \
- -e "s/__executable_start = [0-9a-fx]*/__executable_start = $textseg_addr/" > config-host.ld
- textseg_ldflags="-Wl,-T../config-host.ld"
- fi
- fi
-fi
-
# Check that the C++ compiler exists and works with the C compiler.
# All the QEMU_CXXFLAGS are based on QEMU_CFLAGS. Keep this at the end to don't miss any other that could be added.
if has $cxx; then
@@ -8175,10 +8127,6 @@ if test "$gprof" = "yes" ; then
fi
fi
-if test "$target_linux_user" = "yes" || test "$target_bsd_user" = "yes" ; then
- ldflags="$ldflags $textseg_ldflags"
-fi
-
# Newer kernels on s390 check for an S390_PGSTE program header and
# enable the pgste page table extensions in that case. This makes
# the vm.allocate_pgste sysctl unnecessary. We enable this program
diff --git a/docs/conf.py b/docs/conf.py
index af55f506d5..7768611e89 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -29,14 +29,15 @@
import os
import sys
import sphinx
-from sphinx.errors import VersionRequirementError
+from sphinx.errors import ConfigError
# Make Sphinx fail cleanly if using an old Python, rather than obscurely
# failing because some code in one of our extensions doesn't work there.
-# Unfortunately this doesn't display very neatly (there's an unavoidable
-# Python backtrace) but at least the information gets printed...
+# In newer versions of Sphinx this will display nicely; in older versions
+# Sphinx will also produce a Python backtrace but at least the information
+# gets printed...
if sys.version_info < (3,5):
- raise VersionRequirementError(
+ raise ConfigError(
"QEMU requires a Sphinx that uses Python 3.5 or better\n")
# The per-manual conf.py will set qemu_docdir for a single-manual build;
diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
index 181f5badab..a9f64c5680 100644
--- a/hw/arm/orangepi.c
+++ b/hw/arm/orangepi.c
@@ -104,7 +104,7 @@ static void orangepi_init(MachineState *machine)
machine->ram);
/* Load target kernel or start using BootROM */
- if (!machine->kernel_filename && blk_is_available(blk)) {
+ if (!machine->kernel_filename && blk && blk_is_available(blk)) {
/* Use Boot ROM to copy data from SD card to SRAM */
allwinner_h3_bootrom_setup(h3, blk);
}
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 49f1c8d0de..b84d153d56 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -520,7 +520,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, gic_spi[SATA_INTR]);
for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
- char *bus_name = g_strdup_printf("sd-bus%d", i);
+ char *bus_name;
SysBusDevice *sbd = SYS_BUS_DEVICE(&s->sdhci[i]);
Object *sdhci = OBJECT(&s->sdhci[i]);
@@ -530,8 +530,20 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
* - eMMC Specification Version 4.51
*/
object_property_set_uint(sdhci, 3, "sd-spec-version", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
object_property_set_uint(sdhci, SDHCI_CAPABILITIES, "capareg", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
object_property_set_uint(sdhci, UHS_I, "uhs", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
object_property_set_bool(sdhci, true, "realized", &err);
if (err) {
error_propagate(errp, err);
@@ -541,6 +553,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(sbd, 0, gic_spi[sdhci_intr[i]]);
/* Alias controller SD bus to the SoC itself */
+ bus_name = g_strdup_printf("sd-bus%d", i);
object_property_add_alias(OBJECT(s), bus_name, sdhci, "sd-bus",
&error_abort);
g_free(bus_name);
@@ -550,6 +563,10 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
gchar *bus_name;
object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_addr[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
@@ -564,6 +581,10 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
}
object_property_set_bool(OBJECT(&s->qspi), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 0, QSPI_ADDR);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 1, LQSPI_ADDR);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->qspi), 0, gic_spi[QSPI_IRQ]);
@@ -618,6 +639,10 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
for (i = 0; i < XLNX_ZYNQMP_NUM_GDMA_CH; i++) {
object_property_set_uint(OBJECT(&s->gdma[i]), 128, "bus-width", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
object_property_set_bool(OBJECT(&s->gdma[i]), true, "realized", &err);
if (err) {
error_propagate(errp, err);
diff --git a/hw/misc/allwinner-h3-dramc.c b/hw/misc/allwinner-h3-dramc.c
index 2b5260260e..1d37cf422c 100644
--- a/hw/misc/allwinner-h3-dramc.c
+++ b/hw/misc/allwinner-h3-dramc.c
@@ -85,8 +85,8 @@ static void allwinner_h3_dramc_map_rows(AwH3DramCtlState *s, uint8_t row_bits,
} else if (row_bits_actual) {
/* Row bits not matching ram_size, install the rows mirror */
- hwaddr row_mirror = s->ram_addr + ((1 << (row_bits_actual +
- bank_bits)) * page_size);
+ hwaddr row_mirror = s->ram_addr + ((1ULL << (row_bits_actual +
+ bank_bits)) * page_size);
memory_region_set_enabled(&s->row_mirror_alias, true);
memory_region_set_address(&s->row_mirror_alias, row_mirror);
diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c
index 3fc5e34640..28637ff4c1 100644
--- a/hw/net/allwinner-sun8i-emac.c
+++ b/hw/net/allwinner-sun8i-emac.c
@@ -395,7 +395,7 @@ static void allwinner_sun8i_emac_flush_desc(FrameDescriptor *desc,
cpu_physical_memory_write(phys_addr, desc, sizeof(*desc));
}
-static int allwinner_sun8i_emac_can_receive(NetClientState *nc)
+static bool allwinner_sun8i_emac_can_receive(NetClientState *nc)
{
AwSun8iEmacState *s = qemu_get_nic_opaque(nc);
FrameDescriptor desc;
@@ -611,10 +611,10 @@ static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset,
value = s->mii_data;
break;
case REG_ADDR_HIGH: /* MAC Address High */
- value = *(((uint32_t *) (s->conf.macaddr.a)) + 1);
+ value = lduw_le_p(s->conf.macaddr.a + 4);
break;
case REG_ADDR_LOW: /* MAC Address Low */
- value = *(uint32_t *) (s->conf.macaddr.a);
+ value = ldl_le_p(s->conf.macaddr.a);
break;
case REG_TX_DMA_STA: /* Transmit DMA Status */
break;
@@ -728,14 +728,10 @@ static void allwinner_sun8i_emac_write(void *opaque, hwaddr offset,
s->mii_data = value;
break;
case REG_ADDR_HIGH: /* MAC Address High */
- s->conf.macaddr.a[4] = (value & 0xff);
- s->conf.macaddr.a[5] = (value & 0xff00) >> 8;
+ stw_le_p(s->conf.macaddr.a + 4, value);
break;
case REG_ADDR_LOW: /* MAC Address Low */
- s->conf.macaddr.a[0] = (value & 0xff);
- s->conf.macaddr.a[1] = (value & 0xff00) >> 8;
- s->conf.macaddr.a[2] = (value & 0xff0000) >> 16;
- s->conf.macaddr.a[3] = (value & 0xff000000) >> 24;
+ stl_le_p(s->conf.macaddr.a, value);
break;
case REG_TX_DMA_STA: /* Transmit DMA Status */
case REG_TX_CUR_DESC: /* Transmit Current Descriptor */
diff --git a/hw/net/allwinner_emac.c b/hw/net/allwinner_emac.c
index e9bbff8710..ddddf35c45 100644
--- a/hw/net/allwinner_emac.c
+++ b/hw/net/allwinner_emac.c
@@ -178,7 +178,7 @@ static uint32_t fifo8_pop_word(Fifo8 *fifo)
return ret;
}
-static int aw_emac_can_receive(NetClientState *nc)
+static bool aw_emac_can_receive(NetClientState *nc)
{
AwEmacState *s = qemu_get_nic_opaque(nc);
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 6340c1eaf8..51ec5a072d 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -505,7 +505,7 @@ static void phy_update_link(CadenceGEMState *s)
}
}
-static int gem_can_receive(NetClientState *nc)
+static bool gem_can_receive(NetClientState *nc)
{
CadenceGEMState *s;
int i;
@@ -518,7 +518,7 @@ static int gem_can_receive(NetClientState *nc)
s->can_rx_state = 1;
DB_PRINT("can't receive - no enable\n");
}
- return 0;
+ return false;
}
for (i = 0; i < s->num_priority_queues; i++) {
@@ -532,14 +532,14 @@ static int gem_can_receive(NetClientState *nc)
s->can_rx_state = 2;
DB_PRINT("can't receive - all the buffer descriptors are busy\n");
}
- return 0;
+ return false;
}
if (s->can_rx_state != 0) {
s->can_rx_state = 0;
DB_PRINT("can receive\n");
}
- return 1;
+ return true;
}
/*
diff --git a/hw/net/can/can_sja1000.c b/hw/net/can/can_sja1000.c
index 39c78faf9b..ea915a023a 100644
--- a/hw/net/can/can_sja1000.c
+++ b/hw/net/can/can_sja1000.c
@@ -733,21 +733,21 @@ uint64_t can_sja_mem_read(CanSJA1000State *s, hwaddr addr, unsigned size)
return temp;
}
-int can_sja_can_receive(CanBusClientState *client)
+bool can_sja_can_receive(CanBusClientState *client)
{
CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client);
if (s->clock & 0x80) { /* PeliCAN Mode */
if (s->mode & 0x01) { /* reset mode. */
- return 0;
+ return false;
}
} else { /* BasicCAN mode */
if (s->control & 0x01) {
- return 0;
+ return false;
}
}
- return 1; /* always return 1, when operation mode */
+ return true; /* always return true, when operation mode */
}
ssize_t can_sja_receive(CanBusClientState *client, const qemu_can_frame *frames,
diff --git a/hw/net/can/can_sja1000.h b/hw/net/can/can_sja1000.h
index 220a622087..7ca9cd681e 100644
--- a/hw/net/can/can_sja1000.h
+++ b/hw/net/can/can_sja1000.h
@@ -137,7 +137,7 @@ void can_sja_disconnect(CanSJA1000State *s);
int can_sja_init(CanSJA1000State *s, qemu_irq irq);
-int can_sja_can_receive(CanBusClientState *client);
+bool can_sja_can_receive(CanBusClientState *client);
ssize_t can_sja_receive(CanBusClientState *client,
const qemu_can_frame *frames, size_t frames_cnt);
diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index 1563c11b9e..c54db0d62d 100644
--- a/hw/net/dp8393x.c
+++ b/hw/net/dp8393x.c
@@ -414,7 +414,7 @@ static void dp8393x_do_stop_timer(dp8393xState *s)
dp8393x_update_wt_regs(s);
}
-static int dp8393x_can_receive(NetClientState *nc);
+static bool dp8393x_can_receive(NetClientState *nc);
static void dp8393x_do_receiver_enable(dp8393xState *s)
{
@@ -718,13 +718,11 @@ static void dp8393x_watchdog(void *opaque)
dp8393x_update_irq(s);
}
-static int dp8393x_can_receive(NetClientState *nc)
+static bool dp8393x_can_receive(NetClientState *nc)
{
dp8393xState *s = qemu_get_nic_opaque(nc);
- if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN))
- return 0;
- return 1;
+ return !!(s->regs[SONIC_CR] & SONIC_CR_RXEN);
}
static int dp8393x_receive_filter(dp8393xState *s, const uint8_t * buf,
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 9233248c9a..2a69eee63f 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -845,7 +845,7 @@ static bool e1000_has_rxbufs(E1000State *s, size_t total_size)
return total_size <= bufs * s->rxbuf_size;
}
-static int
+static bool
e1000_can_receive(NetClientState *nc)
{
E1000State *s = qemu_get_nic_opaque(nc);
diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c
index a91dbdca3c..79ba158d41 100644
--- a/hw/net/e1000e.c
+++ b/hw/net/e1000e.c
@@ -199,7 +199,7 @@ static const MemoryRegionOps io_ops = {
},
};
-static int
+static bool
e1000e_nc_can_receive(NetClientState *nc)
{
E1000EState *s = qemu_get_nic_opaque(nc);
@@ -328,7 +328,7 @@ e1000e_init_net_peer(E1000EState *s, PCIDevice *pci_dev, uint8_t *macaddr)
s->nic = qemu_new_nic(&net_e1000e_info, &s->conf,
object_get_typename(OBJECT(s)), dev->id, s);
- s->core.max_queue_num = s->conf.peers.queues - 1;
+ s->core.max_queue_num = s->conf.peers.queues ? s->conf.peers.queues - 1 : 0;
trace_e1000e_mac_set_permanent(MAC_ARG(macaddr));
memcpy(s->core.permanent_mac, macaddr, sizeof(s->core.permanent_mac));
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
index df957e0c1a..d5676871fa 100644
--- a/hw/net/e1000e_core.c
+++ b/hw/net/e1000e_core.c
@@ -967,7 +967,7 @@ e1000e_start_recv(E1000ECore *core)
}
}
-int
+bool
e1000e_can_receive(E1000ECore *core)
{
int i;
diff --git a/hw/net/e1000e_core.h b/hw/net/e1000e_core.h
index 49abb136dd..aee32f7e48 100644
--- a/hw/net/e1000e_core.h
+++ b/hw/net/e1000e_core.h
@@ -143,7 +143,7 @@ e1000e_core_set_link_status(E1000ECore *core);
void
e1000e_core_pci_uninit(E1000ECore *core);
-int
+bool
e1000e_can_receive(E1000ECore *core);
ssize_t
diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c
index 2f92b65d4e..041ed21017 100644
--- a/hw/net/ftgmac100.c
+++ b/hw/net/ftgmac100.c
@@ -562,18 +562,18 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
ftgmac100_update_irq(s);
}
-static int ftgmac100_can_receive(NetClientState *nc)
+static bool ftgmac100_can_receive(NetClientState *nc)
{
FTGMAC100State *s = FTGMAC100(qemu_get_nic_opaque(nc));
FTGMAC100Desc bd;
if ((s->maccr & (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN))
!= (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN)) {
- return 0;
+ return false;
}
if (ftgmac100_read_bd(&bd, s->rx_descriptor)) {
- return 0;
+ return false;
}
return !(bd.des0 & FTGMAC100_RXDES0_RXPKT_RDY);
}
diff --git a/hw/net/i82596.c b/hw/net/i82596.c
index fe9f2390a9..055c3a1470 100644
--- a/hw/net/i82596.c
+++ b/hw/net/i82596.c
@@ -43,6 +43,9 @@
#define SCB_STATUS_CNA 0x2000 /* CU left active state */
#define SCB_STATUS_RNR 0x1000 /* RU left active state */
+#define SCB_COMMAND_ACK_MASK \
+ (SCB_STATUS_CX | SCB_STATUS_FR | SCB_STATUS_CNA | SCB_STATUS_RNR)
+
#define CU_IDLE 0
#define CU_SUSPENDED 1
#define CU_ACTIVE 2
@@ -348,14 +351,7 @@ static void examine_scb(I82596State *s)
/* and clear the scb command word */
set_uint16(s->scb + 2, 0);
- if (command & BIT(31)) /* ACK-CX */
- s->scb_status &= ~SCB_STATUS_CX;
- if (command & BIT(30)) /*ACK-FR */
- s->scb_status &= ~SCB_STATUS_FR;
- if (command & BIT(29)) /*ACK-CNA */
- s->scb_status &= ~SCB_STATUS_CNA;
- if (command & BIT(28)) /*ACK-RNR */
- s->scb_status &= ~SCB_STATUS_RNR;
+ s->scb_status &= ~(command & SCB_COMMAND_ACK_MASK);
switch (cuc) {
case 0: /* no change */
@@ -474,23 +470,23 @@ void i82596_h_reset(void *opaque)
i82596_s_reset(s);
}
-int i82596_can_receive(NetClientState *nc)
+bool i82596_can_receive(NetClientState *nc)
{
I82596State *s = qemu_get_nic_opaque(nc);
if (s->rx_status == RX_SUSPENDED) {
- return 0;
+ return false;
}
if (!s->lnkst) {
- return 0;
+ return false;
}
if (USE_TIMER && !timer_pending(s->flush_queue_timer)) {
- return 1;
+ return true;
}
- return 1;
+ return true;
}
#define MIN_BUF_SIZE 60
@@ -501,7 +497,8 @@ ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t sz)
uint32_t rfd_p;
uint32_t rbd;
uint16_t is_broadcast = 0;
- size_t len = sz;
+ size_t len = sz; /* length of data for guest (including CRC) */
+ size_t bufsz = sz; /* length of data in buf */
uint32_t crc;
uint8_t *crc_ptr;
uint8_t buf1[MIN_BUF_SIZE + VLAN_HLEN];
@@ -595,6 +592,7 @@ ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t sz)
if (len < MIN_BUF_SIZE) {
len = MIN_BUF_SIZE;
}
+ bufsz = len;
}
/* Calculate the ethernet checksum (4 bytes) */
@@ -627,6 +625,7 @@ ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t sz)
while (len) {
uint16_t buffer_size, num;
uint32_t rba;
+ size_t bufcount, crccount;
/* printf("Receive: rbd is %08x\n", rbd); */
buffer_size = get_uint16(rbd + 12);
@@ -639,14 +638,37 @@ ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t sz)
}
rba = get_uint32(rbd + 8);
/* printf("rba is 0x%x\n", rba); */
- address_space_write(&address_space_memory, rba,
- MEMTXATTRS_UNSPECIFIED, buf, num);
- rba += num;
- buf += num;
- len -= num;
- if (len == 0) { /* copy crc */
- address_space_write(&address_space_memory, rba - 4,
- MEMTXATTRS_UNSPECIFIED, crc_ptr, 4);
+ /*
+ * Calculate how many bytes we want from buf[] and how many
+ * from the CRC.
+ */
+ if ((len - num) >= 4) {
+ /* The whole guest buffer, we haven't hit the CRC yet */
+ bufcount = num;
+ } else {
+ /* All that's left of buf[] */
+ bufcount = len - 4;
+ }
+ crccount = num - bufcount;
+
+ if (bufcount > 0) {
+ /* Still some of the actual data buffer to transfer */
+ assert(bufsz >= bufcount);
+ bufsz -= bufcount;
+ address_space_write(&address_space_memory, rba,
+ MEMTXATTRS_UNSPECIFIED, buf, bufcount);
+ rba += bufcount;
+ buf += bufcount;
+ len -= bufcount;
+ }
+
+ /* Write as much of the CRC as fits */
+ if (crccount > 0) {
+ address_space_write(&address_space_memory, rba,
+ MEMTXATTRS_UNSPECIFIED, crc_ptr, crccount);
+ rba += crccount;
+ crc_ptr += crccount;
+ len -= crccount;
}
num |= 0x4000; /* set F BIT */
diff --git a/hw/net/i82596.h b/hw/net/i82596.h
index 1238ac11f8..f0bbe810eb 100644
--- a/hw/net/i82596.h
+++ b/hw/net/i82596.h
@@ -48,7 +48,7 @@ void i82596_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
uint32_t i82596_ioport_readl(void *opaque, uint32_t addr);
uint32_t i82596_bcr_readw(I82596State *s, uint32_t rap);
ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t size_);
-int i82596_can_receive(NetClientState *nc);
+bool i82596_can_receive(NetClientState *nc);
void i82596_set_link_status(NetClientState *nc);
void i82596_common_init(DeviceState *dev, I82596State *s, NetClientInfo *info);
extern const VMStateDescription vmstate_i82596;
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
index 5c145a8197..a35c33683e 100644
--- a/hw/net/imx_fec.c
+++ b/hw/net/imx_fec.c
@@ -1049,7 +1049,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value,
imx_eth_update(s);
}
-static int imx_eth_can_receive(NetClientState *nc)
+static bool imx_eth_can_receive(NetClientState *nc)
{
IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c
index 6b338c2f29..2ba0dc8c2f 100644
--- a/hw/net/opencores_eth.c
+++ b/hw/net/opencores_eth.c
@@ -349,12 +349,11 @@ static void open_eth_reset(void *opaque)
open_eth_set_link_status(qemu_get_queue(s->nic));
}
-static int open_eth_can_receive(NetClientState *nc)
+static bool open_eth_can_receive(NetClientState *nc)
{
OpenEthState *s = qemu_get_nic_opaque(nc);
- return GET_REGBIT(s, MODER, RXEN) &&
- (s->regs[TX_BD_NUM] < 0x80);
+ return GET_REGBIT(s, MODER, RXEN) && (s->regs[TX_BD_NUM] < 0x80);
}
static ssize_t open_eth_receive(NetClientState *nc,
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index ae4739bc09..70aca7ec26 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -793,26 +793,28 @@ static bool rtl8139_cp_rx_valid(RTL8139State *s)
return !(s->RxRingAddrLO == 0 && s->RxRingAddrHI == 0);
}
-static int rtl8139_can_receive(NetClientState *nc)
+static bool rtl8139_can_receive(NetClientState *nc)
{
RTL8139State *s = qemu_get_nic_opaque(nc);
int avail;
/* Receive (drop) packets if card is disabled. */
- if (!s->clock_enabled)
- return 1;
- if (!rtl8139_receiver_enabled(s))
- return 1;
+ if (!s->clock_enabled) {
+ return true;
+ }
+ if (!rtl8139_receiver_enabled(s)) {
+ return true;
+ }
if (rtl8139_cp_receiver_enabled(s) && rtl8139_cp_rx_valid(s)) {
/* ??? Flow control not implemented in c+ mode.
This is a hack to work around slirp deficiencies anyway. */
- return 1;
- } else {
- avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
- s->RxBufferSize);
- return (avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow));
+ return true;
}
+
+ avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
+ s->RxBufferSize);
+ return avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow);
}
static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt)
diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c
index e9eb6f6c05..b3240b9335 100644
--- a/hw/net/smc91c111.c
+++ b/hw/net/smc91c111.c
@@ -130,16 +130,16 @@ static void smc91c111_update(smc91c111_state *s)
qemu_set_irq(s->irq, level);
}
-static int smc91c111_can_receive(smc91c111_state *s)
+static bool smc91c111_can_receive(smc91c111_state *s)
{
if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) {
- return 1;
+ return true;
}
if (s->allocated == (1 << NUM_PACKETS) - 1 ||
s->rx_fifo_len == NUM_PACKETS) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static inline void smc91c111_flush_queued_packets(smc91c111_state *s)
@@ -667,7 +667,7 @@ static void smc91c111_writefn(void *opaque, hwaddr addr,
}
}
-static int smc91c111_can_receive_nc(NetClientState *nc)
+static bool smc91c111_can_receive_nc(NetClientState *nc)
{
smc91c111_state *s = qemu_get_nic_opaque(nc);
diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c
index 80f5a1dd37..a2377025a7 100644
--- a/hw/net/spapr_llan.c
+++ b/hw/net/spapr_llan.c
@@ -110,11 +110,11 @@ typedef struct SpaprVioVlan {
RxBufPool *rx_pool[RX_MAX_POOLS]; /* Receive buffer descriptor pools */
} SpaprVioVlan;
-static int spapr_vlan_can_receive(NetClientState *nc)
+static bool spapr_vlan_can_receive(NetClientState *nc)
{
SpaprVioVlan *dev = qemu_get_nic_opaque(nc);
- return (dev->isopen && dev->rx_bufs > 0);
+ return dev->isopen && dev->rx_bufs > 0;
}
/**
diff --git a/hw/net/sungem.c b/hw/net/sungem.c
index 89da51f7f6..b01197d952 100644
--- a/hw/net/sungem.c
+++ b/hw/net/sungem.c
@@ -433,7 +433,7 @@ static bool sungem_rx_full(SunGEMState *s, uint32_t kick, uint32_t done)
return kick == ((done + 1) & s->rx_mask);
}
-static int sungem_can_receive(NetClientState *nc)
+static bool sungem_can_receive(NetClientState *nc)
{
SunGEMState *s = qemu_get_nic_opaque(nc);
uint32_t kick, done, rxdma_cfg, rxmac_cfg;
@@ -445,11 +445,11 @@ static int sungem_can_receive(NetClientState *nc)
/* If MAC disabled, can't receive */
if ((rxmac_cfg & MAC_RXCFG_ENAB) == 0) {
trace_sungem_rx_mac_disabled();
- return 0;
+ return false;
}
if ((rxdma_cfg & RXDMA_CFG_ENABLE) == 0) {
trace_sungem_rx_txdma_disabled();
- return 0;
+ return false;
}
/* Check RX availability */
diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c
index 8863601f6c..9c38583180 100644
--- a/hw/net/sunhme.c
+++ b/hw/net/sunhme.c
@@ -657,11 +657,11 @@ static void sunhme_transmit(SunHMEState *s)
sunhme_update_irq(s);
}
-static int sunhme_can_receive(NetClientState *nc)
+static bool sunhme_can_receive(NetClientState *nc)
{
SunHMEState *s = qemu_get_nic_opaque(nc);
- return s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_ENABLE;
+ return !!(s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_ENABLE);
}
static void sunhme_link_status_changed(NetClientState *nc)
diff --git a/hw/net/tulip.c b/hw/net/tulip.c
index cfac2719d3..1295f51d07 100644
--- a/hw/net/tulip.c
+++ b/hw/net/tulip.c
@@ -170,6 +170,10 @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc)
} else {
len = s->rx_frame_len;
}
+
+ if (s->rx_frame_len + len > sizeof(s->rx_frame)) {
+ return;
+ }
pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame +
(s->rx_frame_size - s->rx_frame_len), len);
s->rx_frame_len -= len;
@@ -181,6 +185,10 @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc)
} else {
len = s->rx_frame_len;
}
+
+ if (s->rx_frame_len + len > sizeof(s->rx_frame)) {
+ return;
+ }
pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame +
(s->rx_frame_size - s->rx_frame_len), len);
s->rx_frame_len -= len;
@@ -227,7 +235,8 @@ static ssize_t tulip_receive(TULIPState *s, const uint8_t *buf, size_t size)
trace_tulip_receive(buf, size);
- if (size < 14 || size > 2048 || s->rx_frame_len || tulip_rx_stopped(s)) {
+ if (size < 14 || size > sizeof(s->rx_frame) - 4
+ || s->rx_frame_len || tulip_rx_stopped(s)) {
return 0;
}
@@ -275,7 +284,6 @@ static ssize_t tulip_receive_nc(NetClientState *nc,
return tulip_receive(qemu_get_nic_opaque(nc), buf, size);
}
-
static NetClientInfo net_tulip_info = {
.type = NET_CLIENT_DRIVER_NIC,
.size = sizeof(NICState),
@@ -558,7 +566,7 @@ static void tulip_tx(TULIPState *s, struct tulip_descriptor *desc)
if ((s->csr[6] >> CSR6_OM_SHIFT) & CSR6_OM_MASK) {
/* Internal or external Loopback */
tulip_receive(s, s->tx_frame, s->tx_frame_len);
- } else {
+ } else if (s->tx_frame_len <= sizeof(s->tx_frame)) {
qemu_send_packet(qemu_get_queue(s->nic),
s->tx_frame, s->tx_frame_len);
}
@@ -570,23 +578,31 @@ static void tulip_tx(TULIPState *s, struct tulip_descriptor *desc)
}
}
-static void tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc)
+static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc)
{
int len1 = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK;
int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) & TDES1_BUF2_SIZE_MASK;
+ if (s->tx_frame_len + len1 > sizeof(s->tx_frame)) {
+ return -1;
+ }
if (len1) {
pci_dma_read(&s->dev, desc->buf_addr1,
s->tx_frame + s->tx_frame_len, len1);
s->tx_frame_len += len1;
}
+ if (s->tx_frame_len + len2 > sizeof(s->tx_frame)) {
+ return -1;
+ }
if (len2) {
pci_dma_read(&s->dev, desc->buf_addr2,
s->tx_frame + s->tx_frame_len, len2);
s->tx_frame_len += len2;
}
desc->status = (len1 + len2) ? 0 : 0x7fffffff;
+
+ return 0;
}
static void tulip_setup_filter_addr(TULIPState *s, uint8_t *buf, int n)
@@ -651,13 +667,15 @@ static uint32_t tulip_ts(TULIPState *s)
static void tulip_xmit_list_update(TULIPState *s)
{
+#define TULIP_DESC_MAX 128
+ uint8_t i = 0;
struct tulip_descriptor desc;
if (tulip_ts(s) != CSR5_TS_SUSPENDED) {
return;
}
- for (;;) {
+ for (i = 0; i < TULIP_DESC_MAX; i++) {
tulip_desc_read(s, s->current_tx_desc, &desc);
tulip_dump_tx_descriptor(s, &desc);
@@ -675,10 +693,10 @@ static void tulip_xmit_list_update(TULIPState *s)
s->tx_frame_len = 0;
}
- tulip_copy_tx_buffers(s, &desc);
-
- if (desc.control & TDES1_LS) {
- tulip_tx(s, &desc);
+ if (!tulip_copy_tx_buffers(s, &desc)) {
+ if (desc.control & TDES1_LS) {
+ tulip_tx(s, &desc);
+ }
}
}
tulip_desc_write(s, s->current_tx_desc, &desc);
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 3627bb1717..a46e3b37a7 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -1234,26 +1234,26 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
qemu_flush_queued_packets(qemu_get_subqueue(n->nic, queue_index));
}
-static int virtio_net_can_receive(NetClientState *nc)
+static bool virtio_net_can_receive(NetClientState *nc)
{
VirtIONet *n = qemu_get_nic_opaque(nc);
VirtIODevice *vdev = VIRTIO_DEVICE(n);
VirtIONetQueue *q = virtio_net_get_subqueue(nc);
if (!vdev->vm_running) {
- return 0;
+ return false;
}
if (nc->queue_index >= n->curr_queues) {
- return 0;
+ return false;
}
if (!virtio_queue_ready(q->rx_vq) ||
!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize)
diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c
index cf07e698b3..71d16fef3d 100644
--- a/hw/net/xilinx_ethlite.c
+++ b/hw/net/xilinx_ethlite.c
@@ -175,7 +175,7 @@ static const MemoryRegionOps eth_ops = {
}
};
-static int eth_can_rx(NetClientState *nc)
+static bool eth_can_rx(NetClientState *nc)
{
struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
unsigned int rxbase = s->rxbuf * (0x800 / 4);
diff --git a/include/net/can_emu.h b/include/net/can_emu.h
index d4fc51b57d..fce9770928 100644
--- a/include/net/can_emu.h
+++ b/include/net/can_emu.h
@@ -83,7 +83,7 @@ typedef struct CanBusClientState CanBusClientState;
typedef struct CanBusState CanBusState;
typedef struct CanBusClientInfo {
- int (*can_receive)(CanBusClientState *);
+ bool (*can_receive)(CanBusClientState *);
ssize_t (*receive)(CanBusClientState *,
const struct qemu_can_frame *frames, size_t frames_cnt);
} CanBusClientInfo;
diff --git a/include/net/net.h b/include/net/net.h
index 094e966af9..39085d9444 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -42,7 +42,7 @@ typedef struct NICConf {
/* Net clients */
typedef void (NetPoll)(NetClientState *, bool enable);
-typedef int (NetCanReceive)(NetClientState *);
+typedef bool (NetCanReceive)(NetClientState *);
typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t);
typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int);
typedef void (NetCleanup) (NetClientState *);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 49395dcea9..5af55fca78 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -245,7 +245,12 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
#define __NR_sys_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo
#define __NR_sys_syslog __NR_syslog
-#define __NR_sys_futex __NR_futex
+#if defined(__NR_futex)
+# define __NR_sys_futex __NR_futex
+#endif
+#if defined(__NR_futex_time64)
+# define __NR_sys_futex_time64 __NR_futex_time64
+#endif
#define __NR_sys_inotify_init __NR_inotify_init
#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
@@ -295,10 +300,14 @@ _syscall1(int,exit_group,int,error_code)
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
_syscall1(int,set_tid_address,int *,tidptr)
#endif
-#if (defined(TARGET_NR_futex) || defined(TARGET_NR_exit)) && defined(__NR_futex)
+#if defined(__NR_futex)
_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
const struct timespec *,timeout,int *,uaddr2,int,val3)
#endif
+#if defined(__NR_futex_time64)
+_syscall6(int,sys_futex_time64,int *,uaddr,int,op,int,val,
+ const struct timespec *,timeout,int *,uaddr2,int,val3)
+#endif
#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
unsigned long *, user_mask_ptr);
@@ -762,10 +771,14 @@ safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
int, maxevents, int, timeout, const sigset_t *, sigmask,
size_t, sigsetsize)
-#ifdef TARGET_NR_futex
+#if defined(__NR_futex)
safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
const struct timespec *,timeout,int *,uaddr2,int,val3)
#endif
+#if defined(__NR_futex_time64)
+safe_syscall6(int,futex_time64,int *,uaddr,int,op,int,val, \
+ const struct timespec *,timeout,int *,uaddr2,int,val3)
+#endif
safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
safe_syscall2(int, kill, pid_t, pid, int, sig)
safe_syscall2(int, tkill, int, tid, int, sig)
@@ -1229,7 +1242,7 @@ static inline abi_long target_to_host_timespec(struct timespec *host_ts,
}
#endif
-#if defined(TARGET_NR_clock_settime64)
+#if defined(TARGET_NR_clock_settime64) || defined(TARGET_NR_futex_time64)
static inline abi_long target_to_host_timespec64(struct timespec *host_ts,
abi_ulong target_addr)
{
@@ -6916,6 +6929,55 @@ static inline abi_long host_to_target_statx(struct target_statx *host_stx,
}
#endif
+static int do_sys_futex(int *uaddr, int op, int val,
+ const struct timespec *timeout, int *uaddr2,
+ int val3)
+{
+#if HOST_LONG_BITS == 64
+#if defined(__NR_futex)
+ /* always a 64-bit time_t, it doesn't define _time64 version */
+ return sys_futex(uaddr, op, val, timeout, uaddr2, val3);
+
+#endif
+#else /* HOST_LONG_BITS == 64 */
+#if defined(__NR_futex_time64)
+ if (sizeof(timeout->tv_sec) == 8) {
+ /* _time64 function on 32bit arch */
+ return sys_futex_time64(uaddr, op, val, timeout, uaddr2, val3);
+ }
+#endif
+#if defined(__NR_futex)
+ /* old function on 32bit arch */
+ return sys_futex(uaddr, op, val, timeout, uaddr2, val3);
+#endif
+#endif /* HOST_LONG_BITS == 64 */
+ g_assert_not_reached();
+}
+
+static int do_safe_futex(int *uaddr, int op, int val,
+ const struct timespec *timeout, int *uaddr2,
+ int val3)
+{
+#if HOST_LONG_BITS == 64
+#if defined(__NR_futex)
+ /* always a 64-bit time_t, it doesn't define _time64 version */
+ return get_errno(safe_futex(uaddr, op, val, timeout, uaddr2, val3));
+#endif
+#else /* HOST_LONG_BITS == 64 */
+#if defined(__NR_futex_time64)
+ if (sizeof(timeout->tv_sec) == 8) {
+ /* _time64 function on 32bit arch */
+ return get_errno(safe_futex_time64(uaddr, op, val, timeout, uaddr2,
+ val3));
+ }
+#endif
+#if defined(__NR_futex)
+ /* old function on 32bit arch */
+ return get_errno(safe_futex(uaddr, op, val, timeout, uaddr2, val3));
+#endif
+#endif /* HOST_LONG_BITS == 64 */
+ return -TARGET_ENOSYS;
+}
/* ??? Using host futex calls even when target atomic operations
are not really atomic probably breaks things. However implementing
@@ -6945,12 +7007,11 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
} else {
pts = NULL;
}
- return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
- pts, NULL, val3));
+ return do_safe_futex(g2h(uaddr), op, tswap32(val), pts, NULL, val3);
case FUTEX_WAKE:
- return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
+ return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
case FUTEX_FD:
- return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
+ return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
case FUTEX_REQUEUE:
case FUTEX_CMP_REQUEUE:
case FUTEX_WAKE_OP:
@@ -6960,16 +7021,63 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
to satisfy the compiler. We do not need to tswap TIMEOUT
since it's not compared to guest memory. */
pts = (struct timespec *)(uintptr_t) timeout;
- return get_errno(safe_futex(g2h(uaddr), op, val, pts,
- g2h(uaddr2),
- (base_op == FUTEX_CMP_REQUEUE
- ? tswap32(val3)
- : val3)));
+ return do_safe_futex(g2h(uaddr), op, val, pts, g2h(uaddr2),
+ (base_op == FUTEX_CMP_REQUEUE
+ ? tswap32(val3)
+ : val3));
default:
return -TARGET_ENOSYS;
}
}
#endif
+
+#if defined(TARGET_NR_futex_time64)
+static int do_futex_time64(target_ulong uaddr, int op, int val, target_ulong timeout,
+ target_ulong uaddr2, int val3)
+{
+ struct timespec ts, *pts;
+ int base_op;
+
+ /* ??? We assume FUTEX_* constants are the same on both host
+ and target. */
+#ifdef FUTEX_CMD_MASK
+ base_op = op & FUTEX_CMD_MASK;
+#else
+ base_op = op;
+#endif
+ switch (base_op) {
+ case FUTEX_WAIT:
+ case FUTEX_WAIT_BITSET:
+ if (timeout) {
+ pts = &ts;
+ target_to_host_timespec64(pts, timeout);
+ } else {
+ pts = NULL;
+ }
+ return do_safe_futex(g2h(uaddr), op, tswap32(val), pts, NULL, val3);
+ case FUTEX_WAKE:
+ return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
+ case FUTEX_FD:
+ return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
+ case FUTEX_REQUEUE:
+ case FUTEX_CMP_REQUEUE:
+ case FUTEX_WAKE_OP:
+ /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
+ TIMEOUT parameter is interpreted as a uint32_t by the kernel.
+ But the prototype takes a `struct timespec *'; insert casts
+ to satisfy the compiler. We do not need to tswap TIMEOUT
+ since it's not compared to guest memory. */
+ pts = (struct timespec *)(uintptr_t) timeout;
+ return do_safe_futex(g2h(uaddr), op, val, pts, g2h(uaddr2),
+ (base_op == FUTEX_CMP_REQUEUE
+ ? tswap32(val3)
+ : val3));
+ default:
+ return -TARGET_ENOSYS;
+ }
+}
+#endif
+
#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
abi_long handle, abi_long mount_id,
@@ -7541,7 +7649,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
ts = cpu->opaque;
if (ts->child_tidptr) {
put_user_u32(0, ts->child_tidptr);
- sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
+ do_sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
NULL, NULL, 0);
}
thread_cpu = NULL;
@@ -11635,6 +11743,10 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_futex:
return do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
#endif
+#ifdef TARGET_NR_futex_time64
+ case TARGET_NR_futex_time64:
+ return do_futex_time64(arg1, arg2, arg3, arg4, arg5, arg6);
+#endif
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
case TARGET_NR_inotify_init:
ret = get_errno(sys_inotify_init());
diff --git a/net/can/can_socketcan.c b/net/can/can_socketcan.c
index 29bfacd4f8..807f31fcde 100644
--- a/net/can/can_socketcan.c
+++ b/net/can/can_socketcan.c
@@ -110,9 +110,9 @@ static void can_host_socketcan_read(void *opaque)
}
}
-static int can_host_socketcan_can_receive(CanBusClientState *client)
+static bool can_host_socketcan_can_receive(CanBusClientState *client)
{
- return 1;
+ return true;
}
static ssize_t can_host_socketcan_receive(CanBusClientState *client,
diff --git a/net/colo-compare.c b/net/colo-compare.c
index 7ee17f2cf8..10c0239f9d 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -48,8 +48,8 @@ static NotifierList colo_compare_notifiers =
#define COLO_COMPARE_FREE_PRIMARY 0x01
#define COLO_COMPARE_FREE_SECONDARY 0x02
-/* TODO: Should be configurable */
#define REGULAR_PACKET_CHECK_MS 3000
+#define DEFAULT_TIME_OUT_MS 3000
static QemuMutex event_mtx;
static QemuCond event_complete_cond;
@@ -92,6 +92,8 @@ typedef struct CompareState {
SocketReadState sec_rs;
SocketReadState notify_rs;
bool vnet_hdr;
+ uint32_t compare_timeout;
+ uint32_t expired_scan_cycle;
/*
* Record the connection that through the NIC
@@ -607,10 +609,9 @@ static int colo_old_packet_check_one_conn(Connection *conn,
CompareState *s)
{
GList *result = NULL;
- int64_t check_time = REGULAR_PACKET_CHECK_MS;
result = g_queue_find_custom(&conn->primary_list,
- &check_time,
+ &s->compare_timeout,
(GCompareFunc)colo_old_packet_check_one);
if (result) {
@@ -822,7 +823,7 @@ static void check_old_packet_regular(void *opaque)
/* if have old packet we will notify checkpoint */
colo_old_packet_check(s);
timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
- REGULAR_PACKET_CHECK_MS);
+ s->expired_scan_cycle);
}
/* Public API, Used for COLO frame to notify compare event */
@@ -852,7 +853,7 @@ static void colo_compare_timer_init(CompareState *s)
SCALE_MS, check_old_packet_regular,
s);
timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
- REGULAR_PACKET_CHECK_MS);
+ s->expired_scan_cycle);
}
static void colo_compare_timer_del(CompareState *s)
@@ -984,6 +985,72 @@ static void compare_set_notify_dev(Object *obj, const char *value, Error **errp)
s->notify_dev = g_strdup(value);
}
+static void compare_get_timeout(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ CompareState *s = COLO_COMPARE(obj);
+ uint32_t value = s->compare_timeout;
+
+ visit_type_uint32(v, name, &value, errp);
+}
+
+static void compare_set_timeout(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ CompareState *s = COLO_COMPARE(obj);
+ Error *local_err = NULL;
+ uint32_t value;
+
+ visit_type_uint32(v, name, &value, &local_err);
+ if (local_err) {
+ goto out;
+ }
+ if (!value) {
+ error_setg(&local_err, "Property '%s.%s' requires a positive value",
+ object_get_typename(obj), name);
+ goto out;
+ }
+ s->compare_timeout = value;
+
+out:
+ error_propagate(errp, local_err);
+}
+
+static void compare_get_expired_scan_cycle(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ CompareState *s = COLO_COMPARE(obj);
+ uint32_t value = s->expired_scan_cycle;
+
+ visit_type_uint32(v, name, &value, errp);
+}
+
+static void compare_set_expired_scan_cycle(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ CompareState *s = COLO_COMPARE(obj);
+ Error *local_err = NULL;
+ uint32_t value;
+
+ visit_type_uint32(v, name, &value, &local_err);
+ if (local_err) {
+ goto out;
+ }
+ if (!value) {
+ error_setg(&local_err, "Property '%s.%s' requires a positive value",
+ object_get_typename(obj), name);
+ goto out;
+ }
+ s->expired_scan_cycle = value;
+
+out:
+ error_propagate(errp, local_err);
+}
+
static void compare_pri_rs_finalize(SocketReadState *pri_rs)
{
CompareState *s = container_of(pri_rs, CompareState, pri_rs);
@@ -1090,6 +1157,16 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
return;
}
+ if (!s->compare_timeout) {
+ /* Set default value to 3000 MS */
+ s->compare_timeout = DEFAULT_TIME_OUT_MS;
+ }
+
+ if (!s->expired_scan_cycle) {
+ /* Set default value to 3000 MS */
+ s->expired_scan_cycle = REGULAR_PACKET_CHECK_MS;
+ }
+
if (find_and_check_chardev(&chr, s->pri_indev, errp) ||
!qemu_chr_fe_init(&s->chr_pri_in, chr, errp)) {
return;
@@ -1185,6 +1262,14 @@ static void colo_compare_init(Object *obj)
compare_get_notify_dev, compare_set_notify_dev,
NULL);
+ object_property_add(obj, "compare_timeout", "uint32",
+ compare_get_timeout,
+ compare_set_timeout, NULL, NULL, NULL);
+
+ object_property_add(obj, "expired_scan_cycle", "uint32",
+ compare_get_expired_scan_cycle,
+ compare_set_expired_scan_cycle, NULL, NULL, NULL);
+
s->vnet_hdr = false;
object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr,
compare_set_vnet_hdr, NULL);
diff --git a/net/filter-buffer.c b/net/filter-buffer.c
index 88da78f821..12e0254287 100644
--- a/net/filter-buffer.c
+++ b/net/filter-buffer.c
@@ -74,7 +74,7 @@ static ssize_t filter_buffer_receive_iov(NetFilterState *nf,
* the filter can still accept packets until its internal queue is full.
* For example:
* For some reason, receiver could not receive more packets
- * (.can_receive() returns zero). Without a filter, at most one packet
+ * (.can_receive() returns false). Without a filter, at most one packet
* will be queued in incoming queue and sender's poll will be disabled
* unit its sent_cb() was called. With a filter, it will keep receiving
* the packets without caring about the receiver. This is suboptimal.
diff --git a/net/hub.c b/net/hub.c
index 88cfb876f3..1375738bf1 100644
--- a/net/hub.c
+++ b/net/hub.c
@@ -90,7 +90,7 @@ static NetHub *net_hub_new(int id)
return hub;
}
-static int net_hub_port_can_receive(NetClientState *nc)
+static bool net_hub_port_can_receive(NetClientState *nc)
{
NetHubPort *port;
NetHubPort *src_port = DO_UPCAST(NetHubPort, nc, nc);
@@ -102,11 +102,11 @@ static int net_hub_port_can_receive(NetClientState *nc)
}
if (qemu_can_send_packet(&port->nc)) {
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
static ssize_t net_hub_port_receive(NetClientState *nc,
diff --git a/qemu-options.hx b/qemu-options.hx
index 962a5ebaa6..16debd03cb 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4615,7 +4615,7 @@ SRST
stored. The file format is libpcap, so it can be analyzed with
tools such as tcpdump or Wireshark.
- ``-object colo-compare,id=id,primary_in=chardevid,secondary_in=chardevid,outdev=chardevid,iothread=id[,vnet_hdr_support][,notify_dev=id]``
+ ``-object colo-compare,id=id,primary_in=chardevid,secondary_in=chardevid,outdev=chardevid,iothread=id[,vnet_hdr_support][,notify_dev=id][,compare_timeout=@var{ms}][,expired_scan_cycle=@var{ms}``
Colo-compare gets packet from primary\_inchardevid and
secondary\_inchardevid, than compare primary packet with
secondary packet. If the packets are same, we will output
@@ -4624,8 +4624,12 @@ SRST
outdevchardevid. In order to improve efficiency, we need to put
the task of comparison in another thread. If it has the
vnet\_hdr\_support flag, colo compare will send/recv packet with
- vnet\_hdr\_len. If you want to use Xen COLO, will need the
- notify\_dev to notify Xen colo-frame to do checkpoint.
+ vnet\_hdr\_len. Then compare\_timeout=@var{ms} determines the
+ maximum delay colo-compare wait for the packet.
+ The expired\_scan\_cycle=@var{ms} to set the period of scanning
+ expired primary node network packets.
+ If you want to use Xen COLO, will need the notify\_dev to
+ notify Xen colo-frame to do checkpoint.
we must use it with the help of filter-mirror and
filter-redirector.
diff --git a/scripts/decodetree.py b/scripts/decodetree.py
index 2a8f2b6e06..46ab917807 100755
--- a/scripts/decodetree.py
+++ b/scripts/decodetree.py
@@ -1025,7 +1025,7 @@ class SizeTree:
if extracted < self.width:
output(ind, 'insn = ', decode_function,
'_load_bytes(ctx, insn, {0}, {1});\n'
- .format(extracted / 8, self.width / 8));
+ .format(extracted // 8, self.width // 8));
extracted = self.width
# Attempt to aid the compiler in producing compact switch statements.
@@ -1079,7 +1079,7 @@ class SizeLeaf:
if extracted < self.width:
output(ind, 'insn = ', decode_function,
'_load_bytes(ctx, insn, {0}, {1});\n'
- .format(extracted / 8, self.width / 8));
+ .format(extracted // 8, self.width // 8));
extracted = self.width
output(ind, 'return insn;\n')
# end SizeLeaf
diff --git a/target/arm/helper.c b/target/arm/helper.c
index b7b6887241..163c91a1cc 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -9172,7 +9172,6 @@ static void take_aarch32_exception(CPUARMState *env, int new_mode,
/* Change the CPU state so as to actually take the exception. */
switch_mode(env, new_mode);
- new_el = arm_current_el(env);
/*
* For exceptions taken to AArch32 we must clear the SS bit in both
@@ -9184,6 +9183,10 @@ static void take_aarch32_exception(CPUARMState *env, int new_mode,
env->condexec_bits = 0;
/* Switch to the new mode, and to the correct instruction set. */
env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
+
+ /* This must be after mode switching. */
+ new_el = arm_current_el(env);
+
/* Set new mode endianness */
env->uncached_cpsr &= ~CPSR_E;
if (env->cp15.sctlr_el[new_el] & SCTLR_EE) {
diff --git a/target/mips/translate.c b/target/mips/translate.c
index d745bd2803..25b595a17d 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -5529,6 +5529,7 @@ static void gen_loongson_multimedia(DisasContext *ctx, int rd, int rs, int rt)
{
uint32_t opc, shift_max;
TCGv_i64 t0, t1;
+ TCGCond cond;
opc = MASK_LMI(ctx->opcode);
switch (opc) {
@@ -5862,14 +5863,39 @@ static void gen_loongson_multimedia(DisasContext *ctx, int rd, int rs, int rt)
case OPC_SEQU_CP2:
case OPC_SEQ_CP2:
+ cond = TCG_COND_EQ;
+ goto do_cc_cond;
+ break;
case OPC_SLTU_CP2:
+ cond = TCG_COND_LTU;
+ goto do_cc_cond;
+ break;
case OPC_SLT_CP2:
+ cond = TCG_COND_LT;
+ goto do_cc_cond;
+ break;
case OPC_SLEU_CP2:
+ cond = TCG_COND_LEU;
+ goto do_cc_cond;
+ break;
case OPC_SLE_CP2:
- /*
- * ??? Document is unclear: Set FCC[CC]. Does that mean the
- * FD field is the CC field?
- */
+ cond = TCG_COND_LE;
+ do_cc_cond:
+ {
+ int cc = (ctx->opcode >> 8) & 0x7;
+ TCGv_i64 t64 = tcg_temp_new_i64();
+ TCGv_i32 t32 = tcg_temp_new_i32();
+
+ tcg_gen_setcond_i64(cond, t64, t0, t1);
+ tcg_gen_extrl_i64_i32(t32, t64);
+ tcg_gen_deposit_i32(fpu_fcr31, fpu_fcr31, t32,
+ get_fp_bit(cc), 1);
+
+ tcg_temp_free_i32(t32);
+ tcg_temp_free_i64(t64);
+ }
+ goto no_rd;
+ break;
default:
MIPS_INVAL("loongson_cp2");
generate_exception_end(ctx, EXCP_RI);
@@ -5878,6 +5904,7 @@ static void gen_loongson_multimedia(DisasContext *ctx, int rd, int rs, int rt)
gen_store_fpr64(ctx, t0, rd);
+no_rd:
tcg_temp_free_i64(t0);
tcg_temp_free_i64(t1);
}
diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c
index 223dba9c8c..7f61eeedd0 100644
--- a/tcg/i386/tcg-target.inc.c
+++ b/tcg/i386/tcg-target.inc.c
@@ -2855,9 +2855,13 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
goto gen_simd;
#if TCG_TARGET_REG_BITS == 32
case INDEX_op_dup2_vec:
- /* Constraints have already placed both 32-bit inputs in xmm regs. */
- insn = OPC_PUNPCKLDQ;
- goto gen_simd;
+ /* First merge the two 32-bit inputs to a single 64-bit element. */
+ tcg_out_vex_modrm(s, OPC_PUNPCKLDQ, a0, a1, a2);
+ /* Then replicate the 64-bit elements across the rest of the vector. */
+ if (type != TCG_TYPE_V64) {
+ tcg_out_dup_vec(s, type, MO_64, a0, a0);
+ }
+ break;
#endif
case INDEX_op_abs_vec:
insn = abs_insn[vece];
diff --git a/tests/qtest/Makefile.include b/tests/qtest/Makefile.include
index 10a28de8a3..9e5a51d033 100644
--- a/tests/qtest/Makefile.include
+++ b/tests/qtest/Makefile.include
@@ -217,6 +217,7 @@ qos-test-obj-y += tests/qtest/es1370-test.o
qos-test-obj-y += tests/qtest/ipoctal232-test.o
qos-test-obj-y += tests/qtest/megasas-test.o
qos-test-obj-y += tests/qtest/ne2000-test.o
+qos-test-obj-y += tests/qtest/tulip-test.o
qos-test-obj-y += tests/qtest/nvme-test.o
qos-test-obj-y += tests/qtest/pca9552-test.o
qos-test-obj-y += tests/qtest/pci-test.o
diff --git a/tests/qtest/tulip-test.c b/tests/qtest/tulip-test.c
new file mode 100644
index 0000000000..2fb6c4d5a7
--- /dev/null
+++ b/tests/qtest/tulip-test.c
@@ -0,0 +1,91 @@
+/*
+ * QTest testcase for DEC/Intel Tulip 21143
+ *
+ * Copyright (c) 2020 Li Qiang <liq3ea@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
+#include "qemu/bitops.h"
+#include "hw/net/tulip.h"
+
+typedef struct QTulip_pci QTulip_pci;
+
+struct QTulip_pci {
+ QOSGraphObject obj;
+ QPCIDevice dev;
+};
+
+static void *tulip_pci_get_driver(void *obj, const char *interface)
+{
+ QTulip_pci *tulip_pci = obj;
+
+ if (!g_strcmp0(interface, "pci-device")) {
+ return &tulip_pci->dev;
+ }
+
+ fprintf(stderr, "%s not present in tulip_pci\n", interface);
+ g_assert_not_reached();
+}
+
+static void *tulip_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+ QTulip_pci *tulip_pci = g_new0(QTulip_pci, 1);
+ QPCIBus *bus = pci_bus;
+
+ qpci_device_init(&tulip_pci->dev, bus, addr);
+ tulip_pci->obj.get_driver = tulip_pci_get_driver;
+
+ return &tulip_pci->obj;
+}
+
+static void tulip_large_tx(void *obj, void *data, QGuestAllocator *alloc)
+{
+ QTulip_pci *tulip_pci = obj;
+ QPCIDevice *dev = &tulip_pci->dev;
+ QPCIBar bar;
+ struct tulip_descriptor context;
+ char guest_data[4096];
+ uint64_t context_pa;
+ uint64_t guest_pa;
+
+ qpci_device_enable(dev);
+ bar = qpci_iomap(dev, 0, NULL);
+ context_pa = guest_alloc(alloc, sizeof(context));
+ guest_pa = guest_alloc(alloc, 4096);
+ memset(guest_data, 'A', sizeof(guest_data));
+ context.status = TDES0_OWN;
+ context.control = TDES1_BUF2_SIZE_MASK << TDES1_BUF2_SIZE_SHIFT |
+ TDES1_BUF1_SIZE_MASK << TDES1_BUF1_SIZE_SHIFT;
+ context.buf_addr2 = guest_pa;
+ context.buf_addr1 = guest_pa;
+
+ qtest_memwrite(dev->bus->qts, context_pa, &context, sizeof(context));
+ qtest_memwrite(dev->bus->qts, guest_pa, guest_data, sizeof(guest_data));
+ qpci_io_writel(dev, bar, 0x20, context_pa);
+ qpci_io_writel(dev, bar, 0x30, CSR6_ST);
+ guest_free(alloc, context_pa);
+ guest_free(alloc, guest_pa);
+}
+
+static void tulip_register_nodes(void)
+{
+ QOSGraphEdgeOptions opts = {
+ .extra_device_opts = "addr=04.0",
+ };
+ add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+
+ qos_node_create_driver("tulip", tulip_pci_create);
+ qos_node_consumes("tulip", "pci-bus", &opts);
+ qos_node_produces("tulip", "pci-device");
+
+ qos_add_test("tulip_large_tx", "tulip", tulip_large_tx, NULL);
+}
+
+libqos_init(tulip_register_nodes);