aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml1
-rw-r--r--.gitlab-ci.yml24
-rw-r--r--MAINTAINERS25
-rw-r--r--VERSION2
-rw-r--r--block.c89
-rw-r--r--block/blkdebug.c2
-rw-r--r--block/dmg-lzfse.c1
-rw-r--r--block/dmg.c2
-rw-r--r--block/nfs.c13
-rw-r--r--block/qcow2-cluster.c5
-rw-r--r--block/qcow2.c23
-rw-r--r--block/qcow2.h25
-rw-r--r--block/vpc.c10
-rwxr-xr-xconfigure4
-rw-r--r--docs/_templates/editpage.html5
-rw-r--r--docs/conf.py1
-rw-r--r--docs/devel/_templates/editpage.html5
-rw-r--r--docs/devel/fuzzing.rst236
-rw-r--r--docs/devel/fuzzing.txt214
-rw-r--r--docs/devel/index.rst1
-rw-r--r--docs/devel/qapi-code-gen.txt6
-rw-r--r--docs/interop/_templates/editpage.html5
-rw-r--r--docs/specs/_templates/editpage.html5
-rw-r--r--docs/system/_templates/editpage.html5
-rw-r--r--docs/system/arm/sbsa.rst32
-rw-r--r--docs/system/deprecated.rst23
-rw-r--r--docs/system/target-arm.rst1
-rw-r--r--docs/tools/_templates/editpage.html5
-rw-r--r--docs/user/_templates/editpage.html5
-rw-r--r--hw/arm/Kconfig3
-rw-r--r--hw/arm/armsse.c3
-rw-r--r--hw/arm/musicpal.c42
-rw-r--r--hw/arm/nseries.c26
-rw-r--r--hw/arm/stm32f205_soc.c1
-rw-r--r--hw/block/nvme.c6
-rw-r--r--hw/intc/ibex_plic.c3
-rw-r--r--hw/mips/boston.c10
-rw-r--r--hw/misc/stm32f2xx_syscfg.c2
-rw-r--r--hw/net/can/ctucan_core.c23
-rw-r--r--hw/net/can/ctucan_core.h3
-rw-r--r--hw/net/virtio-net.c6
-rw-r--r--hw/rx/rx-gdbsim.c3
-rw-r--r--hw/s390x/ipl.h4
-rw-r--r--hw/ssi/imx_spi.c2
-rw-r--r--hw/ssi/xilinx_spi.c2
-rw-r--r--include/block/block.h6
-rw-r--r--include/block/block_int.h9
-rw-r--r--include/hw/misc/stm32f2xx_syscfg.h2
-rw-r--r--linux-user/sparc/signal.c62
-rw-r--r--meson.build6
-rw-r--r--migration/ram.c14
-rw-r--r--net/colo-compare.c58
-rw-r--r--net/colo.c5
-rw-r--r--net/eth.c6
-rw-r--r--net/filter-rewriter.c2
-rw-r--r--net/l2tpv3.c9
-rw-r--r--qapi/audio.json4
-rw-r--r--qapi/authz.json6
-rw-r--r--qapi/block-core.json47
-rw-r--r--qga/commands-posix.c3
-rwxr-xr-xscripts/device-crash-test4
-rwxr-xr-xscripts/oss-fuzz/build.sh12
-rw-r--r--softmmu/vl.c1
-rw-r--r--target/arm/arch_dump.c8
-rw-r--r--target/arm/arm-semi.c8
-rw-r--r--target/arm/helper.c2
-rw-r--r--target/arm/helper.h2
-rw-r--r--target/arm/op_helper.c23
-rw-r--r--target/arm/translate-a64.c4
-rw-r--r--target/arm/translate-neon.c.inc50
-rw-r--r--target/arm/translate.c2
-rw-r--r--target/mips/cp0_helper.c27
-rw-r--r--target/mips/cpu.h1
-rw-r--r--target/riscv/cpu-param.h11
-rw-r--r--target/riscv/cpu.h19
-rw-r--r--target/riscv/cpu_bits.h1
-rw-r--r--target/riscv/cpu_helper.c62
-rw-r--r--target/riscv/helper.h5
-rw-r--r--target/riscv/insn_trans/trans_rvh.c.inc143
-rw-r--r--target/riscv/op_helper.c124
-rw-r--r--target/riscv/translate.c2
-rw-r--r--target/s390x/cpu_models.c8
-rwxr-xr-xtests/qemu-iotests/240219
-rw-r--r--tests/qemu-iotests/240.out76
-rw-r--r--tests/qemu-iotests/iotests.py10
-rw-r--r--tests/qtest/arm-cpu-features.c8
-rw-r--r--tests/qtest/fuzz/fork_fuzz.ld12
-rw-r--r--tests/qtest/fuzz/meson.build1
-rw-r--r--tests/qtest/fuzz/virtio_blk_fuzz.c234
-rw-r--r--tests/qtest/libqos/libqtest.h18
-rw-r--r--tests/qtest/libqtest-single.h2
-rw-r--r--tests/qtest/npcm7xx_rng-test.c2
-rw-r--r--tests/qtest/tpm-tests.c6
-rwxr-xr-xtests/vm/openbsd8
94 files changed, 1266 insertions, 1002 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 900437dd2a..f0209b7a3e 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -109,6 +109,7 @@ windows_msys2_task:
mingw-w64-x86_64-cyrus-sasl \
mingw-w64-x86_64-curl \
mingw-w64-x86_64-gnutls \
+ mingw-w64-x86_64-libnfs \
"
bitsadmin /transfer msys_download /dynamic /download /priority FOREGROUND `
https://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-python-sphinx-2.3.1-1-any.pkg.tar.xz `
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 3b15ae5c30..9a8b375188 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -7,12 +7,6 @@ stages:
- build
- test
-# We assume GitLab has it's own caching set up for RPM/APT repositories so we
-# just take care of avocado assets here.
-cache:
- paths:
- - $HOME/avocado/data/cache
-
include:
- local: '/.gitlab-ci.d/edk2.yml'
- local: '/.gitlab-ci.d/opensbi.yml'
@@ -80,6 +74,7 @@ build-system-ubuntu:
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
moxie-softmmu microblazeel-softmmu mips64el-softmmu
MAKE_CHECK_ARGS: check-build
+ CONFIGURE_ARGS: --enable-docs
artifacts:
expire_in: 2 days
paths:
@@ -111,6 +106,7 @@ build-system-debian:
TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu
riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu
MAKE_CHECK_ARGS: check-build
+ CONFIGURE_ARGS: --enable-docs
artifacts:
expire_in: 2 days
paths:
@@ -139,7 +135,7 @@ build-system-fedora:
<<: *native_build_job_definition
variables:
IMAGE: fedora
- CONFIGURE_ARGS: --disable-gcrypt --enable-nettle
+ CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs
TARGETS: tricore-softmmu microblaze-softmmu mips-softmmu
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
MAKE_CHECK_ARGS: check-build
@@ -423,3 +419,17 @@ check-dco:
- $CI_PROJECT_NAMESPACE == 'qemu-project' && $CI_COMMIT_BRANCH == 'master'
variables:
GIT_DEPTH: 1000
+
+pages:
+ image: $CI_REGISTRY_IMAGE/qemu/ubuntu2004:latest
+ stage: test
+ needs:
+ - job: build-system-ubuntu
+ artifacts: true
+ script:
+ - mkdir public
+ - mv build/docs/index.html public/
+ - for i in devel interop specs system tools user ; do mv build/docs/$i public/ ; done
+ artifacts:
+ paths:
+ - public
diff --git a/MAINTAINERS b/MAINTAINERS
index 63223e1183..6c2df0bef3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -227,7 +227,7 @@ R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Odd Fixes
F: target/mips/
F: default-configs/*mips*
-F: disas/*mips*
+F: disas/mips.c
F: docs/system/cpu-models-mips.rst.inc
F: hw/intc/mips_gic.c
F: hw/mips/
@@ -240,6 +240,10 @@ F: include/hw/timer/mips_gictimer.h
F: tests/tcg/mips/
K: ^Subject:.*(?i)mips
+MIPS TCG CPUs (nanoMIPS ISA)
+S: Orphan
+F: disas/nanomips.*
+
Moxie TCG CPUs
M: Anthony Green <green@moxielogic.com>
S: Maintained
@@ -289,7 +293,7 @@ F: linux-user/host/riscv64/
RENESAS RX CPUs
M: Yoshinori Sato <ysato@users.sourceforge.jp>
-S: Maintained
+S: Odd Fixes
F: target/rx/
S390 TCG CPUs
@@ -1334,7 +1338,7 @@ RX Machines
-----------
rx-gdbsim
M: Yoshinori Sato <ysato@users.sourceforge.jp>
-S: Maintained
+S: Odd Fixes
F: docs/system/target-rx.rst
F: hw/rx/rx-gdbsim.c
F: tests/acceptance/machine_rx_gdbsim.py
@@ -1344,7 +1348,7 @@ SH4 Machines
R2D
M: Yoshinori Sato <ysato@users.sourceforge.jp>
R: Magnus Damm <magnus.damm@gmail.com>
-S: Maintained
+S: Odd Fixes
F: hw/sh4/r2d.c
F: hw/intc/sh_intc.c
F: include/hw/sh4/sh_intc.h
@@ -1909,6 +1913,7 @@ Rocker
M: Jiri Pirko <jiri@resnulli.us>
S: Maintained
F: hw/net/rocker/
+F: qapi/rocker.json
F: tests/rocker/
F: docs/specs/rocker.txt
@@ -2077,7 +2082,7 @@ F: docs/*/*xive*
Renesas peripherals
M: Yoshinori Sato <ysato@users.sourceforge.jp>
R: Magnus Damm <magnus.damm@gmail.com>
-S: Maintained
+S: Odd Fixes
F: hw/char/renesas_sci.c
F: hw/char/sh_serial.c
F: hw/timer/renesas_*.c
@@ -2088,7 +2093,7 @@ F: include/hw/timer/renesas_*.h
Renesas RX peripherals
M: Yoshinori Sato <ysato@users.sourceforge.jp>
-S: Maintained
+S: Odd Fixes
F: hw/intc/rx_icu.c
F: hw/rx/
F: include/hw/intc/rx_icu.h
@@ -2111,6 +2116,7 @@ S: Maintained
F: audio/
F: hw/audio/
F: include/hw/audio/
+F: qapi/audio.json
F: tests/qtest/ac97-test.c
F: tests/qtest/es1370-test.c
F: tests/qtest/intel-hda-test.c
@@ -2490,7 +2496,9 @@ F: monitor/monitor-internal.h
F: monitor/qmp*
F: monitor/misc.c
F: monitor/monitor.c
+F: qapi/control.json
F: qapi/error.json
+F: qapi/introspect.json
F: docs/devel/*qmp-*
F: docs/interop/*qmp-*
F: scripts/qmp/
@@ -2517,7 +2525,7 @@ R: Thomas Huth <thuth@redhat.com>
S: Maintained
F: tests/qtest/fuzz/
F: scripts/oss-fuzz/
-F: docs/devel/fuzzing.txt
+F: docs/devel/fuzzing.rst
Register API
M: Alistair Francis <alistair@alistair23.me>
@@ -2551,6 +2559,7 @@ S: Maintained
F: trace/
F: trace-events
F: docs/qemu-option-trace.rst.inc
+F: qapi/trace.json
F: scripts/tracetool.py
F: scripts/tracetool/
F: scripts/qemu-trace-stap*
@@ -2610,6 +2619,7 @@ M: Daniel P. Berrange <berrange@redhat.com>
S: Maintained
F: crypto/
F: include/crypto/
+F: qapi/crypto.json
F: tests/test-crypto-*
F: tests/benchmark-crypto-*
F: tests/crypto-tls-*
@@ -3146,6 +3156,7 @@ S: Maintained
F: .gitlab-ci.yml
F: .gitlab-ci.d/crossbuilds.yml
F: .gitlab-ci.d/*py
+F: scripts/ci/gitlab-pipeline-status
Guest Test Compilation Support
M: Alex Bennée <alex.bennee@linaro.org>
diff --git a/VERSION b/VERSION
index 167c7a1847..b1eec09dfb 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-5.1.90
+5.1.91
diff --git a/block.c b/block.c
index 56bacc9e9f..f1cedac362 100644
--- a/block.c
+++ b/block.c
@@ -4563,8 +4563,16 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to)
return ret;
}
-void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
- Error **errp)
+/*
+ * With auto_skip=true bdrv_replace_node_common skips updating from parents
+ * if it creates a parent-child relation loop or if parent is block-job.
+ *
+ * With auto_skip=false the error is returned if from has a parent which should
+ * not be updated.
+ */
+static void bdrv_replace_node_common(BlockDriverState *from,
+ BlockDriverState *to,
+ bool auto_skip, Error **errp)
{
BdrvChild *c, *next;
GSList *list = NULL, *p;
@@ -4583,7 +4591,12 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
assert(c->bs == from);
if (!should_update_child(c, to)) {
- continue;
+ if (auto_skip) {
+ continue;
+ }
+ error_setg(errp, "Should not change '%s' link to '%s'",
+ c->name, from->node_name);
+ goto out;
}
if (c->frozen) {
error_setg(errp, "Cannot change '%s' link to '%s'",
@@ -4623,6 +4636,12 @@ out:
bdrv_unref(from);
}
+void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
+ Error **errp)
+{
+ return bdrv_replace_node_common(from, to, true, errp);
+}
+
/*
* Add new bs contents at the top of an image chain while the chain is
* live, while keeping required fields on the top layer.
@@ -4891,9 +4910,11 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
{
BlockDriverState *explicit_top = top;
bool update_inherits_from;
- BdrvChild *c, *next;
+ BdrvChild *c;
Error *local_err = NULL;
int ret = -EIO;
+ g_autoptr(GSList) updated_children = NULL;
+ GSList *p;
bdrv_ref(top);
bdrv_subtree_drained_begin(top);
@@ -4907,14 +4928,6 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
goto exit;
}
- /* This function changes all links that point to top and makes
- * them point to base. Check that none of them is frozen. */
- QLIST_FOREACH(c, &top->parents, next_parent) {
- if (c->frozen) {
- goto exit;
- }
- }
-
/* If 'base' recursively inherits from 'top' then we should set
* base->inherits_from to top->inherits_from after 'top' and all
* other intermediate nodes have been dropped.
@@ -4931,36 +4944,36 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
backing_file_str = base->filename;
}
- QLIST_FOREACH_SAFE(c, &top->parents, next_parent, next) {
- /* Check whether we are allowed to switch c from top to base */
- GSList *ignore_children = g_slist_prepend(NULL, c);
- ret = bdrv_check_update_perm(base, NULL, c->perm, c->shared_perm,
- ignore_children, NULL, &local_err);
- g_slist_free(ignore_children);
- if (ret < 0) {
- error_report_err(local_err);
- goto exit;
- }
+ QLIST_FOREACH(c, &top->parents, next_parent) {
+ updated_children = g_slist_prepend(updated_children, c);
+ }
+
+ bdrv_replace_node_common(top, base, false, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ goto exit;
+ }
+
+ for (p = updated_children; p; p = p->next) {
+ c = p->data;
- /* If so, update the backing file path in the image file */
if (c->klass->update_filename) {
ret = c->klass->update_filename(c, base, backing_file_str,
&local_err);
if (ret < 0) {
- bdrv_abort_perm_update(base);
+ /*
+ * TODO: Actually, we want to rollback all previous iterations
+ * of this loop, and (which is almost impossible) previous
+ * bdrv_replace_node()...
+ *
+ * Note, that c->klass->update_filename may lead to permission
+ * update, so it's a bad idea to call it inside permission
+ * update transaction of bdrv_replace_node.
+ */
error_report_err(local_err);
goto exit;
}
}
-
- /*
- * Do the actual switch in the in-memory graph.
- * Completes bdrv_check_update_perm() transaction internally.
- * c->frozen is false, we have checked that above.
- */
- bdrv_ref(base);
- bdrv_replace_child(c, base);
- bdrv_unref(top);
}
if (update_inherits_from) {
@@ -5091,8 +5104,13 @@ int64_t bdrv_getlength(BlockDriverState *bs)
{
int64_t ret = bdrv_nb_sectors(bs);
- ret = ret > INT64_MAX / BDRV_SECTOR_SIZE ? -EFBIG : ret;
- return ret < 0 ? ret : ret * BDRV_SECTOR_SIZE;
+ if (ret < 0) {
+ return ret;
+ }
+ if (ret > INT64_MAX / BDRV_SECTOR_SIZE) {
+ return -EFBIG;
+ }
+ return ret * BDRV_SECTOR_SIZE;
}
/* return 0 as number of sectors if no device present or error */
@@ -5782,6 +5800,7 @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp)
bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, NULL, errp);
if (ret < 0) {
+ bdrv_abort_perm_update(bs);
bs->open_flags |= BDRV_O_INACTIVE;
return ret;
}
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 54da719dd1..5fe6172da9 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -173,7 +173,7 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
{
struct add_rule_data *d = opaque;
BDRVBlkdebugState *s = d->s;
- const char* event_name;
+ const char *event_name;
int event;
struct BlkdebugRule *rule;
int64_t sector;
diff --git a/block/dmg-lzfse.c b/block/dmg-lzfse.c
index 19d25bc646..6798cf4fbf 100644
--- a/block/dmg-lzfse.c
+++ b/block/dmg-lzfse.c
@@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "dmg.h"
#include <lzfse.h>
diff --git a/block/dmg.c b/block/dmg.c
index 0d6c317296..ef35a505f2 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -559,7 +559,7 @@ static void dmg_refresh_limits(BlockDriverState *bs, Error **errp)
bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
}
-static inline int is_sector_in_chunk(BDRVDMGState* s,
+static inline int is_sector_in_chunk(BDRVDMGState *s,
uint32_t chunk_num, uint64_t sector_num)
{
if (chunk_num >= s->n_chunks || s->sectors[chunk_num] > sector_num ||
diff --git a/block/nfs.c b/block/nfs.c
index f86e660374..77905f516d 100644
--- a/block/nfs.c
+++ b/block/nfs.c
@@ -24,7 +24,9 @@
#include "qemu/osdep.h"
+#if !defined(_WIN32)
#include <poll.h>
+#endif
#include "qemu/config-file.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
@@ -58,7 +60,7 @@ typedef struct NFSClient {
bool has_zero_init;
AioContext *aio_context;
QemuMutex mutex;
- blkcnt_t st_blocks;
+ uint64_t st_blocks;
bool cache_used;
NFSServer *server;
char *path;
@@ -545,7 +547,9 @@ static int64_t nfs_client_open(NFSClient *client, BlockdevOptionsNfs *opts,
}
ret = DIV_ROUND_UP(st.st_size, BDRV_SECTOR_SIZE);
+#if !defined(_WIN32)
client->st_blocks = st.st_blocks;
+#endif
client->has_zero_init = S_ISREG(st.st_mode);
*strp = '/';
goto out;
@@ -706,6 +710,7 @@ static int nfs_has_zero_init(BlockDriverState *bs)
return client->has_zero_init;
}
+#if !defined(_WIN32)
/* Called (via nfs_service) with QemuMutex held. */
static void
nfs_get_allocated_file_size_cb(int ret, struct nfs_context *nfs, void *data,
@@ -748,6 +753,7 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
return (task.ret < 0 ? task.ret : st.st_blocks * 512);
}
+#endif
static int coroutine_fn
nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
@@ -800,7 +806,9 @@ static int nfs_reopen_prepare(BDRVReopenState *state,
nfs_get_error(client->context));
return ret;
}
+#if !defined(_WIN32)
client->st_blocks = st.st_blocks;
+#endif
}
return 0;
@@ -869,7 +877,10 @@ static BlockDriver bdrv_nfs = {
.create_opts = &nfs_create_opts,
.bdrv_has_zero_init = nfs_has_zero_init,
+/* libnfs does not provide the allocated filesize of a file on win32. */
+#if !defined(_WIN32)
.bdrv_get_allocated_file_size = nfs_get_allocated_file_size,
+#endif
.bdrv_co_truncate = nfs_file_co_truncate,
.bdrv_file_open = nfs_file_open,
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index aa87d3e99b..485b4cb92e 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1049,6 +1049,8 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
assert(l2_index + m->nb_clusters <= s->l2_slice_size);
+ assert(m->cow_end.offset + m->cow_end.nb_bytes <=
+ m->nb_clusters << s->cluster_bits);
for (i = 0; i < m->nb_clusters; i++) {
uint64_t offset = cluster_offset + ((uint64_t)i << s->cluster_bits);
/* if two concurrent writes happen to the same unallocated cluster
@@ -1070,8 +1072,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
if (has_subclusters(s) && !m->prealloc) {
uint64_t l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index + i);
unsigned written_from = m->cow_start.offset;
- unsigned written_to = m->cow_end.offset + m->cow_end.nb_bytes ?:
- m->nb_clusters << s->cluster_bits;
+ unsigned written_to = m->cow_end.offset + m->cow_end.nb_bytes;
int first_sc, last_sc;
/* Narrow written_from and written_to down to the current cluster */
written_from = MAX(written_from, i << s->cluster_bits);
diff --git a/block/qcow2.c b/block/qcow2.c
index 4274806a2a..3a90ef2786 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -269,7 +269,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
case QCOW2_EXT_MAGIC_FEATURE_TABLE:
if (p_feature_table != NULL) {
- void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature));
+ void *feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature));
ret = bdrv_pread(bs->file, offset , feature_table, ext.len);
if (ret < 0) {
error_setg_errno(errp, -ret, "ERROR: ext_feature_table: "
@@ -2361,15 +2361,26 @@ static bool merge_cow(uint64_t offset, unsigned bytes,
continue;
}
- /* The data (middle) region must be immediately after the
- * start region */
+ /*
+ * The write request should start immediately after the first
+ * COW region. This does not always happen because the area
+ * touched by the request can be larger than the one defined
+ * by @m (a single request can span an area consisting of a
+ * mix of previously unallocated and allocated clusters, that
+ * is why @l2meta is a list).
+ */
if (l2meta_cow_start(m) + m->cow_start.nb_bytes != offset) {
+ /* In this case the request starts before this region */
+ assert(offset < l2meta_cow_start(m));
+ assert(m->cow_start.nb_bytes == 0);
continue;
}
- /* The end region must be immediately after the data (middle)
- * region */
+ /* The write request should end immediately before the second
+ * COW region (see above for why it does not always happen) */
if (m->offset + m->cow_end.offset != offset + bytes) {
+ assert(offset + bytes > m->offset + m->cow_end.offset);
+ assert(m->cow_end.nb_bytes == 0);
continue;
}
@@ -3377,7 +3388,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
size_t cluster_size;
int version;
int refcount_order;
- uint64_t* refcount_table;
+ uint64_t *refcount_table;
int ret;
uint8_t compression_type = QCOW2_COMPRESSION_TYPE_ZLIB;
diff --git a/block/qcow2.h b/block/qcow2.h
index 125ea9679b..0678073b74 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -343,8 +343,8 @@ typedef struct BDRVQcow2State {
uint64_t l1_table_offset;
uint64_t *l1_table;
- Qcow2Cache* l2_table_cache;
- Qcow2Cache* refcount_block_cache;
+ Qcow2Cache *l2_table_cache;
+ Qcow2Cache *refcount_block_cache;
QEMUTimer *cache_clean_timer;
unsigned cache_clean_interval;
@@ -394,7 +394,7 @@ typedef struct BDRVQcow2State {
uint64_t autoclear_features;
size_t unknown_header_fields_size;
- void* unknown_header_fields;
+ void *unknown_header_fields;
QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
QTAILQ_HEAD (, Qcow2DiscardRegion) discards;
bool cache_discards;
@@ -435,17 +435,18 @@ typedef struct Qcow2COWRegion {
/**
* Describes an in-flight (part of a) write request that writes to clusters
- * that are not referenced in their L2 table yet.
+ * that need to have their L2 table entries updated (because they are
+ * newly allocated or need changes in their L2 bitmaps)
*/
typedef struct QCowL2Meta
{
- /** Guest offset of the first newly allocated cluster */
+ /** Guest offset of the first updated cluster */
uint64_t offset;
- /** Host offset of the first newly allocated cluster */
+ /** Host offset of the first updated cluster */
uint64_t alloc_offset;
- /** Number of newly allocated clusters */
+ /** Number of updated clusters */
int nb_clusters;
/** Do not free the old clusters */
@@ -458,14 +459,16 @@ typedef struct QCowL2Meta
CoQueue dependent_requests;
/**
- * The COW Region between the start of the first allocated cluster and the
- * area the guest actually writes to.
+ * The COW Region immediately before the area the guest actually
+ * writes to. This (part of the) write request starts at
+ * cow_start.offset + cow_start.nb_bytes.
*/
Qcow2COWRegion cow_start;
/**
- * The COW Region between the area the guest actually writes to and the
- * end of the last allocated cluster.
+ * The COW Region immediately after the area the guest actually
+ * writes to. This (part of the) write request ends at cow_end.offset
+ * (which must always be set even when cow_end.nb_bytes is 0).
*/
Qcow2COWRegion cow_end;
diff --git a/block/vpc.c b/block/vpc.c
index 890554277e..1ab55f9287 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -172,7 +172,7 @@ static QemuOptsList vpc_runtime_opts = {
static QemuOptsList vpc_create_opts;
-static uint32_t vpc_checksum(uint8_t* buf, size_t size)
+static uint32_t vpc_checksum(uint8_t *buf, size_t size)
{
uint32_t res = 0;
int i;
@@ -528,7 +528,7 @@ static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
*
* Returns 0 on success and < 0 on error
*/
-static int rewrite_footer(BlockDriverState* bs)
+static int rewrite_footer(BlockDriverState *bs)
{
int ret;
BDRVVPCState *s = bs->opaque;
@@ -548,7 +548,7 @@ static int rewrite_footer(BlockDriverState* bs)
*
* Returns the sectors' offset in the image file on success and < 0 on error
*/
-static int64_t alloc_block(BlockDriverState* bs, int64_t offset)
+static int64_t alloc_block(BlockDriverState *bs, int64_t offset)
{
BDRVVPCState *s = bs->opaque;
int64_t bat_offset;
@@ -781,8 +781,8 @@ static int coroutine_fn vpc_co_block_status(BlockDriverState *bs,
* the hardware EIDE and ATA-2 limit of 16 heads (max disk size of 127 GB)
* and instead allow up to 255 heads.
*/
-static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
- uint8_t* heads, uint8_t* secs_per_cyl)
+static int calculate_geometry(int64_t total_sectors, uint16_t *cyls,
+ uint8_t *heads, uint8_t *secs_per_cyl)
{
uint32_t cyls_times_heads;
diff --git a/configure b/configure
index 805f779150..4cef321d9d 100755
--- a/configure
+++ b/configure
@@ -1655,9 +1655,11 @@ Standard options:
--prefix=PREFIX install in PREFIX [$prefix]
--interp-prefix=PREFIX where to find shared libraries, etc.
use %M for cpu name [$interp_prefix]
- --target-list=LIST set target list (default: build everything)
+ --target-list=LIST set target list (default: build all non-deprecated)
$(echo Available targets: $default_target_list | \
fold -s -w 53 | sed -e 's/^/ /')
+$(echo Deprecated targets: $deprecated_targets_list | \
+ fold -s -w 53 | sed -e 's/^/ /')
--target-list-exclude=LIST exclude a set of targets from the default target-list
Advanced options (experts only):
diff --git a/docs/_templates/editpage.html b/docs/_templates/editpage.html
new file mode 100644
index 0000000000..4319b0f5ac
--- /dev/null
+++ b/docs/_templates/editpage.html
@@ -0,0 +1,5 @@
+<div id="editpage">
+ <ul>
+ <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/{{pagename}}.rst">Page source</a></li>
+ </ul>
+</div>
diff --git a/docs/conf.py b/docs/conf.py
index e584f68393..d40d8ff37b 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -177,6 +177,7 @@ html_theme_options = {
html_sidebars = {
'**': [
'about.html',
+ 'editpage.html',
'navigation.html',
'searchbox.html',
]
diff --git a/docs/devel/_templates/editpage.html b/docs/devel/_templates/editpage.html
new file mode 100644
index 0000000000..a86d22bca8
--- /dev/null
+++ b/docs/devel/_templates/editpage.html
@@ -0,0 +1,5 @@
+<div id="editpage">
+ <ul>
+ <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/devel/{{pagename}}.rst">Page source</a></li>
+ </ul>
+</div>
diff --git a/docs/devel/fuzzing.rst b/docs/devel/fuzzing.rst
new file mode 100644
index 0000000000..6096242d99
--- /dev/null
+++ b/docs/devel/fuzzing.rst
@@ -0,0 +1,236 @@
+========
+Fuzzing
+========
+
+This document describes the virtual-device fuzzing infrastructure in QEMU and
+how to use it to implement additional fuzzers.
+
+Basics
+------
+
+Fuzzing operates by passing inputs to an entry point/target function. The
+fuzzer tracks the code coverage triggered by the input. Based on these
+findings, the fuzzer mutates the input and repeats the fuzzing.
+
+To fuzz QEMU, we rely on libfuzzer. Unlike other fuzzers such as AFL, libfuzzer
+is an *in-process* fuzzer. For the developer, this means that it is their
+responsibility to ensure that state is reset between fuzzing-runs.
+
+Building the fuzzers
+--------------------
+
+*NOTE*: If possible, build a 32-bit binary. When forking, the 32-bit fuzzer is
+much faster, since the page-map has a smaller size. This is due to the fact that
+AddressSanitizer maps ~20TB of memory, as part of its detection. This results
+in a large page-map, and a much slower ``fork()``.
+
+To build the fuzzers, install a recent version of clang:
+Configure with (substitute the clang binaries with the version you installed).
+Here, enable-sanitizers, is optional but it allows us to reliably detect bugs
+such as out-of-bounds accesses, use-after-frees, double-frees etc.::
+
+ CC=clang-8 CXX=clang++-8 /path/to/configure --enable-fuzzing \
+ --enable-sanitizers
+
+Fuzz targets are built similarly to system targets::
+
+ make qemu-fuzz-i386
+
+This builds ``./qemu-fuzz-i386``
+
+The first option to this command is: ``--fuzz-target=FUZZ_NAME``
+To list all of the available fuzzers run ``qemu-fuzz-i386`` with no arguments.
+
+For example::
+
+ ./qemu-fuzz-i386 --fuzz-target=virtio-scsi-fuzz
+
+Internally, libfuzzer parses all arguments that do not begin with ``"--"``.
+Information about these is available by passing ``-help=1``
+
+Now the only thing left to do is wait for the fuzzer to trigger potential
+crashes.
+
+Useful libFuzzer flags
+----------------------
+
+As mentioned above, libFuzzer accepts some arguments. Passing ``-help=1`` will
+list the available arguments. In particular, these arguments might be helpful:
+
+* ``CORPUS_DIR/`` : Specify a directory as the last argument to libFuzzer.
+ libFuzzer stores each "interesting" input in this corpus directory. The next
+ time you run libFuzzer, it will read all of the inputs from the corpus, and
+ continue fuzzing from there. You can also specify multiple directories.
+ libFuzzer loads existing inputs from all specified directories, but will only
+ write new ones to the first one specified.
+
+* ``-max_len=4096`` : specify the maximum byte-length of the inputs libFuzzer
+ will generate.
+
+* ``-close_fd_mask={1,2,3}`` : close, stderr, or both. Useful for targets that
+ trigger many debug/error messages, or create output on the serial console.
+
+* ``-jobs=4 -workers=4`` : These arguments configure libFuzzer to run 4 fuzzers in
+ parallel (4 fuzzing jobs in 4 worker processes). Alternatively, with only
+ ``-jobs=N``, libFuzzer automatically spawns a number of workers less than or equal
+ to half the available CPU cores. Replace 4 with a number appropriate for your
+ machine. Make sure to specify a ``CORPUS_DIR``, which will allow the parallel
+ fuzzers to share information about the interesting inputs they find.
+
+* ``-use_value_profile=1`` : For each comparison operation, libFuzzer computes
+ ``(caller_pc&4095) | (popcnt(Arg1 ^ Arg2) << 12)`` and places this in the
+ coverage table. Useful for targets with "magic" constants. If Arg1 came from
+ the fuzzer's input and Arg2 is a magic constant, then each time the Hamming
+ distance between Arg1 and Arg2 decreases, libFuzzer adds the input to the
+ corpus.
+
+* ``-shrink=1`` : Tries to make elements of the corpus "smaller". Might lead to
+ better coverage performance, depending on the target.
+
+Note that libFuzzer's exact behavior will depend on the version of
+clang and libFuzzer used to build the device fuzzers.
+
+Generating Coverage Reports
+---------------------------
+
+Code coverage is a crucial metric for evaluating a fuzzer's performance.
+libFuzzer's output provides a "cov: " column that provides a total number of
+unique blocks/edges covered. To examine coverage on a line-by-line basis we
+can use Clang coverage:
+
+ 1. Configure libFuzzer to store a corpus of all interesting inputs (see
+ CORPUS_DIR above)
+ 2. ``./configure`` the QEMU build with ::
+
+ --enable-fuzzing \
+ --extra-cflags="-fprofile-instr-generate -fcoverage-mapping"
+
+ 3. Re-run the fuzzer. Specify $CORPUS_DIR/* as an argument, telling libfuzzer
+ to execute all of the inputs in $CORPUS_DIR and exit. Once the process
+ exits, you should find a file, "default.profraw" in the working directory.
+ 4. Execute these commands to generate a detailed HTML coverage-report::
+
+ llvm-profdata merge -output=default.profdata default.profraw
+ llvm-cov show ./path/to/qemu-fuzz-i386 -instr-profile=default.profdata \
+ --format html -output-dir=/path/to/output/report
+
+Adding a new fuzzer
+-------------------
+
+Coverage over virtual devices can be improved by adding additional fuzzers.
+Fuzzers are kept in ``tests/qtest/fuzz/`` and should be added to
+``tests/qtest/fuzz/Makefile.include``
+
+Fuzzers can rely on both qtest and libqos to communicate with virtual devices.
+
+1. Create a new source file. For example ``tests/qtest/fuzz/foo-device-fuzz.c``.
+
+2. Write the fuzzing code using the libqtest/libqos API. See existing fuzzers
+ for reference.
+
+3. Register the fuzzer in ``tests/fuzz/Makefile.include`` by appending the
+ corresponding object to fuzz-obj-y
+
+Fuzzers can be more-or-less thought of as special qtest programs which can
+modify the qtest commands and/or qtest command arguments based on inputs
+provided by libfuzzer. Libfuzzer passes a byte array and length. Commonly the
+fuzzer loops over the byte-array interpreting it as a list of qtest commands,
+addresses, or values.
+
+The Generic Fuzzer
+------------------
+
+Writing a fuzz target can be a lot of effort (especially if a device driver has
+not be built-out within libqos). Many devices can be fuzzed to some degree,
+without any device-specific code, using the generic-fuzz target.
+
+The generic-fuzz target is capable of fuzzing devices over their PIO, MMIO,
+and DMA input-spaces. To apply the generic-fuzz to a device, we need to define
+two env-variables, at minimum:
+
+* ``QEMU_FUZZ_ARGS=`` is the set of QEMU arguments used to configure a machine, with
+ the device attached. For example, if we want to fuzz the virtio-net device
+ attached to a pc-i440fx machine, we can specify::
+
+ QEMU_FUZZ_ARGS="-M pc -nodefaults -netdev user,id=user0 \
+ -device virtio-net,netdev=user0"
+
+* ``QEMU_FUZZ_OBJECTS=`` is a set of space-delimited strings used to identify
+ the MemoryRegions that will be fuzzed. These strings are compared against
+ MemoryRegion names and MemoryRegion owner names, to decide whether each
+ MemoryRegion should be fuzzed. These strings support globbing. For the
+ virtio-net example, we could use one of ::
+
+ QEMU_FUZZ_OBJECTS='virtio-net'
+ QEMU_FUZZ_OBJECTS='virtio*'
+ QEMU_FUZZ_OBJECTS='virtio* pcspk' # Fuzz the virtio devices and the speaker
+ QEMU_FUZZ_OBJECTS='*' # Fuzz the whole machine``
+
+The ``"info mtree"`` and ``"info qom-tree"`` monitor commands can be especially
+useful for identifying the ``MemoryRegion`` and ``Object`` names used for
+matching.
+
+As a generic rule-of-thumb, the more ``MemoryRegions``/Devices we match, the
+greater the input-space, and the smaller the probability of finding crashing
+inputs for individual devices. As such, it is usually a good idea to limit the
+fuzzer to only a few ``MemoryRegions``.
+
+To ensure that these env variables have been configured correctly, we can use::
+
+ ./qemu-fuzz-i386 --fuzz-target=generic-fuzz -runs=0
+
+The output should contain a complete list of matched MemoryRegions.
+
+Implementation Details / Fuzzer Lifecycle
+-----------------------------------------
+
+The fuzzer has two entrypoints that libfuzzer calls. libfuzzer provides it's
+own ``main()``, which performs some setup, and calls the entrypoints:
+
+``LLVMFuzzerInitialize``: called prior to fuzzing. Used to initialize all of the
+necessary state
+
+``LLVMFuzzerTestOneInput``: called for each fuzzing run. Processes the input and
+resets the state at the end of each run.
+
+In more detail:
+
+``LLVMFuzzerInitialize`` parses the arguments to the fuzzer (must start with two
+dashes, so they are ignored by libfuzzer ``main()``). Currently, the arguments
+select the fuzz target. Then, the qtest client is initialized. If the target
+requires qos, qgraph is set up and the QOM/LIBQOS modules are initialized.
+Then the QGraph is walked and the QEMU cmd_line is determined and saved.
+
+After this, the ``vl.c:qemu_main`` is called to set up the guest. There are
+target-specific hooks that can be called before and after qemu_main, for
+additional setup(e.g. PCI setup, or VM snapshotting).
+
+``LLVMFuzzerTestOneInput``: Uses qtest/qos functions to act based on the fuzz
+input. It is also responsible for manually calling ``main_loop_wait`` to ensure
+that bottom halves are executed and any cleanup required before the next input.
+
+Since the same process is reused for many fuzzing runs, QEMU state needs to
+be reset at the end of each run. There are currently two implemented
+options for resetting state:
+
+- Reboot the guest between runs.
+ - *Pros*: Straightforward and fast for simple fuzz targets.
+
+ - *Cons*: Depending on the device, does not reset all device state. If the
+ device requires some initialization prior to being ready for fuzzing (common
+ for QOS-based targets), this initialization needs to be done after each
+ reboot.
+
+ - *Example target*: ``i440fx-qtest-reboot-fuzz``
+
+- Run each test case in a separate forked process and copy the coverage
+ information back to the parent. This is fairly similar to AFL's "deferred"
+ fork-server mode [3]
+
+ - *Pros*: Relatively fast. Devices only need to be initialized once. No need to
+ do slow reboots or vmloads.
+
+ - *Cons*: Not officially supported by libfuzzer. Does not work well for
+ devices that rely on dedicated threads.
+
+ - *Example target*: ``virtio-net-fork-fuzz``
diff --git a/docs/devel/fuzzing.txt b/docs/devel/fuzzing.txt
deleted file mode 100644
index 03585c1a9b..0000000000
--- a/docs/devel/fuzzing.txt
+++ /dev/null
@@ -1,214 +0,0 @@
-= Fuzzing =
-
-== Introduction ==
-
-This document describes the virtual-device fuzzing infrastructure in QEMU and
-how to use it to implement additional fuzzers.
-
-== Basics ==
-
-Fuzzing operates by passing inputs to an entry point/target function. The
-fuzzer tracks the code coverage triggered by the input. Based on these
-findings, the fuzzer mutates the input and repeats the fuzzing.
-
-To fuzz QEMU, we rely on libfuzzer. Unlike other fuzzers such as AFL, libfuzzer
-is an _in-process_ fuzzer. For the developer, this means that it is their
-responsibility to ensure that state is reset between fuzzing-runs.
-
-== Building the fuzzers ==
-
-NOTE: If possible, build a 32-bit binary. When forking, the 32-bit fuzzer is
-much faster, since the page-map has a smaller size. This is due to the fact that
-AddressSanitizer mmaps ~20TB of memory, as part of its detection. This results
-in a large page-map, and a much slower fork().
-
-To build the fuzzers, install a recent version of clang:
-Configure with (substitute the clang binaries with the version you installed).
-Here, enable-sanitizers, is optional but it allows us to reliably detect bugs
-such as out-of-bounds accesses, use-after-frees, double-frees etc.
-
- CC=clang-8 CXX=clang++-8 /path/to/configure --enable-fuzzing \
- --enable-sanitizers
-
-Fuzz targets are built similarly to system/softmmu:
-
- make i386-softmmu/fuzz
-
-This builds ./i386-softmmu/qemu-fuzz-i386
-
-The first option to this command is: --fuzz-target=FUZZ_NAME
-To list all of the available fuzzers run qemu-fuzz-i386 with no arguments.
-
-For example:
- ./i386-softmmu/qemu-fuzz-i386 --fuzz-target=virtio-scsi-fuzz
-
-Internally, libfuzzer parses all arguments that do not begin with "--".
-Information about these is available by passing -help=1
-
-Now the only thing left to do is wait for the fuzzer to trigger potential
-crashes.
-
-== Useful libFuzzer flags ==
-
-As mentioned above, libFuzzer accepts some arguments. Passing -help=1 will list
-the available arguments. In particular, these arguments might be helpful:
-
-$CORPUS_DIR/ : Specify a directory as the last argument to libFuzzer. libFuzzer
-stores each "interesting" input in this corpus directory. The next time you run
-libFuzzer, it will read all of the inputs from the corpus, and continue fuzzing
-from there. You can also specify multiple directories. libFuzzer loads existing
-inputs from all specified directories, but will only write new ones to the
-first one specified.
-
--max_len=4096 : specify the maximum byte-length of the inputs libFuzzer will
-generate.
-
--close_fd_mask={1,2,3} : close, stderr, or both. Useful for targets that
-trigger many debug/error messages, or create output on the serial console.
-
--jobs=4 -workers=4 : These arguments configure libFuzzer to run 4 fuzzers in
-parallel (4 fuzzing jobs in 4 worker processes). Alternatively, with only
--jobs=N, libFuzzer automatically spawns a number of workers less than or equal
-to half the available CPU cores. Replace 4 with a number appropriate for your
-machine. Make sure to specify a $CORPUS_DIR, which will allow the parallel
-fuzzers to share information about the interesting inputs they find.
-
--use_value_profile=1 : For each comparison operation, libFuzzer computes
-(caller_pc&4095) | (popcnt(Arg1 ^ Arg2) << 12) and places this in the coverage
-table. Useful for targets with "magic" constants. If Arg1 came from the fuzzer's
-input and Arg2 is a magic constant, then each time the Hamming distance
-between Arg1 and Arg2 decreases, libFuzzer adds the input to the corpus.
-
--shrink=1 : Tries to make elements of the corpus "smaller". Might lead to
-better coverage performance, depending on the target.
-
-Note that libFuzzer's exact behavior will depend on the version of
-clang and libFuzzer used to build the device fuzzers.
-
-== Generating Coverage Reports ==
-Code coverage is a crucial metric for evaluating a fuzzer's performance.
-libFuzzer's output provides a "cov: " column that provides a total number of
-unique blocks/edges covered. To examine coverage on a line-by-line basis we
-can use Clang coverage:
-
- 1. Configure libFuzzer to store a corpus of all interesting inputs (see
- CORPUS_DIR above)
- 2. ./configure the QEMU build with:
- --enable-fuzzing \
- --extra-cflags="-fprofile-instr-generate -fcoverage-mapping"
- 3. Re-run the fuzzer. Specify $CORPUS_DIR/* as an argument, telling libfuzzer
- to execute all of the inputs in $CORPUS_DIR and exit. Once the process
- exits, you should find a file, "default.profraw" in the working directory.
- 4. Execute these commands to generate a detailed HTML coverage-report:
- llvm-profdata merge -output=default.profdata default.profraw
- llvm-cov show ./path/to/qemu-fuzz-i386 -instr-profile=default.profdata \
- --format html -output-dir=/path/to/output/report
-
-== Adding a new fuzzer ==
-Coverage over virtual devices can be improved by adding additional fuzzers.
-Fuzzers are kept in tests/qtest/fuzz/ and should be added to
-tests/qtest/fuzz/Makefile.include
-
-Fuzzers can rely on both qtest and libqos to communicate with virtual devices.
-
-1. Create a new source file. For example ``tests/qtest/fuzz/foo-device-fuzz.c``.
-
-2. Write the fuzzing code using the libqtest/libqos API. See existing fuzzers
-for reference.
-
-3. Register the fuzzer in ``tests/fuzz/Makefile.include`` by appending the
-corresponding object to fuzz-obj-y
-
-Fuzzers can be more-or-less thought of as special qtest programs which can
-modify the qtest commands and/or qtest command arguments based on inputs
-provided by libfuzzer. Libfuzzer passes a byte array and length. Commonly the
-fuzzer loops over the byte-array interpreting it as a list of qtest commands,
-addresses, or values.
-
-== The Generic Fuzzer ==
-Writing a fuzz target can be a lot of effort (especially if a device driver has
-not be built-out within libqos). Many devices can be fuzzed to some degree,
-without any device-specific code, using the generic-fuzz target.
-
-The generic-fuzz target is capable of fuzzing devices over their PIO, MMIO,
-and DMA input-spaces. To apply the generic-fuzz to a device, we need to define
-two env-variables, at minimum:
-
-QEMU_FUZZ_ARGS= is the set of QEMU arguments used to configure a machine, with
-the device attached. For example, if we want to fuzz the virtio-net device
-attached to a pc-i440fx machine, we can specify:
-QEMU_FUZZ_ARGS="-M pc -nodefaults -netdev user,id=user0 \
- -device virtio-net,netdev=user0"
-
-QEMU_FUZZ_OBJECTS= is a set of space-delimited strings used to identify the
-MemoryRegions that will be fuzzed. These strings are compared against
-MemoryRegion names and MemoryRegion owner names, to decide whether each
-MemoryRegion should be fuzzed. These strings support globbing. For the
-virtio-net example, we could use QEMU_FUZZ_OBJECTS=
- * 'virtio-net'
- * 'virtio*'
- * 'virtio* pcspk' (Fuzz the virtio devices and the PC speaker...)
- * '*' (Fuzz the whole machine)
-
-The "info mtree" and "info qom-tree" monitor commands can be especially useful
-for identifying the MemoryRegion and Object names used for matching.
-
-As a generic rule-of-thumb, the more MemoryRegions/Devices we match, the greater
-the input-space, and the smaller the probability of finding crashing inputs for
-individual devices. As such, it is usually a good idea to limit the fuzzer to
-only a few MemoryRegions.
-
-To ensure that these env variables have been configured correctly, we can use:
-
-./qemu-fuzz-i386 --fuzz-target=generic-fuzz -runs=0
-
-The output should contain a complete list of matched MemoryRegions.
-
-= Implementation Details =
-
-== The Fuzzer's Lifecycle ==
-
-The fuzzer has two entrypoints that libfuzzer calls. libfuzzer provides it's
-own main(), which performs some setup, and calls the entrypoints:
-
-LLVMFuzzerInitialize: called prior to fuzzing. Used to initialize all of the
-necessary state
-
-LLVMFuzzerTestOneInput: called for each fuzzing run. Processes the input and
-resets the state at the end of each run.
-
-In more detail:
-
-LLVMFuzzerInitialize parses the arguments to the fuzzer (must start with two
-dashes, so they are ignored by libfuzzer main()). Currently, the arguments
-select the fuzz target. Then, the qtest client is initialized. If the target
-requires qos, qgraph is set up and the QOM/LIBQOS modules are initialized.
-Then the QGraph is walked and the QEMU cmd_line is determined and saved.
-
-After this, the vl.c:qemu__main is called to set up the guest. There are
-target-specific hooks that can be called before and after qemu_main, for
-additional setup(e.g. PCI setup, or VM snapshotting).
-
-LLVMFuzzerTestOneInput: Uses qtest/qos functions to act based on the fuzz
-input. It is also responsible for manually calling the main loop/main_loop_wait
-to ensure that bottom halves are executed and any cleanup required before the
-next input.
-
-Since the same process is reused for many fuzzing runs, QEMU state needs to
-be reset at the end of each run. There are currently two implemented
-options for resetting state:
-1. Reboot the guest between runs.
- Pros: Straightforward and fast for simple fuzz targets.
- Cons: Depending on the device, does not reset all device state. If the
- device requires some initialization prior to being ready for fuzzing
- (common for QOS-based targets), this initialization needs to be done after
- each reboot.
- Example target: i440fx-qtest-reboot-fuzz
-2. Run each test case in a separate forked process and copy the coverage
- information back to the parent. This is fairly similar to AFL's "deferred"
- fork-server mode [3]
- Pros: Relatively fast. Devices only need to be initialized once. No need
- to do slow reboots or vmloads.
- Cons: Not officially supported by libfuzzer. Does not work well for devices
- that rely on dedicated threads.
- Example target: virtio-net-fork-fuzz
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
index 77baae5c77..f10ed77e4c 100644
--- a/docs/devel/index.rst
+++ b/docs/devel/index.rst
@@ -22,6 +22,7 @@ Contents:
stable-process
testing
qtest
+ fuzzing
decodetree
secure-coding-practices
tcg
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index c6438c6aa9..6906a06ad2 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -393,7 +393,7 @@ is identical on the wire to:
{ 'enum': 'Enum', 'data': ['one', 'two'] }
{ 'struct': 'Branch1', 'data': { 'data': 'str' } }
{ 'struct': 'Branch2', 'data': { 'data': 'int' } }
- { 'union': 'Flat': 'base': { 'type': 'Enum' }, 'discriminator': 'type',
+ { 'union': 'Flat', 'base': { 'type': 'Enum' }, 'discriminator': 'type',
'data': { 'one': 'Branch1', 'two': 'Branch2' } }
The optional 'if' member specifies a conditional. See "Configuring
@@ -590,6 +590,8 @@ When in doubt, do not implement OOB execution support.
Member 'allow-preconfig' declares whether the command is available
before the machine is built. It defaults to false. For example:
+ { 'enum': 'QMPCapability',
+ 'data': [ 'oob' ] }
{ 'command': 'qmp_capabilities',
'data': { '*enable': [ 'QMPCapability' ] },
'allow-preconfig': true }
@@ -824,7 +826,7 @@ Example: a struct with conditional feature 'allow-negative-numbers'
{ 'struct': 'TestType',
'data': { 'number': 'int' },
'features': [ { 'name': 'allow-negative-numbers',
- 'if' 'defined(IFCOND)' } ] }
+ 'if': 'defined(IFCOND)' } ] }
Please note that you are responsible to ensure that the C code will
compile with an arbitrary combination of conditions, since the
diff --git a/docs/interop/_templates/editpage.html b/docs/interop/_templates/editpage.html
new file mode 100644
index 0000000000..215e562681
--- /dev/null
+++ b/docs/interop/_templates/editpage.html
@@ -0,0 +1,5 @@
+<div id="editpage">
+ <ul>
+ <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/interop/{{pagename}}.rst">Page source</a></li>
+ </ul>
+</div>
diff --git a/docs/specs/_templates/editpage.html b/docs/specs/_templates/editpage.html
new file mode 100644
index 0000000000..aaa468aa98
--- /dev/null
+++ b/docs/specs/_templates/editpage.html
@@ -0,0 +1,5 @@
+<div id="editpage">
+ <ul>
+ <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/specs/{{pagename}}.rst">Page source</a></li>
+ </ul>
+</div>
diff --git a/docs/system/_templates/editpage.html b/docs/system/_templates/editpage.html
new file mode 100644
index 0000000000..6586b2e257
--- /dev/null
+++ b/docs/system/_templates/editpage.html
@@ -0,0 +1,5 @@
+<div id="editpage">
+ <ul>
+ <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/system/{{pagename}}.rst">Page source</a></li>
+ </ul>
+</div>
diff --git a/docs/system/arm/sbsa.rst b/docs/system/arm/sbsa.rst
new file mode 100644
index 0000000000..b8ecfdb62f
--- /dev/null
+++ b/docs/system/arm/sbsa.rst
@@ -0,0 +1,32 @@
+Arm Server Base System Architecture Reference board (``sbsa-ref``)
+==================================================================
+
+While the `virt` board is a generic board platform that doesn't match
+any real hardware the `sbsa-ref` board intends to look like real
+hardware. The `Server Base System Architecture
+<https://developer.arm.com/documentation/den0029/latest>` defines a
+minimum base line of hardware support and importantly how the firmware
+reports that to any operating system. It is a static system that
+reports a very minimal DT to the firmware for non-discoverable
+information about components affected by the qemu command line (i.e.
+cpus and memory). As a result it must have a firmware specifically
+built to expect a certain hardware layout (as you would in a real
+machine).
+
+It is intended to be a machine for developing firmware and testing
+standards compliance with operating systems.
+
+Supported devices
+"""""""""""""""""
+
+The sbsa-ref board supports:
+
+ - A configurable number of AArch64 CPUs
+ - GIC version 3
+ - System bus AHCI controller
+ - System bus EHCI controller
+ - CDROM and hard disc on AHCI bus
+ - E1000E ethernet card on PCIe bus
+ - VGA display adaptor on PCIe bus
+ - A generic SBSA watchdog device
+
diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst
index 8c1dc7645d..bbaae0d97c 100644
--- a/docs/system/deprecated.rst
+++ b/docs/system/deprecated.rst
@@ -310,6 +310,13 @@ to build binaries for it.
``Icelake-Client`` CPU Models are deprecated. Use ``Icelake-Server`` CPU
Models instead.
+MIPS ``I7200`` CPU Model (since 5.2)
+''''''''''''''''''''''''''''''''''''
+
+The ``I7200`` guest CPU relies on the nanoMIPS ISA, which is deprecated
+(the ISA has never been upstreamed to a compiler toolchain). Therefore
+this CPU is also deprecated.
+
System emulator devices
-----------------------
@@ -407,6 +414,13 @@ The ``ppc64abi32`` architecture has a number of issues which regularly
trip up our CI testing and is suspected to be quite broken. For that
reason the maintainers strongly suspect no one actually uses it.
+MIPS ``I7200`` CPU (since 5.2)
+''''''''''''''''''''''''''''''
+
+The ``I7200`` guest CPU relies on the nanoMIPS ISA, which is deprecated
+(the ISA has never been upstreamed to a compiler toolchain). Therefore
+this CPU is also deprecated.
+
Related binaries
----------------
@@ -471,6 +485,15 @@ versions, aliases will point to newer CPU model versions
depending on the machine type, so management software must
resolve CPU model aliases before starting a virtual machine.
+Guest Emulator ISAs
+-------------------
+
+nanoMIPS ISA
+''''''''''''
+
+The ``nanoMIPS`` ISA has never been upstreamed to any compiler toolchain.
+As it is hard to generate binaries for it, declare it deprecated.
+
Recently removed features
=========================
diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst
index fdcf25c237..a0d5c57799 100644
--- a/docs/system/target-arm.rst
+++ b/docs/system/target-arm.rst
@@ -79,6 +79,7 @@ undocumented; you can get a complete list by running
arm/mps2
arm/musca
arm/realview
+ arm/sbsa
arm/versatile
arm/vexpress
arm/aspeed
diff --git a/docs/tools/_templates/editpage.html b/docs/tools/_templates/editpage.html
new file mode 100644
index 0000000000..2a9c8fc92b
--- /dev/null
+++ b/docs/tools/_templates/editpage.html
@@ -0,0 +1,5 @@
+<div id="editpage">
+ <ul>
+ <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/tools/{{pagename}}.rst">Page source</a></li>
+ </ul>
+</div>
diff --git a/docs/user/_templates/editpage.html b/docs/user/_templates/editpage.html
new file mode 100644
index 0000000000..1f5ee01e60
--- /dev/null
+++ b/docs/user/_templates/editpage.html
@@ -0,0 +1,5 @@
+<div id="editpage">
+ <ul>
+ <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/user/{{pagename}}.rst">Page source</a></li>
+ </ul>
+</div>
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index fdf4464b94..7d022eeefd 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -6,7 +6,6 @@ config ARM_VIRT
imply VFIO_PLATFORM
imply VFIO_XGMAC
imply TPM_TIS_SYSBUS
- select A15MPCORE
select ACPI
select ARM_SMMUV3
select GPIO_KEY
@@ -94,6 +93,7 @@ config MUSCA
config MUSICPAL
bool
+ select OR_IRQ
select BITBANG_I2C
select MARVELL_88W8618
select PTIMER
@@ -291,6 +291,7 @@ config ZYNQ
config ARM_V7M
bool
+ select PTIMER
config ALLWINNER_A10
bool
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
index a93da37dcb..baac027659 100644
--- a/hw/arm/armsse.c
+++ b/hw/arm/armsse.c
@@ -1074,7 +1074,8 @@ static void armsse_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(dev_splitter, 0));
qdev_connect_gpio_out(dev_splitter, 0,
qdev_get_gpio_in_named(dev_secctl,
- "mpc_status", 0));
+ "mpc_status",
+ i - IOTS_NUM_EXP_MPC));
}
qdev_connect_gpio_out(dev_splitter, 1,
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 5eb3f969fb..458b1cbeb7 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -27,6 +27,7 @@
#include "ui/console.h"
#include "hw/i2c/i2c.h"
#include "hw/irq.h"
+#include "hw/or-irq.h"
#include "hw/audio/wm8750.h"
#include "sysemu/block-backend.h"
#include "sysemu/runstate.h"
@@ -77,8 +78,7 @@
#define MP_TIMER4_IRQ 7
#define MP_EHCI_IRQ 8
#define MP_ETH_IRQ 9
-#define MP_UART1_IRQ 11
-#define MP_UART2_IRQ 11
+#define MP_UART_SHARED_IRQ 11
#define MP_GPIO_IRQ 12
#define MP_RTC_IRQ 28
#define MP_AUDIO_IRQ 30
@@ -1587,8 +1587,9 @@ static struct arm_boot_info musicpal_binfo = {
static void musicpal_init(MachineState *machine)
{
ARMCPU *cpu;
- qemu_irq pic[32];
DeviceState *dev;
+ DeviceState *pic;
+ DeviceState *uart_orgate;
DeviceState *i2c_dev;
DeviceState *lcd_dev;
DeviceState *key_dev;
@@ -1618,18 +1619,26 @@ static void musicpal_init(MachineState *machine)
&error_fatal);
memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram);
- dev = sysbus_create_simple(TYPE_MV88W8618_PIC, MP_PIC_BASE,
+ pic = sysbus_create_simple(TYPE_MV88W8618_PIC, MP_PIC_BASE,
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
- for (i = 0; i < 32; i++) {
- pic[i] = qdev_get_gpio_in(dev, i);
- }
- sysbus_create_varargs(TYPE_MV88W8618_PIT, MP_PIT_BASE, pic[MP_TIMER1_IRQ],
- pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ],
- pic[MP_TIMER4_IRQ], NULL);
-
- serial_mm_init(address_space_mem, MP_UART1_BASE, 2, pic[MP_UART1_IRQ],
+ sysbus_create_varargs(TYPE_MV88W8618_PIT, MP_PIT_BASE,
+ qdev_get_gpio_in(pic, MP_TIMER1_IRQ),
+ qdev_get_gpio_in(pic, MP_TIMER2_IRQ),
+ qdev_get_gpio_in(pic, MP_TIMER3_IRQ),
+ qdev_get_gpio_in(pic, MP_TIMER4_IRQ), NULL);
+
+ /* Logically OR both UART IRQs together */
+ uart_orgate = DEVICE(object_new(TYPE_OR_IRQ));
+ object_property_set_int(OBJECT(uart_orgate), "num-lines", 2, &error_fatal);
+ qdev_realize_and_unref(uart_orgate, NULL, &error_fatal);
+ qdev_connect_gpio_out(DEVICE(uart_orgate), 0,
+ qdev_get_gpio_in(pic, MP_UART_SHARED_IRQ));
+
+ serial_mm_init(address_space_mem, MP_UART1_BASE, 2,
+ qdev_get_gpio_in(uart_orgate, 0),
1825000, serial_hd(0), DEVICE_NATIVE_ENDIAN);
- serial_mm_init(address_space_mem, MP_UART2_BASE, 2, pic[MP_UART2_IRQ],
+ serial_mm_init(address_space_mem, MP_UART2_BASE, 2,
+ qdev_get_gpio_in(uart_orgate, 1),
1825000, serial_hd(1), DEVICE_NATIVE_ENDIAN);
/* Register flash */
@@ -1665,14 +1674,15 @@ static void musicpal_init(MachineState *machine)
OBJECT(get_system_memory()), &error_fatal);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[MP_ETH_IRQ]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
+ qdev_get_gpio_in(pic, MP_ETH_IRQ));
sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL);
sysbus_create_simple(TYPE_MUSICPAL_MISC, MP_MISC_BASE, NULL);
dev = sysbus_create_simple(TYPE_MUSICPAL_GPIO, MP_GPIO_BASE,
- pic[MP_GPIO_IRQ]);
+ qdev_get_gpio_in(pic, MP_GPIO_IRQ));
i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL);
i2c = (I2CBus *)qdev_get_child_bus(i2c_dev, "i2c");
@@ -1704,7 +1714,7 @@ static void musicpal_init(MachineState *machine)
NULL);
sysbus_realize_and_unref(s, &error_fatal);
sysbus_mmio_map(s, 0, MP_AUDIO_BASE);
- sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]);
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(pic, MP_AUDIO_IRQ));
musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE;
arm_load_kernel(cpu, machine, &musicpal_binfo);
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
index 76fd7fe985..387eea4d44 100644
--- a/hw/arm/nseries.c
+++ b/hw/arm/nseries.c
@@ -789,16 +789,6 @@ static void n8x0_cbus_setup(struct n800_s *s)
cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1));
}
-static void n8x0_uart_setup(struct n800_s *s)
-{
- Chardev *radio = qemu_chr_new("bt-dummy-uart", "null", NULL);
- /*
- * Note: We used to connect N8X0_BT_RESET_GPIO and N8X0_BT_WKUP_GPIO
- * here, but this code has been removed with the bluetooth backend.
- */
- omap_uart_attach(s->mpu->uart[BT_UART], radio);
-}
-
static void n8x0_usb_setup(struct n800_s *s)
{
SysBusDevice *dev;
@@ -1362,7 +1352,6 @@ static void n8x0_init(MachineState *machine,
n8x0_spi_setup(s);
n8x0_dss_setup(s);
n8x0_cbus_setup(s);
- n8x0_uart_setup(s);
if (machine_usb(machine)) {
n8x0_usb_setup(s);
}
@@ -1380,7 +1369,8 @@ static void n8x0_init(MachineState *machine,
/* No, wait, better start at the ROM. */
s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
- /* This is intended for loading the `secondary.bin' program from
+ /*
+ * This is intended for loading the `secondary.bin' program from
* Nokia images (the NOLO bootloader). The entry point seems
* to be at OMAP2_Q2_BASE + 0x400000.
*
@@ -1388,9 +1378,15 @@ static void n8x0_init(MachineState *machine,
* for them the entry point needs to be set to OMAP2_SRAM_BASE.
*
* The code above is for loading the `zImage' file from Nokia
- * images. */
- load_image_targphys(option_rom[0].name, OMAP2_Q2_BASE + 0x400000,
- machine->ram_size - 0x400000);
+ * images.
+ */
+ if (load_image_targphys(option_rom[0].name,
+ OMAP2_Q2_BASE + 0x400000,
+ machine->ram_size - 0x400000) < 0) {
+ error_report("Failed to load secondary bootloader %s",
+ option_rom[0].name);
+ exit(EXIT_FAILURE);
+ }
n800_setup_nolo_tags(nolo_tags);
cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000);
diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c
index a4f3344db2..9cd41bf56d 100644
--- a/hw/arm/stm32f205_soc.c
+++ b/hw/arm/stm32f205_soc.c
@@ -117,7 +117,6 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
}
busdev = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(busdev, 0, 0x40013800);
- sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, 71));
/* Attach UART (uses USART registers) and USART controllers */
for (i = 0; i < STM_NUM_USARTS; i++) {
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index fa2cba744b..01b657b1c5 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -452,7 +452,7 @@ static uint16_t nvme_map_sgl_data(NvmeCtrl *n, QEMUSGList *qsg,
* segments and/or descriptors. The controller might accept
* ignoring the rest of the SGL.
*/
- uint16_t sgls = le16_to_cpu(n->id_ctrl.sgls);
+ uint32_t sgls = le32_to_cpu(n->id_ctrl.sgls);
if (sgls & NVME_CTRL_SGLS_EXCESS_LENGTH) {
break;
}
@@ -2562,8 +2562,7 @@ int nvme_register_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
if (!nsid) {
for (int i = 1; i <= n->num_namespaces; i++) {
- NvmeNamespace *ns = nvme_ns(n, i);
- if (!ns) {
+ if (!nvme_ns(n, i)) {
nsid = ns->params.nsid = i;
break;
}
@@ -2800,7 +2799,6 @@ static void nvme_exit(PCIDevice *pci_dev)
NvmeCtrl *n = NVME(pci_dev);
nvme_clear_ctrl(n);
- g_free(n->namespaces);
g_free(n->cq);
g_free(n->sq);
g_free(n->aer_reqs);
diff --git a/hw/intc/ibex_plic.c b/hw/intc/ibex_plic.c
index f49fa67c91..235e6b88ff 100644
--- a/hw/intc/ibex_plic.c
+++ b/hw/intc/ibex_plic.c
@@ -139,6 +139,9 @@ static uint64_t ibex_plic_read(void *opaque, hwaddr addr,
/* Return the current claimed interrupt */
ret = s->claim;
+ /* Clear the claimed interrupt */
+ s->claim = 0x00000000;
+
/* Update the interrupt status after the claim */
ibex_plic_update(s);
}
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
index 3356d7a681..3d40867dc4 100644
--- a/hw/mips/boston.c
+++ b/hw/mips/boston.c
@@ -349,11 +349,9 @@ static const void *boston_fdt_filter(void *opaque, const void *fdt_orig,
MachineState *machine = s->mach;
const char *cmdline;
int err;
- void *fdt;
- size_t fdt_sz, ram_low_sz, ram_high_sz;
-
- fdt_sz = fdt_totalsize(fdt_orig) * 2;
- fdt = g_malloc0(fdt_sz);
+ size_t ram_low_sz, ram_high_sz;
+ size_t fdt_sz = fdt_totalsize(fdt_orig) * 2;
+ g_autofree void *fdt = g_malloc0(fdt_sz);
err = fdt_open_into(fdt_orig, fdt, fdt_sz);
if (err) {
@@ -380,7 +378,7 @@ static const void *boston_fdt_filter(void *opaque, const void *fdt_orig,
s->fdt_base = *load_addr;
- return fdt;
+ return g_steal_pointer(&fdt);
}
static const void *boston_kernel_filter(void *opaque, const void *kernel,
diff --git a/hw/misc/stm32f2xx_syscfg.c b/hw/misc/stm32f2xx_syscfg.c
index aa59b43549..04c22c2850 100644
--- a/hw/misc/stm32f2xx_syscfg.c
+++ b/hw/misc/stm32f2xx_syscfg.c
@@ -133,8 +133,6 @@ static void stm32f2xx_syscfg_init(Object *obj)
{
STM32F2XXSyscfgState *s = STM32F2XX_SYSCFG(obj);
- sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
-
memory_region_init_io(&s->mmio, obj, &stm32f2xx_syscfg_ops, s,
TYPE_STM32F2XX_SYSCFG, 0x400);
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
diff --git a/hw/net/can/ctucan_core.c b/hw/net/can/ctucan_core.c
index d20835cd7e..d171c372e0 100644
--- a/hw/net/can/ctucan_core.c
+++ b/hw/net/can/ctucan_core.c
@@ -240,8 +240,6 @@ static void ctucan_send_ready_buffers(CtuCanCoreState *s)
uint8_t *pf;
int buff2tx_idx;
uint32_t tx_prio_max;
- unsigned int buff_st;
- uint32_t buff_st_mask;
if (!s->mode_settings.s.ena) {
return;
@@ -256,10 +254,7 @@ static void ctucan_send_ready_buffers(CtuCanCoreState *s)
for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
uint32_t prio;
- buff_st_mask = 0xf << (i * 4);
- buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf;
-
- if (buff_st != TXT_RDY) {
+ if (extract32(s->tx_status.u32, i * 4, 4) != TXT_RDY) {
continue;
}
prio = (s->tx_priority.u32 >> (i * 4)) & 0x7;
@@ -271,10 +266,7 @@ static void ctucan_send_ready_buffers(CtuCanCoreState *s)
if (buff2tx_idx == -1) {
break;
}
- buff_st_mask = 0xf << (buff2tx_idx * 4);
- buff_st = (s->tx_status.u32 >> (buff2tx_idx * 4)) & 0xf;
int_stat.u32 = 0;
- buff_st = TXT_RDY;
pf = s->tx_buffer[buff2tx_idx].data;
ctucan_buff2frame(pf, &frame);
s->status.s.idle = 0;
@@ -283,12 +275,11 @@ static void ctucan_send_ready_buffers(CtuCanCoreState *s)
s->status.s.idle = 1;
s->status.s.txs = 0;
s->tx_fr_ctr.s.tx_fr_ctr_val++;
- buff_st = TXT_TOK;
int_stat.s.txi = 1;
int_stat.s.txbhci = 1;
s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
- s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) |
- (buff_st << (buff2tx_idx * 4));
+ s->tx_status.u32 = deposit32(s->tx_status.u32,
+ buff2tx_idx * 4, 4, TXT_TOK);
} while (1);
}
@@ -303,7 +294,7 @@ void ctucan_mem_write(CtuCanCoreState *s, hwaddr addr, uint64_t val,
DPRINTF("write 0x%02llx addr 0x%02x\n",
(unsigned long long)val, (unsigned int)addr);
- if (addr > CTUCAN_CORE_MEM_SIZE) {
+ if (addr >= CTUCAN_CORE_MEM_SIZE) {
return;
}
@@ -312,9 +303,9 @@ void ctucan_mem_write(CtuCanCoreState *s, hwaddr addr, uint64_t val,
addr -= CTU_CAN_FD_TXTB1_DATA_1;
buff_num = addr / CTUCAN_CORE_TXBUFF_SPAN;
addr %= CTUCAN_CORE_TXBUFF_SPAN;
- if (buff_num < CTUCAN_CORE_TXBUF_NUM) {
- uint32_t *bufp = (uint32_t *)(s->tx_buffer[buff_num].data + addr);
- *bufp = cpu_to_le32(val);
+ if ((buff_num < CTUCAN_CORE_TXBUF_NUM) &&
+ ((addr + size) <= sizeof(s->tx_buffer[buff_num].data))) {
+ stn_le_p(s->tx_buffer[buff_num].data + addr, size, val);
}
} else {
switch (addr & ~3) {
diff --git a/hw/net/can/ctucan_core.h b/hw/net/can/ctucan_core.h
index f21cb1c5ec..bbc09ae067 100644
--- a/hw/net/can/ctucan_core.h
+++ b/hw/net/can/ctucan_core.h
@@ -31,8 +31,7 @@
#include "exec/hwaddr.h"
#include "net/can_emu.h"
-
-#ifndef __LITTLE_ENDIAN_BITFIELD
+#ifndef HOST_WORDS_BIGENDIAN
#define __LITTLE_ENDIAN_BITFIELD 1
#endif
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 277289d56e..9179013ac4 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -3395,6 +3395,12 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
nc = qemu_get_queue(n->nic);
nc->rxfilter_notify_enabled = 1;
+ if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
+ struct virtio_net_config netcfg = {};
+ memcpy(&netcfg.mac, &n->nic_conf.macaddr, ETH_ALEN);
+ vhost_net_set_config(get_vhost_net(nc->peer),
+ (uint8_t *)&netcfg, 0, ETH_ALEN, VHOST_SET_CONFIG_TYPE_MASTER);
+ }
QTAILQ_INIT(&n->rsc_chains);
n->qdev = dev;
diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c
index 417ec0564b..285549c79b 100644
--- a/hw/rx/rx-gdbsim.c
+++ b/hw/rx/rx-gdbsim.c
@@ -122,9 +122,8 @@ static void rx_gdbsim_init(MachineState *machine)
if (dtb_filename) {
ram_addr_t dtb_offset;
int dtb_size;
- void *dtb;
+ g_autofree void *dtb = load_device_tree(dtb_filename, &dtb_size);
- dtb = load_device_tree(dtb_filename, &dtb_size);
if (dtb == NULL) {
error_report("Couldn't open dtb file %s", dtb_filename);
exit(1);
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 9e90169695..dfc6dfd89c 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -32,7 +32,7 @@ struct IPLBlockPV {
uint32_t num_comp; /* 0x74 */
uint64_t pv_header_addr; /* 0x78 */
uint64_t pv_header_len; /* 0x80 */
- struct IPLBlockPVComp components[];
+ struct IPLBlockPVComp components[0];
} QEMU_PACKED;
typedef struct IPLBlockPV IPLBlockPV;
@@ -63,7 +63,7 @@ struct IplBlockFcp {
uint64_t br_lba;
uint32_t scp_data_len;
uint8_t reserved6[260];
- uint8_t scp_data[];
+ uint8_t scp_data[0];
} QEMU_PACKED;
typedef struct IplBlockFcp IplBlockFcp;
diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
index 7f703d8328..d8885ae454 100644
--- a/hw/ssi/imx_spi.c
+++ b/hw/ssi/imx_spi.c
@@ -53,7 +53,7 @@ static const char *imx_spi_reg_name(uint32_t reg)
case ECSPI_MSGDATA:
return "ECSPI_MSGDATA";
default:
- sprintf(unknown, "%d ?", reg);
+ sprintf(unknown, "%u ?", reg);
return unknown;
}
}
diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c
index fec8817d94..49ff275593 100644
--- a/hw/ssi/xilinx_spi.c
+++ b/hw/ssi/xilinx_spi.c
@@ -142,7 +142,7 @@ static void xlx_spi_update_irq(XilinxSPI *s)
irq chain unless things really changed. */
if (pending != s->irqline) {
s->irqline = pending;
- DB_PRINT("irq_change of state %d ISR:%x IER:%X\n",
+ DB_PRINT("irq_change of state %u ISR:%x IER:%X\n",
pending, s->regs[R_IPISR], s->regs[R_IPIER]);
qemu_set_irq(s->irq, pending);
}
diff --git a/include/block/block.h b/include/block/block.h
index 4bfe3b546b..c9d7c58765 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -782,12 +782,6 @@ void bdrv_drained_end(BlockDriverState *bs);
void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter);
/**
- * End all quiescent sections started by bdrv_drain_all_begin(). This is
- * only needed when deleting a BDS before bdrv_drain_all_end() is called.
- */
-void bdrv_drain_all_end_quiesce(BlockDriverState *bs);
-
-/**
* End a quiescent section started by bdrv_subtree_drained_begin().
*/
void bdrv_subtree_drained_end(BlockDriverState *bs);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 38cad9d15c..95d9333be1 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -1407,4 +1407,13 @@ static inline BlockDriverState *bdrv_primary_bs(BlockDriverState *bs)
return child_bs(bdrv_primary_child(bs));
}
+/**
+ * End all quiescent sections started by bdrv_drain_all_begin(). This is
+ * needed when deleting a BDS before bdrv_drain_all_end() is called.
+ *
+ * NOTE: this is an internal helper for bdrv_close() *only*. No one else
+ * should call it.
+ */
+void bdrv_drain_all_end_quiesce(BlockDriverState *bs);
+
#endif /* BLOCK_INT_H */
diff --git a/include/hw/misc/stm32f2xx_syscfg.h b/include/hw/misc/stm32f2xx_syscfg.h
index 57a98c533d..8595a3b31b 100644
--- a/include/hw/misc/stm32f2xx_syscfg.h
+++ b/include/hw/misc/stm32f2xx_syscfg.h
@@ -53,8 +53,6 @@ struct STM32F2XXSyscfgState {
uint32_t syscfg_exticr3;
uint32_t syscfg_exticr4;
uint32_t syscfg_cmpcr;
-
- qemu_irq irq;
};
#endif /* HW_STM32F2XX_SYSCFG_H */
diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
index d796f50f66..d12adc8e6f 100644
--- a/linux-user/sparc/signal.c
+++ b/linux-user/sparc/signal.c
@@ -247,7 +247,7 @@ long do_sigreturn(CPUSPARCState *env)
{
abi_ulong sf_addr;
struct target_signal_frame *sf;
- uint32_t up_psr, pc, npc;
+ abi_ulong up_psr, pc, npc;
target_sigset_t set;
sigset_t host_set;
int i;
@@ -349,10 +349,15 @@ typedef abi_ulong target_mc_greg_t;
typedef target_mc_greg_t target_mc_gregset_t[SPARC_MC_NGREG];
struct target_mc_fq {
- abi_ulong *mcfq_addr;
+ abi_ulong mcfq_addr;
uint32_t mcfq_insn;
};
+/*
+ * Note the manual 16-alignment; the kernel gets this because it
+ * includes a "long double qregs[16]" in the mcpu_fregs union,
+ * which we can't do.
+ */
struct target_mc_fpu {
union {
uint32_t sregs[32];
@@ -362,11 +367,11 @@ struct target_mc_fpu {
abi_ulong mcfpu_fsr;
abi_ulong mcfpu_fprs;
abi_ulong mcfpu_gsr;
- struct target_mc_fq *mcfpu_fq;
+ abi_ulong mcfpu_fq;
unsigned char mcfpu_qcnt;
unsigned char mcfpu_qentsz;
unsigned char mcfpu_enab;
-};
+} __attribute__((aligned(16)));
typedef struct target_mc_fpu target_mc_fpu_t;
typedef struct {
@@ -377,7 +382,7 @@ typedef struct {
} target_mcontext_t;
struct target_ucontext {
- struct target_ucontext *tuc_link;
+ abi_ulong tuc_link;
abi_ulong tuc_flags;
target_sigset_t tuc_sigmask;
target_mcontext_t tuc_mcontext;
@@ -398,7 +403,6 @@ void sparc64_set_context(CPUSPARCState *env)
struct target_ucontext *ucp;
target_mc_gregset_t *grp;
abi_ulong pc, npc, tstate;
- abi_ulong fp, i7, w_addr;
unsigned int i;
ucp_addr = env->regwptr[WREG_O0];
@@ -442,6 +446,15 @@ void sparc64_set_context(CPUSPARCState *env)
__get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5]));
__get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6]));
__get_user(env->gregs[7], (&(*grp)[SPARC_MC_G7]));
+
+ /*
+ * Note that unlike the kernel, we didn't need to mess with the
+ * guest register window state to save it into a pt_regs to run
+ * the kernel. So for us the guest's O regs are still in WREG_O*
+ * (unlike the kernel which has put them in UREG_I* in a pt_regs)
+ * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't
+ * need to be written back to userspace memory.
+ */
__get_user(env->regwptr[WREG_O0], (&(*grp)[SPARC_MC_O0]));
__get_user(env->regwptr[WREG_O1], (&(*grp)[SPARC_MC_O1]));
__get_user(env->regwptr[WREG_O2], (&(*grp)[SPARC_MC_O2]));
@@ -451,18 +464,9 @@ void sparc64_set_context(CPUSPARCState *env)
__get_user(env->regwptr[WREG_O6], (&(*grp)[SPARC_MC_O6]));
__get_user(env->regwptr[WREG_O7], (&(*grp)[SPARC_MC_O7]));
- __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
- __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
+ __get_user(env->regwptr[WREG_FP], &(ucp->tuc_mcontext.mc_fp));
+ __get_user(env->regwptr[WREG_I7], &(ucp->tuc_mcontext.mc_i7));
- w_addr = TARGET_STACK_BIAS + env->regwptr[WREG_O6];
- if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
- abi_ulong) != 0) {
- goto do_sigsegv;
- }
- if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
- abi_ulong) != 0) {
- goto do_sigsegv;
- }
/* FIXME this does not match how the kernel handles the FPU in
* its sparc64_set_context implementation. In particular the FPU
* is only restored if fenab is non-zero in:
@@ -496,7 +500,6 @@ void sparc64_get_context(CPUSPARCState *env)
struct target_ucontext *ucp;
target_mc_gregset_t *grp;
target_mcontext_t *mcp;
- abi_ulong fp, i7, w_addr;
int err;
unsigned int i;
target_sigset_t target_set;
@@ -548,6 +551,15 @@ void sparc64_get_context(CPUSPARCState *env)
__put_user(env->gregs[5], &((*grp)[SPARC_MC_G5]));
__put_user(env->gregs[6], &((*grp)[SPARC_MC_G6]));
__put_user(env->gregs[7], &((*grp)[SPARC_MC_G7]));
+
+ /*
+ * Note that unlike the kernel, we didn't need to mess with the
+ * guest register window state to save it into a pt_regs to run
+ * the kernel. So for us the guest's O regs are still in WREG_O*
+ * (unlike the kernel which has put them in UREG_I* in a pt_regs)
+ * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't
+ * need to be fished out of userspace memory.
+ */
__put_user(env->regwptr[WREG_O0], &((*grp)[SPARC_MC_O0]));
__put_user(env->regwptr[WREG_O1], &((*grp)[SPARC_MC_O1]));
__put_user(env->regwptr[WREG_O2], &((*grp)[SPARC_MC_O2]));
@@ -557,18 +569,8 @@ void sparc64_get_context(CPUSPARCState *env)
__put_user(env->regwptr[WREG_O6], &((*grp)[SPARC_MC_O6]));
__put_user(env->regwptr[WREG_O7], &((*grp)[SPARC_MC_O7]));
- w_addr = TARGET_STACK_BIAS + env->regwptr[WREG_O6];
- fp = i7 = 0;
- if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
- abi_ulong) != 0) {
- goto do_sigsegv;
- }
- if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
- abi_ulong) != 0) {
- goto do_sigsegv;
- }
- __put_user(fp, &(mcp->mc_fp));
- __put_user(i7, &(mcp->mc_i7));
+ __put_user(env->regwptr[WREG_FP], &(mcp->mc_fp));
+ __put_user(env->regwptr[WREG_I7], &(mcp->mc_i7));
{
uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
diff --git a/meson.build b/meson.build
index b7f91cb08d..61d883bc07 100644
--- a/meson.build
+++ b/meson.build
@@ -1450,11 +1450,7 @@ trace_events_subdirs += [
'util',
]
-vhost_user = not_found
-if 'CONFIG_VHOST_USER' in config_host
- subdir('contrib/libvhost-user')
-endif
-
+subdir('contrib/libvhost-user')
subdir('qapi')
subdir('qobject')
subdir('stubs')
diff --git a/migration/ram.c b/migration/ram.c
index 2da2b622ab..add5396a62 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -3011,6 +3011,18 @@ static void decompress_data_with_multi_threads(QEMUFile *f,
qemu_mutex_unlock(&decomp_done_lock);
}
+ /*
+ * we must set ram_bulk_stage to false, otherwise in
+ * migation_bitmap_find_dirty the bitmap will be unused and
+ * all the pages in ram cache wil be flushed to the ram of
+ * secondary VM.
+ */
+static void colo_init_ram_state(void)
+{
+ ram_state_init(&ram_state);
+ ram_state->ram_bulk_stage = false;
+}
+
/*
* colo cache: this is for secondary VM, we cache the whole
* memory of the secondary VM, it is need to hold the global lock
@@ -3054,7 +3066,7 @@ int colo_init_ram_cache(void)
}
}
- ram_state_init(&ram_state);
+ colo_init_ram_state();
return 0;
}
diff --git a/net/colo-compare.c b/net/colo-compare.c
index 3a45d64175..337025b44f 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -52,7 +52,7 @@ static NotifierList colo_compare_notifiers =
#define COLO_COMPARE_FREE_PRIMARY 0x01
#define COLO_COMPARE_FREE_SECONDARY 0x02
-#define REGULAR_PACKET_CHECK_MS 3000
+#define REGULAR_PACKET_CHECK_MS 1000
#define DEFAULT_TIME_OUT_MS 3000
/* #define DEBUG_COLO_PACKETS */
@@ -120,7 +120,7 @@ struct CompareState {
SendCo out_sendco;
SendCo notify_sendco;
bool vnet_hdr;
- uint32_t compare_timeout;
+ uint64_t compare_timeout;
uint32_t expired_scan_cycle;
/*
@@ -194,13 +194,10 @@ static void colo_compare_inconsistency_notify(CompareState *s)
}
}
+/* Use restricted to colo_insert_packet() */
static gint seq_sorter(Packet *a, Packet *b, gpointer data)
{
- struct tcp_hdr *atcp, *btcp;
-
- atcp = (struct tcp_hdr *)(a->transport_header);
- btcp = (struct tcp_hdr *)(b->transport_header);
- return ntohl(atcp->th_seq) - ntohl(btcp->th_seq);
+ return a->tcp_seq - b->tcp_seq;
}
static void fill_pkt_tcp_info(void *data, uint32_t *max_ack)
@@ -480,13 +477,11 @@ sec:
colo_release_primary_pkt(s, ppkt);
g_queue_push_head(&conn->secondary_list, spkt);
goto pri;
- }
- if (mark == COLO_COMPARE_FREE_SECONDARY) {
+ } else if (mark == COLO_COMPARE_FREE_SECONDARY) {
conn->compare_seq = spkt->seq_end;
packet_destroy(spkt, NULL);
goto sec;
- }
- if (mark == (COLO_COMPARE_FREE_PRIMARY | COLO_COMPARE_FREE_SECONDARY)) {
+ } else if (mark == (COLO_COMPARE_FREE_PRIMARY | COLO_COMPARE_FREE_SECONDARY)) {
conn->compare_seq = ppkt->seq_end;
colo_release_primary_pkt(s, ppkt);
packet_destroy(spkt, NULL);
@@ -641,19 +636,26 @@ void colo_compare_unregister_notifier(Notifier *notify)
static int colo_old_packet_check_one_conn(Connection *conn,
CompareState *s)
{
- GList *result = NULL;
-
- result = g_queue_find_custom(&conn->primary_list,
- &s->compare_timeout,
- (GCompareFunc)colo_old_packet_check_one);
+ if (!g_queue_is_empty(&conn->primary_list)) {
+ if (g_queue_find_custom(&conn->primary_list,
+ &s->compare_timeout,
+ (GCompareFunc)colo_old_packet_check_one))
+ goto out;
+ }
- if (result) {
- /* Do checkpoint will flush old packet */
- colo_compare_inconsistency_notify(s);
- return 0;
+ if (!g_queue_is_empty(&conn->secondary_list)) {
+ if (g_queue_find_custom(&conn->secondary_list,
+ &s->compare_timeout,
+ (GCompareFunc)colo_old_packet_check_one))
+ goto out;
}
return 1;
+
+out:
+ /* Do checkpoint will flush old packet */
+ colo_compare_inconsistency_notify(s);
+ return 0;
}
/*
@@ -905,7 +907,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) +
+ timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_HOST) +
s->expired_scan_cycle);
}
@@ -939,10 +941,10 @@ static void colo_compare_timer_init(CompareState *s)
{
AioContext *ctx = iothread_get_aio_context(s->iothread);
- s->packet_check_timer = aio_timer_new(ctx, QEMU_CLOCK_VIRTUAL,
+ s->packet_check_timer = aio_timer_new(ctx, QEMU_CLOCK_HOST,
SCALE_MS, check_old_packet_regular,
s);
- timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+ timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_HOST) +
s->expired_scan_cycle);
}
@@ -1081,9 +1083,9 @@ static void compare_get_timeout(Object *obj, Visitor *v,
Error **errp)
{
CompareState *s = COLO_COMPARE(obj);
- uint32_t value = s->compare_timeout;
+ uint64_t value = s->compare_timeout;
- visit_type_uint32(v, name, &value, errp);
+ visit_type_uint64(v, name, &value, errp);
}
static void compare_set_timeout(Object *obj, Visitor *v,
@@ -1146,9 +1148,9 @@ static void set_max_queue_size(Object *obj, Visitor *v,
Error **errp)
{
Error *local_err = NULL;
- uint32_t value;
+ uint64_t value;
- visit_type_uint32(v, name, &value, &local_err);
+ visit_type_uint64(v, name, &value, &local_err);
if (local_err) {
goto out;
}
@@ -1396,7 +1398,7 @@ static void colo_compare_init(Object *obj)
object_property_add_str(obj, "notify_dev",
compare_get_notify_dev, compare_set_notify_dev);
- object_property_add(obj, "compare_timeout", "uint32",
+ object_property_add(obj, "compare_timeout", "uint64",
compare_get_timeout,
compare_set_timeout, NULL, NULL);
diff --git a/net/colo.c b/net/colo.c
index a6c66d829a..ef00609848 100644
--- a/net/colo.c
+++ b/net/colo.c
@@ -133,14 +133,11 @@ void reverse_connection_key(ConnectionKey *key)
Connection *connection_new(ConnectionKey *key)
{
- Connection *conn = g_slice_new(Connection);
+ Connection *conn = g_slice_new0(Connection);
conn->ip_proto = key->ip_proto;
conn->processing = false;
- conn->offset = 0;
conn->tcp_state = TCPS_CLOSED;
- conn->pack = 0;
- conn->sack = 0;
g_queue_init(&conn->primary_list);
g_queue_init(&conn->secondary_list);
diff --git a/net/eth.c b/net/eth.c
index 0c1d413ee2..1e0821c5f8 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -16,6 +16,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "net/eth.h"
#include "net/checksum.h"
#include "net/tap.h"
@@ -71,9 +72,8 @@ eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto)
return VIRTIO_NET_HDR_GSO_TCPV6 | ecn_state;
}
}
-
- /* Unsupported offload */
- g_assert_not_reached();
+ qemu_log_mask(LOG_UNIMP, "%s: probably not GSO frame, "
+ "unknown L3 protocol: 0x%04"PRIx16"\n", __func__, l3_proto);
return VIRTIO_NET_HDR_GSO_NONE | ecn_state;
}
diff --git a/net/filter-rewriter.c b/net/filter-rewriter.c
index dc3c27a489..e063a818b7 100644
--- a/net/filter-rewriter.c
+++ b/net/filter-rewriter.c
@@ -381,6 +381,8 @@ static void colo_rewriter_cleanup(NetFilterState *nf)
filter_rewriter_flush(nf);
g_free(s->incoming_queue);
}
+
+ g_hash_table_destroy(s->connection_track_table);
}
static void colo_rewriter_setup(NetFilterState *nf, Error **errp)
diff --git a/net/l2tpv3.c b/net/l2tpv3.c
index 55fea17c0f..e4d4218db6 100644
--- a/net/l2tpv3.c
+++ b/net/l2tpv3.c
@@ -655,9 +655,8 @@ int net_init_l2tpv3(const Netdev *netdev,
error_setg(errp, "could not bind socket err=%i", errno);
goto outerr;
}
- if (result) {
- freeaddrinfo(result);
- }
+
+ freeaddrinfo(result);
memset(&hints, 0, sizeof(hints));
@@ -686,9 +685,7 @@ int net_init_l2tpv3(const Netdev *netdev,
memcpy(s->dgram_dst, result->ai_addr, result->ai_addrlen);
s->dst_size = result->ai_addrlen;
- if (result) {
- freeaddrinfo(result);
- }
+ freeaddrinfo(result);
if (l2tpv3->has_counter && l2tpv3->counter) {
s->has_counter = true;
diff --git a/qapi/audio.json b/qapi/audio.json
index 3b843878d2..072ed79def 100644
--- a/qapi/audio.json
+++ b/qapi/audio.json
@@ -6,6 +6,10 @@
# See the COPYING file in the top-level directory.
##
+# = Audio
+##
+
+##
# @AudiodevPerDirectionOptions:
#
# General audio backend options that are used for both playback and
diff --git a/qapi/authz.json b/qapi/authz.json
index f3e9745426..42afe752d1 100644
--- a/qapi/authz.json
+++ b/qapi/authz.json
@@ -1,7 +1,9 @@
# -*- Mode: Python -*-
# vim: filetype=python
-#
-# QAPI authz definitions
+
+##
+# = User authorization
+##
##
# @QAuthZListPolicy:
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 1b8b4156b4..04ad80bc1e 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -244,17 +244,25 @@
#
# Mapping information from a virtual block range to a host file range
#
-# @start: the start byte of the mapped virtual range
+# @start: virtual (guest) offset of the first byte described by this
+# entry
#
# @length: the number of bytes of the mapped virtual range
#
-# @data: whether the mapped range has data
+# @data: reading the image will actually read data from a file (in
+# particular, if @offset is present this means that the sectors
+# are not simply preallocated, but contain actual data in raw
+# format)
#
-# @zero: whether the virtual blocks are zeroed
+# @zero: whether the virtual blocks read as zeroes
#
-# @depth: the depth of the mapping
+# @depth: number of layers (0 = top image, 1 = top image's backing
+# file, ..., n - 1 = bottom image (where n is the number of
+# images in the chain)) before reaching one for which the
+# range is allocated
#
-# @offset: the offset in file that the virtual sectors are mapped to
+# @offset: if present, the image file stores the data for this range
+# in raw format at the given (host) offset
#
# @filename: filename that is referred to by @offset
#
@@ -419,35 +427,6 @@
{ 'enum': 'BlockDeviceIoStatus', 'data': [ 'ok', 'failed', 'nospace' ] }
##
-# @BlockDeviceMapEntry:
-#
-# Entry in the metadata map of the device (returned by "qemu-img map")
-#
-# @start: Offset in the image of the first byte described by this entry
-# (in bytes)
-#
-# @length: Length of the range described by this entry (in bytes)
-#
-# @depth: Number of layers (0 = top image, 1 = top image's backing file, etc.)
-# before reaching one for which the range is allocated. The value is
-# in the range 0 to the depth of the image chain - 1.
-#
-# @zero: the sectors in this range read as zeros
-#
-# @data: reading the image will actually read data from a file (in particular,
-# if @offset is present this means that the sectors are not simply
-# preallocated, but contain actual data in raw format)
-#
-# @offset: if present, the image file stores the data for this range in
-# raw format at the given offset.
-#
-# Since: 1.7
-##
-{ 'struct': 'BlockDeviceMapEntry',
- 'data': { 'start': 'int', 'length': 'int', 'depth': 'int', 'zero': 'bool',
- 'data': 'bool', '*offset': 'int' } }
-
-##
# @DirtyBitmapStatus:
#
# An enumeration of possible states that a dirty bitmap can report to the user.
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 3711080d07..12c1ba5ef7 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1443,6 +1443,9 @@ GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
get_disk_deps(disk_dir, disk);
ret = get_disk_partitions(ret, de->d_name, disk_dir, dev_name);
}
+
+ closedir(dp);
+
return ret;
}
diff --git a/scripts/device-crash-test b/scripts/device-crash-test
index 866baf7058..04118669ba 100755
--- a/scripts/device-crash-test
+++ b/scripts/device-crash-test
@@ -383,7 +383,9 @@ def binariesToTest(args, testcase):
if args.qemu:
r = args.qemu
else:
- r = glob.glob('./qemu-system-*')
+ r = [f.path for f in os.scandir('.')
+ if f.name.startswith('qemu-system-') and
+ f.is_file() and os.access(f, os.X_OK)]
return r
diff --git a/scripts/oss-fuzz/build.sh b/scripts/oss-fuzz/build.sh
index 3b1c82b63d..c1af43fded 100755
--- a/scripts/oss-fuzz/build.sh
+++ b/scripts/oss-fuzz/build.sh
@@ -62,9 +62,6 @@ fi
mkdir -p "$DEST_DIR/lib/" # Copy the shared libraries here
-mkdir -p "$DEST_DIR/bin/" # Copy executables that shouldn't
- # be treated as fuzzers by oss-fuzz here
-
# Build once to get the list of dynamic lib paths, and copy them over
../configure --disable-werror --cc="$CC" --cxx="$CXX" --enable-fuzzing \
--prefix="$DEST_DIR" --bindir="$DEST_DIR" --datadir="$DEST_DIR/data/" \
@@ -91,20 +88,23 @@ make "-j$(nproc)" qemu-fuzz-i386 V=1
# Copy over the datadir
cp -r ../pc-bios/ "$DEST_DIR/pc-bios"
-cp "./qemu-fuzz-i386" "$DEST_DIR/bin/qemu-fuzz-i386.base"
+targets=$(./qemu-fuzz-i386 | awk '$1 ~ /\*/ {print $2}')
+base_copy="$DEST_DIR/qemu-fuzz-i386-target-$(echo "$targets" | head -n 1)"
+
+cp "./qemu-fuzz-i386" "$base_copy"
# Run the fuzzer with no arguments, to print the help-string and get the list
# of available fuzz-targets. Copy over the qemu-fuzz-i386, naming it according
# to each available fuzz target (See 05509c8e6d fuzz: select fuzz target using
# executable name)
-for target in $(./qemu-fuzz-i386 | awk '$1 ~ /\*/ {print $2}');
+for target in $(echo "$targets" | tail -n +2);
do
# Ignore the generic-fuzz target, as it requires some environment variables
# to be configured. We have some generic-fuzz-{pc-q35, floppy, ...} targets
# that are thin wrappers around this target that set the required
# environment variables according to predefined configs.
if [ "$target" != "generic-fuzz" ]; then
- ln "$DEST_DIR/bin/qemu-fuzz-i386.base" \
+ ln $base_copy \
"$DEST_DIR/qemu-fuzz-i386-target-$target"
fi
done
diff --git a/softmmu/vl.c b/softmmu/vl.c
index a71164494e..e32fd48f14 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -632,6 +632,7 @@ static const RunStateTransition runstate_transitions_def[] = {
{ RUN_STATE_SHUTDOWN, RUN_STATE_PAUSED },
{ RUN_STATE_SHUTDOWN, RUN_STATE_FINISH_MIGRATE },
{ RUN_STATE_SHUTDOWN, RUN_STATE_PRELAUNCH },
+ { RUN_STATE_SHUTDOWN, RUN_STATE_COLO },
{ RUN_STATE_DEBUG, RUN_STATE_SUSPENDED },
{ RUN_STATE_RUNNING, RUN_STATE_SUSPENDED },
diff --git a/target/arm/arch_dump.c b/target/arm/arch_dump.c
index 7693e17e96..0184845310 100644
--- a/target/arm/arch_dump.c
+++ b/target/arm/arch_dump.c
@@ -114,8 +114,8 @@ static int aarch64_write_elf64_prfpreg(WriteCoreDumpFunction f,
for (i = 0; i < 32; ++i) {
uint64_t *q = aa64_vfp_qreg(env, i);
- note.vfp.vregs[2*i + 0] = cpu_to_dump64(s, q[0]);
- note.vfp.vregs[2*i + 1] = cpu_to_dump64(s, q[1]);
+ note.vfp.vregs[2 * i + 0] = cpu_to_dump64(s, q[0]);
+ note.vfp.vregs[2 * i + 1] = cpu_to_dump64(s, q[1]);
}
if (s->dump_info.d_endian == ELFDATA2MSB) {
@@ -125,8 +125,8 @@ static int aarch64_write_elf64_prfpreg(WriteCoreDumpFunction f,
*/
for (i = 0; i < 32; ++i) {
uint64_t tmp = note.vfp.vregs[2*i];
- note.vfp.vregs[2*i] = note.vfp.vregs[2*i+1];
- note.vfp.vregs[2*i+1] = tmp;
+ note.vfp.vregs[2 * i] = note.vfp.vregs[2 * i + 1];
+ note.vfp.vregs[2 * i + 1] = tmp;
}
}
diff --git a/target/arm/arm-semi.c b/target/arm/arm-semi.c
index 8718fd0194..c1df664f7e 100644
--- a/target/arm/arm-semi.c
+++ b/target/arm/arm-semi.c
@@ -755,7 +755,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
if (use_gdb_syscalls()) {
arm_semi_open_guestfd = guestfd;
ret = arm_gdb_syscall(cpu, arm_semi_open_cb, "open,%s,%x,1a4", arg0,
- (int)arg2+1, gdb_open_modeflags[arg1]);
+ (int)arg2 + 1, gdb_open_modeflags[arg1]);
} else {
ret = set_swi_errno(env, open(s, open_modeflags[arg1], 0644));
if (ret == (uint32_t)-1) {
@@ -852,7 +852,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
GET_ARG(1);
if (use_gdb_syscalls()) {
ret = arm_gdb_syscall(cpu, arm_semi_cb, "unlink,%s",
- arg0, (int)arg1+1);
+ arg0, (int)arg1 + 1);
} else {
s = lock_user_string(arg0);
if (!s) {
@@ -870,7 +870,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
GET_ARG(3);
if (use_gdb_syscalls()) {
return arm_gdb_syscall(cpu, arm_semi_cb, "rename,%s,%s",
- arg0, (int)arg1+1, arg2, (int)arg3+1);
+ arg0, (int)arg1 + 1, arg2, (int)arg3 + 1);
} else {
char *s2;
s = lock_user_string(arg0);
@@ -896,7 +896,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
GET_ARG(1);
if (use_gdb_syscalls()) {
return arm_gdb_syscall(cpu, arm_semi_cb, "system,%s",
- arg0, (int)arg1+1);
+ arg0, (int)arg1 + 1);
} else {
s = lock_user_string(arg0);
if (!s) {
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 6854591986..11b0803df7 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -12508,7 +12508,7 @@ uint32_t HELPER(usad8)(uint32_t a, uint32_t b)
uint32_t sum;
sum = do_usad(a, b);
sum += do_usad(a >> 8, b >> 8);
- sum += do_usad(a >> 16, b >>16);
+ sum += do_usad(a >> 16, b >> 16);
sum += do_usad(a >> 24, b >> 24);
return sum;
}
diff --git a/target/arm/helper.h b/target/arm/helper.h
index 774d2cddb5..ff8148ddc6 100644
--- a/target/arm/helper.h
+++ b/target/arm/helper.h
@@ -245,7 +245,7 @@ DEF_HELPER_FLAGS_2(rsqrte_f32, TCG_CALL_NO_RWG, f32, f32, ptr)
DEF_HELPER_FLAGS_2(rsqrte_f64, TCG_CALL_NO_RWG, f64, f64, ptr)
DEF_HELPER_FLAGS_1(recpe_u32, TCG_CALL_NO_RWG, i32, i32)
DEF_HELPER_FLAGS_1(rsqrte_u32, TCG_CALL_NO_RWG, i32, i32)
-DEF_HELPER_FLAGS_4(neon_tbl, TCG_CALL_NO_RWG, i32, i32, i32, ptr, i32)
+DEF_HELPER_FLAGS_4(neon_tbl, TCG_CALL_NO_RWG, i64, env, i32, i64, i64)
DEF_HELPER_3(shl_cc, i32, env, i32, i32)
DEF_HELPER_3(shr_cc, i32, env, i32, i32)
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index b1065216b2..aa13b978c0 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -68,21 +68,24 @@ void raise_exception_ra(CPUARMState *env, uint32_t excp, uint32_t syndrome,
cpu_loop_exit_restore(cs, ra);
}
-uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, void *vn,
- uint32_t maxindex)
+uint64_t HELPER(neon_tbl)(CPUARMState *env, uint32_t desc,
+ uint64_t ireg, uint64_t def)
{
- uint32_t val, shift;
- uint64_t *table = vn;
+ uint64_t tmp, val = 0;
+ uint32_t maxindex = ((desc & 3) + 1) * 8;
+ uint32_t base_reg = desc >> 2;
+ uint32_t shift, index, reg;
- val = 0;
- for (shift = 0; shift < 32; shift += 8) {
- uint32_t index = (ireg >> shift) & 0xff;
+ for (shift = 0; shift < 64; shift += 8) {
+ index = (ireg >> shift) & 0xff;
if (index < maxindex) {
- uint32_t tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff;
- val |= tmp << shift;
+ reg = base_reg + (index >> 3);
+ tmp = *aa32_vfp_dreg(env, reg);
+ tmp = ((tmp >> ((index & 7) << 3)) & 0xff) << shift;
} else {
- val |= def & (0xff << shift);
+ tmp = def & (0xffull << shift);
}
+ val |= tmp;
}
return val;
}
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 072754fa24..1867ec293f 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -12114,7 +12114,7 @@ static void disas_simd_three_reg_same_fp16(DisasContext *s, uint32_t insn)
gen_helper_advsimd_acgt_f16(tcg_res, tcg_op1, tcg_op2, fpst);
break;
default:
- fprintf(stderr, "%s: insn %#04x, fpop %#2x @ %#" PRIx64 "\n",
+ fprintf(stderr, "%s: insn 0x%04x, fpop 0x%2x @ 0x%" PRIx64 "\n",
__func__, insn, fpopcode, s->pc_curr);
g_assert_not_reached();
}
@@ -13121,7 +13121,7 @@ static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn)
case 0x7f: /* FSQRT (vector) */
break;
default:
- fprintf(stderr, "%s: insn %#04x fpop %#2x\n", __func__, insn, fpop);
+ fprintf(stderr, "%s: insn 0x%04x fpop 0x%2x\n", __func__, insn, fpop);
g_assert_not_reached();
}
diff --git a/target/arm/translate-neon.c.inc b/target/arm/translate-neon.c.inc
index 59368cb243..2403825d15 100644
--- a/target/arm/translate-neon.c.inc
+++ b/target/arm/translate-neon.c.inc
@@ -2861,9 +2861,8 @@ static bool trans_VEXT(DisasContext *s, arg_VEXT *a)
static bool trans_VTBL(DisasContext *s, arg_VTBL *a)
{
- int n;
- TCGv_i32 tmp, tmp2, tmp3, tmp4;
- TCGv_ptr ptr1;
+ TCGv_i64 val, def;
+ TCGv_i32 desc;
if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
return false;
@@ -2875,47 +2874,34 @@ static bool trans_VTBL(DisasContext *s, arg_VTBL *a)
return false;
}
- if (!vfp_access_check(s)) {
- return true;
- }
-
- n = a->len + 1;
- if ((a->vn + n) > 32) {
+ if ((a->vn + a->len + 1) > 32) {
/*
* This is UNPREDICTABLE; we choose to UNDEF to avoid the
* helper function running off the end of the register file.
*/
return false;
}
- n <<= 3;
- tmp = tcg_temp_new_i32();
- if (a->op) {
- read_neon_element32(tmp, a->vd, 0, MO_32);
- } else {
- tcg_gen_movi_i32(tmp, 0);
+
+ if (!vfp_access_check(s)) {
+ return true;
}
- tmp2 = tcg_temp_new_i32();
- read_neon_element32(tmp2, a->vm, 0, MO_32);
- ptr1 = vfp_reg_ptr(true, a->vn);
- tmp4 = tcg_const_i32(n);
- gen_helper_neon_tbl(tmp2, tmp2, tmp, ptr1, tmp4);
+ desc = tcg_const_i32((a->vn << 2) | a->len);
+ def = tcg_temp_new_i64();
if (a->op) {
- read_neon_element32(tmp, a->vd, 1, MO_32);
+ read_neon_element64(def, a->vd, 0, MO_64);
} else {
- tcg_gen_movi_i32(tmp, 0);
+ tcg_gen_movi_i64(def, 0);
}
- tmp3 = tcg_temp_new_i32();
- read_neon_element32(tmp3, a->vm, 1, MO_32);
- gen_helper_neon_tbl(tmp3, tmp3, tmp, ptr1, tmp4);
- tcg_temp_free_i32(tmp);
- tcg_temp_free_i32(tmp4);
- tcg_temp_free_ptr(ptr1);
+ val = tcg_temp_new_i64();
+ read_neon_element64(val, a->vm, 0, MO_64);
- write_neon_element32(tmp2, a->vd, 0, MO_32);
- write_neon_element32(tmp3, a->vd, 1, MO_32);
- tcg_temp_free_i32(tmp2);
- tcg_temp_free_i32(tmp3);
+ gen_helper_neon_tbl(val, cpu_env, desc, val, def);
+ write_neon_element64(val, a->vd, 0, MO_64);
+
+ tcg_temp_free_i64(def);
+ tcg_temp_free_i64(val);
+ tcg_temp_free_i32(desc);
return true;
}
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 29ea1eb781..f7d4ee393b 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -9171,7 +9171,7 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
- Hardware watchpoints.
Hardware breakpoints have already been handled and skip this code.
*/
- switch(dc->base.is_jmp) {
+ switch (dc->base.is_jmp) {
case DISAS_NEXT:
case DISAS_TOO_MANY:
gen_goto_tb(dc, 1, dc->base.pc_next);
diff --git a/target/mips/cp0_helper.c b/target/mips/cp0_helper.c
index 709cc9a7e3..a1b5140cca 100644
--- a/target/mips/cp0_helper.c
+++ b/target/mips/cp0_helper.c
@@ -892,13 +892,28 @@ void helper_mtc0_memorymapid(CPUMIPSState *env, target_ulong arg1)
void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask)
{
- uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1);
- if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) ||
- (mask == 0x0000 || mask == 0x0003 || mask == 0x000F ||
- mask == 0x003F || mask == 0x00FF || mask == 0x03FF ||
- mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) {
- env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
+ uint32_t mask;
+ int maskbits;
+
+ /* Don't care MASKX as we don't support 1KB page */
+ mask = extract32((uint32_t)arg1, CP0PM_MASK, 16);
+ maskbits = cto32(mask);
+
+ /* Ensure no more set bit after first zero */
+ if ((mask >> maskbits) != 0) {
+ goto invalid;
}
+ /* We don't support VTLB entry smaller than target page */
+ if ((maskbits + 12) < TARGET_PAGE_BITS) {
+ goto invalid;
+ }
+ env->CP0_PageMask = mask << CP0PM_MASK;
+
+ return;
+
+invalid:
+ /* When invalid, set to default target page size. */
+ env->CP0_PageMask = (~TARGET_PAGE_MASK >> 12) << CP0PM_MASK;
}
void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index d41579d44a..23f8c6f96c 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -619,6 +619,7 @@ struct CPUMIPSState {
* CP0 Register 5
*/
int32_t CP0_PageMask;
+#define CP0PM_MASK 13
int32_t CP0_PageGrain_rw_bitmask;
int32_t CP0_PageGrain;
#define CP0PG_RIE 31
diff --git a/target/riscv/cpu-param.h b/target/riscv/cpu-param.h
index 664fc1d371..80eb615f93 100644
--- a/target/riscv/cpu-param.h
+++ b/target/riscv/cpu-param.h
@@ -18,6 +18,15 @@
# define TARGET_VIRT_ADDR_SPACE_BITS 32 /* sv32 */
#endif
#define TARGET_PAGE_BITS 12 /* 4 KiB Pages */
-#define NB_MMU_MODES 4
+/*
+ * The current MMU Modes are:
+ * - U mode 0b000
+ * - S mode 0b001
+ * - M mode 0b011
+ * - U mode HLV/HLVX/HSV 0b100
+ * - S mode HLV/HLVX/HSV 0b101
+ * - M mode HLV/HLVX/HSV 0b111
+ */
+#define NB_MMU_MODES 8
#endif
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 87b68affa8..c0a326c843 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -323,8 +323,7 @@ bool riscv_cpu_virt_enabled(CPURISCVState *env);
void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
bool riscv_cpu_force_hs_excep_enabled(CPURISCVState *env);
void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable);
-bool riscv_cpu_two_stage_lookup(CPURISCVState *env);
-void riscv_cpu_set_two_stage_lookup(CPURISCVState *env, bool enable);
+bool riscv_cpu_two_stage_lookup(int mmu_idx);
int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
@@ -363,7 +362,9 @@ void QEMU_NORETURN riscv_raise_exception(CPURISCVState *env,
target_ulong riscv_cpu_get_fflags(CPURISCVState *env);
void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong);
-#define TB_FLAGS_MMU_MASK 3
+#define TB_FLAGS_MMU_MASK 7
+#define TB_FLAGS_PRIV_MMU_MASK 3
+#define TB_FLAGS_PRIV_HYP_ACCESS_MASK (1 << 2)
#define TB_FLAGS_MSTATUS_FS MSTATUS_FS
typedef CPURISCVState CPUArchState;
@@ -374,6 +375,8 @@ FIELD(TB_FLAGS, VL_EQ_VLMAX, 2, 1)
FIELD(TB_FLAGS, LMUL, 3, 2)
FIELD(TB_FLAGS, SEW, 5, 3)
FIELD(TB_FLAGS, VILL, 8, 1)
+/* Is a Hypervisor instruction load/store allowed? */
+FIELD(TB_FLAGS, HLSX, 9, 1)
/*
* A simplification for VLMAX
@@ -420,7 +423,17 @@ static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
if (riscv_cpu_fp_enabled(env)) {
flags |= env->mstatus & MSTATUS_FS;
}
+
+ if (riscv_has_ext(env, RVH)) {
+ if (env->priv == PRV_M ||
+ (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
+ (env->priv == PRV_U && !riscv_cpu_virt_enabled(env) &&
+ get_field(env->hstatus, HSTATUS_HU))) {
+ flags = FIELD_DP32(flags, TB_FLAGS, HLSX, 1);
+ }
+ }
#endif
+
*pflags = flags;
}
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index daedad8691..24b24c69c5 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -469,7 +469,6 @@
* page table fault.
*/
#define FORCE_HS_EXCEP 2
-#define HS_TWO_STAGE 4
/* RV32 satp CSR field masks */
#define SATP32_MODE 0x80000000
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 3eb3a034db..a2787b1d48 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -207,22 +207,9 @@ void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable)
env->virt = set_field(env->virt, FORCE_HS_EXCEP, enable);
}
-bool riscv_cpu_two_stage_lookup(CPURISCVState *env)
+bool riscv_cpu_two_stage_lookup(int mmu_idx)
{
- if (!riscv_has_ext(env, RVH)) {
- return false;
- }
-
- return get_field(env->virt, HS_TWO_STAGE);
-}
-
-void riscv_cpu_set_two_stage_lookup(CPURISCVState *env, bool enable)
-{
- if (!riscv_has_ext(env, RVH)) {
- return;
- }
-
- env->virt = set_field(env->virt, HS_TWO_STAGE, enable);
+ return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK;
}
int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
@@ -323,7 +310,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
* (riscv_cpu_do_interrupt) is correct */
MemTxResult res;
MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
- int mode = mmu_idx;
+ int mode = mmu_idx & TB_FLAGS_PRIV_MMU_MASK;
bool use_background = false;
/*
@@ -333,7 +320,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
* was called. Background registers will be used if the guest has
* forced a two stage translation to be on (in HS or M mode).
*/
- if (riscv_cpu_two_stage_lookup(env) && access_type != MMU_INST_FETCH) {
+ if (!riscv_cpu_virt_enabled(env) && riscv_cpu_two_stage_lookup(mmu_idx)) {
use_background = true;
}
@@ -572,7 +559,7 @@ restart:
static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
MMUAccessType access_type, bool pmp_violation,
- bool first_stage)
+ bool first_stage, bool two_stage)
{
CPUState *cs = env_cpu(env);
int page_fault_exceptions;
@@ -595,8 +582,7 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
}
break;
case MMU_DATA_LOAD:
- if ((riscv_cpu_virt_enabled(env) || riscv_cpu_two_stage_lookup(env)) &&
- !first_stage) {
+ if (two_stage && !first_stage) {
cs->exception_index = RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT;
} else {
cs->exception_index = page_fault_exceptions ?
@@ -604,8 +590,7 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
}
break;
case MMU_DATA_STORE:
- if ((riscv_cpu_virt_enabled(env) || riscv_cpu_two_stage_lookup(env)) &&
- !first_stage) {
+ if (two_stage && !first_stage) {
cs->exception_index = RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT;
} else {
cs->exception_index = page_fault_exceptions ?
@@ -696,6 +681,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
int prot, prot2;
bool pmp_violation = false;
bool first_stage_error = true;
+ bool two_stage_lookup = false;
int ret = TRANSLATE_FAIL;
int mode = mmu_idx;
target_ulong tlb_size = 0;
@@ -715,11 +701,12 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
access_type != MMU_INST_FETCH &&
get_field(env->mstatus, MSTATUS_MPRV) &&
get_field(env->mstatus, MSTATUS_MPV)) {
- riscv_cpu_set_two_stage_lookup(env, true);
+ two_stage_lookup = true;
}
if (riscv_cpu_virt_enabled(env) ||
- (riscv_cpu_two_stage_lookup(env) && access_type != MMU_INST_FETCH)) {
+ ((riscv_cpu_two_stage_lookup(mmu_idx) || two_stage_lookup) &&
+ access_type != MMU_INST_FETCH)) {
/* Two stage lookup */
ret = get_physical_address(env, &pa, &prot, address,
&env->guest_phys_fault_addr, access_type,
@@ -782,14 +769,6 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
__func__, address, ret, pa, prot);
}
- /* We did the two stage lookup based on MPRV, unset the lookup */
- if (riscv_has_ext(env, RVH) && env->priv == PRV_M &&
- access_type != MMU_INST_FETCH &&
- get_field(env->mstatus, MSTATUS_MPRV) &&
- get_field(env->mstatus, MSTATUS_MPV)) {
- riscv_cpu_set_two_stage_lookup(env, false);
- }
-
if (riscv_feature(env, RISCV_FEATURE_PMP) &&
(ret == TRANSLATE_SUCCESS) &&
!pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) {
@@ -811,7 +790,10 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
} else if (probe) {
return false;
} else {
- raise_mmu_exception(env, address, access_type, pmp_violation, first_stage_error);
+ raise_mmu_exception(env, address, access_type, pmp_violation,
+ first_stage_error,
+ riscv_cpu_virt_enabled(env) ||
+ riscv_cpu_two_stage_lookup(mmu_idx));
riscv_raise_exception(env, cs->exception_index, retaddr);
}
@@ -915,9 +897,16 @@ void riscv_cpu_do_interrupt(CPUState *cs)
/* handle the trap in S-mode */
if (riscv_has_ext(env, RVH)) {
target_ulong hdeleg = async ? env->hideleg : env->hedeleg;
+ bool two_stage_lookup = false;
+
+ if (env->priv == PRV_M ||
+ (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
+ (env->priv == PRV_U && !riscv_cpu_virt_enabled(env) &&
+ get_field(env->hstatus, HSTATUS_HU))) {
+ two_stage_lookup = true;
+ }
- if ((riscv_cpu_virt_enabled(env) ||
- riscv_cpu_two_stage_lookup(env)) && write_tval) {
+ if ((riscv_cpu_virt_enabled(env) || two_stage_lookup) && write_tval) {
/*
* If we are writing a guest virtual address to stval, set
* this to 1. If we are trapping to VS we will set this to 0
@@ -955,11 +944,10 @@ void riscv_cpu_do_interrupt(CPUState *cs)
riscv_cpu_set_force_hs_excep(env, 0);
} else {
/* Trap into HS mode */
- if (!riscv_cpu_two_stage_lookup(env)) {
+ if (!two_stage_lookup) {
env->hstatus = set_field(env->hstatus, HSTATUS_SPV,
riscv_cpu_virt_enabled(env));
}
- riscv_cpu_set_two_stage_lookup(env, false);
htval = env->guest_phys_fault_addr;
}
}
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 4b690147fb..939731c345 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -81,9 +81,8 @@ DEF_HELPER_1(tlb_flush, void, env)
#ifndef CONFIG_USER_ONLY
DEF_HELPER_1(hyp_tlb_flush, void, env)
DEF_HELPER_1(hyp_gvma_tlb_flush, void, env)
-DEF_HELPER_4(hyp_load, tl, env, tl, tl, tl)
-DEF_HELPER_5(hyp_store, void, env, tl, tl, tl, tl)
-DEF_HELPER_4(hyp_x_load, tl, env, tl, tl, tl)
+DEF_HELPER_2(hyp_hlvx_hu, tl, env, tl)
+DEF_HELPER_2(hyp_hlvx_wu, tl, env, tl)
#endif
/* Vector functions */
diff --git a/target/riscv/insn_trans/trans_rvh.c.inc b/target/riscv/insn_trans/trans_rvh.c.inc
index 881c9ef4d2..ce7ed5affb 100644
--- a/target/riscv/insn_trans/trans_rvh.c.inc
+++ b/target/riscv/insn_trans/trans_rvh.c.inc
@@ -16,26 +16,34 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#ifndef CONFIG_USER_ONLY
+static void check_access(DisasContext *ctx) {
+ if (!ctx->hlsx) {
+ if (ctx->virt_enabled) {
+ generate_exception(ctx, RISCV_EXCP_VIRT_INSTRUCTION_FAULT);
+ } else {
+ generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST);
+ }
+ }
+}
+#endif
+
static bool trans_hlv_b(DisasContext *ctx, arg_hlv_b *a)
{
REQUIRE_EXT(ctx, RVH);
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
- TCGv mem_idx = tcg_temp_new();
- TCGv memop = tcg_temp_new();
+
+ check_access(ctx);
gen_get_gpr(t0, a->rs1);
- tcg_gen_movi_tl(mem_idx, ctx->mem_idx);
- tcg_gen_movi_tl(memop, MO_SB);
- gen_helper_hyp_load(t1, cpu_env, t0, mem_idx, memop);
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_SB);
gen_set_gpr(a->rd, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);
- tcg_temp_free(mem_idx);
- tcg_temp_free(memop);
return true;
#else
return false;
@@ -48,20 +56,16 @@ static bool trans_hlv_h(DisasContext *ctx, arg_hlv_h *a)
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
- TCGv mem_idx = tcg_temp_new();
- TCGv memop = tcg_temp_new();
+
+ check_access(ctx);
gen_get_gpr(t0, a->rs1);
- tcg_gen_movi_tl(mem_idx, ctx->mem_idx);
- tcg_gen_movi_tl(memop, MO_TESW);
- gen_helper_hyp_load(t1, cpu_env, t0, mem_idx, memop);
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TESW);
gen_set_gpr(a->rd, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);
- tcg_temp_free(mem_idx);
- tcg_temp_free(memop);
return true;
#else
return false;
@@ -74,20 +78,16 @@ static bool trans_hlv_w(DisasContext *ctx, arg_hlv_w *a)
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
- TCGv mem_idx = tcg_temp_new();
- TCGv memop = tcg_temp_new();
+
+ check_access(ctx);
gen_get_gpr(t0, a->rs1);
- tcg_gen_movi_tl(mem_idx, ctx->mem_idx);
- tcg_gen_movi_tl(memop, MO_TESL);
- gen_helper_hyp_load(t1, cpu_env, t0, mem_idx, memop);
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TESL);
gen_set_gpr(a->rd, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);
- tcg_temp_free(mem_idx);
- tcg_temp_free(memop);
return true;
#else
return false;
@@ -100,20 +100,16 @@ static bool trans_hlv_bu(DisasContext *ctx, arg_hlv_bu *a)
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
- TCGv mem_idx = tcg_temp_new();
- TCGv memop = tcg_temp_new();
+
+ check_access(ctx);
gen_get_gpr(t0, a->rs1);
- tcg_gen_movi_tl(mem_idx, ctx->mem_idx);
- tcg_gen_movi_tl(memop, MO_UB);
- gen_helper_hyp_load(t1, cpu_env, t0, mem_idx, memop);
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_UB);
gen_set_gpr(a->rd, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);
- tcg_temp_free(mem_idx);
- tcg_temp_free(memop);
return true;
#else
return false;
@@ -126,20 +122,15 @@ static bool trans_hlv_hu(DisasContext *ctx, arg_hlv_hu *a)
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
- TCGv mem_idx = tcg_temp_new();
- TCGv memop = tcg_temp_new();
- gen_get_gpr(t0, a->rs1);
- tcg_gen_movi_tl(mem_idx, ctx->mem_idx);
- tcg_gen_movi_tl(memop, MO_TEUW);
+ check_access(ctx);
- gen_helper_hyp_load(t1, cpu_env, t0, mem_idx, memop);
+ gen_get_gpr(t0, a->rs1);
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEUW);
gen_set_gpr(a->rd, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);
- tcg_temp_free(mem_idx);
- tcg_temp_free(memop);
return true;
#else
return false;
@@ -152,20 +143,16 @@ static bool trans_hsv_b(DisasContext *ctx, arg_hsv_b *a)
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv dat = tcg_temp_new();
- TCGv mem_idx = tcg_temp_new();
- TCGv memop = tcg_temp_new();
+
+ check_access(ctx);
gen_get_gpr(t0, a->rs1);
gen_get_gpr(dat, a->rs2);
- tcg_gen_movi_tl(mem_idx, ctx->mem_idx);
- tcg_gen_movi_tl(memop, MO_SB);
- gen_helper_hyp_store(cpu_env, t0, dat, mem_idx, memop);
+ tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_SB);
tcg_temp_free(t0);
tcg_temp_free(dat);
- tcg_temp_free(mem_idx);
- tcg_temp_free(memop);
return true;
#else
return false;
@@ -178,20 +165,16 @@ static bool trans_hsv_h(DisasContext *ctx, arg_hsv_h *a)
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv dat = tcg_temp_new();
- TCGv mem_idx = tcg_temp_new();
- TCGv memop = tcg_temp_new();
+
+ check_access(ctx);
gen_get_gpr(t0, a->rs1);
gen_get_gpr(dat, a->rs2);
- tcg_gen_movi_tl(mem_idx, ctx->mem_idx);
- tcg_gen_movi_tl(memop, MO_TESW);
- gen_helper_hyp_store(cpu_env, t0, dat, mem_idx, memop);
+ tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TESW);
tcg_temp_free(t0);
tcg_temp_free(dat);
- tcg_temp_free(mem_idx);
- tcg_temp_free(memop);
return true;
#else
return false;
@@ -204,20 +187,16 @@ static bool trans_hsv_w(DisasContext *ctx, arg_hsv_w *a)
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv dat = tcg_temp_new();
- TCGv mem_idx = tcg_temp_new();
- TCGv memop = tcg_temp_new();
+
+ check_access(ctx);
gen_get_gpr(t0, a->rs1);
gen_get_gpr(dat, a->rs2);
- tcg_gen_movi_tl(mem_idx, ctx->mem_idx);
- tcg_gen_movi_tl(memop, MO_TESL);
- gen_helper_hyp_store(cpu_env, t0, dat, mem_idx, memop);
+ tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TESL);
tcg_temp_free(t0);
tcg_temp_free(dat);
- tcg_temp_free(mem_idx);
- tcg_temp_free(memop);
return true;
#else
return false;
@@ -231,20 +210,16 @@ static bool trans_hlv_wu(DisasContext *ctx, arg_hlv_wu *a)
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
- TCGv mem_idx = tcg_temp_new();
- TCGv memop = tcg_temp_new();
+
+ check_access(ctx);
gen_get_gpr(t0, a->rs1);
- tcg_gen_movi_tl(mem_idx, ctx->mem_idx);
- tcg_gen_movi_tl(memop, MO_TEUL);
- gen_helper_hyp_load(t1, cpu_env, t0, mem_idx, memop);
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEUL);
gen_set_gpr(a->rd, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);
- tcg_temp_free(mem_idx);
- tcg_temp_free(memop);
return true;
#else
return false;
@@ -257,20 +232,16 @@ static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a)
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
- TCGv mem_idx = tcg_temp_new();
- TCGv memop = tcg_temp_new();
+
+ check_access(ctx);
gen_get_gpr(t0, a->rs1);
- tcg_gen_movi_tl(mem_idx, ctx->mem_idx);
- tcg_gen_movi_tl(memop, MO_TEQ);
- gen_helper_hyp_load(t1, cpu_env, t0, mem_idx, memop);
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEQ);
gen_set_gpr(a->rd, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);
- tcg_temp_free(mem_idx);
- tcg_temp_free(memop);
return true;
#else
return false;
@@ -283,20 +254,16 @@ static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a)
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv dat = tcg_temp_new();
- TCGv mem_idx = tcg_temp_new();
- TCGv memop = tcg_temp_new();
+
+ check_access(ctx);
gen_get_gpr(t0, a->rs1);
gen_get_gpr(dat, a->rs2);
- tcg_gen_movi_tl(mem_idx, ctx->mem_idx);
- tcg_gen_movi_tl(memop, MO_TEQ);
- gen_helper_hyp_store(cpu_env, t0, dat, mem_idx, memop);
+ tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEQ);
tcg_temp_free(t0);
tcg_temp_free(dat);
- tcg_temp_free(mem_idx);
- tcg_temp_free(memop);
return true;
#else
return false;
@@ -310,20 +277,16 @@ static bool trans_hlvx_hu(DisasContext *ctx, arg_hlvx_hu *a)
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
- TCGv mem_idx = tcg_temp_new();
- TCGv memop = tcg_temp_new();
+
+ check_access(ctx);
gen_get_gpr(t0, a->rs1);
- tcg_gen_movi_tl(mem_idx, ctx->mem_idx);
- tcg_gen_movi_tl(memop, MO_TEUW);
- gen_helper_hyp_x_load(t1, cpu_env, t0, mem_idx, memop);
+ gen_helper_hyp_hlvx_hu(t1, cpu_env, t0);
gen_set_gpr(a->rd, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);
- tcg_temp_free(mem_idx);
- tcg_temp_free(memop);
return true;
#else
return false;
@@ -336,20 +299,16 @@ static bool trans_hlvx_wu(DisasContext *ctx, arg_hlvx_wu *a)
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
- TCGv mem_idx = tcg_temp_new();
- TCGv memop = tcg_temp_new();
+
+ check_access(ctx);
gen_get_gpr(t0, a->rs1);
- tcg_gen_movi_tl(mem_idx, ctx->mem_idx);
- tcg_gen_movi_tl(memop, MO_TEUL);
- gen_helper_hyp_x_load(t1, cpu_env, t0, mem_idx, memop);
+ gen_helper_hyp_hlvx_wu(t1, cpu_env, t0);
gen_set_gpr(a->rd, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);
- tcg_temp_free(mem_idx);
- tcg_temp_free(memop);
return true;
#else
return false;
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index e20d56dcb8..d55def76cf 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -227,130 +227,18 @@ void helper_hyp_gvma_tlb_flush(CPURISCVState *env)
helper_hyp_tlb_flush(env);
}
-target_ulong helper_hyp_load(CPURISCVState *env, target_ulong address,
- target_ulong attrs, target_ulong memop)
+target_ulong helper_hyp_hlvx_hu(CPURISCVState *env, target_ulong address)
{
- if (env->priv == PRV_M ||
- (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
- (env->priv == PRV_U && !riscv_cpu_virt_enabled(env) &&
- get_field(env->hstatus, HSTATUS_HU))) {
- target_ulong pte;
-
- riscv_cpu_set_two_stage_lookup(env, true);
-
- switch (memop) {
- case MO_SB:
- pte = cpu_ldsb_data_ra(env, address, GETPC());
- break;
- case MO_UB:
- pte = cpu_ldub_data_ra(env, address, GETPC());
- break;
- case MO_TESW:
- pte = cpu_ldsw_data_ra(env, address, GETPC());
- break;
- case MO_TEUW:
- pte = cpu_lduw_data_ra(env, address, GETPC());
- break;
- case MO_TESL:
- pte = cpu_ldl_data_ra(env, address, GETPC());
- break;
- case MO_TEUL:
- pte = cpu_ldl_data_ra(env, address, GETPC());
- break;
- case MO_TEQ:
- pte = cpu_ldq_data_ra(env, address, GETPC());
- break;
- default:
- g_assert_not_reached();
- }
-
- riscv_cpu_set_two_stage_lookup(env, false);
-
- return pte;
- }
-
- if (riscv_cpu_virt_enabled(env)) {
- riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
- } else {
- riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
- }
- return 0;
-}
-
-void helper_hyp_store(CPURISCVState *env, target_ulong address,
- target_ulong val, target_ulong attrs, target_ulong memop)
-{
- if (env->priv == PRV_M ||
- (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
- (env->priv == PRV_U && !riscv_cpu_virt_enabled(env) &&
- get_field(env->hstatus, HSTATUS_HU))) {
- riscv_cpu_set_two_stage_lookup(env, true);
-
- switch (memop) {
- case MO_SB:
- case MO_UB:
- cpu_stb_data_ra(env, address, val, GETPC());
- break;
- case MO_TESW:
- case MO_TEUW:
- cpu_stw_data_ra(env, address, val, GETPC());
- break;
- case MO_TESL:
- case MO_TEUL:
- cpu_stl_data_ra(env, address, val, GETPC());
- break;
- case MO_TEQ:
- cpu_stq_data_ra(env, address, val, GETPC());
- break;
- default:
- g_assert_not_reached();
- }
-
- riscv_cpu_set_two_stage_lookup(env, false);
+ int mmu_idx = cpu_mmu_index(env, true) | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
- return;
- }
-
- if (riscv_cpu_virt_enabled(env)) {
- riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
- } else {
- riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
- }
+ return cpu_lduw_mmuidx_ra(env, address, mmu_idx, GETPC());
}
-target_ulong helper_hyp_x_load(CPURISCVState *env, target_ulong address,
- target_ulong attrs, target_ulong memop)
+target_ulong helper_hyp_hlvx_wu(CPURISCVState *env, target_ulong address)
{
- if (env->priv == PRV_M ||
- (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
- (env->priv == PRV_U && !riscv_cpu_virt_enabled(env) &&
- get_field(env->hstatus, HSTATUS_HU))) {
- target_ulong pte;
-
- riscv_cpu_set_two_stage_lookup(env, true);
-
- switch (memop) {
- case MO_TEUW:
- pte = cpu_lduw_data_ra(env, address, GETPC());
- break;
- case MO_TEUL:
- pte = cpu_ldl_data_ra(env, address, GETPC());
- break;
- default:
- g_assert_not_reached();
- }
-
- riscv_cpu_set_two_stage_lookup(env, false);
-
- return pte;
- }
+ int mmu_idx = cpu_mmu_index(env, true) | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
- if (riscv_cpu_virt_enabled(env)) {
- riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
- } else {
- riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
- }
- return 0;
+ return cpu_ldl_mmuidx_ra(env, address, mmu_idx, GETPC());
}
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 79dca2291b..554d52a4be 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -56,6 +56,7 @@ typedef struct DisasContext {
to reset this known value. */
int frm;
bool ext_ifencei;
+ bool hlsx;
/* vector extension */
bool vill;
uint8_t lmul;
@@ -807,6 +808,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->frm = -1; /* unknown rounding mode */
ctx->ext_ifencei = cpu->cfg.ext_ifencei;
ctx->vlen = cpu->cfg.vlen;
+ ctx->hlsx = FIELD_EX32(tb_flags, TB_FLAGS, HLSX);
ctx->vill = FIELD_EX32(tb_flags, TB_FLAGS, VILL);
ctx->sew = FIELD_EX32(tb_flags, TB_FLAGS, SEW);
ctx->lmul = FIELD_EX32(tb_flags, TB_FLAGS, LMUL);
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 461e0b8f4a..b5abff8bef 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -986,7 +986,7 @@ void s390_realize_cpu_model(CPUState *cs, Error **errp)
static void get_feature(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- S390Feat feat = (S390Feat) opaque;
+ S390Feat feat = (S390Feat) (uintptr_t) opaque;
S390CPU *cpu = S390_CPU(obj);
bool value;
@@ -1003,7 +1003,7 @@ static void get_feature(Object *obj, Visitor *v, const char *name,
static void set_feature(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- S390Feat feat = (S390Feat) opaque;
+ S390Feat feat = (S390Feat) (uintptr_t) opaque;
DeviceState *dev = DEVICE(obj);
S390CPU *cpu = S390_CPU(obj);
bool value;
@@ -1037,7 +1037,7 @@ static void set_feature(Object *obj, Visitor *v, const char *name,
static void get_feature_group(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- S390FeatGroup group = (S390FeatGroup) opaque;
+ S390FeatGroup group = (S390FeatGroup) (uintptr_t) opaque;
const S390FeatGroupDef *def = s390_feat_group_def(group);
S390CPU *cpu = S390_CPU(obj);
S390FeatBitmap tmp;
@@ -1058,7 +1058,7 @@ static void get_feature_group(Object *obj, Visitor *v, const char *name,
static void set_feature_group(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- S390FeatGroup group = (S390FeatGroup) opaque;
+ S390FeatGroup group = (S390FeatGroup) (uintptr_t) opaque;
const S390FeatGroupDef *def = s390_feat_group_def(group);
DeviceState *dev = DEVICE(obj);
S390CPU *cpu = S390_CPU(obj);
diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240
index 8b4337b58d..c0f71f0461 100755
--- a/tests/qemu-iotests/240
+++ b/tests/qemu-iotests/240
@@ -1,5 +1,5 @@
-#!/usr/bin/env bash
-#
+#!/usr/bin/env python3
+
# Test hot plugging and unplugging with iothreads
#
# Copyright (C) 2019 Igalia, S.L.
@@ -17,133 +17,90 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# creator
-owner=berto@igalia.com
-
-seq=`basename $0`
-echo "QA output created by $seq"
-
-status=1 # failure is the default!
-
-_cleanup()
-{
- rm -f "$SOCK_DIR/nbd"
-}
-trap "_cleanup; exit \$status" 0 1 2 3 15
-
-# get standard environment, filters and checks
-. ./common.rc
-. ./common.filter
-
-_supported_fmt generic
-_supported_proto generic
-
-do_run_qemu()
-{
- echo Testing: "$@"
- $QEMU -nographic -qmp stdio -serial none "$@"
- echo
-}
-
-# Remove QMP events from (pretty-printed) output. Doesn't handle
-# nested dicts correctly, but we don't get any of those in this test.
-_filter_qmp_events()
-{
- tr '\n' '\t' | sed -e \
- 's/{\s*"timestamp":\s*{[^}]*},\s*"event":[^,}]*\(,\s*"data":\s*{[^}]*}\)\?\s*}\s*//g' \
- | tr '\t' '\n'
-}
-
-run_qemu()
-{
- do_run_qemu "$@" 2>&1 | _filter_qmp | _filter_qmp_events
-}
-
-case "$QEMU_DEFAULT_MACHINE" in
- s390-ccw-virtio)
- virtio_scsi=virtio-scsi-ccw
- ;;
- *)
- virtio_scsi=virtio-scsi-pci
- ;;
-esac
-
-echo
-echo === Unplug a SCSI disk and then plug it again ===
-echo
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "blockdev-add", "arguments": {"driver": "null-co", "read-zeroes": true, "node-name": "hd0"}}
-{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread0"}}
-{ "execute": "device_add", "arguments": {"id": "scsi0", "driver": "${virtio_scsi}", "iothread": "iothread0"}}
-{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0"}}
-{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}}
-{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0"}}
-{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}}
-{ "execute": "device_del", "arguments": {"id": "scsi0"}}
-{ "execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
-{ "execute": "quit"}
-EOF
-
-echo
-echo === Attach two SCSI disks using the same block device and the same iothread ===
-echo
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "blockdev-add", "arguments": {"driver": "null-co", "read-zeroes": true, "node-name": "hd0", "read-only": true}}
-{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread0"}}
-{ "execute": "device_add", "arguments": {"id": "scsi0", "driver": "${virtio_scsi}", "iothread": "iothread0"}}
-{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0"}}
-{ "execute": "device_add", "arguments": {"id": "scsi-hd1", "driver": "scsi-hd", "drive": "hd0"}}
-{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}}
-{ "execute": "device_del", "arguments": {"id": "scsi-hd1"}}
-{ "execute": "device_del", "arguments": {"id": "scsi0"}}
-{ "execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
-{ "execute": "quit"}
-EOF
-
-echo
-echo === Attach two SCSI disks using the same block device but different iothreads ===
-echo
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "blockdev-add", "arguments": {"driver": "null-co", "read-zeroes": true, "node-name": "hd0", "read-only": true}}
-{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread0"}}
-{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread1"}}
-{ "execute": "device_add", "arguments": {"id": "scsi0", "driver": "${virtio_scsi}", "iothread": "iothread0"}}
-{ "execute": "device_add", "arguments": {"id": "scsi1", "driver": "${virtio_scsi}", "iothread": "iothread1"}}
-{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0", "bus": "scsi0.0"}}
-{ "execute": "device_add", "arguments": {"id": "scsi-hd1", "driver": "scsi-hd", "drive": "hd0", "bus": "scsi1.0"}}
-{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}}
-{ "execute": "device_add", "arguments": {"id": "scsi-hd1", "driver": "scsi-hd", "drive": "hd0", "bus": "scsi1.0"}}
-{ "execute": "device_del", "arguments": {"id": "scsi-hd1"}}
-{ "execute": "device_del", "arguments": {"id": "scsi0"}}
-{ "execute": "device_del", "arguments": {"id": "scsi1"}}
-{ "execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
-{ "execute": "quit"}
-EOF
-
-echo
-echo === Attach a SCSI disks using the same block device as a NBD server ===
-echo
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "blockdev-add", "arguments": {"driver": "null-co", "read-zeroes": true, "node-name": "hd0", "read-only": true}}
-{ "execute": "nbd-server-start", "arguments": {"addr":{"type":"unix","data":{"path":"$SOCK_DIR/nbd"}}}}
-{ "execute": "nbd-server-add", "arguments": {"device":"hd0"}}
-{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread0"}}
-{ "execute": "device_add", "arguments": {"id": "scsi0", "driver": "${virtio_scsi}", "iothread": "iothread0"}}
-{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0", "bus": "scsi0.0"}}
-{ "execute": "quit"}
-EOF
-
-# success, all done
-echo "*** done"
-rm -f $seq.full
-status=0
+import iotests
+import os
+
+nbd_sock = iotests.file_path('nbd.sock', base_dir=iotests.sock_dir)
+
+class TestCase(iotests.QMPTestCase):
+ test_driver = "null-co"
+
+ def required_drivers(self):
+ return [self.test_driver]
+
+ @iotests.skip_if_unsupported(required_drivers)
+ def setUp(self):
+ self.vm = iotests.VM()
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+
+ def test1(self):
+ iotests.log('==Unplug a SCSI disk and then plug it again==')
+ self.vm.qmp_log('blockdev-add', driver='null-co', read_zeroes=True, node_name='hd0')
+ self.vm.qmp_log('object-add', qom_type='iothread', id="iothread0")
+ self.vm.qmp_log('device_add', id='scsi0', driver=iotests.get_virtio_scsi_device(), iothread='iothread0', filters=[iotests.filter_qmp_virtio_scsi])
+ self.vm.qmp_log('device_add', id='scsi-hd0', driver='scsi-hd', drive='hd0')
+ self.vm.qmp_log('device_del', id='scsi-hd0')
+ self.vm.event_wait('DEVICE_DELETED')
+ self.vm.qmp_log('device_add', id='scsi-hd0', driver='scsi-hd', drive='hd0')
+ self.vm.qmp_log('device_del', id='scsi-hd0')
+ self.vm.event_wait('DEVICE_DELETED')
+ self.vm.qmp_log('blockdev-del', node_name='hd0')
+
+ def test2(self):
+ iotests.log('==Attach two SCSI disks using the same block device and the same iothread==')
+ self.vm.qmp_log('blockdev-add', driver='null-co', read_zeroes=True, node_name='hd0', read_only=True)
+ self.vm.qmp_log('object-add', qom_type='iothread', id="iothread0")
+ self.vm.qmp_log('device_add', id='scsi0', driver=iotests.get_virtio_scsi_device(), iothread='iothread0', filters=[iotests.filter_qmp_virtio_scsi])
+
+ self.vm.qmp_log('device_add', id='scsi-hd0', driver='scsi-hd', drive='hd0')
+ self.vm.qmp_log('device_add', id='scsi-hd1', driver='scsi-hd', drive='hd0')
+ self.vm.qmp_log('device_del', id='scsi-hd0')
+ self.vm.event_wait('DEVICE_DELETED')
+ self.vm.qmp_log('device_del', id='scsi-hd1')
+ self.vm.event_wait('DEVICE_DELETED')
+ self.vm.qmp_log('blockdev-del', node_name='hd0')
+
+ def test3(self):
+ iotests.log('==Attach two SCSI disks using the same block device but different iothreads==')
+
+ self.vm.qmp_log('blockdev-add', driver='null-co', read_zeroes=True, node_name='hd0', read_only=True)
+
+ self.vm.qmp_log('object-add', qom_type='iothread', id="iothread0")
+ self.vm.qmp_log('object-add', qom_type='iothread', id="iothread1")
+
+ self.vm.qmp_log('device_add', id='scsi0', driver=iotests.get_virtio_scsi_device(), iothread='iothread0', filters=[iotests.filter_qmp_virtio_scsi])
+ self.vm.qmp_log('device_add', id='scsi1', driver=iotests.get_virtio_scsi_device(), iothread='iothread1', filters=[iotests.filter_qmp_virtio_scsi])
+
+ self.vm.qmp_log('device_add', id='scsi-hd0', driver='scsi-hd', drive='hd0', bus="scsi0.0")
+ self.vm.qmp_log('device_add', id='scsi-hd1', driver='scsi-hd', drive='hd0', bus="scsi1.0")
+
+ self.vm.qmp_log('device_del', id='scsi-hd0')
+ self.vm.event_wait('DEVICE_DELETED')
+ self.vm.qmp_log('device_add', id='scsi-hd1', driver='scsi-hd', drive='hd0', bus="scsi1.0")
+
+ self.vm.qmp_log('device_del', id='scsi-hd1')
+ self.vm.event_wait('DEVICE_DELETED')
+ self.vm.qmp_log('blockdev-del', node_name='hd0')
+
+ def test4(self):
+ iotests.log('==Attach a SCSI disks using the same block device as a NBD server==')
+
+ self.vm.qmp_log('blockdev-add', driver='null-co', read_zeroes=True, node_name='hd0', read_only=True)
+
+ self.vm.qmp_log('nbd-server-start',
+ filters=[iotests.filter_qmp_testfiles],
+ addr={'type':'unix', 'data':{'path':nbd_sock}})
+
+ self.vm.qmp_log('nbd-server-add', device='hd0')
+
+ self.vm.qmp_log('object-add', qom_type='iothread', id="iothread0")
+ self.vm.qmp_log('device_add', id='scsi0', driver=iotests.get_virtio_scsi_device(), iothread='iothread0', filters=[iotests.filter_qmp_virtio_scsi])
+ self.vm.qmp_log('device_add', id='scsi-hd0', driver='scsi-hd', drive='hd0')
+
+if __name__ == '__main__':
+ iotests.activate_logging()
+ iotests.main()
diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out
index d00df50297..e0982831ae 100644
--- a/tests/qemu-iotests/240.out
+++ b/tests/qemu-iotests/240.out
@@ -1,67 +1,75 @@
-QA output created by 240
-
-=== Unplug a SCSI disk and then plug it again ===
-
-Testing:
-QMP_VERSION
-{"return": {}}
+==Unplug a SCSI disk and then plug it again==
+{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-zeroes": true}}
{"return": {}}
+{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
{"return": {}}
+{"execute": "device_add", "arguments": {"driver": "virtio-scsi", "id": "scsi0", "iothread": "iothread0"}}
{"return": {}}
+{"execute": "device_add", "arguments": {"drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}}
{"return": {}}
+{"execute": "device_del", "arguments": {"id": "scsi-hd0"}}
{"return": {}}
+{"execute": "device_add", "arguments": {"drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}}
{"return": {}}
+{"execute": "device_del", "arguments": {"id": "scsi-hd0"}}
{"return": {}}
+{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
{"return": {}}
+==Attach two SCSI disks using the same block device and the same iothread==
+{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
{"return": {}}
+{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
{"return": {}}
-
-=== Attach two SCSI disks using the same block device and the same iothread ===
-
-Testing:
-QMP_VERSION
-{"return": {}}
+{"execute": "device_add", "arguments": {"driver": "virtio-scsi", "id": "scsi0", "iothread": "iothread0"}}
{"return": {}}
+{"execute": "device_add", "arguments": {"drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}}
{"return": {}}
+{"execute": "device_add", "arguments": {"drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd1"}}
{"return": {}}
+{"execute": "device_del", "arguments": {"id": "scsi-hd0"}}
{"return": {}}
+{"execute": "device_del", "arguments": {"id": "scsi-hd1"}}
{"return": {}}
+{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
{"return": {}}
+==Attach two SCSI disks using the same block device but different iothreads==
+{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
{"return": {}}
+{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
{"return": {}}
+{"execute": "object-add", "arguments": {"id": "iothread1", "qom-type": "iothread"}}
{"return": {}}
+{"execute": "device_add", "arguments": {"driver": "virtio-scsi", "id": "scsi0", "iothread": "iothread0"}}
{"return": {}}
-
-=== Attach two SCSI disks using the same block device but different iothreads ===
-
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
+{"execute": "device_add", "arguments": {"driver": "virtio-scsi", "id": "scsi1", "iothread": "iothread1"}}
{"return": {}}
+{"execute": "device_add", "arguments": {"bus": "scsi0.0", "drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}}
{"return": {}}
+{"execute": "device_add", "arguments": {"bus": "scsi1.0", "drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd1"}}
{"error": {"class": "GenericError", "desc": "Cannot change iothread of active block backend"}}
+{"execute": "device_del", "arguments": {"id": "scsi-hd0"}}
{"return": {}}
+{"execute": "device_add", "arguments": {"bus": "scsi1.0", "drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd1"}}
{"return": {}}
+{"execute": "device_del", "arguments": {"id": "scsi-hd1"}}
{"return": {}}
+{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
{"return": {}}
+==Attach a SCSI disks using the same block device as a NBD server==
+{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
{"return": {}}
+{"execute": "nbd-server-start", "arguments": {"addr": {"data": {"path": "SOCK_DIR/PID-nbd.sock"}, "type": "unix"}}}
{"return": {}}
+{"execute": "nbd-server-add", "arguments": {"device": "hd0"}}
{"return": {}}
-
-=== Attach a SCSI disks using the same block device as a NBD server ===
-
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
+{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
{"return": {}}
+{"execute": "device_add", "arguments": {"driver": "virtio-scsi", "id": "scsi0", "iothread": "iothread0"}}
{"return": {}}
+{"execute": "device_add", "arguments": {"drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}}
{"return": {}}
-{"return": {}}
-*** done
+....
+----------------------------------------------------------------------
+Ran 4 tests
+
+OK
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 814804a4c6..bcd4fe5b6f 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -392,6 +392,16 @@ def filter_qmp_testfiles(qmsg):
return value
return filter_qmp(qmsg, _filter)
+def filter_virtio_scsi(output: str) -> str:
+ return re.sub(r'(virtio-scsi)-(ccw|pci)', r'\1', output)
+
+def filter_qmp_virtio_scsi(qmsg):
+ def _filter(_key, value):
+ if is_str(value):
+ return filter_virtio_scsi(value)
+ return value
+ return filter_qmp(qmsg, _filter)
+
def filter_generated_node_ids(msg):
return re.sub("#block[0-9]+", "NODE_NAME", msg)
diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c
index d20094d5a7..bc681a95d5 100644
--- a/tests/qtest/arm-cpu-features.c
+++ b/tests/qtest/arm-cpu-features.c
@@ -536,7 +536,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
if (kvm_supports_sve) {
g_assert(vls != 0);
max_vq = 64 - __builtin_clzll(vls);
- sprintf(max_name, "sve%d", max_vq * 128);
+ sprintf(max_name, "sve%u", max_vq * 128);
/* Enabling a supported length is of course fine. */
assert_sve_vls(qts, "host", vls, "{ %s: true }", max_name);
@@ -556,7 +556,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
* unless all larger, supported vector lengths are also
* disabled.
*/
- sprintf(name, "sve%d", vq * 128);
+ sprintf(name, "sve%u", vq * 128);
error = g_strdup_printf("cannot disable %s", name);
assert_error(qts, "host", error,
"{ %s: true, %s: false }",
@@ -569,7 +569,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
* we need at least one vector length enabled.
*/
vq = __builtin_ffsll(vls);
- sprintf(name, "sve%d", vq * 128);
+ sprintf(name, "sve%u", vq * 128);
error = g_strdup_printf("cannot disable %s", name);
assert_error(qts, "host", error, "{ %s: false }", name);
g_free(error);
@@ -581,7 +581,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
}
}
if (vq <= SVE_MAX_VQ) {
- sprintf(name, "sve%d", vq * 128);
+ sprintf(name, "sve%u", vq * 128);
error = g_strdup_printf("cannot enable %s", name);
assert_error(qts, "host", error, "{ %s: true }", name);
g_free(error);
diff --git a/tests/qtest/fuzz/fork_fuzz.ld b/tests/qtest/fuzz/fork_fuzz.ld
index bfb667ed06..cfb88b7fdb 100644
--- a/tests/qtest/fuzz/fork_fuzz.ld
+++ b/tests/qtest/fuzz/fork_fuzz.ld
@@ -16,6 +16,11 @@ SECTIONS
/* Lowest stack counter */
*(__sancov_lowest_stack);
}
+}
+INSERT AFTER .data;
+
+SECTIONS
+{
.data.fuzz_ordered :
{
/*
@@ -34,6 +39,11 @@ SECTIONS
*/
*(.bss._ZN6fuzzer3TPCE);
}
+}
+INSERT AFTER .data.fuzz_start;
+
+SECTIONS
+{
.data.fuzz_end : ALIGN(4K)
{
__FUZZ_COUNTERS_END = .;
@@ -43,4 +53,4 @@ SECTIONS
* Don't overwrite the SECTIONS in the default linker script. Instead insert the
* above into the default script
*/
-INSERT AFTER .data;
+INSERT AFTER .data.fuzz_ordered;
diff --git a/tests/qtest/fuzz/meson.build b/tests/qtest/fuzz/meson.build
index 5162321f30..8af6848cd5 100644
--- a/tests/qtest/fuzz/meson.build
+++ b/tests/qtest/fuzz/meson.build
@@ -5,6 +5,7 @@ specific_fuzz_ss.add(files('fuzz.c', 'fork_fuzz.c', 'qos_fuzz.c',
specific_fuzz_ss.add(when: 'CONFIG_I440FX', if_true: files('i440fx_fuzz.c'))
specific_fuzz_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('virtio_net_fuzz.c'))
specific_fuzz_ss.add(when: 'CONFIG_VIRTIO_SCSI', if_true: files('virtio_scsi_fuzz.c'))
+specific_fuzz_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio_blk_fuzz.c'))
specific_fuzz_ss.add(files('generic_fuzz.c'))
fork_fuzz = declare_dependency(
diff --git a/tests/qtest/fuzz/virtio_blk_fuzz.c b/tests/qtest/fuzz/virtio_blk_fuzz.c
new file mode 100644
index 0000000000..623a756fd4
--- /dev/null
+++ b/tests/qtest/fuzz/virtio_blk_fuzz.c
@@ -0,0 +1,234 @@
+/*
+ * virtio-blk Fuzzing Target
+ *
+ * Copyright Red Hat Inc., 2020
+ *
+ * Based on virtio-scsi-fuzz target.
+ *
+ * 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 "tests/qtest/libqos/libqtest.h"
+#include "tests/qtest/libqos/virtio-blk.h"
+#include "tests/qtest/libqos/virtio.h"
+#include "tests/qtest/libqos/virtio-pci.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/virtio_pci.h"
+#include "standard-headers/linux/virtio_blk.h"
+#include "fuzz.h"
+#include "fork_fuzz.h"
+#include "qos_fuzz.h"
+
+#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
+#define PCI_SLOT 0x02
+#define PCI_FN 0x00
+
+#define MAX_NUM_QUEUES 64
+
+/* Based on tests/qtest/virtio-blk-test.c. */
+typedef struct {
+ int num_queues;
+ QVirtQueue *vq[MAX_NUM_QUEUES + 2];
+} QVirtioBlkQueues;
+
+static QVirtioBlkQueues *qvirtio_blk_init(QVirtioDevice *dev, uint64_t mask)
+{
+ QVirtioBlkQueues *vs;
+ uint64_t features;
+
+ vs = g_new0(QVirtioBlkQueues, 1);
+
+ features = qvirtio_get_features(dev);
+ if (!mask) {
+ mask = ~((1u << VIRTIO_RING_F_INDIRECT_DESC) |
+ (1u << VIRTIO_RING_F_EVENT_IDX) |
+ (1u << VIRTIO_BLK_F_SCSI));
+ }
+ mask |= ~QVIRTIO_F_BAD_FEATURE;
+ features &= mask;
+ qvirtio_set_features(dev, features);
+
+ vs->num_queues = 1;
+ vs->vq[0] = qvirtqueue_setup(dev, fuzz_qos_alloc, 0);
+
+ qvirtio_set_driver_ok(dev);
+
+ return vs;
+}
+
+static void virtio_blk_fuzz(QTestState *s, QVirtioBlkQueues* queues,
+ const unsigned char *Data, size_t Size)
+{
+ /*
+ * Data is a sequence of random bytes. We split them up into "actions",
+ * followed by data:
+ * [vqa][dddddddd][vqa][dddd][vqa][dddddddddddd] ...
+ * The length of the data is specified by the preceding vqa.length
+ */
+ typedef struct vq_action {
+ uint8_t queue;
+ uint8_t length;
+ uint8_t write;
+ uint8_t next;
+ uint8_t kick;
+ } vq_action;
+
+ /* Keep track of the free head for each queue we interact with */
+ bool vq_touched[MAX_NUM_QUEUES + 2] = {0};
+ uint32_t free_head[MAX_NUM_QUEUES + 2];
+
+ QGuestAllocator *t_alloc = fuzz_qos_alloc;
+
+ QVirtioBlk *blk = fuzz_qos_obj;
+ QVirtioDevice *dev = blk->vdev;
+ QVirtQueue *q;
+ vq_action vqa;
+ while (Size >= sizeof(vqa)) {
+ /* Copy the action, so we can normalize length, queue and flags */
+ memcpy(&vqa, Data, sizeof(vqa));
+
+ Data += sizeof(vqa);
+ Size -= sizeof(vqa);
+
+ vqa.queue = vqa.queue % queues->num_queues;
+ /* Cap length at the number of remaining bytes in data */
+ vqa.length = vqa.length >= Size ? Size : vqa.length;
+ vqa.write = vqa.write & 1;
+ vqa.next = vqa.next & 1;
+ vqa.kick = vqa.kick & 1;
+
+ q = queues->vq[vqa.queue];
+
+ /* Copy the data into ram, and place it on the virtqueue */
+ uint64_t req_addr = guest_alloc(t_alloc, vqa.length);
+ qtest_memwrite(s, req_addr, Data, vqa.length);
+ if (vq_touched[vqa.queue] == 0) {
+ vq_touched[vqa.queue] = 1;
+ free_head[vqa.queue] = qvirtqueue_add(s, q, req_addr, vqa.length,
+ vqa.write, vqa.next);
+ } else {
+ qvirtqueue_add(s, q, req_addr, vqa.length, vqa.write , vqa.next);
+ }
+
+ if (vqa.kick) {
+ qvirtqueue_kick(s, dev, q, free_head[vqa.queue]);
+ free_head[vqa.queue] = 0;
+ }
+ Data += vqa.length;
+ Size -= vqa.length;
+ }
+ /* In the end, kick each queue we interacted with */
+ for (int i = 0; i < MAX_NUM_QUEUES + 2; i++) {
+ if (vq_touched[i]) {
+ qvirtqueue_kick(s, dev, queues->vq[i], free_head[i]);
+ }
+ }
+}
+
+static void virtio_blk_fork_fuzz(QTestState *s,
+ const unsigned char *Data, size_t Size)
+{
+ QVirtioBlk *blk = fuzz_qos_obj;
+ static QVirtioBlkQueues *queues;
+ if (!queues) {
+ queues = qvirtio_blk_init(blk->vdev, 0);
+ }
+ if (fork() == 0) {
+ virtio_blk_fuzz(s, queues, Data, Size);
+ flush_events(s);
+ _Exit(0);
+ } else {
+ flush_events(s);
+ wait(NULL);
+ }
+}
+
+static void virtio_blk_with_flag_fuzz(QTestState *s,
+ const unsigned char *Data, size_t Size)
+{
+ QVirtioBlk *blk = fuzz_qos_obj;
+ static QVirtioBlkQueues *queues;
+
+ if (fork() == 0) {
+ if (Size >= sizeof(uint64_t)) {
+ queues = qvirtio_blk_init(blk->vdev, *(uint64_t *)Data);
+ virtio_blk_fuzz(s, queues,
+ Data + sizeof(uint64_t), Size - sizeof(uint64_t));
+ flush_events(s);
+ }
+ _Exit(0);
+ } else {
+ flush_events(s);
+ wait(NULL);
+ }
+}
+
+static void virtio_blk_pre_fuzz(QTestState *s)
+{
+ qos_init_path(s);
+ counter_shm_init();
+}
+
+static void drive_destroy(void *path)
+{
+ unlink(path);
+ g_free(path);
+}
+
+static char *drive_create(void)
+{
+ int fd, ret;
+ char *t_path = g_strdup("/tmp/qtest.XXXXXX");
+
+ /* Create a temporary raw image */
+ fd = mkstemp(t_path);
+ g_assert_cmpint(fd, >=, 0);
+ ret = ftruncate(fd, TEST_IMAGE_SIZE);
+ g_assert_cmpint(ret, ==, 0);
+ close(fd);
+
+ g_test_queue_destroy(drive_destroy, t_path);
+ return t_path;
+}
+
+static void *virtio_blk_test_setup(GString *cmd_line, void *arg)
+{
+ char *tmp_path = drive_create();
+
+ g_string_append_printf(cmd_line,
+ " -drive if=none,id=drive0,file=%s,"
+ "format=raw,auto-read-only=off ",
+ tmp_path);
+
+ return arg;
+}
+
+static void register_virtio_blk_fuzz_targets(void)
+{
+ fuzz_add_qos_target(&(FuzzTarget){
+ .name = "virtio-blk-fuzz",
+ .description = "Fuzz the virtio-blk virtual queues, forking "
+ "for each fuzz run",
+ .pre_vm_init = &counter_shm_init,
+ .pre_fuzz = &virtio_blk_pre_fuzz,
+ .fuzz = virtio_blk_fork_fuzz,},
+ "virtio-blk",
+ &(QOSGraphTestOptions){.before = virtio_blk_test_setup}
+ );
+
+ fuzz_add_qos_target(&(FuzzTarget){
+ .name = "virtio-blk-flags-fuzz",
+ .description = "Fuzz the virtio-blk virtual queues, forking "
+ "for each fuzz run (also fuzzes the virtio flags)",
+ .pre_vm_init = &counter_shm_init,
+ .pre_fuzz = &virtio_blk_pre_fuzz,
+ .fuzz = virtio_blk_with_flag_fuzz,},
+ "virtio-blk",
+ &(QOSGraphTestOptions){.before = virtio_blk_test_setup}
+ );
+}
+
+fuzz_target_init(register_virtio_blk_fuzz_targets);
diff --git a/tests/qtest/libqos/libqtest.h b/tests/qtest/libqos/libqtest.h
index 5c959f1853..724f65aa94 100644
--- a/tests/qtest/libqos/libqtest.h
+++ b/tests/qtest/libqos/libqtest.h
@@ -88,7 +88,7 @@ void qtest_quit(QTestState *s);
* @fds: array of file descriptors
* @fds_num: number of elements in @fds
* @fmt: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail(). See parse_escape() for what's
+ * qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
*
* Sends a QMP message to QEMU with fds and returns the response.
@@ -101,7 +101,7 @@ QDict *qtest_qmp_fds(QTestState *s, int *fds, size_t fds_num,
* qtest_qmp:
* @s: #QTestState instance to operate on.
* @fmt: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail(). See parse_escape() for what's
+ * qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
*
* Sends a QMP message to QEMU and returns the response.
@@ -113,7 +113,7 @@ QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
* qtest_qmp_send:
* @s: #QTestState instance to operate on.
* @fmt: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail(). See parse_escape() for what's
+ * qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
*
* Sends a QMP message to QEMU and leaves the response in the stream.
@@ -138,7 +138,7 @@ void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...)
* @fds: array of file descriptors
* @fds_num: number of elements in @fds
* @fmt: QMP message to send to QEMU, formatted like
- * qobject_from_jsonf_nofail(). See parse_escape() for what's
+ * qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
* @ap: QMP message arguments
*
@@ -152,7 +152,7 @@ QDict *qtest_vqmp_fds(QTestState *s, int *fds, size_t fds_num,
* qtest_vqmp:
* @s: #QTestState instance to operate on.
* @fmt: QMP message to send to QEMU, formatted like
- * qobject_from_jsonf_nofail(). See parse_escape() for what's
+ * qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
* @ap: QMP message arguments
*
@@ -167,7 +167,7 @@ QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap)
* @fds: array of file descriptors
* @fds_num: number of elements in @fds
* @fmt: QMP message to send to QEMU, formatted like
- * qobject_from_jsonf_nofail(). See parse_escape() for what's
+ * qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
* @ap: QMP message arguments
*
@@ -181,7 +181,7 @@ void qtest_qmp_vsend_fds(QTestState *s, int *fds, size_t fds_num,
* qtest_qmp_vsend:
* @s: #QTestState instance to operate on.
* @fmt: QMP message to send to QEMU, formatted like
- * qobject_from_jsonf_nofail(). See parse_escape() for what's
+ * qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
* @ap: QMP message arguments
*
@@ -636,7 +636,7 @@ void qtest_add_abrt_handler(GHookFunc fn, const void *data);
* qtest_qmp_assert_success:
* @qts: QTestState instance to operate on
* @fmt: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail(). See parse_escape() for what's
+ * qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
*
* Sends a QMP message to QEMU and asserts that a 'return' key is present in
@@ -683,7 +683,7 @@ void qtest_qmp_device_add_qdict(QTestState *qts, const char *drv,
* @driver: Name of the device that should be added
* @id: Identification string
* @fmt: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail(). See parse_escape() for what's
+ * qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
*
* Generic hot-plugging test via the device_add QMP command.
diff --git a/tests/qtest/libqtest-single.h b/tests/qtest/libqtest-single.h
index 176979a2ce..0d7f568678 100644
--- a/tests/qtest/libqtest-single.h
+++ b/tests/qtest/libqtest-single.h
@@ -47,7 +47,7 @@ static inline void qtest_end(void)
/**
* qmp:
* @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail(). See parse_escape() for what's
+ * qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
*
* Sends a QMP message to QEMU and returns the response.
diff --git a/tests/qtest/npcm7xx_rng-test.c b/tests/qtest/npcm7xx_rng-test.c
index e7cde85fbb..c614968ffc 100644
--- a/tests/qtest/npcm7xx_rng-test.c
+++ b/tests/qtest/npcm7xx_rng-test.c
@@ -126,7 +126,7 @@ static double calc_runs_p(const unsigned long *buf, unsigned int nr_bits)
pi = (double)nr_ones / nr_bits;
for (k = 0; k < nr_bits - 1; k++) {
- vn_obs += !(test_bit(k, buf) ^ test_bit(k + 1, buf));
+ vn_obs += (test_bit(k, buf) ^ test_bit(k + 1, buf));
}
vn_obs += 1;
diff --git a/tests/qtest/tpm-tests.c b/tests/qtest/tpm-tests.c
index 70c80f8379..0da3a8a4df 100644
--- a/tests/qtest/tpm-tests.c
+++ b/tests/qtest/tpm-tests.c
@@ -70,10 +70,8 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
qtest_end();
tpm_util_swtpm_kill(swtpm_pid);
- if (addr) {
- g_unlink(addr->u.q_unix.path);
- qapi_free_SocketAddress(addr);
- }
+ g_unlink(addr->u.q_unix.path);
+ qapi_free_SocketAddress(addr);
}
void tpm_test_swtpm_migration_test(const char *src_tpm_path,
diff --git a/tests/vm/openbsd b/tests/vm/openbsd
index ad882a76a2..386b2c72f7 100755
--- a/tests/vm/openbsd
+++ b/tests/vm/openbsd
@@ -22,8 +22,8 @@ class OpenBSDVM(basevm.BaseVM):
name = "openbsd"
arch = "x86_64"
- link = "https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.iso"
- csum = "b22e63df56e6266de6bbeed8e9be0fbe9ee2291551c5bc03f3cc2e4ab9436ee3"
+ link = "https://cdn.openbsd.org/pub/OpenBSD/6.8/amd64/install68.iso"
+ csum = "47e291fcc2d0c1a8ae0b66329f040b33af755b6adbd21739e20bb5ad56f62b6c"
size = "20G"
pkgs = [
# tools
@@ -37,10 +37,10 @@ class OpenBSDVM(basevm.BaseVM):
"bash",
"gmake",
"gsed",
- "gettext",
+ "gettext-tools",
# libs: usb
- "libusb1",
+ "libusb1--",
# libs: crypto
"gnutls",