aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CODING_STYLE47
-rw-r--r--MAINTAINERS12
-rw-r--r--Makefile13
-rw-r--r--block.c15
-rw-r--r--block/commit.c11
-rw-r--r--block/io.c45
-rw-r--r--block/qcow2-bitmap.c2
-rw-r--r--block/qcow2-refcount.c84
-rw-r--r--block/qcow2.c1
-rw-r--r--block/qcow2.h1
-rw-r--r--block/ssh.c73
-rw-r--r--block/vdi.c15
-rw-r--r--block/vvfat.c12
-rwxr-xr-xconfigure5
-rw-r--r--contrib/libvhost-user/libvhost-user.h2
-rw-r--r--docs/devel/index.rst1
-rw-r--r--docs/devel/secure-coding-practices.rst106
-rw-r--r--docs/security.texi131
-rw-r--r--hw/arm/aspeed.c8
-rw-r--r--hw/arm/raspi.c7
-rw-r--r--hw/arm/virt.c196
-rw-r--r--hw/block/pflash_cfi01.c28
-rw-r--r--hw/display/Kconfig5
-rw-r--r--hw/display/Makefile.objs1
-rw-r--r--hw/display/ati_2d.c12
-rw-r--r--hw/display/cirrus_vga.c10
-rw-r--r--hw/display/i2c-ddc.c (renamed from hw/i2c/i2c-ddc.c)2
-rw-r--r--hw/display/qxl.c58
-rw-r--r--hw/display/sii9022.c2
-rw-r--r--hw/display/sm501.c2
-rw-r--r--hw/i2c/Kconfig5
-rw-r--r--hw/i2c/Makefile.objs1
-rw-r--r--hw/i2c/smbus_ich9.c21
-rw-r--r--hw/i386/pc_sysfw.c18
-rw-r--r--hw/intc/armv7m_nvic.c40
-rw-r--r--hw/net/pcnet.c4
-rw-r--r--hw/openrisc/cputimer.c2
-rw-r--r--hw/openrisc/openrisc_sim.c2
-rw-r--r--hw/openrisc/pic_cpu.c2
-rw-r--r--hw/rdma/rdma_backend.c125
-rw-r--r--hw/rdma/rdma_backend.h18
-rw-r--r--hw/rdma/rdma_backend_defs.h5
-rw-r--r--hw/rdma/rdma_rm.c117
-rw-r--r--hw/rdma/rdma_rm.h13
-rw-r--r--hw/rdma/rdma_rm_defs.h10
-rw-r--r--hw/rdma/vmw/pvrdma_cmd.c206
-rw-r--r--hw/rdma/vmw/pvrdma_main.c16
-rw-r--r--hw/rdma/vmw/pvrdma_qp_ops.c46
-rw-r--r--hw/rdma/vmw/pvrdma_qp_ops.h1
-rw-r--r--hw/sparc/leon3.c4
-rw-r--r--include/block/block.h4
-rw-r--r--include/block/nbd.h38
-rw-r--r--include/exec/cpu-common.h3
-rw-r--r--include/exec/poison.h1
-rw-r--r--include/hw/arm/aspeed.h1
-rw-r--r--include/hw/arm/virt.h2
-rw-r--r--include/hw/block/flash.h1
-rw-r--r--include/hw/display/i2c-ddc.h (renamed from include/hw/i2c/i2c-ddc.h)0
-rw-r--r--include/hw/display/xlnx_dp.h2
-rw-r--r--include/qemu/compiler.h2
-rw-r--r--include/qemu/osdep.h10
-rw-r--r--job.c2
-rw-r--r--linux-user/elfload.c20
-rw-r--r--linux-user/exit.c3
-rw-r--r--linux-user/ioctls.h2
-rw-r--r--linux-user/openrisc/target_cpu.h2
-rw-r--r--linux-user/openrisc/target_structs.h2
-rw-r--r--linux-user/sh4/target_cpu.h2
-rw-r--r--linux-user/sh4/target_structs.h2
-rw-r--r--linux-user/signal.c5
-rw-r--r--linux-user/syscall.c47
-rw-r--r--linux-user/uname.c5
-rw-r--r--net/net.c7
-rw-r--r--qemu-doc.texi3
-rw-r--r--qemu-ga.texi4
-rw-r--r--qemu-img.c77
-rw-r--r--qemu-nbd.c46
-rw-r--r--qga/commands-win32.c2
-rw-r--r--qom/object.c2
-rw-r--r--scripts/cocci-macro-file.h7
-rwxr-xr-xscripts/decodetree.py233
m---------slirp0
-rw-r--r--target/arm/cpu.h13
-rw-r--r--target/arm/helper.c47
-rw-r--r--target/arm/kvm.c8
-rw-r--r--target/arm/kvm32.c20
-rw-r--r--target/arm/kvm64.c2
-rw-r--r--target/arm/machine.c2
-rw-r--r--target/arm/translate-sve.c24
-rw-r--r--target/hppa/translate.c16
-rw-r--r--target/openrisc/cpu.h2
-rw-r--r--target/openrisc/exception.c2
-rw-r--r--target/openrisc/exception_helper.c2
-rw-r--r--target/openrisc/fpu_helper.c2
-rw-r--r--target/openrisc/insns.decode2
-rw-r--r--target/openrisc/interrupt.c2
-rw-r--r--target/openrisc/machine.c2
-rw-r--r--target/openrisc/mmu.c2
-rw-r--r--target/riscv/insn_trans/trans_rvc.inc.c10
-rw-r--r--target/riscv/translate.c4
-rw-r--r--target/sh4/cpu.h2
-rw-r--r--target/sh4/gdbstub.c2
-rw-r--r--target/sh4/helper.c2
-rw-r--r--target/sh4/op_helper.c2
-rw-r--r--target/sh4/translate.c2
-rw-r--r--tests/Makefile.include21
-rw-r--r--tests/drive_del-test.c63
-rw-r--r--tests/e1000e-test.c4
-rw-r--r--tests/ide-test.c284
-rw-r--r--tests/ivshmem-test.c9
-rw-r--r--tests/libqos/pci-pc.c10
-rw-r--r--tests/libqos/pci.h2
-rw-r--r--tests/megasas-test.c2
-rw-r--r--tests/qemu-iotests/059.out8
-rw-r--r--tests/qemu-iotests/083.out68
-rw-r--r--tests/qemu-iotests/092.out24
-rwxr-xr-xtests/qemu-iotests/11010
-rwxr-xr-xtests/qemu-iotests/12610
-rwxr-xr-xtests/qemu-iotests/13812
-rw-r--r--tests/qemu-iotests/138.out5
-rwxr-xr-xtests/qemu-iotests/18222
-rw-r--r--tests/qemu-iotests/182.out1
-rwxr-xr-xtests/qemu-iotests/1924
-rwxr-xr-xtests/qemu-iotests/20710
-rw-r--r--tests/qemu-iotests/207.out10
-rwxr-xr-xtests/qemu-iotests/22110
-rw-r--r--tests/qemu-iotests/221.out20
-rwxr-xr-xtests/qemu-iotests/2336
-rw-r--r--tests/qemu-iotests/233.out4
-rwxr-xr-xtests/qemu-iotests/252124
-rw-r--r--tests/qemu-iotests/252.out39
-rw-r--r--tests/qemu-iotests/common.rc2
-rw-r--r--tests/qemu-iotests/group1
-rw-r--r--tests/qemu-iotests/iotests.py2
-rw-r--r--tests/qmp-cmd-test.c15
-rw-r--r--tests/tco-test.c63
-rw-r--r--tests/test-block-iothread.c107
-rw-r--r--tests/test-hmp.c19
-rw-r--r--tests/tpm-tests.c2
-rw-r--r--tests/virtio-blk-test.c3
-rw-r--r--tests/virtio-net-test.c4
-rw-r--r--tests/virtio-rng-test.c5
-rw-r--r--util/aio-posix.c12
-rw-r--r--util/cacheinfo.c2
-rw-r--r--util/qemu-sockets.c12
-rw-r--r--util/readline.c174
-rw-r--r--vl.c46
147 files changed, 2574 insertions, 949 deletions
diff --git a/CODING_STYLE b/CODING_STYLE
index ec075dedc4..cb8edcbb36 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -29,6 +29,45 @@ Spaces of course are superior to tabs because:
Do not leave whitespace dangling off the ends of lines.
+1.1 Multiline Indent
+
+There are several places where indent is necessary:
+
+ - if/else
+ - while/for
+ - function definition & call
+
+When breaking up a long line to fit within line width, we need a proper indent
+for the following lines.
+
+In case of if/else, while/for, align the secondary lines just after the
+opening parenthesis of the first.
+
+For example:
+
+ if (a == 1 &&
+ b == 2) {
+
+ while (a == 1 &&
+ b == 2) {
+
+In case of function, there are several variants:
+
+ * 4 spaces indent from the beginning
+ * align the secondary lines just after the opening parenthesis of the
+ first
+
+For example:
+
+ do_something(x, y,
+ z);
+
+ do_something(x, y,
+ z);
+
+ do_something(x, do_another(y,
+ z));
+
2. Line width
Lines should be 80 characters; try not to make them longer.
@@ -108,10 +147,10 @@ block to a separate function altogether.
When comparing a variable for (in)equality with a constant, list the
constant on the right, as in:
-if (a == 1) {
- /* Reads like: "If a equals 1" */
- do_something();
-}
+ if (a == 1) {
+ /* Reads like: "If a equals 1" */
+ do_something();
+ }
Rationale: Yoda conditions (as in 'if (1 == a)') are awkward to read.
Besides, good compilers already warn users when '==' is mis-typed as '=',
diff --git a/MAINTAINERS b/MAINTAINERS
index 66ddbda9c9..f25729a06d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1391,6 +1391,13 @@ F: include/hw/net/
F: tests/virtio-net-test.c
T: git https://github.com/jasowang/qemu.git net
+Parallel NOR Flash devices
+M: Philippe Mathieu-Daudé <philmd@redhat.com>
+T: git https://gitlab.com/philmd/qemu.git pflash-next
+S: Maintained
+F: hw/block/pflash_cfi*.c
+F: include/hw/block/flash.h
+
SCSI
M: Paolo Bonzini <pbonzini@redhat.com>
R: Fam Zheng <fam@euphon.net>
@@ -2404,12 +2411,13 @@ F: block/ssh.c
CURL
L: qemu-block@nongnu.org
-S: Supported
+S: Odd Fixes
F: block/curl.c
GLUSTER
L: qemu-block@nongnu.org
-S: Supported
+L: integration@gluster.org
+S: Odd Fixes
F: block/gluster.c
Null Block Driver
diff --git a/Makefile b/Makefile
index d372493042..4a8ae0ef95 100644
--- a/Makefile
+++ b/Makefile
@@ -639,7 +639,7 @@ clean:
! -path ./roms/edk2/BaseTools/Source/Python/UPT/Dll/sqlite3.dll \
-exec rm {} +
rm -f $(edk2-decompressed)
- rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
+ rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga$(EXESUF) TAGS cscope.* *.pod *~ */*~
rm -f fsdev/*.pod scsi/*.pod
rm -f qemu-img-cmds.h
rm -f ui/shader/*-vert.h ui/shader/*-frag.h
@@ -899,11 +899,14 @@ ui/shader.o: $(SRC_PATH)/ui/shader.c \
MAKEINFO=makeinfo
MAKEINFOINCLUDES= -I docs -I $(<D) -I $(@D)
MAKEINFOFLAGS=--no-split --number-sections $(MAKEINFOINCLUDES)
-TEXI2PODFLAGS=$(MAKEINFOINCLUDES) "-DVERSION=$(VERSION)"
+TEXI2PODFLAGS=$(MAKEINFOINCLUDES) -DVERSION="$(VERSION)" -DCONFDIR="$(qemu_confdir)"
TEXI2PDFFLAGS=$(if $(V),,--quiet) -I $(SRC_PATH) $(MAKEINFOINCLUDES)
-docs/version.texi: $(SRC_PATH)/VERSION
- $(call quiet-command,echo "@set VERSION $(VERSION)" > $@,"GEN","$@")
+docs/version.texi: $(SRC_PATH)/VERSION config-host.mak
+ $(call quiet-command,(\
+ echo "@set VERSION $(VERSION)" && \
+ echo "@set CONFDIR $(qemu_confdir)" \
+ )> $@,"GEN","$@")
%.html: %.texi docs/version.texi
$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --no-headers \
@@ -973,7 +976,7 @@ qemu-doc.html qemu-doc.info qemu-doc.pdf qemu-doc.txt: \
qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \
qemu-deprecated.texi qemu-monitor.texi qemu-img-cmds.texi qemu-ga.texi \
qemu-monitor-info.texi docs/qemu-block-drivers.texi \
- docs/qemu-cpu-models.texi
+ docs/qemu-cpu-models.texi docs/security.texi
docs/interop/qemu-ga-ref.dvi docs/interop/qemu-ga-ref.html \
docs/interop/qemu-ga-ref.info docs/interop/qemu-ga-ref.pdf \
diff --git a/block.c b/block.c
index 9ae5c0ed2f..6999aad446 100644
--- a/block.c
+++ b/block.c
@@ -1743,11 +1743,10 @@ static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
uint64_t parent_perm, uint64_t parent_shared,
uint64_t *nperm, uint64_t *nshared)
{
- if (bs->drv && bs->drv->bdrv_child_perm) {
- bs->drv->bdrv_child_perm(bs, c, role, reopen_queue,
- parent_perm, parent_shared,
- nperm, nshared);
- }
+ assert(bs->drv && bs->drv->bdrv_child_perm);
+ bs->drv->bdrv_child_perm(bs, c, role, reopen_queue,
+ parent_perm, parent_shared,
+ nperm, nshared);
/* TODO Take force_share from reopen_queue */
if (child_bs && child_bs->force_share) {
*nshared = BLK_PERM_ALL;
@@ -4083,14 +4082,14 @@ static void bdrv_delete(BlockDriverState *bs)
assert(bdrv_op_blocker_is_empty(bs));
assert(!bs->refcnt);
- bdrv_close(bs);
-
/* remove from list, if necessary */
if (bs->node_name[0] != '\0') {
QTAILQ_REMOVE(&graph_bdrv_states, bs, node_list);
}
QTAILQ_REMOVE(&all_bdrv_states, bs, bs_list);
+ bdrv_close(bs);
+
g_free(bs);
}
@@ -4122,7 +4121,7 @@ typedef struct CheckCo {
int ret;
} CheckCo;
-static void bdrv_check_co_entry(void *opaque)
+static void coroutine_fn bdrv_check_co_entry(void *opaque)
{
CheckCo *cco = opaque;
cco->ret = bdrv_co_check(cco->bs, cco->res, cco->fix);
diff --git a/block/commit.c b/block/commit.c
index 27537d995b..14e5bb394c 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -303,23 +303,14 @@ void commit_start(const char *job_id, BlockDriverState *bs,
commit_top_bs->total_sectors = top->total_sectors;
bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(top));
- bdrv_set_backing_hd(commit_top_bs, top, &local_err);
+ bdrv_append(commit_top_bs, top, &local_err);
if (local_err) {
- bdrv_unref(commit_top_bs);
- commit_top_bs = NULL;
- error_propagate(errp, local_err);
- goto fail;
- }
- bdrv_replace_node(top, commit_top_bs, &local_err);
- if (local_err) {
- bdrv_unref(commit_top_bs);
commit_top_bs = NULL;
error_propagate(errp, local_err);
goto fail;
}
s->commit_top_bs = commit_top_bs;
- bdrv_unref(commit_top_bs);
/* Block all nodes between top and base, because they will
* disappear from the chain after this operation. */
diff --git a/block/io.c b/block/io.c
index dfc153b8d8..aeebc9c23c 100644
--- a/block/io.c
+++ b/block/io.c
@@ -837,42 +837,6 @@ static int bdrv_prwv_co(BdrvChild *child, int64_t offset,
return rwco.ret;
}
-/*
- * Process a synchronous request using coroutines
- */
-static int bdrv_rw_co(BdrvChild *child, int64_t sector_num, uint8_t *buf,
- int nb_sectors, bool is_write, BdrvRequestFlags flags)
-{
- QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf,
- nb_sectors * BDRV_SECTOR_SIZE);
-
- if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
- return -EINVAL;
- }
-
- return bdrv_prwv_co(child, sector_num << BDRV_SECTOR_BITS,
- &qiov, is_write, flags);
-}
-
-/* return < 0 if error. See bdrv_write() for the return codes */
-int bdrv_read(BdrvChild *child, int64_t sector_num,
- uint8_t *buf, int nb_sectors)
-{
- return bdrv_rw_co(child, sector_num, buf, nb_sectors, false, 0);
-}
-
-/* Return < 0 if error. Important errors are:
- -EIO generic I/O error (may happen for all errors)
- -ENOMEDIUM No media inserted.
- -EINVAL Invalid sector number or nb_sectors
- -EACCES Trying to write a read-only device
-*/
-int bdrv_write(BdrvChild *child, int64_t sector_num,
- const uint8_t *buf, int nb_sectors)
-{
- return bdrv_rw_co(child, sector_num, (uint8_t *)buf, nb_sectors, true, 0);
-}
-
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
int bytes, BdrvRequestFlags flags)
{
@@ -935,6 +899,7 @@ int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
return qiov->size;
}
+/* See bdrv_pwrite() for the return codes */
int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes)
{
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
@@ -958,6 +923,12 @@ int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
return qiov->size;
}
+/* Return no. of bytes on success or < 0 on error. Important errors are:
+ -EIO generic I/O error (may happen for all errors)
+ -ENOMEDIUM No media inserted.
+ -EINVAL Invalid offset or number of bytes
+ -EACCES Trying to write a read-only device
+*/
int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes)
{
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
@@ -1516,7 +1487,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
assert(!bs->supported_zero_flags);
}
- if (ret == -ENOTSUP && !(flags & BDRV_REQ_NO_FALLBACK)) {
+ if (ret < 0 && !(flags & BDRV_REQ_NO_FALLBACK)) {
/* Fall back to bounce buffer if write zeroes is unsupported */
BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE;
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index e53a1609d7..8a75366c92 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -202,7 +202,7 @@ static void clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table,
continue;
}
- qcow2_free_clusters(bs, addr, s->cluster_size, QCOW2_DISCARD_OTHER);
+ qcow2_free_clusters(bs, addr, s->cluster_size, QCOW2_DISCARD_ALWAYS);
bitmap_table[i] = 0;
}
}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index e0fe322500..7481903396 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1520,12 +1520,31 @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
{
BDRVQcow2State *s = bs->opaque;
uint64_t start, last, cluster_offset, k, refcount;
+ int64_t file_len;
int ret;
if (size <= 0) {
return 0;
}
+ file_len = bdrv_getlength(bs->file->bs);
+ if (file_len < 0) {
+ return file_len;
+ }
+
+ /*
+ * Last cluster of qcow2 image may be semi-allocated, so it may be OK to
+ * reference some space after file end but it should be less than one
+ * cluster.
+ */
+ if (offset + size - file_len >= s->cluster_size) {
+ fprintf(stderr, "ERROR: counting reference for region exceeding the "
+ "end of the file by one cluster or more: offset 0x%" PRIx64
+ " size 0x%" PRIx64 "\n", offset, size);
+ res->corruptions++;
+ return 0;
+ }
+
start = start_of_cluster(s, offset);
last = start_of_cluster(s, offset + size - 1);
for(cluster_offset = start; cluster_offset <= last;
@@ -1572,7 +1591,7 @@ enum {
static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
void **refcount_table,
int64_t *refcount_table_size, int64_t l2_offset,
- int flags, BdrvCheckMode fix)
+ int flags, BdrvCheckMode fix, bool active)
{
BDRVQcow2State *s = bs->opaque;
uint64_t *l2_table, l2_entry;
@@ -1641,17 +1660,10 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
{
uint64_t offset = l2_entry & L2E_OFFSET_MASK;
- if (flags & CHECK_FRAG_INFO) {
- res->bfi.allocated_clusters++;
- if (next_contiguous_offset &&
- offset != next_contiguous_offset) {
- res->bfi.fragmented_clusters++;
- }
- next_contiguous_offset = offset + s->cluster_size;
- }
-
/* Correct offsets are cluster aligned */
if (offset_into_cluster(s, offset)) {
+ res->corruptions++;
+
if (qcow2_get_cluster_type(bs, l2_entry) ==
QCOW2_CLUSTER_ZERO_ALLOC)
{
@@ -1663,11 +1675,12 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
if (fix & BDRV_FIX_ERRORS) {
uint64_t l2e_offset =
l2_offset + (uint64_t)i * sizeof(uint64_t);
+ int ign = active ? QCOW2_OL_ACTIVE_L2 :
+ QCOW2_OL_INACTIVE_L2;
l2_entry = QCOW_OFLAG_ZERO;
l2_table[i] = cpu_to_be64(l2_entry);
- ret = qcow2_pre_write_overlap_check(bs,
- QCOW2_OL_ACTIVE_L2 | QCOW2_OL_INACTIVE_L2,
+ ret = qcow2_pre_write_overlap_check(bs, ign,
l2e_offset, sizeof(uint64_t), false);
if (ret < 0) {
fprintf(stderr, "ERROR: Overlap check failed\n");
@@ -1686,21 +1699,28 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
/* Do not abort, continue checking the rest of this
* L2 table's entries */
} else {
+ res->corruptions--;
res->corruptions_fixed++;
/* Skip marking the cluster as used
* (it is unused now) */
continue;
}
- } else {
- res->corruptions++;
}
} else {
fprintf(stderr, "ERROR offset=%" PRIx64 ": Data cluster is "
"not properly aligned; L2 entry corrupted.\n", offset);
- res->corruptions++;
}
}
+ if (flags & CHECK_FRAG_INFO) {
+ res->bfi.allocated_clusters++;
+ if (next_contiguous_offset &&
+ offset != next_contiguous_offset) {
+ res->bfi.fragmented_clusters++;
+ }
+ next_contiguous_offset = offset + s->cluster_size;
+ }
+
/* Mark cluster as used */
if (!has_data_file(bs)) {
ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table,
@@ -1743,7 +1763,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
void **refcount_table,
int64_t *refcount_table_size,
int64_t l1_table_offset, int l1_size,
- int flags, BdrvCheckMode fix)
+ int flags, BdrvCheckMode fix, bool active)
{
BDRVQcow2State *s = bs->opaque;
uint64_t *l1_table = NULL, l2_offset, l1_size2;
@@ -1799,7 +1819,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
/* Process and check L2 entries */
ret = check_refcounts_l2(bs, res, refcount_table,
refcount_table_size, l2_offset, flags,
- fix);
+ fix, active);
if (ret < 0) {
goto fail;
}
@@ -1846,7 +1866,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
for (i = 0; i < s->l1_size; i++) {
uint64_t l1_entry = s->l1_table[i];
uint64_t l2_offset = l1_entry & L1E_OFFSET_MASK;
- bool l2_dirty = false;
+ int l2_dirty = 0;
if (!l2_offset) {
continue;
@@ -1859,6 +1879,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
continue;
}
if ((refcount == 1) != ((l1_entry & QCOW_OFLAG_COPIED) != 0)) {
+ res->corruptions++;
fprintf(stderr, "%s OFLAG_COPIED L2 cluster: l1_index=%d "
"l1_entry=%" PRIx64 " refcount=%" PRIu64 "\n",
repair ? "Repairing" : "ERROR", i, l1_entry, refcount);
@@ -1871,9 +1892,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
res->check_errors++;
goto fail;
}
+ res->corruptions--;
res->corruptions_fixed++;
- } else {
- res->corruptions++;
}
}
@@ -1905,6 +1925,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
}
}
if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) {
+ res->corruptions++;
fprintf(stderr, "%s OFLAG_COPIED data cluster: "
"l2_entry=%" PRIx64 " refcount=%" PRIu64 "\n",
repair ? "Repairing" : "ERROR", l2_entry, refcount);
@@ -1912,16 +1933,13 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
l2_table[j] = cpu_to_be64(refcount == 1
? l2_entry | QCOW_OFLAG_COPIED
: l2_entry & ~QCOW_OFLAG_COPIED);
- l2_dirty = true;
- res->corruptions_fixed++;
- } else {
- res->corruptions++;
+ l2_dirty++;
}
}
}
}
- if (l2_dirty) {
+ if (l2_dirty > 0) {
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2,
l2_offset, s->cluster_size,
false);
@@ -1940,6 +1958,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
res->check_errors++;
goto fail;
}
+ res->corruptions -= l2_dirty;
+ res->corruptions_fixed += l2_dirty;
}
}
@@ -1977,6 +1997,7 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
}
if (cluster >= *nb_clusters) {
+ res->corruptions++;
fprintf(stderr, "%s refcount block %" PRId64 " is outside image\n",
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
@@ -2016,6 +2037,7 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
goto resize_fail;
}
+ res->corruptions--;
res->corruptions_fixed++;
ret = qcow2_inc_refcounts_imrt(bs, res,
refcount_table, nb_clusters,
@@ -2029,12 +2051,9 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
continue;
resize_fail:
- res->corruptions++;
*rebuild = true;
fprintf(stderr, "ERROR could not resize image: %s\n",
strerror(-ret));
- } else {
- res->corruptions++;
}
continue;
}
@@ -2090,7 +2109,7 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
/* current L1 table */
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
s->l1_table_offset, s->l1_size, CHECK_FRAG_INFO,
- fix);
+ fix, true);
if (ret < 0) {
return ret;
}
@@ -2119,7 +2138,8 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
continue;
}
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
- sn->l1_table_offset, sn->l1_size, 0, fix);
+ sn->l1_table_offset, sn->l1_size, 0, fix,
+ false);
if (ret < 0) {
return ret;
}
@@ -2409,8 +2429,8 @@ write_refblocks:
on_disk_refblock = (void *)((char *) *refcount_table +
refblock_index * s->cluster_size);
- ret = bdrv_write(bs->file, refblock_offset / BDRV_SECTOR_SIZE,
- on_disk_refblock, s->cluster_sectors);
+ ret = bdrv_pwrite(bs->file, refblock_offset, on_disk_refblock,
+ s->cluster_size);
if (ret < 0) {
fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret));
goto fail;
diff --git a/block/qcow2.c b/block/qcow2.c
index a520d116ef..8e024007db 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1259,7 +1259,6 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
s->cluster_bits = header.cluster_bits;
s->cluster_size = 1 << s->cluster_bits;
- s->cluster_sectors = 1 << (s->cluster_bits - BDRV_SECTOR_BITS);
/* Initialise version 3 header fields */
if (header.version == 2) {
diff --git a/block/qcow2.h b/block/qcow2.h
index fdee297f33..e62508d1ce 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -266,7 +266,6 @@ typedef struct Qcow2BitmapHeaderExt {
typedef struct BDRVQcow2State {
int cluster_bits;
int cluster_size;
- int cluster_sectors;
int l2_slice_size;
int l2_bits;
int l2_size;
diff --git a/block/ssh.c b/block/ssh.c
index 859249113d..12fd4f39e8 100644
--- a/block/ssh.c
+++ b/block/ssh.c
@@ -75,6 +75,14 @@ typedef struct BDRVSSHState {
/* Used to warn if 'flush' is not supported. */
bool unsafe_flush_warning;
+
+ /*
+ * Store the user name for ssh_refresh_filename() because the
+ * default depends on the system you are on -- therefore, when we
+ * generate a filename, it should always contain the user name we
+ * are actually using.
+ */
+ char *user;
} BDRVSSHState;
static void ssh_state_init(BDRVSSHState *s)
@@ -87,6 +95,8 @@ static void ssh_state_init(BDRVSSHState *s)
static void ssh_state_free(BDRVSSHState *s)
{
+ g_free(s->user);
+
if (s->sftp_handle) {
libssh2_sftp_close(s->sftp_handle);
}
@@ -628,14 +638,13 @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
int ssh_flags, int creat_mode, Error **errp)
{
int r, ret;
- const char *user;
long port = 0;
if (opts->has_user) {
- user = opts->user;
+ s->user = g_strdup(opts->user);
} else {
- user = g_get_user_name();
- if (!user) {
+ s->user = g_strdup(g_get_user_name());
+ if (!s->user) {
error_setg_errno(errp, errno, "Can't get user name");
ret = -errno;
goto err;
@@ -685,7 +694,7 @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
}
/* Authenticate. */
- ret = authenticate(s, user, errp);
+ ret = authenticate(s, s->user, errp);
if (ret < 0) {
goto err;
}
@@ -1242,6 +1251,58 @@ static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
return ssh_grow_file(s, offset, errp);
}
+static void ssh_refresh_filename(BlockDriverState *bs)
+{
+ BDRVSSHState *s = bs->opaque;
+ const char *path, *host_key_check;
+ int ret;
+
+ /*
+ * None of these options can be represented in a plain "host:port"
+ * format, so if any was given, we have to abort.
+ */
+ if (s->inet->has_ipv4 || s->inet->has_ipv6 || s->inet->has_to ||
+ s->inet->has_numeric)
+ {
+ return;
+ }
+
+ path = qdict_get_try_str(bs->full_open_options, "path");
+ assert(path); /* mandatory option */
+
+ host_key_check = qdict_get_try_str(bs->full_open_options, "host_key_check");
+
+ ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
+ "ssh://%s@%s:%s%s%s%s",
+ s->user, s->inet->host, s->inet->port, path,
+ host_key_check ? "?host_key_check=" : "",
+ host_key_check ?: "");
+ if (ret >= sizeof(bs->exact_filename)) {
+ /* An overflow makes the filename unusable, so do not report any */
+ bs->exact_filename[0] = '\0';
+ }
+}
+
+static char *ssh_bdrv_dirname(BlockDriverState *bs, Error **errp)
+{
+ if (qdict_haskey(bs->full_open_options, "host_key_check")) {
+ /*
+ * We cannot generate a simple prefix if we would have to
+ * append a query string.
+ */
+ error_setg(errp,
+ "Cannot generate a base directory with host_key_check set");
+ return NULL;
+ }
+
+ if (bs->exact_filename[0] == '\0') {
+ error_setg(errp, "Cannot generate a base directory for this ssh node");
+ return NULL;
+ }
+
+ return path_combine(bs->exact_filename, "");
+}
+
static const char *const ssh_strong_runtime_opts[] = {
"host",
"port",
@@ -1268,6 +1329,8 @@ static BlockDriver bdrv_ssh = {
.bdrv_getlength = ssh_getlength,
.bdrv_co_truncate = ssh_co_truncate,
.bdrv_co_flush_to_disk = ssh_co_flush,
+ .bdrv_refresh_filename = ssh_refresh_filename,
+ .bdrv_dirname = ssh_bdrv_dirname,
.create_opts = &ssh_create_opts,
.strong_runtime_opts = ssh_strong_runtime_opts,
};
diff --git a/block/vdi.c b/block/vdi.c
index e1c42ad732..d7ef6628e7 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -171,6 +171,8 @@ typedef struct {
uint64_t unused2[7];
} QEMU_PACKED VdiHeader;
+QEMU_BUILD_BUG_ON(sizeof(VdiHeader) != 512);
+
typedef struct {
/* The block map entries are little endian (even in memory). */
uint32_t *bmap;
@@ -384,7 +386,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
logout("\n");
- ret = bdrv_read(bs->file, 0, (uint8_t *)&header, 1);
+ ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
if (ret < 0) {
goto fail;
}
@@ -484,8 +486,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
- ret = bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap,
- bmap_size);
+ ret = bdrv_pread(bs->file, header.offset_bmap, s->bmap,
+ bmap_size * SECTOR_SIZE);
if (ret < 0) {
goto fail_free_bmap;
}
@@ -704,7 +706,7 @@ nonallocating_write:
assert(VDI_IS_ALLOCATED(bmap_first));
*header = s->header;
vdi_header_to_le(header);
- ret = bdrv_write(bs->file, 0, block, 1);
+ ret = bdrv_pwrite(bs->file, 0, block, sizeof(VdiHeader));
g_free(block);
block = NULL;
@@ -722,10 +724,11 @@ nonallocating_write:
base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE;
logout("will write %u block map sectors starting from entry %u\n",
n_sectors, bmap_first);
- ret = bdrv_write(bs->file, offset, base, n_sectors);
+ ret = bdrv_pwrite(bs->file, offset * SECTOR_SIZE, base,
+ n_sectors * SECTOR_SIZE);
}
- return ret;
+ return ret < 0 ? ret : 0;
}
static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
diff --git a/block/vvfat.c b/block/vvfat.c
index 5f66787890..253cc716dd 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -1494,8 +1494,8 @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
DLOG(fprintf(stderr, "sectors %" PRId64 "+%" PRId64
" allocated\n", sector_num,
n >> BDRV_SECTOR_BITS));
- if (bdrv_read(s->qcow, sector_num, buf + i * 0x200,
- n >> BDRV_SECTOR_BITS)) {
+ if (bdrv_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE,
+ buf + i * 0x200, n) < 0) {
return -1;
}
i += (n >> BDRV_SECTOR_BITS) - 1;
@@ -1983,8 +1983,9 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
if (res) {
return -1;
}
- res = bdrv_write(s->qcow, offset, s->cluster_buffer, 1);
- if (res) {
+ res = bdrv_pwrite(s->qcow, offset * BDRV_SECTOR_SIZE,
+ s->cluster_buffer, BDRV_SECTOR_SIZE);
+ if (res < 0) {
return -2;
}
}
@@ -3050,7 +3051,8 @@ DLOG(checkpoint());
* Use qcow backend. Commit later.
*/
DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
- ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
+ ret = bdrv_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE, buf,
+ nb_sectors * BDRV_SECTOR_SIZE);
if (ret < 0) {
fprintf(stderr, "Error writing to qcow backend\n");
return ret;
diff --git a/configure b/configure
index 5b183c2e39..63f312bd1f 100755
--- a/configure
+++ b/configure
@@ -2937,9 +2937,9 @@ if test "$auth_pam" != "no"; then
int main(void) {
const char *service_name = "qemu";
const char *user = "frank";
- const struct pam_conv *pam_conv = NULL;
+ const struct pam_conv pam_conv = { 0 };
pam_handle_t *pamh = NULL;
- pam_start(service_name, user, pam_conv, &pamh);
+ pam_start(service_name, user, &pam_conv, &pamh);
return 0;
}
EOF
@@ -7882,7 +7882,6 @@ LINKS="$LINKS python"
for bios_file in \
$source_path/pc-bios/*.bin \
$source_path/pc-bios/*.lid \
- $source_path/pc-bios/*.aml \
$source_path/pc-bios/*.rom \
$source_path/pc-bios/*.dtb \
$source_path/pc-bios/*.img \
diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h
index 414ceb0a2f..78b33306e8 100644
--- a/contrib/libvhost-user/libvhost-user.h
+++ b/contrib/libvhost-user/libvhost-user.h
@@ -148,7 +148,7 @@ typedef struct VhostUserInflight {
uint16_t queue_size;
} VhostUserInflight;
-#if defined(_WIN32)
+#if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__))
# define VU_PACKED __attribute__((gcc_struct, packed))
#else
# define VU_PACKED __attribute__((packed))
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
index ebbab636ce..2a4ddf40ad 100644
--- a/docs/devel/index.rst
+++ b/docs/devel/index.rst
@@ -20,3 +20,4 @@ Contents:
stable-process
testing
decodetree
+ secure-coding-practices
diff --git a/docs/devel/secure-coding-practices.rst b/docs/devel/secure-coding-practices.rst
new file mode 100644
index 0000000000..cbfc8af67e
--- /dev/null
+++ b/docs/devel/secure-coding-practices.rst
@@ -0,0 +1,106 @@
+=======================
+Secure Coding Practices
+=======================
+This document covers topics that both developers and security researchers must
+be aware of so that they can develop safe code and audit existing code
+properly.
+
+Reporting Security Bugs
+-----------------------
+For details on how to report security bugs or ask questions about potential
+security bugs, see the `Security Process wiki page
+<https://wiki.qemu.org/SecurityProcess>`_.
+
+General Secure C Coding Practices
+---------------------------------
+Most CVEs (security bugs) reported against QEMU are not specific to
+virtualization or emulation. They are simply C programming bugs. Therefore
+it's critical to be aware of common classes of security bugs.
+
+There is a wide selection of resources available covering secure C coding. For
+example, the `CERT C Coding Standard
+<https://wiki.sei.cmu.edu/confluence/display/c/SEI+CERT+C+Coding+Standard>`_
+covers the most important classes of security bugs.
+
+Instead of describing them in detail here, only the names of the most important
+classes of security bugs are mentioned:
+
+* Buffer overflows
+* Use-after-free and double-free
+* Integer overflows
+* Format string vulnerabilities
+
+Some of these classes of bugs can be detected by analyzers. Static analysis is
+performed regularly by Coverity and the most obvious of these bugs are even
+reported by compilers. Dynamic analysis is possible with valgrind, tsan, and
+asan.
+
+Input Validation
+----------------
+Inputs from the guest or external sources (e.g. network, files) cannot be
+trusted and may be invalid. Inputs must be checked before using them in a way
+that could crash the program, expose host memory to the guest, or otherwise be
+exploitable by an attacker.
+
+The most sensitive attack surface is device emulation. All hardware register
+accesses and data read from guest memory must be validated. A typical example
+is a device that contains multiple units that are selectable by the guest via
+an index register::
+
+ typedef struct {
+ ProcessingUnit unit[2];
+ ...
+ } MyDeviceState;
+
+ static void mydev_writel(void *opaque, uint32_t addr, uint32_t val)
+ {
+ MyDeviceState *mydev = opaque;
+ ProcessingUnit *unit;
+
+ switch (addr) {
+ case MYDEV_SELECT_UNIT:
+ unit = &mydev->unit[val]; <-- this input wasn't validated!
+ ...
+ }
+ }
+
+If ``val`` is not in range [0, 1] then an out-of-bounds memory access will take
+place when ``unit`` is dereferenced. The code must check that ``val`` is 0 or
+1 and handle the case where it is invalid.
+
+Unexpected Device Accesses
+--------------------------
+The guest may access device registers in unusual orders or at unexpected
+moments. Device emulation code must not assume that the guest follows the
+typical "theory of operation" presented in driver writer manuals. The guest
+may make nonsense accesses to device registers such as starting operations
+before the device has been fully initialized.
+
+A related issue is that device emulation code must be prepared for unexpected
+device register accesses while asynchronous operations are in progress. A
+well-behaved guest might wait for a completion interrupt before accessing
+certain device registers. Device emulation code must handle the case where the
+guest overwrites registers or submits further requests before an ongoing
+request completes. Unexpected accesses must not cause memory corruption or
+leaks in QEMU.
+
+Invalid device register accesses can be reported with
+``qemu_log_mask(LOG_GUEST_ERROR, ...)``. The ``-d guest_errors`` command-line
+option enables these log messages.
+
+Live Migration
+--------------
+Device state can be saved to disk image files and shared with other users.
+Live migration code must validate inputs when loading device state so an
+attacker cannot gain control by crafting invalid device states. Device state
+is therefore considered untrusted even though it is typically generated by QEMU
+itself.
+
+Guest Memory Access Races
+-------------------------
+Guests with multiple vCPUs may modify guest RAM while device emulation code is
+running. Device emulation code must copy in descriptors and other guest RAM
+structures and only process the local copy. This prevents
+time-of-check-to-time-of-use (TOCTOU) race conditions that could cause QEMU to
+crash when a vCPU thread modifies guest RAM while device emulation is
+processing it.
diff --git a/docs/security.texi b/docs/security.texi
new file mode 100644
index 0000000000..927764f1e6
--- /dev/null
+++ b/docs/security.texi
@@ -0,0 +1,131 @@
+@node Security
+@chapter Security
+
+@section Overview
+
+This chapter explains the security requirements that QEMU is designed to meet
+and principles for securely deploying QEMU.
+
+@section Security Requirements
+
+QEMU supports many different use cases, some of which have stricter security
+requirements than others. The community has agreed on the overall security
+requirements that users may depend on. These requirements define what is
+considered supported from a security perspective.
+
+@subsection Virtualization Use Case
+
+The virtualization use case covers cloud and virtual private server (VPS)
+hosting, as well as traditional data center and desktop virtualization. These
+use cases rely on hardware virtualization extensions to execute guest code
+safely on the physical CPU at close-to-native speed.
+
+The following entities are untrusted, meaning that they may be buggy or
+malicious:
+
+@itemize
+@item Guest
+@item User-facing interfaces (e.g. VNC, SPICE, WebSocket)
+@item Network protocols (e.g. NBD, live migration)
+@item User-supplied files (e.g. disk images, kernels, device trees)
+@item Passthrough devices (e.g. PCI, USB)
+@end itemize
+
+Bugs affecting these entities are evaluated on whether they can cause damage in
+real-world use cases and treated as security bugs if this is the case.
+
+@subsection Non-virtualization Use Case
+
+The non-virtualization use case covers emulation using the Tiny Code Generator
+(TCG). In principle the TCG and device emulation code used in conjunction with
+the non-virtualization use case should meet the same security requirements as
+the virtualization use case. However, for historical reasons much of the
+non-virtualization use case code was not written with these security
+requirements in mind.
+
+Bugs affecting the non-virtualization use case are not considered security
+bugs at this time. Users with non-virtualization use cases must not rely on
+QEMU to provide guest isolation or any security guarantees.
+
+@section Architecture
+
+This section describes the design principles that ensure the security
+requirements are met.
+
+@subsection Guest Isolation
+
+Guest isolation is the confinement of guest code to the virtual machine. When
+guest code gains control of execution on the host this is called escaping the
+virtual machine. Isolation also includes resource limits such as throttling of
+CPU, memory, disk, or network. Guests must be unable to exceed their resource
+limits.
+
+QEMU presents an attack surface to the guest in the form of emulated devices.
+The guest must not be able to gain control of QEMU. Bugs in emulated devices
+could allow malicious guests to gain code execution in QEMU. At this point the
+guest has escaped the virtual machine and is able to act in the context of the
+QEMU process on the host.
+
+Guests often interact with other guests and share resources with them. A
+malicious guest must not gain control of other guests or access their data.
+Disk image files and network traffic must be protected from other guests unless
+explicitly shared between them by the user.
+
+@subsection Principle of Least Privilege
+
+The principle of least privilege states that each component only has access to
+the privileges necessary for its function. In the case of QEMU this means that
+each process only has access to resources belonging to the guest.
+
+The QEMU process should not have access to any resources that are inaccessible
+to the guest. This way the guest does not gain anything by escaping into the
+QEMU process since it already has access to those same resources from within
+the guest.
+
+Following the principle of least privilege immediately fulfills guest isolation
+requirements. For example, guest A only has access to its own disk image file
+@code{a.img} and not guest B's disk image file @code{b.img}.
+
+In reality certain resources are inaccessible to the guest but must be
+available to QEMU to perform its function. For example, host system calls are
+necessary for QEMU but are not exposed to guests. A guest that escapes into
+the QEMU process can then begin invoking host system calls.
+
+New features must be designed to follow the principle of least privilege.
+Should this not be possible for technical reasons, the security risk must be
+clearly documented so users are aware of the trade-off of enabling the feature.
+
+@subsection Isolation mechanisms
+
+Several isolation mechanisms are available to realize this architecture of
+guest isolation and the principle of least privilege. With the exception of
+Linux seccomp, these mechanisms are all deployed by management tools that
+launch QEMU, such as libvirt. They are also platform-specific so they are only
+described briefly for Linux here.
+
+The fundamental isolation mechanism is that QEMU processes must run as
+unprivileged users. Sometimes it seems more convenient to launch QEMU as
+root to give it access to host devices (e.g. @code{/dev/net/tun}) but this poses a
+huge security risk. File descriptor passing can be used to give an otherwise
+unprivileged QEMU process access to host devices without running QEMU as root.
+It is also possible to launch QEMU as a non-root user and configure UNIX groups
+for access to @code{/dev/kvm}, @code{/dev/net/tun}, and other device nodes.
+Some Linux distros already ship with UNIX groups for these devices by default.
+
+@itemize
+@item SELinux and AppArmor make it possible to confine processes beyond the
+traditional UNIX process and file permissions model. They restrict the QEMU
+process from accessing processes and files on the host system that are not
+needed by QEMU.
+
+@item Resource limits and cgroup controllers provide throughput and utilization
+limits on key resources such as CPU time, memory, and I/O bandwidth.
+
+@item Linux namespaces can be used to make process, file system, and other system
+resources unavailable to QEMU. A namespaced QEMU process is restricted to only
+those resources that were granted to it.
+
+@item Linux seccomp is available via the QEMU @option{--sandbox} option. It disables
+system calls that are not needed by QEMU, thereby reducing the host kernel
+attack surface.
+@end itemize
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 1c23ebd992..29d225ed14 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -25,6 +25,7 @@
#include "sysemu/block-backend.h"
#include "hw/loader.h"
#include "qemu/error-report.h"
+#include "qemu/units.h"
static struct arm_boot_info aspeed_board_binfo = {
.board_id = -1, /* device-tree-only board */
@@ -331,6 +332,9 @@ static void aspeed_machine_class_init(ObjectClass *oc, void *data)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_parallel = 1;
+ if (board->ram) {
+ mc->default_ram_size = board->ram;
+ }
amc->board = board;
}
@@ -352,6 +356,7 @@ static const AspeedBoardConfig aspeed_boards[] = {
.spi_model = "mx25l25635e",
.num_cs = 1,
.i2c_init = palmetto_bmc_i2c_init,
+ .ram = 256 * MiB,
}, {
.name = MACHINE_TYPE_NAME("ast2500-evb"),
.desc = "Aspeed AST2500 EVB (ARM1176)",
@@ -361,6 +366,7 @@ static const AspeedBoardConfig aspeed_boards[] = {
.spi_model = "mx25l25635e",
.num_cs = 1,
.i2c_init = ast2500_evb_i2c_init,
+ .ram = 512 * MiB,
}, {
.name = MACHINE_TYPE_NAME("romulus-bmc"),
.desc = "OpenPOWER Romulus BMC (ARM1176)",
@@ -370,6 +376,7 @@ static const AspeedBoardConfig aspeed_boards[] = {
.spi_model = "mx66l1g45g",
.num_cs = 2,
.i2c_init = romulus_bmc_i2c_init,
+ .ram = 512 * MiB,
}, {
.name = MACHINE_TYPE_NAME("witherspoon-bmc"),
.desc = "OpenPOWER Witherspoon BMC (ARM1176)",
@@ -379,6 +386,7 @@ static const AspeedBoardConfig aspeed_boards[] = {
.spi_model = "mx66l1g45g",
.num_cs = 2,
.i2c_init = witherspoon_bmc_i2c_init,
+ .ram = 512 * MiB,
},
};
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
index 66899c28dc..fe2bb511b9 100644
--- a/hw/arm/raspi.c
+++ b/hw/arm/raspi.c
@@ -12,6 +12,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "qapi/error.h"
#include "qemu-common.h"
#include "cpu.h"
@@ -175,6 +176,12 @@ static void raspi_init(MachineState *machine, int version)
BusState *bus;
DeviceState *carddev;
+ if (machine->ram_size > 1 * GiB) {
+ error_report("Requested ram size is too large for this machine: "
+ "maximum is 1GB");
+ exit(1);
+ }
+
object_initialize(&s->soc, sizeof(s->soc),
version == 3 ? TYPE_BCM2837 : TYPE_BCM2836);
object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 16ba67f7a7..5331ab71e2 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -30,6 +30,7 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
+#include "qemu/option.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
#include "hw/arm/arm.h"
@@ -871,25 +872,19 @@ static void create_virtio_devices(const VirtMachineState *vms, qemu_irq *pic)
}
}
-static void create_one_flash(const char *name, hwaddr flashbase,
- hwaddr flashsize, const char *file,
- MemoryRegion *sysmem)
+#define VIRT_FLASH_SECTOR_SIZE (256 * KiB)
+
+static PFlashCFI01 *virt_flash_create1(VirtMachineState *vms,
+ const char *name,
+ const char *alias_prop_name)
{
- /* Create and map a single flash device. We use the same
- * parameters as the flash devices on the Versatile Express board.
+ /*
+ * Create a single flash device. We use the same parameters as
+ * the flash devices on the Versatile Express board.
*/
- DriveInfo *dinfo = drive_get_next(IF_PFLASH);
DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- const uint64_t sectorlength = 256 * 1024;
-
- if (dinfo) {
- qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
- &error_abort);
- }
- qdev_prop_set_uint32(dev, "num-blocks", flashsize / sectorlength);
- qdev_prop_set_uint64(dev, "sector-length", sectorlength);
+ qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE);
qdev_prop_set_uint8(dev, "width", 4);
qdev_prop_set_uint8(dev, "device-width", 2);
qdev_prop_set_bit(dev, "big-endian", false);
@@ -898,41 +893,41 @@ static void create_one_flash(const char *name, hwaddr flashbase,
qdev_prop_set_uint16(dev, "id2", 0x00);
qdev_prop_set_uint16(dev, "id3", 0x00);
qdev_prop_set_string(dev, "name", name);
- qdev_init_nofail(dev);
+ object_property_add_child(OBJECT(vms), name, OBJECT(dev),
+ &error_abort);
+ object_property_add_alias(OBJECT(vms), alias_prop_name,
+ OBJECT(dev), "drive", &error_abort);
+ return PFLASH_CFI01(dev);
+}
- memory_region_add_subregion(sysmem, flashbase,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
+static void virt_flash_create(VirtMachineState *vms)
+{
+ vms->flash[0] = virt_flash_create1(vms, "virt.flash0", "pflash0");
+ vms->flash[1] = virt_flash_create1(vms, "virt.flash1", "pflash1");
+}
- if (file) {
- char *fn;
- int image_size;
+static void virt_flash_map1(PFlashCFI01 *flash,
+ hwaddr base, hwaddr size,
+ MemoryRegion *sysmem)
+{
+ DeviceState *dev = DEVICE(flash);
- if (drive_get(IF_PFLASH, 0, 0)) {
- error_report("The contents of the first flash device may be "
- "specified with -bios or with -drive if=pflash... "
- "but you cannot use both options at once");
- exit(1);
- }
- fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, file);
- if (!fn) {
- error_report("Could not find ROM image '%s'", file);
- exit(1);
- }
- image_size = load_image_mr(fn, sysbus_mmio_get_region(sbd, 0));
- g_free(fn);
- if (image_size < 0) {
- error_report("Could not load ROM image '%s'", file);
- exit(1);
- }
- }
+ assert(size % VIRT_FLASH_SECTOR_SIZE == 0);
+ assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX);
+ qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE);
+ qdev_init_nofail(dev);
+
+ memory_region_add_subregion(sysmem, base,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
+ 0));
}
-static void create_flash(const VirtMachineState *vms,
- MemoryRegion *sysmem,
- MemoryRegion *secure_sysmem)
+static void virt_flash_map(VirtMachineState *vms,
+ MemoryRegion *sysmem,
+ MemoryRegion *secure_sysmem)
{
- /* Create two flash devices to fill the VIRT_FLASH space in the memmap.
- * Any file passed via -bios goes in the first of these.
+ /*
+ * Map two flash devices to fill the VIRT_FLASH space in the memmap.
* sysmem is the system memory space. secure_sysmem is the secure view
* of the system, and the first flash device should be made visible only
* there. The second flash device is visible to both secure and nonsecure.
@@ -941,12 +936,20 @@ static void create_flash(const VirtMachineState *vms,
*/
hwaddr flashsize = vms->memmap[VIRT_FLASH].size / 2;
hwaddr flashbase = vms->memmap[VIRT_FLASH].base;
- char *nodename;
- create_one_flash("virt.flash0", flashbase, flashsize,
- bios_name, secure_sysmem);
- create_one_flash("virt.flash1", flashbase + flashsize, flashsize,
- NULL, sysmem);
+ virt_flash_map1(vms->flash[0], flashbase, flashsize,
+ secure_sysmem);
+ virt_flash_map1(vms->flash[1], flashbase + flashsize, flashsize,
+ sysmem);
+}
+
+static void virt_flash_fdt(VirtMachineState *vms,
+ MemoryRegion *sysmem,
+ MemoryRegion *secure_sysmem)
+{
+ hwaddr flashsize = vms->memmap[VIRT_FLASH].size / 2;
+ hwaddr flashbase = vms->memmap[VIRT_FLASH].base;
+ char *nodename;
if (sysmem == secure_sysmem) {
/* Report both flash devices as a single node in the DT */
@@ -959,7 +962,8 @@ static void create_flash(const VirtMachineState *vms,
qemu_fdt_setprop_cell(vms->fdt, nodename, "bank-width", 4);
g_free(nodename);
} else {
- /* Report the devices as separate nodes so we can mark one as
+ /*
+ * Report the devices as separate nodes so we can mark one as
* only visible to the secure world.
*/
nodename = g_strdup_printf("/secflash@%" PRIx64, flashbase);
@@ -982,6 +986,54 @@ static void create_flash(const VirtMachineState *vms,
}
}
+static bool virt_firmware_init(VirtMachineState *vms,
+ MemoryRegion *sysmem,
+ MemoryRegion *secure_sysmem)
+{
+ int i;
+ BlockBackend *pflash_blk0;
+
+ /* Map legacy -drive if=pflash to machine properties */
+ for (i = 0; i < ARRAY_SIZE(vms->flash); i++) {
+ pflash_cfi01_legacy_drive(vms->flash[i],
+ drive_get(IF_PFLASH, 0, i));
+ }
+
+ virt_flash_map(vms, sysmem, secure_sysmem);
+
+ pflash_blk0 = pflash_cfi01_get_blk(vms->flash[0]);
+
+ if (bios_name) {
+ char *fname;
+ MemoryRegion *mr;
+ int image_size;
+
+ if (pflash_blk0) {
+ error_report("The contents of the first flash device may be "
+ "specified with -bios or with -drive if=pflash... "
+ "but you cannot use both options at once");
+ exit(1);
+ }
+
+ /* Fall back to -bios */
+
+ fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+ if (!fname) {
+ error_report("Could not find ROM image '%s'", bios_name);
+ exit(1);
+ }
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(vms->flash[0]), 0);
+ image_size = load_image_mr(fname, mr);
+ g_free(fname);
+ if (image_size < 0) {
+ error_report("Could not load ROM image '%s'", bios_name);
+ exit(1);
+ }
+ }
+
+ return pflash_blk0 || bios_name;
+}
+
static FWCfgState *create_fw_cfg(const VirtMachineState *vms, AddressSpace *as)
{
hwaddr base = vms->memmap[VIRT_FW_CFG].base;
@@ -1421,7 +1473,7 @@ static void machvirt_init(MachineState *machine)
MemoryRegion *secure_sysmem = NULL;
int n, virt_max_cpus;
MemoryRegion *ram = g_new(MemoryRegion, 1);
- bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
+ bool firmware_loaded;
bool aarch64 = true;
/*
@@ -1460,6 +1512,27 @@ static void machvirt_init(MachineState *machine)
exit(1);
}
+ if (vms->secure) {
+ if (kvm_enabled()) {
+ error_report("mach-virt: KVM does not support Security extensions");
+ exit(1);
+ }
+
+ /*
+ * The Secure view of the world is the same as the NonSecure,
+ * but with a few extra devices. Create it as a container region
+ * containing the system memory at low priority; any secure-only
+ * devices go in at higher priority and take precedence.
+ */
+ secure_sysmem = g_new(MemoryRegion, 1);
+ memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory",
+ UINT64_MAX);
+ memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1);
+ }
+
+ firmware_loaded = virt_firmware_init(vms, sysmem,
+ secure_sysmem ?: sysmem);
+
/* If we have an EL3 boot ROM then the assumption is that it will
* implement PSCI itself, so disable QEMU's internal implementation
* so it doesn't get in the way. Instead of starting secondary
@@ -1505,23 +1578,6 @@ static void machvirt_init(MachineState *machine)
exit(1);
}
- if (vms->secure) {
- if (kvm_enabled()) {
- error_report("mach-virt: KVM does not support Security extensions");
- exit(1);
- }
-
- /* The Secure view of the world is the same as the NonSecure,
- * but with a few extra devices. Create it as a container region
- * containing the system memory at low priority; any secure-only
- * devices go in at higher priority and take precedence.
- */
- secure_sysmem = g_new(MemoryRegion, 1);
- memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory",
- UINT64_MAX);
- memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1);
- }
-
create_fdt(vms);
possible_cpus = mc->possible_cpu_arch_ids(machine);
@@ -1610,7 +1666,7 @@ static void machvirt_init(MachineState *machine)
&machine->device_memory->mr);
}
- create_flash(vms, sysmem, secure_sysmem ? secure_sysmem : sysmem);
+ virt_flash_fdt(vms, sysmem, secure_sysmem);
create_gic(vms, pic);
@@ -1956,6 +2012,8 @@ static void virt_instance_init(Object *obj)
NULL);
vms->irqmap = a15irqmap;
+
+ virt_flash_create(vms);
}
static const TypeInfo virt_machine_info = {
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 16dfae14b8..333b736277 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -44,9 +44,12 @@
#include "qapi/error.h"
#include "qemu/timer.h"
#include "qemu/bitops.h"
+#include "qemu/error-report.h"
#include "qemu/host-utils.h"
#include "qemu/log.h"
+#include "qemu/option.h"
#include "hw/sysbus.h"
+#include "sysemu/blockdev.h"
#include "sysemu/sysemu.h"
#include "trace.h"
@@ -968,6 +971,31 @@ MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl)
return &fl->mem;
}
+/*
+ * Handle -drive if=pflash for machines that use properties.
+ * If @dinfo is null, do nothing.
+ * Else if @fl's property "drive" is already set, fatal error.
+ * Else set it to the BlockBackend with @dinfo.
+ */
+void pflash_cfi01_legacy_drive(PFlashCFI01 *fl, DriveInfo *dinfo)
+{
+ Location loc;
+
+ if (!dinfo) {
+ return;
+ }
+
+ loc_push_none(&loc);
+ qemu_opts_loc_restore(dinfo->opts);
+ if (fl->blk) {
+ error_report("clashes with -machine");
+ exit(1);
+ }
+ qdev_prop_set_drive(DEVICE(fl), "drive",
+ blk_by_legacy_dinfo(dinfo), &error_fatal);
+ loc_pop(&loc);
+}
+
static void postload_update_cb(void *opaque, int running, RunState state)
{
PFlashCFI01 *pfl = opaque;
diff --git a/hw/display/Kconfig b/hw/display/Kconfig
index 72be57a403..c236cd2d0a 100644
--- a/hw/display/Kconfig
+++ b/hw/display/Kconfig
@@ -1,3 +1,8 @@
+config DDC
+ bool
+ depends on I2C
+ select EDID
+
config EDID
bool
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index dbd453ab1b..650031f725 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -1,3 +1,4 @@
+common-obj-$(CONFIG_DDC) += i2c-ddc.o
common-obj-$(CONFIG_EDID) += edid-generate.o edid-region.o
common-obj-$(CONFIG_FW_CFG_DMA) += ramfb.o
diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c
index bc98ba6eeb..fe3ae14864 100644
--- a/hw/display/ati_2d.c
+++ b/hw/display/ati_2d.c
@@ -79,10 +79,10 @@ void ati_2d_blt(ATIVGAState *s)
s->regs.dst_width, s->regs.dst_height);
end = s->vga.vram_ptr + s->vga.vram_size;
if (src_bits >= end || dst_bits >= end ||
- src_bits + (s->regs.src_y + s->regs.dst_height) * src_stride +
- s->regs.src_x >= end ||
- dst_bits + (s->regs.dst_y + s->regs.dst_height) * dst_stride +
- s->regs.dst_x >= end) {
+ src_bits + s->regs.src_x + (s->regs.src_y + s->regs.dst_height) *
+ src_stride * sizeof(uint32_t) >= end ||
+ dst_bits + s->regs.dst_x + (s->regs.dst_y + s->regs.dst_height) *
+ dst_stride * sizeof(uint32_t) >= end) {
qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
return;
}
@@ -140,8 +140,8 @@ void ati_2d_blt(ATIVGAState *s)
filler);
end = s->vga.vram_ptr + s->vga.vram_size;
if (dst_bits >= end ||
- dst_bits + (s->regs.dst_y + s->regs.dst_height) * dst_stride +
- s->regs.dst_x >= end) {
+ dst_bits + s->regs.dst_x + (s->regs.dst_y + s->regs.dst_height) *
+ dst_stride * sizeof(uint32_t) >= end) {
qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
return;
}
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index a0e71469f4..76c052c702 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -23,8 +23,13 @@
* THE SOFTWARE.
*/
/*
- * Reference: Finn Thogersons' VGADOC4b
- * available at http://home.worldonline.dk/~finth/
+ * Reference: Finn Thogersons' VGADOC4b:
+ *
+ * http://web.archive.org/web/20021019054927/http://home.worldonline.dk/finth/
+ *
+ * VGADOC4b.ZIP content available at:
+ *
+ * https://pdos.csail.mit.edu/6.828/2005/readings/hardware/vgadoc
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
@@ -33,7 +38,6 @@
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "ui/pixel_ops.h"
-#include "hw/loader.h"
#include "cirrus_vga_internal.h"
/*
diff --git a/hw/i2c/i2c-ddc.c b/hw/display/i2c-ddc.c
index 7aa8727771..9fe5403a92 100644
--- a/hw/i2c/i2c-ddc.c
+++ b/hw/display/i2c-ddc.c
@@ -20,7 +20,7 @@
#include "qemu-common.h"
#include "qemu/log.h"
#include "hw/i2c/i2c.h"
-#include "hw/i2c/i2c-ddc.h"
+#include "hw/display/i2c-ddc.h"
#ifndef DEBUG_I2CDDC
#define DEBUG_I2CDDC 0
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index c8ce5781e0..3880a7410b 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -33,24 +33,6 @@
#include "qxl.h"
-/*
- * NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as
- * such can be changed by the guest, so to avoid a guest trigerrable
- * abort we just qxl_set_guest_bug and set the return to NULL. Still
- * it may happen as a result of emulator bug as well.
- */
-#undef SPICE_RING_PROD_ITEM
-#define SPICE_RING_PROD_ITEM(qxl, r, ret) { \
- uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r); \
- if (prod >= ARRAY_SIZE((r)->items)) { \
- qxl_set_guest_bug(qxl, "SPICE_RING_PROD_ITEM indices mismatch " \
- "%u >= %zu", prod, ARRAY_SIZE((r)->items)); \
- ret = NULL; \
- } else { \
- ret = &(r)->items[prod].el; \
- } \
- }
-
#undef SPICE_RING_CONS_ITEM
#define SPICE_RING_CONS_ITEM(qxl, r, ret) { \
uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r); \
@@ -414,7 +396,8 @@ static void init_qxl_rom(PCIQXLDevice *d)
static void init_qxl_ram(PCIQXLDevice *d)
{
uint8_t *buf;
- uint64_t *item;
+ uint32_t prod;
+ QXLReleaseRing *ring;
buf = d->vga.vram_ptr;
d->ram = (QXLRam *)(buf + le32_to_cpu(d->shadow_rom.ram_header_offset));
@@ -426,9 +409,12 @@ static void init_qxl_ram(PCIQXLDevice *d)
SPICE_RING_INIT(&d->ram->cmd_ring);
SPICE_RING_INIT(&d->ram->cursor_ring);
SPICE_RING_INIT(&d->ram->release_ring);
- SPICE_RING_PROD_ITEM(d, &d->ram->release_ring, item);
- assert(item);
- *item = 0;
+
+ ring = &d->ram->release_ring;
+ prod = ring->prod & SPICE_RING_INDEX_MASK(ring);
+ assert(prod < ARRAY_SIZE(ring->items));
+ ring->items[prod].el = 0;
+
qxl_ring_set_dirty(d);
}
@@ -732,7 +718,7 @@ static int interface_req_cmd_notification(QXLInstance *sin)
static inline void qxl_push_free_res(PCIQXLDevice *d, int flush)
{
QXLReleaseRing *ring = &d->ram->release_ring;
- uint64_t *item;
+ uint32_t prod;
int notify;
#define QXL_FREE_BUNCH_SIZE 32
@@ -759,11 +745,15 @@ static inline void qxl_push_free_res(PCIQXLDevice *d, int flush)
if (notify) {
qxl_send_events(d, QXL_INTERRUPT_DISPLAY);
}
- SPICE_RING_PROD_ITEM(d, ring, item);
- if (!item) {
+
+ ring = &d->ram->release_ring;
+ prod = ring->prod & SPICE_RING_INDEX_MASK(ring);
+ if (prod >= ARRAY_SIZE(ring->items)) {
+ qxl_set_guest_bug(d, "SPICE_RING_PROD_ITEM indices mismatch "
+ "%u >= %zu", prod, ARRAY_SIZE(ring->items));
return;
}
- *item = 0;
+ ring->items[prod].el = 0;
d->num_free_res = 0;
d->last_release = NULL;
qxl_ring_set_dirty(d);
@@ -775,8 +765,12 @@ static void interface_release_resource(QXLInstance *sin,
{
PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
QXLReleaseRing *ring;
- uint64_t *item, id;
+ uint32_t prod;
+ uint64_t id;
+ if (!ext.info) {
+ return;
+ }
if (ext.group_id == MEMSLOT_GROUP_HOST) {
/* host group -> vga mode update request */
QXLCommandExt *cmdext = (void *)(intptr_t)(ext.info->id);
@@ -792,16 +786,18 @@ static void interface_release_resource(QXLInstance *sin,
* pci bar 0, $command.release_info
*/
ring = &qxl->ram->release_ring;
- SPICE_RING_PROD_ITEM(qxl, ring, item);
- if (!item) {
+ prod = ring->prod & SPICE_RING_INDEX_MASK(ring);
+ if (prod >= ARRAY_SIZE(ring->items)) {
+ qxl_set_guest_bug(qxl, "SPICE_RING_PROD_ITEM indices mismatch "
+ "%u >= %zu", prod, ARRAY_SIZE(ring->items));
return;
}
- if (*item == 0) {
+ if (ring->items[prod].el == 0) {
/* stick head into the ring */
id = ext.info->id;
ext.info->next = 0;
qxl_ram_set_dirty(qxl, &ext.info->next);
- *item = id;
+ ring->items[prod].el = id;
qxl_ring_set_dirty(qxl);
} else {
/* append item to the list */
diff --git a/hw/display/sii9022.c b/hw/display/sii9022.c
index 9994385c35..9c36e4c17e 100644
--- a/hw/display/sii9022.c
+++ b/hw/display/sii9022.c
@@ -16,7 +16,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "hw/i2c/i2c.h"
-#include "hw/i2c/i2c-ddc.h"
+#include "hw/display/i2c-ddc.h"
#include "trace.h"
#define SII9022_SYS_CTRL_DATA 0x1a
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 2122291308..1e2709b2d0 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -35,7 +35,7 @@
#include "hw/sysbus.h"
#include "hw/pci/pci.h"
#include "hw/i2c/i2c.h"
-#include "hw/i2c/i2c-ddc.h"
+#include "hw/display/i2c-ddc.h"
#include "qemu/range.h"
#include "ui/pixel_ops.h"
#include "qemu/bswap.h"
diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig
index 820b24de5b..78a2008e3a 100644
--- a/hw/i2c/Kconfig
+++ b/hw/i2c/Kconfig
@@ -5,11 +5,6 @@ config SMBUS_EEPROM
bool
depends on I2C
-config DDC
- bool
- depends on I2C
- select EDID
-
config VERSATILE_I2C
bool
select I2C
diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index 5f76b6a990..d7073a401f 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -1,6 +1,5 @@
common-obj-$(CONFIG_I2C) += core.o smbus_slave.o smbus_master.o
common-obj-$(CONFIG_SMBUS_EEPROM) += smbus_eeprom.o
-common-obj-$(CONFIG_DDC) += i2c-ddc.o
common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
common-obj-$(CONFIG_ACPI_X86_ICH) += smbus_ich9.o
common-obj-$(CONFIG_ACPI_SMBUS) += pm_smbus.o
diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c
index 7b24be8256..251d3d142f 100644
--- a/hw/i2c/smbus_ich9.c
+++ b/hw/i2c/smbus_ich9.c
@@ -6,23 +6,18 @@
* VA Linux Systems Japan K.K.
* Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
*
- * This is based on acpi.c, but heavily rewritten.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
+ * General Public License for more details.
*
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index c628540774..751fcafa12 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -269,9 +269,7 @@ void pc_system_firmware_init(PCMachineState *pcms,
{
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
int i;
- DriveInfo *pflash_drv;
BlockBackend *pflash_blk[ARRAY_SIZE(pcms->flash)];
- Location loc;
if (!pcmc->pci_enabled) {
old_pc_system_rom_init(rom_memory, true);
@@ -280,21 +278,9 @@ void pc_system_firmware_init(PCMachineState *pcms,
/* Map legacy -drive if=pflash to machine properties */
for (i = 0; i < ARRAY_SIZE(pcms->flash); i++) {
+ pflash_cfi01_legacy_drive(pcms->flash[i],
+ drive_get(IF_PFLASH, 0, i));
pflash_blk[i] = pflash_cfi01_get_blk(pcms->flash[i]);
- pflash_drv = drive_get(IF_PFLASH, 0, i);
- if (!pflash_drv) {
- continue;
- }
- loc_push_none(&loc);
- qemu_opts_loc_restore(pflash_drv->opts);
- if (pflash_blk[i]) {
- error_report("clashes with -machine");
- exit(1);
- }
- pflash_blk[i] = blk_by_legacy_dinfo(pflash_drv);
- qdev_prop_set_drive(DEVICE(pcms->flash[i]),
- "drive", pflash_blk[i], &error_fatal);
- loc_pop(&loc);
}
/* Reject gaps */
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index fff6e694e6..3a346a682a 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -213,6 +213,7 @@ static void nvic_recompute_state_secure(NVICState *s)
int active_prio = NVIC_NOEXC_PRIO;
int pend_irq = 0;
bool pending_is_s_banked = false;
+ int pend_subprio = 0;
/* R_CQRV: precedence is by:
* - lowest group priority; if both the same then
@@ -226,7 +227,7 @@ static void nvic_recompute_state_secure(NVICState *s)
for (i = 1; i < s->num_irq; i++) {
for (bank = M_REG_S; bank >= M_REG_NS; bank--) {
VecInfo *vec;
- int prio;
+ int prio, subprio;
bool targets_secure;
if (bank == M_REG_S) {
@@ -241,8 +242,12 @@ static void nvic_recompute_state_secure(NVICState *s)
}
prio = exc_group_prio(s, vec->prio, targets_secure);
- if (vec->enabled && vec->pending && prio < pend_prio) {
+ subprio = vec->prio & ~nvic_gprio_mask(s, targets_secure);
+ if (vec->enabled && vec->pending &&
+ ((prio < pend_prio) ||
+ (prio == pend_prio && prio >= 0 && subprio < pend_subprio))) {
pend_prio = prio;
+ pend_subprio = subprio;
pend_irq = i;
pending_is_s_banked = (bank == M_REG_S);
}
@@ -1162,6 +1167,10 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
goto bad_offset;
}
+ if (!attrs.secure &&
+ !(s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
+ return 0;
+ }
return cpu->env.v7m.bfar;
case 0xd3c: /* Aux Fault Status. */
/* TODO: Implement fault status registers. */
@@ -1641,6 +1650,10 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
goto bad_offset;
}
+ if (!attrs.secure &&
+ !(s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
+ return;
+ }
cpu->env.v7m.bfar = value;
return;
case 0xd3c: /* Aux Fault Status. */
@@ -2125,11 +2138,18 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
val = 0;
break;
};
- /* The BFSR bits [15:8] are shared between security states
- * and we store them in the NS copy
+ /*
+ * The BFSR bits [15:8] are shared between security states
+ * and we store them in the NS copy. They are RAZ/WI for
+ * NS code if AIRCR.BFHFNMINS is 0.
*/
val = s->cpu->env.v7m.cfsr[attrs.secure];
- val |= s->cpu->env.v7m.cfsr[M_REG_NS] & R_V7M_CFSR_BFSR_MASK;
+ if (!attrs.secure &&
+ !(s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
+ val &= ~R_V7M_CFSR_BFSR_MASK;
+ } else {
+ val |= s->cpu->env.v7m.cfsr[M_REG_NS] & R_V7M_CFSR_BFSR_MASK;
+ }
val = extract32(val, (offset - 0xd28) * 8, size * 8);
break;
case 0xfe0 ... 0xfff: /* ID. */
@@ -2244,6 +2264,12 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
*/
value <<= ((offset - 0xd28) * 8);
+ if (!attrs.secure &&
+ !(s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
+ /* BFSR bits are RAZ/WI for NS if BFHFNMINS is set */
+ value &= ~R_V7M_CFSR_BFSR_MASK;
+ }
+
s->cpu->env.v7m.cfsr[attrs.secure] &= ~value;
if (attrs.secure) {
/* The BFSR bits [15:8] are shared between security states
@@ -2465,10 +2491,12 @@ static void armv7m_nvic_reset(DeviceState *dev)
* the System Handler Control register
*/
s->vectors[ARMV7M_EXCP_SVC].enabled = 1;
- s->vectors[ARMV7M_EXCP_DEBUG].enabled = 1;
s->vectors[ARMV7M_EXCP_PENDSV].enabled = 1;
s->vectors[ARMV7M_EXCP_SYSTICK].enabled = 1;
+ /* DebugMonitor is enabled via DEMCR.MON_EN */
+ s->vectors[ARMV7M_EXCP_DEBUG].enabled = 0;
+
resetprio = arm_feature(&s->cpu->env, ARM_FEATURE_V8) ? -4 : -3;
s->vectors[ARMV7M_EXCP_RESET].prio = resetprio;
s->vectors[ARMV7M_EXCP_NMI].prio = -2;
diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c
index d9ba04bdfc..16683091c9 100644
--- a/hw/net/pcnet.c
+++ b/hw/net/pcnet.c
@@ -36,6 +36,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "hw/qdev.h"
#include "net/net.h"
#include "net/eth.h"
@@ -1501,7 +1502,8 @@ static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
val |= 0x0300;
break;
default:
- printf("Bad SWSTYLE=0x%02x\n", val & 0xff);
+ qemu_log_mask(LOG_GUEST_ERROR, "pcnet: Bad SWSTYLE=0x%02x\n",
+ val & 0xff);
val = 0x0200;
break;
}
diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c
index 850f88761c..fe95efc41c 100644
--- a/hw/openrisc/cputimer.c
+++ b/hw/openrisc/cputimer.c
@@ -7,7 +7,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c
index 7d3b734d24..0a906d815e 100644
--- a/hw/openrisc/openrisc_sim.c
+++ b/hw/openrisc/openrisc_sim.c
@@ -7,7 +7,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/hw/openrisc/pic_cpu.c b/hw/openrisc/pic_cpu.c
index 569b443f59..2f53cfc82e 100644
--- a/hw/openrisc/pic_cpu.c
+++ b/hw/openrisc/pic_cpu.c
@@ -7,7 +7,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c
index d1660b6474..cf34874e9d 100644
--- a/hw/rdma/rdma_backend.c
+++ b/hw/rdma/rdma_backend.c
@@ -40,6 +40,7 @@ typedef struct BackendCtx {
void *up_ctx;
struct ibv_sge sge; /* Used to save MAD recv buffer */
RdmaBackendQP *backend_qp; /* To maintain recv buffers */
+ RdmaBackendSRQ *backend_srq;
} BackendCtx;
struct backend_umad {
@@ -99,6 +100,7 @@ static int rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq)
int i, ne, total_ne = 0;
BackendCtx *bctx;
struct ibv_wc wc[2];
+ RdmaProtectedGSList *cqe_ctx_list;
qemu_mutex_lock(&rdma_dev_res->lock);
do {
@@ -116,8 +118,13 @@ static int rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq)
comp_handler(bctx->up_ctx, &wc[i]);
- rdma_protected_gslist_remove_int32(&bctx->backend_qp->cqe_ctx_list,
- wc[i].wr_id);
+ if (bctx->backend_qp) {
+ cqe_ctx_list = &bctx->backend_qp->cqe_ctx_list;
+ } else {
+ cqe_ctx_list = &bctx->backend_srq->cqe_ctx_list;
+ }
+
+ rdma_protected_gslist_remove_int32(cqe_ctx_list, wc[i].wr_id);
rdma_rm_dealloc_cqe_ctx(rdma_dev_res, wc[i].wr_id);
g_free(bctx);
}
@@ -662,6 +669,60 @@ err_free_bctx:
g_free(bctx);
}
+void rdma_backend_post_srq_recv(RdmaBackendDev *backend_dev,
+ RdmaBackendSRQ *srq, struct ibv_sge *sge,
+ uint32_t num_sge, void *ctx)
+{
+ BackendCtx *bctx;
+ struct ibv_sge new_sge[MAX_SGE];
+ uint32_t bctx_id;
+ int rc;
+ struct ibv_recv_wr wr = {}, *bad_wr;
+
+ bctx = g_malloc0(sizeof(*bctx));
+ bctx->up_ctx = ctx;
+ bctx->backend_srq = srq;
+
+ rc = rdma_rm_alloc_cqe_ctx(backend_dev->rdma_dev_res, &bctx_id, bctx);
+ if (unlikely(rc)) {
+ complete_work(IBV_WC_GENERAL_ERR, VENDOR_ERR_NOMEM, ctx);
+ goto err_free_bctx;
+ }
+
+ rdma_protected_gslist_append_int32(&srq->cqe_ctx_list, bctx_id);
+
+ rc = build_host_sge_array(backend_dev->rdma_dev_res, new_sge, sge, num_sge,
+ &backend_dev->rdma_dev_res->stats.rx_bufs_len);
+ if (rc) {
+ complete_work(IBV_WC_GENERAL_ERR, rc, ctx);
+ goto err_dealloc_cqe_ctx;
+ }
+
+ wr.num_sge = num_sge;
+ wr.sg_list = new_sge;
+ wr.wr_id = bctx_id;
+ rc = ibv_post_srq_recv(srq->ibsrq, &wr, &bad_wr);
+ if (rc) {
+ rdma_error_report("ibv_post_srq_recv fail, srqn=0x%x, rc=%d, errno=%d",
+ srq->ibsrq->handle, rc, errno);
+ complete_work(IBV_WC_GENERAL_ERR, VENDOR_ERR_FAIL_BACKEND, ctx);
+ goto err_dealloc_cqe_ctx;
+ }
+
+ atomic_inc(&backend_dev->rdma_dev_res->stats.missing_cqe);
+ backend_dev->rdma_dev_res->stats.rx_bufs++;
+ backend_dev->rdma_dev_res->stats.rx_srq++;
+
+ return;
+
+err_dealloc_cqe_ctx:
+ backend_dev->rdma_dev_res->stats.rx_bufs_err++;
+ rdma_rm_dealloc_cqe_ctx(backend_dev->rdma_dev_res, bctx_id);
+
+err_free_bctx:
+ g_free(bctx);
+}
+
int rdma_backend_create_pd(RdmaBackendDev *backend_dev, RdmaBackendPD *pd)
{
pd->ibpd = ibv_alloc_pd(backend_dev->context);
@@ -733,9 +794,9 @@ void rdma_backend_destroy_cq(RdmaBackendCQ *cq)
int rdma_backend_create_qp(RdmaBackendQP *qp, uint8_t qp_type,
RdmaBackendPD *pd, RdmaBackendCQ *scq,
- RdmaBackendCQ *rcq, uint32_t max_send_wr,
- uint32_t max_recv_wr, uint32_t max_send_sge,
- uint32_t max_recv_sge)
+ RdmaBackendCQ *rcq, RdmaBackendSRQ *srq,
+ uint32_t max_send_wr, uint32_t max_recv_wr,
+ uint32_t max_send_sge, uint32_t max_recv_sge)
{
struct ibv_qp_init_attr attr = {};
@@ -763,6 +824,9 @@ int rdma_backend_create_qp(RdmaBackendQP *qp, uint8_t qp_type,
attr.cap.max_recv_wr = max_recv_wr;
attr.cap.max_send_sge = max_send_sge;
attr.cap.max_recv_sge = max_recv_sge;
+ if (srq) {
+ attr.srq = srq->ibsrq;
+ }
qp->ibqp = ibv_create_qp(pd->ibpd, &attr);
if (!qp->ibqp) {
@@ -938,6 +1002,55 @@ void rdma_backend_destroy_qp(RdmaBackendQP *qp, RdmaDeviceResources *dev_res)
rdma_protected_gslist_destroy(&qp->cqe_ctx_list);
}
+int rdma_backend_create_srq(RdmaBackendSRQ *srq, RdmaBackendPD *pd,
+ uint32_t max_wr, uint32_t max_sge,
+ uint32_t srq_limit)
+{
+ struct ibv_srq_init_attr srq_init_attr = {};
+
+ srq_init_attr.attr.max_wr = max_wr;
+ srq_init_attr.attr.max_sge = max_sge;
+ srq_init_attr.attr.srq_limit = srq_limit;
+
+ srq->ibsrq = ibv_create_srq(pd->ibpd, &srq_init_attr);
+ if (!srq->ibsrq) {
+ rdma_error_report("ibv_create_srq failed, errno=%d", errno);
+ return -EIO;
+ }
+
+ rdma_protected_gslist_init(&srq->cqe_ctx_list);
+
+ return 0;
+}
+
+int rdma_backend_query_srq(RdmaBackendSRQ *srq, struct ibv_srq_attr *srq_attr)
+{
+ if (!srq->ibsrq) {
+ return -EINVAL;
+ }
+
+ return ibv_query_srq(srq->ibsrq, srq_attr);
+}
+
+int rdma_backend_modify_srq(RdmaBackendSRQ *srq, struct ibv_srq_attr *srq_attr,
+ int srq_attr_mask)
+{
+ if (!srq->ibsrq) {
+ return -EINVAL;
+ }
+
+ return ibv_modify_srq(srq->ibsrq, srq_attr, srq_attr_mask);
+}
+
+void rdma_backend_destroy_srq(RdmaBackendSRQ *srq, RdmaDeviceResources *dev_res)
+{
+ if (srq->ibsrq) {
+ ibv_destroy_srq(srq->ibsrq);
+ }
+ g_slist_foreach(srq->cqe_ctx_list.list, free_cqe_ctx, dev_res);
+ rdma_protected_gslist_destroy(&srq->cqe_ctx_list);
+}
+
#define CHK_ATTR(req, dev, member, fmt) ({ \
trace_rdma_check_dev_attr(#member, dev.member, req->member); \
if (req->member > dev.member) { \
@@ -960,6 +1073,7 @@ static int init_device_caps(RdmaBackendDev *backend_dev,
}
dev_attr->max_sge = MAX_SGE;
+ dev_attr->max_srq_sge = MAX_SGE;
CHK_ATTR(dev_attr, bk_dev_attr, max_mr_size, "%" PRId64);
CHK_ATTR(dev_attr, bk_dev_attr, max_qp, "%d");
@@ -970,6 +1084,7 @@ static int init_device_caps(RdmaBackendDev *backend_dev,
CHK_ATTR(dev_attr, bk_dev_attr, max_qp_rd_atom, "%d");
CHK_ATTR(dev_attr, bk_dev_attr, max_qp_init_rd_atom, "%d");
CHK_ATTR(dev_attr, bk_dev_attr, max_ah, "%d");
+ CHK_ATTR(dev_attr, bk_dev_attr, max_srq, "%d");
return 0;
}
diff --git a/hw/rdma/rdma_backend.h b/hw/rdma/rdma_backend.h
index 38056d97c7..7c1a19a2b5 100644
--- a/hw/rdma/rdma_backend.h
+++ b/hw/rdma/rdma_backend.h
@@ -89,9 +89,9 @@ void rdma_backend_poll_cq(RdmaDeviceResources *rdma_dev_res, RdmaBackendCQ *cq);
int rdma_backend_create_qp(RdmaBackendQP *qp, uint8_t qp_type,
RdmaBackendPD *pd, RdmaBackendCQ *scq,
- RdmaBackendCQ *rcq, uint32_t max_send_wr,
- uint32_t max_recv_wr, uint32_t max_send_sge,
- uint32_t max_recv_sge);
+ RdmaBackendCQ *rcq, RdmaBackendSRQ *srq,
+ uint32_t max_send_wr, uint32_t max_recv_wr,
+ uint32_t max_send_sge, uint32_t max_recv_sge);
int rdma_backend_qp_state_init(RdmaBackendDev *backend_dev, RdmaBackendQP *qp,
uint8_t qp_type, uint32_t qkey);
int rdma_backend_qp_state_rtr(RdmaBackendDev *backend_dev, RdmaBackendQP *qp,
@@ -114,4 +114,16 @@ void rdma_backend_post_recv(RdmaBackendDev *backend_dev,
RdmaBackendQP *qp, uint8_t qp_type,
struct ibv_sge *sge, uint32_t num_sge, void *ctx);
+int rdma_backend_create_srq(RdmaBackendSRQ *srq, RdmaBackendPD *pd,
+ uint32_t max_wr, uint32_t max_sge,
+ uint32_t srq_limit);
+int rdma_backend_query_srq(RdmaBackendSRQ *srq, struct ibv_srq_attr *srq_attr);
+int rdma_backend_modify_srq(RdmaBackendSRQ *srq, struct ibv_srq_attr *srq_attr,
+ int srq_attr_mask);
+void rdma_backend_destroy_srq(RdmaBackendSRQ *srq,
+ RdmaDeviceResources *dev_res);
+void rdma_backend_post_srq_recv(RdmaBackendDev *backend_dev,
+ RdmaBackendSRQ *srq, struct ibv_sge *sge,
+ uint32_t num_sge, void *ctx);
+
#endif
diff --git a/hw/rdma/rdma_backend_defs.h b/hw/rdma/rdma_backend_defs.h
index 817153dc8c..0b55be3503 100644
--- a/hw/rdma/rdma_backend_defs.h
+++ b/hw/rdma/rdma_backend_defs.h
@@ -68,4 +68,9 @@ typedef struct RdmaBackendQP {
RdmaProtectedGSList cqe_ctx_list;
} RdmaBackendQP;
+typedef struct RdmaBackendSRQ {
+ struct ibv_srq *ibsrq;
+ RdmaProtectedGSList cqe_ctx_list;
+} RdmaBackendSRQ;
+
#endif
diff --git a/hw/rdma/rdma_rm.c b/hw/rdma/rdma_rm.c
index bac3b2f4a6..1927f85472 100644
--- a/hw/rdma/rdma_rm.c
+++ b/hw/rdma/rdma_rm.c
@@ -37,6 +37,8 @@ void rdma_dump_device_counters(Monitor *mon, RdmaDeviceResources *dev_res)
dev_res->stats.tx_err);
monitor_printf(mon, "\trx_bufs : %" PRId64 "\n",
dev_res->stats.rx_bufs);
+ monitor_printf(mon, "\trx_srq : %" PRId64 "\n",
+ dev_res->stats.rx_srq);
monitor_printf(mon, "\trx_bufs_len : %" PRId64 "\n",
dev_res->stats.rx_bufs_len);
monitor_printf(mon, "\trx_bufs_err : %" PRId64 "\n",
@@ -384,12 +386,14 @@ int rdma_rm_alloc_qp(RdmaDeviceResources *dev_res, uint32_t pd_handle,
uint8_t qp_type, uint32_t max_send_wr,
uint32_t max_send_sge, uint32_t send_cq_handle,
uint32_t max_recv_wr, uint32_t max_recv_sge,
- uint32_t recv_cq_handle, void *opaque, uint32_t *qpn)
+ uint32_t recv_cq_handle, void *opaque, uint32_t *qpn,
+ uint8_t is_srq, uint32_t srq_handle)
{
int rc;
RdmaRmQP *qp;
RdmaRmCQ *scq, *rcq;
RdmaRmPD *pd;
+ RdmaRmSRQ *srq = NULL;
uint32_t rm_qpn;
pd = rdma_rm_get_pd(dev_res, pd_handle);
@@ -406,6 +410,16 @@ int rdma_rm_alloc_qp(RdmaDeviceResources *dev_res, uint32_t pd_handle,
return -EINVAL;
}
+ if (is_srq) {
+ srq = rdma_rm_get_srq(dev_res, srq_handle);
+ if (!srq) {
+ rdma_error_report("Invalid srqn %d", srq_handle);
+ return -EINVAL;
+ }
+
+ srq->recv_cq_handle = recv_cq_handle;
+ }
+
if (qp_type == IBV_QPT_GSI) {
scq->notify = CNT_SET;
rcq->notify = CNT_SET;
@@ -422,10 +436,14 @@ int rdma_rm_alloc_qp(RdmaDeviceResources *dev_res, uint32_t pd_handle,
qp->send_cq_handle = send_cq_handle;
qp->recv_cq_handle = recv_cq_handle;
qp->opaque = opaque;
+ qp->is_srq = is_srq;
rc = rdma_backend_create_qp(&qp->backend_qp, qp_type, &pd->backend_pd,
- &scq->backend_cq, &rcq->backend_cq, max_send_wr,
- max_recv_wr, max_send_sge, max_recv_sge);
+ &scq->backend_cq, &rcq->backend_cq,
+ is_srq ? &srq->backend_srq : NULL,
+ max_send_wr, max_recv_wr, max_send_sge,
+ max_recv_sge);
+
if (rc) {
rc = -EIO;
goto out_dealloc_qp;
@@ -542,6 +560,96 @@ void rdma_rm_dealloc_qp(RdmaDeviceResources *dev_res, uint32_t qp_handle)
rdma_res_tbl_dealloc(&dev_res->qp_tbl, qp->qpn);
}
+RdmaRmSRQ *rdma_rm_get_srq(RdmaDeviceResources *dev_res, uint32_t srq_handle)
+{
+ return rdma_res_tbl_get(&dev_res->srq_tbl, srq_handle);
+}
+
+int rdma_rm_alloc_srq(RdmaDeviceResources *dev_res, uint32_t pd_handle,
+ uint32_t max_wr, uint32_t max_sge, uint32_t srq_limit,
+ uint32_t *srq_handle, void *opaque)
+{
+ RdmaRmSRQ *srq;
+ RdmaRmPD *pd;
+ int rc;
+
+ pd = rdma_rm_get_pd(dev_res, pd_handle);
+ if (!pd) {
+ return -EINVAL;
+ }
+
+ srq = rdma_res_tbl_alloc(&dev_res->srq_tbl, srq_handle);
+ if (!srq) {
+ return -ENOMEM;
+ }
+
+ rc = rdma_backend_create_srq(&srq->backend_srq, &pd->backend_pd,
+ max_wr, max_sge, srq_limit);
+ if (rc) {
+ rc = -EIO;
+ goto out_dealloc_srq;
+ }
+
+ srq->opaque = opaque;
+
+ return 0;
+
+out_dealloc_srq:
+ rdma_res_tbl_dealloc(&dev_res->srq_tbl, *srq_handle);
+
+ return rc;
+}
+
+int rdma_rm_query_srq(RdmaDeviceResources *dev_res, uint32_t srq_handle,
+ struct ibv_srq_attr *srq_attr)
+{
+ RdmaRmSRQ *srq;
+
+ srq = rdma_rm_get_srq(dev_res, srq_handle);
+ if (!srq) {
+ return -EINVAL;
+ }
+
+ return rdma_backend_query_srq(&srq->backend_srq, srq_attr);
+}
+
+int rdma_rm_modify_srq(RdmaDeviceResources *dev_res, uint32_t srq_handle,
+ struct ibv_srq_attr *srq_attr, int srq_attr_mask)
+{
+ RdmaRmSRQ *srq;
+
+ srq = rdma_rm_get_srq(dev_res, srq_handle);
+ if (!srq) {
+ return -EINVAL;
+ }
+
+ if ((srq_attr_mask & IBV_SRQ_LIMIT) &&
+ (srq_attr->srq_limit == 0)) {
+ return -EINVAL;
+ }
+
+ if ((srq_attr_mask & IBV_SRQ_MAX_WR) &&
+ (srq_attr->max_wr == 0)) {
+ return -EINVAL;
+ }
+
+ return rdma_backend_modify_srq(&srq->backend_srq, srq_attr,
+ srq_attr_mask);
+}
+
+void rdma_rm_dealloc_srq(RdmaDeviceResources *dev_res, uint32_t srq_handle)
+{
+ RdmaRmSRQ *srq;
+
+ srq = rdma_rm_get_srq(dev_res, srq_handle);
+ if (!srq) {
+ return;
+ }
+
+ rdma_backend_destroy_srq(&srq->backend_srq, dev_res);
+ rdma_res_tbl_dealloc(&dev_res->srq_tbl, srq_handle);
+}
+
void *rdma_rm_get_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t cqe_ctx_id)
{
void **cqe_ctx;
@@ -671,6 +779,8 @@ int rdma_rm_init(RdmaDeviceResources *dev_res, struct ibv_device_attr *dev_attr)
res_tbl_init("CQE_CTX", &dev_res->cqe_ctx_tbl, dev_attr->max_qp *
dev_attr->max_qp_wr, sizeof(void *));
res_tbl_init("UC", &dev_res->uc_tbl, MAX_UCS, sizeof(RdmaRmUC));
+ res_tbl_init("SRQ", &dev_res->srq_tbl, dev_attr->max_srq,
+ sizeof(RdmaRmSRQ));
init_ports(dev_res);
@@ -689,6 +799,7 @@ void rdma_rm_fini(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
fini_ports(dev_res, backend_dev, ifname);
+ res_tbl_free(&dev_res->srq_tbl);
res_tbl_free(&dev_res->uc_tbl);
res_tbl_free(&dev_res->cqe_ctx_tbl);
res_tbl_free(&dev_res->qp_tbl);
diff --git a/hw/rdma/rdma_rm.h b/hw/rdma/rdma_rm.h
index 4f03f9b8c5..e8639909cd 100644
--- a/hw/rdma/rdma_rm.h
+++ b/hw/rdma/rdma_rm.h
@@ -53,7 +53,8 @@ int rdma_rm_alloc_qp(RdmaDeviceResources *dev_res, uint32_t pd_handle,
uint8_t qp_type, uint32_t max_send_wr,
uint32_t max_send_sge, uint32_t send_cq_handle,
uint32_t max_recv_wr, uint32_t max_recv_sge,
- uint32_t recv_cq_handle, void *opaque, uint32_t *qpn);
+ uint32_t recv_cq_handle, void *opaque, uint32_t *qpn,
+ uint8_t is_srq, uint32_t srq_handle);
RdmaRmQP *rdma_rm_get_qp(RdmaDeviceResources *dev_res, uint32_t qpn);
int rdma_rm_modify_qp(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
uint32_t qp_handle, uint32_t attr_mask, uint8_t sgid_idx,
@@ -65,6 +66,16 @@ int rdma_rm_query_qp(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
int attr_mask, struct ibv_qp_init_attr *init_attr);
void rdma_rm_dealloc_qp(RdmaDeviceResources *dev_res, uint32_t qp_handle);
+RdmaRmSRQ *rdma_rm_get_srq(RdmaDeviceResources *dev_res, uint32_t srq_handle);
+int rdma_rm_alloc_srq(RdmaDeviceResources *dev_res, uint32_t pd_handle,
+ uint32_t max_wr, uint32_t max_sge, uint32_t srq_limit,
+ uint32_t *srq_handle, void *opaque);
+int rdma_rm_query_srq(RdmaDeviceResources *dev_res, uint32_t srq_handle,
+ struct ibv_srq_attr *srq_attr);
+int rdma_rm_modify_srq(RdmaDeviceResources *dev_res, uint32_t srq_handle,
+ struct ibv_srq_attr *srq_attr, int srq_attr_mask);
+void rdma_rm_dealloc_srq(RdmaDeviceResources *dev_res, uint32_t srq_handle);
+
int rdma_rm_alloc_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t *cqe_ctx_id,
void *ctx);
void *rdma_rm_get_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t cqe_ctx_id);
diff --git a/hw/rdma/rdma_rm_defs.h b/hw/rdma/rdma_rm_defs.h
index c200d311de..534f2f74d3 100644
--- a/hw/rdma/rdma_rm_defs.h
+++ b/hw/rdma/rdma_rm_defs.h
@@ -33,6 +33,7 @@
#define MAX_QP_RD_ATOM 16
#define MAX_QP_INIT_RD_ATOM 16
#define MAX_AH 64
+#define MAX_SRQ 512
#define MAX_RM_TBL_NAME 16
#define MAX_CONSEQ_EMPTY_POLL_CQ 4096 /* considered as error above this */
@@ -87,8 +88,15 @@ typedef struct RdmaRmQP {
uint32_t send_cq_handle;
uint32_t recv_cq_handle;
enum ibv_qp_state qp_state;
+ uint8_t is_srq;
} RdmaRmQP;
+typedef struct RdmaRmSRQ {
+ RdmaBackendSRQ backend_srq;
+ uint32_t recv_cq_handle;
+ void *opaque;
+} RdmaRmSRQ;
+
typedef struct RdmaRmGid {
union ibv_gid gid;
int backend_gid_index;
@@ -106,6 +114,7 @@ typedef struct RdmaRmStats {
uint64_t rx_bufs;
uint64_t rx_bufs_len;
uint64_t rx_bufs_err;
+ uint64_t rx_srq;
uint64_t completions;
uint64_t mad_tx;
uint64_t mad_tx_err;
@@ -128,6 +137,7 @@ struct RdmaDeviceResources {
RdmaRmResTbl qp_tbl;
RdmaRmResTbl cq_tbl;
RdmaRmResTbl cqe_ctx_tbl;
+ RdmaRmResTbl srq_tbl;
GHashTable *qp_hash; /* Keeps mapping between real and emulated */
QemuMutex lock;
RdmaRmStats stats;
diff --git a/hw/rdma/vmw/pvrdma_cmd.c b/hw/rdma/vmw/pvrdma_cmd.c
index 4afcd2037d..8d70c0d23d 100644
--- a/hw/rdma/vmw/pvrdma_cmd.c
+++ b/hw/rdma/vmw/pvrdma_cmd.c
@@ -357,7 +357,7 @@ static int destroy_cq(PVRDMADev *dev, union pvrdma_cmd_req *req,
static int create_qp_rings(PCIDevice *pci_dev, uint64_t pdir_dma,
PvrdmaRing **rings, uint32_t scqe, uint32_t smax_sge,
uint32_t spages, uint32_t rcqe, uint32_t rmax_sge,
- uint32_t rpages)
+ uint32_t rpages, uint8_t is_srq)
{
uint64_t *dir = NULL, *tbl = NULL;
PvrdmaRing *sr, *rr;
@@ -365,9 +365,14 @@ static int create_qp_rings(PCIDevice *pci_dev, uint64_t pdir_dma,
char ring_name[MAX_RING_NAME_SZ];
uint32_t wqe_sz;
- if (!spages || spages > PVRDMA_MAX_FAST_REG_PAGES
- || !rpages || rpages > PVRDMA_MAX_FAST_REG_PAGES) {
- rdma_error_report("Got invalid page count for QP ring: %d, %d", spages,
+ if (!spages || spages > PVRDMA_MAX_FAST_REG_PAGES) {
+ rdma_error_report("Got invalid send page count for QP ring: %d",
+ spages);
+ return rc;
+ }
+
+ if (!is_srq && (!rpages || rpages > PVRDMA_MAX_FAST_REG_PAGES)) {
+ rdma_error_report("Got invalid recv page count for QP ring: %d",
rpages);
return rc;
}
@@ -384,8 +389,12 @@ static int create_qp_rings(PCIDevice *pci_dev, uint64_t pdir_dma,
goto out;
}
- sr = g_malloc(2 * sizeof(*rr));
- rr = &sr[1];
+ if (!is_srq) {
+ sr = g_malloc(2 * sizeof(*rr));
+ rr = &sr[1];
+ } else {
+ sr = g_malloc(sizeof(*sr));
+ }
*rings = sr;
@@ -407,15 +416,18 @@ static int create_qp_rings(PCIDevice *pci_dev, uint64_t pdir_dma,
goto out_unmap_ring_state;
}
- /* Create recv ring */
- rr->ring_state = &sr->ring_state[1];
- wqe_sz = pow2ceil(sizeof(struct pvrdma_rq_wqe_hdr) +
- sizeof(struct pvrdma_sge) * rmax_sge - 1);
- sprintf(ring_name, "qp_rring_%" PRIx64, pdir_dma);
- rc = pvrdma_ring_init(rr, ring_name, pci_dev, rr->ring_state,
- rcqe, wqe_sz, (dma_addr_t *)&tbl[1 + spages], rpages);
- if (rc) {
- goto out_free_sr;
+ if (!is_srq) {
+ /* Create recv ring */
+ rr->ring_state = &sr->ring_state[1];
+ wqe_sz = pow2ceil(sizeof(struct pvrdma_rq_wqe_hdr) +
+ sizeof(struct pvrdma_sge) * rmax_sge - 1);
+ sprintf(ring_name, "qp_rring_%" PRIx64, pdir_dma);
+ rc = pvrdma_ring_init(rr, ring_name, pci_dev, rr->ring_state,
+ rcqe, wqe_sz, (dma_addr_t *)&tbl[1 + spages],
+ rpages);
+ if (rc) {
+ goto out_free_sr;
+ }
}
goto out;
@@ -436,10 +448,12 @@ out:
return rc;
}
-static void destroy_qp_rings(PvrdmaRing *ring)
+static void destroy_qp_rings(PvrdmaRing *ring, uint8_t is_srq)
{
pvrdma_ring_free(&ring[0]);
- pvrdma_ring_free(&ring[1]);
+ if (!is_srq) {
+ pvrdma_ring_free(&ring[1]);
+ }
rdma_pci_dma_unmap(ring->dev, ring->ring_state, TARGET_PAGE_SIZE);
g_free(ring);
@@ -458,7 +472,7 @@ static int create_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
rc = create_qp_rings(PCI_DEVICE(dev), cmd->pdir_dma, &rings,
cmd->max_send_wr, cmd->max_send_sge, cmd->send_chunks,
cmd->max_recv_wr, cmd->max_recv_sge,
- cmd->total_chunks - cmd->send_chunks - 1);
+ cmd->total_chunks - cmd->send_chunks - 1, cmd->is_srq);
if (rc) {
return rc;
}
@@ -467,9 +481,9 @@ static int create_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
cmd->max_send_wr, cmd->max_send_sge,
cmd->send_cq_handle, cmd->max_recv_wr,
cmd->max_recv_sge, cmd->recv_cq_handle, rings,
- &resp->qpn);
+ &resp->qpn, cmd->is_srq, cmd->srq_handle);
if (rc) {
- destroy_qp_rings(rings);
+ destroy_qp_rings(rings, cmd->is_srq);
return rc;
}
@@ -531,10 +545,9 @@ static int destroy_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
return -EINVAL;
}
- rdma_rm_dealloc_qp(&dev->rdma_dev_res, cmd->qp_handle);
-
ring = (PvrdmaRing *)qp->opaque;
- destroy_qp_rings(ring);
+ destroy_qp_rings(ring, qp->is_srq);
+ rdma_rm_dealloc_qp(&dev->rdma_dev_res, cmd->qp_handle);
return 0;
}
@@ -596,6 +609,149 @@ static int destroy_uc(PVRDMADev *dev, union pvrdma_cmd_req *req,
return 0;
}
+static int create_srq_ring(PCIDevice *pci_dev, PvrdmaRing **ring,
+ uint64_t pdir_dma, uint32_t max_wr,
+ uint32_t max_sge, uint32_t nchunks)
+{
+ uint64_t *dir = NULL, *tbl = NULL;
+ PvrdmaRing *r;
+ int rc = -EINVAL;
+ char ring_name[MAX_RING_NAME_SZ];
+ uint32_t wqe_sz;
+
+ if (!nchunks || nchunks > PVRDMA_MAX_FAST_REG_PAGES) {
+ rdma_error_report("Got invalid page count for SRQ ring: %d",
+ nchunks);
+ return rc;
+ }
+
+ dir = rdma_pci_dma_map(pci_dev, pdir_dma, TARGET_PAGE_SIZE);
+ if (!dir) {
+ rdma_error_report("Failed to map to SRQ page directory");
+ goto out;
+ }
+
+ tbl = rdma_pci_dma_map(pci_dev, dir[0], TARGET_PAGE_SIZE);
+ if (!tbl) {
+ rdma_error_report("Failed to map to SRQ page table");
+ goto out;
+ }
+
+ r = g_malloc(sizeof(*r));
+ *ring = r;
+
+ r->ring_state = (struct pvrdma_ring *)
+ rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE);
+ if (!r->ring_state) {
+ rdma_error_report("Failed to map tp SRQ ring state");
+ goto out_free_ring_mem;
+ }
+
+ wqe_sz = pow2ceil(sizeof(struct pvrdma_rq_wqe_hdr) +
+ sizeof(struct pvrdma_sge) * max_sge - 1);
+ sprintf(ring_name, "srq_ring_%" PRIx64, pdir_dma);
+ rc = pvrdma_ring_init(r, ring_name, pci_dev, &r->ring_state[1], max_wr,
+ wqe_sz, (dma_addr_t *)&tbl[1], nchunks - 1);
+ if (rc) {
+ goto out_unmap_ring_state;
+ }
+
+ goto out;
+
+out_unmap_ring_state:
+ rdma_pci_dma_unmap(pci_dev, r->ring_state, TARGET_PAGE_SIZE);
+
+out_free_ring_mem:
+ g_free(r);
+
+out:
+ rdma_pci_dma_unmap(pci_dev, tbl, TARGET_PAGE_SIZE);
+ rdma_pci_dma_unmap(pci_dev, dir, TARGET_PAGE_SIZE);
+
+ return rc;
+}
+
+static void destroy_srq_ring(PvrdmaRing *ring)
+{
+ pvrdma_ring_free(ring);
+ rdma_pci_dma_unmap(ring->dev, ring->ring_state, TARGET_PAGE_SIZE);
+ g_free(ring);
+}
+
+static int create_srq(PVRDMADev *dev, union pvrdma_cmd_req *req,
+ union pvrdma_cmd_resp *rsp)
+{
+ struct pvrdma_cmd_create_srq *cmd = &req->create_srq;
+ struct pvrdma_cmd_create_srq_resp *resp = &rsp->create_srq_resp;
+ PvrdmaRing *ring = NULL;
+ int rc;
+
+ memset(resp, 0, sizeof(*resp));
+
+ rc = create_srq_ring(PCI_DEVICE(dev), &ring, cmd->pdir_dma,
+ cmd->attrs.max_wr, cmd->attrs.max_sge,
+ cmd->nchunks);
+ if (rc) {
+ return rc;
+ }
+
+ rc = rdma_rm_alloc_srq(&dev->rdma_dev_res, cmd->pd_handle,
+ cmd->attrs.max_wr, cmd->attrs.max_sge,
+ cmd->attrs.srq_limit, &resp->srqn, ring);
+ if (rc) {
+ destroy_srq_ring(ring);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int query_srq(PVRDMADev *dev, union pvrdma_cmd_req *req,
+ union pvrdma_cmd_resp *rsp)
+{
+ struct pvrdma_cmd_query_srq *cmd = &req->query_srq;
+ struct pvrdma_cmd_query_srq_resp *resp = &rsp->query_srq_resp;
+
+ memset(resp, 0, sizeof(*resp));
+
+ return rdma_rm_query_srq(&dev->rdma_dev_res, cmd->srq_handle,
+ (struct ibv_srq_attr *)&resp->attrs);
+}
+
+static int modify_srq(PVRDMADev *dev, union pvrdma_cmd_req *req,
+ union pvrdma_cmd_resp *rsp)
+{
+ struct pvrdma_cmd_modify_srq *cmd = &req->modify_srq;
+
+ /* Only support SRQ limit */
+ if (!(cmd->attr_mask & IBV_SRQ_LIMIT) ||
+ (cmd->attr_mask & IBV_SRQ_MAX_WR))
+ return -EINVAL;
+
+ return rdma_rm_modify_srq(&dev->rdma_dev_res, cmd->srq_handle,
+ (struct ibv_srq_attr *)&cmd->attrs,
+ cmd->attr_mask);
+}
+
+static int destroy_srq(PVRDMADev *dev, union pvrdma_cmd_req *req,
+ union pvrdma_cmd_resp *rsp)
+{
+ struct pvrdma_cmd_destroy_srq *cmd = &req->destroy_srq;
+ RdmaRmSRQ *srq;
+ PvrdmaRing *ring;
+
+ srq = rdma_rm_get_srq(&dev->rdma_dev_res, cmd->srq_handle);
+ if (!srq) {
+ return -EINVAL;
+ }
+
+ ring = (PvrdmaRing *)srq->opaque;
+ destroy_srq_ring(ring);
+ rdma_rm_dealloc_srq(&dev->rdma_dev_res, cmd->srq_handle);
+
+ return 0;
+}
+
struct cmd_handler {
uint32_t cmd;
uint32_t ack;
@@ -621,6 +777,10 @@ static struct cmd_handler cmd_handlers[] = {
{PVRDMA_CMD_DESTROY_UC, PVRDMA_CMD_DESTROY_UC_RESP_NOOP, destroy_uc},
{PVRDMA_CMD_CREATE_BIND, PVRDMA_CMD_CREATE_BIND_RESP_NOOP, create_bind},
{PVRDMA_CMD_DESTROY_BIND, PVRDMA_CMD_DESTROY_BIND_RESP_NOOP, destroy_bind},
+ {PVRDMA_CMD_CREATE_SRQ, PVRDMA_CMD_CREATE_SRQ_RESP, create_srq},
+ {PVRDMA_CMD_QUERY_SRQ, PVRDMA_CMD_QUERY_SRQ_RESP, query_srq},
+ {PVRDMA_CMD_MODIFY_SRQ, PVRDMA_CMD_MODIFY_SRQ_RESP, modify_srq},
+ {PVRDMA_CMD_DESTROY_SRQ, PVRDMA_CMD_DESTROY_SRQ_RESP, destroy_srq},
};
int pvrdma_exec_cmd(PVRDMADev *dev)
diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c
index 0b46561bad..769f7990f8 100644
--- a/hw/rdma/vmw/pvrdma_main.c
+++ b/hw/rdma/vmw/pvrdma_main.c
@@ -53,6 +53,7 @@ static Property pvrdma_dev_properties[] = {
DEFINE_PROP_INT32("dev-caps-max-qp-init-rd-atom", PVRDMADev,
dev_attr.max_qp_init_rd_atom, MAX_QP_INIT_RD_ATOM),
DEFINE_PROP_INT32("dev-caps-max-ah", PVRDMADev, dev_attr.max_ah, MAX_AH),
+ DEFINE_PROP_INT32("dev-caps-max-srq", PVRDMADev, dev_attr.max_srq, MAX_SRQ),
DEFINE_PROP_CHR("mad-chardev", PVRDMADev, mad_chr),
DEFINE_PROP_END_OF_LIST(),
};
@@ -261,6 +262,9 @@ static void init_dsr_dev_caps(PVRDMADev *dev)
dsr->caps.max_mr = dev->dev_attr.max_mr;
dsr->caps.max_pd = dev->dev_attr.max_pd;
dsr->caps.max_ah = dev->dev_attr.max_ah;
+ dsr->caps.max_srq = dev->dev_attr.max_srq;
+ dsr->caps.max_srq_wr = dev->dev_attr.max_srq_wr;
+ dsr->caps.max_srq_sge = dev->dev_attr.max_srq_sge;
dsr->caps.gid_tbl_len = MAX_GIDS;
dsr->caps.sys_image_guid = 0;
dsr->caps.node_guid = dev->node_guid;
@@ -485,6 +489,13 @@ static void pvrdma_uar_write(void *opaque, hwaddr addr, uint64_t val,
pvrdma_cq_poll(&dev->rdma_dev_res, val & PVRDMA_UAR_HANDLE_MASK);
}
break;
+ case PVRDMA_UAR_SRQ_OFFSET:
+ if (val & PVRDMA_UAR_SRQ_RECV) {
+ trace_pvrdma_uar_write(addr, val, "QP", "SRQ",
+ val & PVRDMA_UAR_HANDLE_MASK, 0);
+ pvrdma_srq_recv(dev, val & PVRDMA_UAR_HANDLE_MASK);
+ }
+ break;
default:
rdma_error_report("Unsupported command, addr=0x%"PRIx64", val=0x%"PRIx64,
addr, val);
@@ -554,6 +565,11 @@ static void init_dev_caps(PVRDMADev *dev)
dev->dev_attr.max_cqe = pg_tbl_bytes / sizeof(struct pvrdma_cqe) -
TARGET_PAGE_SIZE; /* First page is ring state */
+
+ dev->dev_attr.max_srq_wr = pg_tbl_bytes /
+ ((sizeof(struct pvrdma_rq_wqe_hdr) +
+ sizeof(struct pvrdma_sge)) *
+ dev->dev_attr.max_sge) - TARGET_PAGE_SIZE;
}
static int pvrdma_check_ram_shared(Object *obj, void *opaque)
diff --git a/hw/rdma/vmw/pvrdma_qp_ops.c b/hw/rdma/vmw/pvrdma_qp_ops.c
index 5b9786efbe..bd6db858de 100644
--- a/hw/rdma/vmw/pvrdma_qp_ops.c
+++ b/hw/rdma/vmw/pvrdma_qp_ops.c
@@ -70,7 +70,7 @@ static int pvrdma_post_cqe(PVRDMADev *dev, uint32_t cq_handle,
memset(cqe1, 0, sizeof(*cqe1));
cqe1->wr_id = cqe->wr_id;
- cqe1->qp = cqe->qp;
+ cqe1->qp = cqe->qp ? cqe->qp : wc->qp_num;
cqe1->opcode = cqe->opcode;
cqe1->status = wc->status;
cqe1->byte_len = wc->byte_len;
@@ -241,6 +241,50 @@ void pvrdma_qp_recv(PVRDMADev *dev, uint32_t qp_handle)
}
}
+void pvrdma_srq_recv(PVRDMADev *dev, uint32_t srq_handle)
+{
+ RdmaRmSRQ *srq;
+ PvrdmaRqWqe *wqe;
+ PvrdmaRing *ring;
+
+ srq = rdma_rm_get_srq(&dev->rdma_dev_res, srq_handle);
+ if (unlikely(!srq)) {
+ return;
+ }
+
+ ring = (PvrdmaRing *)srq->opaque;
+
+ wqe = (struct PvrdmaRqWqe *)pvrdma_ring_next_elem_read(ring);
+ while (wqe) {
+ CompHandlerCtx *comp_ctx;
+
+ /* Prepare CQE */
+ comp_ctx = g_malloc(sizeof(CompHandlerCtx));
+ comp_ctx->dev = dev;
+ comp_ctx->cq_handle = srq->recv_cq_handle;
+ comp_ctx->cqe.wr_id = wqe->hdr.wr_id;
+ comp_ctx->cqe.qp = 0;
+ comp_ctx->cqe.opcode = IBV_WC_RECV;
+
+ if (wqe->hdr.num_sge > dev->dev_attr.max_sge) {
+ rdma_error_report("Invalid num_sge=%d (max %d)", wqe->hdr.num_sge,
+ dev->dev_attr.max_sge);
+ complete_with_error(VENDOR_ERR_INV_NUM_SGE, comp_ctx);
+ continue;
+ }
+
+ rdma_backend_post_srq_recv(&dev->backend_dev, &srq->backend_srq,
+ (struct ibv_sge *)&wqe->sge[0],
+ wqe->hdr.num_sge,
+ comp_ctx);
+
+ pvrdma_ring_read_inc(ring);
+
+ wqe = pvrdma_ring_next_elem_read(ring);
+ }
+
+}
+
void pvrdma_cq_poll(RdmaDeviceResources *dev_res, uint32_t cq_handle)
{
RdmaRmCQ *cq;
diff --git a/hw/rdma/vmw/pvrdma_qp_ops.h b/hw/rdma/vmw/pvrdma_qp_ops.h
index 31cb48ba29..82e720a76f 100644
--- a/hw/rdma/vmw/pvrdma_qp_ops.h
+++ b/hw/rdma/vmw/pvrdma_qp_ops.h
@@ -22,6 +22,7 @@ int pvrdma_qp_ops_init(void);
void pvrdma_qp_ops_fini(void);
void pvrdma_qp_send(PVRDMADev *dev, uint32_t qp_handle);
void pvrdma_qp_recv(PVRDMADev *dev, uint32_t qp_handle);
+void pvrdma_srq_recv(PVRDMADev *dev, uint32_t srq_handle);
void pvrdma_cq_poll(RdmaDeviceResources *dev_res, uint32_t cq_handle);
#endif
diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c
index 774639af33..0383b17c29 100644
--- a/hw/sparc/leon3.c
+++ b/hw/sparc/leon3.c
@@ -194,6 +194,10 @@ static void leon3_generic_hw_init(MachineState *machine)
&entry, NULL, NULL,
1 /* big endian */, EM_SPARC, 0, 0);
if (kernel_size < 0) {
+ kernel_size = load_uimage(kernel_filename, NULL, &entry,
+ NULL, NULL, NULL);
+ }
+ if (kernel_size < 0) {
error_report("could not load kernel '%s'", kernel_filename);
exit(1);
}
diff --git a/include/block/block.h b/include/block/block.h
index c7a26199aa..5e2b98b0ee 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -316,10 +316,6 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
BlockReopenQueue *queue, Error **errp);
void bdrv_reopen_commit(BDRVReopenState *reopen_state);
void bdrv_reopen_abort(BDRVReopenState *reopen_state);
-int bdrv_read(BdrvChild *child, int64_t sector_num,
- uint8_t *buf, int nb_sectors);
-int bdrv_write(BdrvChild *child, int64_t sector_num,
- const uint8_t *buf, int nb_sectors);
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
int bytes, BdrvRequestFlags flags);
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags);
diff --git a/include/block/nbd.h b/include/block/nbd.h
index 6d05983a55..bb9f5bc021 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -127,18 +127,32 @@ typedef struct NBDExtent {
/* Transmission (export) flags: sent from server to client during handshake,
but describe what will happen during transmission */
-#define NBD_FLAG_HAS_FLAGS (1 << 0) /* Flags are there */
-#define NBD_FLAG_READ_ONLY (1 << 1) /* Device is read-only */
-#define NBD_FLAG_SEND_FLUSH (1 << 2) /* Send FLUSH */
-#define NBD_FLAG_SEND_FUA (1 << 3) /* Send FUA (Force Unit Access) */
-#define NBD_FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm -
- rotational media */
-#define NBD_FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */
-#define NBD_FLAG_SEND_WRITE_ZEROES (1 << 6) /* Send WRITE_ZEROES */
-#define NBD_FLAG_SEND_DF (1 << 7) /* Send DF (Do not Fragment) */
-#define NBD_FLAG_CAN_MULTI_CONN (1 << 8) /* Multi-client cache consistent */
-#define NBD_FLAG_SEND_RESIZE (1 << 9) /* Send resize */
-#define NBD_FLAG_SEND_CACHE (1 << 10) /* Send CACHE (prefetch) */
+enum {
+ NBD_FLAG_HAS_FLAGS_BIT = 0, /* Flags are there */
+ NBD_FLAG_READ_ONLY_BIT = 1, /* Device is read-only */
+ NBD_FLAG_SEND_FLUSH_BIT = 2, /* Send FLUSH */
+ NBD_FLAG_SEND_FUA_BIT = 3, /* Send FUA (Force Unit Access) */
+ NBD_FLAG_ROTATIONAL_BIT = 4, /* Use elevator algorithm -
+ rotational media */
+ NBD_FLAG_SEND_TRIM_BIT = 5, /* Send TRIM (discard) */
+ NBD_FLAG_SEND_WRITE_ZEROES_BIT = 6, /* Send WRITE_ZEROES */
+ NBD_FLAG_SEND_DF_BIT = 7, /* Send DF (Do not Fragment) */
+ NBD_FLAG_CAN_MULTI_CONN_BIT = 8, /* Multi-client cache consistent */
+ NBD_FLAG_SEND_RESIZE_BIT = 9, /* Send resize */
+ NBD_FLAG_SEND_CACHE_BIT = 10, /* Send CACHE (prefetch) */
+};
+
+#define NBD_FLAG_HAS_FLAGS (1 << NBD_FLAG_HAS_FLAGS_BIT)
+#define NBD_FLAG_READ_ONLY (1 << NBD_FLAG_READ_ONLY_BIT)
+#define NBD_FLAG_SEND_FLUSH (1 << NBD_FLAG_SEND_FLUSH_BIT)
+#define NBD_FLAG_SEND_FUA (1 << NBD_FLAG_SEND_FUA_BIT)
+#define NBD_FLAG_ROTATIONAL (1 << NBD_FLAG_ROTATIONAL_BIT)
+#define NBD_FLAG_SEND_TRIM (1 << NBD_FLAG_SEND_TRIM_BIT)
+#define NBD_FLAG_SEND_WRITE_ZEROES (1 << NBD_FLAG_SEND_WRITE_ZEROES_BIT)
+#define NBD_FLAG_SEND_DF (1 << NBD_FLAG_SEND_DF_BIT)
+#define NBD_FLAG_CAN_MULTI_CONN (1 << NBD_FLAG_CAN_MULTI_CONN_BIT)
+#define NBD_FLAG_SEND_RESIZE (1 << NBD_FLAG_SEND_RESIZE_BIT)
+#define NBD_FLAG_SEND_CACHE (1 << NBD_FLAG_SEND_CACHE_BIT)
/* New-style handshake (global) flags, sent from server to client, and
control what will happen during handshake phase. */
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index 848a4b94ab..f7dbe75fbc 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -7,9 +7,6 @@
#include "exec/hwaddr.h"
#endif
-#include "qemu/bswap.h"
-#include "qemu/queue.h"
-
/* The CPU list lock nests outside page_(un)lock or mmap_(un)lock */
void qemu_init_cpu_list(void);
void cpu_list_lock(void);
diff --git a/include/exec/poison.h b/include/exec/poison.h
index 1a7a57baae..b862320fa6 100644
--- a/include/exec/poison.h
+++ b/include/exec/poison.h
@@ -44,6 +44,7 @@
#pragma GCC poison TARGET_LONG_BITS
#pragma GCC poison TARGET_FMT_lx
#pragma GCC poison TARGET_FMT_ld
+#pragma GCC poison TARGET_FMT_lu
#pragma GCC poison TARGET_PAGE_SIZE
#pragma GCC poison TARGET_PAGE_MASK
diff --git a/include/hw/arm/aspeed.h b/include/hw/arm/aspeed.h
index 325c091d09..02073a6b4d 100644
--- a/include/hw/arm/aspeed.h
+++ b/include/hw/arm/aspeed.h
@@ -22,6 +22,7 @@ typedef struct AspeedBoardConfig {
const char *spi_model;
uint32_t num_cs;
void (*i2c_init)(AspeedBoardState *bmc);
+ uint32_t ram;
} AspeedBoardConfig;
#define TYPE_ASPEED_MACHINE MACHINE_TYPE_NAME("aspeed")
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 507517c603..424070924e 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -35,6 +35,7 @@
#include "qemu/notify.h"
#include "hw/boards.h"
#include "hw/arm/arm.h"
+#include "hw/block/flash.h"
#include "sysemu/kvm.h"
#include "hw/intc/arm_gicv3_common.h"
@@ -113,6 +114,7 @@ typedef struct {
Notifier machine_done;
DeviceState *platform_bus_dev;
FWCfgState *fw_cfg;
+ PFlashCFI01 *flash[2];
bool secure;
bool highmem;
bool highmem_ecam;
diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h
index a0f488732a..1acaf7de80 100644
--- a/include/hw/block/flash.h
+++ b/include/hw/block/flash.h
@@ -24,6 +24,7 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base,
int be);
BlockBackend *pflash_cfi01_get_blk(PFlashCFI01 *fl);
MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl);
+void pflash_cfi01_legacy_drive(PFlashCFI01 *dev, DriveInfo *dinfo);
/* pflash_cfi02.c */
diff --git a/include/hw/i2c/i2c-ddc.h b/include/hw/display/i2c-ddc.h
index c29443c5af..c29443c5af 100644
--- a/include/hw/i2c/i2c-ddc.h
+++ b/include/hw/display/i2c-ddc.h
diff --git a/include/hw/display/xlnx_dp.h b/include/hw/display/xlnx_dp.h
index 26b759cd44..45a805033a 100644
--- a/include/hw/display/xlnx_dp.h
+++ b/include/hw/display/xlnx_dp.h
@@ -27,7 +27,7 @@
#include "hw/misc/auxbus.h"
#include "hw/i2c/i2c.h"
#include "hw/display/dpcd.h"
-#include "hw/i2c/i2c-ddc.h"
+#include "hw/display/i2c-ddc.h"
#include "qemu/fifo8.h"
#include "qemu/units.h"
#include "hw/dma/xlnx_dpdma.h"
diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h
index 296b2fd572..09fc44cca4 100644
--- a/include/qemu/compiler.h
+++ b/include/qemu/compiler.h
@@ -28,7 +28,7 @@
#define QEMU_SENTINEL __attribute__((sentinel))
-#if defined(_WIN32)
+#if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__))
# define QEMU_PACKED __attribute__((gcc_struct, packed))
#else
# define QEMU_PACKED __attribute__((packed))
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 303d315c5d..af2b91f0b8 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -85,17 +85,17 @@ extern int daemon(int, int);
#endif
#endif
+/* enable C99/POSIX format strings (needs mingw32-runtime 3.15 or later) */
+#ifdef __MINGW32__
+#define __USE_MINGW_ANSI_STDIO 1
+#endif
+
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <stdlib.h>
-
-/* enable C99/POSIX format strings (needs mingw32-runtime 3.15 or later) */
-#ifdef __MINGW32__
-#define __USE_MINGW_ANSI_STDIO 1
-#endif
#include <stdio.h>
#include <string.h>
diff --git a/job.c b/job.c
index da8e4b7bf2..2167d53717 100644
--- a/job.c
+++ b/job.c
@@ -432,7 +432,7 @@ void job_enter_cond(Job *job, bool(*fn)(Job *job))
timer_del(&job->sleep_timer);
job->busy = true;
job_unlock();
- aio_co_wake(job->co);
+ aio_co_enter(job->aio_context, job->co);
}
void job_enter(Job *job)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index c1a26021f8..ef42e02d82 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -2366,11 +2366,19 @@ static void load_elf_image(const char *image_name, int image_fd,
vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
vaddr_len = TARGET_ELF_PAGELENGTH(eppnt->p_filesz + vaddr_po);
- error = target_mmap(vaddr_ps, vaddr_len,
- elf_prot, MAP_PRIVATE | MAP_FIXED,
- image_fd, eppnt->p_offset - vaddr_po);
- if (error == -1) {
- goto exit_perror;
+ /*
+ * Some segments may be completely empty without any backing file
+ * segment, in that case just let zero_bss allocate an empty buffer
+ * for it.
+ */
+ if (eppnt->p_filesz != 0) {
+ error = target_mmap(vaddr_ps, vaddr_len, elf_prot,
+ MAP_PRIVATE | MAP_FIXED,
+ image_fd, eppnt->p_offset - vaddr_po);
+
+ if (error == -1) {
+ goto exit_perror;
+ }
}
vaddr_ef = vaddr + eppnt->p_filesz;
@@ -2872,7 +2880,7 @@ struct target_elf_prpsinfo {
target_gid_t pr_gid;
target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
/* Lots missing */
- char pr_fname[16]; /* filename of executable */
+ char pr_fname[16] QEMU_NONSTRING; /* filename of executable */
char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
};
diff --git a/linux-user/exit.c b/linux-user/exit.c
index 14e94e28fa..bdda720553 100644
--- a/linux-user/exit.c
+++ b/linux-user/exit.c
@@ -18,6 +18,9 @@
*/
#include "qemu/osdep.h"
#include "qemu.h"
+#ifdef TARGET_GPROF
+#include <sys/gmon.h>
+#endif
#ifdef CONFIG_GCOV
extern void __gcov_dump(void);
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index ae8951625f..37501f575c 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -178,7 +178,7 @@
#endif /* CONFIG_USBFS */
IOCTL(SIOCATMARK, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT))
+ IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_int_ifreq)))
IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
IOCTL(SIOCSIFFLAGS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
IOCTL(SIOCGIFADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
diff --git a/linux-user/openrisc/target_cpu.h b/linux-user/openrisc/target_cpu.h
index d1ea4506e2..32ff135089 100644
--- a/linux-user/openrisc/target_cpu.h
+++ b/linux-user/openrisc/target_cpu.h
@@ -6,7 +6,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/linux-user/openrisc/target_structs.h b/linux-user/openrisc/target_structs.h
index afbb7ad108..e98e2bc799 100644
--- a/linux-user/openrisc/target_structs.h
+++ b/linux-user/openrisc/target_structs.h
@@ -6,7 +6,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/linux-user/sh4/target_cpu.h b/linux-user/sh4/target_cpu.h
index 1a647ddb98..b0be9a2c1b 100644
--- a/linux-user/sh4/target_cpu.h
+++ b/linux-user/sh4/target_cpu.h
@@ -6,7 +6,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/linux-user/sh4/target_structs.h b/linux-user/sh4/target_structs.h
index 3e832bf69a..00ac39478b 100644
--- a/linux-user/sh4/target_structs.h
+++ b/linux-user/sh4/target_structs.h
@@ -6,7 +6,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/linux-user/signal.c b/linux-user/signal.c
index e2c0b37173..44b2d3b35a 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -508,6 +508,11 @@ void signal_init(void)
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = host_signal_handler;
for(i = 1; i <= TARGET_NSIG; i++) {
+#ifdef TARGET_GPROF
+ if (i == SIGPROF) {
+ continue;
+ }
+#endif
host_sig = target_to_host_signal(i);
sigaction(host_sig, NULL, &oact);
if (oact.sa_sigaction == (void *)SIG_IGN) {
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 96cd4bf86d..f5ff6f5dc8 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -59,9 +59,6 @@
#ifdef CONFIG_TIMERFD
#include <sys/timerfd.h>
#endif
-#ifdef TARGET_GPROF
-#include <sys/gmon.h>
-#endif
#ifdef CONFIG_EVENTFD
#include <sys/eventfd.h>
#endif
@@ -1864,6 +1861,28 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
case IPV6_RECVHOPLIMIT:
case IPV6_2292HOPLIMIT:
case IPV6_CHECKSUM:
+ case IPV6_ADDRFORM:
+ case IPV6_2292PKTINFO:
+ case IPV6_RECVTCLASS:
+ case IPV6_RECVRTHDR:
+ case IPV6_2292RTHDR:
+ case IPV6_RECVHOPOPTS:
+ case IPV6_2292HOPOPTS:
+ case IPV6_RECVDSTOPTS:
+ case IPV6_2292DSTOPTS:
+ case IPV6_TCLASS:
+#ifdef IPV6_RECVPATHMTU
+ case IPV6_RECVPATHMTU:
+#endif
+#ifdef IPV6_TRANSPARENT
+ case IPV6_TRANSPARENT:
+#endif
+#ifdef IPV6_FREEBIND
+ case IPV6_FREEBIND:
+#endif
+#ifdef IPV6_RECVORIGDSTADDR
+ case IPV6_RECVORIGDSTADDR:
+#endif
val = 0;
if (optlen < sizeof(uint32_t)) {
return -TARGET_EINVAL;
@@ -2358,6 +2377,28 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
case IPV6_RECVHOPLIMIT:
case IPV6_2292HOPLIMIT:
case IPV6_CHECKSUM:
+ case IPV6_ADDRFORM:
+ case IPV6_2292PKTINFO:
+ case IPV6_RECVTCLASS:
+ case IPV6_RECVRTHDR:
+ case IPV6_2292RTHDR:
+ case IPV6_RECVHOPOPTS:
+ case IPV6_2292HOPOPTS:
+ case IPV6_RECVDSTOPTS:
+ case IPV6_2292DSTOPTS:
+ case IPV6_TCLASS:
+#ifdef IPV6_RECVPATHMTU
+ case IPV6_RECVPATHMTU:
+#endif
+#ifdef IPV6_TRANSPARENT
+ case IPV6_TRANSPARENT:
+#endif
+#ifdef IPV6_FREEBIND
+ case IPV6_FREEBIND:
+#endif
+#ifdef IPV6_RECVORIGDSTADDR
+ case IPV6_RECVORIGDSTADDR:
+#endif
if (get_user_u32(len, optlen))
return -TARGET_EFAULT;
if (len < 0)
diff --git a/linux-user/uname.c b/linux-user/uname.c
index 313b79dbad..1c05f95387 100644
--- a/linux-user/uname.c
+++ b/linux-user/uname.c
@@ -72,9 +72,8 @@ const char *cpu_to_uname_machine(void *cpu_env)
#define COPY_UTSNAME_FIELD(dest, src) \
do { \
- /* __NEW_UTS_LEN doesn't include terminating null */ \
- (void) strncpy((dest), (src), __NEW_UTS_LEN); \
- (dest)[__NEW_UTS_LEN] = '\0'; \
+ memcpy((dest), (src), MIN(sizeof(src), sizeof(dest))); \
+ (dest)[sizeof(dest) - 1] = '\0'; \
} while (0)
int sys_uname(struct new_utsname *buf)
diff --git a/net/net.c b/net/net.c
index f3a3c5444c..2cf5e76469 100644
--- a/net/net.c
+++ b/net/net.c
@@ -837,9 +837,10 @@ int qemu_show_nic_models(const char *arg, const char *const *models)
return 0;
}
- fprintf(stderr, "qemu: Supported NIC models: ");
- for (i = 0 ; models[i]; i++)
- fprintf(stderr, "%s%c", models[i], models[i+1] ? ',' : '\n');
+ printf("Supported NIC models:\n");
+ for (i = 0 ; models[i]; i++) {
+ printf("%s\n", models[i]);
+ }
return 1;
}
diff --git a/qemu-doc.texi b/qemu-doc.texi
index ae3c3f9632..577d1e8376 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -38,6 +38,7 @@
* QEMU Guest Agent::
* QEMU User space emulator::
* System requirements::
+* Security::
* Implementation notes::
* Deprecated features::
* Supported build platforms::
@@ -2878,6 +2879,8 @@ added with Linux 4.5 which is supported by the major distros. And even
if RHEL7 has kernel 3.10, KVM there has the required functionality there
to make it close to a 4.5 or newer kernel.
+@include docs/security.texi
+
@include qemu-tech.texi
@include qemu-deprecated.texi
diff --git a/qemu-ga.texi b/qemu-ga.texi
index 4c7a8fd163..f00ad830f2 100644
--- a/qemu-ga.texi
+++ b/qemu-ga.texi
@@ -30,7 +30,7 @@ set user's password
@end itemize
qemu-ga will read a system configuration file on startup (located at
-@file{/etc/qemu/qemu-ga.conf} by default), then parse remaining
+@file{@value{CONFDIR}/qemu-ga.conf} by default), then parse remaining
configuration options on the command line. For the same key, the last
option wins, but the lists accumulate (see below for configuration
file format).
@@ -58,7 +58,7 @@ file format).
Enable fsfreeze hook. Accepts an optional argument that specifies
script to run on freeze/thaw. Script will be called with
'freeze'/'thaw' arguments accordingly (default is
- @samp{/etc/qemu/fsfreeze-hook}). If using -F with an argument, do
+ @samp{@value{CONFDIR}/fsfreeze-hook}). If using -F with an argument, do
not follow -F with a space (for example:
@samp{-F/var/run/fsfreezehook.sh}).
diff --git a/qemu-img.c b/qemu-img.c
index e6ad5978e0..28fba1e7a7 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -37,6 +37,7 @@
#include "qemu/option.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
+#include "qemu/units.h"
#include "qom/object_interfaces.h"
#include "sysemu/sysemu.h"
#include "sysemu/block-backend.h"
@@ -1216,7 +1217,7 @@ static int compare_buffers(const uint8_t *buf1, const uint8_t *buf2,
return res;
}
-#define IO_BUF_SIZE (2 * 1024 * 1024)
+#define IO_BUF_SIZE (2 * MiB)
/*
* Check if passed sectors are empty (not allocated or contain only 0 bytes)
@@ -2960,7 +2961,7 @@ static int img_map(int argc, char **argv)
int64_t n;
/* Probe up to 1 GiB at a time. */
- n = MIN(1 << 30, length - offset);
+ n = MIN(1 * GiB, length - offset);
ret = get_block_status(bs, offset, n, &next);
if (ret < 0) {
@@ -3311,26 +3312,30 @@ static int img_rebase(int argc, char **argv)
char backing_name[PATH_MAX];
QDict *options = NULL;
- if (bs->backing_format[0] != '\0') {
- options = qdict_new();
- qdict_put_str(options, "driver", bs->backing_format);
- }
-
- if (force_share) {
- if (!options) {
+ if (bs->backing) {
+ if (bs->backing_format[0] != '\0') {
options = qdict_new();
+ qdict_put_str(options, "driver", bs->backing_format);
}
- qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
- }
- bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
- blk_old_backing = blk_new_open(backing_name, NULL,
- options, src_flags, &local_err);
- if (!blk_old_backing) {
- error_reportf_err(local_err,
- "Could not open old backing file '%s': ",
- backing_name);
- ret = -1;
- goto out;
+
+ if (force_share) {
+ if (!options) {
+ options = qdict_new();
+ }
+ qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
+ }
+ bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
+ blk_old_backing = blk_new_open(backing_name, NULL,
+ options, src_flags, &local_err);
+ if (!blk_old_backing) {
+ error_reportf_err(local_err,
+ "Could not open old backing file '%s': ",
+ backing_name);
+ ret = -1;
+ goto out;
+ }
+ } else {
+ blk_old_backing = NULL;
}
if (out_baseimg[0]) {
@@ -3383,7 +3388,7 @@ static int img_rebase(int argc, char **argv)
*/
if (!unsafe) {
int64_t size;
- int64_t old_backing_size;
+ int64_t old_backing_size = 0;
int64_t new_backing_size = 0;
uint64_t offset;
int64_t n;
@@ -3399,15 +3404,18 @@ static int img_rebase(int argc, char **argv)
ret = -1;
goto out;
}
- old_backing_size = blk_getlength(blk_old_backing);
- if (old_backing_size < 0) {
- char backing_name[PATH_MAX];
+ if (blk_old_backing) {
+ old_backing_size = blk_getlength(blk_old_backing);
+ if (old_backing_size < 0) {
+ char backing_name[PATH_MAX];
- bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
- error_report("Could not get size of '%s': %s",
- backing_name, strerror(-old_backing_size));
- ret = -1;
- goto out;
+ bdrv_get_backing_filename(bs, backing_name,
+ sizeof(backing_name));
+ error_report("Could not get size of '%s': %s",
+ backing_name, strerror(-old_backing_size));
+ ret = -1;
+ goto out;
+ }
}
if (blk_new_backing) {
new_backing_size = blk_getlength(blk_new_backing);
@@ -3424,6 +3432,8 @@ static int img_rebase(int argc, char **argv)
}
for (offset = 0; offset < size; offset += n) {
+ bool buf_old_is_zero = false;
+
/* How many bytes can we handle with the next read? */
n = MIN(IO_BUF_SIZE, size - offset);
@@ -3444,6 +3454,7 @@ static int img_rebase(int argc, char **argv)
*/
if (offset >= old_backing_size) {
memset(buf_old, 0, n);
+ buf_old_is_zero = true;
} else {
if (offset + n > old_backing_size) {
n = old_backing_size - offset;
@@ -3479,8 +3490,12 @@ static int img_rebase(int argc, char **argv)
if (compare_buffers(buf_old + written, buf_new + written,
n - written, &pnum))
{
- ret = blk_pwrite(blk, offset + written,
- buf_old + written, pnum, 0);
+ if (buf_old_is_zero) {
+ ret = blk_pwrite_zeroes(blk, offset + written, pnum, 0);
+ } else {
+ ret = blk_pwrite(blk, offset + written,
+ buf_old + written, pnum, 0);
+ }
if (ret < 0) {
error_report("Error while writing to COW image: %s",
strerror(-ret));
diff --git a/qemu-nbd.c b/qemu-nbd.c
index dca9e72cee..081fcf74d5 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -279,37 +279,25 @@ static int qemu_nbd_client_list(SocketAddress *saddr, QCryptoTLSCreds *tls,
printf(" description: %s\n", list[i].description);
}
if (list[i].flags & NBD_FLAG_HAS_FLAGS) {
+ static const char *const flag_names[] = {
+ [NBD_FLAG_READ_ONLY_BIT] = "readonly",
+ [NBD_FLAG_SEND_FLUSH_BIT] = "flush",
+ [NBD_FLAG_SEND_FUA_BIT] = "fua",
+ [NBD_FLAG_ROTATIONAL_BIT] = "rotational",
+ [NBD_FLAG_SEND_TRIM_BIT] = "trim",
+ [NBD_FLAG_SEND_WRITE_ZEROES_BIT] = "zeroes",
+ [NBD_FLAG_SEND_DF_BIT] = "df",
+ [NBD_FLAG_CAN_MULTI_CONN_BIT] = "multi",
+ [NBD_FLAG_SEND_RESIZE_BIT] = "resize",
+ [NBD_FLAG_SEND_CACHE_BIT] = "cache",
+ };
+
printf(" size: %" PRIu64 "\n", list[i].size);
printf(" flags: 0x%x (", list[i].flags);
- if (list[i].flags & NBD_FLAG_READ_ONLY) {
- printf(" readonly");
- }
- if (list[i].flags & NBD_FLAG_SEND_FLUSH) {
- printf(" flush");
- }
- if (list[i].flags & NBD_FLAG_SEND_FUA) {
- printf(" fua");
- }
- if (list[i].flags & NBD_FLAG_ROTATIONAL) {
- printf(" rotational");
- }
- if (list[i].flags & NBD_FLAG_SEND_TRIM) {
- printf(" trim");
- }
- if (list[i].flags & NBD_FLAG_SEND_WRITE_ZEROES) {
- printf(" zeroes");
- }
- if (list[i].flags & NBD_FLAG_SEND_DF) {
- printf(" df");
- }
- if (list[i].flags & NBD_FLAG_CAN_MULTI_CONN) {
- printf(" multi");
- }
- if (list[i].flags & NBD_FLAG_SEND_RESIZE) {
- printf(" resize");
- }
- if (list[i].flags & NBD_FLAG_SEND_CACHE) {
- printf(" cache");
+ for (size_t bit = 0; bit < ARRAY_SIZE(flag_names); bit++) {
+ if (flag_names[bit] && (list[i].flags & (1 << bit))) {
+ printf(" %s", flag_names[bit]);
+ }
}
printf(" )\n");
}
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index d40d61f605..6b67f16faf 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -457,7 +457,7 @@ void qmp_guest_file_flush(int64_t handle, Error **errp)
#ifdef CONFIG_QGA_NTDDSCSI
-static STORAGE_BUS_TYPE win2qemu[] = {
+static GuestDiskBusType win2qemu[] = {
[BusTypeUnknown] = GUEST_DISK_BUS_TYPE_UNKNOWN,
[BusTypeScsi] = GUEST_DISK_BUS_TYPE_SCSI,
[BusTypeAtapi] = GUEST_DISK_BUS_TYPE_IDE,
diff --git a/qom/object.c b/qom/object.c
index e3206d6799..d3412e7fdc 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -679,7 +679,7 @@ Object *object_new_with_propv(const char *typename,
error_setg(errp, "object type '%s' is abstract", typename);
return NULL;
}
- obj = object_new(typename);
+ obj = object_new_with_type(klass->type);
if (object_set_propv(obj, &local_err, vargs) < 0) {
goto error;
diff --git a/scripts/cocci-macro-file.h b/scripts/cocci-macro-file.h
index e485cdccae..c6bbc05ba3 100644
--- a/scripts/cocci-macro-file.h
+++ b/scripts/cocci-macro-file.h
@@ -23,7 +23,12 @@
#define QEMU_NORETURN __attribute__ ((__noreturn__))
#define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#define QEMU_SENTINEL __attribute__((sentinel))
-#define QEMU_PACKED __attribute__((gcc_struct, packed))
+
+#if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__))
+# define QEMU_PACKED __attribute__((gcc_struct, packed))
+#else
+# define QEMU_PACKED __attribute__((packed))
+#endif
#define cat(x,y) x ## y
#define cat2(x,y) cat(x,y)
diff --git a/scripts/decodetree.py b/scripts/decodetree.py
index aa790b596a..81874e22cc 100755
--- a/scripts/decodetree.py
+++ b/scripts/decodetree.py
@@ -27,6 +27,7 @@ import getopt
insnwidth = 32
insnmask = 0xffffffff
+variablewidth = False
fields = {}
arguments = {}
formats = {}
@@ -255,7 +256,7 @@ class FunctionField:
return self.func + '(' + str(self.base) + ')'
def str_extract(self):
- return self.func + '(' + self.base.str_extract() + ')'
+ return self.func + '(ctx, ' + self.base.str_extract() + ')'
def __eq__(self, other):
return self.func == other.func and self.base == other.base
@@ -289,7 +290,7 @@ class Arguments:
class General:
"""Common code between instruction formats and instruction patterns"""
- def __init__(self, name, lineno, base, fixb, fixm, udfm, fldm, flds):
+ def __init__(self, name, lineno, base, fixb, fixm, udfm, fldm, flds, w):
self.name = name
self.file = input_file
self.lineno = lineno
@@ -299,6 +300,7 @@ class General:
self.undefmask = udfm
self.fieldmask = fldm
self.fields = flds
+ self.width = w
def __str__(self):
return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
@@ -316,7 +318,7 @@ class Format(General):
return decode_function + '_extract_' + self.name
def output_extract(self):
- output('static void ', self.extract_name(), '(',
+ output('static void ', self.extract_name(), '(DisasContext *ctx, ',
self.base.struct_name(), ' *a, ', insntype, ' insn)\n{\n')
for n, f in self.fields.items():
output(' a->', n, ' = ', f.str_extract(), ';\n')
@@ -341,7 +343,8 @@ class Pattern(General):
arg = self.base.base.name
output(ind, '/* ', self.file, ':', str(self.lineno), ' */\n')
if not extracted:
- output(ind, self.base.extract_name(), '(&u.f_', arg, ', insn);\n')
+ output(ind, self.base.extract_name(),
+ '(ctx, &u.f_', arg, ', insn);\n')
for n, f in self.fields.items():
output(ind, 'u.f_', arg, '.', n, ' = ', f.str_extract(), ';\n')
output(ind, 'if (', translate_prefix, '_', self.name,
@@ -352,7 +355,7 @@ class Pattern(General):
class MultiPattern(General):
"""Class representing an overlapping set of instruction patterns"""
- def __init__(self, lineno, pats, fixb, fixm, udfm):
+ def __init__(self, lineno, pats, fixb, fixm, udfm, w):
self.file = input_file
self.lineno = lineno
self.pats = pats
@@ -360,6 +363,7 @@ class MultiPattern(General):
self.fixedbits = fixb
self.fixedmask = fixm
self.undefmask = udfm
+ self.width = w
def __str__(self):
r = "{"
@@ -502,7 +506,7 @@ def infer_argument_set(flds):
return arg
-def infer_format(arg, fieldmask, flds):
+def infer_format(arg, fieldmask, flds, width):
global arguments
global formats
global decode_function
@@ -521,6 +525,8 @@ def infer_format(arg, fieldmask, flds):
continue
if fieldmask != fmt.fieldmask:
continue
+ if width != fmt.width:
+ continue
if not eq_fields_for_fmts(flds, fmt.fields):
continue
return (fmt, const_flds)
@@ -529,7 +535,7 @@ def infer_format(arg, fieldmask, flds):
if not arg:
arg = infer_argument_set(flds)
- fmt = Format(name, 0, arg, 0, 0, 0, fieldmask, var_flds)
+ fmt = Format(name, 0, arg, 0, 0, 0, fieldmask, var_flds, width)
formats[name] = fmt
return (fmt, const_flds)
@@ -546,6 +552,7 @@ def parse_generic(lineno, is_format, name, toks):
global re_ident
global insnwidth
global insnmask
+ global variablewidth
fixedmask = 0
fixedbits = 0
@@ -633,8 +640,15 @@ def parse_generic(lineno, is_format, name, toks):
error(lineno, 'invalid token "{0}"'.format(t))
width += shift
+ if variablewidth and width < insnwidth and width % 8 == 0:
+ shift = insnwidth - width
+ fixedbits <<= shift
+ fixedmask <<= shift
+ undefmask <<= shift
+ undefmask |= (1 << shift) - 1
+
# We should have filled in all of the bits of the instruction.
- if not (is_format and width == 0) and width != insnwidth:
+ elif not (is_format and width == 0) and width != insnwidth:
error(lineno, 'definition has {0} bits'.format(width))
# Do not check for fields overlaping fields; one valid usage
@@ -660,7 +674,7 @@ def parse_generic(lineno, is_format, name, toks):
if name in formats:
error(lineno, 'duplicate format name', name)
fmt = Format(name, lineno, arg, fixedbits, fixedmask,
- undefmask, fieldmask, flds)
+ undefmask, fieldmask, flds, width)
formats[name] = fmt
else:
# Patterns can reference a format ...
@@ -670,12 +684,14 @@ def parse_generic(lineno, is_format, name, toks):
error(lineno, 'pattern specifies both format and argument set')
if fixedmask & fmt.fixedmask:
error(lineno, 'pattern fixed bits overlap format fixed bits')
+ if width != fmt.width:
+ error(lineno, 'pattern uses format of different width')
fieldmask |= fmt.fieldmask
fixedbits |= fmt.fixedbits
fixedmask |= fmt.fixedmask
undefmask |= fmt.undefmask
else:
- (fmt, flds) = infer_format(arg, fieldmask, flds)
+ (fmt, flds) = infer_format(arg, fieldmask, flds, width)
arg = fmt.base
for f in flds.keys():
if f not in arg.fields:
@@ -687,7 +703,7 @@ def parse_generic(lineno, is_format, name, toks):
if f not in flds.keys() and f not in fmt.fields.keys():
error(lineno, 'field {0} not initialized'.format(f))
pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
- undefmask, fieldmask, flds)
+ undefmask, fieldmask, flds, width)
patterns.append(pat)
allpatterns.append(pat)
@@ -727,6 +743,13 @@ def build_multi_pattern(lineno, pats):
if p.lineno < lineno:
lineno = p.lineno
+ width = None
+ for p in pats:
+ if width is None:
+ width = p.width
+ elif width != p.width:
+ error(lineno, 'width mismatch in patterns within braces')
+
repeat = True
while repeat:
if fixedmask == 0:
@@ -742,7 +765,7 @@ def build_multi_pattern(lineno, pats):
else:
repeat = False
- mp = MultiPattern(lineno, pats, fixedbits, fixedmask, undefmask)
+ mp = MultiPattern(lineno, pats, fixedbits, fixedmask, undefmask, width)
patterns.append(mp)
# end build_multi_pattern
@@ -872,7 +895,7 @@ class Tree:
# extract the fields now.
if not extracted and self.base:
output(ind, self.base.extract_name(),
- '(&u.f_', self.base.base.name, ', insn);\n')
+ '(ctx, &u.f_', self.base.base.name, ', insn);\n')
extracted = True
# Attempt to aid the compiler in producing compact switch statements.
@@ -943,6 +966,147 @@ def build_tree(pats, outerbits, outermask):
# end build_tree
+class SizeTree:
+ """Class representing a node in a size decode tree"""
+
+ def __init__(self, m, w):
+ self.mask = m
+ self.subs = []
+ self.base = None
+ self.width = w
+
+ def str1(self, i):
+ ind = str_indent(i)
+ r = '{0}{1:08x}'.format(ind, self.mask)
+ r += ' [\n'
+ for (b, s) in self.subs:
+ r += '{0} {1:08x}:\n'.format(ind, b)
+ r += s.str1(i + 4) + '\n'
+ r += ind + ']'
+ return r
+
+ def __str__(self):
+ return self.str1(0)
+
+ def output_code(self, i, extracted, outerbits, outermask):
+ ind = str_indent(i)
+
+ # If we need to load more bytes to test, do so now.
+ if extracted < self.width:
+ output(ind, 'insn = ', decode_function,
+ '_load_bytes(ctx, insn, {0}, {1});\n'
+ .format(extracted / 8, self.width / 8));
+ extracted = self.width
+
+ # Attempt to aid the compiler in producing compact switch statements.
+ # If the bits in the mask are contiguous, extract them.
+ sh = is_contiguous(self.mask)
+ if sh > 0:
+ # Propagate SH down into the local functions.
+ def str_switch(b, sh=sh):
+ return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh)
+
+ def str_case(b, sh=sh):
+ return '0x{0:x}'.format(b >> sh)
+ else:
+ def str_switch(b):
+ return 'insn & 0x{0:08x}'.format(b)
+
+ def str_case(b):
+ return '0x{0:08x}'.format(b)
+
+ output(ind, 'switch (', str_switch(self.mask), ') {\n')
+ for b, s in sorted(self.subs):
+ innermask = outermask | self.mask
+ innerbits = outerbits | b
+ output(ind, 'case ', str_case(b), ':\n')
+ output(ind, ' /* ',
+ str_match_bits(innerbits, innermask), ' */\n')
+ s.output_code(i + 4, extracted, innerbits, innermask)
+ output(ind, '}\n')
+ output(ind, 'return insn;\n')
+# end SizeTree
+
+class SizeLeaf:
+ """Class representing a leaf node in a size decode tree"""
+
+ def __init__(self, m, w):
+ self.mask = m
+ self.width = w
+
+ def str1(self, i):
+ ind = str_indent(i)
+ return '{0}{1:08x}'.format(ind, self.mask)
+
+ def __str__(self):
+ return self.str1(0)
+
+ def output_code(self, i, extracted, outerbits, outermask):
+ global decode_function
+ ind = str_indent(i)
+
+ # If we need to load more bytes, do so now.
+ if extracted < self.width:
+ output(ind, 'insn = ', decode_function,
+ '_load_bytes(ctx, insn, {0}, {1});\n'
+ .format(extracted / 8, self.width / 8));
+ extracted = self.width
+ output(ind, 'return insn;\n')
+# end SizeLeaf
+
+
+def build_size_tree(pats, width, outerbits, outermask):
+ global insnwidth
+
+ # Collect the mask of bits that are fixed in this width
+ innermask = 0xff << (insnwidth - width)
+ innermask &= ~outermask
+ minwidth = None
+ onewidth = True
+ for i in pats:
+ innermask &= i.fixedmask
+ if minwidth is None:
+ minwidth = i.width
+ elif minwidth != i.width:
+ onewidth = False;
+ if minwidth < i.width:
+ minwidth = i.width
+
+ if onewidth:
+ return SizeLeaf(innermask, minwidth)
+
+ if innermask == 0:
+ if width < minwidth:
+ return build_size_tree(pats, width + 8, outerbits, outermask)
+
+ pnames = []
+ for p in pats:
+ pnames.append(p.name + ':' + p.file + ':' + str(p.lineno))
+ error_with_file(pats[0].file, pats[0].lineno,
+ 'overlapping patterns size {0}:'.format(width), pnames)
+
+ bins = {}
+ for i in pats:
+ fb = i.fixedbits & innermask
+ if fb in bins:
+ bins[fb].append(i)
+ else:
+ bins[fb] = [i]
+
+ fullmask = outermask | innermask
+ lens = sorted(bins.keys())
+ if len(lens) == 1:
+ b = lens[0]
+ return build_size_tree(bins[b], width + 8, b | outerbits, fullmask)
+
+ r = SizeTree(innermask, width)
+ for b, l in bins.items():
+ s = build_size_tree(l, width, b | outerbits, fullmask)
+ r.subs.append((b, s))
+ return r
+# end build_size_tree
+
+
def prop_format(tree):
"""Propagate Format objects into the decode tree"""
@@ -965,6 +1129,23 @@ def prop_format(tree):
# end prop_format
+def prop_size(tree):
+ """Propagate minimum widths up the decode size tree"""
+
+ if isinstance(tree, SizeTree):
+ min = None
+ for (b, s) in tree.subs:
+ width = prop_size(s)
+ if min is None or min > width:
+ min = width
+ assert min >= tree.width
+ tree.width = min
+ else:
+ min = tree.width
+ return min
+# end prop_size
+
+
def main():
global arguments
global formats
@@ -979,13 +1160,14 @@ def main():
global insntype
global insnmask
global decode_function
+ global variablewidth
decode_scope = 'static '
long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=',
- 'static-decode=']
+ 'static-decode=', 'varinsnwidth=']
try:
- (opts, args) = getopt.getopt(sys.argv[1:], 'o:w:', long_opts)
+ (opts, args) = getopt.getopt(sys.argv[1:], 'o:vw:', long_opts)
except getopt.GetoptError as err:
error(0, err)
for o, a in opts:
@@ -999,7 +1181,9 @@ def main():
elif o == '--translate':
translate_prefix = a
translate_scope = ''
- elif o in ('-w', '--insnwidth'):
+ elif o in ('-w', '--insnwidth', '--varinsnwidth'):
+ if o == '--varinsnwidth':
+ variablewidth = True
insnwidth = int(a)
if insnwidth == 16:
insntype = 'uint16_t'
@@ -1017,8 +1201,12 @@ def main():
parse_file(f)
f.close()
- t = build_tree(patterns, 0, 0)
- prop_format(t)
+ if variablewidth:
+ stree = build_size_tree(patterns, 8, 0, 0)
+ prop_size(stree)
+
+ dtree = build_tree(patterns, 0, 0)
+ prop_format(dtree)
if output_file:
output_fd = open(output_file, 'w')
@@ -1059,11 +1247,18 @@ def main():
f = arguments[n]
output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
output(i4, '} u;\n\n')
- t.output_code(4, False, 0, 0)
+ dtree.output_code(4, False, 0, 0)
output(i4, 'return false;\n')
output('}\n')
+ if variablewidth:
+ output('\n', decode_scope, insntype, ' ', decode_function,
+ '_load(DisasContext *ctx)\n{\n',
+ ' ', insntype, ' insn = 0;\n\n')
+ stree.output_code(4, 0, 0, 0)
+ output('}\n')
+
if output_file:
output_fd.close()
# end main
diff --git a/slirp b/slirp
-Subproject 59a1b1f165458c2acb7ff0525b543945f741622
+Subproject f0da6726207b740f6101028b2992f918477a4b0
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 22bc6e00ab..733b840a71 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1285,6 +1285,7 @@ static inline uint32_t xpsr_read(CPUARMState *env)
| (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27)
| (env->thumb << 24) | ((env->condexec_bits & 3) << 25)
| ((env->condexec_bits & 0xfc) << 8)
+ | (env->GE << 16)
| env->v7m.exception;
}
@@ -1300,6 +1301,9 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
if (mask & XPSR_Q) {
env->QF = ((val & XPSR_Q) != 0);
}
+ if (mask & XPSR_GE) {
+ env->GE = (val & XPSR_GE) >> 16;
+ }
if (mask & XPSR_T) {
env->thumb = ((val & XPSR_T) != 0);
}
@@ -2610,18 +2614,25 @@ bool write_list_to_cpustate(ARMCPU *cpu);
/**
* write_cpustate_to_list:
* @cpu: ARMCPU
+ * @kvm_sync: true if this is for syncing back to KVM
*
* For each register listed in the ARMCPU cpreg_indexes list, write
* its value from the ARMCPUState structure into the cpreg_values list.
* This is used to copy info from TCG's working data structures into
* KVM or for outbound migration.
*
+ * @kvm_sync is true if we are doing this in order to sync the
+ * register state back to KVM. In this case we will only update
+ * values in the list if the previous list->cpustate sync actually
+ * successfully wrote the CPU state. Otherwise we will keep the value
+ * that is in the list.
+ *
* Returns: true if all register values were read correctly,
* false if some register was unknown or could not be read.
* Note that we do not stop early on failure -- we will attempt
* reading all registers in the list.
*/
-bool write_cpustate_to_list(ARMCPU *cpu);
+bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
#define ARM_CPUID_TI915T 0x54029152
#define ARM_CPUID_TI925T 0x54029252
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 81a92ab491..1e6eb0d0f3 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -1,4 +1,5 @@
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "target/arm/idau.h"
#include "trace.h"
#include "cpu.h"
@@ -266,7 +267,7 @@ static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
return true;
}
-bool write_cpustate_to_list(ARMCPU *cpu)
+bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync)
{
/* Write the coprocessor state from cpu->env to the (index,value) list. */
int i;
@@ -275,6 +276,7 @@ bool write_cpustate_to_list(ARMCPU *cpu)
for (i = 0; i < cpu->cpreg_array_len; i++) {
uint32_t regidx = kvm_to_cpreg_id(cpu->cpreg_indexes[i]);
const ARMCPRegInfo *ri;
+ uint64_t newval;
ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
if (!ri) {
@@ -284,7 +286,29 @@ bool write_cpustate_to_list(ARMCPU *cpu)
if (ri->type & ARM_CP_NO_RAW) {
continue;
}
- cpu->cpreg_values[i] = read_raw_cp_reg(&cpu->env, ri);
+
+ newval = read_raw_cp_reg(&cpu->env, ri);
+ if (kvm_sync) {
+ /*
+ * Only sync if the previous list->cpustate sync succeeded.
+ * Rather than tracking the success/failure state for every
+ * item in the list, we just recheck "does the raw write we must
+ * have made in write_list_to_cpustate() read back OK" here.
+ */
+ uint64_t oldval = cpu->cpreg_values[i];
+
+ if (oldval == newval) {
+ continue;
+ }
+
+ write_raw_cp_reg(&cpu->env, ri, oldval);
+ if (read_raw_cp_reg(&cpu->env, ri) != oldval) {
+ continue;
+ }
+
+ write_raw_cp_reg(&cpu->env, ri, newval);
+ }
+ cpu->cpreg_values[i] = newval;
}
return ok;
}
@@ -8704,7 +8728,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
{
CPUARMState *env = &cpu->env;
uint32_t excret;
- uint32_t xpsr;
+ uint32_t xpsr, xpsr_mask;
bool ufault = false;
bool sfault = false;
bool return_to_sp_process;
@@ -9156,8 +9180,13 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
}
*frame_sp_p = frameptr;
}
+
+ xpsr_mask = ~(XPSR_SPREALIGN | XPSR_SFPA);
+ if (!arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
+ xpsr_mask &= ~XPSR_GE;
+ }
/* This xpsr_write() will invalidate frame_sp_p as it may switch stack */
- xpsr_write(env, xpsr, ~(XPSR_SPREALIGN | XPSR_SFPA));
+ xpsr_write(env, xpsr, xpsr_mask);
if (env->v7m.secure) {
bool sfpa = xpsr & XPSR_SFPA;
@@ -12642,6 +12671,9 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
}
if (!(reg & 4)) {
mask |= XPSR_NZCV | XPSR_Q; /* APSR */
+ if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
+ mask |= XPSR_GE;
+ }
}
/* EPSR reads as zero */
return xpsr_read(env) & mask;
@@ -13099,14 +13131,17 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
* We know that in fact for any v8 CPU the page size is at least 4K
* and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
* 1K as an artefact of legacy v5 subpage support being present in the
- * same QEMU executable.
+ * same QEMU executable. So in practice the hostaddr[] array has
+ * two entries, given the current setting of TARGET_PAGE_BITS_MIN.
*/
int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
- void *hostaddr[maxidx];
+ void *hostaddr[DIV_ROUND_UP(2 * KiB, 1 << TARGET_PAGE_BITS_MIN)];
int try, i;
unsigned mmu_idx = cpu_mmu_index(env, false);
TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
+ assert(maxidx <= ARRAY_SIZE(hostaddr));
+
for (try = 0; try < 2; try++) {
for (i = 0; i < maxidx; i++) {
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 79a79f0190..5995634612 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -497,6 +497,14 @@ void kvm_arm_reset_vcpu(ARMCPU *cpu)
fprintf(stderr, "write_kvmstate_to_list failed\n");
abort();
}
+ /*
+ * Sync the reset values also into the CPUState. This is necessary
+ * because the next thing we do will be a kvm_arch_put_registers()
+ * which will update the list values from the CPUState before copying
+ * the list values back to KVM. It's OK to ignore failure returns here
+ * for the same reason we do so in kvm_arch_get_registers().
+ */
+ write_list_to_cpustate(cpu);
}
/*
diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c
index 50327989dc..327375f625 100644
--- a/target/arm/kvm32.c
+++ b/target/arm/kvm32.c
@@ -384,24 +384,8 @@ int kvm_arch_put_registers(CPUState *cs, int level)
return ret;
}
- /* Note that we do not call write_cpustate_to_list()
- * here, so we are only writing the tuple list back to
- * KVM. This is safe because nothing can change the
- * CPUARMState cp15 fields (in particular gdb accesses cannot)
- * and so there are no changes to sync. In fact syncing would
- * be wrong at this point: for a constant register where TCG and
- * KVM disagree about its value, the preceding write_list_to_cpustate()
- * would not have had any effect on the CPUARMState value (since the
- * register is read-only), and a write_cpustate_to_list() here would
- * then try to write the TCG value back into KVM -- this would either
- * fail or incorrectly change the value the guest sees.
- *
- * If we ever want to allow the user to modify cp15 registers via
- * the gdb stub, we would need to be more clever here (for instance
- * tracking the set of registers kvm_arch_get_registers() successfully
- * managed to update the CPUARMState with, and only allowing those
- * to be written back up into the kernel).
- */
+ write_cpustate_to_list(cpu, true);
+
if (!write_list_to_kvmstate(cpu, level)) {
return EINVAL;
}
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 089af9c5f0..e3ba149248 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -838,6 +838,8 @@ int kvm_arch_put_registers(CPUState *cs, int level)
return ret;
}
+ write_cpustate_to_list(cpu, true);
+
if (!write_list_to_kvmstate(cpu, level)) {
return EINVAL;
}
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 09567d4fc6..96d032f2a7 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -646,7 +646,7 @@ static int cpu_pre_save(void *opaque)
abort();
}
} else {
- if (!write_cpustate_to_list(cpu)) {
+ if (!write_cpustate_to_list(cpu, false)) {
/* This should never fail. */
abort();
}
diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c
index 245cd82621..80645db508 100644
--- a/target/arm/translate-sve.c
+++ b/target/arm/translate-sve.c
@@ -54,35 +54,35 @@ typedef void gen_helper_gvec_mem_scatter(TCGv_env, TCGv_ptr, TCGv_ptr,
/* See e.g. ASR (immediate, predicated).
* Returns -1 for unallocated encoding; diagnose later.
*/
-static int tszimm_esz(int x)
+static int tszimm_esz(DisasContext *s, int x)
{
x >>= 3; /* discard imm3 */
return 31 - clz32(x);
}
-static int tszimm_shr(int x)
+static int tszimm_shr(DisasContext *s, int x)
{
- return (16 << tszimm_esz(x)) - x;
+ return (16 << tszimm_esz(s, x)) - x;
}
/* See e.g. LSL (immediate, predicated). */
-static int tszimm_shl(int x)
+static int tszimm_shl(DisasContext *s, int x)
{
- return x - (8 << tszimm_esz(x));
+ return x - (8 << tszimm_esz(s, x));
}
-static inline int plus1(int x)
+static inline int plus1(DisasContext *s, int x)
{
return x + 1;
}
/* The SH bit is in bit 8. Extract the low 8 and shift. */
-static inline int expand_imm_sh8s(int x)
+static inline int expand_imm_sh8s(DisasContext *s, int x)
{
return (int8_t)x << (x & 0x100 ? 8 : 0);
}
-static inline int expand_imm_sh8u(int x)
+static inline int expand_imm_sh8u(DisasContext *s, int x)
{
return (uint8_t)x << (x & 0x100 ? 8 : 0);
}
@@ -90,7 +90,7 @@ static inline int expand_imm_sh8u(int x)
/* Convert a 2-bit memory size (msz) to a 4-bit data type (dtype)
* with unsigned data. C.f. SVE Memory Contiguous Load Group.
*/
-static inline int msz_dtype(int msz)
+static inline int msz_dtype(DisasContext *s, int msz)
{
static const uint8_t dtype[4] = { 0, 5, 10, 15 };
return dtype[msz];
@@ -4834,7 +4834,7 @@ static void do_ldrq(DisasContext *s, int zt, int pg, TCGv_i64 addr, int msz)
int desc, poff;
/* Load the first quadword using the normal predicated load helpers. */
- desc = sve_memopidx(s, msz_dtype(msz));
+ desc = sve_memopidx(s, msz_dtype(s, msz));
desc |= zt << MEMOPIDX_SHIFT;
desc = simd_desc(16, 16, desc);
t_desc = tcg_const_i32(desc);
@@ -5016,7 +5016,7 @@ static void do_st_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr,
fn = fn_multiple[be][nreg - 1][msz];
}
assert(fn != NULL);
- do_mem_zpa(s, zt, pg, addr, msz_dtype(msz), fn);
+ do_mem_zpa(s, zt, pg, addr, msz_dtype(s, msz), fn);
}
static bool trans_ST_zprr(DisasContext *s, arg_rprr_store *a)
@@ -5065,7 +5065,7 @@ static void do_mem_zpz(DisasContext *s, int zt, int pg, int zm,
TCGv_i32 t_desc;
int desc;
- desc = sve_memopidx(s, msz_dtype(msz));
+ desc = sve_memopidx(s, msz_dtype(s, msz));
desc |= scale << MEMOPIDX_SHIFT;
desc = simd_desc(vsz, vsz, desc);
t_desc = tcg_const_i32(desc);
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index e1febdfea1..188fe688cb 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -279,7 +279,7 @@ typedef struct DisasContext {
} DisasContext;
/* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */
-static int expand_sm_imm(int val)
+static int expand_sm_imm(DisasContext *ctx, int val)
{
if (val & PSW_SM_E) {
val = (val & ~PSW_SM_E) | PSW_E;
@@ -291,43 +291,43 @@ static int expand_sm_imm(int val)
}
/* Inverted space register indicates 0 means sr0 not inferred from base. */
-static int expand_sr3x(int val)
+static int expand_sr3x(DisasContext *ctx, int val)
{
return ~val;
}
/* Convert the M:A bits within a memory insn to the tri-state value
we use for the final M. */
-static int ma_to_m(int val)
+static int ma_to_m(DisasContext *ctx, int val)
{
return val & 2 ? (val & 1 ? -1 : 1) : 0;
}
/* Convert the sign of the displacement to a pre or post-modify. */
-static int pos_to_m(int val)
+static int pos_to_m(DisasContext *ctx, int val)
{
return val ? 1 : -1;
}
-static int neg_to_m(int val)
+static int neg_to_m(DisasContext *ctx, int val)
{
return val ? -1 : 1;
}
/* Used for branch targets and fp memory ops. */
-static int expand_shl2(int val)
+static int expand_shl2(DisasContext *ctx, int val)
{
return val << 2;
}
/* Used for fp memory ops. */
-static int expand_shl3(int val)
+static int expand_shl3(DisasContext *ctx, int val)
{
return val << 3;
}
/* Used for assemble_21. */
-static int expand_shl11(int val)
+static int expand_shl11(DisasContext *ctx, int val)
{
return val << 11;
}
diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h
index a50861955a..88a8c70092 100644
--- a/target/openrisc/cpu.h
+++ b/target/openrisc/cpu.h
@@ -6,7 +6,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/target/openrisc/exception.c b/target/openrisc/exception.c
index 49470be051..28c1fce523 100644
--- a/target/openrisc/exception.c
+++ b/target/openrisc/exception.c
@@ -6,7 +6,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/target/openrisc/exception_helper.c b/target/openrisc/exception_helper.c
index 6073a5b21c..0797cc9d38 100644
--- a/target/openrisc/exception_helper.c
+++ b/target/openrisc/exception_helper.c
@@ -6,7 +6,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c
index 265ce13337..b9d2ebbb8c 100644
--- a/target/openrisc/fpu_helper.c
+++ b/target/openrisc/fpu_helper.c
@@ -7,7 +7,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/target/openrisc/insns.decode b/target/openrisc/insns.decode
index dad68c8422..7df81c1f22 100644
--- a/target/openrisc/insns.decode
+++ b/target/openrisc/insns.decode
@@ -6,7 +6,7 @@
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
+# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c
index bbae956361..ee280df895 100644
--- a/target/openrisc/interrupt.c
+++ b/target/openrisc/interrupt.c
@@ -6,7 +6,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c
index 5d822f7ab1..c9e084814c 100644
--- a/target/openrisc/machine.c
+++ b/target/openrisc/machine.c
@@ -6,7 +6,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c
index e7d5219e11..5dec68dcff 100644
--- a/target/openrisc/mmu.c
+++ b/target/openrisc/mmu.c
@@ -7,7 +7,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/target/riscv/insn_trans/trans_rvc.inc.c b/target/riscv/insn_trans/trans_rvc.inc.c
index ebcd977b2f..3e5d6fd5ea 100644
--- a/target/riscv/insn_trans/trans_rvc.inc.c
+++ b/target/riscv/insn_trans/trans_rvc.inc.c
@@ -48,13 +48,13 @@ static bool trans_c_flw_ld(DisasContext *ctx, arg_c_flw_ld *a)
REQUIRE_EXT(ctx, RVF);
arg_c_lw tmp;
- decode_insn16_extract_cl_w(&tmp, ctx->opcode);
+ decode_insn16_extract_cl_w(ctx, &tmp, ctx->opcode);
arg_flw arg = { .rd = tmp.rd, .rs1 = tmp.rs1, .imm = tmp.uimm };
return trans_flw(ctx, &arg);
#else
/* C.LD ( RV64C/RV128C-only ) */
arg_c_fld tmp;
- decode_insn16_extract_cl_d(&tmp, ctx->opcode);
+ decode_insn16_extract_cl_d(ctx, &tmp, ctx->opcode);
arg_ld arg = { .rd = tmp.rd, .rs1 = tmp.rs1, .imm = tmp.uimm };
return trans_ld(ctx, &arg);
#endif
@@ -80,13 +80,13 @@ static bool trans_c_fsw_sd(DisasContext *ctx, arg_c_fsw_sd *a)
REQUIRE_EXT(ctx, RVF);
arg_c_sw tmp;
- decode_insn16_extract_cs_w(&tmp, ctx->opcode);
+ decode_insn16_extract_cs_w(ctx, &tmp, ctx->opcode);
arg_fsw arg = { .rs1 = tmp.rs1, .rs2 = tmp.rs2, .imm = tmp.uimm };
return trans_fsw(ctx, &arg);
#else
/* C.SD ( RV64C/RV128C-only ) */
arg_c_fsd tmp;
- decode_insn16_extract_cs_d(&tmp, ctx->opcode);
+ decode_insn16_extract_cs_d(ctx, &tmp, ctx->opcode);
arg_sd arg = { .rs1 = tmp.rs1, .rs2 = tmp.rs2, .imm = tmp.uimm };
return trans_sd(ctx, &arg);
#endif
@@ -107,7 +107,7 @@ static bool trans_c_jal_addiw(DisasContext *ctx, arg_c_jal_addiw *a)
#ifdef TARGET_RISCV32
/* C.JAL */
arg_c_j tmp;
- decode_insn16_extract_cj(&tmp, ctx->opcode);
+ decode_insn16_extract_cj(ctx, &tmp, ctx->opcode);
arg_jal arg = { .rd = 1, .imm = tmp.imm };
return trans_jal(ctx, &arg);
#else
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 967eac7bc3..2ff6b49487 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -517,7 +517,7 @@ static void decode_RV32_64C(DisasContext *ctx)
}
#define EX_SH(amount) \
- static int ex_shift_##amount(int imm) \
+ static int ex_shift_##amount(DisasContext *ctx, int imm) \
{ \
return imm << amount; \
}
@@ -533,7 +533,7 @@ EX_SH(12)
} \
} while (0)
-static int ex_rvc_register(int reg)
+static int ex_rvc_register(DisasContext *ctx, int reg)
{
return 8 + reg;
}
diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h
index 84b08ff640..1be36fe875 100644
--- a/target/sh4/cpu.h
+++ b/target/sh4/cpu.h
@@ -6,7 +6,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/target/sh4/gdbstub.c b/target/sh4/gdbstub.c
index 13bea00d7d..54568e96f9 100644
--- a/target/sh4/gdbstub.c
+++ b/target/sh4/gdbstub.c
@@ -7,7 +7,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/target/sh4/helper.c b/target/sh4/helper.c
index 2ff0cf4060..fa51269fb1 100644
--- a/target/sh4/helper.c
+++ b/target/sh4/helper.c
@@ -6,7 +6,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/target/sh4/op_helper.c b/target/sh4/op_helper.c
index 4f825bae5a..28027f9e0b 100644
--- a/target/sh4/op_helper.c
+++ b/target/sh4/op_helper.c
@@ -6,7 +6,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index cdf0888490..5a7d8c4535 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -6,7 +6,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 7c8b9c84b2..60de085ee1 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -482,25 +482,6 @@ GENERATED_FILES += tests/test-qapi-types.h \
tests/test-qapi-events-sub-sub-module.h \
tests/test-qapi-introspect.h
-test-obj-y = tests/check-qnum.o tests/check-qstring.o tests/check-qdict.o \
- tests/check-qlist.o tests/check-qnull.o tests/check-qobject.o \
- tests/check-qjson.o tests/check-qlit.o \
- tests/check-block-qtest.o \
- tests/test-coroutine.o tests/test-string-output-visitor.o \
- tests/test-string-input-visitor.o tests/test-qobject-output-visitor.o \
- tests/test-clone-visitor.o \
- tests/test-qobject-input-visitor.o \
- tests/test-qmp-cmds.o tests/test-visitor-serialization.o \
- tests/test-x86-cpuid.o tests/test-mul64.o tests/test-int128.o \
- tests/test-opts-visitor.o tests/test-qmp-event.o \
- tests/rcutorture.o tests/test-rcu-list.o \
- tests/test-rcu-simpleq.o \
- tests/test-rcu-tailq.o \
- tests/test-qdist.o tests/test-shift128.o \
- tests/test-qht.o tests/qht-bench.o tests/test-qht-par.o \
- tests/atomic_add-bench.o tests/atomic64-bench.o
-
-$(test-obj-y): QEMU_INCLUDES += -Itests
QEMU_CFLAGS += -I$(SRC_PATH)/tests
@@ -1103,7 +1084,7 @@ check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF)
.PHONY: $(patsubst %, check-%, $(check-qapi-schema-y))
$(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json
$(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts \
- $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py \
+ PYTHONIOENCODING=utf-8 $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py \
$^ >$*.test.out 2>$*.test.err; \
echo $$? >$*.test.exit, \
"TEST","$*.out")
diff --git a/tests/drive_del-test.c b/tests/drive_del-test.c
index 2f9474e03c..b56b223fc2 100644
--- a/tests/drive_del-test.c
+++ b/tests/drive_del-test.c
@@ -16,32 +16,32 @@
#include "qapi/qmp/qdict.h"
/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
+#define qmp_discard_response(q, ...) qobject_unref(qtest_qmp(q, __VA_ARGS__))
-static void drive_add(void)
+static void drive_add(QTestState *qts)
{
- char *resp = hmp("drive_add 0 if=none,id=drive0");
+ char *resp = qtest_hmp(qts, "drive_add 0 if=none,id=drive0");
g_assert_cmpstr(resp, ==, "OK\r\n");
g_free(resp);
}
-static void drive_del(void)
+static void drive_del(QTestState *qts)
{
- char *resp = hmp("drive_del drive0");
+ char *resp = qtest_hmp(qts, "drive_del drive0");
g_assert_cmpstr(resp, ==, "");
g_free(resp);
}
-static void device_del(void)
+static void device_del(QTestState *qts)
{
QDict *response;
/* Complication: ignore DEVICE_DELETED event */
- qmp_discard_response("{'execute': 'device_del',"
+ qmp_discard_response(qts, "{'execute': 'device_del',"
" 'arguments': { 'id': 'dev0' } }");
- response = qmp_receive();
+ response = qtest_qmp_receive(qts);
g_assert(response);
g_assert(qdict_haskey(response, "return"));
qobject_unref(response);
@@ -49,18 +49,20 @@ static void device_del(void)
static void test_drive_without_dev(void)
{
+ QTestState *qts;
+
/* Start with an empty drive */
- qtest_start("-drive if=none,id=drive0");
+ qts = qtest_init("-drive if=none,id=drive0");
/* Delete the drive */
- drive_del();
+ drive_del(qts);
/* Ensure re-adding the drive works - there should be no duplicate ID error
* because the old drive must be gone.
*/
- drive_add();
+ drive_add(qts);
- qtest_end();
+ qtest_quit(qts);
}
/*
@@ -85,54 +87,53 @@ static void test_after_failed_device_add(void)
{
char driver[32];
QDict *response;
+ QTestState *qts;
snprintf(driver, sizeof(driver), "virtio-blk-%s",
qvirtio_get_dev_type());
- qtest_start("-drive if=none,id=drive0");
+ qts = qtest_init("-drive if=none,id=drive0");
/* Make device_add fail. If this leaks the virtio-blk device then a
* reference to drive0 will also be held (via qdev properties).
*/
- response = qmp("{'execute': 'device_add',"
- " 'arguments': {"
- " 'driver': %s,"
- " 'drive': 'drive0'"
- "}}", driver);
+ response = qtest_qmp(qts, "{'execute': 'device_add',"
+ " 'arguments': {"
+ " 'driver': %s,"
+ " 'drive': 'drive0'"
+ "}}", driver);
g_assert(response);
qmp_assert_error_class(response, "GenericError");
/* Delete the drive */
- drive_del();
+ drive_del(qts);
/* Try to re-add the drive. This fails with duplicate IDs if a leaked
* virtio-blk device exists that holds a reference to the old drive0.
*/
- drive_add();
+ drive_add(qts);
- qtest_end();
+ qtest_quit(qts);
}
static void test_drive_del_device_del(void)
{
- char *args;
+ QTestState *qts;
/* Start with a drive used by a device that unplugs instantaneously */
- args = g_strdup_printf("-drive if=none,id=drive0,file=null-co://,format=raw"
- " -device virtio-scsi-%s"
- " -device scsi-hd,drive=drive0,id=dev0",
- qvirtio_get_dev_type());
- qtest_start(args);
+ qts = qtest_initf("-drive if=none,id=drive0,file=null-co://,format=raw"
+ " -device virtio-scsi-%s"
+ " -device scsi-hd,drive=drive0,id=dev0",
+ qvirtio_get_dev_type());
/*
* Delete the drive, and then the device
* Doing it in this order takes notoriously tricky special paths
*/
- drive_del();
- device_del();
+ drive_del(qts);
+ device_del(qts);
- qtest_end();
- g_free(args);
+ qtest_quit(qts);
}
int main(int argc, char **argv)
diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c
index 77ba8095bb..6a946c0484 100644
--- a/tests/e1000e-test.c
+++ b/tests/e1000e-test.c
@@ -231,8 +231,10 @@ static void test_e1000e_multiple_transfers(void *obj, void *data,
static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
{
+ QTestState *qts = global_qtest; /* TODO: get rid of global_qtest here */
+
qtest_qmp_device_add("e1000e", "e1000e_net", "{'addr': '0x06'}");
- qpci_unplug_acpi_device_test("e1000e_net", 0x06);
+ qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06);
}
static void data_test_clear(void *sockets)
diff --git a/tests/ide-test.c b/tests/ide-test.c
index d863a99f7f..0277e7d5a9 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -36,7 +36,7 @@
#include "hw/pci/pci_regs.h"
/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
+#define qmp_discard_response(q, ...) qobject_unref(qtest_qmp(q, __VA_ARGS__))
#define TEST_IMAGE_SIZE 64 * 1024 * 1024
@@ -125,38 +125,38 @@ static QGuestAllocator guest_malloc;
static char tmp_path[] = "/tmp/qtest.XXXXXX";
static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX";
-static void ide_test_start(const char *cmdline_fmt, ...)
+static QTestState *ide_test_start(const char *cmdline_fmt, ...)
{
+ QTestState *qts;
va_list ap;
- char *cmdline;
va_start(ap, cmdline_fmt);
- cmdline = g_strdup_vprintf(cmdline_fmt, ap);
+ qts = qtest_vinitf(cmdline_fmt, ap);
va_end(ap);
- qtest_start(cmdline);
- pc_alloc_init(&guest_malloc, global_qtest, 0);
+ pc_alloc_init(&guest_malloc, qts, 0);
- g_free(cmdline);
+ return qts;
}
-static void ide_test_quit(void)
+static void ide_test_quit(QTestState *qts)
{
if (pcibus) {
qpci_free_pc(pcibus);
pcibus = NULL;
}
alloc_destroy(&guest_malloc);
- qtest_end();
+ qtest_quit(qts);
}
-static QPCIDevice *get_pci_device(QPCIBar *bmdma_bar, QPCIBar *ide_bar)
+static QPCIDevice *get_pci_device(QTestState *qts, QPCIBar *bmdma_bar,
+ QPCIBar *ide_bar)
{
QPCIDevice *dev;
uint16_t vendor_id, device_id;
if (!pcibus) {
- pcibus = qpci_new_pc(global_qtest, NULL);
+ pcibus = qpci_new_pc(qts, NULL);
}
/* Find PCI device and verify it's the right one */
@@ -198,8 +198,8 @@ static uint64_t trim_range_le(uint64_t sector, uint16_t count)
return cpu_to_le64(((uint64_t)count << 48) + sector);
}
-static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
- PrdtEntry *prdt, int prdt_entries,
+static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
+ int nb_sectors, PrdtEntry *prdt, int prdt_entries,
void(*post_exec)(QPCIDevice *dev, QPCIBar ide_bar,
uint64_t sector, int nb_sectors))
{
@@ -211,7 +211,7 @@ static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
uint8_t status;
int flags;
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
flags = cmd & ~0xff;
cmd &= 0xff;
@@ -246,7 +246,7 @@ static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
/* Setup PRDT */
len = sizeof(*prdt) * prdt_entries;
guest_prdt = guest_alloc(&guest_malloc, len);
- memwrite(guest_prdt, prdt, len);
+ qtest_memwrite(qts, guest_prdt, prdt, len);
qpci_io_writel(dev, bmdma_bar, bmreg_prdt, guest_prdt);
/* ATA DMA command */
@@ -283,14 +283,15 @@ static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
status = qpci_io_readb(dev, bmdma_bar, bmreg_status);
} while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
- g_assert_cmpint(get_irq(IDE_PRIMARY_IRQ), ==, !!(status & BM_STS_INTR));
+ g_assert_cmpint(qtest_get_irq(qts, IDE_PRIMARY_IRQ), ==,
+ !!(status & BM_STS_INTR));
/* Check IDE status code */
assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), DRDY);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), BSY | DRQ);
/* Reading the status register clears the IRQ */
- g_assert(!get_irq(IDE_PRIMARY_IRQ));
+ g_assert(!qtest_get_irq(qts, IDE_PRIMARY_IRQ));
/* Stop DMA transfer if still active */
if (status & BM_STS_ACTIVE) {
@@ -302,42 +303,61 @@ static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
return status;
}
+static QTestState *test_bmdma_setup(void)
+{
+ QTestState *qts;
+
+ qts = ide_test_start(
+ "-drive file=%s,if=ide,cache=writeback,format=raw "
+ "-global ide-hd.serial=%s -global ide-hd.ver=%s",
+ tmp_path, "testdisk", "version");
+ qtest_irq_intercept_in(qts, "ioapic");
+
+ return qts;
+}
+
+static void test_bmdma_teardown(QTestState *qts)
+{
+ ide_test_quit(qts);
+}
+
static void test_bmdma_simple_rw(void)
{
+ QTestState *qts;
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
uint8_t status;
uint8_t *buf;
uint8_t *cmpbuf;
size_t len = 512;
- uintptr_t guest_buf = guest_alloc(&guest_malloc, len);
+ uintptr_t guest_buf;
+ PrdtEntry prdt[1];
- PrdtEntry prdt[] = {
- {
- .addr = cpu_to_le32(guest_buf),
- .size = cpu_to_le32(len | PRDT_EOT),
- },
- };
+ qts = test_bmdma_setup();
+
+ guest_buf = guest_alloc(&guest_malloc, len);
+ prdt[0].addr = cpu_to_le32(guest_buf);
+ prdt[0].size = cpu_to_le32(len | PRDT_EOT);
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
buf = g_malloc(len);
cmpbuf = g_malloc(len);
/* Write 0x55 pattern to sector 0 */
memset(buf, 0x55, len);
- memwrite(guest_buf, buf, len);
+ qtest_memwrite(qts, guest_buf, buf, len);
- status = send_dma_request(CMD_WRITE_DMA, 0, 1, prdt,
+ status = send_dma_request(qts, CMD_WRITE_DMA, 0, 1, prdt,
ARRAY_SIZE(prdt), NULL);
g_assert_cmphex(status, ==, BM_STS_INTR);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
/* Write 0xaa pattern to sector 1 */
memset(buf, 0xaa, len);
- memwrite(guest_buf, buf, len);
+ qtest_memwrite(qts, guest_buf, buf, len);
- status = send_dma_request(CMD_WRITE_DMA, 1, 1, prdt,
+ status = send_dma_request(qts, CMD_WRITE_DMA, 1, 1, prdt,
ARRAY_SIZE(prdt), NULL);
g_assert_cmphex(status, ==, BM_STS_INTR);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
@@ -345,31 +365,35 @@ static void test_bmdma_simple_rw(void)
/* Read and verify 0x55 pattern in sector 0 */
memset(cmpbuf, 0x55, len);
- status = send_dma_request(CMD_READ_DMA, 0, 1, prdt, ARRAY_SIZE(prdt), NULL);
+ status = send_dma_request(qts, CMD_READ_DMA, 0, 1, prdt, ARRAY_SIZE(prdt),
+ NULL);
g_assert_cmphex(status, ==, BM_STS_INTR);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
- memread(guest_buf, buf, len);
+ qtest_memread(qts, guest_buf, buf, len);
g_assert(memcmp(buf, cmpbuf, len) == 0);
/* Read and verify 0xaa pattern in sector 1 */
memset(cmpbuf, 0xaa, len);
- status = send_dma_request(CMD_READ_DMA, 1, 1, prdt, ARRAY_SIZE(prdt), NULL);
+ status = send_dma_request(qts, CMD_READ_DMA, 1, 1, prdt, ARRAY_SIZE(prdt),
+ NULL);
g_assert_cmphex(status, ==, BM_STS_INTR);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
- memread(guest_buf, buf, len);
+ qtest_memread(qts, guest_buf, buf, len);
g_assert(memcmp(buf, cmpbuf, len) == 0);
-
free_pci_device(dev);
g_free(buf);
g_free(cmpbuf);
+
+ test_bmdma_teardown(qts);
}
static void test_bmdma_trim(void)
{
+ QTestState *qts;
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
uint8_t status;
@@ -380,16 +404,16 @@ static void test_bmdma_trim(void)
const uint64_t bad_range = trim_range_le(TEST_IMAGE_SIZE / 512 - 1, 2);
size_t len = 512;
uint8_t *buf;
- uintptr_t guest_buf = guest_alloc(&guest_malloc, len);
+ uintptr_t guest_buf;
+ PrdtEntry prdt[1];
- PrdtEntry prdt[] = {
- {
- .addr = cpu_to_le32(guest_buf),
- .size = cpu_to_le32(len | PRDT_EOT),
- },
- };
+ qts = test_bmdma_setup();
+
+ guest_buf = guest_alloc(&guest_malloc, len);
+ prdt[0].addr = cpu_to_le32(guest_buf),
+ prdt[0].size = cpu_to_le32(len | PRDT_EOT),
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
buf = g_malloc(len);
@@ -397,9 +421,9 @@ static void test_bmdma_trim(void)
*((uint64_t *)buf) = trim_range[0];
*((uint64_t *)buf + 1) = trim_range[1];
- memwrite(guest_buf, buf, 2 * sizeof(uint64_t));
+ qtest_memwrite(qts, guest_buf, buf, 2 * sizeof(uint64_t));
- status = send_dma_request(CMD_DSM, 0, 1, prdt,
+ status = send_dma_request(qts, CMD_DSM, 0, 1, prdt,
ARRAY_SIZE(prdt), NULL);
g_assert_cmphex(status, ==, BM_STS_INTR);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
@@ -408,9 +432,9 @@ static void test_bmdma_trim(void)
*((uint64_t *)buf) = trim_range[2];
*((uint64_t *)buf + 1) = bad_range;
- memwrite(guest_buf, buf, 2 * sizeof(uint64_t));
+ qtest_memwrite(qts, guest_buf, buf, 2 * sizeof(uint64_t));
- status = send_dma_request(CMD_DSM, 0, 1, prdt,
+ status = send_dma_request(qts, CMD_DSM, 0, 1, prdt,
ARRAY_SIZE(prdt), NULL);
g_assert_cmphex(status, ==, BM_STS_INTR);
assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), ERR);
@@ -418,10 +442,12 @@ static void test_bmdma_trim(void)
free_pci_device(dev);
g_free(buf);
+ test_bmdma_teardown(qts);
}
static void test_bmdma_short_prdt(void)
{
+ QTestState *qts;
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
uint8_t status;
@@ -433,24 +459,28 @@ static void test_bmdma_short_prdt(void)
},
};
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ qts = test_bmdma_setup();
+
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
/* Normal request */
- status = send_dma_request(CMD_READ_DMA, 0, 1,
+ status = send_dma_request(qts, CMD_READ_DMA, 0, 1,
prdt, ARRAY_SIZE(prdt), NULL);
g_assert_cmphex(status, ==, 0);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
/* Abort the request before it completes */
- status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 1,
+ status = send_dma_request(qts, CMD_READ_DMA | CMDF_ABORT, 0, 1,
prdt, ARRAY_SIZE(prdt), NULL);
g_assert_cmphex(status, ==, 0);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
free_pci_device(dev);
+ test_bmdma_teardown(qts);
}
static void test_bmdma_one_sector_short_prdt(void)
{
+ QTestState *qts;
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
uint8_t status;
@@ -463,24 +493,28 @@ static void test_bmdma_one_sector_short_prdt(void)
},
};
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ qts = test_bmdma_setup();
+
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
/* Normal request */
- status = send_dma_request(CMD_READ_DMA, 0, 2,
+ status = send_dma_request(qts, CMD_READ_DMA, 0, 2,
prdt, ARRAY_SIZE(prdt), NULL);
g_assert_cmphex(status, ==, 0);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
/* Abort the request before it completes */
- status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 2,
+ status = send_dma_request(qts, CMD_READ_DMA | CMDF_ABORT, 0, 2,
prdt, ARRAY_SIZE(prdt), NULL);
g_assert_cmphex(status, ==, 0);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
free_pci_device(dev);
+ test_bmdma_teardown(qts);
}
static void test_bmdma_long_prdt(void)
{
+ QTestState *qts;
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
uint8_t status;
@@ -492,29 +526,35 @@ static void test_bmdma_long_prdt(void)
},
};
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ qts = test_bmdma_setup();
+
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
/* Normal request */
- status = send_dma_request(CMD_READ_DMA, 0, 1,
+ status = send_dma_request(qts, CMD_READ_DMA, 0, 1,
prdt, ARRAY_SIZE(prdt), NULL);
g_assert_cmphex(status, ==, BM_STS_ACTIVE | BM_STS_INTR);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
/* Abort the request before it completes */
- status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 1,
+ status = send_dma_request(qts, CMD_READ_DMA | CMDF_ABORT, 0, 1,
prdt, ARRAY_SIZE(prdt), NULL);
g_assert_cmphex(status, ==, BM_STS_INTR);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
free_pci_device(dev);
+ test_bmdma_teardown(qts);
}
static void test_bmdma_no_busmaster(void)
{
+ QTestState *qts;
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
uint8_t status;
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ qts = test_bmdma_setup();
+
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
/* No PRDT_EOT, each entry addr 0/size 64k, and in theory qemu shouldn't be
* able to access it anyway because the Bus Master bit in the PCI command
@@ -522,7 +562,7 @@ static void test_bmdma_no_busmaster(void)
* good at confusing and occasionally crashing qemu. */
PrdtEntry prdt[4096] = { };
- status = send_dma_request(CMD_READ_DMA | CMDF_NO_BM, 0, 512,
+ status = send_dma_request(qts, CMD_READ_DMA | CMDF_NO_BM, 0, 512,
prdt, ARRAY_SIZE(prdt), NULL);
/* Not entirely clear what the expected result is, but this is what we get
@@ -530,20 +570,7 @@ static void test_bmdma_no_busmaster(void)
g_assert_cmphex(status, ==, BM_STS_ACTIVE | BM_STS_INTR);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
free_pci_device(dev);
-}
-
-static void test_bmdma_setup(void)
-{
- ide_test_start(
- "-drive file=%s,if=ide,cache=writeback,format=raw "
- "-global ide-hd.serial=%s -global ide-hd.ver=%s",
- tmp_path, "testdisk", "version");
- qtest_irq_intercept_in(global_qtest, "ioapic");
-}
-
-static void test_bmdma_teardown(void)
-{
- ide_test_quit();
+ test_bmdma_teardown(qts);
}
static void string_cpu_to_be16(uint16_t *s, size_t bytes)
@@ -559,6 +586,7 @@ static void string_cpu_to_be16(uint16_t *s, size_t bytes)
static void test_identify(void)
{
+ QTestState *qts;
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
uint8_t data;
@@ -566,12 +594,12 @@ static void test_identify(void)
int i;
int ret;
- ide_test_start(
+ qts = ide_test_start(
"-drive file=%s,if=ide,cache=writeback,format=raw "
"-global ide-hd.serial=%s -global ide-hd.ver=%s",
tmp_path, "testdisk", "version");
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
/* IDENTIFY command on device 0*/
qpci_io_writeb(dev, ide_bar, reg_device, 0);
@@ -605,7 +633,7 @@ static void test_identify(void)
/* Write cache enabled bit */
assert_bit_set(buf[85], 0x20);
- ide_test_quit();
+ ide_test_quit(qts);
free_pci_device(dev);
}
@@ -613,7 +641,7 @@ static void test_identify(void)
* Write sector 1 with random data to make IDE storage dirty
* Needed for flush tests so that flushes actually go though the block layer
*/
-static void make_dirty(uint8_t device)
+static void make_dirty(QTestState *qts, uint8_t device)
{
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
@@ -622,7 +650,7 @@ static void make_dirty(uint8_t device)
uintptr_t guest_buf;
void* buf;
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
guest_buf = guest_alloc(&guest_malloc, len);
buf = g_malloc(len);
@@ -630,7 +658,7 @@ static void make_dirty(uint8_t device)
g_assert(guest_buf);
g_assert(buf);
- memwrite(guest_buf, buf, len);
+ qtest_memwrite(qts, guest_buf, buf, len);
PrdtEntry prdt[] = {
{
@@ -639,7 +667,7 @@ static void make_dirty(uint8_t device)
},
};
- status = send_dma_request(CMD_WRITE_DMA, 1, 1, prdt,
+ status = send_dma_request(qts, CMD_WRITE_DMA, 1, 1, prdt,
ARRAY_SIZE(prdt), NULL);
g_assert_cmphex(status, ==, BM_STS_INTR);
assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
@@ -650,23 +678,24 @@ static void make_dirty(uint8_t device)
static void test_flush(void)
{
+ QTestState *qts;
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
uint8_t data;
- ide_test_start(
+ qts = ide_test_start(
"-drive file=blkdebug::%s,if=ide,cache=writeback,format=raw",
tmp_path);
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
- qtest_irq_intercept_in(global_qtest, "ioapic");
+ qtest_irq_intercept_in(qts, "ioapic");
/* Dirty media so that CMD_FLUSH_CACHE will actually go to disk */
- make_dirty(0);
+ make_dirty(qts, 0);
/* Delay the completion of the flush request until we explicitly do it */
- g_free(hmp("qemu-io ide0-hd0 \"break flush_to_os A\""));
+ g_free(qtest_hmp(qts, "qemu-io ide0-hd0 \"break flush_to_os A\""));
/* FLUSH CACHE command on device 0*/
qpci_io_writeb(dev, ide_bar, reg_device, 0);
@@ -678,7 +707,7 @@ static void test_flush(void)
assert_bit_clear(data, DF | ERR | DRQ);
/* Complete the command */
- g_free(hmp("qemu-io ide0-hd0 \"resume A\""));
+ g_free(qtest_hmp(qts, "qemu-io ide0-hd0 \"resume A\""));
/* Check registers */
data = qpci_io_readb(dev, ide_bar, reg_device);
@@ -691,29 +720,30 @@ static void test_flush(void)
assert_bit_set(data, DRDY);
assert_bit_clear(data, BSY | DF | ERR | DRQ);
- ide_test_quit();
+ ide_test_quit(qts);
free_pci_device(dev);
}
static void test_retry_flush(const char *machine)
{
+ QTestState *qts;
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
uint8_t data;
prepare_blkdebug_script(debug_path, "flush_to_disk");
- ide_test_start(
+ qts = ide_test_start(
"-drive file=blkdebug:%s:%s,if=ide,cache=writeback,format=raw,"
"rerror=stop,werror=stop",
debug_path, tmp_path);
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
- qtest_irq_intercept_in(global_qtest, "ioapic");
+ qtest_irq_intercept_in(qts, "ioapic");
/* Dirty media so that CMD_FLUSH_CACHE will actually go to disk */
- make_dirty(0);
+ make_dirty(qts, 0);
/* FLUSH CACHE command on device 0*/
qpci_io_writeb(dev, ide_bar, reg_device, 0);
@@ -724,10 +754,10 @@ static void test_retry_flush(const char *machine)
assert_bit_set(data, BSY | DRDY);
assert_bit_clear(data, DF | ERR | DRQ);
- qmp_eventwait("STOP");
+ qtest_qmp_eventwait(qts, "STOP");
/* Complete the command */
- qmp_discard_response("{'execute':'cont' }");
+ qmp_discard_response(qts, "{'execute':'cont' }");
/* Check registers */
data = qpci_io_readb(dev, ide_bar, reg_device);
@@ -740,18 +770,19 @@ static void test_retry_flush(const char *machine)
assert_bit_set(data, DRDY);
assert_bit_clear(data, BSY | DF | ERR | DRQ);
- ide_test_quit();
+ ide_test_quit(qts);
free_pci_device(dev);
}
static void test_flush_nodev(void)
{
+ QTestState *qts;
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
- ide_test_start("");
+ qts = ide_test_start("");
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
/* FLUSH CACHE command on device 0*/
qpci_io_writeb(dev, ide_bar, reg_device, 0);
@@ -760,16 +791,17 @@ static void test_flush_nodev(void)
/* Just testing that qemu doesn't crash... */
free_pci_device(dev);
- ide_test_quit();
+ ide_test_quit(qts);
}
static void test_flush_empty_drive(void)
{
+ QTestState *qts;
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
- ide_test_start("-device ide-cd,bus=ide.0");
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ qts = ide_test_start("-device ide-cd,bus=ide.0");
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
/* FLUSH CACHE command on device 0 */
qpci_io_writeb(dev, ide_bar, reg_device, 0);
@@ -778,7 +810,7 @@ static void test_flush_empty_drive(void)
/* Just testing that qemu doesn't crash... */
free_pci_device(dev);
- ide_test_quit();
+ ide_test_quit(qts);
}
static void test_pci_retry_flush(void)
@@ -823,21 +855,21 @@ static void send_scsi_cdb_read10(QPCIDevice *dev, QPCIBar ide_bar,
}
}
-static void nsleep(int64_t nsecs)
+static void nsleep(QTestState *qts, int64_t nsecs)
{
const struct timespec val = { .tv_nsec = nsecs };
nanosleep(&val, NULL);
- clock_set(nsecs);
+ qtest_clock_set(qts, nsecs);
}
-static uint8_t ide_wait_clear(uint8_t flag)
+static uint8_t ide_wait_clear(QTestState *qts, uint8_t flag)
{
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
uint8_t data;
time_t st;
- dev = get_pci_device(&bmdma_bar, &ide_bar);
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
/* Wait with a 5 second timeout */
time(&st);
@@ -850,26 +882,26 @@ static uint8_t ide_wait_clear(uint8_t flag)
if (difftime(time(NULL), st) > 5.0) {
break;
}
- nsleep(400);
+ nsleep(qts, 400);
}
g_assert_not_reached();
}
-static void ide_wait_intr(int irq)
+static void ide_wait_intr(QTestState *qts, int irq)
{
time_t st;
bool intr;
time(&st);
while (true) {
- intr = get_irq(irq);
+ intr = qtest_get_irq(qts, irq);
if (intr) {
return;
}
if (difftime(time(NULL), st) > 5.0) {
break;
}
- nsleep(400);
+ nsleep(qts, 400);
}
g_assert_not_reached();
@@ -877,6 +909,7 @@ static void ide_wait_intr(int irq)
static void cdrom_pio_impl(int nblocks)
{
+ QTestState *qts;
QPCIDevice *dev;
QPCIBar bmdma_bar, ide_bar;
FILE *fh;
@@ -897,10 +930,11 @@ static void cdrom_pio_impl(int nblocks)
g_assert_cmpint(ret, ==, patt_blocks);
fclose(fh);
- ide_test_start("-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 "
- "-device ide-cd,drive=sr0,bus=ide.0", tmp_path);
- dev = get_pci_device(&bmdma_bar, &ide_bar);
- qtest_irq_intercept_in(global_qtest, "ioapic");
+ qts = ide_test_start(
+ "-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 "
+ "-device ide-cd,drive=sr0,bus=ide.0", tmp_path);
+ dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+ qtest_irq_intercept_in(qts, "ioapic");
/* PACKET command on device 0 */
qpci_io_writeb(dev, ide_bar, reg_device, 0);
@@ -908,8 +942,8 @@ static void cdrom_pio_impl(int nblocks)
qpci_io_writeb(dev, ide_bar, reg_lba_high, (BYTE_COUNT_LIMIT >> 8 & 0xFF));
qpci_io_writeb(dev, ide_bar, reg_command, CMD_PACKET);
/* HP0: Check_Status_A State */
- nsleep(400);
- data = ide_wait_clear(BSY);
+ nsleep(qts, 400);
+ data = ide_wait_clear(qts, BSY);
/* HP1: Send_Packet State */
assert_bit_set(data, DRQ | DRDY);
assert_bit_clear(data, ERR | DF | BSY);
@@ -930,10 +964,10 @@ static void cdrom_pio_impl(int nblocks)
size_t rem = (rxsize / 2) - offset;
/* HP3: INTRQ_Wait */
- ide_wait_intr(IDE_PRIMARY_IRQ);
+ ide_wait_intr(qts, IDE_PRIMARY_IRQ);
/* HP2: Check_Status_B (and clear IRQ) */
- data = ide_wait_clear(BSY);
+ data = ide_wait_clear(qts, BSY);
assert_bit_set(data, DRQ | DRDY);
assert_bit_clear(data, ERR | DF | BSY);
@@ -945,17 +979,17 @@ static void cdrom_pio_impl(int nblocks)
}
/* Check for final completion IRQ */
- ide_wait_intr(IDE_PRIMARY_IRQ);
+ ide_wait_intr(qts, IDE_PRIMARY_IRQ);
/* Sanity check final state */
- data = ide_wait_clear(DRQ);
+ data = ide_wait_clear(qts, DRQ);
assert_bit_set(data, DRDY);
assert_bit_clear(data, DRQ | ERR | DF | BSY);
g_assert_cmpint(memcmp(pattern, rx, rxsize), ==, 0);
g_free(pattern);
g_free(rx);
- test_bmdma_teardown();
+ test_bmdma_teardown(qts);
free_pci_device(dev);
}
@@ -973,6 +1007,7 @@ static void test_cdrom_pio_large(void)
static void test_cdrom_dma(void)
{
+ QTestState *qts;
static const size_t len = ATAPI_BLOCK_SIZE;
size_t ret;
char *pattern = g_malloc(ATAPI_BLOCK_SIZE * 16);
@@ -981,9 +1016,10 @@ static void test_cdrom_dma(void)
PrdtEntry prdt[1];
FILE *fh;
- ide_test_start("-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 "
- "-device ide-cd,drive=sr0,bus=ide.0", tmp_path);
- qtest_irq_intercept_in(global_qtest, "ioapic");
+ qts = ide_test_start(
+ "-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 "
+ "-device ide-cd,drive=sr0,bus=ide.0", tmp_path);
+ qtest_irq_intercept_in(qts, "ioapic");
guest_buf = guest_alloc(&guest_malloc, len);
prdt[0].addr = cpu_to_le32(guest_buf);
@@ -995,15 +1031,15 @@ static void test_cdrom_dma(void)
g_assert_cmpint(ret, ==, 16);
fclose(fh);
- send_dma_request(CMD_PACKET, 0, 1, prdt, 1, send_scsi_cdb_read10);
+ send_dma_request(qts, CMD_PACKET, 0, 1, prdt, 1, send_scsi_cdb_read10);
/* Read back data from guest memory into local qtest memory */
- memread(guest_buf, rx, len);
+ qtest_memread(qts, guest_buf, rx, len);
g_assert_cmpint(memcmp(pattern, rx, len), ==, 0);
g_free(pattern);
g_free(rx);
- test_bmdma_teardown();
+ test_bmdma_teardown(qts);
}
int main(int argc, char **argv)
@@ -1028,7 +1064,6 @@ int main(int argc, char **argv)
qtest_add_func("/ide/identify", test_identify);
- qtest_add_func("/ide/bmdma/setup", test_bmdma_setup);
qtest_add_func("/ide/bmdma/simple_rw", test_bmdma_simple_rw);
qtest_add_func("/ide/bmdma/trim", test_bmdma_trim);
qtest_add_func("/ide/bmdma/short_prdt", test_bmdma_short_prdt);
@@ -1036,7 +1071,6 @@ int main(int argc, char **argv)
test_bmdma_one_sector_short_prdt);
qtest_add_func("/ide/bmdma/long_prdt", test_bmdma_long_prdt);
qtest_add_func("/ide/bmdma/no_busmaster", test_bmdma_no_busmaster);
- qtest_add_func("/ide/bmdma/teardown", test_bmdma_teardown);
qtest_add_func("/ide/flush", test_flush);
qtest_add_func("/ide/flush/nodev", test_flush_nodev);
diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
index 227561fbca..a467b8c03d 100644
--- a/tests/ivshmem-test.c
+++ b/tests/ivshmem-test.c
@@ -383,18 +383,21 @@ static void test_ivshmem_server(void)
static void test_ivshmem_hotplug(void)
{
+ QTestState *qts;
const char *arch = qtest_get_arch();
- qtest_start("-object memory-backend-ram,size=1M,id=mb1");
+ qts = qtest_init("-object memory-backend-ram,size=1M,id=mb1");
+ global_qtest = qts; /* TODO: Get rid of global_qtest here */
qtest_qmp_device_add("ivshmem-plain", "iv1",
"{'addr': %s, 'memdev': 'mb1'}",
stringify(PCI_SLOT_HP));
if (strcmp(arch, "ppc64") != 0) {
- qpci_unplug_acpi_device_test("iv1", PCI_SLOT_HP);
+ qpci_unplug_acpi_device_test(qts, "iv1", PCI_SLOT_HP);
}
- qtest_end();
+ qtest_quit(qts);
+ global_qtest = NULL;
}
static void test_ivshmem_memdev(void)
diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
index 407d8aff78..634fedd049 100644
--- a/tests/libqos/pci-pc.c
+++ b/tests/libqos/pci-pc.c
@@ -176,19 +176,19 @@ void qpci_free_pc(QPCIBus *bus)
g_free(s);
}
-void qpci_unplug_acpi_device_test(const char *id, uint8_t slot)
+void qpci_unplug_acpi_device_test(QTestState *qts, const char *id, uint8_t slot)
{
QDict *response;
- response = qmp("{'execute': 'device_del', 'arguments': {'id': %s}}",
- id);
+ response = qtest_qmp(qts, "{'execute': 'device_del',"
+ " 'arguments': {'id': %s}}", id);
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
qobject_unref(response);
- outb(ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot);
+ qtest_outb(qts, ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot);
- qmp_eventwait("DEVICE_DELETED");
+ qtest_qmp_eventwait(qts, "DEVICE_DELETED");
}
static void qpci_pc_register_nodes(void)
diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h
index 8e1d292a7d..a5389a5845 100644
--- a/tests/libqos/pci.h
+++ b/tests/libqos/pci.h
@@ -123,7 +123,7 @@ QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr);
void qpci_iounmap(QPCIDevice *dev, QPCIBar addr);
QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr);
-void qpci_unplug_acpi_device_test(const char *id, uint8_t slot);
+void qpci_unplug_acpi_device_test(QTestState *qs, const char *id, uint8_t slot);
void add_qpci_address(QOSGraphEdgeOptions *opts, QPCIAddress *addr);
#endif
diff --git a/tests/megasas-test.c b/tests/megasas-test.c
index 33aa97042c..1111d331d3 100644
--- a/tests/megasas-test.c
+++ b/tests/megasas-test.c
@@ -66,7 +66,7 @@ static void megasas_pd_get_info_fuzz(void *obj, void *data, QGuestAllocator *all
context[7] = cpu_to_le32(0);
context_pa = guest_alloc(alloc, sizeof(context));
- memwrite(context_pa, context, sizeof(context));
+ qtest_memwrite(dev->bus->qts, context_pa, context, sizeof(context));
qpci_io_writel(dev, bar, 0x40, context_pa);
}
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
index 700ad1f290..f51394ae8e 100644
--- a/tests/qemu-iotests/059.out
+++ b/tests/qemu-iotests/059.out
@@ -2,15 +2,15 @@ QA output created by 059
=== Testing invalid granularity ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-can't open device TEST_DIR/t.vmdk: Invalid granularity, image may be corrupt
+qemu-io: can't open device TEST_DIR/t.vmdk: Invalid granularity, image may be corrupt
=== Testing too big L2 table size ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-can't open device TEST_DIR/t.vmdk: L2 table size too big
+qemu-io: can't open device TEST_DIR/t.vmdk: L2 table size too big
=== Testing too big L1 table size ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-can't open device TEST_DIR/t.vmdk: L1 size too big
+qemu-io: can't open device TEST_DIR/t.vmdk: L1 size too big
=== Testing monolithicFlat creation and opening ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 subformat=monolithicFlat
@@ -2050,7 +2050,7 @@ wrote 512/512 bytes at offset 10240
=== Testing monolithicFlat with internally generated JSON file name ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 subformat=monolithicFlat
-can't open: Cannot use relative extent paths with VMDK descriptor file 'json:{"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "inject-error.0.event": "read_aio"}'
+qemu-io: can't open: Cannot use relative extent paths with VMDK descriptor file 'json:{"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "inject-error.0.event": "read_aio"}'
=== Testing version 3 ===
image: TEST_DIR/iotest-version3.IMGFMT
diff --git a/tests/qemu-iotests/083.out b/tests/qemu-iotests/083.out
index 7419722cd7..eee6dd1379 100644
--- a/tests/qemu-iotests/083.out
+++ b/tests/qemu-iotests/083.out
@@ -1,43 +1,43 @@
QA output created by 083
=== Check disconnect before neg1 ===
-can't open device nbd+tcp://127.0.0.1:PORT/foo
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect after neg1 ===
-can't open device nbd+tcp://127.0.0.1:PORT/foo
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect 8 neg1 ===
-can't open device nbd+tcp://127.0.0.1:PORT/foo
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect 16 neg1 ===
-can't open device nbd+tcp://127.0.0.1:PORT/foo
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect before export ===
-can't open device nbd+tcp://127.0.0.1:PORT/foo
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect after export ===
-can't open device nbd+tcp://127.0.0.1:PORT/foo
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect 4 export ===
-can't open device nbd+tcp://127.0.0.1:PORT/foo
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect 12 export ===
-can't open device nbd+tcp://127.0.0.1:PORT/foo
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect 16 export ===
-can't open device nbd+tcp://127.0.0.1:PORT/foo
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect before neg2 ===
-can't open device nbd+tcp://127.0.0.1:PORT/foo
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect after neg2 ===
@@ -45,11 +45,11 @@ read failed: Input/output error
=== Check disconnect 8 neg2 ===
-can't open device nbd+tcp://127.0.0.1:PORT/foo
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect 10 neg2 ===
-can't open device nbd+tcp://127.0.0.1:PORT/foo
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect before request ===
@@ -86,23 +86,23 @@ read 512/512 bytes at offset 0
=== Check disconnect before neg-classic ===
-can't open device nbd+tcp://127.0.0.1:PORT/
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/
=== Check disconnect 8 neg-classic ===
-can't open device nbd+tcp://127.0.0.1:PORT/
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/
=== Check disconnect 16 neg-classic ===
-can't open device nbd+tcp://127.0.0.1:PORT/
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/
=== Check disconnect 24 neg-classic ===
-can't open device nbd+tcp://127.0.0.1:PORT/
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/
=== Check disconnect 28 neg-classic ===
-can't open device nbd+tcp://127.0.0.1:PORT/
+qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/
=== Check disconnect after neg-classic ===
@@ -110,43 +110,43 @@ read failed: Input/output error
=== Check disconnect before neg1 ===
-can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect after neg1 ===
-can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect 8 neg1 ===
-can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect 16 neg1 ===
-can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect before export ===
-can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect after export ===
-can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect 4 export ===
-can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect 12 export ===
-can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect 16 export ===
-can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect before neg2 ===
-can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect after neg2 ===
@@ -154,11 +154,11 @@ read failed: Input/output error
=== Check disconnect 8 neg2 ===
-can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect 10 neg2 ===
-can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect before request ===
@@ -195,23 +195,23 @@ read 512/512 bytes at offset 0
=== Check disconnect before neg-classic ===
-can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
=== Check disconnect 8 neg-classic ===
-can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
=== Check disconnect 16 neg-classic ===
-can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
=== Check disconnect 24 neg-classic ===
-can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
=== Check disconnect 28 neg-classic ===
-can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
+qemu-io: can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
=== Check disconnect after neg-classic ===
diff --git a/tests/qemu-iotests/092.out b/tests/qemu-iotests/092.out
index 6eda321fc6..3e79914873 100644
--- a/tests/qemu-iotests/092.out
+++ b/tests/qemu-iotests/092.out
@@ -2,25 +2,25 @@ QA output created by 092
== Invalid cluster size ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
-can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
-can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
-can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
+qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
+qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
+qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
+qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
== Invalid L2 table size ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
-can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
-can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
-can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
== Invalid size ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-can't open device TEST_DIR/t.qcow: Image too large
-can't open device TEST_DIR/t.qcow: Image too large
+qemu-io: can't open device TEST_DIR/t.qcow: Image too large
+qemu-io: can't open device TEST_DIR/t.qcow: Image too large
== Invalid backing file length ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-can't open device TEST_DIR/t.qcow: Backing file name too long
-can't open device TEST_DIR/t.qcow: Backing file name too long
+qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
+qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
*** done
diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110
index fad672c1ae..33b169ffd4 100755
--- a/tests/qemu-iotests/110
+++ b/tests/qemu-iotests/110
@@ -53,8 +53,12 @@ TEST_IMG="$TEST_IMG.base" _make_test_img 64M
_make_test_img -b "$TEST_IMG_REL.base" 64M
# qemu should be able to reconstruct the filename, so relative backing names
# should work
+# (We have to filter the backing file format because vmdk always
+# reports it (as vmdk), whereas other image formats would do so only
+# with the backing_fmt creation option, which neither vmdk nor qcow
+# support)
TEST_IMG="json:{'driver':'$IMGFMT','file':{'driver':'file','filename':'$TEST_IMG'}}" \
- _img_info | _filter_img_info
+ _img_info | _filter_img_info | grep -v 'backing file format'
echo
echo '=== Non-reconstructable filename ==='
@@ -78,7 +82,7 @@ TEST_IMG="json:{
}
]
}
-}" _img_info | _filter_img_info
+}" _img_info | _filter_img_info | grep -v 'backing file format'
echo
echo '=== Backing name is always relative to the backed image ==='
@@ -110,7 +114,7 @@ TEST_IMG="json:{
}
]
}
-}" _img_info | _filter_img_info
+}" _img_info | _filter_img_info | grep -v 'backing file format'
# success, all done
diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126
index 96dc048d59..e3ee65c606 100755
--- a/tests/qemu-iotests/126
+++ b/tests/qemu-iotests/126
@@ -62,8 +62,12 @@ TOP_IMG="$TEST_DIR/image:top.$IMGFMT"
TEST_IMG=$BASE_IMG _make_test_img 64M
TEST_IMG=$TOP_IMG _make_test_img -b ./image:base.$IMGFMT
-# The default cluster size depends on the image format
-TEST_IMG=$TOP_IMG _img_info | grep -v 'cluster_size'
+# (1) The default cluster size depends on the image format
+# (2) vmdk only supports vmdk backing files, so it always reports the
+# format of its backing file as such (but neither it nor qcow
+# support the backing_fmt creation option, so we cannot use that to
+# harmonize the output across all image formats this test supports)
+TEST_IMG=$TOP_IMG _img_info | grep -ve 'cluster_size' -e 'backing file format'
_rm_test_img "$BASE_IMG"
_rm_test_img "$TOP_IMG"
@@ -79,7 +83,7 @@ TOP_IMG="file:image:top.$IMGFMT"
TEST_IMG=$BASE_IMG _make_test_img 64M
TEST_IMG=$TOP_IMG _make_test_img -b "$BASE_IMG"
-TEST_IMG=$TOP_IMG _img_info | grep -v 'cluster_size'
+TEST_IMG=$TOP_IMG _img_info | grep -ve 'cluster_size' -e 'backing file format'
_rm_test_img "$BASE_IMG"
_rm_test_img "image:top.$IMGFMT"
diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138
index f353ac8219..6a731370db 100755
--- a/tests/qemu-iotests/138
+++ b/tests/qemu-iotests/138
@@ -54,15 +54,13 @@ $QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
# Put the data cluster at a multiple of 2 TB, resulting in the image apparently
# having a multiple of 2^32 clusters
# (To be more specific: It is at 32 PB)
-poke_file "$TEST_IMG" 2048 "\x80\x80\x00\x00\x00\x00\x00\x00"
+poke_file "$TEST_IMG" $((2048 + 8)) "\x00\x80\x00\x00\x00\x00\x00\x00"
# An offset of 32 PB results in qemu-img check having to allocate an in-memory
-# refcount table of 128 TB (16 bit refcounts, 512 byte clusters).
-# This should be generally too much for any system and thus fail.
-# What this test is checking is that the qcow2 driver actually tries to allocate
-# such a large amount of memory (and is consequently aborting) instead of having
-# truncated the cluster count somewhere (which would result in much less memory
-# being allocated and then a segfault occurring).
+# refcount table of 128 TB (16 bit refcounts, 512 byte clusters), if qemu-img
+# don't check that referenced data cluster is far beyond the end of file.
+# But starting from 4.0, qemu-img does this check, and instead of "Cannot
+# allocate memory", we have an error showing that l2 entry is invalid.
_check_test_img
# success, all done
diff --git a/tests/qemu-iotests/138.out b/tests/qemu-iotests/138.out
index 3fe911f85a..aca7d47a80 100644
--- a/tests/qemu-iotests/138.out
+++ b/tests/qemu-iotests/138.out
@@ -5,5 +5,8 @@ QA output created by 138
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=512
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-qemu-img: Check failed: Cannot allocate memory
+ERROR: counting reference for region exceeding the end of the file by one cluster or more: offset 0x80000000000000 size 0x200
+
+1 errors were found on the image.
+Data may be corrupted, or further writes to the image may corrupt it.
*** done
diff --git a/tests/qemu-iotests/182 b/tests/qemu-iotests/182
index ff3d7e7ec1..38959bf276 100755
--- a/tests/qemu-iotests/182
+++ b/tests/qemu-iotests/182
@@ -31,6 +31,7 @@ _cleanup()
{
_cleanup_test_img
rm -f "$TEST_IMG.overlay"
+ rm -f "$TEST_DIR/nbd.socket"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -126,15 +127,26 @@ success_or_failure=y _send_qemu_cmd $QEMU_HANDLE \
'return' \
'error'
-# Now we attach the image to a virtio-blk device. This device does
-# require some permissions (at least WRITE and READ_CONSISTENT), so if
+# Start an NBD server to which we can attach node1
+success_or_failure=y _send_qemu_cmd $QEMU_HANDLE \
+ "{'execute': 'nbd-server-start',
+ 'arguments': {
+ 'addr': {
+ 'type': 'unix',
+ 'data': {
+ 'path': '$TEST_DIR/nbd.socket'
+ } } } }" \
+ 'return' \
+ 'error'
+
+# Now we attach the image to the NBD server. This server does require
+# some permissions (at least WRITE and READ_CONSISTENT), so if
# reopening node0 unshared any (which it should not have), this will
# fail (but it should not).
success_or_failure=y _send_qemu_cmd $QEMU_HANDLE \
- "{'execute': 'device_add',
+ "{'execute': 'nbd-server-add',
'arguments': {
- 'driver': 'virtio-blk',
- 'drive': 'node1'
+ 'device': 'node1'
} }" \
'return' \
'error'
diff --git a/tests/qemu-iotests/182.out b/tests/qemu-iotests/182.out
index af501ca3f3..33d41eea91 100644
--- a/tests/qemu-iotests/182.out
+++ b/tests/qemu-iotests/182.out
@@ -14,4 +14,5 @@ Formatting 'TEST_DIR/t.qcow2.overlay', fmt=qcow2 size=197120 backing_file=TEST_D
{"return": {}}
{"return": {}}
{"return": {}}
+{"return": {}}
*** done
diff --git a/tests/qemu-iotests/192 b/tests/qemu-iotests/192
index 158086f9d2..61a88ac88d 100755
--- a/tests/qemu-iotests/192
+++ b/tests/qemu-iotests/192
@@ -29,7 +29,9 @@ status=1 # failure is the default!
_cleanup()
{
- _cleanup_test_img
+ _cleanup_qemu
+ _cleanup_test_img
+ rm -f "$TEST_DIR/nbd"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207
index dfd3c51bd1..b3816136f7 100755
--- a/tests/qemu-iotests/207
+++ b/tests/qemu-iotests/207
@@ -66,7 +66,7 @@ with iotests.FilePath('t.img') as disk_path, \
'size': 4194304 })
vm.shutdown()
- iotests.img_info_log(remote_path, filter_path=disk_path)
+ iotests.img_info_log(remote_path)
iotests.log("")
iotests.img_info_log(disk_path)
@@ -91,7 +91,7 @@ with iotests.FilePath('t.img') as disk_path, \
'size': 8388608 })
vm.shutdown()
- iotests.img_info_log(remote_path, filter_path=disk_path)
+ iotests.img_info_log(remote_path)
vm.launch()
blockdev_create(vm, { 'driver': 'ssh',
@@ -108,7 +108,7 @@ with iotests.FilePath('t.img') as disk_path, \
'size': 4194304 })
vm.shutdown()
- iotests.img_info_log(remote_path, filter_path=disk_path)
+ iotests.img_info_log(remote_path)
md5_key = subprocess.check_output(
'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
@@ -146,7 +146,7 @@ with iotests.FilePath('t.img') as disk_path, \
'size': 8388608 })
vm.shutdown()
- iotests.img_info_log(remote_path, filter_path=disk_path)
+ iotests.img_info_log(remote_path)
sha1_key = subprocess.check_output(
'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
@@ -184,7 +184,7 @@ with iotests.FilePath('t.img') as disk_path, \
'size': 4194304 })
vm.shutdown()
- iotests.img_info_log(remote_path, filter_path=disk_path)
+ iotests.img_info_log(remote_path)
#
# Invalid path and user
diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out
index 979d5cf745..ec9823793a 100644
--- a/tests/qemu-iotests/207.out
+++ b/tests/qemu-iotests/207.out
@@ -5,7 +5,7 @@
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
+image: TEST_IMG
file format: IMGFMT
virtual size: 4 MiB (4194304 bytes)
@@ -21,7 +21,7 @@ virtual size: 4 MiB (4194304 bytes)
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
+image: TEST_IMG
file format: IMGFMT
virtual size: 8 MiB (8388608 bytes)
@@ -30,7 +30,7 @@ virtual size: 8 MiB (8388608 bytes)
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
+image: TEST_IMG
file format: IMGFMT
virtual size: 4 MiB (4194304 bytes)
@@ -45,7 +45,7 @@ Job failed: remote host key does not match host_key_check 'wrong'
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
+image: TEST_IMG
file format: IMGFMT
virtual size: 8 MiB (8388608 bytes)
@@ -60,7 +60,7 @@ Job failed: remote host key does not match host_key_check 'wrong'
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
+image: TEST_IMG
file format: IMGFMT
virtual size: 4 MiB (4194304 bytes)
diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221
index 808cd9a289..25dd47bcfe 100755
--- a/tests/qemu-iotests/221
+++ b/tests/qemu-iotests/221
@@ -2,7 +2,7 @@
#
# Test qemu-img vs. unaligned images
#
-# Copyright (C) 2018 Red Hat, Inc.
+# Copyright (C) 2018-2019 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -41,16 +41,16 @@ echo
echo "=== Check mapping of unaligned raw image ==="
echo
-_make_test_img 43009 # qemu-img create rounds size up
+_make_test_img 65537 # qemu-img create rounds size up
$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
-truncate --size=43009 "$TEST_IMG" # so we resize it and check again
+truncate --size=65537 "$TEST_IMG" # so we resize it and check again
$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
-$QEMU_IO -c 'w 43008 1' "$TEST_IMG" | _filter_qemu_io # writing also rounds up
+$QEMU_IO -c 'w 65536 1' "$TEST_IMG" | _filter_qemu_io # writing also rounds up
$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
-truncate --size=43009 "$TEST_IMG" # so we resize it and check again
+truncate --size=65537 "$TEST_IMG" # so we resize it and check again
$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
# success, all done
diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out
index a9c0190aad..9f9dd52bb0 100644
--- a/tests/qemu-iotests/221.out
+++ b/tests/qemu-iotests/221.out
@@ -2,15 +2,15 @@ QA output created by 221
=== Check mapping of unaligned raw image ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=43009
-[{ "start": 0, "length": 43520, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
-[{ "start": 0, "length": 43520, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
-wrote 1/1 bytes at offset 43008
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65537
+[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+wrote 1/1 bytes at offset 65536
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-[{ "start": 0, "length": 40960, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
-{ "start": 40960, "length": 2049, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
-{ "start": 43009, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
-[{ "start": 0, "length": 40960, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
-{ "start": 40960, "length": 2049, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
-{ "start": 43009, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+{ "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+{ "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
*** done
diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233
index b8b6c8cc4c..41b4d46560 100755
--- a/tests/qemu-iotests/233
+++ b/tests/qemu-iotests/233
@@ -139,11 +139,13 @@ nbd_server_start_tcp_socket \
$QEMU_IMG info --image-opts \
--object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \
- driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0
+ driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
+ 2>&1 | sed "s/$nbd_tcp_port/PORT/g"
$QEMU_IMG info --image-opts \
--object tls-creds-x509,dir=${tls_dir}/client3,endpoint=client,id=tls0 \
- driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0
+ driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
+ 2>&1 | sed "s/$nbd_tcp_port/PORT/g"
echo
echo "== final server log =="
diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out
index 4edc2dd5cf..9b46284ab0 100644
--- a/tests/qemu-iotests/233.out
+++ b/tests/qemu-iotests/233.out
@@ -57,8 +57,8 @@ read 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== check TLS with authorization ==
-qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=10809,tls-creds=tls0': Failed to read option reply: Cannot read from TLS channel: Software caused connection abort
-qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=10809,tls-creds=tls0': Failed to read option reply: Cannot read from TLS channel: Software caused connection abort
+qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Failed to read option reply: Cannot read from TLS channel: Software caused connection abort
+qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Failed to read option reply: Cannot read from TLS channel: Software caused connection abort
== final server log ==
qemu-nbd: option negotiation failed: Verify failed: No certificate was found.
diff --git a/tests/qemu-iotests/252 b/tests/qemu-iotests/252
new file mode 100755
index 0000000000..f6c8f71444
--- /dev/null
+++ b/tests/qemu-iotests/252
@@ -0,0 +1,124 @@
+#!/usr/bin/env bash
+#
+# Tests for rebasing COW images that require zero cluster support
+#
+# Copyright (C) 2019 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# 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=mreitz@redhat.com
+
+seq=$(basename $0)
+echo "QA output created by $seq"
+
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+ rm -f "$TEST_IMG.base_new"
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.pattern
+
+# Currently only qcow2 and qed support rebasing, and only qcow2 v3 has
+# zero cluster support
+_supported_fmt qcow2
+_unsupported_imgopts 'compat=0.10'
+_supported_proto file
+_supported_os Linux
+
+CLUSTER_SIZE=65536
+
+echo
+echo "=== Test rebase without input base ==="
+echo
+
+# Cluster allocations to be tested:
+#
+# Backing (new) 11 -- 11 -- 11 --
+# COW image 22 22 11 11 -- --
+#
+# Expected result:
+#
+# COW image 22 22 11 11 00 --
+#
+# (Cluster 2 might be "--" after the rebase, too, but rebase just
+# compares the new backing file to the old one and disregards the
+# overlay. Therefore, it will never discard overlay clusters.)
+
+_make_test_img $((6 * CLUSTER_SIZE))
+TEST_IMG="$TEST_IMG.base_new" _make_test_img $((6 * CLUSTER_SIZE))
+
+echo
+
+$QEMU_IO "$TEST_IMG" \
+ -c "write -P 0x22 $((0 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
+ -c "write -P 0x11 $((2 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
+ | _filter_qemu_io
+
+$QEMU_IO "$TEST_IMG.base_new" \
+ -c "write -P 0x11 $((0 * CLUSTER_SIZE)) $CLUSTER_SIZE" \
+ -c "write -P 0x11 $((2 * CLUSTER_SIZE)) $CLUSTER_SIZE" \
+ -c "write -P 0x11 $((4 * CLUSTER_SIZE)) $CLUSTER_SIZE" \
+ | _filter_qemu_io
+
+echo
+
+# This should be a no-op
+$QEMU_IMG rebase -b "" "$TEST_IMG"
+
+# Verify the data is correct
+$QEMU_IO "$TEST_IMG" \
+ -c "read -P 0x22 $((0 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
+ -c "read -P 0x11 $((2 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
+ -c "read -P 0x00 $((4 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
+ | _filter_qemu_io
+
+echo
+
+# Verify the allocation status (first four cluster should be allocated
+# in TEST_IMG, clusters 4 and 5 should be unallocated (marked as zero
+# clusters here because there is no backing file))
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
+
+echo
+
+$QEMU_IMG rebase -b "$TEST_IMG.base_new" "$TEST_IMG"
+
+# Verify the data is correct
+$QEMU_IO "$TEST_IMG" \
+ -c "read -P 0x22 $((0 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
+ -c "read -P 0x11 $((2 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
+ -c "read -P 0x00 $((4 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
+ | _filter_qemu_io
+
+echo
+
+# Verify the allocation status (first four cluster should be allocated
+# in TEST_IMG, cluster 4 should be zero, and cluster 5 should be
+# unallocated (signified by '"depth": 1'))
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
+
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/252.out b/tests/qemu-iotests/252.out
new file mode 100644
index 0000000000..12dce889f8
--- /dev/null
+++ b/tests/qemu-iotests/252.out
@@ -0,0 +1,39 @@
+QA output created by 252
+
+=== Test rebase without input base ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=393216
+Formatting 'TEST_DIR/t.IMGFMT.base_new', fmt=IMGFMT size=393216
+
+wrote 131072/131072 bytes at offset 0
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 131072/131072 bytes at offset 131072
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 131072
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 262144
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+read 131072/131072 bytes at offset 0
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 131072/131072 bytes at offset 131072
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 131072/131072 bytes at offset 262144
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+[{ "start": 0, "length": 262144, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 262144, "length": 131072, "depth": 0, "zero": true, "data": false}]
+
+read 131072/131072 bytes at offset 0
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 131072/131072 bytes at offset 131072
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 131072/131072 bytes at offset 262144
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+[{ "start": 0, "length": 262144, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 262144, "length": 65536, "depth": 0, "zero": true, "data": false},
+{ "start": 327680, "length": 65536, "depth": 1, "zero": true, "data": false}]
+*** done
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index a543e546c2..93f87389b6 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -158,7 +158,7 @@ else
TEST_IMG="nbd:127.0.0.1:10810"
elif [ "$IMGPROTO" = "ssh" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
- REMOTE_TEST_DIR="ssh://127.0.0.1$TEST_DIR"
+ REMOTE_TEST_DIR="ssh://\\($USER@\\)\\?127.0.0.1\\(:[0-9]\\+\\)\\?$TEST_DIR"
TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE"
elif [ "$IMGPROTO" = "nfs" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 7ac9a5ea4a..00e474ab0a 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -249,3 +249,4 @@
247 rw auto quick
248 rw auto quick
249 rw auto quick
+252 rw auto backing quick
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 997dc910cb..f811f69135 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -411,7 +411,7 @@ def remote_filename(path):
if imgproto == 'file':
return path
elif imgproto == 'ssh':
- return "ssh://127.0.0.1%s" % (path)
+ return "ssh://%s@127.0.0.1:22%s" % (os.environ.get('USER'), path)
else:
raise Exception("Protocol %s not supported" % (imgproto))
diff --git a/tests/qmp-cmd-test.c b/tests/qmp-cmd-test.c
index d12cac539c..9f5228cd99 100644
--- a/tests/qmp-cmd-test.c
+++ b/tests/qmp-cmd-test.c
@@ -61,10 +61,11 @@ static void test_query(const void *data)
int expected_error_class = query_error_class(cmd);
QDict *resp, *error;
const char *error_class;
+ QTestState *qts;
- qtest_start(common_args);
+ qts = qtest_init(common_args);
- resp = qmp("{ 'execute': %s }", cmd);
+ resp = qtest_qmp(qts, "{ 'execute': %s }", cmd);
error = qdict_get_qdict(resp, "error");
error_class = error ? qdict_get_str(error, "class") : NULL;
@@ -78,7 +79,7 @@ static void test_query(const void *data)
}
qobject_unref(resp);
- qtest_end();
+ qtest_quit(qts);
}
static bool query_is_blacklisted(const char *cmd)
@@ -118,16 +119,18 @@ static void qmp_schema_init(QmpSchema *schema)
QDict *resp;
Visitor *qiv;
SchemaInfoList *tail;
+ QTestState *qts;
- qtest_start(common_args);
- resp = qmp("{ 'execute': 'query-qmp-schema' }");
+ qts = qtest_init(common_args);
+
+ resp = qtest_qmp(qts, "{ 'execute': 'query-qmp-schema' }");
qiv = qobject_input_visitor_new(qdict_get(resp, "return"));
visit_type_SchemaInfoList(qiv, NULL, &schema->list, &error_abort);
visit_free(qiv);
qobject_unref(resp);
- qtest_end();
+ qtest_quit(qts);
schema->hash = g_hash_table_new(g_str_hash, g_str_equal);
diff --git a/tests/tco-test.c b/tests/tco-test.c
index f89a42cdcc..254f735370 100644
--- a/tests/tco-test.c
+++ b/tests/tco-test.c
@@ -45,13 +45,14 @@ typedef struct {
QPCIDevice *dev;
QPCIBar tco_io_bar;
QPCIBus *bus;
+ QTestState *qts;
} TestData;
static void test_end(TestData *d)
{
g_free(d->dev);
qpci_free_pc(d->bus);
- qtest_end();
+ qtest_quit(d->qts);
}
static void test_init(TestData *d)
@@ -61,7 +62,6 @@ static void test_init(TestData *d)
qs = qtest_initf("-machine q35 %s %s",
d->noreboot ? "" : "-global ICH9-LPC.noreboot=false",
!d->args ? "" : d->args);
- global_qtest = qs;
qtest_irq_intercept_in(qs, "ioapic");
d->bus = qpci_new_pc(qs, NULL);
@@ -78,6 +78,7 @@ static void test_init(TestData *d)
qpci_config_writel(d->dev, ICH9_LPC_RCBA, RCBA_BASE_ADDR | 0x1);
d->tco_io_bar = qpci_legacy_iomap(d->dev, PM_IO_BASE_ADDR + 0x60);
+ d->qts = qs;
}
static void stop_tco(const TestData *d)
@@ -115,17 +116,17 @@ static void clear_tco_status(const TestData *d)
qpci_io_writew(d->dev, d->tco_io_bar, TCO2_STS, 0x0004);
}
-static void reset_on_second_timeout(bool enable)
+static void reset_on_second_timeout(const TestData *td, bool enable)
{
uint32_t val;
- val = readl(RCBA_BASE_ADDR + ICH9_CC_GCS);
+ val = qtest_readl(td->qts, RCBA_BASE_ADDR + ICH9_CC_GCS);
if (enable) {
val &= ~ICH9_CC_GCS_NO_REBOOT;
} else {
val |= ICH9_CC_GCS_NO_REBOOT;
}
- writel(RCBA_BASE_ADDR + ICH9_CC_GCS, val);
+ qtest_writel(td->qts, RCBA_BASE_ADDR + ICH9_CC_GCS, val);
}
static void test_tco_defaults(void)
@@ -171,11 +172,11 @@ static void test_tco_timeout(void)
stop_tco(&d);
clear_tco_status(&d);
- reset_on_second_timeout(false);
+ reset_on_second_timeout(&d, false);
set_tco_timeout(&d, ticks);
load_tco(&d);
start_tco(&d);
- clock_step(ticks * TCO_TICK_NSEC);
+ qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC);
/* test first timeout */
val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
@@ -190,7 +191,7 @@ static void test_tco_timeout(void)
g_assert(ret == 0);
/* test second timeout */
- clock_step(ticks * TCO_TICK_NSEC);
+ qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC);
val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
ret = val & TCO_TIMEOUT ? 1 : 0;
g_assert(ret == 1);
@@ -215,18 +216,18 @@ static void test_tco_max_timeout(void)
stop_tco(&d);
clear_tco_status(&d);
- reset_on_second_timeout(false);
+ reset_on_second_timeout(&d, false);
set_tco_timeout(&d, ticks);
load_tco(&d);
start_tco(&d);
- clock_step(((ticks & TCO_TMR_MASK) - 1) * TCO_TICK_NSEC);
+ qtest_clock_step(d.qts, ((ticks & TCO_TMR_MASK) - 1) * TCO_TICK_NSEC);
val = qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD);
g_assert_cmpint(val & TCO_RLD_MASK, ==, 1);
val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
ret = val & TCO_TIMEOUT ? 1 : 0;
g_assert(ret == 0);
- clock_step(TCO_TICK_NSEC);
+ qtest_clock_step(d.qts, TCO_TICK_NSEC);
val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
ret = val & TCO_TIMEOUT ? 1 : 0;
g_assert(ret == 1);
@@ -235,9 +236,9 @@ static void test_tco_max_timeout(void)
test_end(&d);
}
-static QDict *get_watchdog_action(void)
+static QDict *get_watchdog_action(const TestData *td)
{
- QDict *ev = qmp_eventwait_ref("WATCHDOG");
+ QDict *ev = qtest_qmp_eventwait_ref(td->qts, "WATCHDOG");
QDict *data;
data = qdict_get_qdict(ev, "data");
@@ -258,12 +259,12 @@ static void test_tco_second_timeout_pause(void)
stop_tco(&td);
clear_tco_status(&td);
- reset_on_second_timeout(true);
+ reset_on_second_timeout(&td, true);
set_tco_timeout(&td, TCO_SECS_TO_TICKS(16));
load_tco(&td);
start_tco(&td);
- clock_step(ticks * TCO_TICK_NSEC * 2);
- ad = get_watchdog_action();
+ qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
+ ad = get_watchdog_action(&td);
g_assert(!strcmp(qdict_get_str(ad, "action"), "pause"));
qobject_unref(ad);
@@ -283,12 +284,12 @@ static void test_tco_second_timeout_reset(void)
stop_tco(&td);
clear_tco_status(&td);
- reset_on_second_timeout(true);
+ reset_on_second_timeout(&td, true);
set_tco_timeout(&td, TCO_SECS_TO_TICKS(16));
load_tco(&td);
start_tco(&td);
- clock_step(ticks * TCO_TICK_NSEC * 2);
- ad = get_watchdog_action();
+ qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
+ ad = get_watchdog_action(&td);
g_assert(!strcmp(qdict_get_str(ad, "action"), "reset"));
qobject_unref(ad);
@@ -308,12 +309,12 @@ static void test_tco_second_timeout_shutdown(void)
stop_tco(&td);
clear_tco_status(&td);
- reset_on_second_timeout(true);
+ reset_on_second_timeout(&td, true);
set_tco_timeout(&td, ticks);
load_tco(&td);
start_tco(&td);
- clock_step(ticks * TCO_TICK_NSEC * 2);
- ad = get_watchdog_action();
+ qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
+ ad = get_watchdog_action(&td);
g_assert(!strcmp(qdict_get_str(ad, "action"), "shutdown"));
qobject_unref(ad);
@@ -333,12 +334,12 @@ static void test_tco_second_timeout_none(void)
stop_tco(&td);
clear_tco_status(&td);
- reset_on_second_timeout(true);
+ reset_on_second_timeout(&td, true);
set_tco_timeout(&td, ticks);
load_tco(&td);
start_tco(&td);
- clock_step(ticks * TCO_TICK_NSEC * 2);
- ad = get_watchdog_action();
+ qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
+ ad = get_watchdog_action(&td);
g_assert(!strcmp(qdict_get_str(ad, "action"), "none"));
qobject_unref(ad);
@@ -358,7 +359,7 @@ static void test_tco_ticks_counter(void)
stop_tco(&d);
clear_tco_status(&d);
- reset_on_second_timeout(false);
+ reset_on_second_timeout(&d, false);
set_tco_timeout(&d, ticks);
load_tco(&d);
start_tco(&d);
@@ -366,7 +367,7 @@ static void test_tco_ticks_counter(void)
do {
rld = qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD) & TCO_RLD_MASK;
g_assert_cmpint(rld, ==, ticks);
- clock_step(TCO_TICK_NSEC);
+ qtest_clock_step(d.qts, TCO_TICK_NSEC);
ticks--;
} while (!(qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS) & TCO_TIMEOUT));
@@ -405,11 +406,11 @@ static void test_tco1_status_bits(void)
stop_tco(&d);
clear_tco_status(&d);
- reset_on_second_timeout(false);
+ reset_on_second_timeout(&d, false);
set_tco_timeout(&d, ticks);
load_tco(&d);
start_tco(&d);
- clock_step(ticks * TCO_TICK_NSEC);
+ qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC);
qpci_io_writeb(d.dev, d.tco_io_bar, TCO_DAT_IN, 0);
qpci_io_writeb(d.dev, d.tco_io_bar, TCO_DAT_OUT, 0);
@@ -434,11 +435,11 @@ static void test_tco2_status_bits(void)
stop_tco(&d);
clear_tco_status(&d);
- reset_on_second_timeout(true);
+ reset_on_second_timeout(&d, true);
set_tco_timeout(&d, ticks);
load_tco(&d);
start_tco(&d);
- clock_step(ticks * TCO_TICK_NSEC * 2);
+ qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC * 2);
val = qpci_io_readw(d.dev, d.tco_io_bar, TCO2_STS);
ret = val & (TCO_SECOND_TO_STS | TCO_BOOT_STS) ? 1 : 0;
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
index 97ac0b159d..036ed9a3b3 100644
--- a/tests/test-block-iothread.c
+++ b/tests/test-block-iothread.c
@@ -354,6 +354,111 @@ static void test_sync_op(const void *opaque)
blk_unref(blk);
}
+typedef struct TestBlockJob {
+ BlockJob common;
+ bool should_complete;
+ int n;
+} TestBlockJob;
+
+static int test_job_prepare(Job *job)
+{
+ g_assert(qemu_get_current_aio_context() == qemu_get_aio_context());
+ return 0;
+}
+
+static int coroutine_fn test_job_run(Job *job, Error **errp)
+{
+ TestBlockJob *s = container_of(job, TestBlockJob, common.job);
+
+ job_transition_to_ready(&s->common.job);
+ while (!s->should_complete) {
+ s->n++;
+ g_assert(qemu_get_current_aio_context() == job->aio_context);
+
+ /* Avoid job_sleep_ns() because it marks the job as !busy. We want to
+ * emulate some actual activity (probably some I/O) here so that the
+ * drain involved in AioContext switches has to wait for this activity
+ * to stop. */
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000);
+
+ job_pause_point(&s->common.job);
+ }
+
+ g_assert(qemu_get_current_aio_context() == job->aio_context);
+ return 0;
+}
+
+static void test_job_complete(Job *job, Error **errp)
+{
+ TestBlockJob *s = container_of(job, TestBlockJob, common.job);
+ s->should_complete = true;
+}
+
+BlockJobDriver test_job_driver = {
+ .job_driver = {
+ .instance_size = sizeof(TestBlockJob),
+ .free = block_job_free,
+ .user_resume = block_job_user_resume,
+ .drain = block_job_drain,
+ .run = test_job_run,
+ .complete = test_job_complete,
+ .prepare = test_job_prepare,
+ },
+};
+
+static void test_attach_blockjob(void)
+{
+ IOThread *iothread = iothread_new();
+ AioContext *ctx = iothread_get_aio_context(iothread);
+ BlockBackend *blk;
+ BlockDriverState *bs;
+ TestBlockJob *tjob;
+
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
+ bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
+ blk_insert_bs(blk, bs, &error_abort);
+
+ tjob = block_job_create("job0", &test_job_driver, NULL, bs,
+ 0, BLK_PERM_ALL,
+ 0, 0, NULL, NULL, &error_abort);
+ job_start(&tjob->common.job);
+
+ while (tjob->n == 0) {
+ aio_poll(qemu_get_aio_context(), false);
+ }
+
+ blk_set_aio_context(blk, ctx);
+
+ tjob->n = 0;
+ while (tjob->n == 0) {
+ aio_poll(qemu_get_aio_context(), false);
+ }
+
+ aio_context_acquire(ctx);
+ blk_set_aio_context(blk, qemu_get_aio_context());
+ aio_context_release(ctx);
+
+ tjob->n = 0;
+ while (tjob->n == 0) {
+ aio_poll(qemu_get_aio_context(), false);
+ }
+
+ blk_set_aio_context(blk, ctx);
+
+ tjob->n = 0;
+ while (tjob->n == 0) {
+ aio_poll(qemu_get_aio_context(), false);
+ }
+
+ aio_context_acquire(ctx);
+ job_complete_sync(&tjob->common.job, &error_abort);
+ blk_set_aio_context(blk, qemu_get_aio_context());
+ aio_context_release(ctx);
+
+ bdrv_unref(bs);
+ blk_unref(blk);
+}
+
int main(int argc, char **argv)
{
int i;
@@ -368,5 +473,7 @@ int main(int argc, char **argv)
g_test_add_data_func(t->name, t, test_sync_op);
}
+ g_test_add_func("/attach/blockjob", test_attach_blockjob);
+
return g_test_run();
}
diff --git a/tests/test-hmp.c b/tests/test-hmp.c
index e344947f7c..5029c4d2c9 100644
--- a/tests/test-hmp.c
+++ b/tests/test-hmp.c
@@ -73,13 +73,13 @@ static const char *hmp_cmds[] = {
};
/* Run through the list of pre-defined commands */
-static void test_commands(void)
+static void test_commands(QTestState *qts)
{
char *response;
int i;
for (i = 0; hmp_cmds[i] != NULL; i++) {
- response = hmp("%s", hmp_cmds[i]);
+ response = qtest_hmp(qts, "%s", hmp_cmds[i]);
if (verbose) {
fprintf(stderr,
"\texecute HMP command: %s\n"
@@ -92,11 +92,11 @@ static void test_commands(void)
}
/* Run through all info commands and call them blindly (without arguments) */
-static void test_info_commands(void)
+static void test_info_commands(QTestState *qts)
{
char *resp, *info, *info_buf, *endp;
- info_buf = info = hmp("help info");
+ info_buf = info = qtest_hmp(qts, "help info");
while (*info) {
/* Extract the info command, ignore parameters and description */
@@ -108,7 +108,7 @@ static void test_info_commands(void)
if (verbose) {
fprintf(stderr, "\t%s\n", info);
}
- resp = hmp("%s", info);
+ resp = qtest_hmp(qts, "%s", info);
g_free(resp);
/* And move forward to the next line */
info = strchr(endp + 1, '\n');
@@ -125,14 +125,15 @@ static void test_machine(gconstpointer data)
{
const char *machine = data;
char *args;
+ QTestState *qts;
args = g_strdup_printf("-S -M %s", machine);
- qtest_start(args);
+ qts = qtest_init(args);
- test_info_commands();
- test_commands();
+ test_info_commands(qts);
+ test_commands(qts);
- qtest_end();
+ qtest_quit(qts);
g_free(args);
g_free((void *)data);
}
diff --git a/tests/tpm-tests.c b/tests/tpm-tests.c
index 582ec0cfd4..e640777aa9 100644
--- a/tests/tpm-tests.c
+++ b/tests/tpm-tests.c
@@ -22,7 +22,7 @@ static bool
tpm_test_swtpm_skip(void)
{
if (!tpm_util_swtpm_has_tpm2()) {
- g_test_message("swtpm not in PATH or missing --tpm2 support");
+ g_test_skip("swtpm not in PATH or missing --tpm2 support");
return true;
}
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index b65365934b..fe1168a90a 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -679,6 +679,7 @@ static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
{
QVirtioPCIDevice *dev1 = obj;
QVirtioPCIDevice *dev;
+ QTestState *qts = dev1->pdev->bus->qts;
/* plug secondary disk */
qtest_qmp_device_add("virtio-blk-pci", "drv1",
@@ -693,7 +694,7 @@ static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
qos_object_destroy((QOSGraphObject *)dev);
/* unplug secondary disk */
- qpci_unplug_acpi_device_test("drv1", PCI_SLOT_HP);
+ qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
}
/*
diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c
index 0d956f36fe..163126cf07 100644
--- a/tests/virtio-net-test.c
+++ b/tests/virtio-net-test.c
@@ -162,13 +162,15 @@ static void stop_cont_test(void *obj, void *data, QGuestAllocator *t_alloc)
static void hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
{
+ QVirtioPCIDevice *dev = obj;
+ QTestState *qts = dev->pdev->bus->qts;
const char *arch = qtest_get_arch();
qtest_qmp_device_add("virtio-net-pci", "net1",
"{'addr': %s}", stringify(PCI_SLOT_HP));
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
- qpci_unplug_acpi_device_test("net1", PCI_SLOT_HP);
+ qpci_unplug_acpi_device_test(qts, "net1", PCI_SLOT_HP);
}
}
diff --git a/tests/virtio-rng-test.c b/tests/virtio-rng-test.c
index 5309c7c8ab..fcb22481bd 100644
--- a/tests/virtio-rng-test.c
+++ b/tests/virtio-rng-test.c
@@ -16,13 +16,16 @@
static void rng_hotplug(void *obj, void *data, QGuestAllocator *alloc)
{
+ QVirtioPCIDevice *dev = obj;
+ QTestState *qts = dev->pdev->bus->qts;
+
const char *arch = qtest_get_arch();
qtest_qmp_device_add("virtio-rng-pci", "rng1",
"{'addr': %s}", stringify(PCI_SLOT_HP));
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
- qpci_unplug_acpi_device_test("rng1", PCI_SLOT_HP);
+ qpci_unplug_acpi_device_test(qts, "rng1", PCI_SLOT_HP);
}
}
diff --git a/util/aio-posix.c b/util/aio-posix.c
index 6fbfa7924f..db11021287 100644
--- a/util/aio-posix.c
+++ b/util/aio-posix.c
@@ -519,6 +519,10 @@ static bool run_poll_handlers_once(AioContext *ctx, int64_t *timeout)
if (!node->deleted && node->io_poll &&
aio_node_check(ctx, node->is_external) &&
node->io_poll(node->opaque)) {
+ /*
+ * Polling was successful, exit try_poll_mode immediately
+ * to adjust the next polling time.
+ */
*timeout = 0;
if (node->opaque != &ctx->notifier) {
progress = true;
@@ -558,8 +562,9 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns, int64_t *timeout)
do {
progress = run_poll_handlers_once(ctx, timeout);
elapsed_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start_time;
- } while (!progress && elapsed_time < max_ns
- && !atomic_read(&ctx->poll_disable_cnt));
+ max_ns = qemu_soonest_timeout(*timeout, max_ns);
+ assert(!(max_ns && progress));
+ } while (elapsed_time < max_ns && !atomic_read(&ctx->poll_disable_cnt));
/* If time has passed with no successful polling, adjust *timeout to
* keep the same ending time.
@@ -585,8 +590,7 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns, int64_t *timeout)
*/
static bool try_poll_mode(AioContext *ctx, int64_t *timeout)
{
- /* See qemu_soonest_timeout() uint64_t hack */
- int64_t max_ns = MIN((uint64_t)*timeout, (uint64_t)ctx->poll_ns);
+ int64_t max_ns = qemu_soonest_timeout(*timeout, ctx->poll_ns);
if (max_ns && !atomic_read(&ctx->poll_disable_cnt)) {
poll_set_started(ctx, true);
diff --git a/util/cacheinfo.c b/util/cacheinfo.c
index 3cd080b83d..eebe1ce9c5 100644
--- a/util/cacheinfo.c
+++ b/util/cacheinfo.c
@@ -107,7 +107,7 @@ static void sys_cache_info(int *isize, int *dsize)
static void arch_cache_info(int *isize, int *dsize)
{
if (*isize == 0 || *dsize == 0) {
- unsigned long ctr;
+ uint64_t ctr;
/* The real cache geometry is in CCSIDR_EL1/CLIDR_EL1/CSSELR_EL1,
but (at least under Linux) these are marked protected by the
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 9705051690..ba6335e71a 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -830,6 +830,7 @@ static int unix_listen_saddr(UnixSocketAddress *saddr,
int sock, fd;
char *pathbuf = NULL;
const char *path;
+ size_t pathlen;
sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
@@ -845,7 +846,8 @@ static int unix_listen_saddr(UnixSocketAddress *saddr,
path = pathbuf = g_strdup_printf("%s/qemu-socket-XXXXXX", tmpdir);
}
- if (strlen(path) > sizeof(un.sun_path)) {
+ pathlen = strlen(path);
+ if (pathlen > sizeof(un.sun_path)) {
error_setg(errp, "UNIX socket path '%s' is too long", path);
error_append_hint(errp, "Path must be less than %zu bytes\n",
sizeof(un.sun_path));
@@ -877,7 +879,7 @@ static int unix_listen_saddr(UnixSocketAddress *saddr,
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
- strncpy(un.sun_path, path, sizeof(un.sun_path));
+ memcpy(un.sun_path, path, pathlen);
if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
error_setg_errno(errp, errno, "Failed to bind socket to %s", path);
@@ -901,6 +903,7 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp)
{
struct sockaddr_un un;
int sock, rc;
+ size_t pathlen;
if (saddr->path == NULL) {
error_setg(errp, "unix connect: no path specified");
@@ -913,7 +916,8 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp)
return -1;
}
- if (strlen(saddr->path) > sizeof(un.sun_path)) {
+ pathlen = strlen(saddr->path);
+ if (pathlen > sizeof(un.sun_path)) {
error_setg(errp, "UNIX socket path '%s' is too long", saddr->path);
error_append_hint(errp, "Path must be less than %zu bytes\n",
sizeof(un.sun_path));
@@ -922,7 +926,7 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp)
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
- strncpy(un.sun_path, saddr->path, sizeof(un.sun_path));
+ memcpy(un.sun_path, saddr->path, pathlen);
/* connect to peer */
do {
diff --git a/util/readline.c b/util/readline.c
index ec91ee0fea..a7672b51c1 100644
--- a/util/readline.c
+++ b/util/readline.c
@@ -48,14 +48,15 @@ static void readline_update(ReadLineState *rs)
if (rs->cmd_buf_size != rs->last_cmd_buf_size ||
memcmp(rs->cmd_buf, rs->last_cmd_buf, rs->cmd_buf_size) != 0) {
- for(i = 0; i < rs->last_cmd_buf_index; i++) {
+ for (i = 0; i < rs->last_cmd_buf_index; i++) {
rs->printf_func(rs->opaque, "\033[D");
}
rs->cmd_buf[rs->cmd_buf_size] = '\0';
if (rs->read_password) {
len = strlen(rs->cmd_buf);
- for(i = 0; i < len; i++)
+ for (i = 0; i < len; i++) {
rs->printf_func(rs->opaque, "*");
+ }
} else {
rs->printf_func(rs->opaque, "%s", rs->cmd_buf);
}
@@ -67,12 +68,12 @@ static void readline_update(ReadLineState *rs)
if (rs->cmd_buf_index != rs->last_cmd_buf_index) {
delta = rs->cmd_buf_index - rs->last_cmd_buf_index;
if (delta > 0) {
- for(i = 0;i < delta; i++) {
+ for (i = 0; i < delta; i++) {
rs->printf_func(rs->opaque, "\033[C");
}
} else {
delta = -delta;
- for(i = 0;i < delta; i++) {
+ for (i = 0; i < delta; i++) {
rs->printf_func(rs->opaque, "\033[D");
}
}
@@ -178,35 +179,38 @@ static void readline_up_char(ReadLineState *rs)
{
int idx;
- if (rs->hist_entry == 0)
- return;
+ if (rs->hist_entry == 0) {
+ return;
+ }
if (rs->hist_entry == -1) {
- /* Find latest entry */
- for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
- if (rs->history[idx] == NULL)
- break;
- }
- rs->hist_entry = idx;
+ /* Find latest entry */
+ for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
+ if (rs->history[idx] == NULL) {
+ break;
+ }
+ }
+ rs->hist_entry = idx;
}
rs->hist_entry--;
if (rs->hist_entry >= 0) {
- pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
+ pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
rs->history[rs->hist_entry]);
- rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
+ rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
}
}
static void readline_down_char(ReadLineState *rs)
{
- if (rs->hist_entry == -1)
+ if (rs->hist_entry == -1) {
return;
+ }
if (rs->hist_entry < READLINE_MAX_CMDS - 1 &&
rs->history[++rs->hist_entry] != NULL) {
- pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
+ pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
rs->history[rs->hist_entry]);
} else {
rs->cmd_buf[0] = 0;
- rs->hist_entry = -1;
+ rs->hist_entry = -1;
}
rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
}
@@ -216,46 +220,50 @@ static void readline_hist_add(ReadLineState *rs, const char *cmdline)
char *hist_entry, *new_entry;
int idx;
- if (cmdline[0] == '\0')
- return;
+ if (cmdline[0] == '\0') {
+ return;
+ }
new_entry = NULL;
if (rs->hist_entry != -1) {
- /* We were editing an existing history entry: replace it */
- hist_entry = rs->history[rs->hist_entry];
- idx = rs->hist_entry;
- if (strcmp(hist_entry, cmdline) == 0) {
- goto same_entry;
- }
+ /* We were editing an existing history entry: replace it */
+ hist_entry = rs->history[rs->hist_entry];
+ idx = rs->hist_entry;
+ if (strcmp(hist_entry, cmdline) == 0) {
+ goto same_entry;
+ }
}
/* Search cmdline in history buffers */
for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
- hist_entry = rs->history[idx];
- if (hist_entry == NULL)
- break;
- if (strcmp(hist_entry, cmdline) == 0) {
- same_entry:
- new_entry = hist_entry;
- /* Put this entry at the end of history */
- memmove(&rs->history[idx], &rs->history[idx + 1],
- (READLINE_MAX_CMDS - (idx + 1)) * sizeof(char *));
- rs->history[READLINE_MAX_CMDS - 1] = NULL;
- for (; idx < READLINE_MAX_CMDS; idx++) {
- if (rs->history[idx] == NULL)
- break;
- }
- break;
- }
+ hist_entry = rs->history[idx];
+ if (hist_entry == NULL) {
+ break;
+ }
+ if (strcmp(hist_entry, cmdline) == 0) {
+ same_entry:
+ new_entry = hist_entry;
+ /* Put this entry at the end of history */
+ memmove(&rs->history[idx], &rs->history[idx + 1],
+ (READLINE_MAX_CMDS - (idx + 1)) * sizeof(char *));
+ rs->history[READLINE_MAX_CMDS - 1] = NULL;
+ for (; idx < READLINE_MAX_CMDS; idx++) {
+ if (rs->history[idx] == NULL) {
+ break;
+ }
+ }
+ break;
+ }
}
if (idx == READLINE_MAX_CMDS) {
- /* Need to get one free slot */
+ /* Need to get one free slot */
g_free(rs->history[0]);
- memmove(rs->history, &rs->history[1],
- (READLINE_MAX_CMDS - 1) * sizeof(char *));
- rs->history[READLINE_MAX_CMDS - 1] = NULL;
- idx = READLINE_MAX_CMDS - 1;
+ memmove(rs->history, &rs->history[1],
+ (READLINE_MAX_CMDS - 1) * sizeof(char *));
+ rs->history[READLINE_MAX_CMDS - 1] = NULL;
+ idx = READLINE_MAX_CMDS - 1;
}
- if (new_entry == NULL)
+ if (new_entry == NULL) {
new_entry = g_strdup(cmdline);
+ }
rs->history[idx] = new_entry;
rs->hist_entry = -1;
}
@@ -297,49 +305,55 @@ static void readline_completion(ReadLineState *rs)
g_free(cmdline);
/* no completion found */
- if (rs->nb_completions <= 0)
+ if (rs->nb_completions <= 0) {
return;
+ }
if (rs->nb_completions == 1) {
len = strlen(rs->completions[0]);
- for(i = rs->completion_index; i < len; i++) {
+ for (i = rs->completion_index; i < len; i++) {
readline_insert_char(rs, rs->completions[0][i]);
}
/* extra space for next argument. XXX: make it more generic */
- if (len > 0 && rs->completions[0][len - 1] != '/')
+ if (len > 0 && rs->completions[0][len - 1] != '/') {
readline_insert_char(rs, ' ');
+ }
} else {
qsort(rs->completions, rs->nb_completions, sizeof(char *),
completion_comp);
rs->printf_func(rs->opaque, "\n");
max_width = 0;
- max_prefix = 0;
- for(i = 0; i < rs->nb_completions; i++) {
+ max_prefix = 0;
+ for (i = 0; i < rs->nb_completions; i++) {
len = strlen(rs->completions[i]);
- if (i==0) {
+ if (i == 0) {
max_prefix = len;
} else {
- if (len < max_prefix)
+ if (len < max_prefix) {
max_prefix = len;
- for(j=0; j<max_prefix; j++) {
- if (rs->completions[i][j] != rs->completions[0][j])
+ }
+ for (j = 0; j < max_prefix; j++) {
+ if (rs->completions[i][j] != rs->completions[0][j]) {
max_prefix = j;
+ }
}
}
- if (len > max_width)
+ if (len > max_width) {
max_width = len;
+ }
}
- if (max_prefix > 0)
- for(i = rs->completion_index; i < max_prefix; i++) {
+ if (max_prefix > 0)
+ for (i = rs->completion_index; i < max_prefix; i++) {
readline_insert_char(rs, rs->completions[0][i]);
}
max_width += 2;
- if (max_width < 10)
+ if (max_width < 10) {
max_width = 10;
- else if (max_width > 80)
+ } else if (max_width > 80) {
max_width = 80;
+ }
nb_cols = 80 / max_width;
j = 0;
- for(i = 0; i < rs->nb_completions; i++) {
+ for (i = 0; i < rs->nb_completions; i++) {
rs->printf_func(rs->opaque, "%-*s", max_width, rs->completions[i]);
if (++j == nb_cols || i == (rs->nb_completions - 1)) {
rs->printf_func(rs->opaque, "\n");
@@ -362,9 +376,9 @@ static void readline_clear_screen(ReadLineState *rs)
/* return true if command handled */
void readline_handle_byte(ReadLineState *rs, int ch)
{
- switch(rs->esc_state) {
+ switch (rs->esc_state) {
case IS_NORM:
- switch(ch) {
+ switch (ch) {
case 1:
readline_bol(rs);
break;
@@ -383,8 +397,9 @@ void readline_handle_byte(ReadLineState *rs, int ch)
case 10:
case 13:
rs->cmd_buf[rs->cmd_buf_size] = '\0';
- if (!rs->read_password)
+ if (!rs->read_password) {
readline_hist_add(rs, rs->cmd_buf);
+ }
rs->printf_func(rs->opaque, "\n");
rs->cmd_buf_index = 0;
rs->cmd_buf_size = 0;
@@ -403,9 +418,9 @@ void readline_handle_byte(ReadLineState *rs, int ch)
case 8:
readline_backspace(rs);
break;
- case 155:
+ case 155:
rs->esc_state = IS_CSI;
- break;
+ break;
default:
if (ch >= 32) {
readline_insert_char(rs, ch);
@@ -425,15 +440,15 @@ void readline_handle_byte(ReadLineState *rs, int ch)
}
break;
case IS_CSI:
- switch(ch) {
- case 'A':
- case 'F':
- readline_up_char(rs);
- break;
- case 'B':
- case 'E':
- readline_down_char(rs);
- break;
+ switch (ch) {
+ case 'A':
+ case 'F':
+ readline_up_char(rs);
+ break;
+ case 'B':
+ case 'E':
+ readline_down_char(rs);
+ break;
case 'D':
readline_backward_char(rs);
break;
@@ -444,7 +459,7 @@ void readline_handle_byte(ReadLineState *rs, int ch)
rs->esc_param = rs->esc_param * 10 + (ch - '0');
goto the_end;
case '~':
- switch(rs->esc_param) {
+ switch (rs->esc_param) {
case 1:
readline_bol(rs);
break;
@@ -463,7 +478,7 @@ void readline_handle_byte(ReadLineState *rs, int ch)
the_end:
break;
case IS_SS3:
- switch(ch) {
+ switch (ch) {
case 'F':
readline_eol(rs);
break;
@@ -495,8 +510,9 @@ void readline_restart(ReadLineState *rs)
const char *readline_get_history(ReadLineState *rs, unsigned int index)
{
- if (index >= READLINE_MAX_CMDS)
+ if (index >= READLINE_MAX_CMDS) {
return NULL;
+ }
return rs->history[index];
}
diff --git a/vl.c b/vl.c
index d9fea0a119..b6709514c1 100644
--- a/vl.c
+++ b/vl.c
@@ -2015,7 +2015,7 @@ typedef struct VGAInterfaceInfo {
const char *class_names[2];
} VGAInterfaceInfo;
-static VGAInterfaceInfo vga_interfaces[VGA_TYPE_MAX] = {
+static const VGAInterfaceInfo vga_interfaces[VGA_TYPE_MAX] = {
[VGA_NONE] = {
.opt_name = "none",
},
@@ -2061,7 +2061,7 @@ static VGAInterfaceInfo vga_interfaces[VGA_TYPE_MAX] = {
static bool vga_interface_available(VGAInterfaceType t)
{
- VGAInterfaceInfo *ti = &vga_interfaces[t];
+ const VGAInterfaceInfo *ti = &vga_interfaces[t];
assert(t < VGA_TYPE_MAX);
return !ti->class_names[0] ||
@@ -2069,14 +2069,42 @@ static bool vga_interface_available(VGAInterfaceType t)
object_class_by_name(ti->class_names[1]);
}
-static void select_vgahw(const char *p)
+static const char *
+get_default_vga_model(const MachineClass *machine_class)
+{
+ if (machine_class->default_display) {
+ return machine_class->default_display;
+ } else if (vga_interface_available(VGA_CIRRUS)) {
+ return "cirrus";
+ } else if (vga_interface_available(VGA_STD)) {
+ return "std";
+ }
+
+ return NULL;
+}
+
+static void select_vgahw(const MachineClass *machine_class, const char *p)
{
const char *opts;
int t;
+ if (g_str_equal(p, "help")) {
+ const char *def = get_default_vga_model(machine_class);
+
+ for (t = 0; t < VGA_TYPE_MAX; t++) {
+ const VGAInterfaceInfo *ti = &vga_interfaces[t];
+
+ if (vga_interface_available(t) && ti->opt_name) {
+ printf("%-20s %s%s\n", ti->opt_name, ti->name ?: "",
+ g_str_equal(ti->opt_name, def) ? " (default)" : "");
+ }
+ }
+ exit(0);
+ }
+
assert(vga_interface_type == VGA_NONE);
for (t = 0; t < VGA_TYPE_MAX; t++) {
- VGAInterfaceInfo *ti = &vga_interfaces[t];
+ const VGAInterfaceInfo *ti = &vga_interfaces[t];
if (ti->opt_name && strstart(p, ti->opt_name, &opts)) {
if (!vga_interface_available(t)) {
error_report("%s not available", ti->name);
@@ -4424,16 +4452,10 @@ int main(int argc, char **argv, char **envp)
/* If no default VGA is requested, the default is "none". */
if (default_vga) {
- if (machine_class->default_display) {
- vga_model = machine_class->default_display;
- } else if (vga_interface_available(VGA_CIRRUS)) {
- vga_model = "cirrus";
- } else if (vga_interface_available(VGA_STD)) {
- vga_model = "std";
- }
+ vga_model = get_default_vga_model(machine_class);
}
if (vga_model) {
- select_vgahw(vga_model);
+ select_vgahw(machine_class, vga_model);
}
if (watchdog) {