From 1cfd21ccc7576c03914fa48d414451fdd53fb9a5 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 1 Jul 2021 14:06:54 -0500 Subject: [PATCH 001/531] iotests: Improve and rename test 309 to nbd-qemu-allocation Enhance the test to inspect what qemu-nbd is advertising during handshake, and rename it now that we support useful iotest names. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20210701190655.2131223-2-eblake@redhat.com> --- .../qemu-iotests/{309 => tests/nbd-qemu-allocation} | 5 ++++- .../{309.out => tests/nbd-qemu-allocation.out} | 12 +++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) rename tests/qemu-iotests/{309 => tests/nbd-qemu-allocation} (95%) rename tests/qemu-iotests/{309.out => tests/nbd-qemu-allocation.out} (81%) diff --git a/tests/qemu-iotests/309 b/tests/qemu-iotests/tests/nbd-qemu-allocation similarity index 95% rename from tests/qemu-iotests/309 rename to tests/qemu-iotests/tests/nbd-qemu-allocation index b90b279994..4ee73db803 100755 --- a/tests/qemu-iotests/309 +++ b/tests/qemu-iotests/tests/nbd-qemu-allocation @@ -3,7 +3,7 @@ # # Test qemu-nbd -A # -# Copyright (C) 2018-2020 Red Hat, Inc. +# Copyright (C) 2018-2021 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 @@ -32,6 +32,7 @@ _cleanup() trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks +cd .. . ./common.rc . ./common.filter . ./common.nbd @@ -57,6 +58,8 @@ echo $QEMU_IMG map --output=json -f qcow2 "$TEST_IMG" IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket" nbd_server_start_unix_socket -r -f qcow2 -A "$TEST_IMG" +# Inspect what the server is exposing +$QEMU_NBD --list -k $nbd_unix_socket # Normal -f raw NBD block status loses access to allocation information $QEMU_IMG map --output=json --image-opts \ "$IMG" | _filter_qemu_img_map diff --git a/tests/qemu-iotests/309.out b/tests/qemu-iotests/tests/nbd-qemu-allocation.out similarity index 81% rename from tests/qemu-iotests/309.out rename to tests/qemu-iotests/tests/nbd-qemu-allocation.out index db75bb6b0d..c51022b2a3 100644 --- a/tests/qemu-iotests/309.out +++ b/tests/qemu-iotests/tests/nbd-qemu-allocation.out @@ -1,4 +1,4 @@ -QA output created by 309 +QA output created by nbd-qemu-allocation === Initial image setup === @@ -14,6 +14,16 @@ wrote 2097152/2097152 bytes at offset 1048576 [{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}, { "start": 1048576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}, { "start": 3145728, "length": 1048576, "depth": 1, "zero": true, "data": false}] +exports available: 1 + export: '' + size: 4194304 + flags: 0x58f ( readonly flush fua df multi cache ) + min block: 1 + opt block: 4096 + max block: 33554432 + available meta contexts: 2 + base:allocation + qemu:allocation-depth [{ "start": 0, "length": 3145728, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, { "start": 3145728, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] [{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": true, "offset": OFFSET}, From 8417e1378cadb8928c24755a95ff267def53922f Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 1 Jul 2021 14:06:55 -0500 Subject: [PATCH 002/531] qemu-img: Make unallocated part of backing chain obvious in map The recently-added NBD context qemu:allocation-depth is able to distinguish between locally-present data (even when that data is sparse) [shown as depth 1 over NBD], and data that could not be found anywhere in the backing chain [shown as depth 0]; and the libnbd project was recently patched to give the human-readable name "absent" to an allocation-depth of 0. But qemu-img map --output=json predates that addition, and has the unfortunate behavior that all portions of the backing chain that resolve without finding a hit in any backing layer report the same depth as the final backing layer. This makes it harder to reconstruct a qcow2 backing chain using just 'qemu-img map' output, especially when using "backing":null to artificially limit a backing chain, because it is impossible to distinguish between a QCOW2_CLUSTER_UNALLOCATED (which defers to a [missing] backing file) and a QCOW2_CLUSTER_ZERO_PLAIN cluster (which would override any backing file), since both types of clusters otherwise show as "data":false,"zero":true" (but note that we can distinguish a QCOW2_CLUSTER_ZERO_ALLOCATED, which would also have an "offset": listing). The task of reconstructing a qcow2 chain was made harder in commit 0da9856851 (nbd: server: Report holes for raw images), because prior to that point, it was possible to abuse NBD's block status command to see which portions of a qcow2 file resulted in BDRV_BLOCK_ALLOCATED (showing up as NBD_STATE_ZERO in isolation) vs. missing from the chain (showing up as NBD_STATE_ZERO|NBD_STATE_HOLE); but now qemu reports more accurate sparseness information over NBD. An obvious solution is to make 'qemu-img map --output=json' add an additional "present":false designation to any cluster lacking an allocation anywhere in the chain, without any change to the "depth" parameter to avoid breaking existing clients. The iotests have several examples where this distinction demonstrates the additional accuracy. Signed-off-by: Eric Blake Message-Id: <20210701190655.2131223-3-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy [eblake: fix more iotest fallout] Signed-off-by: Eric Blake --- docs/tools/qemu-img.rst | 3 + qapi/block-core.json | 7 +- qemu-img.c | 7 +- tests/qemu-iotests/122.out | 84 +- tests/qemu-iotests/146.out | 780 +++++++++--------- tests/qemu-iotests/154.out | 190 ++--- tests/qemu-iotests/179.out | 133 ++- tests/qemu-iotests/209.out | 4 +- tests/qemu-iotests/211.out | 8 +- tests/qemu-iotests/221.out | 16 +- tests/qemu-iotests/223.out | 56 +- tests/qemu-iotests/241.out | 10 +- tests/qemu-iotests/244.out | 23 +- tests/qemu-iotests/252.out | 10 +- tests/qemu-iotests/253.out | 20 +- tests/qemu-iotests/274.out | 48 +- tests/qemu-iotests/291.out | 24 +- .../tests/nbd-qemu-allocation.out | 16 +- 18 files changed, 749 insertions(+), 690 deletions(-) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index cfe1147879..d6300f7ee0 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -597,6 +597,9 @@ Command description: if false, the sectors are either unallocated or stored as optimized all-zero clusters); - whether the data is known to read as zero (boolean field ``zero``); + - whether the data is actually present (boolean field ``present``); + if false, rebasing the backing chain onto a deeper file would pick + up data from the deeper file; - in order to make the output shorter, the target file is expressed as a ``depth``; for example, a depth of 2 refers to the backing file of the backing file of *FILENAME*. diff --git a/qapi/block-core.json b/qapi/block-core.json index c7a311798a..675d8265eb 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -274,6 +274,9 @@ # images in the chain)) before reaching one for which the # range is allocated # +# @present: true if this layer provides the data, false if adding a backing +# layer could impact this region (since 6.1) +# # @offset: if present, the image file stores the data for this range # in raw format at the given (host) offset # @@ -284,8 +287,8 @@ ## { 'struct': 'MapEntry', 'data': {'start': 'int', 'length': 'int', 'data': 'bool', - 'zero': 'bool', 'depth': 'int', '*offset': 'int', - '*filename': 'str' } } + 'zero': 'bool', 'depth': 'int', 'present': 'bool', + '*offset': 'int', '*filename': 'str' } } ## # @BlockdevCacheInfo: diff --git a/qemu-img.c b/qemu-img.c index 7c4fc60312..797742a443 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2982,8 +2982,9 @@ static int dump_map_entry(OutputFormat output_format, MapEntry *e, break; case OFORMAT_JSON: printf("{ \"start\": %"PRId64", \"length\": %"PRId64"," - " \"depth\": %"PRId64", \"zero\": %s, \"data\": %s", - e->start, e->length, e->depth, + " \"depth\": %"PRId64", \"present\": %s, \"zero\": %s," + " \"data\": %s", e->start, e->length, e->depth, + e->present ? "true" : "false", e->zero ? "true" : "false", e->data ? "true" : "false"); if (e->has_offset) { @@ -3049,6 +3050,7 @@ static int get_block_status(BlockDriverState *bs, int64_t offset, .offset = map, .has_offset = has_offset, .depth = depth, + .present = !!(ret & BDRV_BLOCK_ALLOCATED), .has_filename = filename, .filename = filename, }; @@ -3064,6 +3066,7 @@ static inline bool entry_mergeable(const MapEntry *curr, const MapEntry *next) if (curr->zero != next->zero || curr->data != next->data || curr->depth != next->depth || + curr->present != next->present || curr->has_filename != next->has_filename || curr->has_offset != next->has_offset) { return false; diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out index 3a3e121d57..8fbdac2b39 100644 --- a/tests/qemu-iotests/122.out +++ b/tests/qemu-iotests/122.out @@ -67,12 +67,12 @@ read 65536/65536 bytes at offset 4194304 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 65536/65536 bytes at offset 8388608 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 65536, "depth": 0, "zero": false, "data": true}, -{ "start": 65536, "length": 4128768, "depth": 0, "zero": true, "data": false}, -{ "start": 4194304, "length": 65536, "depth": 0, "zero": false, "data": true}, -{ "start": 4259840, "length": 4128768, "depth": 0, "zero": true, "data": false}, -{ "start": 8388608, "length": 65536, "depth": 0, "zero": false, "data": true}, -{ "start": 8454144, "length": 4128768, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true}, +{ "start": 65536, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 4194304, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true}, +{ "start": 4259840, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 8388608, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true}, +{ "start": 8454144, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false}] read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 65536/65536 bytes at offset 4194304 @@ -94,12 +94,12 @@ wrote 1024/1024 bytes at offset 1046528 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1024/1024 bytes at offset 0 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 65536, "depth": 0, "zero": false, "data": true}, -{ "start": 65536, "length": 65536, "depth": 0, "zero": true, "data": false}, -{ "start": 131072, "length": 196608, "depth": 0, "zero": false, "data": true}, -{ "start": 327680, "length": 655360, "depth": 0, "zero": true, "data": false}, -{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true}, -{ "start": 1048576, "length": 1046528, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true}, +{ "start": 65536, "length": 65536, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 131072, "length": 196608, "depth": 0, "present": true, "zero": false, "data": true}, +{ "start": 327680, "length": 655360, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true}, +{ "start": 1048576, "length": 1046528, "depth": 0, "present": false, "zero": true, "data": false}] read 16384/16384 bytes at offset 0 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 16384/16384 bytes at offset 16384 @@ -130,14 +130,14 @@ read 3145728/3145728 bytes at offset 0 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 63963136/63963136 bytes at offset 3145728 61 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 67108864, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] convert -c -S 0: read 3145728/3145728 bytes at offset 0 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 63963136/63963136 bytes at offset 3145728 61 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 67108864, "depth": 0, "zero": false, "data": true}] +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true}] Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 wrote 33554432/33554432 bytes at offset 0 32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -152,7 +152,7 @@ read 30408704/30408704 bytes at offset 3145728 29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 33554432/33554432 bytes at offset 33554432 32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 67108864, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] convert -c -S 0 with source backing file: read 3145728/3145728 bytes at offset 0 @@ -161,7 +161,7 @@ read 30408704/30408704 bytes at offset 3145728 29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 33554432/33554432 bytes at offset 33554432 32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 67108864, "depth": 0, "zero": false, "data": true}] +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true}] convert -S 0 -B ... read 3145728/3145728 bytes at offset 0 @@ -170,7 +170,7 @@ read 30408704/30408704 bytes at offset 3145728 29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 33554432/33554432 bytes at offset 33554432 32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 67108864, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] convert -c -S 0 -B ... read 3145728/3145728 bytes at offset 0 @@ -179,7 +179,7 @@ read 30408704/30408704 bytes at offset 3145728 29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 33554432/33554432 bytes at offset 33554432 32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 67108864, "depth": 0, "zero": false, "data": true}] +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true}] === Non-zero -S === @@ -194,32 +194,32 @@ wrote 1024/1024 bytes at offset 17408 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) convert -S 4k -[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 4096, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 8192, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 12288, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 16384, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 20480, "length": 67088384, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 12288, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 20480, "length": 67088384, "depth": 0, "present": false, "zero": true, "data": false}] convert -c -S 4k -[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true}, -{ "start": 1024, "length": 7168, "depth": 0, "zero": true, "data": false}, -{ "start": 8192, "length": 1024, "depth": 0, "zero": false, "data": true}, -{ "start": 9216, "length": 8192, "depth": 0, "zero": true, "data": false}, -{ "start": 17408, "length": 1024, "depth": 0, "zero": false, "data": true}, -{ "start": 18432, "length": 67090432, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, +{ "start": 1024, "length": 7168, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 8192, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, +{ "start": 9216, "length": 8192, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 17408, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, +{ "start": 18432, "length": 67090432, "depth": 0, "present": false, "zero": true, "data": false}] convert -S 8k -[{ "start": 0, "length": 24576, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 24576, "length": 67084288, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 24576, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 24576, "length": 67084288, "depth": 0, "present": false, "zero": true, "data": false}] convert -c -S 8k -[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true}, -{ "start": 1024, "length": 7168, "depth": 0, "zero": true, "data": false}, -{ "start": 8192, "length": 1024, "depth": 0, "zero": false, "data": true}, -{ "start": 9216, "length": 8192, "depth": 0, "zero": true, "data": false}, -{ "start": 17408, "length": 1024, "depth": 0, "zero": false, "data": true}, -{ "start": 18432, "length": 67090432, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, +{ "start": 1024, "length": 7168, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 8192, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, +{ "start": 9216, "length": 8192, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 17408, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, +{ "start": 18432, "length": 67090432, "depth": 0, "present": false, "zero": true, "data": false}] === -n to a non-zero image === @@ -233,18 +233,18 @@ Images are identical. Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 67108864, "depth": 0, "present": false, "zero": true, "data": false}] === -n to an empty image with a backing file === Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT -[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT -[{ "start": 0, "length": 67108864, "depth": 0, "zero": false, "data": true, "offset": 327680}] +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}] === -n -B to an image without a backing file === diff --git a/tests/qemu-iotests/146.out b/tests/qemu-iotests/146.out index c67ba4ba7c..dfd6c77140 100644 --- a/tests/qemu-iotests/146.out +++ b/tests/qemu-iotests/146.out @@ -2,414 +2,414 @@ QA output created by 146 === Testing VPC Autodetect === -[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false}] === Testing VPC with current_size force === -[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false}] === Testing VPC with chs force === -[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false}] === Testing Hyper-V Autodetect === -[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false}] === Testing Hyper-V with current_size force === -[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false}] === Testing Hyper-V with chs force === -[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false}] === Testing d2v Autodetect === -[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] === Testing d2v with current_size force === -[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] === Testing d2v with chs force === -[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] === Testing Image create, default === @@ -417,15 +417,15 @@ Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296 === Read created image, default opts ==== -[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false}] === Read created image, force_size_calc=chs ==== -[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false}] === Read created image, force_size_calc=current_size ==== -[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false}] === Testing Image create, force_size === @@ -433,13 +433,13 @@ Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296 === Read created image, default opts ==== -[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false}] === Read created image, force_size_calc=chs ==== -[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false}] === Read created image, force_size_calc=current_size ==== -[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false}] *** done diff --git a/tests/qemu-iotests/154.out b/tests/qemu-iotests/154.out index 4863e24838..1fa7ffc475 100644 --- a/tests/qemu-iotests/154.out +++ b/tests/qemu-iotests/154.out @@ -11,14 +11,14 @@ wrote 2048/2048 bytes at offset 17408 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2048/2048 bytes at offset 27648 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 4096, "length": 4096, "depth": 1, "zero": true, "data": false}, -{ "start": 8192, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 12288, "length": 4096, "depth": 1, "zero": true, "data": false}, -{ "start": 16384, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 20480, "length": 4096, "depth": 1, "zero": true, "data": false}, -{ "start": 24576, "length": 8192, "depth": 0, "zero": true, "data": false}, -{ "start": 32768, "length": 134184960, "depth": 1, "zero": true, "data": false}] +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 4096, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 12288, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 20480, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 24576, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 32768, "length": 134184960, "depth": 1, "present": false, "zero": true, "data": false}] == backing file contains non-zero data before write_zeroes == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 @@ -41,11 +41,11 @@ read 1024/1024 bytes at offset 65536 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 2048/2048 bytes at offset 67584 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 32768, "depth": 1, "zero": true, "data": false}, -{ "start": 32768, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 36864, "length": 28672, "depth": 1, "zero": true, "data": false}, -{ "start": 65536, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 69632, "length": 134148096, "depth": 1, "zero": true, "data": false}] +[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 36864, "length": 28672, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 69632, "length": 134148096, "depth": 1, "present": false, "zero": true, "data": false}] == backing file contains non-zero data after write_zeroes == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 @@ -68,11 +68,11 @@ read 1024/1024 bytes at offset 44032 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 3072/3072 bytes at offset 40960 3 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 32768, "depth": 1, "zero": true, "data": false}, -{ "start": 32768, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 36864, "length": 4096, "depth": 1, "zero": true, "data": false}, -{ "start": 40960, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 45056, "length": 134172672, "depth": 1, "zero": true, "data": false}] +[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 36864, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 40960, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 45056, "length": 134172672, "depth": 1, "present": false, "zero": true, "data": false}] == write_zeroes covers non-zero data == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 @@ -101,15 +101,15 @@ wrote 2048/2048 bytes at offset 29696 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 4096/4096 bytes at offset 28672 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 4096, "depth": 1, "zero": true, "data": false}, -{ "start": 4096, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 8192, "length": 4096, "depth": 1, "zero": true, "data": false}, -{ "start": 12288, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 16384, "length": 4096, "depth": 1, "zero": true, "data": false}, -{ "start": 20480, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 24576, "length": 4096, "depth": 1, "zero": true, "data": false}, -{ "start": 28672, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 32768, "length": 134184960, "depth": 1, "zero": true, "data": false}] +[{ "start": 0, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 4096, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 8192, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 12288, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 16384, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 20480, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 24576, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 28672, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 32768, "length": 134184960, "depth": 1, "present": false, "zero": true, "data": false}] == spanning two clusters, non-zero before request == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 @@ -142,16 +142,16 @@ read 1024/1024 bytes at offset 67584 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 5120/5120 bytes at offset 68608 5 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 32768, "depth": 1, "zero": true, "data": false}, -{ "start": 32768, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 36864, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 40960, "length": 8192, "depth": 1, "zero": true, "data": false}, -{ "start": 49152, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 53248, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 57344, "length": 8192, "depth": 1, "zero": true, "data": false}, -{ "start": 65536, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 69632, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 73728, "length": 134144000, "depth": 1, "zero": true, "data": false}] +[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 36864, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 40960, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 49152, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 53248, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 57344, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 73728, "length": 134144000, "depth": 1, "present": false, "zero": true, "data": false}] == spanning two clusters, non-zero after request == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 @@ -184,16 +184,16 @@ read 7168/7168 bytes at offset 65536 7 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 1024/1024 bytes at offset 72704 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 32768, "depth": 1, "zero": true, "data": false}, -{ "start": 32768, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 36864, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 40960, "length": 8192, "depth": 1, "zero": true, "data": false}, -{ "start": 49152, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 53248, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 57344, "length": 8192, "depth": 1, "zero": true, "data": false}, -{ "start": 65536, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 69632, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 73728, "length": 134144000, "depth": 1, "zero": true, "data": false}] +[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 36864, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 40960, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 49152, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 53248, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 57344, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 73728, "length": 134144000, "depth": 1, "present": false, "zero": true, "data": false}] == spanning two clusters, partially overwriting backing file == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 @@ -212,8 +212,8 @@ read 1024/1024 bytes at offset 5120 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 2048/2048 bytes at offset 6144 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 8192, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 8192, "length": 134209536, "depth": 1, "zero": true, "data": false}] +[{ "start": 0, "length": 8192, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 8192, "length": 134209536, "depth": 1, "present": false, "zero": true, "data": false}] == spanning multiple clusters, non-zero in first cluster == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 @@ -226,10 +226,10 @@ read 2048/2048 bytes at offset 65536 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 10240/10240 bytes at offset 67584 10 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 65536, "depth": 1, "zero": true, "data": false}, -{ "start": 65536, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 69632, "length": 8192, "depth": 0, "zero": true, "data": false}, -{ "start": 77824, "length": 134139904, "depth": 1, "zero": true, "data": false}] +[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 69632, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false}] == spanning multiple clusters, non-zero in intermediate cluster == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 @@ -240,9 +240,9 @@ wrote 7168/7168 bytes at offset 67584 7 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 12288/12288 bytes at offset 65536 12 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 65536, "depth": 1, "zero": true, "data": false}, -{ "start": 65536, "length": 12288, "depth": 0, "zero": true, "data": false}, -{ "start": 77824, "length": 134139904, "depth": 1, "zero": true, "data": false}] +[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 65536, "length": 12288, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false}] == spanning multiple clusters, non-zero in final cluster == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 @@ -255,10 +255,10 @@ read 10240/10240 bytes at offset 65536 10 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 2048/2048 bytes at offset 75776 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 65536, "depth": 1, "zero": true, "data": false}, -{ "start": 65536, "length": 8192, "depth": 0, "zero": true, "data": false}, -{ "start": 73728, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 77824, "length": 134139904, "depth": 1, "zero": true, "data": false}] +[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 65536, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 73728, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false}] == spanning multiple clusters, partially overwriting backing file == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 @@ -277,84 +277,88 @@ read 2048/2048 bytes at offset 74752 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 1024/1024 bytes at offset 76800 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 65536, "depth": 1, "zero": true, "data": false}, -{ "start": 65536, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 69632, "length": 4096, "depth": 0, "zero": true, "data": false}, -{ "start": 73728, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 77824, "length": 134139904, "depth": 1, "zero": true, "data": false}] +[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 73728, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false}] == unaligned image tail cluster, no allocation needed == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 wrote 512/512 bytes at offset 134217728 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB -[{ "start": 0, "length": 134219776, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 wrote 512/512 bytes at offset 134219264 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB -[{ "start": 0, "length": 134219776, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 wrote 1024/1024 bytes at offset 134218240 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB -[{ "start": 0, "length": 134219776, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 wrote 2048/2048 bytes at offset 134217728 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB -[{ "start": 0, "length": 134219776, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134218752 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 512/512 bytes at offset 134217728 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB -[{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, -{ "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 512/512 bytes at offset 134219264 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB -[{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, -{ "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 1024/1024 bytes at offset 134218240 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB -[{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, -{ "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 2048/2048 bytes at offset 134217728 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB -[{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, -{ "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] wrote 512/512 bytes at offset 134217728 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 512/512 bytes at offset 134217728 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB -[{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, -{ "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 512/512 bytes at offset 134219264 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB -[{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, -{ "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 1024/1024 bytes at offset 134218240 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB -[{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, -{ "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 2048/2048 bytes at offset 134217728 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB -[{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, -{ "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134218752 wrote 1024/1024 bytes at offset 134217728 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -365,15 +369,15 @@ read 512/512 bytes at offset 134217728 read 512/512 bytes at offset 134218240 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 1024/1024 bytes allocated at offset 128 MiB -[{ "start": 0, "length": 134217728, "depth": 0, "zero": true, "data": false}, -{ "start": 134217728, "length": 1024, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] wrote 1024/1024 bytes at offset 134217728 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 1024/1024 bytes allocated at offset 128 MiB read 1024/1024 bytes at offset 134217728 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 134217728, "depth": 0, "zero": true, "data": false}, -{ "start": 134217728, "length": 1024, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] +[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 1024, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] == unaligned image tail cluster, allocation required == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134218752 @@ -386,8 +390,8 @@ read 512/512 bytes at offset 134217728 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 1536/1536 bytes at offset 134218240 1.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, -{ "start": 134217728, "length": 2048, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134218752 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 512/512 bytes at offset 134218240 @@ -408,6 +412,6 @@ read 512/512 bytes at offset 134218240 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 1024/1024 bytes at offset 134218752 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, -{ "start": 134217728, "length": 2048, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] *** done diff --git a/tests/qemu-iotests/179.out b/tests/qemu-iotests/179.out index 1f7680002c..7cf22cd75f 100644 --- a/tests/qemu-iotests/179.out +++ b/tests/qemu-iotests/179.out @@ -13,7 +13,11 @@ wrote 2097152/2097152 bytes at offset 6291456 2 MiB (0x200000) bytes not allocated at offset 4 MiB (0x400000) 2 MiB (0x200000) bytes allocated at offset 6 MiB (0x600000) 56 MiB (0x3800000) bytes not allocated at offset 8 MiB (0x800000) -[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 8388608, "length": 58720256, "depth": 0, "present": false, "zero": true, "data": false}] wrote 2097150/2097150 bytes at offset 10485761 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2097150/2097150 bytes at offset 14680065 @@ -27,7 +31,15 @@ wrote 2097150/2097150 bytes at offset 14680065 2 MiB (0x200000) bytes not allocated at offset 12 MiB (0xc00000) 2 MiB (0x200000) bytes allocated at offset 14 MiB (0xe00000) 48 MiB (0x3000000) bytes not allocated at offset 16 MiB (0x1000000) -[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 16777216, "length": 50331648, "depth": 0, "present": false, "zero": true, "data": false}] wrote 14680064/14680064 bytes at offset 18874368 14 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2097152/2097152 bytes at offset 20971520 @@ -45,13 +57,21 @@ wrote 6291456/6291456 bytes at offset 25165824 2 MiB (0x200000) bytes not allocated at offset 16 MiB (0x1000000) 14 MiB (0xe00000) bytes allocated at offset 18 MiB (0x1200000) 32 MiB (0x2000000) bytes not allocated at offset 32 MiB (0x2000000) -[{ "start": 0, "length": 18874368, "depth": 0, "zero": true, "data": false}, -{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 20971520, "length": 2097152, "depth": 0, "zero": true, "data": false}, -{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 25165824, "length": 6291456, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, -{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 33554432, "length": 33554432, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 25165824, "length": 6291456, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, +{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 33554432, "length": 33554432, "depth": 0, "present": false, "zero": true, "data": false}] wrote 2097152/2097152 bytes at offset 27262976 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2097152/2097152 bytes at offset 29360128 @@ -67,15 +87,23 @@ wrote 2097152/2097152 bytes at offset 29360128 2 MiB (0x200000) bytes not allocated at offset 16 MiB (0x1000000) 14 MiB (0xe00000) bytes allocated at offset 18 MiB (0x1200000) 32 MiB (0x2000000) bytes not allocated at offset 32 MiB (0x2000000) -[{ "start": 0, "length": 18874368, "depth": 0, "zero": true, "data": false}, -{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 20971520, "length": 2097152, "depth": 0, "zero": true, "data": false}, -{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 25165824, "length": 2097152, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, -{ "start": 27262976, "length": 2097152, "depth": 0, "zero": true, "data": false}, -{ "start": 29360128, "length": 2097152, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, -{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 33554432, "length": 33554432, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, +{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, +{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 33554432, "length": 33554432, "depth": 0, "present": false, "zero": true, "data": false}] wrote 8388608/8388608 bytes at offset 33554432 8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2097152/2097152 bytes at offset 35651584 @@ -93,15 +121,24 @@ wrote 2097152/2097152 bytes at offset 37748736 2 MiB (0x200000) bytes not allocated at offset 16 MiB (0x1000000) 22 MiB (0x1600000) bytes allocated at offset 18 MiB (0x1200000) 24 MiB (0x1800000) bytes not allocated at offset 40 MiB (0x2800000) -[{ "start": 0, "length": 18874368, "depth": 0, "zero": true, "data": false}, -{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 20971520, "length": 2097152, "depth": 0, "zero": true, "data": false}, -{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 25165824, "length": 2097152, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, -{ "start": 27262976, "length": 2097152, "depth": 0, "zero": true, "data": false}, -{ "start": 29360128, "length": 2097152, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, -{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 33554432, "length": 33554432, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, +{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, +{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 33554432, "length": 8388608, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 41943040, "length": 25165824, "depth": 0, "present": false, "zero": true, "data": false}] wrote 8388608/8388608 bytes at offset 41943040 8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 8388608/8388608 bytes at offset 50331648 @@ -125,23 +162,31 @@ wrote 2097152/2097152 bytes at offset 62914560 4 MiB (0x400000) bytes not allocated at offset 54 MiB (0x3600000) 4 MiB (0x400000) bytes allocated at offset 58 MiB (0x3a00000) 2 MiB (0x200000) bytes not allocated at offset 62 MiB (0x3e00000) -[{ "start": 0, "length": 18874368, "depth": 1, "zero": true, "data": false}, -{ "start": 18874368, "length": 2097152, "depth": 1, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 20971520, "length": 2097152, "depth": 1, "zero": true, "data": false}, -{ "start": 23068672, "length": 2097152, "depth": 1, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 25165824, "length": 2097152, "depth": 1, "zero": true, "data": false, "offset": OFFSET}, -{ "start": 27262976, "length": 2097152, "depth": 1, "zero": true, "data": false}, -{ "start": 29360128, "length": 2097152, "depth": 1, "zero": true, "data": false, "offset": OFFSET}, -{ "start": 31457280, "length": 2097152, "depth": 1, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 33554432, "length": 10485760, "depth": 1, "zero": true, "data": false}, -{ "start": 44040192, "length": 4194304, "depth": 0, "zero": true, "data": false}, -{ "start": 48234496, "length": 2097152, "depth": 1, "zero": true, "data": false}, -{ "start": 50331648, "length": 2097152, "depth": 1, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 52428800, "length": 4194304, "depth": 0, "zero": true, "data": false}, -{ "start": 56623104, "length": 2097152, "depth": 1, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 58720256, "length": 2097152, "depth": 1, "zero": true, "data": false}, -{ "start": 60817408, "length": 4194304, "depth": 0, "zero": true, "data": false}, -{ "start": 65011712, "length": 2097152, "depth": 1, "zero": true, "data": false}] +[{ "start": 0, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 2097152, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, +{ "start": 4194304, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 6291456, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, +{ "start": 8388608, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 10485760, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, +{ "start": 12582912, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 14680064, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, +{ "start": 16777216, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 18874368, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 20971520, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, +{ "start": 23068672, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 25165824, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "offset": OFFSET}, +{ "start": 27262976, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, +{ "start": 29360128, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "offset": OFFSET}, +{ "start": 31457280, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 33554432, "length": 10485760, "depth": 1, "present": true, "zero": true, "data": false}, +{ "start": 44040192, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 48234496, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, +{ "start": 50331648, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 52428800, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 56623104, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 58720256, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 60817408, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 65011712, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}] No errors were found on the image. No errors were found on the image. diff --git a/tests/qemu-iotests/209.out b/tests/qemu-iotests/209.out index 214e27bfce..f27be3fa7b 100644 --- a/tests/qemu-iotests/209.out +++ b/tests/qemu-iotests/209.out @@ -1,2 +1,2 @@ -[{ "start": 0, "length": 524288, "depth": 0, "zero": false, "data": true, "offset": 0}, -{ "start": 524288, "length": 524288, "depth": 0, "zero": true, "data": false, "offset": 524288}] +[{ "start": 0, "length": 524288, "depth": 0, "present": true, "zero": false, "data": true, "offset": 0}, +{ "start": 524288, "length": 524288, "depth": 0, "present": true, "zero": true, "data": false, "offset": 524288}] diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out index 3bc092a8a8..c4425b5982 100644 --- a/tests/qemu-iotests/211.out +++ b/tests/qemu-iotests/211.out @@ -17,7 +17,7 @@ file format: IMGFMT virtual size: 128 MiB (134217728 bytes) cluster_size: 1048576 -[{ "start": 0, "length": 134217728, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 134217728, "depth": 0, "present": true, "zero": true, "data": false}] === Successful image creation (explicit defaults) === @@ -36,7 +36,7 @@ file format: IMGFMT virtual size: 64 MiB (67108864 bytes) cluster_size: 1048576 -[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": true, "data": false}] === Successful image creation (with non-default options) === @@ -55,8 +55,8 @@ file format: IMGFMT virtual size: 32 MiB (33554432 bytes) cluster_size: 1048576 -[{ "start": 0, "length": 3072, "depth": 0, "zero": false, "data": true, "offset": 1024}, -{ "start": 3072, "length": 33551360, "depth": 0, "zero": true, "data": true, "offset": 4096}] +[{ "start": 0, "length": 3072, "depth": 0, "present": true, "zero": false, "data": true, "offset": 1024}, +{ "start": 3072, "length": 33551360, "depth": 0, "present": true, "zero": true, "data": true, "offset": 4096}] === Invalid BlockdevRef === diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out index 93846c7dab..9cdd171a2d 100644 --- a/tests/qemu-iotests/221.out +++ b/tests/qemu-iotests/221.out @@ -5,14 +5,14 @@ QA output created by 221 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65537 discard 65537/65537 bytes at offset 0 64.001 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] -[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] +[{ "start": 0, "length": 66048, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] +[{ "start": 0, "length": 66048, "depth": 0, "present": true, "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": 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}] +[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, +{ "start": 65536, "length": 1, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 65537, "length": 511, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] +[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, +{ "start": 65536, "length": 1, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 65537, "length": 511, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] *** done diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out index 083b62d053..e58ea5abbd 100644 --- a/tests/qemu-iotests/223.out +++ b/tests/qemu-iotests/223.out @@ -100,19 +100,19 @@ read 1048576/1048576 bytes at offset 1048576 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 2097152/2097152 bytes at offset 2097152 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, -{ "start": 1048576, "length": 3145728, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] -[{ "start": 0, "length": 65536, "depth": 0, "zero": false, "data": false}, -{ "start": 65536, "length": 2031616, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, +{ "start": 1048576, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false}, +{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] === Contrast to small granularity dirty-bitmap === -[{ "start": 0, "length": 512, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 512, "length": 512, "depth": 0, "zero": false, "data": false}, -{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] +[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false}, +{ "start": 1024, "length": 2096128, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] === End qemu NBD server === @@ -201,19 +201,19 @@ read 1048576/1048576 bytes at offset 1048576 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 2097152/2097152 bytes at offset 2097152 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, -{ "start": 1048576, "length": 3145728, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] -[{ "start": 0, "length": 65536, "depth": 0, "zero": false, "data": false}, -{ "start": 65536, "length": 2031616, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, +{ "start": 1048576, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false}, +{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] === Contrast to small granularity dirty-bitmap === -[{ "start": 0, "length": 512, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 512, "length": 512, "depth": 0, "zero": false, "data": false}, -{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] +[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false}, +{ "start": 1024, "length": 2096128, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] === End qemu NBD server === @@ -238,12 +238,12 @@ read 2097152/2097152 bytes at offset 2097152 === Use qemu-nbd as server === -[{ "start": 0, "length": 65536, "depth": 0, "zero": false, "data": false}, -{ "start": 65536, "length": 2031616, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] -[{ "start": 0, "length": 512, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 512, "length": 512, "depth": 0, "zero": false, "data": false}, -{ "start": 1024, "length": 11321, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] -[{ "start": 12345, "length": 2084807, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] +[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false}, +{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] +[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false}, +{ "start": 1024, "length": 11321, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 12345, "length": 2084807, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] *** done diff --git a/tests/qemu-iotests/241.out b/tests/qemu-iotests/241.out index 3f8c173cc8..56e95b599a 100644 --- a/tests/qemu-iotests/241.out +++ b/tests/qemu-iotests/241.out @@ -4,15 +4,15 @@ QA output created by 241 size: 1024 min block: 1 -[{ "start": 0, "length": 1000, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 1000, "length": 24, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] +[{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) === Exporting unaligned raw image, forced server sector alignment === size: 1024 min block: 512 -[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. @@ -22,7 +22,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed size: 1024 min block: 1 -[{ "start": 0, "length": 1000, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 1000, "length": 24, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] +[{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) *** done diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out index 99f56ac18c..5e03add054 100644 --- a/tests/qemu-iotests/244.out +++ b/tests/qemu-iotests/244.out @@ -57,11 +57,12 @@ wrote 3145728/3145728 bytes at offset 3145728 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) No errors were found on the image. -[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false}, -{ "start": 1048576, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": 1048576}, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": true, "data": false}, -{ "start": 4194304, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": 4194304}, -{ "start": 5242880, "length": 61865984, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 1048576, "depth": 0, "present": false, "zero": true, "data": false}, +{ "start": 1048576, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "offset": 1048576}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 4194304, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false, "offset": 4194304}, +{ "start": 5242880, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 6291456, "length": 60817408, "depth": 0, "present": false, "zero": true, "data": false}] read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -93,10 +94,10 @@ wrote 3145728/3145728 bytes at offset 3145728 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) No errors were found on the image. -[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 0}, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": true, "data": false}, -{ "start": 4194304, "length": 2097152, "depth": 0, "zero": true, "data": false, "offset": 4194304}, -{ "start": 6291456, "length": 60817408, "depth": 0, "zero": false, "data": true, "offset": 6291456}] +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": 0}, +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": 4194304}, +{ "start": 6291456, "length": 60817408, "depth": 0, "present": true, "zero": false, "data": true, "offset": 6291456}] read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -122,8 +123,8 @@ read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) Offset Length Mapped to File 0 0x100000 0 TEST_DIR/t.qcow2.data -[{ "start": 0, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": 0}, -{ "start": 1048576, "length": 66060288, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "offset": 0}, +{ "start": 1048576, "length": 66060288, "depth": 0, "present": false, "zero": true, "data": false}] === Copy offloading === diff --git a/tests/qemu-iotests/252.out b/tests/qemu-iotests/252.out index 12dce889f8..c578129c25 100644 --- a/tests/qemu-iotests/252.out +++ b/tests/qemu-iotests/252.out @@ -23,8 +23,8 @@ read 131072/131072 bytes at offset 131072 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}] +[{ "start": 0, "length": 262144, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 262144, "length": 131072, "depth": 0, "present": false, "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) @@ -33,7 +33,7 @@ read 131072/131072 bytes at offset 131072 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}] +[{ "start": 0, "length": 262144, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 262144, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false}, +{ "start": 327680, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false}] *** done diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out index 3d08b305d7..b3dca75a89 100644 --- a/tests/qemu-iotests/253.out +++ b/tests/qemu-iotests/253.out @@ -3,16 +3,16 @@ QA output created by 253 === Check mapping of unaligned raw image === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575 -[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] -[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] wrote 65535/65535 bytes at offset 983040 63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, -{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] -[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, -{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 978944, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, +{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 978944, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, +{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] *** done diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out index cfe17a8659..16a95a4850 100644 --- a/tests/qemu-iotests/274.out +++ b/tests/qemu-iotests/274.out @@ -26,18 +26,18 @@ read 1048576/1048576 bytes at offset 1048576 0/1048576 bytes allocated at offset 1 MiB === Checking map === -[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}] +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}] Offset Length Mapped to File 0 0x200000 0x50000 TEST_DIR/PID-base -[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}] +[{ "start": 0, "length": 1048576, "depth": 1, "present": true, "zero": false, "data": true, "offset": 327680}] Offset Length Mapped to File 0 0x100000 0x50000 TEST_DIR/PID-base -[{ "start": 0, "length": 1048576, "depth": 2, "zero": false, "data": true, "offset": 327680}, -{ "start": 1048576, "length": 1048576, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 1048576, "depth": 2, "present": true, "zero": false, "data": true, "offset": 327680}, +{ "start": 1048576, "length": 1048576, "depth": 0, "present": false, "zero": true, "data": false}] Offset Length Mapped to File 0 0x100000 0x50000 TEST_DIR/PID-base @@ -220,8 +220,8 @@ read 65536/65536 bytes at offset 5368709120 1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0) 7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000) -[{ "start": 0, "length": 1073741824, "depth": 1, "zero": true, "data": false}, -{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 1073741824, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 1073741824, "length": 7516192768, "depth": 0, "present": true, "zero": true, "data": false}] === preallocation=metadata === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=34359738368 lazy_refcounts=off refcount_bits=16 @@ -239,13 +239,13 @@ read 65536/65536 bytes at offset 33285996544 30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0) 3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000) -[{ "start": 0, "length": 32212254720, "depth": 1, "zero": true, "data": false}, -{ "start": 32212254720, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 327680}, -{ "start": 32749125632, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 537264128}, -{ "start": 33285996544, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1074200576}, -{ "start": 33822867456, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1611137024}, -{ "start": 34359738368, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2148139008}, -{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}] +[{ "start": 0, "length": 32212254720, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 32212254720, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 327680}, +{ "start": 32749125632, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 537264128}, +{ "start": 33285996544, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 1074200576}, +{ "start": 33822867456, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 1611137024}, +{ "start": 34359738368, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 2148139008}, +{ "start": 34896609280, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 2685075456}] === preallocation=falloc === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=10485760 lazy_refcounts=off refcount_bits=16 @@ -263,8 +263,8 @@ read 65536/65536 bytes at offset 9437184 5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0) 10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000) -[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false}, -{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}] +[{ "start": 0, "length": 5242880, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 5242880, "length": 10485760, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}] === preallocation=full === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=16777216 lazy_refcounts=off refcount_bits=16 @@ -282,8 +282,8 @@ read 65536/65536 bytes at offset 11534336 8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0) 4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000) -[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false}, -{ "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}] +[{ "start": 0, "length": 8388608, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 8388608, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}] === preallocation=off === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=393216 lazy_refcounts=off refcount_bits=16 @@ -301,9 +301,9 @@ read 65536/65536 bytes at offset 259072 192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0) 320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000) -[{ "start": 0, "length": 196608, "depth": 1, "zero": true, "data": false}, -{ "start": 196608, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": 327680}, -{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 196608, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 196608, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}, +{ "start": 262144, "length": 262144, "depth": 0, "present": true, "zero": true, "data": false}] === preallocation=off === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=409600 lazy_refcounts=off refcount_bits=16 @@ -321,8 +321,8 @@ read 65536/65536 bytes at offset 344064 256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0) 256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000) -[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false}, -{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 262144, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 262144, "length": 262144, "depth": 0, "present": true, "zero": true, "data": false}] === preallocation=off === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=524288 lazy_refcounts=off refcount_bits=16 @@ -340,6 +340,6 @@ read 65536/65536 bytes at offset 446464 256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0) 244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000) -[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false}, -{ "start": 262144, "length": 249856, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 262144, "depth": 1, "present": false, "zero": true, "data": false}, +{ "start": 262144, "length": 249856, "depth": 0, "present": true, "zero": true, "data": false}] diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/291.out index 23411c0ff4..018d6b103f 100644 --- a/tests/qemu-iotests/291.out +++ b/tests/qemu-iotests/291.out @@ -103,16 +103,16 @@ Format specific information: === Check bitmap contents === -[{ "start": 0, "length": 3145728, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 3145728, "length": 1048576, "depth": 0, "zero": false, "data": false}, -{ "start": 4194304, "length": 6291456, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] -[{ "start": 0, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 1048576, "length": 1048576, "depth": 0, "zero": false, "data": false}, -{ "start": 2097152, "length": 8388608, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] -[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 2097152, "length": 1048576, "depth": 0, "zero": false, "data": false}, -{ "start": 3145728, "length": 7340032, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] -[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 2097152, "length": 1048576, "depth": 0, "zero": false, "data": false}, -{ "start": 3145728, "length": 7340032, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 3145728, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false}, +{ "start": 4194304, "length": 6291456, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 1048576, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false}, +{ "start": 2097152, "length": 8388608, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false}, +{ "start": 3145728, "length": 7340032, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false}, +{ "start": 3145728, "length": 7340032, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] *** done diff --git a/tests/qemu-iotests/tests/nbd-qemu-allocation.out b/tests/qemu-iotests/tests/nbd-qemu-allocation.out index c51022b2a3..0bf1abb063 100644 --- a/tests/qemu-iotests/tests/nbd-qemu-allocation.out +++ b/tests/qemu-iotests/tests/nbd-qemu-allocation.out @@ -11,9 +11,9 @@ wrote 2097152/2097152 bytes at offset 1048576 === Check allocation over NBD === -[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}, -{ "start": 1048576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}, -{ "start": 3145728, "length": 1048576, "depth": 1, "zero": true, "data": false}] +[{ "start": 0, "length": 1048576, "depth": 1, "present": true, "zero": false, "data": true, "offset": 327680}, +{ "start": 1048576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}, +{ "start": 3145728, "length": 1048576, "depth": 1, "present": false, "zero": true, "data": false}] exports available: 1 export: '' size: 4194304 @@ -24,9 +24,9 @@ exports available: 1 available meta contexts: 2 base:allocation qemu:allocation-depth -[{ "start": 0, "length": 3145728, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -{ "start": 3145728, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] -[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": true, "offset": OFFSET}, -{ "start": 1048576, "length": 2097152, "depth": 0, "zero": false, "data": false}, -{ "start": 3145728, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 3145728, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] +[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": true, "offset": OFFSET}, +{ "start": 1048576, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}, +{ "start": 3145728, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] *** done From a275b452c65cea2df598d966a6554f71060d3f3b Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 7 Jul 2021 13:41:25 -0500 Subject: [PATCH 003/531] qemu-img: Reword 'qemu-img map --output=json' docs Reword the paragraphs to list the JSON key first, rather than in the middle of prose. Suggested-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Eric Blake Message-Id: <20210707184125.2551140-1-eblake@redhat.com> Reviewed-by: Nir Soffer Reviewed-by: Vladimir Sementsov-Ogievskiy --- docs/tools/qemu-img.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index d6300f7ee0..1d8470eada 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -593,16 +593,16 @@ Command description: the ``start``, ``length``, ``offset`` fields; it will also include other more specific information: - - whether the sectors contain actual data or not (boolean field ``data``; - if false, the sectors are either unallocated or stored as optimized - all-zero clusters); - - whether the data is known to read as zero (boolean field ``zero``); - - whether the data is actually present (boolean field ``present``); - if false, rebasing the backing chain onto a deeper file would pick - up data from the deeper file; - - in order to make the output shorter, the target file is expressed as - a ``depth``; for example, a depth of 2 refers to the backing file - of the backing file of *FILENAME*. + - boolean field ``data``: true if the sectors contain actual data, + false if the sectors are either unallocated or stored as optimized + all-zero clusters + - boolean field ``zero``: true if the data is known to read as zero + - boolean field ``present``: true if the data belongs to the backing + chain, false if rebasing the backing chain onto a deeper file + would pick up data from the deeper file; + - integer field ``depth``: the depth within the backing chain at + which the data was resolved; for example, a depth of 2 refers to + the backing file of the backing file of *FILENAME*. In JSON format, the ``offset`` field is optional; it is absent in cases where ``human`` format would omit the entry or exit with an error. From 0b9cd6b947d905b388e84df4070056fad138588e Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Sun, 4 Jul 2021 00:07:30 +0200 Subject: [PATCH 004/531] nbd: register yank function earlier Although unlikely, qemu might hang in nbd_send_request(). Allow recovery in this case by registering the yank function before calling it. Signed-off-by: Lukas Straub Message-Id: <20210704000730.1befb596@gecko.fritz.box> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Eric Blake --- block/nbd.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index 601fccc5ba..f6ff1c4fb4 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -371,6 +371,9 @@ int coroutine_fn nbd_co_do_establish_connection(BlockDriverState *bs, return -ECONNREFUSED; } + yank_register_function(BLOCKDEV_YANK_INSTANCE(s->bs->node_name), nbd_yank, + bs); + ret = nbd_handle_updated_info(s->bs, NULL); if (ret < 0) { /* @@ -381,6 +384,8 @@ int coroutine_fn nbd_co_do_establish_connection(BlockDriverState *bs, nbd_send_request(s->ioc, &request); + yank_unregister_function(BLOCKDEV_YANK_INSTANCE(s->bs->node_name), + nbd_yank, bs); object_unref(OBJECT(s->ioc)); s->ioc = NULL; @@ -390,9 +395,6 @@ int coroutine_fn nbd_co_do_establish_connection(BlockDriverState *bs, qio_channel_set_blocking(s->ioc, false, NULL); qio_channel_attach_aio_context(s->ioc, bdrv_get_aio_context(bs)); - yank_register_function(BLOCKDEV_YANK_INSTANCE(s->bs->node_name), nbd_yank, - bs); - /* successfully connected */ s->state = NBD_CLIENT_CONNECTED; qemu_co_queue_restart_all(&s->free_sema); From c141814d4f495bd9efdabb1229ce0a5b5a239bf3 Mon Sep 17 00:00:00 2001 From: Kostiantyn Kostiuk Date: Mon, 21 Jun 2021 15:50:17 +0300 Subject: [PATCH 005/531] qga-win: Add support of Windows Server 2022 in get-osinfo command Signed-off-by: Kostiantyn Kostiuk Signed-off-by: Michael Roth --- qga/commands-win32.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 27baf17d6c..a099acb34d 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -2166,9 +2166,10 @@ typedef struct _ga_win_10_0_server_t { char const *version_id; } ga_win_10_0_server_t; -static ga_win_10_0_server_t const WIN_10_0_SERVER_VERSION_MATRIX[3] = { +static ga_win_10_0_server_t const WIN_10_0_SERVER_VERSION_MATRIX[4] = { {14393, "Microsoft Windows Server 2016", "2016"}, {17763, "Microsoft Windows Server 2019", "2019"}, + {20344, "Microsoft Windows Server 2022", "2022"}, {0, 0} }; From 2adf2164918e2dc74fef2cdd0257917aff488640 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 1 Jun 2021 15:24:02 +0200 Subject: [PATCH 006/531] qemu-trace-stap: changing SYSTEMTAP_TAPSET considered harmful. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting SYSTEMTAP_TAPSET to some value other than /usr/share/systemtap/tapsets results in systemtap not finding the standard tapset library any more, which in turn breaks tracing because pid() and other standard systemtap functions are not available any more. So using SYSTEMTAP_TAPSET to point systemtap to the qemu probes will only work for the prefix=/usr installs because both qemu and system tapsets in the same directory then. All other prefixes are broken. Fix that by using the "-I $tapsetdir" command line switch instead. Signed-off-by: Gerd Hoffmann Reviewed-by: Stefan Hajnoczi Reviewed-by: Daniel P. Berrangé Message-id: 20210601132414.432430-2-kraxel@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/qemu-trace-stap | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/scripts/qemu-trace-stap b/scripts/qemu-trace-stap index 90527eb974..eb6e951ff2 100755 --- a/scripts/qemu-trace-stap +++ b/scripts/qemu-trace-stap @@ -55,11 +55,6 @@ def tapset_dir(binary): return os.path.realpath(tapset) -def tapset_env(tapset_dir): - tenv = copy.copy(os.environ) - tenv["SYSTEMTAP_TAPSET"] = tapset_dir - return tenv - def cmd_run(args): prefix = probe_prefix(args.binary) tapsets = tapset_dir(args.binary) @@ -81,11 +76,11 @@ def cmd_run(args): # We request an 8MB buffer, since the stap default 1MB buffer # can be easily overflowed by frequently firing QEMU traces - stapargs = ["stap", "-s", "8"] + stapargs = ["stap", "-s", "8", "-I", tapsets ] if args.pid is not None: stapargs.extend(["-x", args.pid]) stapargs.extend(["-e", script]) - subprocess.call(stapargs, env=tapset_env(tapsets)) + subprocess.call(stapargs) def cmd_list(args): @@ -101,10 +96,9 @@ def cmd_list(args): if verbose: print("Listing probes with name '%s'" % script) - proc = subprocess.Popen(["stap", "-l", script], + proc = subprocess.Popen(["stap", "-I", tapsets, "-l", script], stdout=subprocess.PIPE, - universal_newlines=True, - env=tapset_env(tapsets)) + universal_newlines=True) out, err = proc.communicate() if proc.returncode != 0: print("No probes found, are the tapsets installed in %s" % tapset_dir(args.binary)) From 117856c3748dfda50351d1c0328486ede5f2646c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 1 Jun 2021 15:24:03 +0200 Subject: [PATCH 007/531] trace: iter init tweaks Rename trace_event_iter_init() to trace_event_iter_init_pattern(), add trace_event_iter_init_all() for interating over all events. Signed-off-by: Gerd Hoffmann Reviewed-by: Stefan Hajnoczi Message-id: 20210601132414.432430-3-kraxel@redhat.com Signed-off-by: Stefan Hajnoczi --- monitor/misc.c | 4 ++-- trace/control-target.c | 2 +- trace/control.c | 16 +++++++++++----- trace/control.h | 17 +++++++++++++---- trace/qmp.c | 6 +++--- trace/simple.c | 2 +- 6 files changed, 31 insertions(+), 16 deletions(-) diff --git a/monitor/misc.c b/monitor/misc.c index b28874d6dc..ffe7966870 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -1804,7 +1804,7 @@ void info_trace_events_completion(ReadLineState *rs, int nb_args, const char *st TraceEventIter iter; TraceEvent *ev; char *pattern = g_strdup_printf("%s*", str); - trace_event_iter_init(&iter, pattern); + trace_event_iter_init_pattern(&iter, pattern); while ((ev = trace_event_iter_next(&iter)) != NULL) { readline_add_completion(rs, trace_event_get_name(ev)); } @@ -1822,7 +1822,7 @@ void trace_event_completion(ReadLineState *rs, int nb_args, const char *str) TraceEventIter iter; TraceEvent *ev; char *pattern = g_strdup_printf("%s*", str); - trace_event_iter_init(&iter, pattern); + trace_event_iter_init_pattern(&iter, pattern); while ((ev = trace_event_iter_next(&iter)) != NULL) { readline_add_completion(rs, trace_event_get_name(ev)); } diff --git a/trace/control-target.c b/trace/control-target.c index e293eeed7c..8418673c18 100644 --- a/trace/control-target.c +++ b/trace/control-target.c @@ -127,7 +127,7 @@ void trace_init_vcpu(CPUState *vcpu) { TraceEventIter iter; TraceEvent *ev; - trace_event_iter_init(&iter, NULL); + trace_event_iter_init_all(&iter); while ((ev = trace_event_iter_next(&iter)) != NULL) { if (trace_event_is_vcpu(ev) && trace_event_get_state_static(ev) && diff --git a/trace/control.c b/trace/control.c index 4be38e1af2..ed38e813b2 100644 --- a/trace/control.c +++ b/trace/control.c @@ -91,7 +91,7 @@ TraceEvent *trace_event_name(const char *name) TraceEventIter iter; TraceEvent *ev; - trace_event_iter_init(&iter, NULL); + trace_event_iter_init_all(&iter); while ((ev = trace_event_iter_next(&iter)) != NULL) { if (strcmp(trace_event_get_name(ev), name) == 0) { return ev; @@ -100,10 +100,16 @@ TraceEvent *trace_event_name(const char *name) return NULL; } -void trace_event_iter_init(TraceEventIter *iter, const char *pattern) +void trace_event_iter_init_all(TraceEventIter *iter) { iter->event = 0; iter->group = 0; + iter->pattern = NULL; +} + +void trace_event_iter_init_pattern(TraceEventIter *iter, const char *pattern) +{ + trace_event_iter_init_all(iter); iter->pattern = pattern; } @@ -130,7 +136,7 @@ void trace_list_events(FILE *f) { TraceEventIter iter; TraceEvent *ev; - trace_event_iter_init(&iter, NULL); + trace_event_iter_init_all(&iter); while ((ev = trace_event_iter_next(&iter)) != NULL) { fprintf(f, "%s\n", trace_event_get_name(ev)); } @@ -150,7 +156,7 @@ static void do_trace_enable_events(const char *line_buf) TraceEvent *ev; bool is_pattern = trace_event_is_pattern(line_ptr); - trace_event_iter_init(&iter, line_ptr); + trace_event_iter_init_pattern(&iter, line_ptr); while ((ev = trace_event_iter_next(&iter)) != NULL) { if (!trace_event_get_state_static(ev)) { if (!is_pattern) { @@ -256,7 +262,7 @@ void trace_fini_vcpu(CPUState *vcpu) trace_guest_cpu_exit(vcpu); - trace_event_iter_init(&iter, NULL); + trace_event_iter_init_all(&iter); while ((ev = trace_event_iter_next(&iter)) != NULL) { if (trace_event_is_vcpu(ev) && trace_event_get_state_static(ev) && diff --git a/trace/control.h b/trace/control.h index 9522a7b318..ce40bd0405 100644 --- a/trace/control.h +++ b/trace/control.h @@ -20,15 +20,24 @@ typedef struct TraceEventIter { /** - * trace_event_iter_init: + * trace_event_iter_init_all: * @iter: the event iterator struct - * @pattern: optional pattern to filter events on name * * Initialize the event iterator struct @iter, - * optionally using @pattern to filter out events + * for all events. + */ +void trace_event_iter_init_all(TraceEventIter *iter); + +/** + * trace_event_iter_init_pattern: + * @iter: the event iterator struct + * @pattern: pattern to filter events on name + * + * Initialize the event iterator struct @iter, + * using @pattern to filter out events * with non-matching names. */ -void trace_event_iter_init(TraceEventIter *iter, const char *pattern); +void trace_event_iter_init_pattern(TraceEventIter *iter, const char *pattern); /** * trace_event_iter_next: diff --git a/trace/qmp.c b/trace/qmp.c index 85f81e47cc..3b4f4702b4 100644 --- a/trace/qmp.c +++ b/trace/qmp.c @@ -55,7 +55,7 @@ static bool check_events(bool has_vcpu, bool ignore_unavailable, bool is_pattern /* error for unavailable events */ TraceEventIter iter; TraceEvent *ev; - trace_event_iter_init(&iter, name); + trace_event_iter_init_pattern(&iter, name); while ((ev = trace_event_iter_next(&iter)) != NULL) { if (!ignore_unavailable && !trace_event_get_state_static(ev)) { error_setg(errp, "event \"%s\" is disabled", trace_event_get_name(ev)); @@ -90,7 +90,7 @@ TraceEventInfoList *qmp_trace_event_get_state(const char *name, } /* Get states (all errors checked above) */ - trace_event_iter_init(&iter, name); + trace_event_iter_init_pattern(&iter, name); while ((ev = trace_event_iter_next(&iter)) != NULL) { TraceEventInfo *value; bool is_vcpu = trace_event_is_vcpu(ev); @@ -153,7 +153,7 @@ void qmp_trace_event_set_state(const char *name, bool enable, } /* Apply changes (all errors checked above) */ - trace_event_iter_init(&iter, name); + trace_event_iter_init_pattern(&iter, name); while ((ev = trace_event_iter_next(&iter)) != NULL) { if (!trace_event_get_state_static(ev) || (has_vcpu && !trace_event_is_vcpu(ev))) { diff --git a/trace/simple.c b/trace/simple.c index 9cd2ed1fb3..97b6f85168 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -286,7 +286,7 @@ static int st_write_event_mapping(void) TraceEventIter iter; TraceEvent *ev; - trace_event_iter_init(&iter, NULL); + trace_event_iter_init_all(&iter); while ((ev = trace_event_iter_next(&iter)) != NULL) { uint64_t id = trace_event_get_id(ev); const char *name = trace_event_get_name(ev); From c5cc58b176f23f6664d0e12e5956af4d904dcca4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 1 Jun 2021 15:24:04 +0200 Subject: [PATCH 008/531] trace: add trace_event_iter_init_group This allows to interate over an event group. Signed-off-by: Gerd Hoffmann Reviewed-by: Stefan Hajnoczi Message-id: 20210601132414.432430-4-kraxel@redhat.com Signed-off-by: Stefan Hajnoczi --- trace/control.c | 19 ++++++++++++++++--- trace/control.h | 13 +++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/trace/control.c b/trace/control.c index ed38e813b2..2c904b7ee4 100644 --- a/trace/control.c +++ b/trace/control.c @@ -104,6 +104,7 @@ void trace_event_iter_init_all(TraceEventIter *iter) { iter->event = 0; iter->group = 0; + iter->group_id = -1; iter->pattern = NULL; } @@ -113,20 +114,32 @@ void trace_event_iter_init_pattern(TraceEventIter *iter, const char *pattern) iter->pattern = pattern; } +void trace_event_iter_init_group(TraceEventIter *iter, size_t group_id) +{ + trace_event_iter_init_all(iter); + iter->group_id = group_id; +} + TraceEvent *trace_event_iter_next(TraceEventIter *iter) { while (iter->group < nevent_groups && event_groups[iter->group].events[iter->event] != NULL) { TraceEvent *ev = event_groups[iter->group].events[iter->event]; + size_t group = iter->group; iter->event++; if (event_groups[iter->group].events[iter->event] == NULL) { iter->event = 0; iter->group++; } - if (!iter->pattern || - g_pattern_match_simple(iter->pattern, trace_event_get_name(ev))) { - return ev; + if (iter->pattern && + !g_pattern_match_simple(iter->pattern, trace_event_get_name(ev))) { + continue; } + if (iter->group_id != -1 && + iter->group_id != group) { + continue; + } + return ev; } return NULL; diff --git a/trace/control.h b/trace/control.h index ce40bd0405..23b8393b29 100644 --- a/trace/control.h +++ b/trace/control.h @@ -13,8 +13,11 @@ #include "event-internal.h" typedef struct TraceEventIter { + /* iter state */ size_t event; size_t group; + /* filter conditions */ + size_t group_id; const char *pattern; } TraceEventIter; @@ -39,6 +42,16 @@ void trace_event_iter_init_all(TraceEventIter *iter); */ void trace_event_iter_init_pattern(TraceEventIter *iter, const char *pattern); +/** + * trace_event_iter_init_group: + * @iter: the event iterator struct + * @group_id: group_id to filter events by group. + * + * Initialize the event iterator struct @iter, + * using @group_id to filter for events in the group. + */ +void trace_event_iter_init_group(TraceEventIter *iter, size_t group_id); + /** * trace_event_iter_next: * @iter: the event iterator struct From 3f2a09842f989af020b8355622d5f7fa9bdeb832 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 1 Jun 2021 15:24:05 +0200 Subject: [PATCH 009/531] trace/simple: pass iter to st_write_event_mapping Pass an iter to st_write_event_mapping, so the function can interate different things depending on how we initialize the iter. Signed-off-by: Gerd Hoffmann Reviewed-by: Stefan Hajnoczi Message-id: 20210601132414.432430-5-kraxel@redhat.com Signed-off-by: Stefan Hajnoczi --- trace/simple.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/trace/simple.c b/trace/simple.c index 97b6f85168..ec2156d135 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -280,14 +280,12 @@ void trace_record_finish(TraceBufferRecord *rec) } } -static int st_write_event_mapping(void) +static int st_write_event_mapping(TraceEventIter *iter) { uint64_t type = TRACE_RECORD_TYPE_MAPPING; - TraceEventIter iter; TraceEvent *ev; - trace_event_iter_init_all(&iter); - while ((ev = trace_event_iter_next(&iter)) != NULL) { + while ((ev = trace_event_iter_next(iter)) != NULL) { uint64_t id = trace_event_get_id(ev); const char *name = trace_event_get_name(ev); uint32_t len = strlen(name); @@ -309,6 +307,7 @@ static int st_write_event_mapping(void) */ bool st_set_trace_file_enabled(bool enable) { + TraceEventIter iter; bool was_enabled = trace_fp; if (enable == !!trace_fp) { @@ -333,8 +332,9 @@ bool st_set_trace_file_enabled(bool enable) return was_enabled; } + trace_event_iter_init_all(&iter); if (fwrite(&header, sizeof header, 1, trace_fp) != 1 || - st_write_event_mapping() < 0) { + st_write_event_mapping(&iter) < 0) { fclose(trace_fp); trace_fp = NULL; return was_enabled; From 263b6e96449d07808bc6eb21ab24f3a8b7a49bb6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 1 Jun 2021 15:24:06 +0200 Subject: [PATCH 010/531] trace/simple: add st_init_group Add helper function and call it for each trace event group added. Makes sure that events added at module load time are initialized properly. Signed-off-by: Gerd Hoffmann Reviewed-by: Stefan Hajnoczi Message-id: 20210601132414.432430-6-kraxel@redhat.com Signed-off-by: Stefan Hajnoczi --- trace/control.c | 4 ++++ trace/simple.c | 12 ++++++++++++ trace/simple.h | 1 + 3 files changed, 17 insertions(+) diff --git a/trace/control.c b/trace/control.c index 2c904b7ee4..d5b68e846e 100644 --- a/trace/control.c +++ b/trace/control.c @@ -82,6 +82,10 @@ void trace_event_register_group(TraceEvent **events) event_groups = g_renew(TraceEventGroup, event_groups, nevent_groups + 1); event_groups[nevent_groups].events = events; nevent_groups++; + +#ifdef CONFIG_TRACE_SIMPLE + st_init_group(nevent_groups - 1); +#endif } diff --git a/trace/simple.c b/trace/simple.c index ec2156d135..ac499edee0 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -422,3 +422,15 @@ bool st_init(void) atexit(st_flush_trace_buffer); return true; } + +void st_init_group(size_t group) +{ + TraceEventIter iter; + + if (!trace_writeout_enabled) { + return; + } + + trace_event_iter_init_group(&iter, group); + st_write_event_mapping(&iter); +} diff --git a/trace/simple.h b/trace/simple.h index 26ccbc8b8a..ee1983ce56 100644 --- a/trace/simple.h +++ b/trace/simple.h @@ -15,6 +15,7 @@ void st_print_trace_file_status(void); bool st_set_trace_file_enabled(bool enable); void st_set_trace_file(const char *file); bool st_init(void); +void st_init_group(size_t group); void st_flush_trace_buffer(void); typedef struct { From bbe47ed2928542e7db58146b6108e3f2836f278f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 12 Jul 2021 17:57:10 +0200 Subject: [PATCH 011/531] trace, lttng: require .pc files The next version of lttng-libs will not require liburcu at run time anymore. Therefore, it is expected that distros will not include the urcubp libraries anymore when installing lttng-ust-devel. To avoid future problems, just require pkg-config to detect lttng-ust. The .pc files for lttng-ust correctly include liburcubp.a for static builds, and have always done since pkg-config files were added in 2011. Signed-off-by: Paolo Bonzini Message-id: 20210712155710.520889-1-pbonzini@redhat.com Signed-off-by: Stefan Hajnoczi --- configure | 18 ++---------------- meson.build | 4 ---- trace/meson.build | 2 +- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/configure b/configure index 85db248ac1..4d0a2bfdd8 100755 --- a/configure +++ b/configure @@ -3606,21 +3606,8 @@ fi ########################################## # For 'ust' backend, test if ust headers are present if have_backend "ust"; then - cat > $TMPC << EOF -#include -int main(void) { return 0; } -EOF - if compile_prog "" "-Wl,--no-as-needed -ldl" ; then - if $pkg_config lttng-ust --exists; then - lttng_ust_libs=$($pkg_config --libs lttng-ust) - else - lttng_ust_libs="-llttng-ust -ldl" - fi - if $pkg_config liburcu-bp --exists; then - urcu_bp_libs=$($pkg_config --libs liburcu-bp) - else - urcu_bp_libs="-lurcu-bp" - fi + if $pkg_config lttng-ust --exists; then + lttng_ust_libs=$($pkg_config --libs lttng-ust) else error_exit "Trace backend 'ust' missing lttng-ust header files" fi @@ -4773,7 +4760,6 @@ fi if have_backend "ust"; then echo "CONFIG_TRACE_UST=y" >> $config_host_mak echo "LTTNG_UST_LIBS=$lttng_ust_libs" >> $config_host_mak - echo "URCU_BP_LIBS=$urcu_bp_libs" >> $config_host_mak fi if have_backend "dtrace"; then echo "CONFIG_TRACE_DTRACE=y" >> $config_host_mak diff --git a/meson.build b/meson.build index dd7f9ed6a8..4dea2d9dd3 100644 --- a/meson.build +++ b/meson.build @@ -319,10 +319,6 @@ lttng = not_found if 'CONFIG_TRACE_UST' in config_host lttng = declare_dependency(link_args: config_host['LTTNG_UST_LIBS'].split()) endif -urcubp = not_found -if 'CONFIG_TRACE_UST' in config_host - urcubp = declare_dependency(link_args: config_host['URCU_BP_LIBS'].split()) -endif pixman = not_found if have_system or have_tools pixman = dependency('pixman-1', required: have_system, version:'>=0.21.8', diff --git a/trace/meson.build b/trace/meson.build index 08f83a15c3..ef18f11d64 100644 --- a/trace/meson.build +++ b/trace/meson.build @@ -26,7 +26,7 @@ foreach dir : [ '.' ] + trace_events_subdirs input: trace_events_file, command: [ tracetool, group, '--format=ust-events-h', '@INPUT@', '@OUTPUT@' ], depend_files: tracetool_depends) - trace_ss.add(trace_ust_h, lttng, urcubp) + trace_ss.add(trace_ust_h, lttng) genh += trace_ust_h endif trace_ss.add(trace_h, trace_c) From f7588fe90623cef751e94225229a63b3d91e2df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Jul 2021 19:05:43 +0200 Subject: [PATCH 012/531] linux-user/syscall: Fix RF-kill errno (typo in ERFKILL) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Affected targets: alpha, hppa, mips/64, sparc Fixes: fe8ed7d5794 ("linux-user: Handle ERFKILL and EHWPOISON") Reviewed-by: Laurent Vivier Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210708170550.1846343-2-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 2e826206d2..4842a1987b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -629,7 +629,7 @@ static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = { #ifdef ENOMSG [ENOMSG] = TARGET_ENOMSG, #endif -#ifdef ERKFILL +#ifdef ERFKILL [ERFKILL] = TARGET_ERFKILL, #endif #ifdef EHWPOISON From f007472331068f35e1cf3dca9adb87a4c1df59e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Jul 2021 19:05:44 +0200 Subject: [PATCH 013/531] linux-user/sparc: Rename target_errno.h -> target_errno_defs.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to have one generic target_errno.h (API to access target errno), and will add target errno definitions in target_errno_defs.h. The sparc target already have its errnos in an header, simply rename it. Reviewed-by: Laurent Vivier Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210708170550.1846343-3-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/{target_errno.h => target_errno_defs.h} | 4 ++-- linux-user/sparc/target_syscall.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename linux-user/sparc/{target_errno.h => target_errno_defs.h} (99%) diff --git a/linux-user/sparc/target_errno.h b/linux-user/sparc/target_errno_defs.h similarity index 99% rename from linux-user/sparc/target_errno.h rename to linux-user/sparc/target_errno_defs.h index 9b846899cd..e000810986 100644 --- a/linux-user/sparc/target_errno.h +++ b/linux-user/sparc/target_errno_defs.h @@ -1,5 +1,5 @@ -#ifndef SPARC_TARGET_ERRNO_H -#define SPARC_TARGET_ERRNO_H +#ifndef SPARC_TARGET_ERRNO_DEFS_H +#define SPARC_TARGET_ERRNO_DEFS_H /* Target errno definitions taken from asm-sparc/errno.h */ #undef TARGET_EWOULDBLOCK diff --git a/linux-user/sparc/target_syscall.h b/linux-user/sparc/target_syscall.h index 15d531f389..dad501d008 100644 --- a/linux-user/sparc/target_syscall.h +++ b/linux-user/sparc/target_syscall.h @@ -1,7 +1,7 @@ #ifndef SPARC_TARGET_SYSCALL_H #define SPARC_TARGET_SYSCALL_H -#include "target_errno.h" +#include "target_errno_defs.h" #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) struct target_pt_regs { From 8f968b6a24aec7de8b1a1b4d2de922adad689297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Jul 2021 19:05:45 +0200 Subject: [PATCH 014/531] linux-user: Extract target errno to 'target_errno_defs.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to access the target errno indepently of the rest of the linux-user code. Move the header containing the generic errno definitions ('errno_defs.h') to 'generic/target_errno_defs.h', create a new 'target_errno_defs.h' in each target which itself includes 'generic/target_errno_defs.h'. Suggested-by: Richard Henderson Reviewed-by: Laurent Vivier Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210708170550.1846343-4-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/aarch64/target_errno_defs.h | 7 +++++++ linux-user/alpha/target_errno_defs.h | 6 ++++++ linux-user/arm/target_errno_defs.h | 7 +++++++ linux-user/cris/target_errno_defs.h | 7 +++++++ linux-user/{errno_defs.h => generic/target_errno_defs.h} | 4 ++-- linux-user/hexagon/target_errno_defs.h | 7 +++++++ linux-user/hppa/target_errno_defs.h | 6 ++++++ linux-user/i386/target_errno_defs.h | 7 +++++++ linux-user/m68k/target_errno_defs.h | 7 +++++++ linux-user/microblaze/target_errno_defs.h | 7 +++++++ linux-user/mips/target_errno_defs.h | 6 ++++++ linux-user/mips64/target_errno_defs.h | 6 ++++++ linux-user/nios2/target_errno_defs.h | 7 +++++++ linux-user/openrisc/target_errno_defs.h | 7 +++++++ linux-user/ppc/target_errno_defs.h | 7 +++++++ linux-user/riscv/target_errno_defs.h | 7 +++++++ linux-user/s390x/target_errno_defs.h | 7 +++++++ linux-user/safe-syscall.S | 2 +- linux-user/sh4/target_errno_defs.h | 7 +++++++ linux-user/sparc/target_errno_defs.h | 7 ++++++- linux-user/sparc/target_syscall.h | 2 -- linux-user/syscall_defs.h | 2 +- linux-user/x86_64/target_errno_defs.h | 7 +++++++ linux-user/xtensa/target_errno_defs.h | 7 +++++++ 24 files changed, 139 insertions(+), 7 deletions(-) create mode 100644 linux-user/aarch64/target_errno_defs.h create mode 100644 linux-user/alpha/target_errno_defs.h create mode 100644 linux-user/arm/target_errno_defs.h create mode 100644 linux-user/cris/target_errno_defs.h rename linux-user/{errno_defs.h => generic/target_errno_defs.h} (99%) create mode 100644 linux-user/hexagon/target_errno_defs.h create mode 100644 linux-user/hppa/target_errno_defs.h create mode 100644 linux-user/i386/target_errno_defs.h create mode 100644 linux-user/m68k/target_errno_defs.h create mode 100644 linux-user/microblaze/target_errno_defs.h create mode 100644 linux-user/mips/target_errno_defs.h create mode 100644 linux-user/mips64/target_errno_defs.h create mode 100644 linux-user/nios2/target_errno_defs.h create mode 100644 linux-user/openrisc/target_errno_defs.h create mode 100644 linux-user/ppc/target_errno_defs.h create mode 100644 linux-user/riscv/target_errno_defs.h create mode 100644 linux-user/s390x/target_errno_defs.h create mode 100644 linux-user/sh4/target_errno_defs.h create mode 100644 linux-user/x86_64/target_errno_defs.h create mode 100644 linux-user/xtensa/target_errno_defs.h diff --git a/linux-user/aarch64/target_errno_defs.h b/linux-user/aarch64/target_errno_defs.h new file mode 100644 index 0000000000..461b547728 --- /dev/null +++ b/linux-user/aarch64/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef AARCH64_TARGET_ERRNO_DEFS_H +#define AARCH64_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/alpha/target_errno_defs.h b/linux-user/alpha/target_errno_defs.h new file mode 100644 index 0000000000..54770108c0 --- /dev/null +++ b/linux-user/alpha/target_errno_defs.h @@ -0,0 +1,6 @@ +#ifndef ALPHA_TARGET_ERRNO_DEFS_H +#define ALPHA_TARGET_ERRNO_DEFS_H + +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/arm/target_errno_defs.h b/linux-user/arm/target_errno_defs.h new file mode 100644 index 0000000000..fd84373238 --- /dev/null +++ b/linux-user/arm/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef ARM_TARGET_ERRNO_DEFS_H +#define ARM_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/cris/target_errno_defs.h b/linux-user/cris/target_errno_defs.h new file mode 100644 index 0000000000..1cf43b17a5 --- /dev/null +++ b/linux-user/cris/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef CRIS_TARGET_ERRNO_DEFS_H +#define CRIS_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/errno_defs.h b/linux-user/generic/target_errno_defs.h similarity index 99% rename from linux-user/errno_defs.h rename to linux-user/generic/target_errno_defs.h index aaf5208d62..17d85e0b61 100644 --- a/linux-user/errno_defs.h +++ b/linux-user/generic/target_errno_defs.h @@ -5,8 +5,8 @@ * Taken from asm-generic/errno-base.h and asm-generic/errno.h */ -#ifndef LINUX_USER_ERRNO_DEFS_H -#define LINUX_USER_ERRNO_DEFS_H +#ifndef GENERIC_TARGET_ERRNO_DEFS_H +#define GENERIC_TARGET_ERRNO_DEFS_H #define TARGET_EPERM 1 /* Operation not permitted */ #define TARGET_ENOENT 2 /* No such file or directory */ diff --git a/linux-user/hexagon/target_errno_defs.h b/linux-user/hexagon/target_errno_defs.h new file mode 100644 index 0000000000..da033a9a9e --- /dev/null +++ b/linux-user/hexagon/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef HEXAGON_TARGET_ERRNO_DEFS_H +#define HEXAGON_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/hppa/target_errno_defs.h b/linux-user/hppa/target_errno_defs.h new file mode 100644 index 0000000000..d6e9676ce2 --- /dev/null +++ b/linux-user/hppa/target_errno_defs.h @@ -0,0 +1,6 @@ +#ifndef HPPA_TARGET_ERRNO_DEFS_H +#define HPPA_TARGET_ERRNO_DEFS_H + +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/i386/target_errno_defs.h b/linux-user/i386/target_errno_defs.h new file mode 100644 index 0000000000..459b2189e2 --- /dev/null +++ b/linux-user/i386/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef I386_TARGET_ERRNO_DEFS_H +#define I386_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/m68k/target_errno_defs.h b/linux-user/m68k/target_errno_defs.h new file mode 100644 index 0000000000..96485a7543 --- /dev/null +++ b/linux-user/m68k/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef M68K_TARGET_ERRNO_DEFS_H +#define M68K_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/microblaze/target_errno_defs.h b/linux-user/microblaze/target_errno_defs.h new file mode 100644 index 0000000000..91a0bbf9dc --- /dev/null +++ b/linux-user/microblaze/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef MICROBLAZE_TARGET_ERRNO_DEFS_H +#define MICROBLAZE_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/mips/target_errno_defs.h b/linux-user/mips/target_errno_defs.h new file mode 100644 index 0000000000..daef95ea70 --- /dev/null +++ b/linux-user/mips/target_errno_defs.h @@ -0,0 +1,6 @@ +#ifndef MIPS_TARGET_ERRNO_DEFS_H +#define MIPS_TARGET_ERRNO_DEFS_H + +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/mips64/target_errno_defs.h b/linux-user/mips64/target_errno_defs.h new file mode 100644 index 0000000000..82b0a704f6 --- /dev/null +++ b/linux-user/mips64/target_errno_defs.h @@ -0,0 +1,6 @@ +#ifndef MIPS64_TARGET_ERRNO_DEFS_H +#define MIPS64_TARGET_ERRNO_DEFS_H + +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/nios2/target_errno_defs.h b/linux-user/nios2/target_errno_defs.h new file mode 100644 index 0000000000..28120013e2 --- /dev/null +++ b/linux-user/nios2/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef NIOS2_TARGET_ERRNO_DEFS_H +#define NIOS2_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/openrisc/target_errno_defs.h b/linux-user/openrisc/target_errno_defs.h new file mode 100644 index 0000000000..cdf159746b --- /dev/null +++ b/linux-user/openrisc/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef OR1K_TARGET_ERRNO_DEFS_H +#define OR1K_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/ppc/target_errno_defs.h b/linux-user/ppc/target_errno_defs.h new file mode 100644 index 0000000000..a24a973342 --- /dev/null +++ b/linux-user/ppc/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef PPC_TARGET_ERRNO_DEFS_H +#define PPC_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/riscv/target_errno_defs.h b/linux-user/riscv/target_errno_defs.h new file mode 100644 index 0000000000..5e377a2fce --- /dev/null +++ b/linux-user/riscv/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef RISCV_TARGET_ERRNO_DEFS_H +#define RISCV_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/s390x/target_errno_defs.h b/linux-user/s390x/target_errno_defs.h new file mode 100644 index 0000000000..f4c09700b5 --- /dev/null +++ b/linux-user/s390x/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef S390X_TARGET_ERRNO_DEFS_H +#define S390X_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/safe-syscall.S b/linux-user/safe-syscall.S index b5df6254ae..42ea7c40ba 100644 --- a/linux-user/safe-syscall.S +++ b/linux-user/safe-syscall.S @@ -11,7 +11,7 @@ */ #include "hostdep.h" -#include "errno_defs.h" +#include "target_errno_defs.h" /* We have the correct host directory on our include path * so that this will pull in the right fragment for the architecture. diff --git a/linux-user/sh4/target_errno_defs.h b/linux-user/sh4/target_errno_defs.h new file mode 100644 index 0000000000..e90adb54ab --- /dev/null +++ b/linux-user/sh4/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef SH4_TARGET_ERRNO_DEFS_H +#define SH4_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/sparc/target_errno_defs.h b/linux-user/sparc/target_errno_defs.h index e000810986..de4f1ffb0a 100644 --- a/linux-user/sparc/target_errno_defs.h +++ b/linux-user/sparc/target_errno_defs.h @@ -1,7 +1,12 @@ #ifndef SPARC_TARGET_ERRNO_DEFS_H #define SPARC_TARGET_ERRNO_DEFS_H -/* Target errno definitions taken from asm-sparc/errno.h */ +#include "../generic/target_errno_defs.h" + +/* + * Generic target errno overridden with definitions taken + * from asm-sparc/errno.h + */ #undef TARGET_EWOULDBLOCK #define TARGET_EWOULDBLOCK TARGET_EAGAIN /* Operation would block */ #undef TARGET_EINPROGRESS diff --git a/linux-user/sparc/target_syscall.h b/linux-user/sparc/target_syscall.h index dad501d008..087b39d39c 100644 --- a/linux-user/sparc/target_syscall.h +++ b/linux-user/sparc/target_syscall.h @@ -1,8 +1,6 @@ #ifndef SPARC_TARGET_SYSCALL_H #define SPARC_TARGET_SYSCALL_H -#include "target_errno_defs.h" - #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) struct target_pt_regs { abi_ulong u_regs[16]; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 18b031a2f6..a5ce487dcc 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2751,7 +2751,7 @@ struct target_drm_i915_getparam { #include "socket.h" -#include "errno_defs.h" +#include "target_errno_defs.h" #define FUTEX_WAIT 0 #define FUTEX_WAKE 1 diff --git a/linux-user/x86_64/target_errno_defs.h b/linux-user/x86_64/target_errno_defs.h new file mode 100644 index 0000000000..cb2a0f6e0b --- /dev/null +++ b/linux-user/x86_64/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef X86_64_TARGET_ERRNO_DEFS_H +#define X86_64_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/xtensa/target_errno_defs.h b/linux-user/xtensa/target_errno_defs.h new file mode 100644 index 0000000000..66fade2d0c --- /dev/null +++ b/linux-user/xtensa/target_errno_defs.h @@ -0,0 +1,7 @@ +#ifndef XTENSA_TARGET_ERRNO_DEFS_H +#define XTENSA_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif From a4c7e27d472933fda24aec48f304febe9455fc7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Jul 2021 19:05:46 +0200 Subject: [PATCH 015/531] linux-user/alpha: Move errno definitions to 'target_errno_defs.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Laurent Vivier Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210708170550.1846343-5-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/alpha/target_errno_defs.h | 198 +++++++++++++++++++++++++++ linux-user/alpha/target_syscall.h | 194 -------------------------- 2 files changed, 198 insertions(+), 194 deletions(-) diff --git a/linux-user/alpha/target_errno_defs.h b/linux-user/alpha/target_errno_defs.h index 54770108c0..07924b13aa 100644 --- a/linux-user/alpha/target_errno_defs.h +++ b/linux-user/alpha/target_errno_defs.h @@ -3,4 +3,202 @@ #include "../generic/target_errno_defs.h" +/* + * Generic target errno overridden with definitions taken + * from asm-alpha/errno.h + */ +#undef TARGET_EWOULDBLOCK +#define TARGET_EWOULDBLOCK TARGET_EAGAIN +#undef TARGET_EDEADLK +#define TARGET_EDEADLK 11 +#undef TARGET_EAGAIN +#define TARGET_EAGAIN 35 +#undef TARGET_EINPROGRESS +#define TARGET_EINPROGRESS 36 +#undef TARGET_EALREADY +#define TARGET_EALREADY 37 +#undef TARGET_ENOTSOCK +#define TARGET_ENOTSOCK 38 +#undef TARGET_EDESTADDRREQ +#define TARGET_EDESTADDRREQ 39 +#undef TARGET_EMSGSIZE +#define TARGET_EMSGSIZE 40 +#undef TARGET_EPROTOTYPE +#define TARGET_EPROTOTYPE 41 +#undef TARGET_ENOPROTOOPT +#define TARGET_ENOPROTOOPT 42 +#undef TARGET_EPROTONOSUPPORT +#define TARGET_EPROTONOSUPPORT 43 +#undef TARGET_ESOCKTNOSUPPORT +#define TARGET_ESOCKTNOSUPPORT 44 +#undef TARGET_EOPNOTSUPP +#define TARGET_EOPNOTSUPP 45 +#undef TARGET_EPFNOSUPPORT +#define TARGET_EPFNOSUPPORT 46 +#undef TARGET_EAFNOSUPPORT +#define TARGET_EAFNOSUPPORT 47 +#undef TARGET_EADDRINUSE +#define TARGET_EADDRINUSE 48 +#undef TARGET_EADDRNOTAVAIL +#define TARGET_EADDRNOTAVAIL 49 +#undef TARGET_ENETDOWN +#define TARGET_ENETDOWN 50 +#undef TARGET_ENETUNREACH +#define TARGET_ENETUNREACH 51 +#undef TARGET_ENETRESET +#define TARGET_ENETRESET 52 +#undef TARGET_ECONNABORTED +#define TARGET_ECONNABORTED 53 +#undef TARGET_ECONNRESET +#define TARGET_ECONNRESET 54 +#undef TARGET_ENOBUFS +#define TARGET_ENOBUFS 55 +#undef TARGET_EISCONN +#define TARGET_EISCONN 56 +#undef TARGET_ENOTCONN +#define TARGET_ENOTCONN 57 +#undef TARGET_ESHUTDOWN +#define TARGET_ESHUTDOWN 58 +#undef TARGET_ETOOMANYREFS +#define TARGET_ETOOMANYREFS 59 +#undef TARGET_ETIMEDOUT +#define TARGET_ETIMEDOUT 60 +#undef TARGET_ECONNREFUSED +#define TARGET_ECONNREFUSED 61 +#undef TARGET_ELOOP +#define TARGET_ELOOP 62 +#undef TARGET_ENAMETOOLONG +#define TARGET_ENAMETOOLONG 63 +#undef TARGET_EHOSTDOWN +#define TARGET_EHOSTDOWN 64 +#undef TARGET_EHOSTUNREACH +#define TARGET_EHOSTUNREACH 65 +#undef TARGET_ENOTEMPTY +#define TARGET_ENOTEMPTY 66 +/* Unused 67 */ +#undef TARGET_EUSERS +#define TARGET_EUSERS 68 +#undef TARGET_EDQUOT +#define TARGET_EDQUOT 69 +#undef TARGET_ESTALE +#define TARGET_ESTALE 70 +#undef TARGET_EREMOTE +#define TARGET_EREMOTE 71 +/* Unused 72-76 */ +#undef TARGET_ENOLCK +#define TARGET_ENOLCK 77 +#undef TARGET_ENOSYS +#define TARGET_ENOSYS 78 +/* Unused 79 */ +#undef TARGET_ENOMSG +#define TARGET_ENOMSG 80 +#undef TARGET_EIDRM +#define TARGET_EIDRM 81 +#undef TARGET_ENOSR +#define TARGET_ENOSR 82 +#undef TARGET_ETIME +#define TARGET_ETIME 83 +#undef TARGET_EBADMSG +#define TARGET_EBADMSG 84 +#undef TARGET_EPROTO +#define TARGET_EPROTO 85 +#undef TARGET_ENODATA +#define TARGET_ENODATA 86 +#undef TARGET_ENOSTR +#define TARGET_ENOSTR 87 +#undef TARGET_ECHRNG +#define TARGET_ECHRNG 88 +#undef TARGET_EL2NSYNC +#define TARGET_EL2NSYNC 89 +#undef TARGET_EL3HLT +#define TARGET_EL3HLT 90 +#undef TARGET_EL3RST +#define TARGET_EL3RST 91 +#undef TARGET_ENOPKG +#define TARGET_ENOPKG 92 +#undef TARGET_ELNRNG +#define TARGET_ELNRNG 93 +#undef TARGET_EUNATCH +#define TARGET_EUNATCH 94 +#undef TARGET_ENOCSI +#define TARGET_ENOCSI 95 +#undef TARGET_EL2HLT +#define TARGET_EL2HLT 96 +#undef TARGET_EBADE +#define TARGET_EBADE 97 +#undef TARGET_EBADR +#define TARGET_EBADR 98 +#undef TARGET_EXFULL +#define TARGET_EXFULL 99 +#undef TARGET_ENOANO +#define TARGET_ENOANO 100 +#undef TARGET_EBADRQC +#define TARGET_EBADRQC 101 +#undef TARGET_EBADSLT +#define TARGET_EBADSLT 102 +/* Unused 103 */ +#undef TARGET_EBFONT +#define TARGET_EBFONT 104 +#undef TARGET_ENONET +#define TARGET_ENONET 105 +#undef TARGET_ENOLINK +#define TARGET_ENOLINK 106 +#undef TARGET_EADV +#define TARGET_EADV 107 +#undef TARGET_ESRMNT +#define TARGET_ESRMNT 108 +#undef TARGET_ECOMM +#define TARGET_ECOMM 109 +#undef TARGET_EMULTIHOP +#define TARGET_EMULTIHOP 110 +#undef TARGET_EDOTDOT +#define TARGET_EDOTDOT 111 +#undef TARGET_EOVERFLOW +#define TARGET_EOVERFLOW 112 +#undef TARGET_ENOTUNIQ +#define TARGET_ENOTUNIQ 113 +#undef TARGET_EBADFD +#define TARGET_EBADFD 114 +#undef TARGET_EREMCHG +#define TARGET_EREMCHG 115 +#undef TARGET_EILSEQ +#define TARGET_EILSEQ 116 +/* Same as default 117-121 */ +#undef TARGET_ELIBACC +#define TARGET_ELIBACC 122 +#undef TARGET_ELIBBAD +#define TARGET_ELIBBAD 123 +#undef TARGET_ELIBSCN +#define TARGET_ELIBSCN 124 +#undef TARGET_ELIBMAX +#define TARGET_ELIBMAX 125 +#undef TARGET_ELIBEXEC +#define TARGET_ELIBEXEC 126 +#undef TARGET_ERESTART +#define TARGET_ERESTART 127 +#undef TARGET_ESTRPIPE +#define TARGET_ESTRPIPE 128 +#undef TARGET_ENOMEDIUM +#define TARGET_ENOMEDIUM 129 +#undef TARGET_EMEDIUMTYPE +#define TARGET_EMEDIUMTYPE 130 +#undef TARGET_ECANCELED +#define TARGET_ECANCELED 131 +#undef TARGET_ENOKEY +#define TARGET_ENOKEY 132 +#undef TARGET_EKEYEXPIRED +#define TARGET_EKEYEXPIRED 133 +#undef TARGET_EKEYREVOKED +#define TARGET_EKEYREVOKED 134 +#undef TARGET_EKEYREJECTED +#define TARGET_EKEYREJECTED 135 +#undef TARGET_EOWNERDEAD +#define TARGET_EOWNERDEAD 136 +#undef TARGET_ENOTRECOVERABLE +#define TARGET_ENOTRECOVERABLE 137 +#undef TARGET_ERFKILL +#define TARGET_ERFKILL 138 +#undef TARGET_EHWPOISON +#define TARGET_EHWPOISON 139 + #endif diff --git a/linux-user/alpha/target_syscall.h b/linux-user/alpha/target_syscall.h index 13a71f35ea..03091bf0a8 100644 --- a/linux-user/alpha/target_syscall.h +++ b/linux-user/alpha/target_syscall.h @@ -44,200 +44,6 @@ struct target_pt_regs { #define UNAME_MACHINE "alpha" #define UNAME_MINIMUM_RELEASE "2.6.32" -#undef TARGET_EWOULDBLOCK -#define TARGET_EWOULDBLOCK TARGET_EAGAIN /* Operation would block */ -#undef TARGET_EDEADLK -#define TARGET_EDEADLK 11 -#undef TARGET_EAGAIN -#define TARGET_EAGAIN 35 -#undef TARGET_EINPROGRESS -#define TARGET_EINPROGRESS 36 -#undef TARGET_EALREADY -#define TARGET_EALREADY 37 -#undef TARGET_ENOTSOCK -#define TARGET_ENOTSOCK 38 -#undef TARGET_EDESTADDRREQ -#define TARGET_EDESTADDRREQ 39 -#undef TARGET_EMSGSIZE -#define TARGET_EMSGSIZE 40 -#undef TARGET_EPROTOTYPE -#define TARGET_EPROTOTYPE 41 -#undef TARGET_ENOPROTOOPT -#define TARGET_ENOPROTOOPT 42 -#undef TARGET_EPROTONOSUPPORT -#define TARGET_EPROTONOSUPPORT 43 -#undef TARGET_ESOCKTNOSUPPORT -#define TARGET_ESOCKTNOSUPPORT 44 -#undef TARGET_EOPNOTSUPP -#define TARGET_EOPNOTSUPP 45 -#undef TARGET_EPFNOSUPPORT -#define TARGET_EPFNOSUPPORT 46 -#undef TARGET_EAFNOSUPPORT -#define TARGET_EAFNOSUPPORT 47 -#undef TARGET_EADDRINUSE -#define TARGET_EADDRINUSE 48 -#undef TARGET_EADDRNOTAVAIL -#define TARGET_EADDRNOTAVAIL 49 -#undef TARGET_ENETDOWN -#define TARGET_ENETDOWN 50 -#undef TARGET_ENETUNREACH -#define TARGET_ENETUNREACH 51 -#undef TARGET_ENETRESET -#define TARGET_ENETRESET 52 -#undef TARGET_ECONNABORTED -#define TARGET_ECONNABORTED 53 -#undef TARGET_ECONNRESET -#define TARGET_ECONNRESET 54 -#undef TARGET_ENOBUFS -#define TARGET_ENOBUFS 55 -#undef TARGET_EISCONN -#define TARGET_EISCONN 56 -#undef TARGET_ENOTCONN -#define TARGET_ENOTCONN 57 -#undef TARGET_ESHUTDOWN -#define TARGET_ESHUTDOWN 58 -#undef TARGET_ETOOMANYREFS -#define TARGET_ETOOMANYREFS 59 -#undef TARGET_ETIMEDOUT -#define TARGET_ETIMEDOUT 60 -#undef TARGET_ECONNREFUSED -#define TARGET_ECONNREFUSED 61 -#undef TARGET_ELOOP -#define TARGET_ELOOP 62 -#undef TARGET_ENAMETOOLONG -#define TARGET_ENAMETOOLONG 63 -#undef TARGET_EHOSTDOWN -#define TARGET_EHOSTDOWN 64 -#undef TARGET_EHOSTUNREACH -#define TARGET_EHOSTUNREACH 65 -#undef TARGET_ENOTEMPTY -#define TARGET_ENOTEMPTY 66 -/* Unused 67 */ -#undef TARGET_EUSERS -#define TARGET_EUSERS 68 -#undef TARGET_EDQUOT -#define TARGET_EDQUOT 69 -#undef TARGET_ESTALE -#define TARGET_ESTALE 70 -#undef TARGET_EREMOTE -#define TARGET_EREMOTE 71 -/* Unused 72-76 */ -#undef TARGET_ENOLCK -#define TARGET_ENOLCK 77 -#undef TARGET_ENOSYS -#define TARGET_ENOSYS 78 -/* Unused 79 */ -#undef TARGET_ENOMSG -#define TARGET_ENOMSG 80 -#undef TARGET_EIDRM -#define TARGET_EIDRM 81 -#undef TARGET_ENOSR -#define TARGET_ENOSR 82 -#undef TARGET_ETIME -#define TARGET_ETIME 83 -#undef TARGET_EBADMSG -#define TARGET_EBADMSG 84 -#undef TARGET_EPROTO -#define TARGET_EPROTO 85 -#undef TARGET_ENODATA -#define TARGET_ENODATA 86 -#undef TARGET_ENOSTR -#define TARGET_ENOSTR 87 -#undef TARGET_ECHRNG -#define TARGET_ECHRNG 88 -#undef TARGET_EL2NSYNC -#define TARGET_EL2NSYNC 89 -#undef TARGET_EL3HLT -#define TARGET_EL3HLT 90 -#undef TARGET_EL3RST -#define TARGET_EL3RST 91 -#undef TARGET_ENOPKG -#define TARGET_ENOPKG 92 -#undef TARGET_ELNRNG -#define TARGET_ELNRNG 93 -#undef TARGET_EUNATCH -#define TARGET_EUNATCH 94 -#undef TARGET_ENOCSI -#define TARGET_ENOCSI 95 -#undef TARGET_EL2HLT -#define TARGET_EL2HLT 96 -#undef TARGET_EBADE -#define TARGET_EBADE 97 -#undef TARGET_EBADR -#define TARGET_EBADR 98 -#undef TARGET_EXFULL -#define TARGET_EXFULL 99 -#undef TARGET_ENOANO -#define TARGET_ENOANO 100 -#undef TARGET_EBADRQC -#define TARGET_EBADRQC 101 -#undef TARGET_EBADSLT -#define TARGET_EBADSLT 102 -/* Unused 103 */ -#undef TARGET_EBFONT -#define TARGET_EBFONT 104 -#undef TARGET_ENONET -#define TARGET_ENONET 105 -#undef TARGET_ENOLINK -#define TARGET_ENOLINK 106 -#undef TARGET_EADV -#define TARGET_EADV 107 -#undef TARGET_ESRMNT -#define TARGET_ESRMNT 108 -#undef TARGET_ECOMM -#define TARGET_ECOMM 109 -#undef TARGET_EMULTIHOP -#define TARGET_EMULTIHOP 110 -#undef TARGET_EDOTDOT -#define TARGET_EDOTDOT 111 -#undef TARGET_EOVERFLOW -#define TARGET_EOVERFLOW 112 -#undef TARGET_ENOTUNIQ -#define TARGET_ENOTUNIQ 113 -#undef TARGET_EBADFD -#define TARGET_EBADFD 114 -#undef TARGET_EREMCHG -#define TARGET_EREMCHG 115 -#undef TARGET_EILSEQ -#define TARGET_EILSEQ 116 -/* Same as default 117-121 */ -#undef TARGET_ELIBACC -#define TARGET_ELIBACC 122 -#undef TARGET_ELIBBAD -#define TARGET_ELIBBAD 123 -#undef TARGET_ELIBSCN -#define TARGET_ELIBSCN 124 -#undef TARGET_ELIBMAX -#define TARGET_ELIBMAX 125 -#undef TARGET_ELIBEXEC -#define TARGET_ELIBEXEC 126 -#undef TARGET_ERESTART -#define TARGET_ERESTART 127 -#undef TARGET_ESTRPIPE -#define TARGET_ESTRPIPE 128 -#undef TARGET_ENOMEDIUM -#define TARGET_ENOMEDIUM 129 -#undef TARGET_EMEDIUMTYPE -#define TARGET_EMEDIUMTYPE 130 -#undef TARGET_ECANCELED -#define TARGET_ECANCELED 131 -#undef TARGET_ENOKEY -#define TARGET_ENOKEY 132 -#undef TARGET_EKEYEXPIRED -#define TARGET_EKEYEXPIRED 133 -#undef TARGET_EKEYREVOKED -#define TARGET_EKEYREVOKED 134 -#undef TARGET_EKEYREJECTED -#define TARGET_EKEYREJECTED 135 -#undef TARGET_EOWNERDEAD -#define TARGET_EOWNERDEAD 136 -#undef TARGET_ENOTRECOVERABLE -#define TARGET_ENOTRECOVERABLE 137 -#undef TARGET_ERFKILL -#define TARGET_ERFKILL 138 -#undef TARGET_EHWPOISON -#define TARGET_EHWPOISON 139 - // For sys_osf_getsysinfo #define TARGET_GSI_UACPROC 8 #define TARGET_GSI_IEEE_FP_CONTROL 45 From 366d1ef2e6e262a08ad2de2aa67b5896b7f460b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Jul 2021 19:05:47 +0200 Subject: [PATCH 016/531] linux-user/hppa: Move errno definitions to 'target_errno_defs.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Laurent Vivier Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210708170550.1846343-6-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/hppa/target_errno_defs.h | 214 ++++++++++++++++++++++++++++ linux-user/hppa/target_syscall.h | 210 --------------------------- 2 files changed, 214 insertions(+), 210 deletions(-) diff --git a/linux-user/hppa/target_errno_defs.h b/linux-user/hppa/target_errno_defs.h index d6e9676ce2..b8f728f586 100644 --- a/linux-user/hppa/target_errno_defs.h +++ b/linux-user/hppa/target_errno_defs.h @@ -3,4 +3,218 @@ #include "../generic/target_errno_defs.h" +/* + * Generic target errno overridden with definitions taken + * from asm-parisc/errno.h + */ +#undef TARGET_EWOULDBLOCK +#define TARGET_EWOULDBLOCK TARGET_EAGAIN /* Operation would block */ +#undef TARGET_ENOMSG +#define TARGET_ENOMSG 35 +#undef TARGET_EIDRM +#define TARGET_EIDRM 36 +#undef TARGET_ECHRNG +#define TARGET_ECHRNG 37 +#undef TARGET_EL2NSYNC +#define TARGET_EL2NSYNC 38 +#undef TARGET_EL3HLT +#define TARGET_EL3HLT 39 +#undef TARGET_EL3RST +#define TARGET_EL3RST 40 +#undef TARGET_ELNRNG +#define TARGET_ELNRNG 41 +#undef TARGET_EUNATCH +#define TARGET_EUNATCH 42 +#undef TARGET_ENOCSI +#define TARGET_ENOCSI 43 +#undef TARGET_EL2HLT +#define TARGET_EL2HLT 44 +#undef TARGET_EDEADLK +#define TARGET_EDEADLK 45 +#undef TARGET_ENOLCK +#define TARGET_ENOLCK 46 +#undef TARGET_EILSEQ +#define TARGET_EILSEQ 47 + +#undef TARGET_ENONET +#define TARGET_ENONET 50 +#undef TARGET_ENODATA +#define TARGET_ENODATA 51 +#undef TARGET_ETIME +#define TARGET_ETIME 52 +#undef TARGET_ENOSR +#define TARGET_ENOSR 53 +#undef TARGET_ENOSTR +#define TARGET_ENOSTR 54 +#undef TARGET_ENOPKG +#define TARGET_ENOPKG 55 + +#undef TARGET_ENOLINK +#define TARGET_ENOLINK 57 +#undef TARGET_EADV +#define TARGET_EADV 58 +#undef TARGET_ESRMNT +#define TARGET_ESRMNT 59 +#undef TARGET_ECOMM +#define TARGET_ECOMM 60 +#undef TARGET_EPROTO +#define TARGET_EPROTO 61 + +#undef TARGET_EMULTIHOP +#define TARGET_EMULTIHOP 64 + +#undef TARGET_EDOTDOT +#define TARGET_EDOTDOT 66 +#undef TARGET_EBADMSG +#define TARGET_EBADMSG 67 +#undef TARGET_EUSERS +#define TARGET_EUSERS 68 +#undef TARGET_EDQUOT +#define TARGET_EDQUOT 69 +#undef TARGET_ESTALE +#define TARGET_ESTALE 70 +#undef TARGET_EREMOTE +#define TARGET_EREMOTE 71 +#undef TARGET_EOVERFLOW +#define TARGET_EOVERFLOW 72 + +#undef TARGET_EBADE +#define TARGET_EBADE 160 +#undef TARGET_EBADR +#define TARGET_EBADR 161 +#undef TARGET_EXFULL +#define TARGET_EXFULL 162 +#undef TARGET_ENOANO +#define TARGET_ENOANO 163 +#undef TARGET_EBADRQC +#define TARGET_EBADRQC 164 +#undef TARGET_EBADSLT +#define TARGET_EBADSLT 165 +#undef TARGET_EBFONT +#define TARGET_EBFONT 166 +#undef TARGET_ENOTUNIQ +#define TARGET_ENOTUNIQ 167 +#undef TARGET_EBADFD +#define TARGET_EBADFD 168 +#undef TARGET_EREMCHG +#define TARGET_EREMCHG 169 +#undef TARGET_ELIBACC +#define TARGET_ELIBACC 170 +#undef TARGET_ELIBBAD +#define TARGET_ELIBBAD 171 +#undef TARGET_ELIBSCN +#define TARGET_ELIBSCN 172 +#undef TARGET_ELIBMAX +#define TARGET_ELIBMAX 173 +#undef TARGET_ELIBEXEC +#define TARGET_ELIBEXEC 174 +#undef TARGET_ERESTART +#define TARGET_ERESTART 175 +#undef TARGET_ESTRPIPE +#define TARGET_ESTRPIPE 176 +#undef TARGET_EUCLEAN +#define TARGET_EUCLEAN 177 +#undef TARGET_ENOTNAM +#define TARGET_ENOTNAM 178 +#undef TARGET_ENAVAIL +#define TARGET_ENAVAIL 179 +#undef TARGET_EISNAM +#define TARGET_EISNAM 180 +#undef TARGET_EREMOTEIO +#define TARGET_EREMOTEIO 181 +#undef TARGET_ENOMEDIUM +#define TARGET_ENOMEDIUM 182 +#undef TARGET_EMEDIUMTYPE +#define TARGET_EMEDIUMTYPE 183 +#undef TARGET_ENOKEY +#define TARGET_ENOKEY 184 +#undef TARGET_EKEYEXPIRED +#define TARGET_EKEYEXPIRED 185 +#undef TARGET_EKEYREVOKED +#define TARGET_EKEYREVOKED 186 +#undef TARGET_EKEYREJECTED +#define TARGET_EKEYREJECTED 187 + +/* Never used in linux. */ +/* #define TARGET_ENOSYM 215 */ +#undef TARGET_ENOTSOCK +#define TARGET_ENOTSOCK 216 +#undef TARGET_EDESTADDRREQ +#define TARGET_EDESTADDRREQ 217 +#undef TARGET_EMSGSIZE +#define TARGET_EMSGSIZE 218 +#undef TARGET_EPROTOTYPE +#define TARGET_EPROTOTYPE 219 +#undef TARGET_ENOPROTOOPT +#define TARGET_ENOPROTOOPT 220 +#undef TARGET_EPROTONOSUPPORT +#define TARGET_EPROTONOSUPPORT 221 +#undef TARGET_ESOCKTNOSUPPORT +#define TARGET_ESOCKTNOSUPPORT 222 +#undef TARGET_EOPNOTSUPP +#define TARGET_EOPNOTSUPP 223 +#undef TARGET_EPFNOSUPPORT +#define TARGET_EPFNOSUPPORT 224 +#undef TARGET_EAFNOSUPPORT +#define TARGET_EAFNOSUPPORT 225 +#undef TARGET_EADDRINUSE +#define TARGET_EADDRINUSE 226 +#undef TARGET_EADDRNOTAVAIL +#define TARGET_EADDRNOTAVAIL 227 +#undef TARGET_ENETDOWN +#define TARGET_ENETDOWN 228 +#undef TARGET_ENETUNREACH +#define TARGET_ENETUNREACH 229 +#undef TARGET_ENETRESET +#define TARGET_ENETRESET 230 +#undef TARGET_ECONNABORTED +#define TARGET_ECONNABORTED 231 +#undef TARGET_ECONNRESET +#define TARGET_ECONNRESET 232 +#undef TARGET_ENOBUFS +#define TARGET_ENOBUFS 233 +#undef TARGET_EISCONN +#define TARGET_EISCONN 234 +#undef TARGET_ENOTCONN +#define TARGET_ENOTCONN 235 +#undef TARGET_ESHUTDOWN +#define TARGET_ESHUTDOWN 236 +#undef TARGET_ETOOMANYREFS +#define TARGET_ETOOMANYREFS 237 +#undef TARGET_ETIMEDOUT +#define TARGET_ETIMEDOUT 238 +#undef TARGET_ECONNREFUSED +#define TARGET_ECONNREFUSED 239 +#define TARGET_EREMOTERELEASE 240 +#undef TARGET_EHOSTDOWN +#define TARGET_EHOSTDOWN 241 +#undef TARGET_EHOSTUNREACH +#define TARGET_EHOSTUNREACH 242 + +#undef TARGET_EALREADY +#define TARGET_EALREADY 244 +#undef TARGET_EINPROGRESS +#define TARGET_EINPROGRESS 245 +#undef TARGET_ENOTEMPTY +#define TARGET_ENOTEMPTY 247 +#undef TARGET_ENAMETOOLONG +#define TARGET_ENAMETOOLONG 248 +#undef TARGET_ELOOP +#define TARGET_ELOOP 249 +#undef TARGET_ENOSYS +#define TARGET_ENOSYS 251 + +#undef TARGET_ECANCELED +#define TARGET_ECANCELED 253 + +#undef TARGET_EOWNERDEAD +#define TARGET_EOWNERDEAD 254 +#undef TARGET_ENOTRECOVERABLE +#define TARGET_ENOTRECOVERABLE 255 + +#undef TARGET_ERFKILL +#define TARGET_ERFKILL 256 +#undef TARGET_EHWPOISON +#define TARGET_EHWPOISON 257 + #endif diff --git a/linux-user/hppa/target_syscall.h b/linux-user/hppa/target_syscall.h index 97a095656d..0018bcb5c4 100644 --- a/linux-user/hppa/target_syscall.h +++ b/linux-user/hppa/target_syscall.h @@ -27,214 +27,4 @@ struct target_pt_regs { #define TARGET_MCL_FUTURE 2 #define TARGET_MCL_ONFAULT 4 -#undef TARGET_EWOULDBLOCK -#define TARGET_EWOULDBLOCK TARGET_EAGAIN /* Operation would block */ -#undef TARGET_ENOMSG -#define TARGET_ENOMSG 35 -#undef TARGET_EIDRM -#define TARGET_EIDRM 36 -#undef TARGET_ECHRNG -#define TARGET_ECHRNG 37 -#undef TARGET_EL2NSYNC -#define TARGET_EL2NSYNC 38 -#undef TARGET_EL3HLT -#define TARGET_EL3HLT 39 -#undef TARGET_EL3RST -#define TARGET_EL3RST 40 -#undef TARGET_ELNRNG -#define TARGET_ELNRNG 41 -#undef TARGET_EUNATCH -#define TARGET_EUNATCH 42 -#undef TARGET_ENOCSI -#define TARGET_ENOCSI 43 -#undef TARGET_EL2HLT -#define TARGET_EL2HLT 44 -#undef TARGET_EDEADLK -#define TARGET_EDEADLK 45 -#undef TARGET_ENOLCK -#define TARGET_ENOLCK 46 -#undef TARGET_EILSEQ -#define TARGET_EILSEQ 47 - -#undef TARGET_ENONET -#define TARGET_ENONET 50 -#undef TARGET_ENODATA -#define TARGET_ENODATA 51 -#undef TARGET_ETIME -#define TARGET_ETIME 52 -#undef TARGET_ENOSR -#define TARGET_ENOSR 53 -#undef TARGET_ENOSTR -#define TARGET_ENOSTR 54 -#undef TARGET_ENOPKG -#define TARGET_ENOPKG 55 - -#undef TARGET_ENOLINK -#define TARGET_ENOLINK 57 -#undef TARGET_EADV -#define TARGET_EADV 58 -#undef TARGET_ESRMNT -#define TARGET_ESRMNT 59 -#undef TARGET_ECOMM -#define TARGET_ECOMM 60 -#undef TARGET_EPROTO -#define TARGET_EPROTO 61 - -#undef TARGET_EMULTIHOP -#define TARGET_EMULTIHOP 64 - -#undef TARGET_EDOTDOT -#define TARGET_EDOTDOT 66 -#undef TARGET_EBADMSG -#define TARGET_EBADMSG 67 -#undef TARGET_EUSERS -#define TARGET_EUSERS 68 -#undef TARGET_EDQUOT -#define TARGET_EDQUOT 69 -#undef TARGET_ESTALE -#define TARGET_ESTALE 70 -#undef TARGET_EREMOTE -#define TARGET_EREMOTE 71 -#undef TARGET_EOVERFLOW -#define TARGET_EOVERFLOW 72 - -#undef TARGET_EBADE -#define TARGET_EBADE 160 -#undef TARGET_EBADR -#define TARGET_EBADR 161 -#undef TARGET_EXFULL -#define TARGET_EXFULL 162 -#undef TARGET_ENOANO -#define TARGET_ENOANO 163 -#undef TARGET_EBADRQC -#define TARGET_EBADRQC 164 -#undef TARGET_EBADSLT -#define TARGET_EBADSLT 165 -#undef TARGET_EBFONT -#define TARGET_EBFONT 166 -#undef TARGET_ENOTUNIQ -#define TARGET_ENOTUNIQ 167 -#undef TARGET_EBADFD -#define TARGET_EBADFD 168 -#undef TARGET_EREMCHG -#define TARGET_EREMCHG 169 -#undef TARGET_ELIBACC -#define TARGET_ELIBACC 170 -#undef TARGET_ELIBBAD -#define TARGET_ELIBBAD 171 -#undef TARGET_ELIBSCN -#define TARGET_ELIBSCN 172 -#undef TARGET_ELIBMAX -#define TARGET_ELIBMAX 173 -#undef TARGET_ELIBEXEC -#define TARGET_ELIBEXEC 174 -#undef TARGET_ERESTART -#define TARGET_ERESTART 175 -#undef TARGET_ESTRPIPE -#define TARGET_ESTRPIPE 176 -#undef TARGET_EUCLEAN -#define TARGET_EUCLEAN 177 -#undef TARGET_ENOTNAM -#define TARGET_ENOTNAM 178 -#undef TARGET_ENAVAIL -#define TARGET_ENAVAIL 179 -#undef TARGET_EISNAM -#define TARGET_EISNAM 180 -#undef TARGET_EREMOTEIO -#define TARGET_EREMOTEIO 181 -#undef TARGET_ENOMEDIUM -#define TARGET_ENOMEDIUM 182 -#undef TARGET_EMEDIUMTYPE -#define TARGET_EMEDIUMTYPE 183 -#undef TARGET_ENOKEY -#define TARGET_ENOKEY 184 -#undef TARGET_EKEYEXPIRED -#define TARGET_EKEYEXPIRED 185 -#undef TARGET_EKEYREVOKED -#define TARGET_EKEYREVOKED 186 -#undef TARGET_EKEYREJECTED -#define TARGET_EKEYREJECTED 187 - -/* Never used in linux. */ -/* #define TARGET_ENOSYM 215 */ -#undef TARGET_ENOTSOCK -#define TARGET_ENOTSOCK 216 -#undef TARGET_EDESTADDRREQ -#define TARGET_EDESTADDRREQ 217 -#undef TARGET_EMSGSIZE -#define TARGET_EMSGSIZE 218 -#undef TARGET_EPROTOTYPE -#define TARGET_EPROTOTYPE 219 -#undef TARGET_ENOPROTOOPT -#define TARGET_ENOPROTOOPT 220 -#undef TARGET_EPROTONOSUPPORT -#define TARGET_EPROTONOSUPPORT 221 -#undef TARGET_ESOCKTNOSUPPORT -#define TARGET_ESOCKTNOSUPPORT 222 -#undef TARGET_EOPNOTSUPP -#define TARGET_EOPNOTSUPP 223 -#undef TARGET_EPFNOSUPPORT -#define TARGET_EPFNOSUPPORT 224 -#undef TARGET_EAFNOSUPPORT -#define TARGET_EAFNOSUPPORT 225 -#undef TARGET_EADDRINUSE -#define TARGET_EADDRINUSE 226 -#undef TARGET_EADDRNOTAVAIL -#define TARGET_EADDRNOTAVAIL 227 -#undef TARGET_ENETDOWN -#define TARGET_ENETDOWN 228 -#undef TARGET_ENETUNREACH -#define TARGET_ENETUNREACH 229 -#undef TARGET_ENETRESET -#define TARGET_ENETRESET 230 -#undef TARGET_ECONNABORTED -#define TARGET_ECONNABORTED 231 -#undef TARGET_ECONNRESET -#define TARGET_ECONNRESET 232 -#undef TARGET_ENOBUFS -#define TARGET_ENOBUFS 233 -#undef TARGET_EISCONN -#define TARGET_EISCONN 234 -#undef TARGET_ENOTCONN -#define TARGET_ENOTCONN 235 -#undef TARGET_ESHUTDOWN -#define TARGET_ESHUTDOWN 236 -#undef TARGET_ETOOMANYREFS -#define TARGET_ETOOMANYREFS 237 -#undef TARGET_ETIMEDOUT -#define TARGET_ETIMEDOUT 238 -#undef TARGET_ECONNREFUSED -#define TARGET_ECONNREFUSED 239 -#define TARGET_EREMOTERELEASE 240 -#undef TARGET_EHOSTDOWN -#define TARGET_EHOSTDOWN 241 -#undef TARGET_EHOSTUNREACH -#define TARGET_EHOSTUNREACH 242 - -#undef TARGET_EALREADY -#define TARGET_EALREADY 244 -#undef TARGET_EINPROGRESS -#define TARGET_EINPROGRESS 245 -#undef TARGET_ENOTEMPTY -#define TARGET_ENOTEMPTY 247 -#undef TARGET_ENAMETOOLONG -#define TARGET_ENAMETOOLONG 248 -#undef TARGET_ELOOP -#define TARGET_ELOOP 249 -#undef TARGET_ENOSYS -#define TARGET_ENOSYS 251 - -#undef TARGET_ECANCELED -#define TARGET_ECANCELED 253 - -#undef TARGET_EOWNERDEAD -#define TARGET_EOWNERDEAD 254 -#undef TARGET_ENOTRECOVERABLE -#define TARGET_ENOTRECOVERABLE 255 - -#undef TARGET_ERFKILL -#define TARGET_ERFKILL 256 -#undef TARGET_EHWPOISON -#define TARGET_EHWPOISON 257 - #endif /* HPPA_TARGET_SYSCALL_H */ From f317c0ee575c07b6461a6f1c254b9230c2952c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Jul 2021 19:05:48 +0200 Subject: [PATCH 017/531] linux-user/mips: Move errno definitions to 'target_errno_defs.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Richard Henderson Reviewed-by: Laurent Vivier Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210708170550.1846343-7-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/mips/target_errno_defs.h | 215 ++++++++++++++++++++++++++ linux-user/mips/target_syscall.h | 211 ------------------------- linux-user/mips64/target_errno_defs.h | 6 +- linux-user/mips64/target_syscall.h | 211 ------------------------- 4 files changed, 220 insertions(+), 423 deletions(-) diff --git a/linux-user/mips/target_errno_defs.h b/linux-user/mips/target_errno_defs.h index daef95ea70..5685cda10d 100644 --- a/linux-user/mips/target_errno_defs.h +++ b/linux-user/mips/target_errno_defs.h @@ -3,4 +3,219 @@ #include "../generic/target_errno_defs.h" +/* + * Generic target errno overridden with definitions taken + * from asm-mips/errno.h + */ + +#undef TARGET_EWOULDBLOCK +#define TARGET_EWOULDBLOCK TARGET_EAGAIN /* Operation would block */ +#undef TARGET_ENOMSG +#define TARGET_ENOMSG 35 /* Identifier removed */ +#undef TARGET_EIDRM +#define TARGET_EIDRM 36 /* Identifier removed */ +#undef TARGET_ECHRNG +#define TARGET_ECHRNG 37 /* Channel number out of range */ +#undef TARGET_EL2NSYNC +#define TARGET_EL2NSYNC 38 /* Level 2 not synchronized */ +#undef TARGET_EL3HLT +#define TARGET_EL3HLT 39 /* Level 3 halted */ +#undef TARGET_EL3RST +#define TARGET_EL3RST 40 /* Level 3 reset */ +#undef TARGET_ELNRNG +#define TARGET_ELNRNG 41 /* Link number out of range */ +#undef TARGET_EUNATCH +#define TARGET_EUNATCH 42 /* Protocol driver not attached */ +#undef TARGET_ENOCSI +#define TARGET_ENOCSI 43 /* No CSI structure available */ +#undef TARGET_EL2HLT +#define TARGET_EL2HLT 44 /* Level 2 halted */ +#undef TARGET_EDEADLK +#define TARGET_EDEADLK 45 /* Resource deadlock would occur */ +#undef TARGET_ENOLCK +#define TARGET_ENOLCK 46 /* No record locks available */ +#undef TARGET_EBADE +#define TARGET_EBADE 50 /* Invalid exchange */ +#undef TARGET_EBADR +#define TARGET_EBADR 51 /* Invalid request descriptor */ +#undef TARGET_EXFULL +#define TARGET_EXFULL 52 /* TARGET_Exchange full */ +#undef TARGET_ENOANO +#define TARGET_ENOANO 53 /* No anode */ +#undef TARGET_EBADRQC +#define TARGET_EBADRQC 54 /* Invalid request code */ +#undef TARGET_EBADSLT +#define TARGET_EBADSLT 55 /* Invalid slot */ +#undef TARGET_EDEADLOCK +#define TARGET_EDEADLOCK 56 /* File locking deadlock error */ +#undef TARGET_EBFONT +#define TARGET_EBFONT 59 /* Bad font file format */ +#undef TARGET_ENOSTR +#define TARGET_ENOSTR 60 /* Device not a stream */ +#undef TARGET_ENODATA +#define TARGET_ENODATA 61 /* No data available */ +#undef TARGET_ETIME +#define TARGET_ETIME 62 /* Timer expired */ +#undef TARGET_ENOSR +#define TARGET_ENOSR 63 /* Out of streams resources */ +#undef TARGET_ENONET +#define TARGET_ENONET 64 /* Machine is not on the network */ +#undef TARGET_ENOPKG +#define TARGET_ENOPKG 65 /* Package not installed */ +#undef TARGET_EREMOTE +#define TARGET_EREMOTE 66 /* Object is remote */ +#undef TARGET_ENOLINK +#define TARGET_ENOLINK 67 /* Link has been severed */ +#undef TARGET_EADV +#define TARGET_EADV 68 /* Advertise error */ +#undef TARGET_ESRMNT +#define TARGET_ESRMNT 69 /* Srmount error */ +#undef TARGET_ECOMM +#define TARGET_ECOMM 70 /* Communication error on send */ +#undef TARGET_EPROTO +#define TARGET_EPROTO 71 /* Protocol error */ +#undef TARGET_EDOTDOT +#define TARGET_EDOTDOT 73 /* RFS specific error */ +#undef TARGET_EMULTIHOP +#define TARGET_EMULTIHOP 74 /* Multihop attempted */ +#undef TARGET_EBADMSG +#define TARGET_EBADMSG 77 /* Not a data message */ +#undef TARGET_ENAMETOOLONG +#define TARGET_ENAMETOOLONG 78 /* File name too long */ +#undef TARGET_EOVERFLOW +#define TARGET_EOVERFLOW 79 /* Value too large for defined data type */ +#undef TARGET_ENOTUNIQ +#define TARGET_ENOTUNIQ 80 /* Name not unique on network */ +#undef TARGET_EBADFD +#define TARGET_EBADFD 81 /* File descriptor in bad state */ +#undef TARGET_EREMCHG +#define TARGET_EREMCHG 82 /* Remote address changed */ +#undef TARGET_ELIBACC +#define TARGET_ELIBACC 83 /* Can not access a needed shared library */ +#undef TARGET_ELIBBAD +#define TARGET_ELIBBAD 84 /* Accessing a corrupted shared library */ +#undef TARGET_ELIBSCN +#define TARGET_ELIBSCN 85 /* .lib section in a.out corrupted */ +#undef TARGET_ELIBMAX +#define TARGET_ELIBMAX 86 /* Attempting to link in too many shared libraries */ +#undef TARGET_ELIBEXEC +#define TARGET_ELIBEXEC 87 /* Cannot exec a shared library directly */ +#undef TARGET_EILSEQ +#define TARGET_EILSEQ 88 /* Illegal byte sequence */ +#undef TARGET_ENOSYS +#define TARGET_ENOSYS 89 /* Function not implemented */ +#undef TARGET_ELOOP +#define TARGET_ELOOP 90 /* Too many symbolic links encountered */ +#undef TARGET_ERESTART +#define TARGET_ERESTART 91 /* Interrupted system call should be restarted */ +#undef TARGET_ESTRPIPE +#define TARGET_ESTRPIPE 92 /* Streams pipe error */ +#undef TARGET_ENOTEMPTY +#define TARGET_ENOTEMPTY 93 /* Directory not empty */ +#undef TARGET_EUSERS +#define TARGET_EUSERS 94 /* Too many users */ +#undef TARGET_ENOTSOCK +#define TARGET_ENOTSOCK 95 /* Socket operation on non-socket */ +#undef TARGET_EDESTADDRREQ +#define TARGET_EDESTADDRREQ 96 /* Destination address required */ +#undef TARGET_EMSGSIZE +#define TARGET_EMSGSIZE 97 /* Message too long */ +#undef TARGET_EPROTOTYPE +#define TARGET_EPROTOTYPE 98 /* Protocol wrong type for socket */ +#undef TARGET_ENOPROTOOPT +#define TARGET_ENOPROTOOPT 99 /* Protocol not available */ +#undef TARGET_EPROTONOSUPPORT +#define TARGET_EPROTONOSUPPORT 120 /* Protocol not supported */ +#undef TARGET_ESOCKTNOSUPPORT +#define TARGET_ESOCKTNOSUPPORT 121 /* Socket type not supported */ +#undef TARGET_EOPNOTSUPP +#define TARGET_EOPNOTSUPP 122 /* Operation not supported on transport endpoint */ +#undef TARGET_EPFNOSUPPORT +#define TARGET_EPFNOSUPPORT 123 /* Protocol family not supported */ +#undef TARGET_EAFNOSUPPORT +#define TARGET_EAFNOSUPPORT 124 /* Address family not supported by protocol */ +#undef TARGET_EADDRINUSE +#define TARGET_EADDRINUSE 125 /* Address already in use */ +#undef TARGET_EADDRNOTAVAIL +#define TARGET_EADDRNOTAVAIL 126 /* Cannot assign requested address */ +#undef TARGET_ENETDOWN +#define TARGET_ENETDOWN 127 /* Network is down */ +#undef TARGET_ENETUNREACH +#define TARGET_ENETUNREACH 128 /* Network is unreachable */ +#undef TARGET_ENETRESET +#define TARGET_ENETRESET 129 /* Network dropped connection because of reset */ +#undef TARGET_ECONNABORTED +#define TARGET_ECONNABORTED 130 /* Software caused connection abort */ +#undef TARGET_ECONNRESET +#define TARGET_ECONNRESET 131 /* Connection reset by peer */ +#undef TARGET_ENOBUFS +#define TARGET_ENOBUFS 132 /* No buffer space available */ +#undef TARGET_EISCONN +#define TARGET_EISCONN 133 /* Transport endpoint is already connected */ +#undef TARGET_ENOTCONN +#define TARGET_ENOTCONN 134 /* Transport endpoint is not connected */ +#undef TARGET_EUCLEAN +#define TARGET_EUCLEAN 135 /* Structure needs cleaning */ +#undef TARGET_ENOTNAM +#define TARGET_ENOTNAM 137 /* Not a XENIX named type file */ +#undef TARGET_ENAVAIL +#define TARGET_ENAVAIL 138 /* No XENIX semaphores available */ +#undef TARGET_EISNAM +#define TARGET_EISNAM 139 /* Is a named type file */ +#undef TARGET_EREMOTEIO +#define TARGET_EREMOTEIO 140 /* Remote I/O error */ +#undef TARGET_EINIT +#define TARGET_EINIT 141 /* Reserved */ +#undef TARGET_EREMDEV +#define TARGET_EREMDEV 142 /* TARGET_Error 142 */ +#undef TARGET_ESHUTDOWN +#define TARGET_ESHUTDOWN 143 /* Cannot send after transport endpoint shutdown */ +#undef TARGET_ETOOMANYREFS +#define TARGET_ETOOMANYREFS 144 /* Too many references: cannot splice */ +#undef TARGET_ETIMEDOUT +#define TARGET_ETIMEDOUT 145 /* Connection timed out */ +#undef TARGET_ECONNREFUSED +#define TARGET_ECONNREFUSED 146 /* Connection refused */ +#undef TARGET_EHOSTDOWN +#define TARGET_EHOSTDOWN 147 /* Host is down */ +#undef TARGET_EHOSTUNREACH +#define TARGET_EHOSTUNREACH 148 /* No route to host */ +#undef TARGET_EALREADY +#define TARGET_EALREADY 149 /* Operation already in progress */ +#undef TARGET_EINPROGRESS +#define TARGET_EINPROGRESS 150 /* Operation now in progress */ +#undef TARGET_ESTALE +#define TARGET_ESTALE 151 /* Stale NFS file handle */ +#undef TARGET_ECANCELED +#define TARGET_ECANCELED 158 /* AIO operation canceled */ +/* + * These error are Linux extensions. + */ +#undef TARGET_ENOMEDIUM +#define TARGET_ENOMEDIUM 159 /* No medium found */ +#undef TARGET_EMEDIUMTYPE +#define TARGET_EMEDIUMTYPE 160 /* Wrong medium type */ +#undef TARGET_ENOKEY +#define TARGET_ENOKEY 161 /* Required key not available */ +#undef TARGET_EKEYEXPIRED +#define TARGET_EKEYEXPIRED 162 /* Key has expired */ +#undef TARGET_EKEYREVOKED +#define TARGET_EKEYREVOKED 163 /* Key has been revoked */ +#undef TARGET_EKEYREJECTED +#define TARGET_EKEYREJECTED 164 /* Key was rejected by service */ + +/* for robust mutexes */ +#undef TARGET_EOWNERDEAD +#define TARGET_EOWNERDEAD 165 /* Owner died */ +#undef TARGET_ENOTRECOVERABLE +#define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ + +#undef TARGET_ERFKILL +#define TARGET_ERFKILL 167 +#undef TARGET_EHWPOISON +#define TARGET_EHWPOISON 168 + +#undef TARGET_EDQUOT +#define TARGET_EDQUOT 1133 /* Quota exceeded */ + #endif diff --git a/linux-user/mips/target_syscall.h b/linux-user/mips/target_syscall.h index 3e558fdb4b..f59057493a 100644 --- a/linux-user/mips/target_syscall.h +++ b/linux-user/mips/target_syscall.h @@ -20,217 +20,6 @@ struct target_pt_regs { abi_ulong cp0_epc; }; -/* Target errno definitions taken from asm-mips/errno.h */ -#undef TARGET_EWOULDBLOCK -#define TARGET_EWOULDBLOCK TARGET_EAGAIN /* Operation would block */ -#undef TARGET_ENOMSG -#define TARGET_ENOMSG 35 /* Identifier removed */ -#undef TARGET_EIDRM -#define TARGET_EIDRM 36 /* Identifier removed */ -#undef TARGET_ECHRNG -#define TARGET_ECHRNG 37 /* Channel number out of range */ -#undef TARGET_EL2NSYNC -#define TARGET_EL2NSYNC 38 /* Level 2 not synchronized */ -#undef TARGET_EL3HLT -#define TARGET_EL3HLT 39 /* Level 3 halted */ -#undef TARGET_EL3RST -#define TARGET_EL3RST 40 /* Level 3 reset */ -#undef TARGET_ELNRNG -#define TARGET_ELNRNG 41 /* Link number out of range */ -#undef TARGET_EUNATCH -#define TARGET_EUNATCH 42 /* Protocol driver not attached */ -#undef TARGET_ENOCSI -#define TARGET_ENOCSI 43 /* No CSI structure available */ -#undef TARGET_EL2HLT -#define TARGET_EL2HLT 44 /* Level 2 halted */ -#undef TARGET_EDEADLK -#define TARGET_EDEADLK 45 /* Resource deadlock would occur */ -#undef TARGET_ENOLCK -#define TARGET_ENOLCK 46 /* No record locks available */ -#undef TARGET_EBADE -#define TARGET_EBADE 50 /* Invalid exchange */ -#undef TARGET_EBADR -#define TARGET_EBADR 51 /* Invalid request descriptor */ -#undef TARGET_EXFULL -#define TARGET_EXFULL 52 /* TARGET_Exchange full */ -#undef TARGET_ENOANO -#define TARGET_ENOANO 53 /* No anode */ -#undef TARGET_EBADRQC -#define TARGET_EBADRQC 54 /* Invalid request code */ -#undef TARGET_EBADSLT -#define TARGET_EBADSLT 55 /* Invalid slot */ -#undef TARGET_EDEADLOCK -#define TARGET_EDEADLOCK 56 /* File locking deadlock error */ -#undef TARGET_EBFONT -#define TARGET_EBFONT 59 /* Bad font file format */ -#undef TARGET_ENOSTR -#define TARGET_ENOSTR 60 /* Device not a stream */ -#undef TARGET_ENODATA -#define TARGET_ENODATA 61 /* No data available */ -#undef TARGET_ETIME -#define TARGET_ETIME 62 /* Timer expired */ -#undef TARGET_ENOSR -#define TARGET_ENOSR 63 /* Out of streams resources */ -#undef TARGET_ENONET -#define TARGET_ENONET 64 /* Machine is not on the network */ -#undef TARGET_ENOPKG -#define TARGET_ENOPKG 65 /* Package not installed */ -#undef TARGET_EREMOTE -#define TARGET_EREMOTE 66 /* Object is remote */ -#undef TARGET_ENOLINK -#define TARGET_ENOLINK 67 /* Link has been severed */ -#undef TARGET_EADV -#define TARGET_EADV 68 /* Advertise error */ -#undef TARGET_ESRMNT -#define TARGET_ESRMNT 69 /* Srmount error */ -#undef TARGET_ECOMM -#define TARGET_ECOMM 70 /* Communication error on send */ -#undef TARGET_EPROTO -#define TARGET_EPROTO 71 /* Protocol error */ -#undef TARGET_EDOTDOT -#define TARGET_EDOTDOT 73 /* RFS specific error */ -#undef TARGET_EMULTIHOP -#define TARGET_EMULTIHOP 74 /* Multihop attempted */ -#undef TARGET_EBADMSG -#define TARGET_EBADMSG 77 /* Not a data message */ -#undef TARGET_ENAMETOOLONG -#define TARGET_ENAMETOOLONG 78 /* File name too long */ -#undef TARGET_EOVERFLOW -#define TARGET_EOVERFLOW 79 /* Value too large for defined data type */ -#undef TARGET_ENOTUNIQ -#define TARGET_ENOTUNIQ 80 /* Name not unique on network */ -#undef TARGET_EBADFD -#define TARGET_EBADFD 81 /* File descriptor in bad state */ -#undef TARGET_EREMCHG -#define TARGET_EREMCHG 82 /* Remote address changed */ -#undef TARGET_ELIBACC -#define TARGET_ELIBACC 83 /* Can not access a needed shared library */ -#undef TARGET_ELIBBAD -#define TARGET_ELIBBAD 84 /* Accessing a corrupted shared library */ -#undef TARGET_ELIBSCN -#define TARGET_ELIBSCN 85 /* .lib section in a.out corrupted */ -#undef TARGET_ELIBMAX -#define TARGET_ELIBMAX 86 /* Attempting to link in too many shared libraries */ -#undef TARGET_ELIBEXEC -#define TARGET_ELIBEXEC 87 /* Cannot exec a shared library directly */ -#undef TARGET_EILSEQ -#define TARGET_EILSEQ 88 /* Illegal byte sequence */ -#undef TARGET_ENOSYS -#define TARGET_ENOSYS 89 /* Function not implemented */ -#undef TARGET_ELOOP -#define TARGET_ELOOP 90 /* Too many symbolic links encountered */ -#undef TARGET_ERESTART -#define TARGET_ERESTART 91 /* Interrupted system call should be restarted */ -#undef TARGET_ESTRPIPE -#define TARGET_ESTRPIPE 92 /* Streams pipe error */ -#undef TARGET_ENOTEMPTY -#define TARGET_ENOTEMPTY 93 /* Directory not empty */ -#undef TARGET_EUSERS -#define TARGET_EUSERS 94 /* Too many users */ -#undef TARGET_ENOTSOCK -#define TARGET_ENOTSOCK 95 /* Socket operation on non-socket */ -#undef TARGET_EDESTADDRREQ -#define TARGET_EDESTADDRREQ 96 /* Destination address required */ -#undef TARGET_EMSGSIZE -#define TARGET_EMSGSIZE 97 /* Message too long */ -#undef TARGET_EPROTOTYPE -#define TARGET_EPROTOTYPE 98 /* Protocol wrong type for socket */ -#undef TARGET_ENOPROTOOPT -#define TARGET_ENOPROTOOPT 99 /* Protocol not available */ -#undef TARGET_EPROTONOSUPPORT -#define TARGET_EPROTONOSUPPORT 120 /* Protocol not supported */ -#undef TARGET_ESOCKTNOSUPPORT -#define TARGET_ESOCKTNOSUPPORT 121 /* Socket type not supported */ -#undef TARGET_EOPNOTSUPP -#define TARGET_EOPNOTSUPP 122 /* Operation not supported on transport endpoint */ -#undef TARGET_EPFNOSUPPORT -#define TARGET_EPFNOSUPPORT 123 /* Protocol family not supported */ -#undef TARGET_EAFNOSUPPORT -#define TARGET_EAFNOSUPPORT 124 /* Address family not supported by protocol */ -#undef TARGET_EADDRINUSE -#define TARGET_EADDRINUSE 125 /* Address already in use */ -#undef TARGET_EADDRNOTAVAIL -#define TARGET_EADDRNOTAVAIL 126 /* Cannot assign requested address */ -#undef TARGET_ENETDOWN -#define TARGET_ENETDOWN 127 /* Network is down */ -#undef TARGET_ENETUNREACH -#define TARGET_ENETUNREACH 128 /* Network is unreachable */ -#undef TARGET_ENETRESET -#define TARGET_ENETRESET 129 /* Network dropped connection because of reset */ -#undef TARGET_ECONNABORTED -#define TARGET_ECONNABORTED 130 /* Software caused connection abort */ -#undef TARGET_ECONNRESET -#define TARGET_ECONNRESET 131 /* Connection reset by peer */ -#undef TARGET_ENOBUFS -#define TARGET_ENOBUFS 132 /* No buffer space available */ -#undef TARGET_EISCONN -#define TARGET_EISCONN 133 /* Transport endpoint is already connected */ -#undef TARGET_ENOTCONN -#define TARGET_ENOTCONN 134 /* Transport endpoint is not connected */ -#undef TARGET_EUCLEAN -#define TARGET_EUCLEAN 135 /* Structure needs cleaning */ -#undef TARGET_ENOTNAM -#define TARGET_ENOTNAM 137 /* Not a XENIX named type file */ -#undef TARGET_ENAVAIL -#define TARGET_ENAVAIL 138 /* No XENIX semaphores available */ -#undef TARGET_EISNAM -#define TARGET_EISNAM 139 /* Is a named type file */ -#undef TARGET_EREMOTEIO -#define TARGET_EREMOTEIO 140 /* Remote I/O error */ -#undef TARGET_EINIT -#define TARGET_EINIT 141 /* Reserved */ -#undef TARGET_EREMDEV -#define TARGET_EREMDEV 142 /* TARGET_Error 142 */ -#undef TARGET_ESHUTDOWN -#define TARGET_ESHUTDOWN 143 /* Cannot send after transport endpoint shutdown */ -#undef TARGET_ETOOMANYREFS -#define TARGET_ETOOMANYREFS 144 /* Too many references: cannot splice */ -#undef TARGET_ETIMEDOUT -#define TARGET_ETIMEDOUT 145 /* Connection timed out */ -#undef TARGET_ECONNREFUSED -#define TARGET_ECONNREFUSED 146 /* Connection refused */ -#undef TARGET_EHOSTDOWN -#define TARGET_EHOSTDOWN 147 /* Host is down */ -#undef TARGET_EHOSTUNREACH -#define TARGET_EHOSTUNREACH 148 /* No route to host */ -#undef TARGET_EALREADY -#define TARGET_EALREADY 149 /* Operation already in progress */ -#undef TARGET_EINPROGRESS -#define TARGET_EINPROGRESS 150 /* Operation now in progress */ -#undef TARGET_ESTALE -#define TARGET_ESTALE 151 /* Stale NFS file handle */ -#undef TARGET_ECANCELED -#define TARGET_ECANCELED 158 /* AIO operation canceled */ -/* - * These error are Linux extensions. - */ -#undef TARGET_ENOMEDIUM -#define TARGET_ENOMEDIUM 159 /* No medium found */ -#undef TARGET_EMEDIUMTYPE -#define TARGET_EMEDIUMTYPE 160 /* Wrong medium type */ -#undef TARGET_ENOKEY -#define TARGET_ENOKEY 161 /* Required key not available */ -#undef TARGET_EKEYEXPIRED -#define TARGET_EKEYEXPIRED 162 /* Key has expired */ -#undef TARGET_EKEYREVOKED -#define TARGET_EKEYREVOKED 163 /* Key has been revoked */ -#undef TARGET_EKEYREJECTED -#define TARGET_EKEYREJECTED 164 /* Key was rejected by service */ - -/* for robust mutexes */ -#undef TARGET_EOWNERDEAD -#define TARGET_EOWNERDEAD 165 /* Owner died */ -#undef TARGET_ENOTRECOVERABLE -#define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ - -#undef TARGET_ERFKILL -#define TARGET_ERFKILL 167 -#undef TARGET_EHWPOISON -#define TARGET_EHWPOISON 168 - -#undef TARGET_EDQUOT -#define TARGET_EDQUOT 1133 /* Quota exceeded */ - #define UNAME_MACHINE "mips" #define UNAME_MINIMUM_RELEASE "2.6.32" diff --git a/linux-user/mips64/target_errno_defs.h b/linux-user/mips64/target_errno_defs.h index 82b0a704f6..fb7b4628a9 100644 --- a/linux-user/mips64/target_errno_defs.h +++ b/linux-user/mips64/target_errno_defs.h @@ -1,6 +1,10 @@ #ifndef MIPS64_TARGET_ERRNO_DEFS_H #define MIPS64_TARGET_ERRNO_DEFS_H -#include "../generic/target_errno_defs.h" +/* + * The mips64 target uses errno definitions taken from asm-mips/errno.h + * so directly use the mips target errno definitions. + */ +#include "../mips/target_errno_defs.h" #endif diff --git a/linux-user/mips64/target_syscall.h b/linux-user/mips64/target_syscall.h index c54374c5a2..cd1e1b4969 100644 --- a/linux-user/mips64/target_syscall.h +++ b/linux-user/mips64/target_syscall.h @@ -17,217 +17,6 @@ struct target_pt_regs { target_ulong cp0_epc; }; -/* Target errno definitions taken from asm-mips/errno.h */ -#undef TARGET_EWOULDBLOCK -#define TARGET_EWOULDBLOCK TARGET_EAGAIN /* Operation would block */ -#undef TARGET_ENOMSG -#define TARGET_ENOMSG 35 /* Identifier removed */ -#undef TARGET_EIDRM -#define TARGET_EIDRM 36 /* Identifier removed */ -#undef TARGET_ECHRNG -#define TARGET_ECHRNG 37 /* Channel number out of range */ -#undef TARGET_EL2NSYNC -#define TARGET_EL2NSYNC 38 /* Level 2 not synchronized */ -#undef TARGET_EL3HLT -#define TARGET_EL3HLT 39 /* Level 3 halted */ -#undef TARGET_EL3RST -#define TARGET_EL3RST 40 /* Level 3 reset */ -#undef TARGET_ELNRNG -#define TARGET_ELNRNG 41 /* Link number out of range */ -#undef TARGET_EUNATCH -#define TARGET_EUNATCH 42 /* Protocol driver not attached */ -#undef TARGET_ENOCSI -#define TARGET_ENOCSI 43 /* No CSI structure available */ -#undef TARGET_EL2HLT -#define TARGET_EL2HLT 44 /* Level 2 halted */ -#undef TARGET_EDEADLK -#define TARGET_EDEADLK 45 /* Resource deadlock would occur */ -#undef TARGET_ENOLCK -#define TARGET_ENOLCK 46 /* No record locks available */ -#undef TARGET_EBADE -#define TARGET_EBADE 50 /* Invalid exchange */ -#undef TARGET_EBADR -#define TARGET_EBADR 51 /* Invalid request descriptor */ -#undef TARGET_EXFULL -#define TARGET_EXFULL 52 /* TARGET_Exchange full */ -#undef TARGET_ENOANO -#define TARGET_ENOANO 53 /* No anode */ -#undef TARGET_EBADRQC -#define TARGET_EBADRQC 54 /* Invalid request code */ -#undef TARGET_EBADSLT -#define TARGET_EBADSLT 55 /* Invalid slot */ -#undef TARGET_EDEADLOCK -#define TARGET_EDEADLOCK 56 /* File locking deadlock error */ -#undef TARGET_EBFONT -#define TARGET_EBFONT 59 /* Bad font file format */ -#undef TARGET_ENOSTR -#define TARGET_ENOSTR 60 /* Device not a stream */ -#undef TARGET_ENODATA -#define TARGET_ENODATA 61 /* No data available */ -#undef TARGET_ETIME -#define TARGET_ETIME 62 /* Timer expired */ -#undef TARGET_ENOSR -#define TARGET_ENOSR 63 /* Out of streams resources */ -#undef TARGET_ENONET -#define TARGET_ENONET 64 /* Machine is not on the network */ -#undef TARGET_ENOPKG -#define TARGET_ENOPKG 65 /* Package not installed */ -#undef TARGET_EREMOTE -#define TARGET_EREMOTE 66 /* Object is remote */ -#undef TARGET_ENOLINK -#define TARGET_ENOLINK 67 /* Link has been severed */ -#undef TARGET_EADV -#define TARGET_EADV 68 /* Advertise error */ -#undef TARGET_ESRMNT -#define TARGET_ESRMNT 69 /* Srmount error */ -#undef TARGET_ECOMM -#define TARGET_ECOMM 70 /* Communication error on send */ -#undef TARGET_EPROTO -#define TARGET_EPROTO 71 /* Protocol error */ -#undef TARGET_EDOTDOT -#define TARGET_EDOTDOT 73 /* RFS specific error */ -#undef TARGET_EMULTIHOP -#define TARGET_EMULTIHOP 74 /* Multihop attempted */ -#undef TARGET_EBADMSG -#define TARGET_EBADMSG 77 /* Not a data message */ -#undef TARGET_ENAMETOOLONG -#define TARGET_ENAMETOOLONG 78 /* File name too long */ -#undef TARGET_EOVERFLOW -#define TARGET_EOVERFLOW 79 /* Value too large for defined data type */ -#undef TARGET_ENOTUNIQ -#define TARGET_ENOTUNIQ 80 /* Name not unique on network */ -#undef TARGET_EBADFD -#define TARGET_EBADFD 81 /* File descriptor in bad state */ -#undef TARGET_EREMCHG -#define TARGET_EREMCHG 82 /* Remote address changed */ -#undef TARGET_ELIBACC -#define TARGET_ELIBACC 83 /* Can not access a needed shared library */ -#undef TARGET_ELIBBAD -#define TARGET_ELIBBAD 84 /* Accessing a corrupted shared library */ -#undef TARGET_ELIBSCN -#define TARGET_ELIBSCN 85 /* .lib section in a.out corrupted */ -#undef TARGET_ELIBMAX -#define TARGET_ELIBMAX 86 /* Attempting to link in too many shared libraries */ -#undef TARGET_ELIBEXEC -#define TARGET_ELIBEXEC 87 /* Cannot exec a shared library directly */ -#undef TARGET_EILSEQ -#define TARGET_EILSEQ 88 /* Illegal byte sequence */ -#undef TARGET_ENOSYS -#define TARGET_ENOSYS 89 /* Function not implemented */ -#undef TARGET_ELOOP -#define TARGET_ELOOP 90 /* Too many symbolic links encountered */ -#undef TARGET_ERESTART -#define TARGET_ERESTART 91 /* Interrupted system call should be restarted */ -#undef TARGET_ESTRPIPE -#define TARGET_ESTRPIPE 92 /* Streams pipe error */ -#undef TARGET_ENOTEMPTY -#define TARGET_ENOTEMPTY 93 /* Directory not empty */ -#undef TARGET_EUSERS -#define TARGET_EUSERS 94 /* Too many users */ -#undef TARGET_ENOTSOCK -#define TARGET_ENOTSOCK 95 /* Socket operation on non-socket */ -#undef TARGET_EDESTADDRREQ -#define TARGET_EDESTADDRREQ 96 /* Destination address required */ -#undef TARGET_EMSGSIZE -#define TARGET_EMSGSIZE 97 /* Message too long */ -#undef TARGET_EPROTOTYPE -#define TARGET_EPROTOTYPE 98 /* Protocol wrong type for socket */ -#undef TARGET_ENOPROTOOPT -#define TARGET_ENOPROTOOPT 99 /* Protocol not available */ -#undef TARGET_EPROTONOSUPPORT -#define TARGET_EPROTONOSUPPORT 120 /* Protocol not supported */ -#undef TARGET_ESOCKTNOSUPPORT -#define TARGET_ESOCKTNOSUPPORT 121 /* Socket type not supported */ -#undef TARGET_EOPNOTSUPP -#define TARGET_EOPNOTSUPP 122 /* Operation not supported on transport endpoint */ -#undef TARGET_EPFNOSUPPORT -#define TARGET_EPFNOSUPPORT 123 /* Protocol family not supported */ -#undef TARGET_EAFNOSUPPORT -#define TARGET_EAFNOSUPPORT 124 /* Address family not supported by protocol */ -#undef TARGET_EADDRINUSE -#define TARGET_EADDRINUSE 125 /* Address already in use */ -#undef TARGET_EADDRNOTAVAIL -#define TARGET_EADDRNOTAVAIL 126 /* Cannot assign requested address */ -#undef TARGET_ENETDOWN -#define TARGET_ENETDOWN 127 /* Network is down */ -#undef TARGET_ENETUNREACH -#define TARGET_ENETUNREACH 128 /* Network is unreachable */ -#undef TARGET_ENETRESET -#define TARGET_ENETRESET 129 /* Network dropped connection because of reset */ -#undef TARGET_ECONNABORTED -#define TARGET_ECONNABORTED 130 /* Software caused connection abort */ -#undef TARGET_ECONNRESET -#define TARGET_ECONNRESET 131 /* Connection reset by peer */ -#undef TARGET_ENOBUFS -#define TARGET_ENOBUFS 132 /* No buffer space available */ -#undef TARGET_EISCONN -#define TARGET_EISCONN 133 /* Transport endpoint is already connected */ -#undef TARGET_ENOTCONN -#define TARGET_ENOTCONN 134 /* Transport endpoint is not connected */ -#undef TARGET_EUCLEAN -#define TARGET_EUCLEAN 135 /* Structure needs cleaning */ -#undef TARGET_ENOTNAM -#define TARGET_ENOTNAM 137 /* Not a XENIX named type file */ -#undef TARGET_ENAVAIL -#define TARGET_ENAVAIL 138 /* No XENIX semaphores available */ -#undef TARGET_EISNAM -#define TARGET_EISNAM 139 /* Is a named type file */ -#undef TARGET_EREMOTEIO -#define TARGET_EREMOTEIO 140 /* Remote I/O error */ -#undef TARGET_EINIT -#define TARGET_EINIT 141 /* Reserved */ -#undef TARGET_EREMDEV -#define TARGET_EREMDEV 142 /* TARGET_Error 142 */ -#undef TARGET_ESHUTDOWN -#define TARGET_ESHUTDOWN 143 /* Cannot send after transport endpoint shutdown */ -#undef TARGET_ETOOMANYREFS -#define TARGET_ETOOMANYREFS 144 /* Too many references: cannot splice */ -#undef TARGET_ETIMEDOUT -#define TARGET_ETIMEDOUT 145 /* Connection timed out */ -#undef TARGET_ECONNREFUSED -#define TARGET_ECONNREFUSED 146 /* Connection refused */ -#undef TARGET_EHOSTDOWN -#define TARGET_EHOSTDOWN 147 /* Host is down */ -#undef TARGET_EHOSTUNREACH -#define TARGET_EHOSTUNREACH 148 /* No route to host */ -#undef TARGET_EALREADY -#define TARGET_EALREADY 149 /* Operation already in progress */ -#undef TARGET_EINPROGRESS -#define TARGET_EINPROGRESS 150 /* Operation now in progress */ -#undef TARGET_ESTALE -#define TARGET_ESTALE 151 /* Stale NFS file handle */ -#undef TARGET_ECANCELED -#define TARGET_ECANCELED 158 /* AIO operation canceled */ -/* - * These error are Linux extensions. - */ -#undef TARGET_ENOMEDIUM -#define TARGET_ENOMEDIUM 159 /* No medium found */ -#undef TARGET_EMEDIUMTYPE -#define TARGET_EMEDIUMTYPE 160 /* Wrong medium type */ -#undef TARGET_ENOKEY -#define TARGET_ENOKEY 161 /* Required key not available */ -#undef TARGET_EKEYEXPIRED -#define TARGET_EKEYEXPIRED 162 /* Key has expired */ -#undef TARGET_EKEYREVOKED -#define TARGET_EKEYREVOKED 163 /* Key has been revoked */ -#undef TARGET_EKEYREJECTED -#define TARGET_EKEYREJECTED 164 /* Key was rejected by service */ - -/* for robust mutexes */ -#undef TARGET_EOWNERDEAD -#define TARGET_EOWNERDEAD 165 /* Owner died */ -#undef TARGET_ENOTRECOVERABLE -#define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ - -#undef TARGET_ERFKILL -#define TARGET_ERFKILL 167 -#undef TARGET_EHWPOISON -#define TARGET_EHWPOISON 168 - -#undef TARGET_EDQUOT -#define TARGET_EDQUOT 1133 /* Quota exceeded */ - #define UNAME_MACHINE "mips64" #define UNAME_MINIMUM_RELEASE "2.6.32" From 3ffe3268ea5e938de0c5fc309013805e4123531d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Jul 2021 19:05:49 +0200 Subject: [PATCH 018/531] linux-user: Simplify host <-> target errno conversion using macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the host_to_target_errno_table[] array to a switch case to allow compiler optimizations (such noticing the identity function when host and guest errnos match). Extract the errnos list as to a new includible unit, using a generic macro. Remove the code related to target_to_host_errno_table[] initialization. Suggested-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20210708170550.1846343-8-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/errnos.c.inc | 140 +++++++++++++++++++++++++++++++++++ linux-user/syscall.c | 159 ++++------------------------------------ 2 files changed, 154 insertions(+), 145 deletions(-) create mode 100644 linux-user/errnos.c.inc diff --git a/linux-user/errnos.c.inc b/linux-user/errnos.c.inc new file mode 100644 index 0000000000..963ba1ce9d --- /dev/null +++ b/linux-user/errnos.c.inc @@ -0,0 +1,140 @@ +/* + * This list is the union of errno values overridden in asm-/errno.h + * minus the errnos that are not actually generic to all archs. + * + * Please keep this list sorted alphabetically. + * + * Copyright (c) 2003 Fabrice Bellard + * + * 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 . + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +E(EADDRINUSE) +E(EADDRNOTAVAIL) +E(EADV) +E(EAFNOSUPPORT) +E(EAGAIN) +E(EALREADY) +E(EBADE) +E(EBADFD) +E(EBADMSG) +E(EBADR) +E(EBADRQC) +E(EBADSLT) +E(EBFONT) +E(ECANCELED) +E(ECHRNG) +E(ECOMM) +E(ECONNABORTED) +E(ECONNREFUSED) +E(ECONNRESET) +E(EDEADLK) +E(EDESTADDRREQ) +E(EDOTDOT) +E(EDQUOT) +E(EHOSTDOWN) +E(EHOSTUNREACH) +#ifdef EHWPOISON +E(EHWPOISON) +#endif +E(EIDRM) +E(EILSEQ) +E(EINPROGRESS) +E(EISCONN) +E(EISNAM) +#ifdef EKEYEXPIRED +E(EKEYEXPIRED) +#endif +#ifdef EKEYREJECTED +E(EKEYREJECTED) +#endif +#ifdef EKEYREVOKED +E(EKEYREVOKED) +#endif +E(EL2HLT) +E(EL2NSYNC) +E(EL3HLT) +E(EL3RST) +E(ELIBACC) +E(ELIBBAD) +E(ELIBEXEC) +E(ELIBMAX) +E(ELIBSCN) +E(ELNRNG) +E(ELOOP) +E(EMEDIUMTYPE) +E(EMSGSIZE) +E(EMULTIHOP) +E(ENAMETOOLONG) +E(ENAVAIL) +E(ENETDOWN) +E(ENETRESET) +E(ENETUNREACH) +E(ENOANO) +E(ENOBUFS) +E(ENOCSI) +E(ENODATA) +#ifdef ENOKEY +E(ENOKEY) +#endif +E(ENOLCK) +E(ENOLINK) +E(ENOMEDIUM) +#ifdef ENOMSG +E(ENOMSG) +#endif +E(ENONET) +E(ENOPKG) +E(ENOPROTOOPT) +E(ENOSR) +E(ENOSTR) +E(ENOSYS) +E(ENOTCONN) +E(ENOTEMPTY) +E(ENOTNAM) +#ifdef ENOTRECOVERABLE +E(ENOTRECOVERABLE) +#endif +E(ENOTSOCK) +E(ENOTUNIQ) +E(EOPNOTSUPP) +E(EOVERFLOW) +#ifdef EOWNERDEAD +E(EOWNERDEAD) +#endif +E(EPFNOSUPPORT) +E(EPROTO) +E(EPROTONOSUPPORT) +E(EPROTOTYPE) +E(EREMCHG) +E(EREMOTE) +E(EREMOTEIO) +E(ERESTART) +#ifdef ERFKILL +E(ERFKILL) +#endif +E(ESHUTDOWN) +E(ESOCKTNOSUPPORT) +E(ESRMNT) +E(ESTALE) +E(ESTRPIPE) +E(ETIME) +E(ETIMEDOUT) +E(ETOOMANYREFS) +E(EUCLEAN) +E(EUNATCH) +E(EUSERS) +E(EXFULL) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 4842a1987b..94ec6f730b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -509,150 +509,26 @@ static inline int next_free_host_timer(void) #define ERRNO_TABLE_SIZE 1200 -/* target_to_host_errno_table[] is initialized from - * host_to_target_errno_table[] in syscall_init(). */ -static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = { -}; - -/* - * This list is the union of errno values overridden in asm-/errno.h - * minus the errnos that are not actually generic to all archs. - */ -static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = { - [EAGAIN] = TARGET_EAGAIN, - [EIDRM] = TARGET_EIDRM, - [ECHRNG] = TARGET_ECHRNG, - [EL2NSYNC] = TARGET_EL2NSYNC, - [EL3HLT] = TARGET_EL3HLT, - [EL3RST] = TARGET_EL3RST, - [ELNRNG] = TARGET_ELNRNG, - [EUNATCH] = TARGET_EUNATCH, - [ENOCSI] = TARGET_ENOCSI, - [EL2HLT] = TARGET_EL2HLT, - [EDEADLK] = TARGET_EDEADLK, - [ENOLCK] = TARGET_ENOLCK, - [EBADE] = TARGET_EBADE, - [EBADR] = TARGET_EBADR, - [EXFULL] = TARGET_EXFULL, - [ENOANO] = TARGET_ENOANO, - [EBADRQC] = TARGET_EBADRQC, - [EBADSLT] = TARGET_EBADSLT, - [EBFONT] = TARGET_EBFONT, - [ENOSTR] = TARGET_ENOSTR, - [ENODATA] = TARGET_ENODATA, - [ETIME] = TARGET_ETIME, - [ENOSR] = TARGET_ENOSR, - [ENONET] = TARGET_ENONET, - [ENOPKG] = TARGET_ENOPKG, - [EREMOTE] = TARGET_EREMOTE, - [ENOLINK] = TARGET_ENOLINK, - [EADV] = TARGET_EADV, - [ESRMNT] = TARGET_ESRMNT, - [ECOMM] = TARGET_ECOMM, - [EPROTO] = TARGET_EPROTO, - [EDOTDOT] = TARGET_EDOTDOT, - [EMULTIHOP] = TARGET_EMULTIHOP, - [EBADMSG] = TARGET_EBADMSG, - [ENAMETOOLONG] = TARGET_ENAMETOOLONG, - [EOVERFLOW] = TARGET_EOVERFLOW, - [ENOTUNIQ] = TARGET_ENOTUNIQ, - [EBADFD] = TARGET_EBADFD, - [EREMCHG] = TARGET_EREMCHG, - [ELIBACC] = TARGET_ELIBACC, - [ELIBBAD] = TARGET_ELIBBAD, - [ELIBSCN] = TARGET_ELIBSCN, - [ELIBMAX] = TARGET_ELIBMAX, - [ELIBEXEC] = TARGET_ELIBEXEC, - [EILSEQ] = TARGET_EILSEQ, - [ENOSYS] = TARGET_ENOSYS, - [ELOOP] = TARGET_ELOOP, - [ERESTART] = TARGET_ERESTART, - [ESTRPIPE] = TARGET_ESTRPIPE, - [ENOTEMPTY] = TARGET_ENOTEMPTY, - [EUSERS] = TARGET_EUSERS, - [ENOTSOCK] = TARGET_ENOTSOCK, - [EDESTADDRREQ] = TARGET_EDESTADDRREQ, - [EMSGSIZE] = TARGET_EMSGSIZE, - [EPROTOTYPE] = TARGET_EPROTOTYPE, - [ENOPROTOOPT] = TARGET_ENOPROTOOPT, - [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT, - [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT, - [EOPNOTSUPP] = TARGET_EOPNOTSUPP, - [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT, - [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT, - [EADDRINUSE] = TARGET_EADDRINUSE, - [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL, - [ENETDOWN] = TARGET_ENETDOWN, - [ENETUNREACH] = TARGET_ENETUNREACH, - [ENETRESET] = TARGET_ENETRESET, - [ECONNABORTED] = TARGET_ECONNABORTED, - [ECONNRESET] = TARGET_ECONNRESET, - [ENOBUFS] = TARGET_ENOBUFS, - [EISCONN] = TARGET_EISCONN, - [ENOTCONN] = TARGET_ENOTCONN, - [EUCLEAN] = TARGET_EUCLEAN, - [ENOTNAM] = TARGET_ENOTNAM, - [ENAVAIL] = TARGET_ENAVAIL, - [EISNAM] = TARGET_EISNAM, - [EREMOTEIO] = TARGET_EREMOTEIO, - [EDQUOT] = TARGET_EDQUOT, - [ESHUTDOWN] = TARGET_ESHUTDOWN, - [ETOOMANYREFS] = TARGET_ETOOMANYREFS, - [ETIMEDOUT] = TARGET_ETIMEDOUT, - [ECONNREFUSED] = TARGET_ECONNREFUSED, - [EHOSTDOWN] = TARGET_EHOSTDOWN, - [EHOSTUNREACH] = TARGET_EHOSTUNREACH, - [EALREADY] = TARGET_EALREADY, - [EINPROGRESS] = TARGET_EINPROGRESS, - [ESTALE] = TARGET_ESTALE, - [ECANCELED] = TARGET_ECANCELED, - [ENOMEDIUM] = TARGET_ENOMEDIUM, - [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE, -#ifdef ENOKEY - [ENOKEY] = TARGET_ENOKEY, -#endif -#ifdef EKEYEXPIRED - [EKEYEXPIRED] = TARGET_EKEYEXPIRED, -#endif -#ifdef EKEYREVOKED - [EKEYREVOKED] = TARGET_EKEYREVOKED, -#endif -#ifdef EKEYREJECTED - [EKEYREJECTED] = TARGET_EKEYREJECTED, -#endif -#ifdef EOWNERDEAD - [EOWNERDEAD] = TARGET_EOWNERDEAD, -#endif -#ifdef ENOTRECOVERABLE - [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE, -#endif -#ifdef ENOMSG - [ENOMSG] = TARGET_ENOMSG, -#endif -#ifdef ERFKILL - [ERFKILL] = TARGET_ERFKILL, -#endif -#ifdef EHWPOISON - [EHWPOISON] = TARGET_EHWPOISON, -#endif -}; - -static inline int host_to_target_errno(int err) +static inline int host_to_target_errno(int host_errno) { - if (err >= 0 && err < ERRNO_TABLE_SIZE && - host_to_target_errno_table[err]) { - return host_to_target_errno_table[err]; + switch (host_errno) { +#define E(X) case X: return TARGET_##X; +#include "errnos.c.inc" +#undef E + default: + return host_errno; } - return err; } -static inline int target_to_host_errno(int err) +static inline int target_to_host_errno(int target_errno) { - if (err >= 0 && err < ERRNO_TABLE_SIZE && - target_to_host_errno_table[err]) { - return target_to_host_errno_table[err]; + switch (target_errno) { +#define E(X) case TARGET_##X: return X; +#include "errnos.c.inc" +#undef E + default: + return target_errno; } - return err; } static inline abi_long get_errno(abi_long ret) @@ -7102,7 +6978,6 @@ void syscall_init(void) IOCTLEntry *ie; const argtype *arg_type; int size; - int i; thunk_init(STRUCT_MAX); @@ -7112,12 +6987,6 @@ void syscall_init(void) #undef STRUCT #undef STRUCT_SPECIAL - /* Build target_to_host_errno_table[] table from - * host_to_target_errno_table[]. */ - for (i = 0; i < ERRNO_TABLE_SIZE; i++) { - target_to_host_errno_table[host_to_target_errno_table[i]] = i; - } - /* we patch the ioctl size if necessary. We rely on the fact that no ioctl has all the bits at '1' in the size field */ ie = ioctl_entries; From 4f6a9f84f1d29b61e3ebd3bfd774d9fd5afe60c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Jul 2021 19:05:50 +0200 Subject: [PATCH 019/531] linux-user/syscall: Remove ERRNO_TABLE_SIZE check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now than target_to_host_errno() always return an errno, we can remove the unused and arbitrary ERRNO_TABLE_SIZE definition. Suggested-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20210708170550.1846343-9-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 94ec6f730b..376629c689 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -507,8 +507,6 @@ static inline int next_free_host_timer(void) } #endif -#define ERRNO_TABLE_SIZE 1200 - static inline int host_to_target_errno(int host_errno) { switch (host_errno) { @@ -548,9 +546,6 @@ const char *target_strerror(int err) return "Successful exit from sigreturn"; } - if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) { - return NULL; - } return strerror(target_to_host_errno(err)); } From c093364f4d911c1d59949b122f2d4c290986fff9 Mon Sep 17 00:00:00 2001 From: Owen Anderson Date: Thu, 1 Jul 2021 22:12:55 +0000 Subject: [PATCH 020/531] fd-trans: Fix race condition on reallocation of the translation table. The mapping from file-descriptors to translator functions is not guarded on realloc which may cause invalid function pointers to be read from a previously deallocated mapping. Signed-off-by: Owen Anderson Reviewed-by: Laurent Vivier Message-Id: <20210701221255.107976-1-oanderso@google.com> Signed-off-by: Laurent Vivier --- linux-user/fd-trans.c | 1 + linux-user/fd-trans.h | 55 +++++++++++++++++++++++++++++++++++++------ linux-user/main.c | 3 +++ 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/linux-user/fd-trans.c b/linux-user/fd-trans.c index 23adaca836..86b6f484d3 100644 --- a/linux-user/fd-trans.c +++ b/linux-user/fd-trans.c @@ -267,6 +267,7 @@ enum { }; TargetFdTrans **target_fd_trans; +QemuMutex target_fd_trans_lock; unsigned int target_fd_max; static void tswap_nlmsghdr(struct nlmsghdr *nlh) diff --git a/linux-user/fd-trans.h b/linux-user/fd-trans.h index a3fcdaabc7..1b9fa2041c 100644 --- a/linux-user/fd-trans.h +++ b/linux-user/fd-trans.h @@ -16,6 +16,8 @@ #ifndef FD_TRANS_H #define FD_TRANS_H +#include "qemu/lockable.h" + typedef abi_long (*TargetFdDataFunc)(void *, size_t); typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t); typedef struct TargetFdTrans { @@ -25,12 +27,23 @@ typedef struct TargetFdTrans { } TargetFdTrans; extern TargetFdTrans **target_fd_trans; +extern QemuMutex target_fd_trans_lock; extern unsigned int target_fd_max; +static inline void fd_trans_init(void) +{ + qemu_mutex_init(&target_fd_trans_lock); +} + static inline TargetFdDataFunc fd_trans_target_to_host_data(int fd) { - if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) { + if (fd < 0) { + return NULL; + } + + QEMU_LOCK_GUARD(&target_fd_trans_lock); + if (fd < target_fd_max && target_fd_trans[fd]) { return target_fd_trans[fd]->target_to_host_data; } return NULL; @@ -38,7 +51,12 @@ static inline TargetFdDataFunc fd_trans_target_to_host_data(int fd) static inline TargetFdDataFunc fd_trans_host_to_target_data(int fd) { - if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) { + if (fd < 0) { + return NULL; + } + + QEMU_LOCK_GUARD(&target_fd_trans_lock); + if (fd < target_fd_max && target_fd_trans[fd]) { return target_fd_trans[fd]->host_to_target_data; } return NULL; @@ -46,13 +64,19 @@ static inline TargetFdDataFunc fd_trans_host_to_target_data(int fd) static inline TargetFdAddrFunc fd_trans_target_to_host_addr(int fd) { - if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) { + if (fd < 0) { + return NULL; + } + + QEMU_LOCK_GUARD(&target_fd_trans_lock); + if (fd < target_fd_max && target_fd_trans[fd]) { return target_fd_trans[fd]->target_to_host_addr; } return NULL; } -static inline void fd_trans_register(int fd, TargetFdTrans *trans) +static inline void internal_fd_trans_register_unsafe(int fd, + TargetFdTrans *trans) { unsigned int oldmax; @@ -67,18 +91,35 @@ static inline void fd_trans_register(int fd, TargetFdTrans *trans) target_fd_trans[fd] = trans; } -static inline void fd_trans_unregister(int fd) +static inline void fd_trans_register(int fd, TargetFdTrans *trans) +{ + QEMU_LOCK_GUARD(&target_fd_trans_lock); + internal_fd_trans_register_unsafe(fd, trans); +} + +static inline void internal_fd_trans_unregister_unsafe(int fd) { if (fd >= 0 && fd < target_fd_max) { target_fd_trans[fd] = NULL; } } +static inline void fd_trans_unregister(int fd) +{ + if (fd < 0) { + return; + } + + QEMU_LOCK_GUARD(&target_fd_trans_lock); + internal_fd_trans_unregister_unsafe(fd); +} + static inline void fd_trans_dup(int oldfd, int newfd) { - fd_trans_unregister(newfd); + QEMU_LOCK_GUARD(&target_fd_trans_lock); + internal_fd_trans_unregister_unsafe(newfd); if (oldfd < target_fd_max && target_fd_trans[oldfd]) { - fd_trans_register(newfd, target_fd_trans[oldfd]); + internal_fd_trans_register_unsafe(newfd, target_fd_trans[oldfd]); } } diff --git a/linux-user/main.c b/linux-user/main.c index 2fb3a366a6..37ed50d98e 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -48,6 +48,7 @@ #include "target_elf.h" #include "cpu_loop-common.h" #include "crypto/init.h" +#include "fd-trans.h" #ifndef AT_FLAGS_PRESERVE_ARGV0 #define AT_FLAGS_PRESERVE_ARGV0_BIT 0 @@ -829,6 +830,8 @@ int main(int argc, char **argv, char **envp) cpu->opaque = ts; task_settid(ts); + fd_trans_init(); + ret = loader_exec(execfd, exec_path, target_argv, target_environ, regs, info, &bprm); if (ret != 0) { From a312aaeb4d137a1e7781c9d79c1e7c3f65921eb8 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Fri, 9 Jul 2021 15:19:13 +0200 Subject: [PATCH 021/531] ppc/pegasos2: Allow setprop in VOF Linux needs setprop to fix up the device tree, otherwise it's not finding devices and cannot boot. Since recent VOF change now we need to add a callback to allow this which is what this patch does. Signed-off-by: BALATON Zoltan Message-Id: <20210709132920.6544E7457EF@zero.eik.bme.hu> Signed-off-by: David Gibson --- hw/ppc/pegasos2.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index 9a6ae867e4..9fad1854b1 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -443,10 +443,17 @@ static target_ulong vhyp_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp) return POWERPC_CPU(current_cpu)->env.spr[SPR_SDR1]; } +static bool pegasos2_setprop(MachineState *ms, const char *path, + const char *propname, void *val, int vallen) +{ + return true; +} + static void pegasos2_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc); + VofMachineIfClass *vmc = VOF_MACHINE_CLASS(oc); mc->desc = "Genesi/bPlan Pegasos II"; mc->init = pegasos2_init; @@ -462,6 +469,8 @@ static void pegasos2_machine_class_init(ObjectClass *oc, void *data) vhc->cpu_exec_enter = vhyp_nop; vhc->cpu_exec_exit = vhyp_nop; vhc->encode_hpt_for_kvm_pr = vhyp_encode_hpt_for_kvm_pr; + + vmc->setprop = pegasos2_setprop; } static const TypeInfo pegasos2_machine_info = { @@ -471,6 +480,7 @@ static const TypeInfo pegasos2_machine_info = { .instance_size = sizeof(Pegasos2MachineState), .interfaces = (InterfaceInfo[]) { { TYPE_PPC_VIRTUAL_HYPERVISOR }, + { TYPE_VOF_MACHINE_IF }, { } }, }; From d01e8dcf2749e3a3bb6e4690492bedd259784ca5 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 12 Jul 2021 00:04:38 +1000 Subject: [PATCH 022/531] pseries: Update SLOF firmware image This is all about TPM fixes and improvements. The change log is: Alexey Kardashevskiy (2): tcgbios: Fix warnings version: update to 20210711 Stefan Berger (9): tcgbios: Fix details in log entries tcgbios: Fix a typo in the sha256 algo description tcgbios: Add implementations for sha1, sha384, and sha512 tpm: Add firmware API call 2HASH-EXT-LOG tcgbios: Change format of S_CRTM_VERSION string to ucs-2 tcgbios: Use assembly for 32 bit rotr in sha256 tcgbios: Use The proper sha function for each PCR bank tcgbios: Add test cases and test script to run them Travis: Add script for running tests on Travis Thomas Huth (1): Fix bad header guard in version.h Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson --- pc-bios/README | 2 +- pc-bios/slof.bin | Bin 968888 -> 991744 bytes roms/SLOF | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index d344e3bc1b..db39d757b0 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,7 +14,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/aik/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20210217. + built from git tag qemu-slof-20210711. - VOF (Virtual Open Firmware) is a minimalistic firmware to work with -machine pseries,x-vof=on. When enabled, the firmware acts as a slim shim and diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin index 3f3918a9e144e12f6e39fab6fc1c9ec9cf9d2898..855521e650e8b33279dc3b9561952ae2ce7e9188 100644 GIT binary patch literal 991744 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

P-bkTOZ?>_pt%Ws% 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

?(^2cLw?6~;Mnj&w^r{`_4u*`41G_= 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

%xT`|3SLl8Nn(gF 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

4sL*L%VEm;qm~86nil`Z;@mT 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

x3TBoCAAlU00-JV~Bov7cwr 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 SWU`(!>|Foyr(fRqd;cGNJF5Z! diff --git a/roms/SLOF b/roms/SLOF index 33a7322de1..dd0dcaa1c1 160000 --- a/roms/SLOF +++ b/roms/SLOF @@ -1 +1 @@ -Subproject commit 33a7322de13e9dca4b38851a345a58d37e7a441d +Subproject commit dd0dcaa1c1085c159ddab709c7f274b3917be8bd From c785a40179b10ce2d7a4afdb04f63c98d53a1756 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Mon, 12 Jul 2021 15:11:01 +0200 Subject: [PATCH 023/531] mv64361: Remove extra break from a switch case The switch case of writing PCI 1 IO base address had an extra break statement that made part of the code unreachable. This did not cause a problem as guests ususally leave this register at its default value. Fixes: dcdf98a9015 ("Add emulation of Marvell MV64361 PPC system controller") Reported-by: Coverity (CID 1458135) Signed-off-by: BALATON Zoltan Message-Id: <20210712131259.B705B7456E3@zero.eik.bme.hu> Signed-off-by: David Gibson --- hw/pci-host/mv64361.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/pci-host/mv64361.c b/hw/pci-host/mv64361.c index 20510d8680..92b0f5d047 100644 --- a/hw/pci-host/mv64361.c +++ b/hw/pci-host/mv64361.c @@ -687,7 +687,6 @@ static void mv64361_write(void *opaque, hwaddr addr, uint64_t val, case MV64340_PCI_1_IO_BASE_ADDR: s->pci[1].io_base = val & 0x30fffffULL; warn_swap_bit(val); - break; if (!(s->cpu_conf & BIT(27))) { s->pci[1].remap[4] = (val & 0xffffULL) << 16; } From 3a2f19b7ee3abbba5fd6f3e02fcdd26dc392a990 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 8 Jul 2021 23:57:54 +0200 Subject: [PATCH 024/531] linux-user: update syscall_nr.h to Linux v5.13 Automatically generated using scripts/gensyscalls.sh Signed-off-by: Laurent Vivier Reviewed-by: Taylor Simpson Message-Id: <20210708215756.268805-2-laurent@vivier.eu> Signed-off-by: Laurent Vivier --- linux-user/aarch64/syscall_nr.h | 8 +++++++- linux-user/hexagon/syscall_nr.h | 12 +++++++++++- linux-user/nios2/syscall_nr.h | 8 +++++++- linux-user/openrisc/syscall_nr.h | 8 +++++++- linux-user/riscv/syscall32_nr.h | 8 +++++++- linux-user/riscv/syscall64_nr.h | 8 +++++++- 6 files changed, 46 insertions(+), 6 deletions(-) diff --git a/linux-user/aarch64/syscall_nr.h b/linux-user/aarch64/syscall_nr.h index 6fd5b331e7..12ef002d60 100644 --- a/linux-user/aarch64/syscall_nr.h +++ b/linux-user/aarch64/syscall_nr.h @@ -302,6 +302,12 @@ #define TARGET_NR_openat2 437 #define TARGET_NR_pidfd_getfd 438 #define TARGET_NR_faccessat2 439 -#define TARGET_NR_syscalls 440 +#define TARGET_NR_process_madvise 440 +#define TARGET_NR_epoll_pwait2 441 +#define TARGET_NR_mount_setattr 442 +#define TARGET_NR_landlock_create_ruleset 444 +#define TARGET_NR_landlock_add_rule 445 +#define TARGET_NR_landlock_restrict_self 446 +#define TARGET_NR_syscalls 447 #endif /* LINUX_USER_AARCH64_SYSCALL_NR_H */ diff --git a/linux-user/hexagon/syscall_nr.h b/linux-user/hexagon/syscall_nr.h index da1314f713..b047dbbf6d 100644 --- a/linux-user/hexagon/syscall_nr.h +++ b/linux-user/hexagon/syscall_nr.h @@ -317,6 +317,16 @@ #define TARGET_NR_fsmount 432 #define TARGET_NR_fspick 433 #define TARGET_NR_pidfd_open 434 -#define TARGET_NR_syscalls 436 +#define TARGET_NR_close_range 436 +#define TARGET_NR_openat2 437 +#define TARGET_NR_pidfd_getfd 438 +#define TARGET_NR_faccessat2 439 +#define TARGET_NR_process_madvise 440 +#define TARGET_NR_epoll_pwait2 441 +#define TARGET_NR_mount_setattr 442 +#define TARGET_NR_landlock_create_ruleset 444 +#define TARGET_NR_landlock_add_rule 445 +#define TARGET_NR_landlock_restrict_self 446 +#define TARGET_NR_syscalls 447 #endif /* LINUX_USER_HEXAGON_SYSCALL_NR_H */ diff --git a/linux-user/nios2/syscall_nr.h b/linux-user/nios2/syscall_nr.h index e37f40179b..11a37b32e8 100644 --- a/linux-user/nios2/syscall_nr.h +++ b/linux-user/nios2/syscall_nr.h @@ -322,6 +322,12 @@ #define TARGET_NR_openat2 437 #define TARGET_NR_pidfd_getfd 438 #define TARGET_NR_faccessat2 439 -#define TARGET_NR_syscalls 440 +#define TARGET_NR_process_madvise 440 +#define TARGET_NR_epoll_pwait2 441 +#define TARGET_NR_mount_setattr 442 +#define TARGET_NR_landlock_create_ruleset 444 +#define TARGET_NR_landlock_add_rule 445 +#define TARGET_NR_landlock_restrict_self 446 +#define TARGET_NR_syscalls 447 #endif /* LINUX_USER_NIOS2_SYSCALL_NR_H */ diff --git a/linux-user/openrisc/syscall_nr.h b/linux-user/openrisc/syscall_nr.h index a8fc029510..f7faddb54c 100644 --- a/linux-user/openrisc/syscall_nr.h +++ b/linux-user/openrisc/syscall_nr.h @@ -323,6 +323,12 @@ #define TARGET_NR_openat2 437 #define TARGET_NR_pidfd_getfd 438 #define TARGET_NR_faccessat2 439 -#define TARGET_NR_syscalls 440 +#define TARGET_NR_process_madvise 440 +#define TARGET_NR_epoll_pwait2 441 +#define TARGET_NR_mount_setattr 442 +#define TARGET_NR_landlock_create_ruleset 444 +#define TARGET_NR_landlock_add_rule 445 +#define TARGET_NR_landlock_restrict_self 446 +#define TARGET_NR_syscalls 447 #endif /* LINUX_USER_OPENRISC_SYSCALL_NR_H */ diff --git a/linux-user/riscv/syscall32_nr.h b/linux-user/riscv/syscall32_nr.h index 079b804dae..1327d7dffa 100644 --- a/linux-user/riscv/syscall32_nr.h +++ b/linux-user/riscv/syscall32_nr.h @@ -296,6 +296,12 @@ #define TARGET_NR_openat2 437 #define TARGET_NR_pidfd_getfd 438 #define TARGET_NR_faccessat2 439 -#define TARGET_NR_syscalls 440 +#define TARGET_NR_process_madvise 440 +#define TARGET_NR_epoll_pwait2 441 +#define TARGET_NR_mount_setattr 442 +#define TARGET_NR_landlock_create_ruleset 444 +#define TARGET_NR_landlock_add_rule 445 +#define TARGET_NR_landlock_restrict_self 446 +#define TARGET_NR_syscalls 447 #endif /* LINUX_USER_RISCV_SYSCALL32_NR_H */ diff --git a/linux-user/riscv/syscall64_nr.h b/linux-user/riscv/syscall64_nr.h index d54224ccec..6659751933 100644 --- a/linux-user/riscv/syscall64_nr.h +++ b/linux-user/riscv/syscall64_nr.h @@ -302,6 +302,12 @@ #define TARGET_NR_openat2 437 #define TARGET_NR_pidfd_getfd 438 #define TARGET_NR_faccessat2 439 -#define TARGET_NR_syscalls 440 +#define TARGET_NR_process_madvise 440 +#define TARGET_NR_epoll_pwait2 441 +#define TARGET_NR_mount_setattr 442 +#define TARGET_NR_landlock_create_ruleset 444 +#define TARGET_NR_landlock_add_rule 445 +#define TARGET_NR_landlock_restrict_self 446 +#define TARGET_NR_syscalls 447 #endif /* LINUX_USER_RISCV_SYSCALL64_NR_H */ From e2dcdcea23d4b88188ccb7f77715dd0eab98f0a6 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 8 Jul 2021 23:57:55 +0200 Subject: [PATCH 025/531] linux-user, mips: update syscall-args-o32.c.inc to Linux v5.13 Updated running scripts/update-mips-syscall-args.sh scripts/update-mips-syscall-args.sh has been updated to reflect file directory changes in strace repository. Signed-off-by: Laurent Vivier Message-Id: <20210708215756.268805-3-laurent@vivier.eu> Signed-off-by: Laurent Vivier --- linux-user/mips/syscall-args-o32.c.inc | 5 ++++- scripts/update-mips-syscall-args.sh | 13 +++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/linux-user/mips/syscall-args-o32.c.inc b/linux-user/mips/syscall-args-o32.c.inc index 92ee4f921e..a6a2c5c566 100644 --- a/linux-user/mips/syscall-args-o32.c.inc +++ b/linux-user/mips/syscall-args-o32.c.inc @@ -356,7 +356,7 @@ [ 355] = 3, /* bpf */ [ 356] = 5, /* execveat */ [ 357] = 1, /* userfaultfd */ - [ 358] = 2, /* membarrier */ + [ 358] = 3, /* membarrier */ [ 359] = 3, /* mlock2 */ [ 360] = 6, /* copy_file_range */ [ 361] = 6, /* preadv2 */ @@ -438,3 +438,6 @@ [ 437] = 4, /* openat2 */ [ 438] = 3, /* pidfd_getfd */ [ 439] = 4, /* faccessat2 */ + [ 440] = 5, /* process_madvise */ + [ 441] = 6, /* epoll_pwait2 */ + [ 442] = 5, /* mount_setattr */ diff --git a/scripts/update-mips-syscall-args.sh b/scripts/update-mips-syscall-args.sh index 4f0dda4b83..5a529b699e 100755 --- a/scripts/update-mips-syscall-args.sh +++ b/scripts/update-mips-syscall-args.sh @@ -1,9 +1,9 @@ #!/bin/sh -URL=https://raw.githubusercontent.com/strace/strace/master +URL=https://raw.githubusercontent.com/strace/strace/master/src FILES="sysent.h sysent_shorthand_defs.h linux/mips/syscallent-compat.h \ - linux/mips/syscallent-o32.h linux/syscallent-common-32.h \ - linux/syscallent-common.h" + linux/mips/syscallent-o32.h linux/32/syscallent-common-32.h \ + linux/generic/syscallent-common.h" output="$1" if [ "$output" = "" ] ; then @@ -16,10 +16,11 @@ TMP=$(mktemp -d) cd $TMP for file in $FILES; do - curl -O $URL/$file + curl --create-dirs $URL/$file -o $TMP/$file done -> subcall32.h +> linux/generic/subcallent.h +> linux/32/subcallent.h cat > gen_mips_o32.c < @@ -52,6 +53,6 @@ int main(void) } EOF -cc -o gen_mips_o32 gen_mips_o32.c && ./gen_mips_o32 > "$output/$INC" +cc -o gen_mips_o32 -I linux/mips -I linux/generic gen_mips_o32.c && ./gen_mips_o32 > "$output/$INC" rm -fr "$TMP" From 2fa4ad3f9000c385f71237984fdd1eefe2a91900 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 8 Jul 2021 23:57:56 +0200 Subject: [PATCH 026/531] linux-user: update syscall.tbl to Linux v5.13 Updated running scripts/update-syscalltbl.sh Signed-off-by: Laurent Vivier Message-Id: <20210708215756.268805-4-laurent@vivier.eu> Signed-off-by: Laurent Vivier --- linux-user/alpha/syscall.tbl | 7 ++++++ linux-user/arm/syscall.tbl | 7 ++++++ linux-user/hppa/syscall.tbl | 31 ++++++++++++++---------- linux-user/i386/syscall_32.tbl | 21 +++++++++++------ linux-user/m68k/syscall.tbl | 7 ++++++ linux-user/microblaze/syscall.tbl | 7 ++++++ linux-user/mips/syscall_o32.tbl | 19 ++++++++++----- linux-user/mips64/syscall_n32.tbl | 19 ++++++++++----- linux-user/mips64/syscall_n64.tbl | 7 ++++++ linux-user/ppc/syscall.tbl | 39 ++++++++++++++----------------- linux-user/s390x/syscall.tbl | 19 ++++++++++----- linux-user/sh4/syscall.tbl | 7 ++++++ linux-user/sparc/syscall.tbl | 19 ++++++++++----- linux-user/x86_64/syscall_64.tbl | 27 ++++++++++++++------- linux-user/xtensa/syscall.tbl | 7 ++++++ 15 files changed, 170 insertions(+), 73 deletions(-) diff --git a/linux-user/alpha/syscall.tbl b/linux-user/alpha/syscall.tbl index ec8bed9e7b..3000a2e8ee 100644 --- a/linux-user/alpha/syscall.tbl +++ b/linux-user/alpha/syscall.tbl @@ -479,3 +479,10 @@ 547 common openat2 sys_openat2 548 common pidfd_getfd sys_pidfd_getfd 549 common faccessat2 sys_faccessat2 +550 common process_madvise sys_process_madvise +551 common epoll_pwait2 sys_epoll_pwait2 +552 common mount_setattr sys_mount_setattr +# 553 reserved for quotactl_path +554 common landlock_create_ruleset sys_landlock_create_ruleset +555 common landlock_add_rule sys_landlock_add_rule +556 common landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/arm/syscall.tbl b/linux-user/arm/syscall.tbl index 171077cbf4..28e03b5fec 100644 --- a/linux-user/arm/syscall.tbl +++ b/linux-user/arm/syscall.tbl @@ -453,3 +453,10 @@ 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd 439 common faccessat2 sys_faccessat2 +440 common process_madvise sys_process_madvise +441 common epoll_pwait2 sys_epoll_pwait2 +442 common mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 common landlock_create_ruleset sys_landlock_create_ruleset +445 common landlock_add_rule sys_landlock_add_rule +446 common landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/hppa/syscall.tbl b/linux-user/hppa/syscall.tbl index def64d221c..aabc37f8ca 100644 --- a/linux-user/hppa/syscall.tbl +++ b/linux-user/hppa/syscall.tbl @@ -29,7 +29,7 @@ 18 common stat sys_newstat compat_sys_newstat 19 common lseek sys_lseek compat_sys_lseek 20 common getpid sys_getpid -21 common mount sys_mount compat_sys_mount +21 common mount sys_mount 22 common bind sys_bind 23 common setuid sys_setuid 24 common getuid sys_getuid @@ -159,8 +159,8 @@ 142 common _newselect sys_select compat_sys_select 143 common flock sys_flock 144 common msync sys_msync -145 common readv sys_readv compat_sys_readv -146 common writev sys_writev compat_sys_writev +145 common readv sys_readv +146 common writev sys_writev 147 common getsid sys_getsid 148 common fdatasync sys_fdatasync 149 common _sysctl sys_ni_syscall @@ -330,7 +330,7 @@ 292 32 sync_file_range parisc_sync_file_range 292 64 sync_file_range sys_sync_file_range 293 common tee sys_tee -294 common vmsplice sys_vmsplice compat_sys_vmsplice +294 common vmsplice sys_vmsplice 295 common move_pages sys_move_pages compat_sys_move_pages 296 common getcpu sys_getcpu 297 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait @@ -344,17 +344,17 @@ 304 common eventfd sys_eventfd 305 32 fallocate parisc_fallocate 305 64 fallocate sys_fallocate -306 common timerfd_create sys_timerfd_create +306 common timerfd_create parisc_timerfd_create 307 32 timerfd_settime sys_timerfd_settime32 307 64 timerfd_settime sys_timerfd_settime 308 32 timerfd_gettime sys_timerfd_gettime32 308 64 timerfd_gettime sys_timerfd_gettime -309 common signalfd4 sys_signalfd4 compat_sys_signalfd4 -310 common eventfd2 sys_eventfd2 +309 common signalfd4 parisc_signalfd4 parisc_compat_signalfd4 +310 common eventfd2 parisc_eventfd2 311 common epoll_create1 sys_epoll_create1 312 common dup3 sys_dup3 -313 common pipe2 sys_pipe2 -314 common inotify_init1 sys_inotify_init1 +313 common pipe2 parisc_pipe2 +314 common inotify_init1 parisc_inotify_init1 315 common preadv sys_preadv compat_sys_preadv 316 common pwritev sys_pwritev compat_sys_pwritev 317 common rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo @@ -372,8 +372,8 @@ 327 common syncfs sys_syncfs 328 common setns sys_setns 329 common sendmmsg sys_sendmmsg compat_sys_sendmmsg -330 common process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv -331 common process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev +330 common process_vm_readv sys_process_vm_readv +331 common process_vm_writev sys_process_vm_writev 332 common kcmp sys_kcmp 333 common finit_module sys_finit_module 334 common sched_setattr sys_sched_setattr @@ -387,7 +387,7 @@ 341 common bpf sys_bpf 342 common execveat sys_execveat compat_sys_execveat 343 common membarrier sys_membarrier -344 common userfaultfd sys_userfaultfd +344 common userfaultfd parisc_userfaultfd 345 common mlock2 sys_mlock2 346 common copy_file_range sys_copy_file_range 347 common preadv2 sys_preadv2 compat_sys_preadv2 @@ -437,3 +437,10 @@ 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd 439 common faccessat2 sys_faccessat2 +440 common process_madvise sys_process_madvise +441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2 +442 common mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 common landlock_create_ruleset sys_landlock_create_ruleset +445 common landlock_add_rule sys_landlock_add_rule +446 common landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/i386/syscall_32.tbl b/linux-user/i386/syscall_32.tbl index 9d11028736..4bbc267fb3 100644 --- a/linux-user/i386/syscall_32.tbl +++ b/linux-user/i386/syscall_32.tbl @@ -32,7 +32,7 @@ 18 i386 oldstat sys_stat 19 i386 lseek sys_lseek compat_sys_lseek 20 i386 getpid sys_getpid -21 i386 mount sys_mount compat_sys_mount +21 i386 mount sys_mount 22 i386 umount sys_oldumount 23 i386 setuid sys_setuid16 24 i386 getuid sys_getuid16 @@ -142,7 +142,7 @@ 128 i386 init_module sys_init_module 129 i386 delete_module sys_delete_module 130 i386 get_kernel_syms -131 i386 quotactl sys_quotactl compat_sys_quotactl32 +131 i386 quotactl sys_quotactl 132 i386 getpgid sys_getpgid 133 i386 fchdir sys_fchdir 134 i386 bdflush sys_bdflush @@ -156,8 +156,8 @@ 142 i386 _newselect sys_select compat_sys_select 143 i386 flock sys_flock 144 i386 msync sys_msync -145 i386 readv sys_readv compat_sys_readv -146 i386 writev sys_writev compat_sys_writev +145 i386 readv sys_readv +146 i386 writev sys_writev 147 i386 getsid sys_getsid 148 i386 fdatasync sys_fdatasync 149 i386 _sysctl sys_ni_syscall @@ -327,7 +327,7 @@ 313 i386 splice sys_splice 314 i386 sync_file_range sys_ia32_sync_file_range 315 i386 tee sys_tee -316 i386 vmsplice sys_vmsplice compat_sys_vmsplice +316 i386 vmsplice sys_vmsplice 317 i386 move_pages sys_move_pages compat_sys_move_pages 318 i386 getcpu sys_getcpu 319 i386 epoll_pwait sys_epoll_pwait @@ -358,8 +358,8 @@ 344 i386 syncfs sys_syncfs 345 i386 sendmmsg sys_sendmmsg compat_sys_sendmmsg 346 i386 setns sys_setns -347 i386 process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv -348 i386 process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev +347 i386 process_vm_readv sys_process_vm_readv +348 i386 process_vm_writev sys_process_vm_writev 349 i386 kcmp sys_kcmp 350 i386 finit_module sys_finit_module 351 i386 sched_setattr sys_sched_setattr @@ -444,3 +444,10 @@ 437 i386 openat2 sys_openat2 438 i386 pidfd_getfd sys_pidfd_getfd 439 i386 faccessat2 sys_faccessat2 +440 i386 process_madvise sys_process_madvise +441 i386 epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2 +442 i386 mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 i386 landlock_create_ruleset sys_landlock_create_ruleset +445 i386 landlock_add_rule sys_landlock_add_rule +446 i386 landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/m68k/syscall.tbl b/linux-user/m68k/syscall.tbl index 81fc799d83..79c2d24c89 100644 --- a/linux-user/m68k/syscall.tbl +++ b/linux-user/m68k/syscall.tbl @@ -439,3 +439,10 @@ 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd 439 common faccessat2 sys_faccessat2 +440 common process_madvise sys_process_madvise +441 common epoll_pwait2 sys_epoll_pwait2 +442 common mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 common landlock_create_ruleset sys_landlock_create_ruleset +445 common landlock_add_rule sys_landlock_add_rule +446 common landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/microblaze/syscall.tbl b/linux-user/microblaze/syscall.tbl index b4e263916f..b11395a20c 100644 --- a/linux-user/microblaze/syscall.tbl +++ b/linux-user/microblaze/syscall.tbl @@ -445,3 +445,10 @@ 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd 439 common faccessat2 sys_faccessat2 +440 common process_madvise sys_process_madvise +441 common epoll_pwait2 sys_epoll_pwait2 +442 common mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 common landlock_create_ruleset sys_landlock_create_ruleset +445 common landlock_add_rule sys_landlock_add_rule +446 common landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/mips/syscall_o32.tbl b/linux-user/mips/syscall_o32.tbl index 195b43cf27..d560c467a8 100644 --- a/linux-user/mips/syscall_o32.tbl +++ b/linux-user/mips/syscall_o32.tbl @@ -29,7 +29,7 @@ 18 o32 unused18 sys_ni_syscall 19 o32 lseek sys_lseek 20 o32 getpid sys_getpid -21 o32 mount sys_mount compat_sys_mount +21 o32 mount sys_mount 22 o32 umount sys_oldumount 23 o32 setuid sys_setuid 24 o32 getuid sys_getuid @@ -156,8 +156,8 @@ 142 o32 _newselect sys_select compat_sys_select 143 o32 flock sys_flock 144 o32 msync sys_msync -145 o32 readv sys_readv compat_sys_readv -146 o32 writev sys_writev compat_sys_writev +145 o32 readv sys_readv +146 o32 writev sys_writev 147 o32 cacheflush sys_cacheflush 148 o32 cachectl sys_cachectl 149 o32 sysmips __sys_sysmips @@ -318,7 +318,7 @@ 304 o32 splice sys_splice 305 o32 sync_file_range sys_sync_file_range sys32_sync_file_range 306 o32 tee sys_tee -307 o32 vmsplice sys_vmsplice compat_sys_vmsplice +307 o32 vmsplice sys_vmsplice 308 o32 move_pages sys_move_pages compat_sys_move_pages 309 o32 set_robust_list sys_set_robust_list compat_sys_set_robust_list 310 o32 get_robust_list sys_get_robust_list compat_sys_get_robust_list @@ -356,8 +356,8 @@ 342 o32 syncfs sys_syncfs 343 o32 sendmmsg sys_sendmmsg compat_sys_sendmmsg 344 o32 setns sys_setns -345 o32 process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv -346 o32 process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev +345 o32 process_vm_readv sys_process_vm_readv +346 o32 process_vm_writev sys_process_vm_writev 347 o32 kcmp sys_kcmp 348 o32 finit_module sys_finit_module 349 o32 sched_setattr sys_sched_setattr @@ -427,3 +427,10 @@ 437 o32 openat2 sys_openat2 438 o32 pidfd_getfd sys_pidfd_getfd 439 o32 faccessat2 sys_faccessat2 +440 o32 process_madvise sys_process_madvise +441 o32 epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2 +442 o32 mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 o32 landlock_create_ruleset sys_landlock_create_ruleset +445 o32 landlock_add_rule sys_landlock_add_rule +446 o32 landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/mips64/syscall_n32.tbl b/linux-user/mips64/syscall_n32.tbl index f9df9edb67..9220909526 100644 --- a/linux-user/mips64/syscall_n32.tbl +++ b/linux-user/mips64/syscall_n32.tbl @@ -25,8 +25,8 @@ 15 n32 ioctl compat_sys_ioctl 16 n32 pread64 sys_pread64 17 n32 pwrite64 sys_pwrite64 -18 n32 readv compat_sys_readv -19 n32 writev compat_sys_writev +18 n32 readv sys_readv +19 n32 writev sys_writev 20 n32 access sys_access 21 n32 pipe sysm_pipe 22 n32 _newselect compat_sys_select @@ -167,7 +167,7 @@ 157 n32 sync sys_sync 158 n32 acct sys_acct 159 n32 settimeofday compat_sys_settimeofday -160 n32 mount compat_sys_mount +160 n32 mount sys_mount 161 n32 umount2 sys_umount 162 n32 swapon sys_swapon 163 n32 swapoff sys_swapoff @@ -278,7 +278,7 @@ 267 n32 splice sys_splice 268 n32 sync_file_range sys_sync_file_range 269 n32 tee sys_tee -270 n32 vmsplice compat_sys_vmsplice +270 n32 vmsplice sys_vmsplice 271 n32 move_pages compat_sys_move_pages 272 n32 set_robust_list compat_sys_set_robust_list 273 n32 get_robust_list compat_sys_get_robust_list @@ -317,8 +317,8 @@ 306 n32 syncfs sys_syncfs 307 n32 sendmmsg compat_sys_sendmmsg 308 n32 setns sys_setns -309 n32 process_vm_readv compat_sys_process_vm_readv -310 n32 process_vm_writev compat_sys_process_vm_writev +309 n32 process_vm_readv sys_process_vm_readv +310 n32 process_vm_writev sys_process_vm_writev 311 n32 kcmp sys_kcmp 312 n32 finit_module sys_finit_module 313 n32 sched_setattr sys_sched_setattr @@ -378,3 +378,10 @@ 437 n32 openat2 sys_openat2 438 n32 pidfd_getfd sys_pidfd_getfd 439 n32 faccessat2 sys_faccessat2 +440 n32 process_madvise sys_process_madvise +441 n32 epoll_pwait2 compat_sys_epoll_pwait2 +442 n32 mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 n32 landlock_create_ruleset sys_landlock_create_ruleset +445 n32 landlock_add_rule sys_landlock_add_rule +446 n32 landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/mips64/syscall_n64.tbl b/linux-user/mips64/syscall_n64.tbl index 557f9954a2..9cd1c34f31 100644 --- a/linux-user/mips64/syscall_n64.tbl +++ b/linux-user/mips64/syscall_n64.tbl @@ -354,3 +354,10 @@ 437 n64 openat2 sys_openat2 438 n64 pidfd_getfd sys_pidfd_getfd 439 n64 faccessat2 sys_faccessat2 +440 n64 process_madvise sys_process_madvise +441 n64 epoll_pwait2 sys_epoll_pwait2 +442 n64 mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 n64 landlock_create_ruleset sys_landlock_create_ruleset +445 n64 landlock_add_rule sys_landlock_add_rule +446 n64 landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/ppc/syscall.tbl b/linux-user/ppc/syscall.tbl index c2d737ff2e..8f052ff405 100644 --- a/linux-user/ppc/syscall.tbl +++ b/linux-user/ppc/syscall.tbl @@ -9,9 +9,7 @@ # 0 nospu restart_syscall sys_restart_syscall 1 nospu exit sys_exit -2 32 fork ppc_fork sys_fork -2 64 fork sys_fork -2 spu fork sys_ni_syscall +2 nospu fork sys_fork 3 common read sys_read 4 common write sys_write 5 common open sys_open compat_sys_open @@ -34,7 +32,7 @@ 18 spu oldstat sys_ni_syscall 19 common lseek sys_lseek compat_sys_lseek 20 common getpid sys_getpid -21 nospu mount sys_mount compat_sys_mount +21 nospu mount sys_mount 22 32 umount sys_oldumount 22 64 umount sys_ni_syscall 22 spu umount sys_ni_syscall @@ -160,9 +158,7 @@ 119 32 sigreturn sys_sigreturn compat_sys_sigreturn 119 64 sigreturn sys_ni_syscall 119 spu sigreturn sys_ni_syscall -120 32 clone ppc_clone sys_clone -120 64 clone sys_clone -120 spu clone sys_ni_syscall +120 nospu clone sys_clone 121 common setdomainname sys_setdomainname 122 common uname sys_newuname 123 common modify_ldt sys_ni_syscall @@ -193,8 +189,8 @@ 142 common _newselect sys_select compat_sys_select 143 common flock sys_flock 144 common msync sys_msync -145 common readv sys_readv compat_sys_readv -146 common writev sys_writev compat_sys_writev +145 common readv sys_readv +146 common writev sys_writev 147 common getsid sys_getsid 148 common fdatasync sys_fdatasync 149 nospu _sysctl sys_ni_syscall @@ -244,9 +240,7 @@ 186 spu sendfile sys_sendfile64 187 common getpmsg sys_ni_syscall 188 common putpmsg sys_ni_syscall -189 32 vfork ppc_vfork sys_vfork -189 64 vfork sys_vfork -189 spu vfork sys_ni_syscall +189 nospu vfork sys_vfork 190 common ugetrlimit sys_getrlimit compat_sys_getrlimit 191 common readahead sys_readahead compat_sys_readahead 192 32 mmap2 sys_mmap2 compat_sys_mmap2 @@ -322,9 +316,7 @@ 248 32 clock_nanosleep sys_clock_nanosleep_time32 248 64 clock_nanosleep sys_clock_nanosleep 248 spu clock_nanosleep sys_clock_nanosleep -249 32 swapcontext ppc_swapcontext compat_sys_swapcontext -249 64 swapcontext sys_swapcontext -249 spu swapcontext sys_ni_syscall +249 nospu swapcontext sys_swapcontext compat_sys_swapcontext 250 common tgkill sys_tgkill 251 32 utimes sys_utimes_time32 251 64 utimes sys_utimes @@ -369,7 +361,7 @@ 282 common unshare sys_unshare 283 common splice sys_splice 284 common tee sys_tee -285 common vmsplice sys_vmsplice compat_sys_vmsplice +285 common vmsplice sys_vmsplice 286 common openat sys_openat compat_sys_openat 287 common mkdirat sys_mkdirat 288 common mknodat sys_mknodat @@ -449,8 +441,8 @@ 348 common syncfs sys_syncfs 349 common sendmmsg sys_sendmmsg compat_sys_sendmmsg 350 common setns sys_setns -351 nospu process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv -352 nospu process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev +351 nospu process_vm_readv sys_process_vm_readv +352 nospu process_vm_writev sys_process_vm_writev 353 nospu finit_module sys_finit_module 354 nospu kcmp sys_kcmp 355 common sched_setattr sys_sched_setattr @@ -522,10 +514,15 @@ 432 common fsmount sys_fsmount 433 common fspick sys_fspick 434 common pidfd_open sys_pidfd_open -435 32 clone3 ppc_clone3 sys_clone3 -435 64 clone3 sys_clone3 -435 spu clone3 sys_ni_syscall +435 nospu clone3 sys_clone3 436 common close_range sys_close_range 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd 439 common faccessat2 sys_faccessat2 +440 common process_madvise sys_process_madvise +441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2 +442 common mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 common landlock_create_ruleset sys_landlock_create_ruleset +445 common landlock_add_rule sys_landlock_add_rule +446 common landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/s390x/syscall.tbl b/linux-user/s390x/syscall.tbl index 10456bc936..0690263df1 100644 --- a/linux-user/s390x/syscall.tbl +++ b/linux-user/s390x/syscall.tbl @@ -26,7 +26,7 @@ 16 32 lchown - sys_lchown16 19 common lseek sys_lseek compat_sys_lseek 20 common getpid sys_getpid sys_getpid -21 common mount sys_mount compat_sys_mount +21 common mount sys_mount sys_mount 22 common umount sys_oldumount sys_oldumount 23 32 setuid - sys_setuid16 24 32 getuid - sys_getuid16 @@ -134,8 +134,8 @@ 142 64 select sys_select - 143 common flock sys_flock sys_flock 144 common msync sys_msync sys_msync -145 common readv sys_readv compat_sys_readv -146 common writev sys_writev compat_sys_writev +145 common readv sys_readv sys_readv +146 common writev sys_writev sys_writev 147 common getsid sys_getsid sys_getsid 148 common fdatasync sys_fdatasync sys_fdatasync 149 common _sysctl - - @@ -316,7 +316,7 @@ 306 common splice sys_splice sys_splice 307 common sync_file_range sys_sync_file_range compat_sys_s390_sync_file_range 308 common tee sys_tee sys_tee -309 common vmsplice sys_vmsplice compat_sys_vmsplice +309 common vmsplice sys_vmsplice sys_vmsplice 310 common move_pages sys_move_pages compat_sys_move_pages 311 common getcpu sys_getcpu sys_getcpu 312 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait @@ -347,8 +347,8 @@ 337 common clock_adjtime sys_clock_adjtime sys_clock_adjtime32 338 common syncfs sys_syncfs sys_syncfs 339 common setns sys_setns sys_setns -340 common process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv -341 common process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev +340 common process_vm_readv sys_process_vm_readv sys_process_vm_readv +341 common process_vm_writev sys_process_vm_writev sys_process_vm_writev 342 common s390_runtime_instr sys_s390_runtime_instr sys_s390_runtime_instr 343 common kcmp sys_kcmp sys_kcmp 344 common finit_module sys_finit_module sys_finit_module @@ -442,3 +442,10 @@ 437 common openat2 sys_openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd sys_pidfd_getfd 439 common faccessat2 sys_faccessat2 sys_faccessat2 +440 common process_madvise sys_process_madvise sys_process_madvise +441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2 +442 common mount_setattr sys_mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 common landlock_create_ruleset sys_landlock_create_ruleset sys_landlock_create_ruleset +445 common landlock_add_rule sys_landlock_add_rule sys_landlock_add_rule +446 common landlock_restrict_self sys_landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/sh4/syscall.tbl b/linux-user/sh4/syscall.tbl index ae0a00beea..0b91499ebd 100644 --- a/linux-user/sh4/syscall.tbl +++ b/linux-user/sh4/syscall.tbl @@ -442,3 +442,10 @@ 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd 439 common faccessat2 sys_faccessat2 +440 common process_madvise sys_process_madvise +441 common epoll_pwait2 sys_epoll_pwait2 +442 common mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 common landlock_create_ruleset sys_landlock_create_ruleset +445 common landlock_add_rule sys_landlock_add_rule +446 common landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/sparc/syscall.tbl b/linux-user/sparc/syscall.tbl index 4af114e84f..e34cc30ef2 100644 --- a/linux-user/sparc/syscall.tbl +++ b/linux-user/sparc/syscall.tbl @@ -38,7 +38,7 @@ 23 64 setuid sys_setuid 24 32 getuid sys_getuid16 24 64 getuid sys_getuid -25 common vmsplice sys_vmsplice compat_sys_vmsplice +25 common vmsplice sys_vmsplice 26 common ptrace sys_ptrace compat_sys_ptrace 27 common alarm sys_alarm 28 common sigaltstack sys_sigaltstack compat_sys_sigaltstack @@ -149,8 +149,8 @@ 117 common getrusage sys_getrusage compat_sys_getrusage 118 common getsockopt sys_getsockopt sys_getsockopt 119 common getcwd sys_getcwd -120 common readv sys_readv compat_sys_readv -121 common writev sys_writev compat_sys_writev +120 common readv sys_readv +121 common writev sys_writev 122 common settimeofday sys_settimeofday compat_sys_settimeofday 123 32 fchown sys_fchown16 123 64 fchown sys_fchown @@ -201,7 +201,7 @@ 164 64 utrap_install sys_utrap_install 165 common quotactl sys_quotactl 166 common set_tid_address sys_set_tid_address -167 common mount sys_mount compat_sys_mount +167 common mount sys_mount 168 common ustat sys_ustat compat_sys_ustat 169 common setxattr sys_setxattr 170 common lsetxattr sys_lsetxattr @@ -406,8 +406,8 @@ 335 common syncfs sys_syncfs 336 common sendmmsg sys_sendmmsg compat_sys_sendmmsg 337 common setns sys_setns -338 common process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv -339 common process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev +338 common process_vm_readv sys_process_vm_readv +339 common process_vm_writev sys_process_vm_writev 340 32 kern_features sys_ni_syscall sys_kern_features 340 64 kern_features sys_kern_features 341 common kcmp sys_kcmp @@ -485,3 +485,10 @@ 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd 439 common faccessat2 sys_faccessat2 +440 common process_madvise sys_process_madvise +441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2 +442 common mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 common landlock_create_ruleset sys_landlock_create_ruleset +445 common landlock_add_rule sys_landlock_add_rule +446 common landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/x86_64/syscall_64.tbl b/linux-user/x86_64/syscall_64.tbl index f30d6ae9a6..ce18119ea0 100644 --- a/linux-user/x86_64/syscall_64.tbl +++ b/linux-user/x86_64/syscall_64.tbl @@ -361,18 +361,25 @@ 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd 439 common faccessat2 sys_faccessat2 +440 common process_madvise sys_process_madvise +441 common epoll_pwait2 sys_epoll_pwait2 +442 common mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 common landlock_create_ruleset sys_landlock_create_ruleset +445 common landlock_add_rule sys_landlock_add_rule +446 common landlock_restrict_self sys_landlock_restrict_self # -# x32-specific system call numbers start at 512 to avoid cache impact -# for native 64-bit operation. The __x32_compat_sys stubs are created -# on-the-fly for compat_sys_*() compatibility system calls if X86_X32 -# is defined. +# Due to a historical design error, certain syscalls are numbered differently +# in x32 as compared to native x86_64. These syscalls have numbers 512-547. +# Do not add new syscalls to this range. Numbers 548 and above are available +# for non-x32 use. # 512 x32 rt_sigaction compat_sys_rt_sigaction 513 x32 rt_sigreturn compat_sys_x32_rt_sigreturn 514 x32 ioctl compat_sys_ioctl -515 x32 readv compat_sys_readv -516 x32 writev compat_sys_writev +515 x32 readv sys_readv +516 x32 writev sys_writev 517 x32 recvfrom compat_sys_recvfrom 518 x32 sendmsg compat_sys_sendmsg 519 x32 recvmsg compat_sys_recvmsg @@ -388,15 +395,15 @@ 529 x32 waitid compat_sys_waitid 530 x32 set_robust_list compat_sys_set_robust_list 531 x32 get_robust_list compat_sys_get_robust_list -532 x32 vmsplice compat_sys_vmsplice +532 x32 vmsplice sys_vmsplice 533 x32 move_pages compat_sys_move_pages 534 x32 preadv compat_sys_preadv64 535 x32 pwritev compat_sys_pwritev64 536 x32 rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo 537 x32 recvmmsg compat_sys_recvmmsg_time64 538 x32 sendmmsg compat_sys_sendmmsg -539 x32 process_vm_readv compat_sys_process_vm_readv -540 x32 process_vm_writev compat_sys_process_vm_writev +539 x32 process_vm_readv sys_process_vm_readv +540 x32 process_vm_writev sys_process_vm_writev 541 x32 setsockopt sys_setsockopt 542 x32 getsockopt sys_getsockopt 543 x32 io_setup compat_sys_io_setup @@ -404,3 +411,5 @@ 545 x32 execveat compat_sys_execveat 546 x32 preadv2 compat_sys_preadv64v2 547 x32 pwritev2 compat_sys_pwritev64v2 +# This is the end of the legacy x32 range. Numbers 548 and above are +# not special and are not to be used for x32-specific syscalls. diff --git a/linux-user/xtensa/syscall.tbl b/linux-user/xtensa/syscall.tbl index 6276e3c2d3..fd2f30227d 100644 --- a/linux-user/xtensa/syscall.tbl +++ b/linux-user/xtensa/syscall.tbl @@ -410,3 +410,10 @@ 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd 439 common faccessat2 sys_faccessat2 +440 common process_madvise sys_process_madvise +441 common epoll_pwait2 sys_epoll_pwait2 +442 common mount_setattr sys_mount_setattr +# 443 reserved for quotactl_path +444 common landlock_create_ruleset sys_landlock_create_ruleset +445 common landlock_add_rule sys_landlock_add_rule +446 common landlock_restrict_self sys_landlock_restrict_self From 00c1b316edb33f2efb0775c2983bc5348c86529d Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 8 Jun 2021 14:08:10 +0200 Subject: [PATCH 027/531] i386: clarify 'hv-passthrough' behavior Clarify the fact that 'hv-passthrough' only enables features which are already known to QEMU and that it overrides all other 'hv-*' settings. Reviewed-by: Eduardo Habkost Signed-off-by: Vitaly Kuznetsov Message-Id: <20210608120817.1325125-3-vkuznets@redhat.com> Signed-off-by: Eduardo Habkost --- docs/hyperv.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/hyperv.txt b/docs/hyperv.txt index e53c581f45..a51953daa8 100644 --- a/docs/hyperv.txt +++ b/docs/hyperv.txt @@ -209,8 +209,11 @@ In some cases (e.g. during development) it may make sense to use QEMU in 'pass-through' mode and give Windows guests all enlightenments currently supported by KVM. This pass-through mode is enabled by "hv-passthrough" CPU flag. -Note: enabling this flag effectively prevents migration as supported features -may differ between target and destination. +Note: "hv-passthrough" flag only enables enlightenments which are known to QEMU +(have corresponding "hv-*" flag) and copies "hv-spinlocks="/"hv-vendor-id=" +values from KVM to QEMU. "hv-passthrough" overrides all other "hv-*" settings on +the command line. Also, enabling this flag effectively prevents migration as the +list of enabled enlightenments may differ between target and destination hosts. 4. Useful links From 07454e2ea84ee9be298c96d9730dc82abfb1488a Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 8 Jun 2021 14:08:11 +0200 Subject: [PATCH 028/531] i386: hardcode supported eVMCS version to '1' Currently, the only eVMCS version, supported by KVM (and described in TLFS) is '1'. When Enlightened VMCS feature is enabled, QEMU takes the supported eVMCS version range (from KVM_CAP_HYPERV_ENLIGHTENED_VMCS enablement) and puts it to guest visible CPUIDs. When (and if) eVMCS ver.2 appears a problem on migration is expected: it doesn't seem to be possible to migrate from a host supporting eVMCS ver.2 to a host, which only support eVMCS ver.1. Hardcode eVMCS ver.1 as the result of 'hv-evmcs' enablement for now. Newer eVMCS versions will have to have their own enablement options (e.g. 'hv-evmcs=2'). Signed-off-by: Vitaly Kuznetsov Reviewed-by: Eduardo Habkost Message-Id: <20210608120817.1325125-4-vkuznets@redhat.com> Signed-off-by: Eduardo Habkost --- docs/hyperv.txt | 2 +- target/i386/kvm/kvm.c | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/docs/hyperv.txt b/docs/hyperv.txt index a51953daa8..000638a2fd 100644 --- a/docs/hyperv.txt +++ b/docs/hyperv.txt @@ -170,7 +170,7 @@ Recommended: hv-frequencies 3.16. hv-evmcs =============== The enlightenment is nested specific, it targets Hyper-V on KVM guests. When -enabled, it provides Enlightened VMCS feature to the guest. The feature +enabled, it provides Enlightened VMCS version 1 feature to the guest. The feature implements paravirtualized protocol between L0 (KVM) and L1 (Hyper-V) hypervisors making L2 exits to the hypervisor faster. The feature is Intel-only. Note: some virtualization features (e.g. Posted Interrupts) are disabled when diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index a85035492f..02216b7031 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -1409,6 +1409,21 @@ static int hyperv_fill_cpuids(CPUState *cs, static Error *hv_passthrough_mig_blocker; static Error *hv_no_nonarch_cs_mig_blocker; +/* Checks that the exposed eVMCS version range is supported by KVM */ +static bool evmcs_version_supported(uint16_t evmcs_version, + uint16_t supported_evmcs_version) +{ + uint8_t min_version = evmcs_version & 0xff; + uint8_t max_version = evmcs_version >> 8; + uint8_t min_supported_version = supported_evmcs_version & 0xff; + uint8_t max_supported_version = supported_evmcs_version >> 8; + + return (min_version >= min_supported_version) && + (max_version <= max_supported_version); +} + +#define DEFAULT_EVMCS_VERSION ((1 << 8) | 1) + static int hyperv_init_vcpu(X86CPU *cpu) { CPUState *cs = CPU(cpu); @@ -1488,17 +1503,33 @@ static int hyperv_init_vcpu(X86CPU *cpu) } if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS)) { - uint16_t evmcs_version; + uint16_t evmcs_version = DEFAULT_EVMCS_VERSION; + uint16_t supported_evmcs_version; ret = kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_ENLIGHTENED_VMCS, 0, - (uintptr_t)&evmcs_version); + (uintptr_t)&supported_evmcs_version); + /* + * KVM is required to support EVMCS ver.1. as that's what 'hv-evmcs' + * option sets. Note: we hardcode the maximum supported eVMCS version + * to '1' as well so 'hv-evmcs' feature is migratable even when (and if) + * ver.2 is implemented. A new option (e.g. 'hv-evmcs=2') will then have + * to be added. + */ if (ret < 0) { - fprintf(stderr, "Hyper-V %s is not supported by kernel\n", - kvm_hyperv_properties[HYPERV_FEAT_EVMCS].desc); + error_report("Hyper-V %s is not supported by kernel", + kvm_hyperv_properties[HYPERV_FEAT_EVMCS].desc); return ret; } + if (!evmcs_version_supported(evmcs_version, supported_evmcs_version)) { + error_report("eVMCS version range [%d..%d] is not supported by " + "kernel (supported: [%d..%d])", evmcs_version & 0xff, + evmcs_version >> 8, supported_evmcs_version & 0xff, + supported_evmcs_version >> 8); + return -ENOTSUP; + } + cpu->hyperv_nested[0] = evmcs_version; } From d7652b772f302346c8f1043aa850a28c445e80d7 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 8 Jun 2021 14:08:12 +0200 Subject: [PATCH 029/531] i386: make hyperv_expand_features() return bool Return 'false' when hyperv_expand_features() sets an error. No functional change intended. Reviewed-by: Eduardo Habkost Signed-off-by: Vitaly Kuznetsov Message-Id: <20210608120817.1325125-5-vkuznets@redhat.com> Signed-off-by: Eduardo Habkost --- target/i386/kvm/kvm.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 02216b7031..ef127762bc 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -1220,12 +1220,12 @@ static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg) * of 'hv_passthrough' mode and fills the environment with all supported * Hyper-V features. */ -static void hyperv_expand_features(CPUState *cs, Error **errp) +static bool hyperv_expand_features(CPUState *cs, Error **errp) { X86CPU *cpu = X86_CPU(cs); if (!hyperv_enabled(cpu)) - return; + return true; if (cpu->hyperv_passthrough) { cpu->hyperv_vendor_id[0] = @@ -1273,49 +1273,49 @@ static void hyperv_expand_features(CPUState *cs, Error **errp) /* Features */ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RELAXED, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_VAPIC, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_TIME, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_CRASH, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RESET, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_VPINDEX, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RUNTIME, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_SYNIC, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_FREQUENCIES, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_REENLIGHTENMENT, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_TLBFLUSH, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_EVMCS, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_IPI, errp)) { - return; + return false; } if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER_DIRECT, errp)) { - return; + return false; } /* Additional dependencies not covered by kvm_hyperv_properties[] */ @@ -1325,7 +1325,10 @@ static void hyperv_expand_features(CPUState *cs, Error **errp) error_setg(errp, "Hyper-V %s requires Hyper-V %s", kvm_hyperv_properties[HYPERV_FEAT_SYNIC].desc, kvm_hyperv_properties[HYPERV_FEAT_VPINDEX].desc); + return false; } + + return true; } /* @@ -1591,8 +1594,7 @@ int kvm_arch_init_vcpu(CPUState *cs) env->apic_bus_freq = KVM_APIC_BUS_FREQUENCY; /* Paravirtualization CPUIDs */ - hyperv_expand_features(cs, &local_err); - if (local_err) { + if (!hyperv_expand_features(cs, &local_err)) { error_report_err(local_err); return -ENOSYS; } From 071ce4b03becf9e2df6b758fde9609be8ddf56f1 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 8 Jun 2021 14:08:13 +0200 Subject: [PATCH 030/531] i386: expand Hyper-V features during CPU feature expansion time To make Hyper-V features appear in e.g. QMP query-cpu-model-expansion we need to expand and set the corresponding CPUID leaves early. Modify x86_cpu_get_supported_feature_word() to call newly intoduced Hyper-V specific kvm_hv_get_supported_cpuid() instead of kvm_arch_get_supported_cpuid(). We can't use kvm_arch_get_supported_cpuid() as Hyper-V specific CPUID leaves intersect with KVM's. Note, early expansion will only happen when KVM supports system wide KVM_GET_SUPPORTED_HV_CPUID ioctl (KVM_CAP_SYS_HYPERV_CPUID). Reviewed-by: Eduardo Habkost Signed-off-by: Vitaly Kuznetsov Message-Id: <20210608120817.1325125-6-vkuznets@redhat.com> Signed-off-by: Eduardo Habkost --- target/i386/cpu.c | 4 ++++ target/i386/kvm/kvm-stub.c | 5 +++++ target/i386/kvm/kvm.c | 24 ++++++++++++++++++++---- target/i386/kvm/kvm_i386.h | 1 + 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 5f595a0d7e..46befde387 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5974,6 +5974,10 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) if (env->cpuid_xlevel2 == UINT32_MAX) { env->cpuid_xlevel2 = env->cpuid_min_xlevel2; } + + if (kvm_enabled()) { + kvm_hyperv_expand_features(cpu, errp); + } } /* diff --git a/target/i386/kvm/kvm-stub.c b/target/i386/kvm/kvm-stub.c index 92f49121b8..f6e7e4466e 100644 --- a/target/i386/kvm/kvm-stub.c +++ b/target/i386/kvm/kvm-stub.c @@ -39,3 +39,8 @@ bool kvm_hv_vpindex_settable(void) { return false; } + +bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp) +{ + abort(); +} diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index ef127762bc..556815db13 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -1220,13 +1220,22 @@ static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg) * of 'hv_passthrough' mode and fills the environment with all supported * Hyper-V features. */ -static bool hyperv_expand_features(CPUState *cs, Error **errp) +bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp) { - X86CPU *cpu = X86_CPU(cs); + CPUState *cs = CPU(cpu); if (!hyperv_enabled(cpu)) return true; + /* + * When kvm_hyperv_expand_features is called at CPU feature expansion + * time per-CPU kvm_state is not available yet so we can only proceed + * when KVM_CAP_SYS_HYPERV_CPUID is supported. + */ + if (!cs->kvm_state && + !kvm_check_extension(kvm_state, KVM_CAP_SYS_HYPERV_CPUID)) + return true; + if (cpu->hyperv_passthrough) { cpu->hyperv_vendor_id[0] = hv_cpuid_get_host(cs, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_EBX); @@ -1593,8 +1602,15 @@ int kvm_arch_init_vcpu(CPUState *cs) env->apic_bus_freq = KVM_APIC_BUS_FREQUENCY; - /* Paravirtualization CPUIDs */ - if (!hyperv_expand_features(cs, &local_err)) { + /* + * kvm_hyperv_expand_features() is called here for the second time in case + * KVM_CAP_SYS_HYPERV_CPUID is not supported. While we can't possibly handle + * 'query-cpu-model-expansion' in this case as we don't have a KVM vCPU to + * check which Hyper-V enlightenments are supported and which are not, we + * can still proceed and check/expand Hyper-V enlightenments here so legacy + * behavior is preserved. + */ + if (!kvm_hyperv_expand_features(cpu, &local_err)) { error_report_err(local_err); return -ENOSYS; } diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h index dc72508389..54667b35f0 100644 --- a/target/i386/kvm/kvm_i386.h +++ b/target/i386/kvm/kvm_i386.h @@ -47,6 +47,7 @@ bool kvm_has_x2apic_api(void); bool kvm_has_waitpkg(void); bool kvm_hv_vpindex_settable(void); +bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp); uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address); From 5ce48fa354f2270731e20f81dbb7ff191630c321 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 8 Jun 2021 14:08:14 +0200 Subject: [PATCH 031/531] i386: kill off hv_cpuid_check_and_set() hv_cpuid_check_and_set() does too much: - Checks if the feature is supported by KVM; - Checks if all dependencies are enabled; - Sets the feature bit in cpu->hyperv_features for 'passthrough' mode. To reduce the complexity, move all the logic except for dependencies check out of it. Also, in 'passthrough' mode we don't really need to check dependencies because KVM is supposed to provide a consistent set anyway. Reviewed-by: Eduardo Habkost Signed-off-by: Vitaly Kuznetsov Message-Id: <20210608120817.1325125-7-vkuznets@redhat.com> Signed-off-by: Eduardo Habkost --- target/i386/kvm/kvm.c | 104 +++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 68 deletions(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 556815db13..945d24300c 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -1148,16 +1148,12 @@ static bool hyperv_feature_supported(CPUState *cs, int feature) return true; } -static int hv_cpuid_check_and_set(CPUState *cs, int feature, Error **errp) +/* Checks that all feature dependencies are enabled */ +static bool hv_feature_check_deps(X86CPU *cpu, int feature, Error **errp) { - X86CPU *cpu = X86_CPU(cs); uint64_t deps; int dep_feat; - if (!hyperv_feat_enabled(cpu, feature) && !cpu->hyperv_passthrough) { - return 0; - } - deps = kvm_hyperv_properties[feature].dependencies; while (deps) { dep_feat = ctz64(deps); @@ -1165,26 +1161,12 @@ static int hv_cpuid_check_and_set(CPUState *cs, int feature, Error **errp) error_setg(errp, "Hyper-V %s requires Hyper-V %s", kvm_hyperv_properties[feature].desc, kvm_hyperv_properties[dep_feat].desc); - return 1; + return false; } deps &= ~(1ull << dep_feat); } - if (!hyperv_feature_supported(cs, feature)) { - if (hyperv_feat_enabled(cpu, feature)) { - error_setg(errp, "Hyper-V %s is not supported by kernel", - kvm_hyperv_properties[feature].desc); - return 1; - } else { - return 0; - } - } - - if (cpu->hyperv_passthrough) { - cpu->hyperv_features |= BIT(feature); - } - - return 0; + return true; } static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg) @@ -1223,6 +1205,8 @@ static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg) bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp) { CPUState *cs = CPU(cpu); + Error *local_err = NULL; + int feat; if (!hyperv_enabled(cpu)) return true; @@ -1278,53 +1262,37 @@ bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp) cpu->hyperv_spinlock_attempts = hv_cpuid_get_host(cs, HV_CPUID_ENLIGHTMENT_INFO, R_EBX); - } - /* Features */ - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RELAXED, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_VAPIC, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_TIME, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_CRASH, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RESET, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_VPINDEX, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RUNTIME, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_SYNIC, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_FREQUENCIES, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_REENLIGHTENMENT, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_TLBFLUSH, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_EVMCS, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_IPI, errp)) { - return false; - } - if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER_DIRECT, errp)) { - return false; + /* + * Mark feature as enabled in 'cpu->hyperv_features' as + * hv_build_cpuid_leaf() uses this info to build guest CPUIDs. + */ + for (feat = 0; feat < ARRAY_SIZE(kvm_hyperv_properties); feat++) { + if (hyperv_feature_supported(cs, feat)) { + cpu->hyperv_features |= BIT(feat); + } + } + } else { + /* Check features availability and dependencies */ + for (feat = 0; feat < ARRAY_SIZE(kvm_hyperv_properties); feat++) { + /* If the feature was not requested skip it. */ + if (!hyperv_feat_enabled(cpu, feat)) { + continue; + } + + /* Check if the feature is supported by KVM */ + if (!hyperv_feature_supported(cs, feat)) { + error_setg(errp, "Hyper-V %s is not supported by kernel", + kvm_hyperv_properties[feat].desc); + return false; + } + + /* Check dependencies */ + if (!hv_feature_check_deps(cpu, feat, &local_err)) { + error_propagate(errp, local_err); + return false; + } + } } /* Additional dependencies not covered by kvm_hyperv_properties[] */ From b26f68c36bf6edaaa224f8a6ab285394af4d0f8c Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 8 Jun 2021 14:08:15 +0200 Subject: [PATCH 032/531] i386: HV_HYPERCALL_AVAILABLE privilege bit is always needed According to TLFS, Hyper-V guest is supposed to check HV_HYPERCALL_AVAILABLE privilege bit before accessing HV_X64_MSR_GUEST_OS_ID/HV_X64_MSR_HYPERCALL MSRs but at least some Windows versions ignore that. As KVM is very permissive and allows accessing these MSRs unconditionally, no issue is observed. We may, however, want to tighten the checks eventually. Conforming to the spec is probably also a good idea. Enable HV_HYPERCALL_AVAILABLE bit unconditionally. Reviewed-by: Eduardo Habkost Signed-off-by: Vitaly Kuznetsov Message-Id: <20210608120817.1325125-8-vkuznets@redhat.com> Signed-off-by: Eduardo Habkost --- target/i386/kvm/kvm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 945d24300c..eee1a6b46e 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -813,8 +813,6 @@ static struct { [HYPERV_FEAT_RELAXED] = { .desc = "relaxed timing (hv-relaxed)", .flags = { - {.func = HV_CPUID_FEATURES, .reg = R_EAX, - .bits = HV_HYPERCALL_AVAILABLE}, {.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX, .bits = HV_RELAXED_TIMING_RECOMMENDED} } @@ -823,7 +821,7 @@ static struct { .desc = "virtual APIC (hv-vapic)", .flags = { {.func = HV_CPUID_FEATURES, .reg = R_EAX, - .bits = HV_HYPERCALL_AVAILABLE | HV_APIC_ACCESS_AVAILABLE}, + .bits = HV_APIC_ACCESS_AVAILABLE}, {.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX, .bits = HV_APIC_ACCESS_RECOMMENDED} } @@ -832,8 +830,7 @@ static struct { .desc = "clocksources (hv-time)", .flags = { {.func = HV_CPUID_FEATURES, .reg = R_EAX, - .bits = HV_HYPERCALL_AVAILABLE | HV_TIME_REF_COUNT_AVAILABLE | - HV_REFERENCE_TSC_AVAILABLE} + .bits = HV_TIME_REF_COUNT_AVAILABLE | HV_REFERENCE_TSC_AVAILABLE} } }, [HYPERV_FEAT_CRASH] = { @@ -1346,6 +1343,9 @@ static int hyperv_fill_cpuids(CPUState *cs, c->ebx = hv_build_cpuid_leaf(cs, HV_CPUID_FEATURES, R_EBX); c->edx = hv_build_cpuid_leaf(cs, HV_CPUID_FEATURES, R_EDX); + /* Unconditionally required with any Hyper-V enlightenment */ + c->eax |= HV_HYPERCALL_AVAILABLE; + /* Not exposed by KVM but needed to make CPU hotplug in Windows work */ c->edx |= HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE; From cce087f628c651e905f5e2097d9bb9f678689669 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 8 Jun 2021 14:08:16 +0200 Subject: [PATCH 033/531] i386: Hyper-V SynIC requires POST_MESSAGES/SIGNAL_EVENTS privileges When Hyper-V SynIC is enabled, we may need to allow Windows guests to make hypercalls (POST_MESSAGES/SIGNAL_EVENTS). No issue is currently observed because KVM is very permissive, allowing these hypercalls regarding of guest visible CPUid bits. Reviewed-by: Eduardo Habkost Signed-off-by: Vitaly Kuznetsov Message-Id: <20210608120817.1325125-9-vkuznets@redhat.com> Signed-off-by: Eduardo Habkost --- target/i386/kvm/hyperv-proto.h | 6 ++++++ target/i386/kvm/kvm.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h index e30d64b4ad..5fbb385cc1 100644 --- a/target/i386/kvm/hyperv-proto.h +++ b/target/i386/kvm/hyperv-proto.h @@ -38,6 +38,12 @@ #define HV_ACCESS_FREQUENCY_MSRS (1u << 11) #define HV_ACCESS_REENLIGHTENMENTS_CONTROL (1u << 13) +/* + * HV_CPUID_FEATURES.EBX bits + */ +#define HV_POST_MESSAGES (1u << 4) +#define HV_SIGNAL_EVENTS (1u << 5) + /* * HV_CPUID_FEATURES.EDX bits */ diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index eee1a6b46e..59ed8327ac 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -1346,6 +1346,12 @@ static int hyperv_fill_cpuids(CPUState *cs, /* Unconditionally required with any Hyper-V enlightenment */ c->eax |= HV_HYPERCALL_AVAILABLE; + /* SynIC and Vmbus devices require messages/signals hypercalls */ + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC) && + !cpu->hyperv_synic_kvm_only) { + c->ebx |= HV_POST_MESSAGES | HV_SIGNAL_EVENTS; + } + /* Not exposed by KVM but needed to make CPU hotplug in Windows work */ c->edx |= HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE; From a7a0da844d299971bdbf99665bd63398668dde83 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Wed, 7 Jul 2021 19:36:23 -0500 Subject: [PATCH 034/531] target/i386: suppress CPUID leaves not defined by the CPU vendor Currently all built-in CPUs report cache information via CPUID leaves 2 and 4, but these have never been defined for AMD. In the case of SEV-SNP this can cause issues with CPUID enforcement. Address this by allowing CPU types to suppress these via a new "x-vendor-cpuid-only" CPU property, which is true by default, but switched off for older machine types to maintain compatibility. Cc: "Dr. David Alan Gilbert" Cc: Eduardo Habkost Cc: Richard Henderson Cc: Igor Mammedov Cc: zhenwei pi Suggested-by: Eduardo Habkost Signed-off-by: Michael Roth Message-Id: <20210708003623.18665-1-michael.roth@amd.com> Signed-off-by: Eduardo Habkost --- hw/i386/pc.c | 1 + target/i386/cpu.c | 6 ++++++ target/i386/cpu.h | 3 +++ 3 files changed, 10 insertions(+) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 8e1220db72..aa79c5e0e6 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -98,6 +98,7 @@ GlobalProperty pc_compat_6_0[] = { { "qemu64" "-" TYPE_X86_CPU, "family", "6" }, { "qemu64" "-" TYPE_X86_CPU, "model", "6" }, { "qemu64" "-" TYPE_X86_CPU, "stepping", "3" }, + { TYPE_X86_CPU, "x-vendor-cpuid-only", "off" }, }; const size_t pc_compat_6_0_len = G_N_ELEMENTS(pc_compat_6_0); diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 46befde387..6b7043e425 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5155,6 +5155,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, if (cpu->cache_info_passthrough) { host_cpuid(index, 0, eax, ebx, ecx, edx); break; + } else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) { + *eax = *ebx = *ecx = *edx = 0; + break; } *eax = 1; /* Number of CPUID[EAX=2] calls required */ *ebx = 0; @@ -5176,6 +5179,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, if ((*eax & 31) && cs->nr_cores > 1) { *eax |= (cs->nr_cores - 1) << 26; } + } else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) { + *eax = *ebx = *ecx = *edx = 0; } else { *eax = 0; switch (count) { @@ -6651,6 +6656,7 @@ static Property x86_cpu_properties[] = { DEFINE_PROP_BOOL("full-cpuid-auto-level", X86CPU, full_cpuid_auto_level, true), DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor), DEFINE_PROP_BOOL("cpuid-0xb", X86CPU, enable_cpuid_0xb, true), + DEFINE_PROP_BOOL("x-vendor-cpuid-only", X86CPU, vendor_cpuid_only, true), DEFINE_PROP_BOOL("lmce", X86CPU, enable_lmce, false), DEFINE_PROP_BOOL("l3-cache", X86CPU, enable_l3_cache, true), DEFINE_PROP_BOOL("kvm-no-smi-migration", X86CPU, kvm_no_smi_migration, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 8f3747dd28..950a991a71 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1748,6 +1748,9 @@ struct X86CPU { /* Enable auto level-increase for all CPUID leaves */ bool full_cpuid_auto_level; + /* Only advertise CPUID leaves defined by the vendor */ + bool vendor_cpuid_only; + /* Enable auto level-increase for Intel Processor Trace leave */ bool intel_pt_auto_level; From 760746ac533dd770a56340b1376e7b3fb1693562 Mon Sep 17 00:00:00 2001 From: zhenwei pi Date: Thu, 8 Jul 2021 12:06:41 -0500 Subject: [PATCH 035/531] target/i386: Fix cpuid level for AMD A AMD server typically has cpuid level 0x10(test on Rome/Milan), it should not be changed to 0x1f in multi-dies case. * to maintain compatibility with older machine types, only implement this change when the CPU's "x-vendor-cpuid-only" property is false Cc: "Dr. David Alan Gilbert" Cc: Eduardo Habkost Cc: Richard Henderson Cc: Igor Mammedov Cc: zhenwei pi Fixes: a94e1428991 (target/i386: Add CPUID.1F generation support for multi-dies PCMachine) Signed-off-by: zhenwei pi Signed-off-by: Michael Roth Message-Id: <20210708170641.49410-1-michael.roth@amd.com> Signed-off-by: Eduardo Habkost --- target/i386/cpu.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 6b7043e425..48b55ebd0a 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5950,8 +5950,15 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) } } - /* CPU topology with multi-dies support requires CPUID[0x1F] */ - if (env->nr_dies > 1) { + /* + * Intel CPU topology with multi-dies support requires CPUID[0x1F]. + * For AMD Rome/Milan, cpuid level is 0x10, and guest OS should detect + * extended toplogy by leaf 0xB. Only adjust it for Intel CPU, unless + * cpu->vendor_cpuid_only has been unset for compatibility with older + * machine types. + */ + if ((env->nr_dies > 1) && + (IS_INTEL_CPU(env) || !cpu->vendor_cpuid_only)) { x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x1F); } From f74d339c86d4460f1d7a644e965170c03518a737 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Wed, 7 Jul 2021 15:40:29 +0200 Subject: [PATCH 036/531] numa: Report expected initiator When setting up NUMA with HMAT enabled there's a check performed in machine_set_cpu_numa_node() that reports an error when a NUMA node has a CPU but the node's initiator is not itself. The error message reported contains only the expected value and not the actual value (which is different because an error is being reported). Report both values in the error message. Signed-off-by: Michal Privoznik Reviewed-by: Igor Mammedov Reviewed-by: Pankaj Gupta Message-Id: Signed-off-by: Eduardo Habkost --- hw/core/machine.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 57c18f909a..6f59fb0b7f 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -728,7 +728,8 @@ void machine_set_cpu_numa_node(MachineState *machine, if ((numa_info[props->node_id].initiator < MAX_NODES) && (props->node_id != numa_info[props->node_id].initiator)) { error_setg(errp, "The initiator of CPU NUMA node %" PRId64 - " should be itself", props->node_id); + " should be itself (got %" PRIu16 ")", + props->node_id, numa_info[props->node_id].initiator); return; } numa_info[props->node_id].has_cpu = true; From 294aa0437b7f6a3e94653ef661310ef621859c87 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Wed, 7 Jul 2021 15:40:30 +0200 Subject: [PATCH 037/531] numa: Parse initiator= attribute before cpus= attribute When parsing cpus= attribute of -numa object couple of checks is performed, such as correct initiator setting (see the if() statement at the end of for() loop in machine_set_cpu_numa_node()). However, with the current code cpus= attribute is parsed before initiator= attribute and thus the check may fail even though it is not obvious why. But since parsing the initiator= attribute does not depend on the cpus= attribute we can swap the order of the two. It's fairly easy to reproduce with the following command line (snippet of an actual cmd line): -smp 4,sockets=4,cores=1,threads=1 \ -object '{"qom-type":"memory-backend-ram","id":"ram-node0","size":2147483648}' \ -numa node,nodeid=0,cpus=0-1,initiator=0,memdev=ram-node0 \ -object '{"qom-type":"memory-backend-ram","id":"ram-node1","size":2147483648}' \ -numa node,nodeid=1,cpus=2-3,initiator=1,memdev=ram-node1 \ -numa hmat-lb,initiator=0,target=0,hierarchy=memory,data-type=access-latency,latency=5 \ -numa hmat-lb,initiator=0,target=0,hierarchy=first-level,data-type=access-latency,latency=10 \ -numa hmat-lb,initiator=1,target=1,hierarchy=memory,data-type=access-latency,latency=5 \ -numa hmat-lb,initiator=1,target=1,hierarchy=first-level,data-type=access-latency,latency=10 \ -numa hmat-lb,initiator=0,target=0,hierarchy=memory,data-type=access-bandwidth,bandwidth=204800K \ -numa hmat-lb,initiator=0,target=0,hierarchy=first-level,data-type=access-bandwidth,bandwidth=208896K \ -numa hmat-lb,initiator=1,target=1,hierarchy=memory,data-type=access-bandwidth,bandwidth=204800K \ -numa hmat-lb,initiator=1,target=1,hierarchy=first-level,data-type=access-bandwidth,bandwidth=208896K \ -numa hmat-cache,node-id=0,size=10K,level=1,associativity=direct,policy=write-back,line=8 \ -numa hmat-cache,node-id=1,size=10K,level=1,associativity=direct,policy=write-back,line=8 \ Signed-off-by: Michal Privoznik Reviewed-by: Igor Mammedov Message-Id: Signed-off-by: Eduardo Habkost --- hw/core/numa.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/hw/core/numa.c b/hw/core/numa.c index 1058d3697b..510d096a88 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -88,6 +88,29 @@ static void parse_numa_node(MachineState *ms, NumaNodeOptions *node, return; } + /* + * If not set the initiator, set it to MAX_NODES. And if + * HMAT is enabled and this node has no cpus, QEMU will raise error. + */ + numa_info[nodenr].initiator = MAX_NODES; + if (node->has_initiator) { + if (!ms->numa_state->hmat_enabled) { + error_setg(errp, "ACPI Heterogeneous Memory Attribute Table " + "(HMAT) is disabled, enable it with -machine hmat=on " + "before using any of hmat specific options"); + return; + } + + if (node->initiator >= MAX_NODES) { + error_report("The initiator id %" PRIu16 " expects an integer " + "between 0 and %d", node->initiator, + MAX_NODES - 1); + return; + } + + numa_info[nodenr].initiator = node->initiator; + } + for (cpus = node->cpus; cpus; cpus = cpus->next) { CpuInstanceProperties props; if (cpus->value >= max_cpus) { @@ -142,28 +165,6 @@ static void parse_numa_node(MachineState *ms, NumaNodeOptions *node, numa_info[nodenr].node_memdev = MEMORY_BACKEND(o); } - /* - * If not set the initiator, set it to MAX_NODES. And if - * HMAT is enabled and this node has no cpus, QEMU will raise error. - */ - numa_info[nodenr].initiator = MAX_NODES; - if (node->has_initiator) { - if (!ms->numa_state->hmat_enabled) { - error_setg(errp, "ACPI Heterogeneous Memory Attribute Table " - "(HMAT) is disabled, enable it with -machine hmat=on " - "before using any of hmat specific options"); - return; - } - - if (node->initiator >= MAX_NODES) { - error_report("The initiator id %" PRIu16 " expects an integer " - "between 0 and %d", node->initiator, - MAX_NODES - 1); - return; - } - - numa_info[nodenr].initiator = node->initiator; - } numa_info[nodenr].present = true; max_numa_nodeid = MAX(max_numa_nodeid, nodenr + 1); ms->numa_state->num_nodes++; From 080ac33542d7ee042710f05c023fe5e3a70b9ebf Mon Sep 17 00:00:00 2001 From: Dmitry Voronetskiy Date: Sun, 13 Jun 2021 21:08:38 +0300 Subject: [PATCH 038/531] target/i386: Tidy hw_breakpoint_remove Since cpu_breakpoint and cpu_watchpoint are in a union, the code should access only one of them. Signed-off-by: Dmitry Voronetskiy Message-Id: <20210613180838.21349-1-davoronetskiy@gmail.com> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- target/i386/tcg/sysemu/bpt_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/i386/tcg/sysemu/bpt_helper.c b/target/i386/tcg/sysemu/bpt_helper.c index 624f90b789..4d96a48a3c 100644 --- a/target/i386/tcg/sysemu/bpt_helper.c +++ b/target/i386/tcg/sysemu/bpt_helper.c @@ -109,9 +109,9 @@ static void hw_breakpoint_remove(CPUX86State *env, int index) case DR7_TYPE_DATA_WR: case DR7_TYPE_DATA_RW: - if (env->cpu_breakpoint[index]) { + if (env->cpu_watchpoint[index]) { cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]); - env->cpu_breakpoint[index] = NULL; + env->cpu_watchpoint[index] = NULL; } break; From 505910a6e2d5ca374cbbed874251952d113c7919 Mon Sep 17 00:00:00 2001 From: Ziqiao Kong Date: Sun, 30 May 2021 23:01:12 +0800 Subject: [PATCH 039/531] target/i386: Trivial code motion and code style fix A new pair of braces has to be added to declare variables in the case block. The code style is also fixed according to the transalte.c itself during the code motion. Signed-off-by: Ziqiao Kong Message-Id: <20210530150112.74411-1-ziqiaokong@gmail.com> Signed-off-by: Richard Henderson --- target/i386/tcg/translate.c | 933 ++++++++++++++++++------------------ 1 file changed, 472 insertions(+), 461 deletions(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 3814ce2a3e..a43e577019 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -5919,503 +5919,514 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) /************************/ /* floats */ case 0xd8 ... 0xdf: - if (s->flags & (HF_EM_MASK | HF_TS_MASK)) { - /* if CR0.EM or CR0.TS are set, generate an FPU exception */ - /* XXX: what to do if illegal op ? */ - gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); - break; - } - modrm = x86_ldub_code(env, s); - mod = (modrm >> 6) & 3; - rm = modrm & 7; - op = ((b & 7) << 3) | ((modrm >> 3) & 7); - if (mod != 3) { - /* memory op */ - gen_lea_modrm(env, s, modrm); - switch(op) { - case 0x00 ... 0x07: /* fxxxs */ - case 0x10 ... 0x17: /* fixxxl */ - case 0x20 ... 0x27: /* fxxxl */ - case 0x30 ... 0x37: /* fixxx */ - { - int op1; - op1 = op & 7; - - switch(op >> 4) { - case 0: - tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUL); - gen_helper_flds_FT0(cpu_env, s->tmp2_i32); - break; - case 1: - tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUL); - gen_helper_fildl_FT0(cpu_env, s->tmp2_i32); - break; - case 2: - tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, - s->mem_index, MO_LEQ); - gen_helper_fldl_FT0(cpu_env, s->tmp1_i64); - break; - case 3: - default: - tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LESW); - gen_helper_fildl_FT0(cpu_env, s->tmp2_i32); - break; - } - - gen_helper_fp_arith_ST0_FT0(op1); - if (op1 == 3) { - /* fcomp needs pop */ - gen_helper_fpop(cpu_env); - } - } + { + if (s->flags & (HF_EM_MASK | HF_TS_MASK)) { + /* if CR0.EM or CR0.TS are set, generate an FPU exception */ + /* XXX: what to do if illegal op ? */ + gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); break; - case 0x08: /* flds */ - case 0x0a: /* fsts */ - case 0x0b: /* fstps */ - case 0x18 ... 0x1b: /* fildl, fisttpl, fistl, fistpl */ - case 0x28 ... 0x2b: /* fldl, fisttpll, fstl, fstpl */ - case 0x38 ... 0x3b: /* filds, fisttps, fists, fistps */ - switch(op & 7) { - case 0: - switch(op >> 4) { + } + modrm = x86_ldub_code(env, s); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = ((b & 7) << 3) | ((modrm >> 3) & 7); + if (mod != 3) { + /* memory op */ + gen_lea_modrm(env, s, modrm); + switch (op) { + case 0x00 ... 0x07: /* fxxxs */ + case 0x10 ... 0x17: /* fixxxl */ + case 0x20 ... 0x27: /* fxxxl */ + case 0x30 ... 0x37: /* fixxx */ + { + int op1; + op1 = op & 7; + + switch (op >> 4) { + case 0: + tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LEUL); + gen_helper_flds_FT0(cpu_env, s->tmp2_i32); + break; + case 1: + tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LEUL); + gen_helper_fildl_FT0(cpu_env, s->tmp2_i32); + break; + case 2: + tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, + s->mem_index, MO_LEQ); + gen_helper_fldl_FT0(cpu_env, s->tmp1_i64); + break; + case 3: + default: + tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LESW); + gen_helper_fildl_FT0(cpu_env, s->tmp2_i32); + break; + } + + gen_helper_fp_arith_ST0_FT0(op1); + if (op1 == 3) { + /* fcomp needs pop */ + gen_helper_fpop(cpu_env); + } + } + break; + case 0x08: /* flds */ + case 0x0a: /* fsts */ + case 0x0b: /* fstps */ + case 0x18 ... 0x1b: /* fildl, fisttpl, fistl, fistpl */ + case 0x28 ... 0x2b: /* fldl, fisttpll, fstl, fstpl */ + case 0x38 ... 0x3b: /* filds, fisttps, fists, fistps */ + switch (op & 7) { case 0: - tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUL); - gen_helper_flds_ST0(cpu_env, s->tmp2_i32); + switch (op >> 4) { + case 0: + tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LEUL); + gen_helper_flds_ST0(cpu_env, s->tmp2_i32); + break; + case 1: + tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LEUL); + gen_helper_fildl_ST0(cpu_env, s->tmp2_i32); + break; + case 2: + tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, + s->mem_index, MO_LEQ); + gen_helper_fldl_ST0(cpu_env, s->tmp1_i64); + break; + case 3: + default: + tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LESW); + gen_helper_fildl_ST0(cpu_env, s->tmp2_i32); + break; + } break; case 1: - tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUL); - gen_helper_fildl_ST0(cpu_env, s->tmp2_i32); + /* XXX: the corresponding CPUID bit must be tested ! */ + switch (op >> 4) { + case 1: + gen_helper_fisttl_ST0(s->tmp2_i32, cpu_env); + tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LEUL); + break; + case 2: + gen_helper_fisttll_ST0(s->tmp1_i64, cpu_env); + tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, + s->mem_index, MO_LEQ); + break; + case 3: + default: + gen_helper_fistt_ST0(s->tmp2_i32, cpu_env); + tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LEUW); + break; + } + gen_helper_fpop(cpu_env); break; - case 2: - tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, - s->mem_index, MO_LEQ); - gen_helper_fldl_ST0(cpu_env, s->tmp1_i64); - break; - case 3: default: - tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LESW); - gen_helper_fildl_ST0(cpu_env, s->tmp2_i32); + switch (op >> 4) { + case 0: + gen_helper_fsts_ST0(s->tmp2_i32, cpu_env); + tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LEUL); + break; + case 1: + gen_helper_fistl_ST0(s->tmp2_i32, cpu_env); + tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LEUL); + break; + case 2: + gen_helper_fstl_ST0(s->tmp1_i64, cpu_env); + tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, + s->mem_index, MO_LEQ); + break; + case 3: + default: + gen_helper_fist_ST0(s->tmp2_i32, cpu_env); + tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LEUW); + break; + } + if ((op & 7) == 3) { + gen_helper_fpop(cpu_env); + } break; } break; - case 1: - /* XXX: the corresponding CPUID bit must be tested ! */ - switch(op >> 4) { - case 1: - gen_helper_fisttl_ST0(s->tmp2_i32, cpu_env); - tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUL); - break; - case 2: - gen_helper_fisttll_ST0(s->tmp1_i64, cpu_env); - tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, - s->mem_index, MO_LEQ); - break; - case 3: - default: - gen_helper_fistt_ST0(s->tmp2_i32, cpu_env); - tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUW); - break; - } + case 0x0c: /* fldenv mem */ + gen_helper_fldenv(cpu_env, s->A0, + tcg_const_i32(dflag - 1)); + break; + case 0x0d: /* fldcw mem */ + tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LEUW); + gen_helper_fldcw(cpu_env, s->tmp2_i32); + break; + case 0x0e: /* fnstenv mem */ + gen_helper_fstenv(cpu_env, s->A0, + tcg_const_i32(dflag - 1)); + break; + case 0x0f: /* fnstcw mem */ + gen_helper_fnstcw(s->tmp2_i32, cpu_env); + tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LEUW); + break; + case 0x1d: /* fldt mem */ + gen_helper_fldt_ST0(cpu_env, s->A0); + break; + case 0x1f: /* fstpt mem */ + gen_helper_fstt_ST0(cpu_env, s->A0); + gen_helper_fpop(cpu_env); + break; + case 0x2c: /* frstor mem */ + gen_helper_frstor(cpu_env, s->A0, + tcg_const_i32(dflag - 1)); + break; + case 0x2e: /* fnsave mem */ + gen_helper_fsave(cpu_env, s->A0, + tcg_const_i32(dflag - 1)); + break; + case 0x2f: /* fnstsw mem */ + gen_helper_fnstsw(s->tmp2_i32, cpu_env); + tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, + s->mem_index, MO_LEUW); + break; + case 0x3c: /* fbld */ + gen_helper_fbld_ST0(cpu_env, s->A0); + break; + case 0x3e: /* fbstp */ + gen_helper_fbst_ST0(cpu_env, s->A0); + gen_helper_fpop(cpu_env); + break; + case 0x3d: /* fildll */ + tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, + s->mem_index, MO_LEQ); + gen_helper_fildll_ST0(cpu_env, s->tmp1_i64); + break; + case 0x3f: /* fistpll */ + gen_helper_fistll_ST0(s->tmp1_i64, cpu_env); + tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, + s->mem_index, MO_LEQ); gen_helper_fpop(cpu_env); break; default: - switch(op >> 4) { - case 0: - gen_helper_fsts_ST0(s->tmp2_i32, cpu_env); - tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUL); - break; - case 1: - gen_helper_fistl_ST0(s->tmp2_i32, cpu_env); - tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUL); - break; - case 2: - gen_helper_fstl_ST0(s->tmp1_i64, cpu_env); - tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, - s->mem_index, MO_LEQ); - break; - case 3: - default: - gen_helper_fist_ST0(s->tmp2_i32, cpu_env); - tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUW); - break; - } - if ((op & 7) == 3) - gen_helper_fpop(cpu_env); - break; + goto unknown_op; } - break; - case 0x0c: /* fldenv mem */ - gen_helper_fldenv(cpu_env, s->A0, tcg_const_i32(dflag - 1)); - break; - case 0x0d: /* fldcw mem */ - tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUW); - gen_helper_fldcw(cpu_env, s->tmp2_i32); - break; - case 0x0e: /* fnstenv mem */ - gen_helper_fstenv(cpu_env, s->A0, tcg_const_i32(dflag - 1)); - break; - case 0x0f: /* fnstcw mem */ - gen_helper_fnstcw(s->tmp2_i32, cpu_env); - tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUW); - break; - case 0x1d: /* fldt mem */ - gen_helper_fldt_ST0(cpu_env, s->A0); - break; - case 0x1f: /* fstpt mem */ - gen_helper_fstt_ST0(cpu_env, s->A0); - gen_helper_fpop(cpu_env); - break; - case 0x2c: /* frstor mem */ - gen_helper_frstor(cpu_env, s->A0, tcg_const_i32(dflag - 1)); - break; - case 0x2e: /* fnsave mem */ - gen_helper_fsave(cpu_env, s->A0, tcg_const_i32(dflag - 1)); - break; - case 0x2f: /* fnstsw mem */ - gen_helper_fnstsw(s->tmp2_i32, cpu_env); - tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUW); - break; - case 0x3c: /* fbld */ - gen_helper_fbld_ST0(cpu_env, s->A0); - break; - case 0x3e: /* fbstp */ - gen_helper_fbst_ST0(cpu_env, s->A0); - gen_helper_fpop(cpu_env); - break; - case 0x3d: /* fildll */ - tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEQ); - gen_helper_fildll_ST0(cpu_env, s->tmp1_i64); - break; - case 0x3f: /* fistpll */ - gen_helper_fistll_ST0(s->tmp1_i64, cpu_env); - tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEQ); - gen_helper_fpop(cpu_env); - break; - default: - goto unknown_op; - } - } else { - /* register float ops */ - opreg = rm; + } else { + /* register float ops */ + opreg = rm; - switch(op) { - case 0x08: /* fld sti */ - gen_helper_fpush(cpu_env); - gen_helper_fmov_ST0_STN(cpu_env, - tcg_const_i32((opreg + 1) & 7)); - break; - case 0x09: /* fxchg sti */ - case 0x29: /* fxchg4 sti, undocumented op */ - case 0x39: /* fxchg7 sti, undocumented op */ - gen_helper_fxchg_ST0_STN(cpu_env, tcg_const_i32(opreg)); - break; - case 0x0a: /* grp d9/2 */ - switch(rm) { - case 0: /* fnop */ - /* check exceptions (FreeBSD FPU probe) */ - gen_helper_fwait(cpu_env); + switch (op) { + case 0x08: /* fld sti */ + gen_helper_fpush(cpu_env); + gen_helper_fmov_ST0_STN(cpu_env, + tcg_const_i32((opreg + 1) & 7)); break; - default: - goto unknown_op; - } - break; - case 0x0c: /* grp d9/4 */ - switch(rm) { - case 0: /* fchs */ - gen_helper_fchs_ST0(cpu_env); + case 0x09: /* fxchg sti */ + case 0x29: /* fxchg4 sti, undocumented op */ + case 0x39: /* fxchg7 sti, undocumented op */ + gen_helper_fxchg_ST0_STN(cpu_env, tcg_const_i32(opreg)); break; - case 1: /* fabs */ - gen_helper_fabs_ST0(cpu_env); - break; - case 4: /* ftst */ - gen_helper_fldz_FT0(cpu_env); - gen_helper_fcom_ST0_FT0(cpu_env); - break; - case 5: /* fxam */ - gen_helper_fxam_ST0(cpu_env); - break; - default: - goto unknown_op; - } - break; - case 0x0d: /* grp d9/5 */ - { - switch(rm) { - case 0: - gen_helper_fpush(cpu_env); - gen_helper_fld1_ST0(cpu_env); - break; - case 1: - gen_helper_fpush(cpu_env); - gen_helper_fldl2t_ST0(cpu_env); - break; - case 2: - gen_helper_fpush(cpu_env); - gen_helper_fldl2e_ST0(cpu_env); - break; - case 3: - gen_helper_fpush(cpu_env); - gen_helper_fldpi_ST0(cpu_env); - break; - case 4: - gen_helper_fpush(cpu_env); - gen_helper_fldlg2_ST0(cpu_env); - break; - case 5: - gen_helper_fpush(cpu_env); - gen_helper_fldln2_ST0(cpu_env); - break; - case 6: - gen_helper_fpush(cpu_env); - gen_helper_fldz_ST0(cpu_env); + case 0x0a: /* grp d9/2 */ + switch (rm) { + case 0: /* fnop */ + /* check exceptions (FreeBSD FPU probe) */ + gen_helper_fwait(cpu_env); break; default: goto unknown_op; } - } - break; - case 0x0e: /* grp d9/6 */ - switch(rm) { - case 0: /* f2xm1 */ - gen_helper_f2xm1(cpu_env); break; - case 1: /* fyl2x */ - gen_helper_fyl2x(cpu_env); - break; - case 2: /* fptan */ - gen_helper_fptan(cpu_env); - break; - case 3: /* fpatan */ - gen_helper_fpatan(cpu_env); - break; - case 4: /* fxtract */ - gen_helper_fxtract(cpu_env); - break; - case 5: /* fprem1 */ - gen_helper_fprem1(cpu_env); - break; - case 6: /* fdecstp */ - gen_helper_fdecstp(cpu_env); - break; - default: - case 7: /* fincstp */ - gen_helper_fincstp(cpu_env); - break; - } - break; - case 0x0f: /* grp d9/7 */ - switch(rm) { - case 0: /* fprem */ - gen_helper_fprem(cpu_env); - break; - case 1: /* fyl2xp1 */ - gen_helper_fyl2xp1(cpu_env); - break; - case 2: /* fsqrt */ - gen_helper_fsqrt(cpu_env); - break; - case 3: /* fsincos */ - gen_helper_fsincos(cpu_env); - break; - case 5: /* fscale */ - gen_helper_fscale(cpu_env); - break; - case 4: /* frndint */ - gen_helper_frndint(cpu_env); - break; - case 6: /* fsin */ - gen_helper_fsin(cpu_env); - break; - default: - case 7: /* fcos */ - gen_helper_fcos(cpu_env); - break; - } - break; - case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */ - case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */ - case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ - { - int op1; - - op1 = op & 7; - if (op >= 0x20) { - gen_helper_fp_arith_STN_ST0(op1, opreg); - if (op >= 0x30) - gen_helper_fpop(cpu_env); - } else { - gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); - gen_helper_fp_arith_ST0_FT0(op1); + case 0x0c: /* grp d9/4 */ + switch (rm) { + case 0: /* fchs */ + gen_helper_fchs_ST0(cpu_env); + break; + case 1: /* fabs */ + gen_helper_fabs_ST0(cpu_env); + break; + case 4: /* ftst */ + gen_helper_fldz_FT0(cpu_env); + gen_helper_fcom_ST0_FT0(cpu_env); + break; + case 5: /* fxam */ + gen_helper_fxam_ST0(cpu_env); + break; + default: + goto unknown_op; } - } - break; - case 0x02: /* fcom */ - case 0x22: /* fcom2, undocumented op */ - gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); - gen_helper_fcom_ST0_FT0(cpu_env); - break; - case 0x03: /* fcomp */ - case 0x23: /* fcomp3, undocumented op */ - case 0x32: /* fcomp5, undocumented op */ - gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); - gen_helper_fcom_ST0_FT0(cpu_env); - gen_helper_fpop(cpu_env); - break; - case 0x15: /* da/5 */ - switch(rm) { - case 1: /* fucompp */ - gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(1)); - gen_helper_fucom_ST0_FT0(cpu_env); - gen_helper_fpop(cpu_env); - gen_helper_fpop(cpu_env); break; - default: - goto unknown_op; - } - break; - case 0x1c: - switch(rm) { - case 0: /* feni (287 only, just do nop here) */ + case 0x0d: /* grp d9/5 */ + { + switch (rm) { + case 0: + gen_helper_fpush(cpu_env); + gen_helper_fld1_ST0(cpu_env); + break; + case 1: + gen_helper_fpush(cpu_env); + gen_helper_fldl2t_ST0(cpu_env); + break; + case 2: + gen_helper_fpush(cpu_env); + gen_helper_fldl2e_ST0(cpu_env); + break; + case 3: + gen_helper_fpush(cpu_env); + gen_helper_fldpi_ST0(cpu_env); + break; + case 4: + gen_helper_fpush(cpu_env); + gen_helper_fldlg2_ST0(cpu_env); + break; + case 5: + gen_helper_fpush(cpu_env); + gen_helper_fldln2_ST0(cpu_env); + break; + case 6: + gen_helper_fpush(cpu_env); + gen_helper_fldz_ST0(cpu_env); + break; + default: + goto unknown_op; + } + } break; - case 1: /* fdisi (287 only, just do nop here) */ + case 0x0e: /* grp d9/6 */ + switch (rm) { + case 0: /* f2xm1 */ + gen_helper_f2xm1(cpu_env); + break; + case 1: /* fyl2x */ + gen_helper_fyl2x(cpu_env); + break; + case 2: /* fptan */ + gen_helper_fptan(cpu_env); + break; + case 3: /* fpatan */ + gen_helper_fpatan(cpu_env); + break; + case 4: /* fxtract */ + gen_helper_fxtract(cpu_env); + break; + case 5: /* fprem1 */ + gen_helper_fprem1(cpu_env); + break; + case 6: /* fdecstp */ + gen_helper_fdecstp(cpu_env); + break; + default: + case 7: /* fincstp */ + gen_helper_fincstp(cpu_env); + break; + } break; - case 2: /* fclex */ - gen_helper_fclex(cpu_env); + case 0x0f: /* grp d9/7 */ + switch (rm) { + case 0: /* fprem */ + gen_helper_fprem(cpu_env); + break; + case 1: /* fyl2xp1 */ + gen_helper_fyl2xp1(cpu_env); + break; + case 2: /* fsqrt */ + gen_helper_fsqrt(cpu_env); + break; + case 3: /* fsincos */ + gen_helper_fsincos(cpu_env); + break; + case 5: /* fscale */ + gen_helper_fscale(cpu_env); + break; + case 4: /* frndint */ + gen_helper_frndint(cpu_env); + break; + case 6: /* fsin */ + gen_helper_fsin(cpu_env); + break; + default: + case 7: /* fcos */ + gen_helper_fcos(cpu_env); + break; + } break; - case 3: /* fninit */ - gen_helper_fninit(cpu_env); + case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */ + case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */ + case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ + { + int op1; + + op1 = op & 7; + if (op >= 0x20) { + gen_helper_fp_arith_STN_ST0(op1, opreg); + if (op >= 0x30) { + gen_helper_fpop(cpu_env); + } + } else { + gen_helper_fmov_FT0_STN(cpu_env, + tcg_const_i32(opreg)); + gen_helper_fp_arith_ST0_FT0(op1); + } + } break; - case 4: /* fsetpm (287 only, just do nop here) */ + case 0x02: /* fcom */ + case 0x22: /* fcom2, undocumented op */ + gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); + gen_helper_fcom_ST0_FT0(cpu_env); break; - default: - goto unknown_op; - } - break; - case 0x1d: /* fucomi */ - if (!(s->cpuid_features & CPUID_CMOV)) { - goto illegal_op; - } - gen_update_cc_op(s); - gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); - gen_helper_fucomi_ST0_FT0(cpu_env); - set_cc_op(s, CC_OP_EFLAGS); - break; - case 0x1e: /* fcomi */ - if (!(s->cpuid_features & CPUID_CMOV)) { - goto illegal_op; - } - gen_update_cc_op(s); - gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); - gen_helper_fcomi_ST0_FT0(cpu_env); - set_cc_op(s, CC_OP_EFLAGS); - break; - case 0x28: /* ffree sti */ - gen_helper_ffree_STN(cpu_env, tcg_const_i32(opreg)); - break; - case 0x2a: /* fst sti */ - gen_helper_fmov_STN_ST0(cpu_env, tcg_const_i32(opreg)); - break; - case 0x2b: /* fstp sti */ - case 0x0b: /* fstp1 sti, undocumented op */ - case 0x3a: /* fstp8 sti, undocumented op */ - case 0x3b: /* fstp9 sti, undocumented op */ - gen_helper_fmov_STN_ST0(cpu_env, tcg_const_i32(opreg)); - gen_helper_fpop(cpu_env); - break; - case 0x2c: /* fucom st(i) */ - gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); - gen_helper_fucom_ST0_FT0(cpu_env); - break; - case 0x2d: /* fucomp st(i) */ - gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); - gen_helper_fucom_ST0_FT0(cpu_env); - gen_helper_fpop(cpu_env); - break; - case 0x33: /* de/3 */ - switch(rm) { - case 1: /* fcompp */ - gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(1)); + case 0x03: /* fcomp */ + case 0x23: /* fcomp3, undocumented op */ + case 0x32: /* fcomp5, undocumented op */ + gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); gen_helper_fcom_ST0_FT0(cpu_env); gen_helper_fpop(cpu_env); - gen_helper_fpop(cpu_env); break; - default: - goto unknown_op; - } - break; - case 0x38: /* ffreep sti, undocumented op */ - gen_helper_ffree_STN(cpu_env, tcg_const_i32(opreg)); - gen_helper_fpop(cpu_env); - break; - case 0x3c: /* df/4 */ - switch(rm) { - case 0: - gen_helper_fnstsw(s->tmp2_i32, cpu_env); - tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32); - gen_op_mov_reg_v(s, MO_16, R_EAX, s->T0); + case 0x15: /* da/5 */ + switch (rm) { + case 1: /* fucompp */ + gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(1)); + gen_helper_fucom_ST0_FT0(cpu_env); + gen_helper_fpop(cpu_env); + gen_helper_fpop(cpu_env); + break; + default: + goto unknown_op; + } break; - default: - goto unknown_op; - } - break; - case 0x3d: /* fucomip */ - if (!(s->cpuid_features & CPUID_CMOV)) { - goto illegal_op; - } - gen_update_cc_op(s); - gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); - gen_helper_fucomi_ST0_FT0(cpu_env); - gen_helper_fpop(cpu_env); - set_cc_op(s, CC_OP_EFLAGS); - break; - case 0x3e: /* fcomip */ - if (!(s->cpuid_features & CPUID_CMOV)) { - goto illegal_op; - } - gen_update_cc_op(s); - gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); - gen_helper_fcomi_ST0_FT0(cpu_env); - gen_helper_fpop(cpu_env); - set_cc_op(s, CC_OP_EFLAGS); - break; - case 0x10 ... 0x13: /* fcmovxx */ - case 0x18 ... 0x1b: - { - int op1; - TCGLabel *l1; - static const uint8_t fcmov_cc[8] = { - (JCC_B << 1), - (JCC_Z << 1), - (JCC_BE << 1), - (JCC_P << 1), - }; - + case 0x1c: + switch (rm) { + case 0: /* feni (287 only, just do nop here) */ + break; + case 1: /* fdisi (287 only, just do nop here) */ + break; + case 2: /* fclex */ + gen_helper_fclex(cpu_env); + break; + case 3: /* fninit */ + gen_helper_fninit(cpu_env); + break; + case 4: /* fsetpm (287 only, just do nop here) */ + break; + default: + goto unknown_op; + } + break; + case 0x1d: /* fucomi */ if (!(s->cpuid_features & CPUID_CMOV)) { goto illegal_op; } - op1 = fcmov_cc[op & 3] | (((op >> 3) & 1) ^ 1); - l1 = gen_new_label(); - gen_jcc1_noeob(s, op1, l1); - gen_helper_fmov_ST0_STN(cpu_env, tcg_const_i32(opreg)); - gen_set_label(l1); + gen_update_cc_op(s); + gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); + gen_helper_fucomi_ST0_FT0(cpu_env); + set_cc_op(s, CC_OP_EFLAGS); + break; + case 0x1e: /* fcomi */ + if (!(s->cpuid_features & CPUID_CMOV)) { + goto illegal_op; + } + gen_update_cc_op(s); + gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); + gen_helper_fcomi_ST0_FT0(cpu_env); + set_cc_op(s, CC_OP_EFLAGS); + break; + case 0x28: /* ffree sti */ + gen_helper_ffree_STN(cpu_env, tcg_const_i32(opreg)); + break; + case 0x2a: /* fst sti */ + gen_helper_fmov_STN_ST0(cpu_env, tcg_const_i32(opreg)); + break; + case 0x2b: /* fstp sti */ + case 0x0b: /* fstp1 sti, undocumented op */ + case 0x3a: /* fstp8 sti, undocumented op */ + case 0x3b: /* fstp9 sti, undocumented op */ + gen_helper_fmov_STN_ST0(cpu_env, tcg_const_i32(opreg)); + gen_helper_fpop(cpu_env); + break; + case 0x2c: /* fucom st(i) */ + gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); + gen_helper_fucom_ST0_FT0(cpu_env); + break; + case 0x2d: /* fucomp st(i) */ + gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); + gen_helper_fucom_ST0_FT0(cpu_env); + gen_helper_fpop(cpu_env); + break; + case 0x33: /* de/3 */ + switch (rm) { + case 1: /* fcompp */ + gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(1)); + gen_helper_fcom_ST0_FT0(cpu_env); + gen_helper_fpop(cpu_env); + gen_helper_fpop(cpu_env); + break; + default: + goto unknown_op; + } + break; + case 0x38: /* ffreep sti, undocumented op */ + gen_helper_ffree_STN(cpu_env, tcg_const_i32(opreg)); + gen_helper_fpop(cpu_env); + break; + case 0x3c: /* df/4 */ + switch (rm) { + case 0: + gen_helper_fnstsw(s->tmp2_i32, cpu_env); + tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32); + gen_op_mov_reg_v(s, MO_16, R_EAX, s->T0); + break; + default: + goto unknown_op; + } + break; + case 0x3d: /* fucomip */ + if (!(s->cpuid_features & CPUID_CMOV)) { + goto illegal_op; + } + gen_update_cc_op(s); + gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); + gen_helper_fucomi_ST0_FT0(cpu_env); + gen_helper_fpop(cpu_env); + set_cc_op(s, CC_OP_EFLAGS); + break; + case 0x3e: /* fcomip */ + if (!(s->cpuid_features & CPUID_CMOV)) { + goto illegal_op; + } + gen_update_cc_op(s); + gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); + gen_helper_fcomi_ST0_FT0(cpu_env); + gen_helper_fpop(cpu_env); + set_cc_op(s, CC_OP_EFLAGS); + break; + case 0x10 ... 0x13: /* fcmovxx */ + case 0x18 ... 0x1b: + { + int op1; + TCGLabel *l1; + static const uint8_t fcmov_cc[8] = { + (JCC_B << 1), + (JCC_Z << 1), + (JCC_BE << 1), + (JCC_P << 1), + }; + + if (!(s->cpuid_features & CPUID_CMOV)) { + goto illegal_op; + } + op1 = fcmov_cc[op & 3] | (((op >> 3) & 1) ^ 1); + l1 = gen_new_label(); + gen_jcc1_noeob(s, op1, l1); + gen_helper_fmov_ST0_STN(cpu_env, tcg_const_i32(opreg)); + gen_set_label(l1); + } + break; + default: + goto unknown_op; } - break; - default: - goto unknown_op; } } break; From bbdda9b74f289328e9ee7be28bb472350dc84028 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 7 Jul 2021 14:45:19 -0700 Subject: [PATCH 040/531] target/i386: Split out do_fninit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not call helper_fninit directly from helper_xrstor. Do call the new helper from do_fsave. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/i386/tcg/fpu_helper.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index 74bbe94b80..beb63be432 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -727,7 +727,7 @@ void helper_fwait(CPUX86State *env) } } -void helper_fninit(CPUX86State *env) +static void do_fninit(CPUX86State *env) { env->fpus = 0; env->fpstt = 0; @@ -742,6 +742,11 @@ void helper_fninit(CPUX86State *env) env->fptags[7] = 1; } +void helper_fninit(CPUX86State *env) +{ + do_fninit(env); +} + /* BCD ops */ void helper_fbld_ST0(CPUX86State *env, target_ulong ptr) @@ -2451,18 +2456,7 @@ static void do_fsave(CPUX86State *env, target_ulong ptr, int data32, ptr += 10; } - /* fninit */ - env->fpus = 0; - env->fpstt = 0; - cpu_set_fpuc(env, 0x37f); - env->fptags[0] = 1; - env->fptags[1] = 1; - env->fptags[2] = 1; - env->fptags[3] = 1; - env->fptags[4] = 1; - env->fptags[5] = 1; - env->fptags[6] = 1; - env->fptags[7] = 1; + do_fninit(env); } void helper_fsave(CPUX86State *env, target_ulong ptr, int data32) @@ -2834,7 +2828,7 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) if (xstate_bv & XSTATE_FP_MASK) { do_xrstor_fpu(env, ptr, ra); } else { - helper_fninit(env); + do_fninit(env); memset(env->fpregs, 0, sizeof(env->fpregs)); } } From 84abdd7d271c2df69a9d394be093efd885da7a4c Mon Sep 17 00:00:00 2001 From: Ziqiao Kong Date: Sun, 30 May 2021 23:01:14 +0800 Subject: [PATCH 041/531] target/i386: Correct implementation for FCS, FIP, FDS and FDP Update FCS:FIP and FDS:FDP according to the Intel Manual Vol.1 8.1.8. Note that CPUID.(EAX=07H,ECX=0H):EBX[bit 13] is not implemented by design in this patch and will be added along with TCG features flag in a separate patch later. Signed-off-by: Ziqiao Kong Message-Id: <20210530150112.74411-2-ziqiaokong@gmail.com> [rth: Push FDS/FDP handling down into mod != 3 case; free last_addr.] Signed-off-by: Richard Henderson --- target/i386/cpu.h | 2 ++ target/i386/tcg/fpu_helper.c | 20 ++++++++++------- target/i386/tcg/translate.c | 43 +++++++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 8f3747dd28..3dc52deaef 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1437,6 +1437,8 @@ typedef struct CPUX86State { FPReg fpregs[8]; /* KVM-only so far */ uint16_t fpop; + uint16_t fpcs; + uint16_t fpds; uint64_t fpip; uint64_t fpdp; diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index beb63be432..cdd8e9f947 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -731,6 +731,10 @@ static void do_fninit(CPUX86State *env) { env->fpus = 0; env->fpstt = 0; + env->fpcs = 0; + env->fpds = 0; + env->fpip = 0; + env->fpdp = 0; cpu_set_fpuc(env, 0x37f); env->fptags[0] = 1; env->fptags[1] = 1; @@ -2378,19 +2382,19 @@ static void do_fstenv(CPUX86State *env, target_ulong ptr, int data32, cpu_stl_data_ra(env, ptr, env->fpuc, retaddr); cpu_stl_data_ra(env, ptr + 4, fpus, retaddr); cpu_stl_data_ra(env, ptr + 8, fptag, retaddr); - cpu_stl_data_ra(env, ptr + 12, 0, retaddr); /* fpip */ - cpu_stl_data_ra(env, ptr + 16, 0, retaddr); /* fpcs */ - cpu_stl_data_ra(env, ptr + 20, 0, retaddr); /* fpoo */ - cpu_stl_data_ra(env, ptr + 24, 0, retaddr); /* fpos */ + cpu_stl_data_ra(env, ptr + 12, env->fpip, retaddr); /* fpip */ + cpu_stl_data_ra(env, ptr + 16, env->fpcs, retaddr); /* fpcs */ + cpu_stl_data_ra(env, ptr + 20, env->fpdp, retaddr); /* fpoo */ + cpu_stl_data_ra(env, ptr + 24, env->fpds, retaddr); /* fpos */ } else { /* 16 bit */ cpu_stw_data_ra(env, ptr, env->fpuc, retaddr); cpu_stw_data_ra(env, ptr + 2, fpus, retaddr); cpu_stw_data_ra(env, ptr + 4, fptag, retaddr); - cpu_stw_data_ra(env, ptr + 6, 0, retaddr); - cpu_stw_data_ra(env, ptr + 8, 0, retaddr); - cpu_stw_data_ra(env, ptr + 10, 0, retaddr); - cpu_stw_data_ra(env, ptr + 12, 0, retaddr); + cpu_stw_data_ra(env, ptr + 6, env->fpip, retaddr); + cpu_stw_data_ra(env, ptr + 8, env->fpcs, retaddr); + cpu_stw_data_ra(env, ptr + 10, env->fpdp, retaddr); + cpu_stw_data_ra(env, ptr + 12, env->fpds, retaddr); } } diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index a43e577019..8520d5a1e2 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -5920,6 +5920,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) /* floats */ case 0xd8 ... 0xdf: { + bool update_fip = true; + if (s->flags & (HF_EM_MASK | HF_TS_MASK)) { /* if CR0.EM or CR0.TS are set, generate an FPU exception */ /* XXX: what to do if illegal op ? */ @@ -5932,7 +5934,14 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) op = ((b & 7) << 3) | ((modrm >> 3) & 7); if (mod != 3) { /* memory op */ - gen_lea_modrm(env, s, modrm); + AddressParts a = gen_lea_modrm_0(env, s, modrm); + TCGv ea = gen_lea_modrm_1(s, a); + TCGv last_addr = tcg_temp_new(); + bool update_fdp = true; + + tcg_gen_mov_tl(last_addr, ea); + gen_lea_v_seg(s, s->aflag, ea, a.def_seg, s->override); + switch (op) { case 0x00 ... 0x07: /* fxxxs */ case 0x10 ... 0x17: /* fixxxl */ @@ -6060,20 +6069,24 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x0c: /* fldenv mem */ gen_helper_fldenv(cpu_env, s->A0, tcg_const_i32(dflag - 1)); + update_fip = update_fdp = false; break; case 0x0d: /* fldcw mem */ tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUW); gen_helper_fldcw(cpu_env, s->tmp2_i32); + update_fip = update_fdp = false; break; case 0x0e: /* fnstenv mem */ gen_helper_fstenv(cpu_env, s->A0, tcg_const_i32(dflag - 1)); + update_fip = update_fdp = false; break; case 0x0f: /* fnstcw mem */ gen_helper_fnstcw(s->tmp2_i32, cpu_env); tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUW); + update_fip = update_fdp = false; break; case 0x1d: /* fldt mem */ gen_helper_fldt_ST0(cpu_env, s->A0); @@ -6085,15 +6098,18 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x2c: /* frstor mem */ gen_helper_frstor(cpu_env, s->A0, tcg_const_i32(dflag - 1)); + update_fip = update_fdp = false; break; case 0x2e: /* fnsave mem */ gen_helper_fsave(cpu_env, s->A0, tcg_const_i32(dflag - 1)); + update_fip = update_fdp = false; break; case 0x2f: /* fnstsw mem */ gen_helper_fnstsw(s->tmp2_i32, cpu_env); tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUW); + update_fip = update_fdp = false; break; case 0x3c: /* fbld */ gen_helper_fbld_ST0(cpu_env, s->A0); @@ -6116,6 +6132,19 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) default: goto unknown_op; } + + if (update_fdp) { + int last_seg = s->override >= 0 ? s->override : a.def_seg; + + tcg_gen_ld_i32(s->tmp2_i32, cpu_env, + offsetof(CPUX86State, + segs[last_seg].selector)); + tcg_gen_st16_i32(s->tmp2_i32, cpu_env, + offsetof(CPUX86State, fpds)); + tcg_gen_st_tl(last_addr, cpu_env, + offsetof(CPUX86State, fpdp)); + } + tcg_temp_free(last_addr); } else { /* register float ops */ opreg = rm; @@ -6136,6 +6165,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0: /* fnop */ /* check exceptions (FreeBSD FPU probe) */ gen_helper_fwait(cpu_env); + update_fip = false; break; default: goto unknown_op; @@ -6305,9 +6335,11 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 2: /* fclex */ gen_helper_fclex(cpu_env); + update_fip = false; break; case 3: /* fninit */ gen_helper_fninit(cpu_env); + update_fip = false; break; case 4: /* fsetpm (287 only, just do nop here) */ break; @@ -6428,6 +6460,15 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) goto unknown_op; } } + + if (update_fip) { + tcg_gen_ld_i32(s->tmp2_i32, cpu_env, + offsetof(CPUX86State, segs[R_CS].selector)); + tcg_gen_st16_i32(s->tmp2_i32, cpu_env, + offsetof(CPUX86State, fpcs)); + tcg_gen_st_tl(tcg_constant_tl(pc_start - s->cs_base), + cpu_env, offsetof(CPUX86State, fpip)); + } } break; /************************/ From 492f85b92adf4e6fbe15b9cd4a36d5e0c3f2c44a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 7 Jul 2021 18:22:19 -0700 Subject: [PATCH 042/531] target/alpha: Store set into rx flag A paste-o meant that we wrote back the existing value of the RX flag rather than changing it to TMP. Use tcg_constant_i64 while we're at it. Signed-off-by: Richard Henderson --- target/alpha/translate.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 833d3baa7b..b439b57a66 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -1084,15 +1084,11 @@ static void gen_msk_l(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit, static void gen_rx(DisasContext *ctx, int ra, int set) { - TCGv tmp; - if (ra != 31) { ld_flag_byte(ctx->ir[ra], ENV_FLAG_RX_SHIFT); } - tmp = tcg_const_i64(set); - st_flag_byte(ctx->ir[ra], ENV_FLAG_RX_SHIFT); - tcg_temp_free(tmp); + st_flag_byte(tcg_constant_i64(set), ENV_FLAG_RX_SHIFT); } static DisasJumpType gen_call_pal(DisasContext *ctx, int palcode) From 3e646c3a3cfb1ce9522c230c2cbbafaf42f0a9c5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 7 Jul 2021 18:46:32 -0700 Subject: [PATCH 043/531] target/alpha: Use dest_sink for HW_RET temporary This temp is automatically freed, just like ctx->lit. But we're about to remove ctx->lit, so use sink instead. Signed-off-by: Richard Henderson --- target/alpha/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/alpha/translate.c b/target/alpha/translate.c index b439b57a66..64c4865dda 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -2717,7 +2717,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) /* Pre-EV6 CPUs interpreted this as HW_REI, loading the return address from EXC_ADDR. This turns out to be useful for our emulation PALcode, so continue to accept it. */ - ctx->lit = vb = tcg_temp_new(); + vb = dest_sink(ctx); tcg_gen_ld_i64(vb, cpu_env, offsetof(CPUAlphaState, exc_addr)); } else { vb = load_gpr(ctx, rb); From 212c88c0c78b1b2027b91d0669b92c49d921e91c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 7 Jul 2021 18:50:46 -0700 Subject: [PATCH 044/531] target/alpha: Use tcg_constant_i64 for zero and lit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These constant temps do not need to be freed, and therefore need less bookkeeping from tcg producers. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/alpha/translate.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 64c4865dda..58c0e08c0c 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -66,8 +66,6 @@ struct DisasContext { /* Temporaries for $31 and $f31 as source and destination. */ TCGv zero; TCGv sink; - /* Temporary for immediate constants. */ - TCGv lit; }; /* Target-specific return values from translate_one, indicating the @@ -157,7 +155,7 @@ void alpha_translate_init(void) static TCGv load_zero(DisasContext *ctx) { if (!ctx->zero) { - ctx->zero = tcg_const_i64(0); + ctx->zero = tcg_constant_i64(0); } return ctx->zero; } @@ -177,14 +175,6 @@ static void free_context_temps(DisasContext *ctx) tcg_temp_free(ctx->sink); ctx->sink = NULL; } - if (ctx->zero) { - tcg_temp_free(ctx->zero); - ctx->zero = NULL; - } - if (ctx->lit) { - tcg_temp_free(ctx->lit); - ctx->lit = NULL; - } } static TCGv load_gpr(DisasContext *ctx, unsigned reg) @@ -200,8 +190,7 @@ static TCGv load_gpr_lit(DisasContext *ctx, unsigned reg, uint8_t lit, bool islit) { if (islit) { - ctx->lit = tcg_const_i64(lit); - return ctx->lit; + return tcg_constant_i64(lit); } else if (likely(reg < 31)) { return ctx->ir[reg]; } else { @@ -2992,7 +2981,6 @@ static void alpha_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) ctx->zero = NULL; ctx->sink = NULL; - ctx->lit = NULL; /* Bound the number of insns to execute to those left on the page. */ bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; From 904bd855d38f8deb3f85a63d19475bb4a0c0d1a4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 7 Jul 2021 18:54:44 -0700 Subject: [PATCH 045/531] target/alpha: Use tcg_constant_* elsewhere MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the remaining uses of tcg_const_*. These uses are all local, with the allocate and free close together. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/alpha/translate.c | 46 ++++++++++++---------------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 58c0e08c0c..103c6326a2 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -250,11 +250,9 @@ static void gen_excp_1(int exception, int error_code) { TCGv_i32 tmp1, tmp2; - tmp1 = tcg_const_i32(exception); - tmp2 = tcg_const_i32(error_code); + tmp1 = tcg_constant_i32(exception); + tmp2 = tcg_constant_i32(error_code); gen_helper_excp(cpu_env, tmp1, tmp2); - tcg_temp_free_i32(tmp2); - tcg_temp_free_i32(tmp1); } static DisasJumpType gen_excp(DisasContext *ctx, int exception, int error_code) @@ -474,15 +472,11 @@ static DisasJumpType gen_bcond_internal(DisasContext *ctx, TCGCond cond, return DISAS_NORETURN; } else { - TCGv_i64 z = tcg_const_i64(0); - TCGv_i64 d = tcg_const_i64(dest); - TCGv_i64 p = tcg_const_i64(ctx->base.pc_next); + TCGv_i64 z = load_zero(ctx); + TCGv_i64 d = tcg_constant_i64(dest); + TCGv_i64 p = tcg_constant_i64(ctx->base.pc_next); tcg_gen_movcond_i64(cond, cpu_pc, cmp, z, d, p); - - tcg_temp_free_i64(z); - tcg_temp_free_i64(d); - tcg_temp_free_i64(p); return DISAS_PC_UPDATED; } } @@ -684,22 +678,19 @@ static void gen_fp_exc_raise(int rc, int fn11) if (!(fn11 & QUAL_I)) { ignore |= FPCR_INE; } - ign = tcg_const_i32(ignore); + ign = tcg_constant_i32(ignore); /* ??? Pass in the regno of the destination so that the helper can set EXC_MASK, which contains a bitmask of destination registers that have caused arithmetic traps. A simple userspace emulation does not require this. We do need it for a guest kernel's entArith, or if we were to do something clever with imprecise exceptions. */ - reg = tcg_const_i32(rc + 32); + reg = tcg_constant_i32(rc + 32); if (fn11 & QUAL_S) { gen_helper_fp_exc_raise_s(cpu_env, ign, reg); } else { gen_helper_fp_exc_raise(cpu_env, ign, reg); } - - tcg_temp_free_i32(reg); - tcg_temp_free_i32(ign); } static void gen_cvtlq(TCGv vc, TCGv vb) @@ -792,7 +783,7 @@ IEEE_INTCVT(cvtqt) static void gen_cpy_mask(TCGv vc, TCGv va, TCGv vb, bool inv_a, uint64_t mask) { - TCGv vmask = tcg_const_i64(mask); + TCGv vmask = tcg_constant_i64(mask); TCGv tmp = tcg_temp_new_i64(); if (inv_a) { @@ -804,7 +795,6 @@ static void gen_cpy_mask(TCGv vc, TCGv va, TCGv vb, bool inv_a, uint64_t mask) tcg_gen_andc_i64(vc, vb, vmask); tcg_gen_or_i64(vc, vc, tmp); - tcg_temp_free(vmask); tcg_temp_free(tmp); } @@ -1178,12 +1168,9 @@ static DisasJumpType gen_call_pal(DisasContext *ctx, int palcode) case 0x3E: /* WTINT */ - { - TCGv_i32 tmp = tcg_const_i32(1); - tcg_gen_st_i32(tmp, cpu_env, -offsetof(AlphaCPU, env) + - offsetof(CPUState, halted)); - tcg_temp_free_i32(tmp); - } + tcg_gen_st_i32(tcg_constant_i32(1), cpu_env, + -offsetof(AlphaCPU, env) + + offsetof(CPUState, halted)); tcg_gen_movi_i64(ctx->ir[IR_V0], 0); return gen_excp(ctx, EXCP_HALTED, 0); @@ -1334,12 +1321,8 @@ static DisasJumpType gen_mtpr(DisasContext *ctx, TCGv vb, int regno) case 253: /* WAIT */ - { - TCGv_i32 tmp = tcg_const_i32(1); - tcg_gen_st_i32(tmp, cpu_env, -offsetof(AlphaCPU, env) + - offsetof(CPUState, halted)); - tcg_temp_free_i32(tmp); - } + tcg_gen_st_i32(tcg_constant_i32(1), cpu_env, + -offsetof(AlphaCPU, env) + offsetof(CPUState, halted)); return gen_excp(ctx, EXCP_HALTED, 0); case 252: @@ -2712,9 +2695,8 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) vb = load_gpr(ctx, rb); } tcg_gen_movi_i64(cpu_lock_addr, -1); + st_flag_byte(load_zero(ctx), ENV_FLAG_RX_SHIFT); tmp = tcg_temp_new(); - tcg_gen_movi_i64(tmp, 0); - st_flag_byte(tmp, ENV_FLAG_RX_SHIFT); tcg_gen_andi_i64(tmp, vb, 1); st_flag_byte(tmp, ENV_FLAG_PAL_SHIFT); tcg_temp_free(tmp); From af42d3540179d48ee31bd421d00100c26bfb63e3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 8 Jul 2021 14:05:03 -0700 Subject: [PATCH 046/531] target/openrisc: Use tcg_constant_* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace uses of tcg_const_* allocate and free close together with tcg_constant_*. Reviewed-by: Stafford Horne Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 42 ++++++++----------------------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 37c3e3e0a3..1e3b019c59 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -129,9 +129,7 @@ void openrisc_translate_init(void) static void gen_exception(DisasContext *dc, unsigned int excp) { - TCGv_i32 tmp = tcg_const_i32(excp); - gen_helper_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); + gen_helper_exception(cpu_env, tcg_constant_i32(excp)); } static void gen_illegal_exception(DisasContext *dc) @@ -538,13 +536,11 @@ static bool trans_l_extbz(DisasContext *dc, arg_da *a) static bool trans_l_cmov(DisasContext *dc, arg_dab *a) { - TCGv zero; + TCGv zero = tcg_constant_tl(0); check_r0_write(dc, a->d); - zero = tcg_const_tl(0); tcg_gen_movcond_tl(TCG_COND_NE, cpu_R(dc, a->d), cpu_sr_f, zero, cpu_R(dc, a->a), cpu_R(dc, a->b)); - tcg_temp_free(zero); return true; } @@ -632,15 +628,11 @@ static bool trans_l_jal(DisasContext *dc, arg_l_jal *a) static void do_bf(DisasContext *dc, arg_l_bf *a, TCGCond cond) { target_ulong tmp_pc = dc->base.pc_next + a->n * 4; - TCGv t_next = tcg_const_tl(dc->base.pc_next + 8); - TCGv t_true = tcg_const_tl(tmp_pc); - TCGv t_zero = tcg_const_tl(0); + TCGv t_next = tcg_constant_tl(dc->base.pc_next + 8); + TCGv t_true = tcg_constant_tl(tmp_pc); + TCGv t_zero = tcg_constant_tl(0); tcg_gen_movcond_tl(cond, jmp_pc, cpu_sr_f, t_zero, t_true, t_next); - - tcg_temp_free(t_next); - tcg_temp_free(t_true); - tcg_temp_free(t_zero); dc->delayed_branch = 2; } @@ -813,44 +805,28 @@ static bool trans_l_adrp(DisasContext *dc, arg_l_adrp *a) static bool trans_l_addi(DisasContext *dc, arg_rri *a) { - TCGv t0; - check_r0_write(dc, a->d); - t0 = tcg_const_tl(a->i); - gen_add(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), t0); - tcg_temp_free(t0); + gen_add(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), tcg_constant_tl(a->i)); return true; } static bool trans_l_addic(DisasContext *dc, arg_rri *a) { - TCGv t0; - check_r0_write(dc, a->d); - t0 = tcg_const_tl(a->i); - gen_addc(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), t0); - tcg_temp_free(t0); + gen_addc(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), tcg_constant_tl(a->i)); return true; } static bool trans_l_muli(DisasContext *dc, arg_rri *a) { - TCGv t0; - check_r0_write(dc, a->d); - t0 = tcg_const_tl(a->i); - gen_mul(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), t0); - tcg_temp_free(t0); + gen_mul(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), tcg_constant_tl(a->i)); return true; } static bool trans_l_maci(DisasContext *dc, arg_l_maci *a) { - TCGv t0; - - t0 = tcg_const_tl(a->i); - gen_mac(dc, cpu_R(dc, a->a), t0); - tcg_temp_free(t0); + gen_mac(dc, cpu_R(dc, a->a), tcg_constant_tl(a->i)); return true; } From 4d10fa0ff901b055ca75f6986974609bc99820dd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 8 Jul 2021 14:12:09 -0700 Subject: [PATCH 047/531] target/openrisc: Use tcg_constant_tl for dc->R0 The temp allocated for tcg_const_tl is auto-freed at branches, but pure constants are not. So we can remove the extra hoop jumping in trans_l_swa. Reviewed-by: Stafford Horne Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 1e3b019c59..2db529b7de 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -732,12 +732,6 @@ static bool trans_l_swa(DisasContext *dc, arg_store *a) ea = tcg_temp_new(); tcg_gen_addi_tl(ea, cpu_R(dc, a->a), a->i); - /* For TB_FLAGS_R0_0, the branch below invalidates the temporary assigned - to cpu_regs[0]. Since l.swa is quite often immediately followed by a - branch, don't bother reallocating; finish the TB using the "real" R0. - This also takes care of RB input across the branch. */ - dc->R0 = cpu_regs[0]; - lab_fail = gen_new_label(); lab_done = gen_new_label(); tcg_gen_brcond_tl(TCG_COND_NE, ea, cpu_lock_addr, lab_fail); @@ -745,7 +739,7 @@ static bool trans_l_swa(DisasContext *dc, arg_store *a) val = tcg_temp_new(); tcg_gen_atomic_cmpxchg_tl(val, cpu_lock_addr, cpu_lock_value, - cpu_regs[a->b], dc->mem_idx, MO_TEUL); + cpu_R(dc, a->b), dc->mem_idx, MO_TEUL); tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, val, cpu_lock_value); tcg_temp_free(val); @@ -1601,7 +1595,7 @@ static void openrisc_tr_tb_start(DisasContextBase *db, CPUState *cs) /* Allow the TCG optimizer to see that R0 == 0, when it's true, which is the common case. */ if (dc->tb_flags & TB_FLAGS_R0_0) { - dc->R0 = tcg_const_tl(0); + dc->R0 = tcg_constant_tl(0); } else { dc->R0 = cpu_regs[0]; } From 118671f02faf4d67f283731eafc96bb72b125431 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 8 Jul 2021 14:15:56 -0700 Subject: [PATCH 048/531] target/openrisc: Cache constant 0 in DisasContext MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are virtually certain to have fetched constant 0 once, at the beginning of the TB, so we might as well use it elsewhere. Reviewed-by: Stafford Horne Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 2db529b7de..6aba4c2ffc 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -52,6 +52,8 @@ typedef struct DisasContext { /* The temporary corresponding to register 0 for this compilation. */ TCGv R0; + /* The constant zero. */ + TCGv zero; } DisasContext; static inline bool is_user(DisasContext *dc) @@ -536,10 +538,8 @@ static bool trans_l_extbz(DisasContext *dc, arg_da *a) static bool trans_l_cmov(DisasContext *dc, arg_dab *a) { - TCGv zero = tcg_constant_tl(0); - check_r0_write(dc, a->d); - tcg_gen_movcond_tl(TCG_COND_NE, cpu_R(dc, a->d), cpu_sr_f, zero, + tcg_gen_movcond_tl(TCG_COND_NE, cpu_R(dc, a->d), cpu_sr_f, dc->zero, cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } @@ -630,9 +630,8 @@ static void do_bf(DisasContext *dc, arg_l_bf *a, TCGCond cond) target_ulong tmp_pc = dc->base.pc_next + a->n * 4; TCGv t_next = tcg_constant_tl(dc->base.pc_next + 8); TCGv t_true = tcg_constant_tl(tmp_pc); - TCGv t_zero = tcg_constant_tl(0); - tcg_gen_movcond_tl(cond, jmp_pc, cpu_sr_f, t_zero, t_true, t_next); + tcg_gen_movcond_tl(cond, jmp_pc, cpu_sr_f, dc->zero, t_true, t_next); dc->delayed_branch = 2; } @@ -1594,8 +1593,9 @@ static void openrisc_tr_tb_start(DisasContextBase *db, CPUState *cs) /* Allow the TCG optimizer to see that R0 == 0, when it's true, which is the common case. */ + dc->zero = tcg_constant_tl(0); if (dc->tb_flags & TB_FLAGS_R0_0) { - dc->R0 = tcg_constant_tl(0); + dc->R0 = dc->zero; } else { dc->R0 = cpu_regs[0]; } From e0efc48fbc6ed9f308fbbff394c5c1044067909f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 8 Jul 2021 14:34:29 -0700 Subject: [PATCH 049/531] target/openrisc: Use dc->zero in gen_add, gen_addc We still need the t0 temporary for computing overflow, but we do not need to initialize it to zero first. Reviewed-by: Stafford Horne Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 6aba4c2ffc..059da48475 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -199,10 +199,10 @@ static void gen_ove_cyov(DisasContext *dc) static void gen_add(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) { - TCGv t0 = tcg_const_tl(0); + TCGv t0 = tcg_temp_new(); TCGv res = tcg_temp_new(); - tcg_gen_add2_tl(res, cpu_sr_cy, srca, t0, srcb, t0); + tcg_gen_add2_tl(res, cpu_sr_cy, srca, dc->zero, srcb, dc->zero); tcg_gen_xor_tl(cpu_sr_ov, srca, srcb); tcg_gen_xor_tl(t0, res, srcb); tcg_gen_andc_tl(cpu_sr_ov, t0, cpu_sr_ov); @@ -216,11 +216,11 @@ static void gen_add(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) static void gen_addc(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) { - TCGv t0 = tcg_const_tl(0); + TCGv t0 = tcg_temp_new(); TCGv res = tcg_temp_new(); - tcg_gen_add2_tl(res, cpu_sr_cy, srca, t0, cpu_sr_cy, t0); - tcg_gen_add2_tl(res, cpu_sr_cy, res, cpu_sr_cy, srcb, t0); + tcg_gen_add2_tl(res, cpu_sr_cy, srca, dc->zero, cpu_sr_cy, dc->zero); + tcg_gen_add2_tl(res, cpu_sr_cy, res, cpu_sr_cy, srcb, dc->zero); tcg_gen_xor_tl(cpu_sr_ov, srca, srcb); tcg_gen_xor_tl(t0, res, srcb); tcg_gen_andc_tl(cpu_sr_ov, t0, cpu_sr_ov); From 29dd6f644a7b8a5a9a8bc249a25d50bc0e266da9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 8 Jul 2021 12:41:29 -0700 Subject: [PATCH 050/531] target/hppa: Use tcg_constant_* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace uses of tcg_const_* with the allocate and free close together. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/hppa/translate.c | 56 +++++++++++++---------------------------- 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 835120c038..fa668072d0 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -144,6 +144,7 @@ #define tcg_gen_sextract_reg tcg_gen_sextract_i64 #define tcg_const_reg tcg_const_i64 #define tcg_const_local_reg tcg_const_local_i64 +#define tcg_constant_reg tcg_constant_i64 #define tcg_gen_movcond_reg tcg_gen_movcond_i64 #define tcg_gen_add2_reg tcg_gen_add2_i64 #define tcg_gen_sub2_reg tcg_gen_sub2_i64 @@ -238,6 +239,7 @@ #define tcg_gen_sextract_reg tcg_gen_sextract_i32 #define tcg_const_reg tcg_const_i32 #define tcg_const_local_reg tcg_const_local_i32 +#define tcg_constant_reg tcg_constant_i32 #define tcg_gen_movcond_reg tcg_gen_movcond_i32 #define tcg_gen_add2_reg tcg_gen_add2_i32 #define tcg_gen_sub2_reg tcg_gen_sub2_i32 @@ -771,9 +773,7 @@ static inline target_ureg iaoq_dest(DisasContext *ctx, target_sreg disp) static void gen_excp_1(int exception) { - TCGv_i32 t = tcg_const_i32(exception); - gen_helper_excp(cpu_env, t); - tcg_temp_free_i32(t); + gen_helper_excp(cpu_env, tcg_constant_i32(exception)); } static void gen_excp(DisasContext *ctx, int exception) @@ -787,12 +787,9 @@ static void gen_excp(DisasContext *ctx, int exception) static bool gen_excp_iir(DisasContext *ctx, int exc) { - TCGv_reg tmp; - nullify_over(ctx); - tmp = tcg_const_reg(ctx->insn); - tcg_gen_st_reg(tmp, cpu_env, offsetof(CPUHPPAState, cr[CR_IIR])); - tcg_temp_free(tmp); + tcg_gen_st_reg(tcg_constant_reg(ctx->insn), + cpu_env, offsetof(CPUHPPAState, cr[CR_IIR])); gen_excp(ctx, exc); return nullify_end(ctx); } @@ -1150,13 +1147,12 @@ static void do_add(DisasContext *ctx, unsigned rt, TCGv_reg in1, } if (!is_l || cond_need_cb(c)) { - TCGv_reg zero = tcg_const_reg(0); + TCGv_reg zero = tcg_constant_reg(0); cb_msb = get_temp(ctx); tcg_gen_add2_reg(dest, cb_msb, in1, zero, in2, zero); if (is_c) { tcg_gen_add2_reg(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero); } - tcg_temp_free(zero); if (!is_l) { cb = get_temp(ctx); tcg_gen_xor_reg(cb, in1, in2); @@ -1242,7 +1238,7 @@ static void do_sub(DisasContext *ctx, unsigned rt, TCGv_reg in1, cb = tcg_temp_new(); cb_msb = tcg_temp_new(); - zero = tcg_const_reg(0); + zero = tcg_constant_reg(0); if (is_b) { /* DEST,C = IN1 + ~IN2 + C. */ tcg_gen_not_reg(cb, in2); @@ -1258,7 +1254,6 @@ static void do_sub(DisasContext *ctx, unsigned rt, TCGv_reg in1, tcg_gen_eqv_reg(cb, in1, in2); tcg_gen_xor_reg(cb, cb, dest); } - tcg_temp_free(zero); /* Compute signed overflow if required. */ sv = NULL; @@ -2449,17 +2444,16 @@ static bool trans_probe(DisasContext *ctx, arg_probe *a) form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); if (a->imm) { - level = tcg_const_i32(a->ri); + level = tcg_constant_i32(a->ri); } else { level = tcg_temp_new_i32(); tcg_gen_trunc_reg_i32(level, load_gpr(ctx, a->ri)); tcg_gen_andi_i32(level, level, 3); } - want = tcg_const_i32(a->write ? PAGE_WRITE : PAGE_READ); + want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ); gen_helper_probe(dest, cpu_env, addr, level, want); - tcg_temp_free_i32(want); tcg_temp_free_i32(level); save_gpr(ctx, a->t, dest); @@ -2599,17 +2593,13 @@ static bool trans_lpa(DisasContext *ctx, arg_ldst *a) static bool trans_lci(DisasContext *ctx, arg_lci *a) { - TCGv_reg ci; - CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); /* The Coherence Index is an implementation-defined function of the physical address. Two addresses with the same CI have a coherent view of the cache. Our implementation is to return 0 for all, since the entire address space is coherent. */ - ci = tcg_const_reg(0); - save_gpr(ctx, a->t, ci); - tcg_temp_free(ci); + save_gpr(ctx, a->t, tcg_constant_reg(0)); cond_free(&ctx->null_cond); return true; @@ -2710,8 +2700,6 @@ static bool trans_or(DisasContext *ctx, arg_rrr_cf *a) * currently implemented as idle. */ if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */ - TCGv_i32 tmp; - /* No need to check for supervisor, as userland can only pause until the next timer interrupt. */ nullify_over(ctx); @@ -2722,10 +2710,8 @@ static bool trans_or(DisasContext *ctx, arg_rrr_cf *a) nullify_set(ctx, 0); /* Tell the qemu main loop to halt until this cpu has work. */ - tmp = tcg_const_i32(1); - tcg_gen_st_i32(tmp, cpu_env, -offsetof(HPPACPU, env) + - offsetof(CPUState, halted)); - tcg_temp_free_i32(tmp); + tcg_gen_st_i32(tcg_constant_i32(1), cpu_env, + offsetof(CPUState, halted) - offsetof(HPPACPU, env)); gen_excp_1(EXCP_HALTED); ctx->base.is_jmp = DISAS_NORETURN; @@ -2833,7 +2819,7 @@ static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) add2 = tcg_temp_new(); addc = tcg_temp_new(); dest = tcg_temp_new(); - zero = tcg_const_reg(0); + zero = tcg_constant_reg(0); /* Form R1 << 1 | PSW[CB]{8}. */ tcg_gen_add_reg(add1, in1, in1); @@ -2851,7 +2837,6 @@ static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero); tcg_temp_free(addc); - tcg_temp_free(zero); /* Write back the result register. */ save_gpr(ctx, a->t, dest); @@ -2967,9 +2952,8 @@ static bool trans_ldc(DisasContext *ctx, arg_ldst *a) */ gen_helper_ldc_check(addr); - zero = tcg_const_reg(0); + zero = tcg_constant_reg(0); tcg_gen_atomic_xchg_reg(dest, addr, zero, ctx->mmu_idx, mop); - tcg_temp_free(zero); if (a->m) { save_gpr(ctx, a->b, ofs); @@ -3882,15 +3866,13 @@ static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a) ta = load_frw0_i32(a->r1); tb = load_frw0_i32(a->r2); - ty = tcg_const_i32(a->y); - tc = tcg_const_i32(a->c); + ty = tcg_constant_i32(a->y); + tc = tcg_constant_i32(a->c); gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc); tcg_temp_free_i32(ta); tcg_temp_free_i32(tb); - tcg_temp_free_i32(ty); - tcg_temp_free_i32(tc); return nullify_end(ctx); } @@ -3904,15 +3886,13 @@ static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a) ta = load_frd0(a->r1); tb = load_frd0(a->r2); - ty = tcg_const_i32(a->y); - tc = tcg_const_i32(a->c); + ty = tcg_constant_i32(a->y); + tc = tcg_constant_i32(a->c); gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc); tcg_temp_free_i64(ta); tcg_temp_free_i64(tb); - tcg_temp_free_i32(ty); - tcg_temp_free_i32(tc); return nullify_end(ctx); } From 6e94937a54c6ef80c3f523d8560c8b6521e6c79c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 8 Jul 2021 13:54:36 -0700 Subject: [PATCH 051/531] target/hppa: Clean up DisasCond The a0_is_n flag is redundant with comparing a0 to cpu_psw_n. The a1_is_0 flag can be removed by initializing a1 to $0, which also means that cond_prep can be removed entirely. Signed-off-by: Richard Henderson --- target/hppa/translate.c | 43 +++++++++-------------------------------- 1 file changed, 9 insertions(+), 34 deletions(-) diff --git a/target/hppa/translate.c b/target/hppa/translate.c index fa668072d0..2552747138 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -252,8 +252,6 @@ typedef struct DisasCond { TCGCond c; TCGv_reg a0, a1; - bool a0_is_n; - bool a1_is_0; } DisasCond; typedef struct DisasContext { @@ -448,9 +446,7 @@ static DisasCond cond_make_n(void) return (DisasCond){ .c = TCG_COND_NE, .a0 = cpu_psw_n, - .a0_is_n = true, - .a1 = NULL, - .a1_is_0 = true + .a1 = tcg_constant_reg(0) }; } @@ -458,7 +454,7 @@ static DisasCond cond_make_0_tmp(TCGCond c, TCGv_reg a0) { assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); return (DisasCond){ - .c = c, .a0 = a0, .a1_is_0 = true + .c = c, .a0 = a0, .a1 = tcg_constant_reg(0) }; } @@ -482,26 +478,14 @@ static DisasCond cond_make(TCGCond c, TCGv_reg a0, TCGv_reg a1) return r; } -static void cond_prep(DisasCond *cond) -{ - if (cond->a1_is_0) { - cond->a1_is_0 = false; - cond->a1 = tcg_const_reg(0); - } -} - static void cond_free(DisasCond *cond) { switch (cond->c) { default: - if (!cond->a0_is_n) { + if (cond->a0 != cpu_psw_n) { tcg_temp_free(cond->a0); } - if (!cond->a1_is_0) { - tcg_temp_free(cond->a1); - } - cond->a0_is_n = false; - cond->a1_is_0 = false; + tcg_temp_free(cond->a1); cond->a0 = NULL; cond->a1 = NULL; /* fallthru */ @@ -559,9 +543,8 @@ static TCGv_reg dest_gpr(DisasContext *ctx, unsigned reg) static void save_or_nullify(DisasContext *ctx, TCGv_reg dest, TCGv_reg t) { if (ctx->null_cond.c != TCG_COND_NEVER) { - cond_prep(&ctx->null_cond); tcg_gen_movcond_reg(ctx->null_cond.c, dest, ctx->null_cond.a0, - ctx->null_cond.a1, dest, t); + ctx->null_cond.a1, dest, t); } else { tcg_gen_mov_reg(dest, t); } @@ -668,11 +651,9 @@ static void nullify_over(DisasContext *ctx) assert(ctx->null_cond.c != TCG_COND_ALWAYS); ctx->null_lab = gen_new_label(); - cond_prep(&ctx->null_cond); /* If we're using PSW[N], copy it to a temp because... */ - if (ctx->null_cond.a0_is_n) { - ctx->null_cond.a0_is_n = false; + if (ctx->null_cond.a0 == cpu_psw_n) { ctx->null_cond.a0 = tcg_temp_new(); tcg_gen_mov_reg(ctx->null_cond.a0, cpu_psw_n); } @@ -685,7 +666,7 @@ static void nullify_over(DisasContext *ctx) } tcg_gen_brcond_reg(ctx->null_cond.c, ctx->null_cond.a0, - ctx->null_cond.a1, ctx->null_lab); + ctx->null_cond.a1, ctx->null_lab); cond_free(&ctx->null_cond); } } @@ -699,10 +680,9 @@ static void nullify_save(DisasContext *ctx) } return; } - if (!ctx->null_cond.a0_is_n) { - cond_prep(&ctx->null_cond); + if (ctx->null_cond.a0 != cpu_psw_n) { tcg_gen_setcond_reg(ctx->null_cond.c, cpu_psw_n, - ctx->null_cond.a0, ctx->null_cond.a1); + ctx->null_cond.a0, ctx->null_cond.a1); ctx->psw_n_nonzero = true; } cond_free(&ctx->null_cond); @@ -1178,7 +1158,6 @@ static void do_add(DisasContext *ctx, unsigned rt, TCGv_reg in1, /* Emit any conditional trap before any writeback. */ cond = do_cond(cf, dest, cb_msb, sv); if (is_tc) { - cond_prep(&cond); tmp = tcg_temp_new(); tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1); gen_helper_tcond(cpu_env, tmp); @@ -1273,7 +1252,6 @@ static void do_sub(DisasContext *ctx, unsigned rt, TCGv_reg in1, /* Emit any conditional trap before any writeback. */ if (is_tc) { - cond_prep(&cond); tmp = tcg_temp_new(); tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1); gen_helper_tcond(cpu_env, tmp); @@ -1399,7 +1377,6 @@ static void do_unit(DisasContext *ctx, unsigned rt, TCGv_reg in1, if (is_tc) { TCGv_reg tmp = tcg_temp_new(); - cond_prep(&cond); tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1); gen_helper_tcond(cpu_env, tmp); tcg_temp_free(tmp); @@ -1855,7 +1832,6 @@ static bool do_cbranch(DisasContext *ctx, target_sreg disp, bool is_n, } taken = gen_new_label(); - cond_prep(cond); tcg_gen_brcond_reg(c, cond->a0, cond->a1, taken); cond_free(cond); @@ -1952,7 +1928,6 @@ static bool do_ibranch(DisasContext *ctx, TCGv_reg dest, tcg_gen_lookup_and_goto_ptr(); return nullify_end(ctx); } else { - cond_prep(&ctx->null_cond); c = ctx->null_cond.c; a0 = ctx->null_cond.a0; a1 = ctx->null_cond.a1; From 224f364a49ec88f9710908574393818d964d0593 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Thu, 8 Jul 2021 22:45:21 +0800 Subject: [PATCH 052/531] migration/rdma: prevent from double free the same mr backtrace: '0x00007ffff5f44ec2 in __ibv_dereg_mr_1_1 (mr=0x7fff1007d390) at /home/lizhijian/rdma-core/libibverbs/verbs.c:478 478 void *addr = mr->addr; (gdb) bt #0 0x00007ffff5f44ec2 in __ibv_dereg_mr_1_1 (mr=0x7fff1007d390) at /home/lizhijian/rdma-core/libibverbs/verbs.c:478 #1 0x0000555555891fcc in rdma_delete_block (block=, rdma=0x7fff38176010) at ../migration/rdma.c:691 #2 qemu_rdma_cleanup (rdma=0x7fff38176010) at ../migration/rdma.c:2365 #3 0x00005555558925b0 in qio_channel_rdma_close_rcu (rcu=0x555556b8b6c0) at ../migration/rdma.c:3073 #4 0x0000555555d652a3 in call_rcu_thread (opaque=opaque@entry=0x0) at ../util/rcu.c:281 #5 0x0000555555d5edf9 in qemu_thread_start (args=0x7fffe88bb4d0) at ../util/qemu-thread-posix.c:541 #6 0x00007ffff54c73f9 in start_thread () at /lib64/libpthread.so.0 #7 0x00007ffff53f3b03 in clone () at /lib64/libc.so.6 ' Signed-off-by: Li Zhijian Message-Id: <20210708144521.1959614-1-lizhijian@cn.fujitsu.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- migration/rdma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/migration/rdma.c b/migration/rdma.c index 38a099f7ee..5c2d113aa9 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1143,6 +1143,7 @@ static int qemu_rdma_reg_whole_ram_blocks(RDMAContext *rdma) for (i--; i >= 0; i--) { ibv_dereg_mr(local->block[i].mr); + local->block[i].mr = NULL; rdma->total_registrations--; } From a51dcef08ba574c129ae347f6f47b61ccb10cf07 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 1 Jul 2021 15:14:58 +0200 Subject: [PATCH 053/531] migration: failover: emit a warning when the card is not fully unplugged When the migration fails or is canceled we wait the end of the unplug operation to be able to plug it back. But if the unplug operation is never finished we stop to wait and QEMU emits a warning to inform the user. Based-on: 20210629155007.629086-1-lvivier@redhat.com Signed-off-by: Laurent Vivier Message-Id: <20210701131458.112036-1-lvivier@redhat.com> Reviewed-by: Juan Quintela Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/migration/migration.c b/migration/migration.c index 5ff7ba9d5c..d717cd089a 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -3701,6 +3701,10 @@ static void qemu_savevm_wait_unplug(MigrationState *s, int old_state, while (timeout-- && qemu_savevm_state_guest_unplug_pending()) { qemu_sem_timedwait(&s->wait_unplug_sem, 250); } + if (qemu_savevm_state_guest_unplug_pending()) { + warn_report("migration: partially unplugged device on " + "failure"); + } } migrate_set_state(&s->state, MIGRATION_STATUS_WAIT_UNPLUG, new_state); From 2e3e3da3c2ad559d1255a9a3bf3df0782c2cf231 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 8 Jul 2021 15:06:51 -0400 Subject: [PATCH 054/531] migration: Release return path early for paused postcopy When postcopy pause triggered, we rely on the migration thread to cleanup the to_dst_file handle, and the return path thread to cleanup the from_dst_file handle (which is stored in the local variable "rp"). Within the process, from_dst_file cleanup (qemu_fclose) is postponed until it's setup again due to a postcopy recovery. It used to work before yank was born; after yank is introduced we rely on the refcount of IOC to correctly unregister yank function in channel_close(). If without the early and on-time release of from_dst_file handle the yank function will be leftover during paused postcopy. Without this patch, below steps (quoted from Xiaohui) could trigger qemu src crash: 1.Boot vm on src host 2.Boot vm on dst host 3.Enable postcopy on src&dst host 4.Load stressapptest in vm and set postcopy speed to 50M 5.Start migration from src to dst host, change into postcopy mode when migration is active. 6.When postcopy is active, down the network card(do migration via this network) on dst host. 7.Wait untill postcopy is paused on src&dst host. 8.Before up network card, recover migration on dst host, will get error like following. 9.Ignore the error of step 8, go on recovering migration on src host: After step 9, qemu on src host will core dump after some seconds: qemu-kvm: ../util/yank.c:107: yank_unregister_instance: Assertion `QLIST_EMPTY(&entry->yankfns)' failed. 1.sh: line 38: 44662 Aborted (core dumped) Reported-by: Li Xiaohui Signed-off-by: Peter Xu Message-Id: <20210708190653.252961-2-peterx@redhat.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index d717cd089a..38ebc6c1ab 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -2818,12 +2818,12 @@ out: * Maybe there is something we can do: it looks like a * network down issue, and we pause for a recovery. */ + qemu_fclose(rp); + ms->rp_state.from_dst_file = NULL; + rp = NULL; if (postcopy_pause_return_path_thread(ms)) { /* Reload rp, reset the rest */ - if (rp != ms->rp_state.from_dst_file) { - qemu_fclose(rp); - rp = ms->rp_state.from_dst_file; - } + rp = ms->rp_state.from_dst_file; ms->rp_state.error = false; goto retry; } From ca30f24d12c9ba1fc0654e6e983f950f7792a217 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 8 Jul 2021 15:06:52 -0400 Subject: [PATCH 055/531] migration: Don't do migrate cleanup if during postcopy resume Below process could crash qemu with postcopy recovery: 1. (hmp) migrate -d .. 2. (hmp) migrate_start_postcopy 3. [network down, postcopy paused] 4. (hmp) migrate -r $WRONG_PORT when try the recover on an invalid $WRONG_PORT, cleanup_bh will be cleared 5. (hmp) migrate -r $RIGHT_PORT [qemu crash on assert(cleanup_bh)] The thing is we shouldn't cleanup if it's postcopy resume; the error is set mostly because the channel is wrong, so we return directly waiting for the user to retry. migrate_fd_cleanup() should only be called when migration is cancelled or completed. Signed-off-by: Peter Xu Message-Id: <20210708190653.252961-3-peterx@redhat.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/migration/migration.c b/migration/migration.c index 38ebc6c1ab..20c48cfff1 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -3979,7 +3979,18 @@ void migrate_fd_connect(MigrationState *s, Error *error_in) } if (error_in) { migrate_fd_error(s, error_in); - migrate_fd_cleanup(s); + if (resume) { + /* + * Don't do cleanup for resume if channel is invalid, but only dump + * the error. We wait for another channel connect from the user. + * The error_report still gives HMP user a hint on what failed. + * It's normally done in migrate_fd_cleanup(), but call it here + * explicitly. + */ + error_report_err(error_copy(s->error)); + } else { + migrate_fd_cleanup(s); + } return; } From ca7bd0821bb62a1561dd409507039558c0e1f5ac Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 8 Jul 2021 15:06:53 -0400 Subject: [PATCH 056/531] migration: Clear error at entry of migrate_fd_connect() For each "migrate" command, remember to clear the s->error before going on. For one reason, when there's a new error it'll be still remembered; see migrate_set_error() who only sets the error if error==NULL. Meanwhile if a failed migration completes (e.g., postcopy recovered and finished), we shouldn't dump an error when calling migrate_fd_cleanup() at last. Signed-off-by: Peter Xu Message-Id: <20210708190653.252961-4-peterx@redhat.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/migration/migration.c b/migration/migration.c index 20c48cfff1..2d306582eb 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1855,6 +1855,15 @@ void migrate_set_error(MigrationState *s, const Error *error) } } +static void migrate_error_free(MigrationState *s) +{ + QEMU_LOCK_GUARD(&s->error_mutex); + if (s->error) { + error_free(s->error); + s->error = NULL; + } +} + void migrate_fd_error(MigrationState *s, const Error *error) { trace_migrate_fd_error(error_get_pretty(error)); @@ -3970,6 +3979,13 @@ void migrate_fd_connect(MigrationState *s, Error *error_in) int64_t rate_limit; bool resume = s->state == MIGRATION_STATUS_POSTCOPY_PAUSED; + /* + * If there's a previous error, free it and prepare for another one. + * Meanwhile if migration completes successfully, there won't have an error + * dumped when calling migrate_fd_cleanup(). + */ + migrate_error_free(s); + s->expected_downtime = s->parameters.downtime_limit; if (resume) { assert(s->cleanup_bh); From 63268c4970a5f126cc9af75f3ccb8057abef5ec0 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 30 Jun 2021 16:08:05 -0400 Subject: [PATCH 057/531] migration: Move bitmap_mutex out of migration_bitmap_clear_dirty() Taking the mutex every time for each dirty bit to clear is too slow, especially we'll take/release even if the dirty bit is cleared. So far it's only used to sync with special cases with qemu_guest_free_page_hint() against migration thread, nothing really that serious yet. Let's move the lock to be upper. There're two callers of migration_bitmap_clear_dirty(). For migration, move it into ram_save_iterate(). With the help of MAX_WAIT logic, we'll only run ram_save_iterate() for no more than 50ms-ish time, so taking the lock once there at the entry. It also means any call sites to qemu_guest_free_page_hint() can be delayed; but it should be very rare, only during migration, and I don't see a problem with it. For COLO, move it up to colo_flush_ram_cache(). I think COLO forgot to take that lock even when calling ramblock_sync_dirty_bitmap(), where another example is migration_bitmap_sync() who took it right. So let the mutex cover both the ramblock_sync_dirty_bitmap() and migration_bitmap_clear_dirty() calls. It's even possible to drop the lock so we use atomic operations upon rb->bmap and the variable migration_dirty_pages. I didn't do it just to still be safe, also not predictable whether the frequent atomic ops could bring overhead too e.g. on huge vms when it happens very often. When that really comes, we can keep a local counter and periodically call atomic ops. Keep it simple for now. Cc: Wei Wang Cc: David Hildenbrand Cc: Hailiang Zhang Cc: Dr. David Alan Gilbert Cc: Juan Quintela Cc: Leonardo Bras Soares Passos Signed-off-by: Peter Xu Message-Id: <20210630200805.280905-1-peterx@redhat.com> Reviewed-by: Wei Wang Signed-off-by: Dr. David Alan Gilbert --- migration/ram.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 88ff34f574..b5fc454b2f 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -795,8 +795,6 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs, { bool ret; - QEMU_LOCK_GUARD(&rs->bitmap_mutex); - /* * Clear dirty bitmap if needed. This _must_ be called before we * send any of the page in the chunk because we need to make sure @@ -2834,6 +2832,14 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) goto out; } + /* + * We'll take this lock a little bit long, but it's okay for two reasons. + * Firstly, the only possible other thread to take it is who calls + * qemu_guest_free_page_hint(), which should be rare; secondly, see + * MAX_WAIT (if curious, further see commit 4508bd9ed8053ce) below, which + * guarantees that we'll at least released it in a regular basis. + */ + qemu_mutex_lock(&rs->bitmap_mutex); WITH_RCU_READ_LOCK_GUARD() { if (ram_list.version != rs->last_version) { ram_state_reset(rs); @@ -2893,6 +2899,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) i++; } } + qemu_mutex_unlock(&rs->bitmap_mutex); /* * Must occur before EOS (or any QEMUFile operation) @@ -3682,6 +3689,7 @@ void colo_flush_ram_cache(void) unsigned long offset = 0; memory_global_dirty_log_sync(); + qemu_mutex_lock(&ram_state->bitmap_mutex); WITH_RCU_READ_LOCK_GUARD() { RAMBLOCK_FOREACH_NOT_IGNORED(block) { ramblock_sync_dirty_bitmap(ram_state, block); @@ -3710,6 +3718,7 @@ void colo_flush_ram_cache(void) } } trace_colo_flush_ram_cache_end(); + qemu_mutex_unlock(&ram_state->bitmap_mutex); } /** From b1f3b410528177c0a2f86b48bb9fb24422008fb1 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Thu, 11 Feb 2021 16:55:05 -0500 Subject: [PATCH 058/531] Acceptance Tests: use the job work directory for created VMs The QEMUMachine uses a base temporary directory for all temporary needs. By setting it to the Avocado's workdir, it's possible to keep the temporary files during debugging sessions much more easily by setting the "--keep-tmp" command line option. Reference: https://avocado-framework.readthedocs.io/en/85.0/api/test/avocado.html#avocado.Test.workdir Reference: https://avocado-framework.readthedocs.io/en/85.0/config/index.html#run-keep-tmp Signed-off-by: Cleber Rosa Reviewed-by: Wainer dos Santos Moschetta Reviewed-by: John Snow Message-Id: <20210211220146.2525771-4-crosa@redhat.com> Signed-off-by: Cleber Rosa --- tests/acceptance/avocado_qemu/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py index 93c4b9851f..693c226d91 100644 --- a/tests/acceptance/avocado_qemu/__init__.py +++ b/tests/acceptance/avocado_qemu/__init__.py @@ -221,7 +221,8 @@ class Test(avocado.Test): def _new_vm(self, *args): self._sd = tempfile.TemporaryDirectory(prefix="avo_qemu_sock_") - vm = QEMUMachine(self.qemu_bin, sock_dir=self._sd.name) + vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir, + sock_dir=self._sd.name) if args: vm.add_args(*args) return vm From 776b019d9d446c2a24a4dcde352616d496a89b36 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Thu, 11 Feb 2021 16:55:05 -0500 Subject: [PATCH 059/531] Acceptance Tests: log information when creating QEMUMachine Including its base temporary directory, given that information useful for debugging can be put there. Signed-off-by: Cleber Rosa Reviewed-by: Wainer dos Santos Moschetta Message-Id: <20210211220146.2525771-5-crosa@redhat.com> Signed-off-by: Cleber Rosa --- tests/acceptance/avocado_qemu/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py index 693c226d91..4ce09de4fa 100644 --- a/tests/acceptance/avocado_qemu/__init__.py +++ b/tests/acceptance/avocado_qemu/__init__.py @@ -219,10 +219,12 @@ class Test(avocado.Test): if self.qemu_bin is None: self.cancel("No QEMU binary defined or found in the build tree") - def _new_vm(self, *args): + def _new_vm(self, name, *args): self._sd = tempfile.TemporaryDirectory(prefix="avo_qemu_sock_") vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir, sock_dir=self._sd.name) + self.log.debug('QEMUMachine "%s" created', name) + self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir) if args: vm.add_args(*args) return vm @@ -235,7 +237,7 @@ class Test(avocado.Test): if not name: name = str(uuid.uuid4()) if self._vms.get(name) is None: - self._vms[name] = self._new_vm(*args) + self._vms[name] = self._new_vm(name, *args) if self.machine is not None: self._vms[name].set_machine(self.machine) return self._vms[name] From b306e26ce0f33ef0a899131c5191b77aaf6df364 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Thu, 11 Feb 2021 16:55:05 -0500 Subject: [PATCH 060/531] Acceptance Tests: distinguish between temp and logs dir Logs can be very important to debug issues, and currently QEMUMachine instances will remove logs that are created under the temporary directories. With this change, the stdout and stderr generated by the QEMU process started by QEMUMachine will always be kept along the test results directory. Signed-off-by: Cleber Rosa Message-Id: <20210211220146.2525771-6-crosa@redhat.com> Reviewed-by: Wainer dos Santos Moschetta Signed-off-by: Cleber Rosa --- python/qemu/machine/machine.py | 17 ++++++++++++++--- tests/acceptance/avocado_qemu/__init__.py | 3 ++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index d47ab3d896..94846dd71b 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -96,7 +96,8 @@ class QEMUMachine: socket_scm_helper: Optional[str] = None, sock_dir: Optional[str] = None, drain_console: bool = False, - console_log: Optional[str] = None): + console_log: Optional[str] = None, + log_dir: Optional[str] = None): ''' Initialize a QEMUMachine @@ -110,6 +111,7 @@ class QEMUMachine: @param sock_dir: where to create socket (defaults to base_temp_dir) @param drain_console: (optional) True to drain console socket to buffer @param console_log: (optional) path to console log file + @param log_dir: where to create and keep log files @note: Qemu process is not started until launch() is used. ''' # pylint: disable=too-many-arguments @@ -123,6 +125,7 @@ class QEMUMachine: self._name = name or "qemu-%d" % os.getpid() self._base_temp_dir = base_temp_dir self._sock_dir = sock_dir or self._base_temp_dir + self._log_dir = log_dir self._socket_scm_helper = socket_scm_helper if monitor_address is not None: @@ -314,8 +317,6 @@ class QEMUMachine: return args def _pre_launch(self) -> None: - self._qemu_log_path = os.path.join(self.temp_dir, self._name + ".log") - if self._console_set: self._remove_files.append(self._console_address) @@ -332,6 +333,7 @@ class QEMUMachine: # NOTE: Make sure any opened resources are *definitely* freed in # _post_shutdown()! # pylint: disable=consider-using-with + self._qemu_log_path = os.path.join(self.log_dir, self._name + ".log") self._qemu_log_file = open(self._qemu_log_path, 'wb') def _post_launch(self) -> None: @@ -770,3 +772,12 @@ class QEMUMachine: self._temp_dir = tempfile.mkdtemp(prefix="qemu-machine-", dir=self._base_temp_dir) return self._temp_dir + + @property + def log_dir(self) -> str: + """ + Returns a directory to be used for writing logs + """ + if self._log_dir is None: + return self.temp_dir + return self._log_dir diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py index 4ce09de4fa..420c00f1a9 100644 --- a/tests/acceptance/avocado_qemu/__init__.py +++ b/tests/acceptance/avocado_qemu/__init__.py @@ -222,9 +222,10 @@ class Test(avocado.Test): def _new_vm(self, name, *args): self._sd = tempfile.TemporaryDirectory(prefix="avo_qemu_sock_") vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir, - sock_dir=self._sd.name) + sock_dir=self._sd.name, log_dir=self.logdir) self.log.debug('QEMUMachine "%s" created', name) self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir) + self.log.debug('QEMUMachine "%s" log_dir: %s', name, vm.log_dir) if args: vm.add_args(*args) return vm From 341929234c584565ddd7d29bb48d2a5f5f40de22 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Wed, 14 Apr 2021 18:14:55 -0400 Subject: [PATCH 061/531] Acceptance Tests: rename attribute holding the distro image checksum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This renames the attribute that holds the checksum for the image Linux distribution image used. The current name of the attribute is not very descriptive. Also, in preparation for making the distribution used configurable, which will add distro related parameters, attributes and tags, let's make the naming of those more uniform. Signed-off-by: Cleber Rosa Message-Id: <20210414221457.1653745-2-crosa@redhat.com> Reviewed-by: Wainer dos Santos Moschetta Reviewed-by: Eric Auger Reviewed-by: Willian Rampazzo Reviewed-by: Philippe Mathieu-Daudé [CR: split long lines] Signed-off-by: Cleber Rosa --- tests/acceptance/avocado_qemu/__init__.py | 4 ++-- tests/acceptance/boot_linux.py | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py index 420c00f1a9..0e62c15c60 100644 --- a/tests/acceptance/avocado_qemu/__init__.py +++ b/tests/acceptance/avocado_qemu/__init__.py @@ -312,7 +312,7 @@ class LinuxTest(Test, LinuxSSHMixIn): """ timeout = 900 - chksum = None + distro_checksum = None username = 'root' password = 'password' @@ -360,7 +360,7 @@ class LinuxTest(Test, LinuxSSHMixIn): try: boot = vmimage.get( 'fedora', arch=image_arch, version='31', - checksum=self.chksum, + checksum=self.distro_checksum, algorithm='sha256', cache_dir=self.cache_dirs[0], snapshot_dir=self.workdir) diff --git a/tests/acceptance/boot_linux.py b/tests/acceptance/boot_linux.py index 4c8a5994b2..3901c23690 100644 --- a/tests/acceptance/boot_linux.py +++ b/tests/acceptance/boot_linux.py @@ -20,7 +20,8 @@ class BootLinuxX8664(LinuxTest): :avocado: tags=arch:x86_64 """ - chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0' + distro_checksum = ('e3c1b309d9203604922d6e255c2c5d09' + '8a309c2d46215d8fc026954f3c5c27a0') def test_pc_i440fx_tcg(self): """ @@ -66,7 +67,8 @@ class BootLinuxAarch64(LinuxTest): :avocado: tags=machine:gic-version=2 """ - chksum = '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49' + distro_checksum = ('1e18d9c0cf734940c4b5d5ec592facae' + 'd2af0ad0329383d5639c997fdf16fe49') def add_common_args(self): self.vm.add_args('-bios', @@ -119,7 +121,8 @@ class BootLinuxPPC64(LinuxTest): :avocado: tags=arch:ppc64 """ - chksum = '7c3528b85a3df4b2306e892199a9e1e43f991c506f2cc390dc4efa2026ad2f58' + distro_checksum = ('7c3528b85a3df4b2306e892199a9e1e4' + '3f991c506f2cc390dc4efa2026ad2f58') def test_pseries_tcg(self): """ @@ -136,7 +139,8 @@ class BootLinuxS390X(LinuxTest): :avocado: tags=arch:s390x """ - chksum = '4caaab5a434fd4d1079149a072fdc7891e354f834d355069ca982fdcaf5a122d' + distro_checksum = ('4caaab5a434fd4d1079149a072fdc789' + '1e354f834d355069ca982fdcaf5a122d') @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_s390_ccw_virtio_tcg(self): From 889554f09ed0d4c2fcc6be28b81e2e9fc8f35aee Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Wed, 14 Apr 2021 18:14:56 -0400 Subject: [PATCH 062/531] Acceptance Tests: move definition of distro checksums to the framework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of having, by default, the checksum in the tests, and the definition of tests in the framework, let's keep them together. A central definition for distributions is available, and it should allow other known distros to be added more easily. No behavior change is expected here, and tests can still define a distro_checksum value if for some reason they want to override the known distribution information. Signed-off-by: Cleber Rosa Message-Id: <20210414221457.1653745-3-crosa@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Acked-by: Eric Auger [CR: split long lines] Signed-off-by: Cleber Rosa --- tests/acceptance/avocado_qemu/__init__.py | 39 +++++++++++++++++++++-- tests/acceptance/boot_linux.py | 12 ------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py index 0e62c15c60..3a144cded4 100644 --- a/tests/acceptance/avocado_qemu/__init__.py +++ b/tests/acceptance/avocado_qemu/__init__.py @@ -304,6 +304,35 @@ class LinuxSSHMixIn: return stdout_lines, stderr_lines +#: A collection of known distros and their respective image checksum +KNOWN_DISTROS = { + 'fedora': { + '31': { + 'x86_64': + {'checksum': ('e3c1b309d9203604922d6e255c2c5d09' + '8a309c2d46215d8fc026954f3c5c27a0')}, + 'aarch64': + {'checksum': ('1e18d9c0cf734940c4b5d5ec592facae' + 'd2af0ad0329383d5639c997fdf16fe49')}, + 'ppc64': + {'checksum': ('7c3528b85a3df4b2306e892199a9e1e4' + '3f991c506f2cc390dc4efa2026ad2f58')}, + 's390x': + {'checksum': ('4caaab5a434fd4d1079149a072fdc789' + '1e354f834d355069ca982fdcaf5a122d')}, + } + } + } + + +def get_known_distro_checksum(distro, distro_version, arch): + try: + return KNOWN_DISTROS.get(distro).get(distro_version).\ + get(arch).get('checksum') + except AttributeError: + return None + + class LinuxTest(Test, LinuxSSHMixIn): """Facilitates having a cloud-image Linux based available. @@ -353,14 +382,20 @@ class LinuxTest(Test, LinuxSSHMixIn): vmimage.QEMU_IMG = qemu_img self.log.info('Downloading/preparing boot image') + distro = 'fedora' + distro_version = '31' + known_distro_checksum = get_known_distro_checksum(distro, + distro_version, + self.arch) + distro_checksum = self.distro_checksum or known_distro_checksum # Fedora 31 only provides ppc64le images image_arch = self.arch if image_arch == 'ppc64': image_arch = 'ppc64le' try: boot = vmimage.get( - 'fedora', arch=image_arch, version='31', - checksum=self.distro_checksum, + distro, arch=image_arch, version=distro_version, + checksum=distro_checksum, algorithm='sha256', cache_dir=self.cache_dirs[0], snapshot_dir=self.workdir) diff --git a/tests/acceptance/boot_linux.py b/tests/acceptance/boot_linux.py index 3901c23690..34c4366366 100644 --- a/tests/acceptance/boot_linux.py +++ b/tests/acceptance/boot_linux.py @@ -20,9 +20,6 @@ class BootLinuxX8664(LinuxTest): :avocado: tags=arch:x86_64 """ - distro_checksum = ('e3c1b309d9203604922d6e255c2c5d09' - '8a309c2d46215d8fc026954f3c5c27a0') - def test_pc_i440fx_tcg(self): """ :avocado: tags=machine:pc @@ -67,9 +64,6 @@ class BootLinuxAarch64(LinuxTest): :avocado: tags=machine:gic-version=2 """ - distro_checksum = ('1e18d9c0cf734940c4b5d5ec592facae' - 'd2af0ad0329383d5639c997fdf16fe49') - def add_common_args(self): self.vm.add_args('-bios', os.path.join(BUILD_DIR, 'pc-bios', @@ -121,9 +115,6 @@ class BootLinuxPPC64(LinuxTest): :avocado: tags=arch:ppc64 """ - distro_checksum = ('7c3528b85a3df4b2306e892199a9e1e4' - '3f991c506f2cc390dc4efa2026ad2f58') - def test_pseries_tcg(self): """ :avocado: tags=machine:pseries @@ -139,9 +130,6 @@ class BootLinuxS390X(LinuxTest): :avocado: tags=arch:s390x """ - distro_checksum = ('4caaab5a434fd4d1079149a072fdc789' - '1e354f834d355069ca982fdcaf5a122d') - @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_s390_ccw_virtio_tcg(self): """ From d5adf9d52b36d63347b2f658b8c67567ff6bd525 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Wed, 14 Apr 2021 18:14:57 -0400 Subject: [PATCH 063/531] Acceptance Tests: support choosing specific distro and version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tests based on the LinuxTest class give the test writer a ready to use guest operating system, currently pinned to Fedora 31. With this change, it's now possible to choose different distros and versions, similar to how other tags and parameter can be set for the target arch, accelerator, etc. One of the reasons for this work, is that some development features depend on updates on the guest side. For instance the tests on virtiofs_submounts.py, require newer kernels, and may benefit from running, say on Fedora 34, without the need for a custom kernel. Please notice that the pre-caching of the Fedora 31 images done during the early stages of `make check-acceptance` (before the tests are actually executed) are not expanded here to cover every new image added. But, the tests will download other needed images (and cache them) during the first execution. Signed-off-by: Cleber Rosa Message-Id: <20210414221457.1653745-4-crosa@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Willian Rampazzo Signed-off-by: Cleber Rosa --- docs/devel/testing.rst | 65 +++++++++++++++++++++++ tests/acceptance/avocado_qemu/__init__.py | 47 ++++++++++++---- 2 files changed, 102 insertions(+), 10 deletions(-) diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst index 4e42392810..19cbf532ae 100644 --- a/docs/devel/testing.rst +++ b/docs/devel/testing.rst @@ -922,6 +922,39 @@ The preserved value of the ``qemu_bin`` parameter or the result of the dynamic probe for a QEMU binary in the current working directory or source tree. +LinuxTest +~~~~~~~~~ + +Besides the attributes present on the ``avocado_qemu.Test`` base +class, the ``avocado_qemu.LinuxTest`` adds the following attributes: + +distro +...... + +The name of the Linux distribution used as the guest image for the +test. The name should match the **Provider** column on the list +of images supported by the avocado.utils.vmimage library: + +https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images + +distro_version +.............. + +The version of the Linux distribution as the guest image for the +test. The name should match the **Version** column on the list +of images supported by the avocado.utils.vmimage library: + +https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images + +distro_checksum +............... + +The sha256 hash of the guest image file used for the test. + +If this value is not set in the code or by a test parameter (with the +same name), no validation on the integrity of the image will be +performed. + Parameter reference ------------------- @@ -962,6 +995,38 @@ qemu_bin The exact QEMU binary to be used on QEMUMachine. +LinuxTest +~~~~~~~~~ + +Besides the parameters present on the ``avocado_qemu.Test`` base +class, the ``avocado_qemu.LinuxTest`` adds the following parameters: + +distro +...... + +The name of the Linux distribution used as the guest image for the +test. The name should match the **Provider** column on the list +of images supported by the avocado.utils.vmimage library: + +https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images + +distro_version +.............. + +The version of the Linux distribution as the guest image for the +test. The name should match the **Version** column on the list +of images supported by the avocado.utils.vmimage library: + +https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images + +distro_checksum +............... + +The sha256 hash of the guest image file used for the test. + +If this value is not set in the code or by this parameter no +validation on the integrity of the image will be performed. + Skipping tests -------------- The Avocado framework provides Python decorators which allow for easily skip diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py index 3a144cded4..1f1728ab83 100644 --- a/tests/acceptance/avocado_qemu/__init__.py +++ b/tests/acceptance/avocado_qemu/__init__.py @@ -345,8 +345,39 @@ class LinuxTest(Test, LinuxSSHMixIn): username = 'root' password = 'password' + def _set_distro(self): + distro = self.params.get( + 'distro', + default=self._get_unique_tag_val('distro')) + if not distro: + distro = 'fedora' + self.distro = distro + + distro_version = self.params.get( + 'distro_version', + default=self._get_unique_tag_val('distro_version')) + if not distro_version: + distro_version = '31' + self.distro_version = distro_version + + # The distro checksum behaves differently than distro name and + # version. First, it does not respect a tag with the same + # name, given that it's not expected to be used for filtering + # (distro name versions are the natural choice). Second, the + # order of precedence is: parameter, attribute and then value + # from KNOWN_DISTROS. + distro_checksum = self.params.get('distro_checksum', + default=self.distro_checksum) + if not distro_checksum: + distro_checksum = get_known_distro_checksum(self.distro, + self.distro_version, + self.arch) + if distro_checksum: + self.distro_checksum = distro_checksum + def setUp(self, ssh_pubkey=None, network_device_type='virtio-net'): super(LinuxTest, self).setUp() + self._set_distro() self.vm.add_args('-smp', '2') self.vm.add_args('-m', '1024') # The following network device allows for SSH connections @@ -382,20 +413,16 @@ class LinuxTest(Test, LinuxSSHMixIn): vmimage.QEMU_IMG = qemu_img self.log.info('Downloading/preparing boot image') - distro = 'fedora' - distro_version = '31' - known_distro_checksum = get_known_distro_checksum(distro, - distro_version, - self.arch) - distro_checksum = self.distro_checksum or known_distro_checksum # Fedora 31 only provides ppc64le images image_arch = self.arch - if image_arch == 'ppc64': - image_arch = 'ppc64le' + if self.distro == 'fedora': + if image_arch == 'ppc64': + image_arch = 'ppc64le' + try: boot = vmimage.get( - distro, arch=image_arch, version=distro_version, - checksum=distro_checksum, + self.distro, arch=image_arch, version=self.distro_version, + checksum=self.distro_checksum, algorithm='sha256', cache_dir=self.cache_dirs[0], snapshot_dir=self.workdir) From 9f5193413026ed65f9651108b6656054b40e43a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 15 May 2021 15:45:54 +0200 Subject: [PATCH 064/531] tests/acceptance: Ignore binary data sent on serial console MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a guest sends binary data on the serial console, we get: File "tests/acceptance/avocado_qemu/__init__.py", line 92, in _console_interaction msg = console.readline().strip() File "/usr/lib64/python3.8/codecs.py", line 322, in decode (result, consumed) = self._buffer_decode(data, self.errors, final) UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa9 in position 2: invalid start byte Since we use the console with readline(), fix it the easiest way possible: ignore binary data (all current tests compare text string anyway). Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210515134555.307404-2-f4bug@amsat.org> Reviewed-by: Wainer dos Santos Moschetta Tested-by: Wainer dos Santos Moschetta Signed-off-by: Cleber Rosa --- tests/acceptance/avocado_qemu/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py index 1f1728ab83..c3163af3b7 100644 --- a/tests/acceptance/avocado_qemu/__init__.py +++ b/tests/acceptance/avocado_qemu/__init__.py @@ -86,14 +86,17 @@ def _console_interaction(test, success_message, failure_message, assert not keep_sending or send_string if vm is None: vm = test.vm - console = vm.console_socket.makefile() + console = vm.console_socket.makefile(mode='rb', encoding='utf-8') console_logger = logging.getLogger('console') while True: if send_string: vm.console_socket.sendall(send_string.encode()) if not keep_sending: send_string = None # send only once - msg = console.readline().strip() + try: + msg = console.readline().decode().strip() + except UnicodeDecodeError: + msg = None if not msg: continue console_logger.debug(msg) From fb130401736d294843764bfbab37a9e9e020ef08 Mon Sep 17 00:00:00 2001 From: Willian Rampazzo Date: Tue, 6 Jul 2021 15:17:26 +0200 Subject: [PATCH 065/531] avocado_qemu: Fix KNOWN_DISTROS map into the LinuxDistro class As the KNOWN_DISTROS grows, more loosely methods will be created in the avocado_qemu/__init__.py file. Let's refactor the code so that KNOWN_DISTROS and related methods are packaged in a class Signed-off-by: Wainer dos Santos Moschetta Signed-off-by: Eric Auger Message-Id: <20210706131729.30749-2-eric.auger@redhat.com> [CR: moved aarch64 definition from patch 2 to 1] [CR: protect get() when arch is not defined] [CR: split long lines] Acked-by: Wainer dos Santos Moschetta Signed-off-by: Cleber Rosa --- tests/acceptance/avocado_qemu/__init__.py | 86 +++++++++++++---------- 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py index c3163af3b7..256befafc4 100644 --- a/tests/acceptance/avocado_qemu/__init__.py +++ b/tests/acceptance/avocado_qemu/__init__.py @@ -306,34 +306,50 @@ class LinuxSSHMixIn: f'Guest command failed: {command}') return stdout_lines, stderr_lines +class LinuxDistro: + """Represents a Linux distribution -#: A collection of known distros and their respective image checksum -KNOWN_DISTROS = { - 'fedora': { - '31': { - 'x86_64': - {'checksum': ('e3c1b309d9203604922d6e255c2c5d09' - '8a309c2d46215d8fc026954f3c5c27a0')}, - 'aarch64': - {'checksum': ('1e18d9c0cf734940c4b5d5ec592facae' - 'd2af0ad0329383d5639c997fdf16fe49')}, - 'ppc64': - {'checksum': ('7c3528b85a3df4b2306e892199a9e1e4' - '3f991c506f2cc390dc4efa2026ad2f58')}, - 's390x': - {'checksum': ('4caaab5a434fd4d1079149a072fdc789' - '1e354f834d355069ca982fdcaf5a122d')}, + Holds information of known distros. + """ + #: A collection of known distros and their respective image checksum + KNOWN_DISTROS = { + 'fedora': { + '31': { + 'x86_64': + {'checksum': ('e3c1b309d9203604922d6e255c2c5d09' + '8a309c2d46215d8fc026954f3c5c27a0')}, + 'aarch64': + {'checksum': ('1e18d9c0cf734940c4b5d5ec592facae' + 'd2af0ad0329383d5639c997fdf16fe49')}, + 'ppc64': + {'checksum': ('7c3528b85a3df4b2306e892199a9e1e4' + '3f991c506f2cc390dc4efa2026ad2f58')}, + 's390x': + {'checksum': ('4caaab5a434fd4d1079149a072fdc789' + '1e354f834d355069ca982fdcaf5a122d')}, } } } + def __init__(self, name, version, arch): + self.name = name + self.version = version + self.arch = arch + try: + info = self.KNOWN_DISTROS.get(name).get(version).get(arch) + except AttributeError: + # Unknown distro + info = None + self._info = info or {} -def get_known_distro_checksum(distro, distro_version, arch): - try: - return KNOWN_DISTROS.get(distro).get(distro_version).\ - get(arch).get('checksum') - except AttributeError: - return None + @property + def checksum(self): + """Gets the cloud-image file checksum""" + return self._info.get('checksum', None) + + @checksum.setter + def checksum(self, value): + self._info['checksum'] = value class LinuxTest(Test, LinuxSSHMixIn): @@ -344,24 +360,24 @@ class LinuxTest(Test, LinuxSSHMixIn): """ timeout = 900 - distro_checksum = None + distro = None username = 'root' password = 'password' def _set_distro(self): - distro = self.params.get( + distro_name = self.params.get( 'distro', default=self._get_unique_tag_val('distro')) - if not distro: - distro = 'fedora' - self.distro = distro + if not distro_name: + distro_name = 'fedora' distro_version = self.params.get( 'distro_version', default=self._get_unique_tag_val('distro_version')) if not distro_version: distro_version = '31' - self.distro_version = distro_version + + self.distro = LinuxDistro(distro_name, distro_version, self.arch) # The distro checksum behaves differently than distro name and # version. First, it does not respect a tag with the same @@ -370,13 +386,9 @@ class LinuxTest(Test, LinuxSSHMixIn): # order of precedence is: parameter, attribute and then value # from KNOWN_DISTROS. distro_checksum = self.params.get('distro_checksum', - default=self.distro_checksum) - if not distro_checksum: - distro_checksum = get_known_distro_checksum(self.distro, - self.distro_version, - self.arch) + default=None) if distro_checksum: - self.distro_checksum = distro_checksum + self.distro.checksum = distro_checksum def setUp(self, ssh_pubkey=None, network_device_type='virtio-net'): super(LinuxTest, self).setUp() @@ -418,14 +430,14 @@ class LinuxTest(Test, LinuxSSHMixIn): self.log.info('Downloading/preparing boot image') # Fedora 31 only provides ppc64le images image_arch = self.arch - if self.distro == 'fedora': + if self.distro.name == 'fedora': if image_arch == 'ppc64': image_arch = 'ppc64le' try: boot = vmimage.get( - self.distro, arch=image_arch, version=self.distro_version, - checksum=self.distro_checksum, + self.distro.name, arch=image_arch, version=self.distro.version, + checksum=self.distro.checksum, algorithm='sha256', cache_dir=self.cache_dirs[0], snapshot_dir=self.workdir) From c839d305b90d04643c21b30b8cd1828a9e995163 Mon Sep 17 00:00:00 2001 From: Willian Rampazzo Date: Tue, 6 Jul 2021 15:17:27 +0200 Subject: [PATCH 066/531] Acceptance Tests: Add default kernel params and pxeboot url to the KNOWN_DISTROS collection When running LinuxTests we may need to run the guest with custom params. It is practical to store the pxeboot URL and the default kernel params so that the tests just need to fetch those and augment the kernel params. Signed-off-by: Eric Auger Reviewed-by: Willian Rampazzo Message-Id: <20210706131729.30749-3-eric.auger@redhat.com> [CR: split long lines] Signed-off-by: Cleber Rosa --- tests/acceptance/avocado_qemu/__init__.py | 58 +++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py index 256befafc4..1de1edce0d 100644 --- a/tests/acceptance/avocado_qemu/__init__.py +++ b/tests/acceptance/avocado_qemu/__init__.py @@ -317,17 +317,59 @@ class LinuxDistro: '31': { 'x86_64': {'checksum': ('e3c1b309d9203604922d6e255c2c5d09' - '8a309c2d46215d8fc026954f3c5c27a0')}, + '8a309c2d46215d8fc026954f3c5c27a0'), + 'pxeboot_url': ('https://archives.fedoraproject.org/' + 'pub/archive/fedora/linux/releases/31/' + 'Everything/x86_64/os/images/pxeboot/'), + 'kernel_params': ('root=UUID=b1438b9b-2cab-4065-a99a-' + '08a96687f73c ro no_timer_check ' + 'net.ifnames=0 console=tty1 ' + 'console=ttyS0,115200n8'), + }, 'aarch64': {'checksum': ('1e18d9c0cf734940c4b5d5ec592facae' - 'd2af0ad0329383d5639c997fdf16fe49')}, + 'd2af0ad0329383d5639c997fdf16fe49'), + 'pxeboot_url': 'https://archives.fedoraproject.org/' + 'pub/archive/fedora/linux/releases/31/' + 'Everything/aarch64/os/images/pxeboot/', + 'kernel_params': ('root=UUID=b6950a44-9f3c-4076-a9c2-' + '355e8475b0a7 ro earlyprintk=pl011,0x9000000' + ' ignore_loglevel no_timer_check' + ' printk.time=1 rd_NO_PLYMOUTH' + ' console=ttyAMA0'), + }, 'ppc64': {'checksum': ('7c3528b85a3df4b2306e892199a9e1e4' '3f991c506f2cc390dc4efa2026ad2f58')}, 's390x': {'checksum': ('4caaab5a434fd4d1079149a072fdc789' '1e354f834d355069ca982fdcaf5a122d')}, - } + }, + '32': { + 'aarch64': + {'checksum': ('b367755c664a2d7a26955bbfff985855' + 'adfa2ca15e908baf15b4b176d68d3967'), + 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/' + 'releases/32/Server/aarch64/os/images/' + 'pxeboot/'), + 'kernel_params': ('root=UUID=3df75b65-be8d-4db4-8655-' + '14d95c0e90c5 ro no_timer_check net.ifnames=0' + ' console=tty1 console=ttyS0,115200n8'), + }, + }, + '33': { + 'aarch64': + {'checksum': ('e7f75cdfd523fe5ac2ca9eeece68edc1' + 'a81f386a17f969c1d1c7c87031008a6b'), + 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/' + 'releases/33/Server/aarch64/os/images/' + 'pxeboot/'), + 'kernel_params': ('root=UUID=d20b3ffa-6397-4a63-a734-' + '1126a0208f8a ro no_timer_check net.ifnames=0' + ' console=tty1 console=ttyS0,115200n8' + ' console=tty0'), + }, + }, } } @@ -351,6 +393,16 @@ class LinuxDistro: def checksum(self, value): self._info['checksum'] = value + @property + def pxeboot_url(self): + """Gets the repository url where pxeboot files can be found""" + return self._info.get('pxeboot_url', None) + + @property + def default_kernel_params(self): + """Gets the default kernel parameters""" + return self._info.get('kernel_params', None) + class LinuxTest(Test, LinuxSSHMixIn): """Facilitates having a cloud-image Linux based available. From 6ace9b4e5e78f5d4fac1e5b63264945a5373afd5 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 6 Jul 2021 15:17:28 +0200 Subject: [PATCH 067/531] avocado_qemu: Add SMMUv3 tests Add new tests checking the good behavior of the SMMUv3 protecting 2 virtio pci devices (block and net). We check the guest boots and we are able to install a package. Different guest configs are tested: standard, passthrough an strict=0. This is tested with both fedora 31 and 33. The former uses a 5.3 kernel without range invalidation whereas the latter uses a 5.8 kernel that features range invalidation. Signed-off-by: Eric Auger Reviewed-by: Willian Rampazzo Reviewed-by: Wainer dos Santos Moschetta Tested-by: Wainer dos Santos Moschetta Message-Id: <20210706131729.30749-4-eric.auger@redhat.com> [CR: split long lines] [CR: added MAINTAINERS entry] Signed-off-by: Cleber Rosa --- MAINTAINERS | 1 + tests/acceptance/smmu.py | 137 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 tests/acceptance/smmu.py diff --git a/MAINTAINERS b/MAINTAINERS index c340bb02b0..148153d74f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -171,6 +171,7 @@ L: qemu-arm@nongnu.org S: Maintained F: hw/arm/smmu* F: include/hw/arm/smmu* +F: tests/acceptance/smmu.py AVR TCG CPUs M: Michael Rolnik diff --git a/tests/acceptance/smmu.py b/tests/acceptance/smmu.py new file mode 100644 index 0000000000..b3c4de6bf4 --- /dev/null +++ b/tests/acceptance/smmu.py @@ -0,0 +1,137 @@ +# SMMUv3 Functional tests +# +# Copyright (c) 2021 Red Hat, Inc. +# +# Author: +# Eric Auger +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. +import os + +from avocado import skipIf +from avocado_qemu import LinuxTest, BUILD_DIR + +@skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') +class SMMU(LinuxTest): + """ + :avocado: tags=accel:kvm + :avocado: tags=cpu:host + :avocado: tags=arch:aarch64 + :avocado: tags=machine:virt + :avocado: tags=distro:fedora + :avocado: tags=smmu + """ + + IOMMU_ADDON = ',iommu_platform=on,disable-modern=off,disable-legacy=on' + kernel_path = None + initrd_path = None + kernel_params = None + + def set_up_boot(self): + path = self.download_boot() + self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,scsi=off,' + + 'drive=drv0,id=virtio-disk0,bootindex=1,' + 'werror=stop,rerror=stop' + self.IOMMU_ADDON) + self.vm.add_args('-drive', + 'file=%s,if=none,cache=writethrough,id=drv0' % path) + + def setUp(self): + super(SMMU, self).setUp(None, 'virtio-net-pci' + self.IOMMU_ADDON) + + def common_vm_setup(self, custom_kernel=False): + self.require_accelerator("kvm") + self.vm.add_args("-accel", "kvm") + self.vm.add_args("-cpu", "host") + self.vm.add_args("-machine", "iommu=smmuv3") + self.vm.add_args("-d", "guest_errors") + self.vm.add_args('-bios', os.path.join(BUILD_DIR, 'pc-bios', + 'edk2-aarch64-code.fd')) + self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0') + self.vm.add_args('-object', + 'rng-random,id=rng0,filename=/dev/urandom') + + if custom_kernel is False: + return + + kernel_url = self.distro.pxeboot_url + 'vmlinuz' + initrd_url = self.distro.pxeboot_url + 'initrd.img' + self.kernel_path = self.fetch_asset(kernel_url) + self.initrd_path = self.fetch_asset(initrd_url) + + def run_and_check(self): + if self.kernel_path: + self.vm.add_args('-kernel', self.kernel_path, + '-append', self.kernel_params, + '-initrd', self.initrd_path) + self.launch_and_wait() + self.ssh_command('cat /proc/cmdline') + self.ssh_command('dnf -y install numactl-devel') + + + # 5.3 kernel without RIL # + + def test_smmu_noril(self): + """ + :avocado: tags=smmu_noril + :avocado: tags=smmu_noril_tests + :avocado: tags=distro_version:31 + """ + self.common_vm_setup() + self.run_and_check() + + def test_smmu_noril_passthrough(self): + """ + :avocado: tags=smmu_noril_passthrough + :avocado: tags=smmu_noril_tests + :avocado: tags=distro_version:31 + """ + self.common_vm_setup(True) + self.kernel_params = (self.distro.default_kernel_params + + ' iommu.passthrough=on') + self.run_and_check() + + def test_smmu_noril_nostrict(self): + """ + :avocado: tags=smmu_noril_nostrict + :avocado: tags=smmu_noril_tests + :avocado: tags=distro_version:31 + """ + self.common_vm_setup(True) + self.kernel_params = (self.distro.default_kernel_params + + ' iommu.strict=0') + self.run_and_check() + + # 5.8 kernel featuring range invalidation + # >= v5.7 kernel + + def test_smmu_ril(self): + """ + :avocado: tags=smmu_ril + :avocado: tags=smmu_ril_tests + :avocado: tags=distro_version:33 + """ + self.common_vm_setup() + self.run_and_check() + + def test_smmu_ril_passthrough(self): + """ + :avocado: tags=smmu_ril_passthrough + :avocado: tags=smmu_ril_tests + :avocado: tags=distro_version:33 + """ + self.common_vm_setup(True) + self.kernel_params = (self.distro.default_kernel_params + + ' iommu.passthrough=on') + self.run_and_check() + + def test_smmu_ril_nostrict(self): + """ + :avocado: tags=smmu_ril_nostrict + :avocado: tags=smmu_ril_tests + :avocado: tags=distro_version:33 + """ + self.common_vm_setup(True) + self.kernel_params = (self.distro.default_kernel_params + + ' iommu.strict=0') + self.run_and_check() From 5e57d4e895e59579b3c3a7119df259cdfde2d1ce Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 6 Jul 2021 15:17:29 +0200 Subject: [PATCH 068/531] avocado_qemu: Add Intel iommu tests Add Intel IOMMU functional tests based on fedora 31. Different configs are checked: - strict - caching mode, strict - passthrough. Signed-off-by: Eric Auger Signed-off-by: Willian Rampazzo Tested-by: Wainer dos Santos Moschetta Acked-by: Peter Xu Message-Id: <20210706131729.30749-5-eric.auger@redhat.com> [CR: split long lines] Signed-off-by: Cleber Rosa --- tests/acceptance/intel_iommu.py | 119 ++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 tests/acceptance/intel_iommu.py diff --git a/tests/acceptance/intel_iommu.py b/tests/acceptance/intel_iommu.py new file mode 100644 index 0000000000..474d62f6bf --- /dev/null +++ b/tests/acceptance/intel_iommu.py @@ -0,0 +1,119 @@ +# INTEL_IOMMU Functional tests +# +# Copyright (c) 2021 Red Hat, Inc. +# +# Author: +# Eric Auger +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. +import os + +from avocado import skipIf +from avocado_qemu import LinuxTest + +@skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') +class IntelIOMMU(LinuxTest): + """ + :avocado: tags=arch:x86_64 + :avocado: tags=distro:fedora + :avocado: tags=distro_version:31 + :avocado: tags=machine:q35 + :avocado: tags=accel:kvm + :avocado: tags=intel_iommu + """ + + IOMMU_ADDON = ',iommu_platform=on,disable-modern=off,disable-legacy=on' + kernel_path = None + initrd_path = None + kernel_params = None + + def set_up_boot(self): + path = self.download_boot() + self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,scsi=off,' + + 'drive=drv0,id=virtio-disk0,bootindex=1,' + 'werror=stop,rerror=stop' + self.IOMMU_ADDON) + self.vm.add_args('-device', 'virtio-gpu-pci' + self.IOMMU_ADDON) + self.vm.add_args('-drive', + 'file=%s,if=none,cache=writethrough,id=drv0' % path) + + def setUp(self): + super(IntelIOMMU, self).setUp(None, 'virtio-net-pci' + self.IOMMU_ADDON) + + def add_common_args(self): + self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0') + self.vm.add_args('-object', + 'rng-random,id=rng0,filename=/dev/urandom') + + def common_vm_setup(self, custom_kernel=None): + self.require_accelerator("kvm") + self.add_common_args() + self.vm.add_args("-accel", "kvm") + + if custom_kernel is None: + return + + kernel_url = self.distro.pxeboot_url + 'vmlinuz' + initrd_url = self.distro.pxeboot_url + 'initrd.img' + self.kernel_path = self.fetch_asset(kernel_url) + self.initrd_path = self.fetch_asset(initrd_url) + + def run_and_check(self): + if self.kernel_path: + self.vm.add_args('-kernel', self.kernel_path, + '-append', self.kernel_params, + '-initrd', self.initrd_path) + self.launch_and_wait() + self.ssh_command('cat /proc/cmdline') + self.ssh_command('dmesg | grep -e DMAR -e IOMMU') + self.ssh_command('find /sys/kernel/iommu_groups/ -type l') + self.ssh_command('dnf -y install numactl-devel') + + def test_intel_iommu(self): + """ + :avocado: tags=intel_iommu_intremap + """ + + self.common_vm_setup(True) + self.vm.add_args('-device', 'intel-iommu,intremap=on') + self.vm.add_args('-machine', 'kernel_irqchip=split') + + self.kernel_params = (self.distro.default_kernel_params + + ' quiet intel_iommu=on') + self.run_and_check() + + def test_intel_iommu_strict(self): + """ + :avocado: tags=intel_iommu_strict + """ + + self.common_vm_setup(True) + self.vm.add_args('-device', 'intel-iommu,intremap=on') + self.vm.add_args('-machine', 'kernel_irqchip=split') + self.kernel_params = (self.distro.default_kernel_params + + ' quiet intel_iommu=on,strict') + self.run_and_check() + + def test_intel_iommu_strict_cm(self): + """ + :avocado: tags=intel_iommu_strict_cm + """ + + self.common_vm_setup(True) + self.vm.add_args('-device', 'intel-iommu,intremap=on,caching-mode=on') + self.vm.add_args('-machine', 'kernel_irqchip=split') + self.kernel_params = (self.distro.default_kernel_params + + ' quiet intel_iommu=on,strict') + self.run_and_check() + + def test_intel_iommu_pt(self): + """ + :avocado: tags=intel_iommu_pt + """ + + self.common_vm_setup(True) + self.vm.add_args('-device', 'intel-iommu,intremap=on') + self.vm.add_args('-machine', 'kernel_irqchip=split') + self.kernel_params = (self.distro.default_kernel_params + + ' quiet intel_iommu=on iommu=pt') + self.run_and_check() From 012293c1b1451edc28e9b3a6ea573d74c5ed373c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 23 Jun 2021 20:00:15 +0200 Subject: [PATCH 069/531] tests/acceptance: Tag NetBSD tests as 'os:netbsd' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avocado allows us to select set of tests using tags. When wanting to run all tests using a NetBSD guest OS, it is convenient to have them tagged, add the 'os:netbsd' tag. It allows one to run the NetBSD tests with: $ avocado --show=app,console run -t os:netbsd tests/acceptance/ Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210623180021.898286-4-f4bug@amsat.org> Reviewed-by: Niek Linnenbank Reviewed-by: Willian Rampazzo Reviewed-by: Cleber Rosa [PMD: ammend the commit message with example command] Signed-off-by: Cleber Rosa --- tests/acceptance/boot_linux_console.py | 1 + tests/acceptance/ppc_prep_40p.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index 3ae11a7a8f..0a8222f17d 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -905,6 +905,7 @@ class BootLinuxConsole(LinuxKernelTest): :avocado: tags=arch:arm :avocado: tags=machine:orangepi-pc :avocado: tags=device:sd + :avocado: tags=os:netbsd """ # This test download a 304MB compressed image and expand it to 2GB deb_url = ('http://snapshot.debian.org/archive/debian/' diff --git a/tests/acceptance/ppc_prep_40p.py b/tests/acceptance/ppc_prep_40p.py index 96ba13b894..2993ee3b07 100644 --- a/tests/acceptance/ppc_prep_40p.py +++ b/tests/acceptance/ppc_prep_40p.py @@ -27,6 +27,7 @@ class IbmPrep40pMachine(Test): """ :avocado: tags=arch:ppc :avocado: tags=machine:40p + :avocado: tags=os:netbsd :avocado: tags=slowness:high """ bios_url = ('http://ftpmirror.your.org/pub/misc/' @@ -64,6 +65,7 @@ class IbmPrep40pMachine(Test): """ :avocado: tags=arch:ppc :avocado: tags=machine:40p + :avocado: tags=os:netbsd """ drive_url = ('https://cdn.netbsd.org/pub/NetBSD/iso/7.1.2/' 'NetBSD-7.1.2-prep.iso') From 20bbf846b960477a71284bbf848437f2a6e7c804 Mon Sep 17 00:00:00 2001 From: Wainer dos Santos Moschetta Date: Fri, 30 Apr 2021 10:34:08 -0300 Subject: [PATCH 070/531] tests/acceptance: Automatic set -cpu to the test vm This introduces a new feature to the functional tests: automatic setting of the '-cpu VALUE' option to the created vm if the test is tagged with 'cpu:VALUE'. The 'cpu' property is made available to the test object as well. For example, for a simple test as: def test(self): """ :avocado: tags=cpu:host """ self.assertEqual(self.cpu, "host") self.vm.launch() The resulting QEMU evocation will be like: qemu-system-x86_64 -display none -vga none \ -chardev socket,id=mon,path=/var/tmp/avo_qemu_sock_pdgzbgd_/qemu-1135557-monitor.sock \ -mon chardev=mon,mode=control -cpu host Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Reviewed-by: Willian Rampazzo Signed-off-by: Wainer dos Santos Moschetta Message-Id: <20210430133414.39905-2-wainersm@redhat.com> Signed-off-by: Cleber Rosa --- docs/devel/testing.rst | 17 +++++++++++++++++ tests/acceptance/avocado_qemu/__init__.py | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst index 19cbf532ae..8f572255d3 100644 --- a/docs/devel/testing.rst +++ b/docs/devel/testing.rst @@ -904,6 +904,17 @@ name. If one is not given explicitly, it will either be set to ``None``, or, if the test is tagged with one (and only one) ``:avocado: tags=arch:VALUE`` tag, it will be set to ``VALUE``. +cpu +~~~ + +The cpu model that will be set to all QEMUMachine instances created +by the test. + +The ``cpu`` attribute will be set to the test parameter of the same +name. If one is not given explicitly, it will either be set to +``None ``, or, if the test is tagged with one (and only one) +``:avocado: tags=cpu:VALUE`` tag, it will be set to ``VALUE``. + machine ~~~~~~~ @@ -983,6 +994,12 @@ architecture of a kernel or disk image to boot a VM with. This parameter has a direct relation with the ``arch`` attribute. If not given, it will default to None. +cpu +~~~ + +The cpu model that will be set to all QEMUMachine instances created +by the test. + machine ~~~~~~~ diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py index 1de1edce0d..3a218057b3 100644 --- a/tests/acceptance/avocado_qemu/__init__.py +++ b/tests/acceptance/avocado_qemu/__init__.py @@ -213,6 +213,9 @@ class Test(avocado.Test): self.arch = self.params.get('arch', default=self._get_unique_tag_val('arch')) + self.cpu = self.params.get('cpu', + default=self._get_unique_tag_val('cpu')) + self.machine = self.params.get('machine', default=self._get_unique_tag_val('machine')) @@ -242,6 +245,8 @@ class Test(avocado.Test): name = str(uuid.uuid4()) if self._vms.get(name) is None: self._vms[name] = self._new_vm(name, *args) + if self.cpu is not None: + self._vms[name].add_args('-cpu', self.cpu) if self.machine is not None: self._vms[name].set_machine(self.machine) return self._vms[name] From 8a7c1fdecb91b6aeb943156a169fd7a160691542 Mon Sep 17 00:00:00 2001 From: Wainer dos Santos Moschetta Date: Fri, 30 Apr 2021 10:34:09 -0300 Subject: [PATCH 071/531] tests/acceptance: Fix mismatch on cpu tagged tests There are test cases on machine_mips_malta.py and tcg_plugins.py files where the cpu tag does not correspond to the value actually given to the QEMU binary. This fixed those tests tags. Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Reviewed-by: Willian Rampazzo Signed-off-by: Wainer dos Santos Moschetta Message-Id: <20210430133414.39905-3-wainersm@redhat.com> Signed-off-by: Cleber Rosa --- tests/acceptance/machine_mips_malta.py | 6 +++--- tests/acceptance/tcg_plugins.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/acceptance/machine_mips_malta.py b/tests/acceptance/machine_mips_malta.py index 7c9a4ee4d2..b1fd075f51 100644 --- a/tests/acceptance/machine_mips_malta.py +++ b/tests/acceptance/machine_mips_malta.py @@ -96,7 +96,7 @@ class MaltaMachineFramebuffer(Test): """ :avocado: tags=arch:mips64el :avocado: tags=machine:malta - :avocado: tags=cpu:i6400 + :avocado: tags=cpu:I6400 """ self.do_test_i6400_framebuffer_logo(1) @@ -105,7 +105,7 @@ class MaltaMachineFramebuffer(Test): """ :avocado: tags=arch:mips64el :avocado: tags=machine:malta - :avocado: tags=cpu:i6400 + :avocado: tags=cpu:I6400 :avocado: tags=mips:smp """ self.do_test_i6400_framebuffer_logo(7) @@ -115,7 +115,7 @@ class MaltaMachineFramebuffer(Test): """ :avocado: tags=arch:mips64el :avocado: tags=machine:malta - :avocado: tags=cpu:i6400 + :avocado: tags=cpu:I6400 :avocado: tags=mips:smp """ self.do_test_i6400_framebuffer_logo(8) diff --git a/tests/acceptance/tcg_plugins.py b/tests/acceptance/tcg_plugins.py index c21bf9e52a..aa6e18b62d 100644 --- a/tests/acceptance/tcg_plugins.py +++ b/tests/acceptance/tcg_plugins.py @@ -68,7 +68,7 @@ class PluginKernelNormal(PluginKernelBase): :avocado: tags=accel:tcg :avocado: tags=arch:aarch64 :avocado: tags=machine:virt - :avocado: tags=cpu:cortex-a57 + :avocado: tags=cpu:cortex-a53 """ kernel_path = self._grab_aarch64_kernel() kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + @@ -95,7 +95,7 @@ class PluginKernelNormal(PluginKernelBase): :avocado: tags=accel:tcg :avocado: tags=arch:aarch64 :avocado: tags=machine:virt - :avocado: tags=cpu:cortex-a57 + :avocado: tags=cpu:cortex-a53 """ kernel_path = self._grab_aarch64_kernel() kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + @@ -121,7 +121,7 @@ class PluginKernelNormal(PluginKernelBase): :avocado: tags=accel:tcg :avocado: tags=arch:aarch64 :avocado: tags=machine:virt - :avocado: tags=cpu:cortex-a57 + :avocado: tags=cpu:cortex-a53 """ kernel_path = self._grab_aarch64_kernel() kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + From d377ba48524781310536d5e97642e4b95a4b62c8 Mon Sep 17 00:00:00 2001 From: Wainer dos Santos Moschetta Date: Fri, 30 Apr 2021 10:34:10 -0300 Subject: [PATCH 072/531] tests/acceptance: Let the framework handle "cpu:VALUE" tagged tests The tests that are already tagged with "cpu:VALUE" don't need to add "-cpu VALUE" to the list of arguments of the vm object because the avocado_qemu framework is able to handle it automatically. Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Reviewed-by: Willian Rampazzo Signed-off-by: Wainer dos Santos Moschetta Message-Id: <20210430133414.39905-4-wainersm@redhat.com> Signed-off-by: Cleber Rosa --- tests/acceptance/boot_linux.py | 3 --- tests/acceptance/boot_xen.py | 1 - tests/acceptance/machine_mips_malta.py | 1 - tests/acceptance/replay_kernel.py | 8 +++----- tests/acceptance/reverse_debugging.py | 2 +- tests/acceptance/tcg_plugins.py | 9 ++++----- 6 files changed, 8 insertions(+), 16 deletions(-) diff --git a/tests/acceptance/boot_linux.py b/tests/acceptance/boot_linux.py index 34c4366366..ab19146d1e 100644 --- a/tests/acceptance/boot_linux.py +++ b/tests/acceptance/boot_linux.py @@ -79,7 +79,6 @@ class BootLinuxAarch64(LinuxTest): """ self.require_accelerator("tcg") self.vm.add_args("-accel", "tcg") - self.vm.add_args("-cpu", "max") self.vm.add_args("-machine", "virt,gic-version=2") self.add_common_args() self.launch_and_wait(set_up_ssh_connection=False) @@ -92,7 +91,6 @@ class BootLinuxAarch64(LinuxTest): """ self.require_accelerator("tcg") self.vm.add_args("-accel", "tcg") - self.vm.add_args("-cpu", "max") self.vm.add_args("-machine", "virt,gic-version=3") self.add_common_args() self.launch_and_wait(set_up_ssh_connection=False) @@ -104,7 +102,6 @@ class BootLinuxAarch64(LinuxTest): """ self.require_accelerator("kvm") self.vm.add_args("-accel", "kvm") - self.vm.add_args("-cpu", "host") self.vm.add_args("-machine", "virt,gic-version=host") self.add_common_args() self.launch_and_wait(set_up_ssh_connection=False) diff --git a/tests/acceptance/boot_xen.py b/tests/acceptance/boot_xen.py index 75c2d44492..3479b5233b 100644 --- a/tests/acceptance/boot_xen.py +++ b/tests/acceptance/boot_xen.py @@ -48,7 +48,6 @@ class BootXenBase(LinuxKernelTest): xen_command_line = self.XEN_COMMON_COMMAND_LINE self.vm.add_args('-machine', 'virtualization=on', - '-cpu', 'cortex-a57', '-m', '768', '-kernel', xen_path, '-append', xen_command_line, diff --git a/tests/acceptance/machine_mips_malta.py b/tests/acceptance/machine_mips_malta.py index b1fd075f51..b67d8cb141 100644 --- a/tests/acceptance/machine_mips_malta.py +++ b/tests/acceptance/machine_mips_malta.py @@ -62,7 +62,6 @@ class MaltaMachineFramebuffer(Test): kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + 'clocksource=GIC console=tty0 console=ttyS0') self.vm.add_args('-kernel', kernel_path, - '-cpu', 'I6400', '-smp', '%u' % cpu_cores_count, '-vga', 'std', '-append', kernel_command_line) diff --git a/tests/acceptance/replay_kernel.py b/tests/acceptance/replay_kernel.py index 71facdaa75..75f80506c1 100644 --- a/tests/acceptance/replay_kernel.py +++ b/tests/acceptance/replay_kernel.py @@ -156,8 +156,7 @@ class ReplayKernelNormal(ReplayKernelBase): 'console=ttyAMA0') console_pattern = 'VFS: Cannot open root device' - self.run_rr(kernel_path, kernel_command_line, console_pattern, - args=('-cpu', 'cortex-a53')) + self.run_rr(kernel_path, kernel_command_line, console_pattern) def test_arm_virt(self): """ @@ -301,7 +300,7 @@ class ReplayKernelNormal(ReplayKernelBase): tar_url = ('https://www.qemu-advent-calendar.org' '/2018/download/day19.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) - self.do_test_advcal_2018(file_path, 'uImage', ('-cpu', 'e5500')) + self.do_test_advcal_2018(file_path, 'uImage') def test_ppc_g3beige(self): """ @@ -348,8 +347,7 @@ class ReplayKernelNormal(ReplayKernelBase): tar_url = ('https://www.qemu-advent-calendar.org' '/2018/download/day02.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) - self.do_test_advcal_2018(file_path, 'santas-sleigh-ride.elf', - args=('-cpu', 'dc233c')) + self.do_test_advcal_2018(file_path, 'santas-sleigh-ride.elf') @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') class ReplayKernelSlow(ReplayKernelBase): diff --git a/tests/acceptance/reverse_debugging.py b/tests/acceptance/reverse_debugging.py index be01aca217..d2921e70c3 100644 --- a/tests/acceptance/reverse_debugging.py +++ b/tests/acceptance/reverse_debugging.py @@ -207,4 +207,4 @@ class ReverseDebugging_AArch64(ReverseDebugging): kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) self.reverse_debugging( - args=('-kernel', kernel_path, '-cpu', 'cortex-a53')) + args=('-kernel', kernel_path)) diff --git a/tests/acceptance/tcg_plugins.py b/tests/acceptance/tcg_plugins.py index aa6e18b62d..9ca1515c3b 100644 --- a/tests/acceptance/tcg_plugins.py +++ b/tests/acceptance/tcg_plugins.py @@ -25,7 +25,7 @@ class PluginKernelBase(LinuxKernelTest): KERNEL_COMMON_COMMAND_LINE = 'printk.time=1 panic=-1 ' def run_vm(self, kernel_path, kernel_command_line, - plugin, plugin_log, console_pattern, args): + plugin, plugin_log, console_pattern, args=None): vm = self.get_vm() vm.set_console() @@ -80,8 +80,7 @@ class PluginKernelNormal(PluginKernelBase): self.run_vm(kernel_path, kernel_command_line, "tests/plugin/libinsn.so", plugin_log.name, - console_pattern, - args=('-cpu', 'cortex-a53')) + console_pattern) with plugin_log as lf, \ mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s: @@ -108,7 +107,7 @@ class PluginKernelNormal(PluginKernelBase): self.run_vm(kernel_path, kernel_command_line, "tests/plugin/libinsn.so", plugin_log.name, console_pattern, - args=('-cpu', 'cortex-a53', '-icount', 'shift=1')) + args=('-icount', 'shift=1')) with plugin_log as lf, \ mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s: @@ -134,7 +133,7 @@ class PluginKernelNormal(PluginKernelBase): self.run_vm(kernel_path, kernel_command_line, "tests/plugin/libmem.so,arg=both", plugin_log.name, console_pattern, - args=('-cpu', 'cortex-a53', '-icount', 'shift=1')) + args=('-icount', 'shift=1')) with plugin_log as lf, \ mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s: From 2d14975963b831701363a1153a0db97dc19e0d2e Mon Sep 17 00:00:00 2001 From: Wainer dos Santos Moschetta Date: Fri, 30 Apr 2021 10:34:11 -0300 Subject: [PATCH 073/531] tests/acceptance: Tagging tests with "cpu:VALUE" The existing tests which are passing "-cpu VALUE" argument to the vm object are now properly "cpu:VALUE" tagged, so letting the avocado_qemu framework to handle that automatically. Reviewed-by: Cleber Rosa Reviewed-by: Willian Rampazzo Signed-off-by: Wainer dos Santos Moschetta Message-Id: <20210430133414.39905-5-wainersm@redhat.com> Signed-off-by: Cleber Rosa --- tests/acceptance/boot_linux_console.py | 13 ++++++++----- tests/acceptance/pc_cpu_hotplug_props.py | 2 +- tests/acceptance/replay_kernel.py | 9 ++++++--- tests/acceptance/virtio-gpu.py | 4 ++-- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index 0a8222f17d..5248c8097d 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -239,6 +239,7 @@ class BootLinuxConsole(LinuxKernelTest): :avocado: tags=arch:mips64el :avocado: tags=machine:malta :avocado: tags=endian:little + :avocado: tags=cpu:5KEc """ kernel_url = ('https://github.com/philmd/qemu-testing-blob/' 'raw/9ad2df38/mips/malta/mips64el/' @@ -258,8 +259,7 @@ class BootLinuxConsole(LinuxKernelTest): kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0 console=tty ' + 'rdinit=/sbin/init noreboot') - self.vm.add_args('-cpu', '5KEc', - '-kernel', kernel_path, + self.vm.add_args('-kernel', kernel_path, '-initrd', initrd_path, '-append', kernel_command_line, '-no-reboot') @@ -287,7 +287,6 @@ class BootLinuxConsole(LinuxKernelTest): + 'mem=256m@@0x0 ' + 'console=ttyS0') self.vm.add_args('-no-reboot', - '-cpu', 'I7200', '-kernel', kernel_path, '-append', kernel_command_line) self.vm.launch() @@ -299,6 +298,7 @@ class BootLinuxConsole(LinuxKernelTest): :avocado: tags=arch:mipsel :avocado: tags=machine:malta :avocado: tags=endian:little + :avocado: tags=cpu:I7200 """ kernel_url = ('https://mipsdistros.mips.com/LinuxDistro/nanomips/' 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/' @@ -311,6 +311,7 @@ class BootLinuxConsole(LinuxKernelTest): :avocado: tags=arch:mipsel :avocado: tags=machine:malta :avocado: tags=endian:little + :avocado: tags=cpu:I7200 """ kernel_url = ('https://mipsdistros.mips.com/LinuxDistro/nanomips/' 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/' @@ -323,6 +324,7 @@ class BootLinuxConsole(LinuxKernelTest): :avocado: tags=arch:mipsel :avocado: tags=machine:malta :avocado: tags=endian:little + :avocado: tags=cpu:I7200 """ kernel_url = ('https://mipsdistros.mips.com/LinuxDistro/nanomips/' 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/' @@ -335,6 +337,7 @@ class BootLinuxConsole(LinuxKernelTest): :avocado: tags=arch:aarch64 :avocado: tags=machine:virt :avocado: tags=accel:tcg + :avocado: tags=cpu:cortex-a53 """ kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' '/linux/releases/29/Everything/aarch64/os/images/pxeboot' @@ -1168,9 +1171,9 @@ class BootLinuxConsole(LinuxKernelTest): """ :avocado: tags=arch:ppc64 :avocado: tags=machine:ppce500 + :avocado: tags=cpu:e5500 """ tar_hash = '6951d86d644b302898da2fd701739c9406527fe1' - self.vm.add_args('-cpu', 'e5500') self.do_test_advcal_2018('19', tar_hash, 'uImage') def test_ppc_g3beige(self): @@ -1212,7 +1215,7 @@ class BootLinuxConsole(LinuxKernelTest): """ :avocado: tags=arch:xtensa :avocado: tags=machine:lx60 + :avocado: tags=cpu:dc233c """ tar_hash = '49e88d9933742f0164b60839886c9739cb7a0d34' - self.vm.add_args('-cpu', 'dc233c') self.do_test_advcal_2018('02', tar_hash, 'santas-sleigh-ride.elf') diff --git a/tests/acceptance/pc_cpu_hotplug_props.py b/tests/acceptance/pc_cpu_hotplug_props.py index f48f68fc6b..2e86d5017a 100644 --- a/tests/acceptance/pc_cpu_hotplug_props.py +++ b/tests/acceptance/pc_cpu_hotplug_props.py @@ -25,11 +25,11 @@ from avocado_qemu import Test class OmittedCPUProps(Test): """ :avocado: tags=arch:x86_64 + :avocado: tags=cpu:qemu64 """ def test_no_die_id(self): self.vm.add_args('-nodefaults', '-S') self.vm.add_args('-smp', '1,sockets=2,cores=2,threads=2,maxcpus=8') - self.vm.add_args('-cpu', 'qemu64') self.vm.add_args('-device', 'qemu64-x86_64-cpu,socket-id=1,core-id=0,thread-id=0') self.vm.launch() self.assertEquals(len(self.vm.command('query-cpus-fast')), 2) diff --git a/tests/acceptance/replay_kernel.py b/tests/acceptance/replay_kernel.py index 75f80506c1..bb32b31240 100644 --- a/tests/acceptance/replay_kernel.py +++ b/tests/acceptance/replay_kernel.py @@ -392,6 +392,7 @@ class ReplayKernelSlow(ReplayKernelBase): :avocado: tags=machine:malta :avocado: tags=endian:little :avocado: tags=slowness:high + :avocado: tags=cpu:5KEc """ kernel_url = ('https://github.com/philmd/qemu-testing-blob/' 'raw/9ad2df38/mips/malta/mips64el/' @@ -412,7 +413,7 @@ class ReplayKernelSlow(ReplayKernelBase): 'rdinit=/sbin/init noreboot') console_pattern = 'Boot successful.' self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5, - args=('-initrd', initrd_path, '-cpu', '5KEc')) + args=('-initrd', initrd_path)) def do_test_mips_malta32el_nanomips(self, kernel_path_xz): kernel_path = self.workdir + "kernel" @@ -424,14 +425,14 @@ class ReplayKernelSlow(ReplayKernelBase): 'mem=256m@@0x0 ' 'console=ttyS0') console_pattern = 'Kernel command line: %s' % kernel_command_line - self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5, - args=('-cpu', 'I7200')) + self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5) def test_mips_malta32el_nanomips_4k(self): """ :avocado: tags=arch:mipsel :avocado: tags=machine:malta :avocado: tags=endian:little + :avocado: tags=cpu:I7200 """ kernel_url = ('https://mipsdistros.mips.com/LinuxDistro/nanomips/' 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/' @@ -445,6 +446,7 @@ class ReplayKernelSlow(ReplayKernelBase): :avocado: tags=arch:mipsel :avocado: tags=machine:malta :avocado: tags=endian:little + :avocado: tags=cpu:I7200 """ kernel_url = ('https://mipsdistros.mips.com/LinuxDistro/nanomips/' 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/' @@ -458,6 +460,7 @@ class ReplayKernelSlow(ReplayKernelBase): :avocado: tags=arch:mipsel :avocado: tags=machine:malta :avocado: tags=endian:little + :avocado: tags=cpu:I7200 """ kernel_url = ('https://mipsdistros.mips.com/LinuxDistro/nanomips/' 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/' diff --git a/tests/acceptance/virtio-gpu.py b/tests/acceptance/virtio-gpu.py index e7979343e9..589332c1b7 100644 --- a/tests/acceptance/virtio-gpu.py +++ b/tests/acceptance/virtio-gpu.py @@ -60,6 +60,7 @@ class VirtioGPUx86(Test): """ :avocado: tags=arch:x86_64 :avocado: tags=device:virtio-vga + :avocado: tags=cpu:host """ kernel_command_line = ( self.KERNEL_COMMON_COMMAND_LINE + "console=ttyS0 rdinit=/bin/bash" @@ -72,7 +73,6 @@ class VirtioGPUx86(Test): initrd_path = self.fetch_asset(self.INITRD_URL) self.vm.set_console() - self.vm.add_args("-cpu", "host") self.vm.add_args("-m", "2G") self.vm.add_args("-machine", "pc,accel=kvm") self.vm.add_args("-device", "virtio-vga,virgl=on") @@ -101,6 +101,7 @@ class VirtioGPUx86(Test): """ :avocado: tags=arch:x86_64 :avocado: tags=device:vhost-user-vga + :avocado: tags=cpu:host """ kernel_command_line = ( self.KERNEL_COMMON_COMMAND_LINE + "console=ttyS0 rdinit=/bin/bash" @@ -140,7 +141,6 @@ class VirtioGPUx86(Test): ) self.vm.set_console() - self.vm.add_args("-cpu", "host") self.vm.add_args("-m", "2G") self.vm.add_args("-object", "memory-backend-memfd,id=mem,size=2G") self.vm.add_args("-machine", "pc,memory-backend=mem,accel=kvm") From 555fe0c2a8d5c8a9b6dbf17670018cc2d8f062b3 Mon Sep 17 00:00:00 2001 From: Wainer dos Santos Moschetta Date: Fri, 30 Apr 2021 10:34:12 -0300 Subject: [PATCH 074/531] python/qemu: Add args property to the QEMUMachine class This added the args property to QEMUMachine so that users of the class can access and handle the list of arguments to be given to the QEMU binary. Reviewed-by: Cleber Rosa Reviewed-by: Willian Rampazzo Signed-off-by: Wainer dos Santos Moschetta Message-Id: <20210430133414.39905-6-wainersm@redhat.com> Signed-off-by: Cleber Rosa --- python/qemu/machine/machine.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index 94846dd71b..971ed7e8c6 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -316,6 +316,11 @@ class QEMUMachine: args.extend(['-device', device]) return args + @property + def args(self) -> List[str]: + """Returns the list of arguments given to the QEMU binary.""" + return self._args + def _pre_launch(self) -> None: if self._console_set: self._remove_files.append(self._console_address) From 58954ac0b59966ebd32720b183a3c7fcfc60e83d Mon Sep 17 00:00:00 2001 From: Wainer dos Santos Moschetta Date: Fri, 30 Apr 2021 10:34:13 -0300 Subject: [PATCH 075/531] tests/acceptance: Add set_vm_arg() to the Test class The set_vm_arg method is added to avocado_qemu.Test class on this change. Use that method to set (or replace) an argument to the list of arguments given to the QEMU binary. Suggested-by: Cleber Rosa Signed-off-by: Wainer dos Santos Moschetta Reviewed-by: Willian Rampazzo Message-Id: <20210430133414.39905-7-wainersm@redhat.com> Signed-off-by: Cleber Rosa --- tests/acceptance/avocado_qemu/__init__.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py index 3a218057b3..2c4fef3e14 100644 --- a/tests/acceptance/avocado_qemu/__init__.py +++ b/tests/acceptance/avocado_qemu/__init__.py @@ -251,6 +251,27 @@ class Test(avocado.Test): self._vms[name].set_machine(self.machine) return self._vms[name] + def set_vm_arg(self, arg, value): + """ + Set an argument to list of extra arguments to be given to the QEMU + binary. If the argument already exists then its value is replaced. + + :param arg: the QEMU argument, such as "-cpu" in "-cpu host" + :type arg: str + :param value: the argument value, such as "host" in "-cpu host" + :type value: str + """ + if not arg or not value: + return + if arg not in self.vm.args: + self.vm.args.extend([arg, value]) + else: + idx = self.vm.args.index(arg) + 1 + if idx < len(self.vm.args): + self.vm.args[idx] = value + else: + self.vm.args.append(value) + def tearDown(self): for vm in self._vms.values(): vm.shutdown() From 3843a32152a54092f1fc2c8eb54a03da64ad4c6d Mon Sep 17 00:00:00 2001 From: Wainer dos Santos Moschetta Date: Fri, 30 Apr 2021 10:34:14 -0300 Subject: [PATCH 076/531] tests/acceptance: Handle cpu tag on x86_cpu_model_versions tests Some test cases on x86_cpu_model_versions.py are corner cases because they need to pass extra options to the -cpu argument. Once the avocado_qemu framework will set -cpu automatically, the value should be reset. This changed those tests so to call set_vm_arg() to overwrite the -cpu value. Signed-off-by: Wainer dos Santos Moschetta Reviewed-by: Willian Rampazzo Message-Id: <20210430133414.39905-8-wainersm@redhat.com> Signed-off-by: Cleber Rosa --- tests/acceptance/x86_cpu_model_versions.py | 40 +++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/tests/acceptance/x86_cpu_model_versions.py b/tests/acceptance/x86_cpu_model_versions.py index 77ed8597a4..0e9feda62d 100644 --- a/tests/acceptance/x86_cpu_model_versions.py +++ b/tests/acceptance/x86_cpu_model_versions.py @@ -252,10 +252,13 @@ class CascadelakeArchCapabilities(avocado_qemu.Test): def test_4_1(self): """ :avocado: tags=machine:pc-i440fx-4.1 + :avocado: tags=cpu:Cascadelake-Server """ # machine-type only: self.vm.add_args('-S') - self.vm.add_args('-cpu', 'Cascadelake-Server,x-force-features=on,check=off,enforce=off') + self.set_vm_arg('-cpu', + 'Cascadelake-Server,x-force-features=on,check=off,' + 'enforce=off') self.vm.launch() self.assertFalse(self.get_cpu_prop('arch-capabilities'), 'pc-i440fx-4.1 + Cascadelake-Server should not have arch-capabilities') @@ -263,9 +266,12 @@ class CascadelakeArchCapabilities(avocado_qemu.Test): def test_4_0(self): """ :avocado: tags=machine:pc-i440fx-4.0 + :avocado: tags=cpu:Cascadelake-Server """ self.vm.add_args('-S') - self.vm.add_args('-cpu', 'Cascadelake-Server,x-force-features=on,check=off,enforce=off') + self.set_vm_arg('-cpu', + 'Cascadelake-Server,x-force-features=on,check=off,' + 'enforce=off') self.vm.launch() self.assertFalse(self.get_cpu_prop('arch-capabilities'), 'pc-i440fx-4.0 + Cascadelake-Server should not have arch-capabilities') @@ -273,10 +279,13 @@ class CascadelakeArchCapabilities(avocado_qemu.Test): def test_set_4_0(self): """ :avocado: tags=machine:pc-i440fx-4.0 + :avocado: tags=cpu:Cascadelake-Server """ # command line must override machine-type if CPU model is not versioned: self.vm.add_args('-S') - self.vm.add_args('-cpu', 'Cascadelake-Server,x-force-features=on,check=off,enforce=off,+arch-capabilities') + self.set_vm_arg('-cpu', + 'Cascadelake-Server,x-force-features=on,check=off,' + 'enforce=off,+arch-capabilities') self.vm.launch() self.assertTrue(self.get_cpu_prop('arch-capabilities'), 'pc-i440fx-4.0 + Cascadelake-Server,+arch-capabilities should have arch-capabilities') @@ -284,9 +293,12 @@ class CascadelakeArchCapabilities(avocado_qemu.Test): def test_unset_4_1(self): """ :avocado: tags=machine:pc-i440fx-4.1 + :avocado: tags=cpu:Cascadelake-Server """ self.vm.add_args('-S') - self.vm.add_args('-cpu', 'Cascadelake-Server,x-force-features=on,check=off,enforce=off,-arch-capabilities') + self.set_vm_arg('-cpu', + 'Cascadelake-Server,x-force-features=on,check=off,' + 'enforce=off,-arch-capabilities') self.vm.launch() self.assertFalse(self.get_cpu_prop('arch-capabilities'), 'pc-i440fx-4.1 + Cascadelake-Server,-arch-capabilities should not have arch-capabilities') @@ -294,10 +306,13 @@ class CascadelakeArchCapabilities(avocado_qemu.Test): def test_v1_4_0(self): """ :avocado: tags=machine:pc-i440fx-4.0 + :avocado: tags=cpu:Cascadelake-Server """ # versioned CPU model overrides machine-type: self.vm.add_args('-S') - self.vm.add_args('-cpu', 'Cascadelake-Server-v1,x-force-features=on,check=off,enforce=off') + self.set_vm_arg('-cpu', + 'Cascadelake-Server-v1,x-force-features=on,check=off,' + 'enforce=off') self.vm.launch() self.assertFalse(self.get_cpu_prop('arch-capabilities'), 'pc-i440fx-4.0 + Cascadelake-Server-v1 should not have arch-capabilities') @@ -305,9 +320,12 @@ class CascadelakeArchCapabilities(avocado_qemu.Test): def test_v2_4_0(self): """ :avocado: tags=machine:pc-i440fx-4.0 + :avocado: tags=cpu:Cascadelake-Server """ self.vm.add_args('-S') - self.vm.add_args('-cpu', 'Cascadelake-Server-v2,x-force-features=on,check=off,enforce=off') + self.set_vm_arg('-cpu', + 'Cascadelake-Server-v2,x-force-features=on,check=off,' + 'enforce=off') self.vm.launch() self.assertTrue(self.get_cpu_prop('arch-capabilities'), 'pc-i440fx-4.0 + Cascadelake-Server-v2 should have arch-capabilities') @@ -315,10 +333,13 @@ class CascadelakeArchCapabilities(avocado_qemu.Test): def test_v1_set_4_0(self): """ :avocado: tags=machine:pc-i440fx-4.0 + :avocado: tags=cpu:Cascadelake-Server """ # command line must override machine-type and versioned CPU model: self.vm.add_args('-S') - self.vm.add_args('-cpu', 'Cascadelake-Server-v1,x-force-features=on,check=off,enforce=off,+arch-capabilities') + self.set_vm_arg('-cpu', + 'Cascadelake-Server-v1,x-force-features=on,check=off,' + 'enforce=off,+arch-capabilities') self.vm.launch() self.assertTrue(self.get_cpu_prop('arch-capabilities'), 'pc-i440fx-4.0 + Cascadelake-Server-v1,+arch-capabilities should have arch-capabilities') @@ -326,9 +347,12 @@ class CascadelakeArchCapabilities(avocado_qemu.Test): def test_v2_unset_4_1(self): """ :avocado: tags=machine:pc-i440fx-4.1 + :avocado: tags=cpu:Cascadelake-Server """ self.vm.add_args('-S') - self.vm.add_args('-cpu', 'Cascadelake-Server-v2,x-force-features=on,check=off,enforce=off,-arch-capabilities') + self.set_vm_arg('-cpu', + 'Cascadelake-Server-v2,x-force-features=on,check=off,' + 'enforce=off,-arch-capabilities') self.vm.launch() self.assertFalse(self.get_cpu_prop('arch-capabilities'), 'pc-i440fx-4.1 + Cascadelake-Server-v2,-arch-capabilities should not have arch-capabilities') From 6f651a6d84b64060aa77373a72ba02ff61ad9911 Mon Sep 17 00:00:00 2001 From: Wainer dos Santos Moschetta Date: Wed, 30 Jun 2021 15:45:46 -0300 Subject: [PATCH 077/531] python: Configure tox to skip missing interpreters Currently tox tests against the installed interpreters, however if any supported interpreter is absent then it will return fail. It seems not reasonable to expect developers to have all supported interpreters installed on their systems. Luckily tox can be configured to skip missing interpreters. This changed the tox setup so that missing interpreters are skipped by default. On the CI, however, we still want to enforce it tests against all supported. This way on CI the --skip-missing-interpreters=false option is passed to tox. Signed-off-by: Wainer dos Santos Moschetta Message-Id: <20210630184546.456582-1-wainersm@redhat.com> Reviewed-by: Willian Rampazzo Reviewed-by: John Snow Signed-off-by: Cleber Rosa --- .gitlab-ci.d/static_checks.yml | 1 + python/Makefile | 5 ++++- python/setup.cfg | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.d/static_checks.yml b/.gitlab-ci.d/static_checks.yml index b01f6ec231..96dbd9e310 100644 --- a/.gitlab-ci.d/static_checks.yml +++ b/.gitlab-ci.d/static_checks.yml @@ -43,6 +43,7 @@ check-python-tox: - make -C python check-tox variables: GIT_DEPTH: 1 + QEMU_TOX_EXTRA_ARGS: --skip-missing-interpreters=false needs: job: python-container allow_failure: true diff --git a/python/Makefile b/python/Makefile index ac46ae33e7..fe27a3e12e 100644 --- a/python/Makefile +++ b/python/Makefile @@ -1,4 +1,5 @@ QEMU_VENV_DIR=.dev-venv +QEMU_TOX_EXTRA_ARGS ?= .PHONY: help help: @@ -15,6 +16,8 @@ help: @echo " These tests use the newest dependencies." @echo " Requires: Python 3.6 - 3.10, and tox." @echo " Hint (Fedora): 'sudo dnf install python3-tox python3.10'" + @echo " The variable QEMU_TOX_EXTRA_ARGS can be use to pass extra" + @echo " arguments to tox". @echo "" @echo "make check-dev:" @echo " Run tests in a venv against your default python3 version." @@ -87,7 +90,7 @@ check: .PHONY: check-tox check-tox: - @tox + @tox $(QEMU_TOX_EXTRA_ARGS) .PHONY: clean clean: diff --git a/python/setup.cfg b/python/setup.cfg index 11f71d5312..14bab90288 100644 --- a/python/setup.cfg +++ b/python/setup.cfg @@ -121,6 +121,7 @@ multi_line_output=3 [tox:tox] envlist = py36, py37, py38, py39, py310 +skip_missing_interpreters = true [testenv] allowlist_externals = make From 414e9ae345c5372ece6699342f8afe8d2db107d0 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Thu, 15 Apr 2021 17:51:35 -0400 Subject: [PATCH 078/531] Acceptance tests: do not try to reuse packages from the system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The premise behind the original behavior is that it would save people from downloading Avocado (and other dependencies) if already installed on the system. To be honest, I think it's extremely rare that the same versions described as dependencies will be available on most systems. But, the biggest motivations here are that: 1) Hacking on QEMU in the same system used to develop Avocado leads to confusion with regards to the exact bits that are being used; 2) Not reusing Python packages from system wide installations gives extra assurance that the same behavior will be seen from tests run on different machines; With regards to downloads, pip already caches the downloaded wheels and tarballs under ~/.cache/pip, so there should not be more than one download even if the venv is destroyed and recreated. Signed-off-by: Cleber Rosa Message-Id: <20210415215141.1865467-3-crosa@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Willian Rampazzo Reviewed-by: Wainer dos Santos Moschetta Signed-off-by: Cleber Rosa --- tests/Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index e4dcb17329..6e16c05f10 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -96,7 +96,7 @@ AVOCADO_TAGS=$(patsubst %-softmmu,-t arch:%, $(filter %-softmmu,$(TARGETS))) $(TESTS_VENV_DIR): $(TESTS_VENV_REQ) $(call quiet-command, \ - $(PYTHON) -m venv --system-site-packages $@, \ + $(PYTHON) -m venv $@, \ VENV, $@) $(call quiet-command, \ $(TESTS_VENV_DIR)/bin/python -m pip -q install -r $(TESTS_VENV_REQ), \ From 9a94d8ae97cd25d71565b99682bb7e49133c1af3 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Thu, 15 Apr 2021 17:51:36 -0400 Subject: [PATCH 079/531] tests/acceptance/linux_ssh_mips_malta.py: drop identical setUp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These tests' setUp do not do anything beyong what their base class do. And while they do decorate the setUp() we can decorate the classes instead, so no functionality is lost here. This is possible because since Avocado 76.0 we can decorate setUp() directly. Signed-off-by: Cleber Rosa Message-Id: <20210415215141.1865467-4-crosa@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Willian Rampazzo [PMD: added note to commit message about Avocado feature/version] Signed-off-by: Cleber Rosa --- tests/acceptance/linux_ssh_mips_malta.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/acceptance/linux_ssh_mips_malta.py b/tests/acceptance/linux_ssh_mips_malta.py index 61c9079d04..4de1947418 100644 --- a/tests/acceptance/linux_ssh_mips_malta.py +++ b/tests/acceptance/linux_ssh_mips_malta.py @@ -19,6 +19,8 @@ from avocado.utils import archive from avocado.utils import ssh +@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') +@skipUnless(ssh.SSH_CLIENT_BINARY, 'No SSH client available') class LinuxSSH(Test, LinuxSSHMixIn): timeout = 150 # Not for 'configure --enable-debug --enable-debug-tcg' @@ -65,11 +67,6 @@ class LinuxSSH(Test, LinuxSSHMixIn): kernel_hash = self.IMAGE_INFO[endianess]['kernel_hash'][wordsize] return kernel_url, kernel_hash - @skipUnless(ssh.SSH_CLIENT_BINARY, 'No SSH client available') - @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') - def setUp(self): - super(LinuxSSH, self).setUp() - def ssh_disconnect_vm(self): self.ssh_session.quit() From c4e2d499c94fb7d6ea43d28e2613559861ef5d79 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Thu, 15 Apr 2021 17:51:38 -0400 Subject: [PATCH 080/531] tests/acceptance/cpu_queries.py: use the proper logging channels The test contains methods for the proper log of test related information. Let's use that and remove the print and the unused logging import. Reference: https://avocado-framework.readthedocs.io/en/87.0/api/test/avocado.html#avocado.Test.log Signed-off-by: Cleber Rosa Message-Id: <20210415215141.1865467-6-crosa@redhat.com> Reviewed-by: Willian Rampazzo Reviewed-by: Wainer dos Santos Moschetta Signed-off-by: Cleber Rosa --- tests/acceptance/cpu_queries.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/acceptance/cpu_queries.py b/tests/acceptance/cpu_queries.py index 293dccb89a..cc9e380cc7 100644 --- a/tests/acceptance/cpu_queries.py +++ b/tests/acceptance/cpu_queries.py @@ -8,8 +8,6 @@ # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. -import logging - from avocado_qemu import Test class QueryCPUModelExpansion(Test): @@ -27,7 +25,7 @@ class QueryCPUModelExpansion(Test): cpus = self.vm.command('query-cpu-definitions') for c in cpus: - print(repr(c)) + self.log.info("Checking CPU: %s", c) self.assertNotIn('', c['unavailable-features'], c['name']) for c in cpus: From bca579e61954f6dcdd11d88c9b9c59f22a3e695d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 29 Jun 2021 14:57:04 +0100 Subject: [PATCH 081/531] crypto: remove conditional around 3DES crypto test cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The main method checks whether the cipher choice is supported at runtime, so there is no need for compile time conditions. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- tests/unit/test-crypto-cipher.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/unit/test-crypto-cipher.c b/tests/unit/test-crypto-cipher.c index 280319a223..fd0a8de34c 100644 --- a/tests/unit/test-crypto-cipher.c +++ b/tests/unit/test-crypto-cipher.c @@ -165,7 +165,6 @@ static QCryptoCipherTestData test_data[] = { "ffd29f1bb5596ad94ea2d8e6196b7f09" "30d8ed0bf2773af36dd82a6280c20926", }, -#if defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT) { /* Borrowed from linux-kernel crypto/testmgr.h */ .path = "/crypto/cipher/3des-cbc", @@ -283,7 +282,6 @@ static QCryptoCipherTestData test_data[] = { "407772c2ea0e3a7846b991b6e73d5142" "fd51b0c62c6313785ceefccfc4700034", }, -#endif { /* RFC 2144, Appendix B.1 */ .path = "/crypto/cipher/cast5-128", From 1685983133fe855553b337cb5d34d430e0aceca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 30 Jun 2021 12:41:56 +0100 Subject: [PATCH 082/531] crypto: remove obsolete crypto test condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we now require gcrypt >= 1.8.0, there is no need to exclude the pbkdf test case. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- tests/unit/test-crypto-pbkdf.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/unit/test-crypto-pbkdf.c b/tests/unit/test-crypto-pbkdf.c index c50fd639d2..43c417f6b4 100644 --- a/tests/unit/test-crypto-pbkdf.c +++ b/tests/unit/test-crypto-pbkdf.c @@ -229,10 +229,8 @@ static QCryptoPbkdfTestData test_data[] = { }, /* non-RFC misc test data */ -#ifdef CONFIG_NETTLE { - /* empty password test. - * Broken with libgcrypt <= 1.5.0, hence CONFIG_NETTLE */ + /* empty password test. */ .path = "/crypto/pbkdf/nonrfc/sha1/iter2", .hash = QCRYPTO_HASH_ALG_SHA1, .iterations = 2, @@ -244,7 +242,6 @@ static QCryptoPbkdfTestData test_data[] = { "\xbf\x03\xe1\x1c\x71\xca\x79\x4e\x07\x97", .nout = 20 }, -#endif { /* Password exceeds block size test */ .path = "/crypto/pbkdf/nonrfc/sha256/iter1200", From 295736cfc82ae9019cd647ef012a71f4e277e864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 8 Oct 2020 17:41:21 +0100 Subject: [PATCH 083/531] crypto: skip essiv ivgen tests if AES+ECB isn't available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- tests/unit/test-crypto-ivgen.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/unit/test-crypto-ivgen.c b/tests/unit/test-crypto-ivgen.c index f581e6aba7..29630ed348 100644 --- a/tests/unit/test-crypto-ivgen.c +++ b/tests/unit/test-crypto-ivgen.c @@ -136,8 +136,15 @@ struct QCryptoIVGenTestData { static void test_ivgen(const void *opaque) { const struct QCryptoIVGenTestData *data = opaque; - uint8_t *iv = g_new0(uint8_t, data->niv); - QCryptoIVGen *ivgen = qcrypto_ivgen_new( + g_autofree uint8_t *iv = g_new0(uint8_t, data->niv); + g_autoptr(QCryptoIVGen) ivgen = NULL; + + if (!qcrypto_cipher_supports(data->cipheralg, + QCRYPTO_CIPHER_MODE_ECB)) { + return; + } + + ivgen = qcrypto_ivgen_new( data->ivalg, data->cipheralg, data->hashalg, @@ -152,9 +159,6 @@ static void test_ivgen(const void *opaque) &error_abort); g_assert(memcmp(iv, data->iv, data->niv) == 0); - - qcrypto_ivgen_free(ivgen); - g_free(iv); } int main(int argc, char **argv) From 7ea450b0f02f83637794af4991f0b684608d6a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 25 Jun 2021 18:48:41 +0100 Subject: [PATCH 084/531] crypto: use &error_fatal in crypto tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using error_fatal provides better diagnostics when tests failed, than using asserts, because we see the text of the error message. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- tests/unit/test-crypto-hash.c | 13 +++++++------ tests/unit/test-crypto-hmac.c | 28 ++++++++-------------------- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/tests/unit/test-crypto-hash.c b/tests/unit/test-crypto-hash.c index ce7d0ab9b5..1f4abb822b 100644 --- a/tests/unit/test-crypto-hash.c +++ b/tests/unit/test-crypto-hash.c @@ -104,7 +104,7 @@ static void test_hash_alloc(void) strlen(INPUT_TEXT), &result, &resultlen, - NULL); + &error_fatal); g_assert(ret == 0); g_assert(resultlen == expected_lens[i]); @@ -139,7 +139,7 @@ static void test_hash_prealloc(void) strlen(INPUT_TEXT), &result, &resultlen, - NULL); + &error_fatal); g_assert(ret == 0); g_assert(resultlen == expected_lens[i]); @@ -176,7 +176,7 @@ static void test_hash_iov(void) iov, 3, &result, &resultlen, - NULL); + &error_fatal); g_assert(ret == 0); g_assert(resultlen == expected_lens[i]); for (j = 0; j < resultlen; j++) { @@ -210,7 +210,7 @@ static void test_hash_digest(void) INPUT_TEXT, strlen(INPUT_TEXT), &digest, - NULL); + &error_fatal); g_assert(ret == 0); g_assert_cmpstr(digest, ==, expected_outputs[i]); g_free(digest); @@ -234,7 +234,7 @@ static void test_hash_base64(void) INPUT_TEXT, strlen(INPUT_TEXT), &digest, - NULL); + &error_fatal); g_assert(ret == 0); g_assert_cmpstr(digest, ==, expected_outputs_b64[i]); g_free(digest); @@ -243,7 +243,8 @@ static void test_hash_base64(void) int main(int argc, char **argv) { - g_assert(qcrypto_init(NULL) == 0); + int ret = qcrypto_init(&error_fatal); + g_assert(ret == 0); g_test_init(&argc, &argv, NULL); g_test_add_func("/crypto/hash/iov", test_hash_iov); diff --git a/tests/unit/test-crypto-hmac.c b/tests/unit/test-crypto-hmac.c index ee55382a3c..23eb724d94 100644 --- a/tests/unit/test-crypto-hmac.c +++ b/tests/unit/test-crypto-hmac.c @@ -89,7 +89,6 @@ static void test_hmac_alloc(void) QCryptoHmac *hmac = NULL; uint8_t *result = NULL; size_t resultlen = 0; - Error *err = NULL; const char *exp_output = NULL; int ret; size_t j; @@ -101,14 +100,12 @@ static void test_hmac_alloc(void) exp_output = data->hex_digest; hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY, - strlen(KEY), &err); - g_assert(err == NULL); + strlen(KEY), &error_fatal); g_assert(hmac != NULL); ret = qcrypto_hmac_bytes(hmac, (const char *)INPUT_TEXT, strlen(INPUT_TEXT), &result, - &resultlen, &err); - g_assert(err == NULL); + &resultlen, &error_fatal); g_assert(ret == 0); for (j = 0; j < resultlen; j++) { @@ -131,7 +128,6 @@ static void test_hmac_prealloc(void) QCryptoHmac *hmac = NULL; uint8_t *result = NULL; size_t resultlen = 0; - Error *err = NULL; const char *exp_output = NULL; int ret; size_t j; @@ -146,14 +142,12 @@ static void test_hmac_prealloc(void) result = g_new0(uint8_t, resultlen); hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY, - strlen(KEY), &err); - g_assert(err == NULL); + strlen(KEY), &error_fatal); g_assert(hmac != NULL); ret = qcrypto_hmac_bytes(hmac, (const char *)INPUT_TEXT, strlen(INPUT_TEXT), &result, - &resultlen, &err); - g_assert(err == NULL); + &resultlen, &error_fatal); g_assert(ret == 0); exp_output = data->hex_digest; @@ -177,7 +171,6 @@ static void test_hmac_iov(void) QCryptoHmac *hmac = NULL; uint8_t *result = NULL; size_t resultlen = 0; - Error *err = NULL; const char *exp_output = NULL; int ret; size_t j; @@ -194,13 +187,11 @@ static void test_hmac_iov(void) exp_output = data->hex_digest; hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY, - strlen(KEY), &err); - g_assert(err == NULL); + strlen(KEY), &error_fatal); g_assert(hmac != NULL); ret = qcrypto_hmac_bytesv(hmac, iov, 3, &result, - &resultlen, &err); - g_assert(err == NULL); + &resultlen, &error_fatal); g_assert(ret == 0); for (j = 0; j < resultlen; j++) { @@ -222,7 +213,6 @@ static void test_hmac_digest(void) QCryptoHmacTestData *data = &test_data[i]; QCryptoHmac *hmac = NULL; uint8_t *result = NULL; - Error *err = NULL; const char *exp_output = NULL; int ret; @@ -233,14 +223,12 @@ static void test_hmac_digest(void) exp_output = data->hex_digest; hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY, - strlen(KEY), &err); - g_assert(err == NULL); + strlen(KEY), &error_fatal); g_assert(hmac != NULL); ret = qcrypto_hmac_digest(hmac, (const char *)INPUT_TEXT, strlen(INPUT_TEXT), (char **)&result, - &err); - g_assert(err == NULL); + &error_fatal); g_assert(ret == 0); g_assert_cmpstr((const char *)result, ==, exp_output); From 1741093b0a782541b7508ca5ff26836f179e864b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 29 Jun 2021 17:08:28 +0100 Subject: [PATCH 085/531] crypto: fix gcrypt min version 1.8 regression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The min gcrypt was bumped: commit b33a84632a3759c00320fd80923aa963c11207fc Author: Daniel P. Berrangé Date: Fri May 14 13:04:08 2021 +0100 crypto: bump min gcrypt to 1.8.0, dropping RHEL-7 support but this was accidentally lost in conflict resolution for commit 5761251138cb69c310e9df7dfc82c4c6fd2444e4 Author: Paolo Bonzini Date: Thu Jun 3 11:15:26 2021 +0200 configure, meson: convert crypto detection to meson Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index b0e2b9a8a0..e7de68d795 100644 --- a/meson.build +++ b/meson.build @@ -839,7 +839,7 @@ elif (not get_option('nettle').auto() or have_system) and not get_option('gcrypt endif endif if (not get_option('gcrypt').auto() or have_system) and not nettle.found() - gcrypt = dependency('libgcrypt', version: '>=1.5', + gcrypt = dependency('libgcrypt', version: '>=1.8', method: 'config-tool', required: get_option('gcrypt'), kwargs: static_kwargs) From ea7a6802c75acdc199e434dfd9d4093dbdb18863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 25 Jun 2021 18:29:52 +0100 Subject: [PATCH 086/531] crypto: drop gcrypt thread initialization code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is only required on gcrypt < 1.6.0, and is thus obsolete since commit b33a84632a3759c00320fd80923aa963c11207fc Author: Daniel P. Berrangé Date: Fri May 14 13:04:08 2021 +0100 crypto: bump min gcrypt to 1.8.0, dropping RHEL-7 support Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- crypto/init.c | 62 --------------------------------------------------- 1 file changed, 62 deletions(-) diff --git a/crypto/init.c b/crypto/init.c index ea233b9192..fb7f1bff10 100644 --- a/crypto/init.c +++ b/crypto/init.c @@ -35,21 +35,6 @@ #include "crypto/random.h" /* #define DEBUG_GNUTLS */ - -/* - * We need to init gcrypt threading if - * - * - gcrypt < 1.6.0 - * - */ - -#if (defined(CONFIG_GCRYPT) && \ - (GCRYPT_VERSION_NUMBER < 0x010600)) -#define QCRYPTO_INIT_GCRYPT_THREADS -#else -#undef QCRYPTO_INIT_GCRYPT_THREADS -#endif - #ifdef DEBUG_GNUTLS static void qcrypto_gnutls_log(int level, const char *str) { @@ -57,55 +42,8 @@ static void qcrypto_gnutls_log(int level, const char *str) } #endif -#ifdef QCRYPTO_INIT_GCRYPT_THREADS -static int qcrypto_gcrypt_mutex_init(void **priv) -{ \ - QemuMutex *lock = NULL; - lock = g_new0(QemuMutex, 1); - qemu_mutex_init(lock); - *priv = lock; - return 0; -} - -static int qcrypto_gcrypt_mutex_destroy(void **priv) -{ - QemuMutex *lock = *priv; - qemu_mutex_destroy(lock); - g_free(lock); - return 0; -} - -static int qcrypto_gcrypt_mutex_lock(void **priv) -{ - QemuMutex *lock = *priv; - qemu_mutex_lock(lock); - return 0; -} - -static int qcrypto_gcrypt_mutex_unlock(void **priv) -{ - QemuMutex *lock = *priv; - qemu_mutex_unlock(lock); - return 0; -} - -static struct gcry_thread_cbs qcrypto_gcrypt_thread_impl = { - (GCRY_THREAD_OPTION_PTHREAD | (GCRY_THREAD_OPTION_VERSION << 8)), - NULL, - qcrypto_gcrypt_mutex_init, - qcrypto_gcrypt_mutex_destroy, - qcrypto_gcrypt_mutex_lock, - qcrypto_gcrypt_mutex_unlock, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; -#endif /* QCRYPTO_INIT_GCRYPT */ - int qcrypto_init(Error **errp) { -#ifdef QCRYPTO_INIT_GCRYPT_THREADS - gcry_control(GCRYCTL_SET_THREAD_CBS, &qcrypto_gcrypt_thread_impl); -#endif /* QCRYPTO_INIT_GCRYPT_THREADS */ - #ifdef CONFIG_GNUTLS int ret; ret = gnutls_global_init(); From 7b40aa4b968a5674a75bbf7e25b88927fcb9ae01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 29 Jun 2021 17:11:59 +0100 Subject: [PATCH 087/531] crypto: drop custom XTS support in gcrypt driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The XTS cipher mode was introduced in gcrypt 1.8.0, which matches QEMU's current minimum version. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- crypto/cipher-gcrypt.c.inc | 127 ------------------------------------- meson.build | 14 +--- 2 files changed, 1 insertion(+), 140 deletions(-) diff --git a/crypto/cipher-gcrypt.c.inc b/crypto/cipher-gcrypt.c.inc index 42d4137534..3aab08a1a9 100644 --- a/crypto/cipher-gcrypt.c.inc +++ b/crypto/cipher-gcrypt.c.inc @@ -18,10 +18,6 @@ * */ -#ifdef CONFIG_QEMU_PRIVATE_XTS -#include "crypto/xts.h" -#endif - #include bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, @@ -59,10 +55,6 @@ typedef struct QCryptoCipherGcrypt { QCryptoCipher base; gcry_cipher_hd_t handle; size_t blocksize; -#ifdef CONFIG_QEMU_PRIVATE_XTS - gcry_cipher_hd_t tweakhandle; - uint8_t iv[XTS_BLOCK_SIZE]; -#endif } QCryptoCipherGcrypt; @@ -178,90 +170,6 @@ static const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = { .cipher_free = qcrypto_gcrypt_ctx_free, }; -#ifdef CONFIG_QEMU_PRIVATE_XTS -static void qcrypto_gcrypt_xts_ctx_free(QCryptoCipher *cipher) -{ - QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base); - - gcry_cipher_close(ctx->tweakhandle); - qcrypto_gcrypt_ctx_free(cipher); -} - -static void qcrypto_gcrypt_xts_wrape(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - gcry_error_t err; - err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); - g_assert(err == 0); -} - -static void qcrypto_gcrypt_xts_wrapd(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - gcry_error_t err; - err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); - g_assert(err == 0); -} - -static int qcrypto_gcrypt_xts_encrypt(QCryptoCipher *cipher, const void *in, - void *out, size_t len, Error **errp) -{ - QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base); - - if (len & (ctx->blocksize - 1)) { - error_setg(errp, "Length %zu must be a multiple of block size %zu", - len, ctx->blocksize); - return -1; - } - - xts_encrypt(ctx->handle, ctx->tweakhandle, - qcrypto_gcrypt_xts_wrape, qcrypto_gcrypt_xts_wrapd, - ctx->iv, len, out, in); - return 0; -} - -static int qcrypto_gcrypt_xts_decrypt(QCryptoCipher *cipher, const void *in, - void *out, size_t len, Error **errp) -{ - QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base); - - if (len & (ctx->blocksize - 1)) { - error_setg(errp, "Length %zu must be a multiple of block size %zu", - len, ctx->blocksize); - return -1; - } - - xts_decrypt(ctx->handle, ctx->tweakhandle, - qcrypto_gcrypt_xts_wrape, qcrypto_gcrypt_xts_wrapd, - ctx->iv, len, out, in); - return 0; -} - -static int qcrypto_gcrypt_xts_setiv(QCryptoCipher *cipher, - const uint8_t *iv, size_t niv, - Error **errp) -{ - QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base); - - if (niv != ctx->blocksize) { - error_setg(errp, "Expected IV size %zu not %zu", - ctx->blocksize, niv); - return -1; - } - - memcpy(ctx->iv, iv, niv); - return 0; -} - -static const struct QCryptoCipherDriver qcrypto_gcrypt_xts_driver = { - .cipher_encrypt = qcrypto_gcrypt_xts_encrypt, - .cipher_decrypt = qcrypto_gcrypt_xts_decrypt, - .cipher_setiv = qcrypto_gcrypt_xts_setiv, - .cipher_free = qcrypto_gcrypt_xts_ctx_free, -}; -#endif /* CONFIG_QEMU_PRIVATE_XTS */ - - static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, QCryptoCipherMode mode, const uint8_t *key, @@ -323,12 +231,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, gcrymode = GCRY_CIPHER_MODE_ECB; break; case QCRYPTO_CIPHER_MODE_XTS: -#ifdef CONFIG_QEMU_PRIVATE_XTS - drv = &qcrypto_gcrypt_xts_driver; - gcrymode = GCRY_CIPHER_MODE_ECB; -#else gcrymode = GCRY_CIPHER_MODE_XTS; -#endif break; case QCRYPTO_CIPHER_MODE_CBC: gcrymode = GCRY_CIPHER_MODE_CBC; @@ -354,23 +257,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, } ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg); -#ifdef CONFIG_QEMU_PRIVATE_XTS - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - if (ctx->blocksize != XTS_BLOCK_SIZE) { - error_setg(errp, - "Cipher block size %zu must equal XTS block size %d", - ctx->blocksize, XTS_BLOCK_SIZE); - goto error; - } - err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0); - if (err != 0) { - error_setg(errp, "Cannot initialize cipher: %s", - gcry_strerror(err)); - goto error; - } - } -#endif - if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) { /* We're using standard DES cipher from gcrypt, so we need * to munge the key so that the results are the same as the @@ -380,16 +266,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey); g_free(rfbkey); } else { -#ifdef CONFIG_QEMU_PRIVATE_XTS - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - nkey /= 2; - err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey); - if (err != 0) { - error_setg(errp, "Cannot set key: %s", gcry_strerror(err)); - goto error; - } - } -#endif err = gcry_cipher_setkey(ctx->handle, key, nkey); } if (err != 0) { @@ -400,9 +276,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, return &ctx->base; error: -#ifdef CONFIG_QEMU_PRIVATE_XTS - gcry_cipher_close(ctx->tweakhandle); -#endif gcry_cipher_close(ctx->handle); g_free(ctx); return NULL; diff --git a/meson.build b/meson.build index e7de68d795..a96c8b858c 100644 --- a/meson.build +++ b/meson.build @@ -843,16 +843,7 @@ if (not get_option('gcrypt').auto() or have_system) and not nettle.found() method: 'config-tool', required: get_option('gcrypt'), kwargs: static_kwargs) - if gcrypt.found() and cc.compiles(''' - #include - int main(void) { - gcry_cipher_hd_t handle; - gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_XTS, 0); - return 0; - } - ''', dependencies: gcrypt) - xts = 'gcrypt' - endif + xts = 'gcrypt' # Debian has removed -lgpg-error from libgcrypt-config # as it "spreads unnecessary dependencies" which in # turn breaks static builds... @@ -2970,9 +2961,6 @@ summary_info += {'TLS priority': config_host['CONFIG_TLS_PRIORITY']} summary_info += {'GNUTLS support': gnutls.found()} # TODO: add back version summary_info += {'libgcrypt': gcrypt.found()} -if gcrypt.found() - summary_info += {' XTS': xts != 'private'} -endif # TODO: add back version summary_info += {'nettle': nettle.found()} if nettle.found() From f8157e100c0ed7c0b6ca98ce20c969e1f6dcb968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 29 Jun 2021 13:09:16 +0100 Subject: [PATCH 088/531] crypto: add crypto tests for single block DES-ECB and DES-CBC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GNUTLS crypto provider doesn't support DES-ECB, only DES-CBC. We can use the latter to simulate the former, if we encrypt only 1 block (8 bytes) of data at a time, using an all-zeros IV. This is a very inefficient way to use the QCryptoCipher APIs, but since the VNC authentication challenge is only 16 bytes, this is acceptable. No other part of QEMU should be using DES. This test case demonstrates the equivalence of ECB and CBC for the single-block case. Signed-off-by: Daniel P. Berrangé --- tests/unit/test-crypto-cipher.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/unit/test-crypto-cipher.c b/tests/unit/test-crypto-cipher.c index fd0a8de34c..7dca7b26e4 100644 --- a/tests/unit/test-crypto-cipher.c +++ b/tests/unit/test-crypto-cipher.c @@ -149,6 +149,29 @@ static QCryptoCipherTestData test_data[] = { "39f23369a9d9bacfa530e26304231461" "b2eb05e2c39be9fcda6c19078c6a9d1b", }, + { + /* + * Testing 'password' as plaintext fits + * in single AES block, and gives identical + * ciphertext in ECB and CBC modes + */ + .path = "/crypto/cipher/des-rfb-ecb-56-one-block", + .alg = QCRYPTO_CIPHER_ALG_DES_RFB, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "0123456789abcdef", + .plaintext = "70617373776f7264", + .ciphertext = "73fa80b66134e403", + }, + { + /* See previous comment */ + .path = "/crypto/cipher/des-rfb-cbc-56-one-block", + .alg = QCRYPTO_CIPHER_ALG_DES_RFB, + .mode = QCRYPTO_CIPHER_MODE_CBC, + .key = "0123456789abcdef", + .iv = "0000000000000000", + .plaintext = "70617373776f7264", + .ciphertext = "73fa80b66134e403", + }, { .path = "/crypto/cipher/des-rfb-ecb-56", .alg = QCRYPTO_CIPHER_ALG_DES_RFB, From 21407ddf967f9b6f9ea22ab3a1644f6b29d53255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 2 Jul 2021 17:00:32 +0100 Subject: [PATCH 089/531] crypto: delete built-in DES implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The built-in DES implementation is used for the VNC server password authentication scheme. When building system emulators it is reasonable to expect that an external crypto library is being used. It is thus not worth keeping a home grown DES implementation in tree. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- crypto/cipher-builtin.c.inc | 72 ------- crypto/desrfb.c | 416 ------------------------------------ crypto/meson.build | 1 - 3 files changed, 489 deletions(-) delete mode 100644 crypto/desrfb.c diff --git a/crypto/cipher-builtin.c.inc b/crypto/cipher-builtin.c.inc index 7597cf4a10..70743f253c 100644 --- a/crypto/cipher-builtin.c.inc +++ b/crypto/cipher-builtin.c.inc @@ -19,7 +19,6 @@ */ #include "crypto/aes.h" -#include "crypto/desrfb.h" #include "crypto/xts.h" typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext; @@ -265,69 +264,10 @@ static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_xts = { }; -typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB; -struct QCryptoCipherBuiltinDESRFB { - QCryptoCipher base; - - /* C.f. alg_key_len[QCRYPTO_CIPHER_ALG_DES_RFB] */ - uint8_t key[8]; -}; - -static int qcrypto_cipher_encrypt_des_rfb(QCryptoCipher *cipher, - const void *in, void *out, - size_t len, Error **errp) -{ - QCryptoCipherBuiltinDESRFB *ctx - = container_of(cipher, QCryptoCipherBuiltinDESRFB, base); - size_t i; - - if (!qcrypto_length_check(len, 8, errp)) { - return -1; - } - - deskey(ctx->key, EN0); - - for (i = 0; i < len; i += 8) { - des((void *)in + i, out + i); - } - - return 0; -} - -static int qcrypto_cipher_decrypt_des_rfb(QCryptoCipher *cipher, - const void *in, void *out, - size_t len, Error **errp) -{ - QCryptoCipherBuiltinDESRFB *ctx - = container_of(cipher, QCryptoCipherBuiltinDESRFB, base); - size_t i; - - if (!qcrypto_length_check(len, 8, errp)) { - return -1; - } - - deskey(ctx->key, DE1); - - for (i = 0; i < len; i += 8) { - des((void *)in + i, out + i); - } - - return 0; -} - -static const struct QCryptoCipherDriver qcrypto_cipher_des_rfb_driver = { - .cipher_encrypt = qcrypto_cipher_encrypt_des_rfb, - .cipher_decrypt = qcrypto_cipher_decrypt_des_rfb, - .cipher_setiv = qcrypto_cipher_no_setiv, - .cipher_free = qcrypto_cipher_ctx_free, -}; - bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, QCryptoCipherMode mode) { switch (alg) { - case QCRYPTO_CIPHER_ALG_DES_RFB: - return mode == QCRYPTO_CIPHER_MODE_ECB; case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_256: @@ -356,18 +296,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, } switch (alg) { - case QCRYPTO_CIPHER_ALG_DES_RFB: - if (mode == QCRYPTO_CIPHER_MODE_ECB) { - QCryptoCipherBuiltinDESRFB *ctx; - - ctx = g_new0(QCryptoCipherBuiltinDESRFB, 1); - ctx->base.driver = &qcrypto_cipher_des_rfb_driver; - memcpy(ctx->key, key, sizeof(ctx->key)); - - return &ctx->base; - } - goto bad_mode; - case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_256: diff --git a/crypto/desrfb.c b/crypto/desrfb.c deleted file mode 100644 index b2a105ebbc..0000000000 --- a/crypto/desrfb.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * This is D3DES (V5.09) by Richard Outerbridge with the double and - * triple-length support removed for use in VNC. Also the bytebit[] array - * has been reversed so that the most significant bit in each byte of the - * key is ignored, not the least significant. - * - * These changes are: - * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. - * - * This software 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. - */ - -/* D3DES (V5.09) - - * - * A portable, public domain, version of the Data Encryption Standard. - * - * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge. - * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation - * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis - * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau, - * for humouring me on. - * - * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. - * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. - */ - -#include "qemu/osdep.h" -#include "crypto/desrfb.h" - -static void scrunch(unsigned char *, unsigned long *); -static void unscrun(unsigned long *, unsigned char *); -static void desfunc(unsigned long *, unsigned long *); -static void cookey(unsigned long *); - -static unsigned long KnL[32] = { 0L }; - -static const unsigned short bytebit[8] = { - 01, 02, 04, 010, 020, 040, 0100, 0200 }; - -static const unsigned long bigbyte[24] = { - 0x800000L, 0x400000L, 0x200000L, 0x100000L, - 0x80000L, 0x40000L, 0x20000L, 0x10000L, - 0x8000L, 0x4000L, 0x2000L, 0x1000L, - 0x800L, 0x400L, 0x200L, 0x100L, - 0x80L, 0x40L, 0x20L, 0x10L, - 0x8L, 0x4L, 0x2L, 0x1L }; - -/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */ - -static const unsigned char pc1[56] = { - 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, - 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, - 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, - 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 }; - -static const unsigned char totrot[16] = { - 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 }; - -static const unsigned char pc2[48] = { - 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, - 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, - 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, - 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; - -/* Thanks to James Gillogly & Phil Karn! */ -void deskey(unsigned char *key, int edf) -{ - register int i, j, l, m, n; - unsigned char pc1m[56], pcr[56]; - unsigned long kn[32]; - - for ( j = 0; j < 56; j++ ) { - l = pc1[j]; - m = l & 07; - pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0; - } - for( i = 0; i < 16; i++ ) { - if( edf == DE1 ) m = (15 - i) << 1; - else m = i << 1; - n = m + 1; - kn[m] = kn[n] = 0L; - for( j = 0; j < 28; j++ ) { - l = j + totrot[i]; - if( l < 28 ) pcr[j] = pc1m[l]; - else pcr[j] = pc1m[l - 28]; - } - for( j = 28; j < 56; j++ ) { - l = j + totrot[i]; - if( l < 56 ) pcr[j] = pc1m[l]; - else pcr[j] = pc1m[l - 28]; - } - for( j = 0; j < 24; j++ ) { - if( pcr[pc2[j]] ) kn[m] |= bigbyte[j]; - if( pcr[pc2[j + 24]] ) kn[n] |= bigbyte[j]; - } - } - cookey(kn); - return; - } - -static void cookey(register unsigned long *raw1) -{ - register unsigned long *cook, *raw0; - unsigned long dough[32]; - register int i; - - cook = dough; - for( i = 0; i < 16; i++, raw1++ ) { - raw0 = raw1++; - *cook = (*raw0 & 0x00fc0000L) << 6; - *cook |= (*raw0 & 0x00000fc0L) << 10; - *cook |= (*raw1 & 0x00fc0000L) >> 10; - *cook++ |= (*raw1 & 0x00000fc0L) >> 6; - *cook = (*raw0 & 0x0003f000L) << 12; - *cook |= (*raw0 & 0x0000003fL) << 16; - *cook |= (*raw1 & 0x0003f000L) >> 4; - *cook++ |= (*raw1 & 0x0000003fL); - } - usekey(dough); - return; - } - -void usekey(register unsigned long *from) -{ - register unsigned long *to, *endp; - - to = KnL, endp = &KnL[32]; - while( to < endp ) *to++ = *from++; - return; - } - -void des(unsigned char *inblock, unsigned char *outblock) -{ - unsigned long work[2]; - - scrunch(inblock, work); - desfunc(work, KnL); - unscrun(work, outblock); - return; - } - -static void scrunch(register unsigned char *outof, register unsigned long *into) -{ - *into = (*outof++ & 0xffL) << 24; - *into |= (*outof++ & 0xffL) << 16; - *into |= (*outof++ & 0xffL) << 8; - *into++ |= (*outof++ & 0xffL); - *into = (*outof++ & 0xffL) << 24; - *into |= (*outof++ & 0xffL) << 16; - *into |= (*outof++ & 0xffL) << 8; - *into |= (*outof & 0xffL); - return; - } - -static void unscrun(register unsigned long *outof, register unsigned char *into) -{ - *into++ = (unsigned char)((*outof >> 24) & 0xffL); - *into++ = (unsigned char)((*outof >> 16) & 0xffL); - *into++ = (unsigned char)((*outof >> 8) & 0xffL); - *into++ = (unsigned char)(*outof++ & 0xffL); - *into++ = (unsigned char)((*outof >> 24) & 0xffL); - *into++ = (unsigned char)((*outof >> 16) & 0xffL); - *into++ = (unsigned char)((*outof >> 8) & 0xffL); - *into = (unsigned char)(*outof & 0xffL); - return; - } - -static const unsigned long SP1[64] = { - 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, - 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, - 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, - 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, - 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, - 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, - 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, - 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, - 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, - 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, - 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, - 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, - 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, - 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, - 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, - 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L }; - -static const unsigned long SP2[64] = { - 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, - 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, - 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, - 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, - 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, - 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, - 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, - 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, - 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, - 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, - 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, - 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, - 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, - 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, - 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, - 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L }; - -static const unsigned long SP3[64] = { - 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, - 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, - 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, - 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, - 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, - 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, - 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, - 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, - 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, - 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, - 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, - 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, - 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, - 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, - 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, - 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L }; - -static const unsigned long SP4[64] = { - 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, - 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, - 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, - 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, - 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, - 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, - 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, - 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, - 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, - 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, - 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, - 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, - 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, - 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, - 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, - 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L }; - -static const unsigned long SP5[64] = { - 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, - 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, - 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, - 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, - 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, - 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, - 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, - 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, - 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, - 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, - 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, - 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, - 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, - 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, - 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, - 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L }; - -static const unsigned long SP6[64] = { - 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, - 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, - 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, - 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, - 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, - 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, - 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, - 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, - 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, - 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, - 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, - 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, - 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, - 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, - 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, - 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L }; - -static const unsigned long SP7[64] = { - 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, - 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, - 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, - 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, - 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, - 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, - 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, - 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, - 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, - 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, - 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, - 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, - 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, - 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, - 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, - 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L }; - -static const unsigned long SP8[64] = { - 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, - 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, - 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, - 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, - 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, - 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, - 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, - 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, - 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, - 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, - 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, - 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, - 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, - 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, - 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, - 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L }; - -static void desfunc(register unsigned long *block, register unsigned long *keys) -{ - register unsigned long fval, work, right, leftt; - register int round; - - leftt = block[0]; - right = block[1]; - work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; - right ^= work; - leftt ^= (work << 4); - work = ((leftt >> 16) ^ right) & 0x0000ffffL; - right ^= work; - leftt ^= (work << 16); - work = ((right >> 2) ^ leftt) & 0x33333333L; - leftt ^= work; - right ^= (work << 2); - work = ((right >> 8) ^ leftt) & 0x00ff00ffL; - leftt ^= work; - right ^= (work << 8); - right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL; - work = (leftt ^ right) & 0xaaaaaaaaL; - leftt ^= work; - right ^= work; - leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL; - - for( round = 0; round < 8; round++ ) { - work = (right << 28) | (right >> 4); - work ^= *keys++; - fval = SP7[ work & 0x3fL]; - fval |= SP5[(work >> 8) & 0x3fL]; - fval |= SP3[(work >> 16) & 0x3fL]; - fval |= SP1[(work >> 24) & 0x3fL]; - work = right ^ *keys++; - fval |= SP8[ work & 0x3fL]; - fval |= SP6[(work >> 8) & 0x3fL]; - fval |= SP4[(work >> 16) & 0x3fL]; - fval |= SP2[(work >> 24) & 0x3fL]; - leftt ^= fval; - work = (leftt << 28) | (leftt >> 4); - work ^= *keys++; - fval = SP7[ work & 0x3fL]; - fval |= SP5[(work >> 8) & 0x3fL]; - fval |= SP3[(work >> 16) & 0x3fL]; - fval |= SP1[(work >> 24) & 0x3fL]; - work = leftt ^ *keys++; - fval |= SP8[ work & 0x3fL]; - fval |= SP6[(work >> 8) & 0x3fL]; - fval |= SP4[(work >> 16) & 0x3fL]; - fval |= SP2[(work >> 24) & 0x3fL]; - right ^= fval; - } - - right = (right << 31) | (right >> 1); - work = (leftt ^ right) & 0xaaaaaaaaL; - leftt ^= work; - right ^= work; - leftt = (leftt << 31) | (leftt >> 1); - work = ((leftt >> 8) ^ right) & 0x00ff00ffL; - right ^= work; - leftt ^= (work << 8); - work = ((leftt >> 2) ^ right) & 0x33333333L; - right ^= work; - leftt ^= (work << 2); - work = ((right >> 16) ^ leftt) & 0x0000ffffL; - leftt ^= work; - right ^= (work << 16); - work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; - leftt ^= work; - right ^= (work << 4); - *block++ = right; - *block = leftt; - return; - } - -/* Validation sets: - * - * Single-length key, single-length plaintext - - * Key : 0123 4567 89ab cdef - * Plain : 0123 4567 89ab cde7 - * Cipher : c957 4425 6a5e d31d - * - * Double-length key, single-length plaintext - - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 - * Plain : 0123 4567 89ab cde7 - * Cipher : 7f1d 0a77 826b 8aff - * - * Double-length key, double-length plaintext - - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 - * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff - * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7 - * - * Triple-length key, single-length plaintext - - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 - * Plain : 0123 4567 89ab cde7 - * Cipher : de0b 7c06 ae5e 0ed5 - * - * Triple-length key, double-length plaintext - - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 - * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff - * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5 - * - * d3des V5.0a rwo 9208.07 18:44 Graven Imagery - **********************************************************************/ diff --git a/crypto/meson.build b/crypto/meson.build index 7cbf1a6ba7..b384ca8b57 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -5,7 +5,6 @@ crypto_ss.add(files( 'block-qcow.c', 'block.c', 'cipher.c', - 'desrfb.c', 'hash.c', 'hmac.c', 'ivgen-essiv.c', From 6801404429d51b260e08c6ad54dbf3ac430016db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 2 Jul 2021 17:00:32 +0100 Subject: [PATCH 090/531] crypto: delete built-in XTS cipher mode support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The built-in AES+XTS implementation is used for the LUKS encryption When building system emulators it is reasonable to expect that an external crypto library is being used instead. The performance of the builtin XTS implementation is terrible as it has no CPU acceleration support. It is thus not worth keeping a home grown XTS implementation for the built-in cipher backend. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- crypto/cipher-builtin.c.inc | 60 ------------------------------------- crypto/meson.build | 6 ++-- meson.build | 7 ++--- 3 files changed, 6 insertions(+), 67 deletions(-) diff --git a/crypto/cipher-builtin.c.inc b/crypto/cipher-builtin.c.inc index 70743f253c..b409089095 100644 --- a/crypto/cipher-builtin.c.inc +++ b/crypto/cipher-builtin.c.inc @@ -19,7 +19,6 @@ */ #include "crypto/aes.h" -#include "crypto/xts.h" typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext; struct QCryptoCipherBuiltinAESContext { @@ -31,7 +30,6 @@ typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES; struct QCryptoCipherBuiltinAES { QCryptoCipher base; QCryptoCipherBuiltinAESContext key; - QCryptoCipherBuiltinAESContext key_tweak; uint8_t iv[AES_BLOCK_SIZE]; }; @@ -193,39 +191,6 @@ static int qcrypto_cipher_aes_decrypt_cbc(QCryptoCipher *cipher, return 0; } -static int qcrypto_cipher_aes_encrypt_xts(QCryptoCipher *cipher, - const void *in, void *out, - size_t len, Error **errp) -{ - QCryptoCipherBuiltinAES *ctx - = container_of(cipher, QCryptoCipherBuiltinAES, base); - - if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) { - return -1; - } - xts_encrypt(&ctx->key, &ctx->key_tweak, - do_aes_encrypt_ecb, do_aes_decrypt_ecb, - ctx->iv, len, out, in); - return 0; -} - -static int qcrypto_cipher_aes_decrypt_xts(QCryptoCipher *cipher, - const void *in, void *out, - size_t len, Error **errp) -{ - QCryptoCipherBuiltinAES *ctx - = container_of(cipher, QCryptoCipherBuiltinAES, base); - - if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) { - return -1; - } - xts_decrypt(&ctx->key, &ctx->key_tweak, - do_aes_encrypt_ecb, do_aes_decrypt_ecb, - ctx->iv, len, out, in); - return 0; -} - - static int qcrypto_cipher_aes_setiv(QCryptoCipher *cipher, const uint8_t *iv, size_t niv, Error **errp) { @@ -256,14 +221,6 @@ static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_cbc = { .cipher_free = qcrypto_cipher_ctx_free, }; -static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_xts = { - .cipher_encrypt = qcrypto_cipher_aes_encrypt_xts, - .cipher_decrypt = qcrypto_cipher_aes_decrypt_xts, - .cipher_setiv = qcrypto_cipher_aes_setiv, - .cipher_free = qcrypto_cipher_ctx_free, -}; - - bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, QCryptoCipherMode mode) { @@ -274,7 +231,6 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, switch (mode) { case QCRYPTO_CIPHER_MODE_ECB: case QCRYPTO_CIPHER_MODE_CBC: - case QCRYPTO_CIPHER_MODE_XTS: return true; default: return false; @@ -310,9 +266,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, case QCRYPTO_CIPHER_MODE_CBC: drv = &qcrypto_cipher_aes_driver_cbc; break; - case QCRYPTO_CIPHER_MODE_XTS: - drv = &qcrypto_cipher_aes_driver_xts; - break; default: goto bad_mode; } @@ -320,19 +273,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, ctx = g_new0(QCryptoCipherBuiltinAES, 1); ctx->base.driver = drv; - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - nkey /= 2; - if (AES_set_encrypt_key(key + nkey, nkey * 8, - &ctx->key_tweak.enc)) { - error_setg(errp, "Failed to set encryption key"); - goto error; - } - if (AES_set_decrypt_key(key + nkey, nkey * 8, - &ctx->key_tweak.dec)) { - error_setg(errp, "Failed to set decryption key"); - goto error; - } - } if (AES_set_encrypt_key(key, nkey * 8, &ctx->key.enc)) { error_setg(errp, "Failed to set encryption key"); goto error; diff --git a/crypto/meson.build b/crypto/meson.build index b384ca8b57..fc8de287e1 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -23,14 +23,14 @@ crypto_ss.add(files( if nettle.found() crypto_ss.add(nettle, files('hash-nettle.c', 'hmac-nettle.c', 'pbkdf-nettle.c')) + if xts == 'private' + crypto_ss.add(files('xts.c')) + endif elif gcrypt.found() crypto_ss.add(gcrypt, files('hash-gcrypt.c', 'hmac-gcrypt.c', 'pbkdf-gcrypt.c')) else crypto_ss.add(files('hash-glib.c', 'hmac-glib.c', 'pbkdf-stub.c')) endif -if xts == 'private' - crypto_ss.add(files('xts.c')) -endif crypto_ss.add(when: 'CONFIG_SECRET_KEYRING', if_true: files('secret_keyring.c')) crypto_ss.add(when: 'CONFIG_AF_ALG', if_true: files('afalg.c', 'cipher-afalg.c', 'hash-afalg.c')) diff --git a/meson.build b/meson.build index a96c8b858c..8f899e1e9b 100644 --- a/meson.build +++ b/meson.build @@ -826,7 +826,7 @@ endif # Nettle has priority over gcrypt gcrypt = not_found nettle = not_found -xts = 'private' +xts = 'none' if get_option('nettle').enabled() and get_option('gcrypt').enabled() error('Only one of gcrypt & nettle can be enabled') elif (not get_option('nettle').auto() or have_system) and not get_option('gcrypt').enabled() @@ -834,8 +834,8 @@ elif (not get_option('nettle').auto() or have_system) and not get_option('gcrypt method: 'pkg-config', required: get_option('nettle'), kwargs: static_kwargs) - if nettle.found() and cc.has_header('nettle/xts.h', dependencies: nettle) - xts = 'nettle' + if nettle.found() and not cc.has_header('nettle/xts.h', dependencies: nettle) + xts = 'private' endif endif if (not get_option('gcrypt').auto() or have_system) and not nettle.found() @@ -843,7 +843,6 @@ if (not get_option('gcrypt').auto() or have_system) and not nettle.found() method: 'config-tool', required: get_option('gcrypt'), kwargs: static_kwargs) - xts = 'gcrypt' # Debian has removed -lgpg-error from libgcrypt-config # as it "spreads unnecessary dependencies" which in # turn breaks static builds... From 83bee4b51fad383c1ee9b9f58fefb90fddae1c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 29 Jun 2021 14:25:32 +0100 Subject: [PATCH 091/531] crypto: replace 'des-rfb' cipher with 'des' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the crypto layer exposes support for a 'des-rfb' algorithm which is just normal single-DES, with the bits in each key byte reversed. This special key munging is required by the RFB protocol password authentication mechanism. Since the crypto layer is generic shared code, it makes more sense to do the key byte munging in the VNC server code, and expose normal single-DES support. Replacing cipher 'des-rfb' by 'des' looks like an incompatible interface change, but it doesn't matter. While the QMP schema allows any QCryptoCipherAlgorithm for the 'cipher-alg' field in QCryptoBlockCreateOptionsLUKS, the code restricts what can be used at runtime. Thus the only effect is a change in error message. Original behaviour: $ qemu-img create -f luks --object secret,id=sec0,data=123 -o cipher-alg=des-rfb,key-secret=sec0 demo.luks 1G Formatting 'demo.luks', fmt=luks size=1073741824 key-secret=sec0 cipher-alg=des-rfb qemu-img: demo.luks: Algorithm 'des-rfb' not supported New behaviour: $ qemu-img create -f luks --object secret,id=sec0,data=123 -o cipher-alg=des-rfb,key-secret=sec0 demo.luks 1G Formatting 'demo.luks', fmt=luks size=1073741824 key-secret=sec0 cipher-alg=des-fish qemu-img: demo.luks: Invalid parameter 'des-rfb' Reviewed-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- crypto/cipher-gcrypt.c.inc | 16 +++------------- crypto/cipher-nettle.c.inc | 26 +++++++++++--------------- crypto/cipher.c | 28 +++++----------------------- qapi/crypto.json | 4 ++-- tests/unit/test-crypto-cipher.c | 18 +++++++++--------- ui/vnc.c | 20 +++++++++++++++++--- 6 files changed, 47 insertions(+), 65 deletions(-) diff --git a/crypto/cipher-gcrypt.c.inc b/crypto/cipher-gcrypt.c.inc index 3aab08a1a9..a6a0117717 100644 --- a/crypto/cipher-gcrypt.c.inc +++ b/crypto/cipher-gcrypt.c.inc @@ -24,7 +24,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, QCryptoCipherMode mode) { switch (alg) { - case QCRYPTO_CIPHER_ALG_DES_RFB: + case QCRYPTO_CIPHER_ALG_DES: case QCRYPTO_CIPHER_ALG_3DES: case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_192: @@ -186,7 +186,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, } switch (alg) { - case QCRYPTO_CIPHER_ALG_DES_RFB: + case QCRYPTO_CIPHER_ALG_DES: gcryalg = GCRY_CIPHER_DES; break; case QCRYPTO_CIPHER_ALG_3DES: @@ -257,17 +257,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, } ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg); - if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) { - /* We're using standard DES cipher from gcrypt, so we need - * to munge the key so that the results are the same as the - * bizarre RFB variant of DES :-) - */ - uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey); - err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey); - g_free(rfbkey); - } else { - err = gcry_cipher_setkey(ctx->handle, key, nkey); - } + err = gcry_cipher_setkey(ctx->handle, key, nkey); if (err != 0) { error_setg(errp, "Cannot set key: %s", gcry_strerror(err)); goto error; diff --git a/crypto/cipher-nettle.c.inc b/crypto/cipher-nettle.c.inc index fc6f40c026..24cc61f87b 100644 --- a/crypto/cipher-nettle.c.inc +++ b/crypto/cipher-nettle.c.inc @@ -235,11 +235,11 @@ static const struct QCryptoCipherDriver NAME##_driver_xts = { \ DEFINE_XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) -typedef struct QCryptoNettleDESRFB { +typedef struct QCryptoNettleDES { QCryptoCipher base; struct des_ctx key; uint8_t iv[DES_BLOCK_SIZE]; -} QCryptoNettleDESRFB; +} QCryptoNettleDES; static void des_encrypt_native(const void *ctx, size_t length, uint8_t *dst, const uint8_t *src) @@ -253,7 +253,7 @@ static void des_decrypt_native(const void *ctx, size_t length, des_decrypt(ctx, length, dst, src); } -DEFINE_ECB_CBC_CTR(qcrypto_nettle_des_rfb, QCryptoNettleDESRFB, +DEFINE_ECB_CBC_CTR(qcrypto_nettle_des, QCryptoNettleDES, DES_BLOCK_SIZE, des_encrypt_native, des_decrypt_native) @@ -431,7 +431,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, QCryptoCipherMode mode) { switch (alg) { - case QCRYPTO_CIPHER_ALG_DES_RFB: + case QCRYPTO_CIPHER_ALG_DES: case QCRYPTO_CIPHER_ALG_3DES: case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_192: @@ -480,32 +480,28 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, } switch (alg) { - case QCRYPTO_CIPHER_ALG_DES_RFB: + case QCRYPTO_CIPHER_ALG_DES: { - QCryptoNettleDESRFB *ctx; + QCryptoNettleDES *ctx; const QCryptoCipherDriver *drv; - uint8_t *rfbkey; switch (mode) { case QCRYPTO_CIPHER_MODE_ECB: - drv = &qcrypto_nettle_des_rfb_driver_ecb; + drv = &qcrypto_nettle_des_driver_ecb; break; case QCRYPTO_CIPHER_MODE_CBC: - drv = &qcrypto_nettle_des_rfb_driver_cbc; + drv = &qcrypto_nettle_des_driver_cbc; break; case QCRYPTO_CIPHER_MODE_CTR: - drv = &qcrypto_nettle_des_rfb_driver_ctr; + drv = &qcrypto_nettle_des_driver_ctr; break; default: goto bad_cipher_mode; } - ctx = g_new0(QCryptoNettleDESRFB, 1); + ctx = g_new0(QCryptoNettleDES, 1); ctx->base.driver = drv; - - rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey); - des_set_key(&ctx->key, rfbkey); - g_free(rfbkey); + des_set_key(&ctx->key, key); return &ctx->base; } diff --git a/crypto/cipher.c b/crypto/cipher.c index 068b2fb867..1f5528be49 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -29,7 +29,7 @@ static const size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_AES_128] = 16, [QCRYPTO_CIPHER_ALG_AES_192] = 24, [QCRYPTO_CIPHER_ALG_AES_256] = 32, - [QCRYPTO_CIPHER_ALG_DES_RFB] = 8, + [QCRYPTO_CIPHER_ALG_DES] = 8, [QCRYPTO_CIPHER_ALG_3DES] = 24, [QCRYPTO_CIPHER_ALG_CAST5_128] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, @@ -44,7 +44,7 @@ static const size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_AES_128] = 16, [QCRYPTO_CIPHER_ALG_AES_192] = 16, [QCRYPTO_CIPHER_ALG_AES_256] = 16, - [QCRYPTO_CIPHER_ALG_DES_RFB] = 8, + [QCRYPTO_CIPHER_ALG_DES] = 8, [QCRYPTO_CIPHER_ALG_3DES] = 8, [QCRYPTO_CIPHER_ALG_CAST5_128] = 8, [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, @@ -107,9 +107,9 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg, } if (mode == QCRYPTO_CIPHER_MODE_XTS) { - if (alg == QCRYPTO_CIPHER_ALG_DES_RFB - || alg == QCRYPTO_CIPHER_ALG_3DES) { - error_setg(errp, "XTS mode not compatible with DES-RFB/3DES"); + if (alg == QCRYPTO_CIPHER_ALG_DES || + alg == QCRYPTO_CIPHER_ALG_3DES) { + error_setg(errp, "XTS mode not compatible with DES/3DES"); return false; } if (nkey % 2) { @@ -132,24 +132,6 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg, return true; } -#if defined(CONFIG_GCRYPT) || defined(CONFIG_NETTLE) -static uint8_t * -qcrypto_cipher_munge_des_rfb_key(const uint8_t *key, - size_t nkey) -{ - uint8_t *ret = g_new0(uint8_t, nkey); - size_t i; - for (i = 0; i < nkey; i++) { - uint8_t r = key[i]; - r = (r & 0xf0) >> 4 | (r & 0x0f) << 4; - r = (r & 0xcc) >> 2 | (r & 0x33) << 2; - r = (r & 0xaa) >> 1 | (r & 0x55) << 1; - ret[i] = r; - } - return ret; -} -#endif /* CONFIG_GCRYPT || CONFIG_NETTLE */ - #ifdef CONFIG_GCRYPT #include "cipher-gcrypt.c.inc" #elif defined CONFIG_NETTLE diff --git a/qapi/crypto.json b/qapi/crypto.json index 7116ae9a46..1ec54c15ca 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -66,7 +66,7 @@ # @aes-128: AES with 128 bit / 16 byte keys # @aes-192: AES with 192 bit / 24 byte keys # @aes-256: AES with 256 bit / 32 byte keys -# @des-rfb: RFB specific variant of single DES. Do not use except in VNC. +# @des: DES with 56 bit / 8 byte keys. Do not use except in VNC. (since 6.1) # @3des: 3DES(EDE) with 192 bit / 24 byte keys (since 2.9) # @cast5-128: Cast5 with 128 bit / 16 byte keys # @serpent-128: Serpent with 128 bit / 16 byte keys @@ -80,7 +80,7 @@ { 'enum': 'QCryptoCipherAlgorithm', 'prefix': 'QCRYPTO_CIPHER_ALG', 'data': ['aes-128', 'aes-192', 'aes-256', - 'des-rfb', '3des', + 'des', '3des', 'cast5-128', 'serpent-128', 'serpent-192', 'serpent-256', 'twofish-128', 'twofish-192', 'twofish-256']} diff --git a/tests/unit/test-crypto-cipher.c b/tests/unit/test-crypto-cipher.c index 7dca7b26e4..d9d9d078ff 100644 --- a/tests/unit/test-crypto-cipher.c +++ b/tests/unit/test-crypto-cipher.c @@ -155,28 +155,28 @@ static QCryptoCipherTestData test_data[] = { * in single AES block, and gives identical * ciphertext in ECB and CBC modes */ - .path = "/crypto/cipher/des-rfb-ecb-56-one-block", - .alg = QCRYPTO_CIPHER_ALG_DES_RFB, + .path = "/crypto/cipher/des-ecb-56-one-block", + .alg = QCRYPTO_CIPHER_ALG_DES, .mode = QCRYPTO_CIPHER_MODE_ECB, - .key = "0123456789abcdef", + .key = "80c4a2e691d5b3f7", .plaintext = "70617373776f7264", .ciphertext = "73fa80b66134e403", }, { /* See previous comment */ - .path = "/crypto/cipher/des-rfb-cbc-56-one-block", - .alg = QCRYPTO_CIPHER_ALG_DES_RFB, + .path = "/crypto/cipher/des-cbc-56-one-block", + .alg = QCRYPTO_CIPHER_ALG_DES, .mode = QCRYPTO_CIPHER_MODE_CBC, - .key = "0123456789abcdef", + .key = "80c4a2e691d5b3f7", .iv = "0000000000000000", .plaintext = "70617373776f7264", .ciphertext = "73fa80b66134e403", }, { - .path = "/crypto/cipher/des-rfb-ecb-56", - .alg = QCRYPTO_CIPHER_ALG_DES_RFB, + .path = "/crypto/cipher/des-ecb-56", + .alg = QCRYPTO_CIPHER_ALG_DES, .mode = QCRYPTO_CIPHER_MODE_ECB, - .key = "0123456789abcdef", + .key = "80c4a2e691d5b3f7", .plaintext = "6bc1bee22e409f96e93d7e117393172a" "ae2d8a571e03ac9c9eb76fac45af8e51" diff --git a/ui/vnc.c b/ui/vnc.c index 0e5fcb278f..af02522e84 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -2733,6 +2733,19 @@ static void authentication_failed(VncState *vs) vnc_client_error(vs); } +static void +vnc_munge_des_rfb_key(unsigned char *key, size_t nkey) +{ + size_t i; + for (i = 0; i < nkey; i++) { + uint8_t r = key[i]; + r = (r & 0xf0) >> 4 | (r & 0x0f) << 4; + r = (r & 0xcc) >> 2 | (r & 0x33) << 2; + r = (r & 0xaa) >> 1 | (r & 0x55) << 1; + key[i] = r; + } +} + static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) { unsigned char response[VNC_AUTH_CHALLENGE_SIZE]; @@ -2757,9 +2770,10 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) pwlen = strlen(vs->vd->password); for (i=0; ivd->password[i] : 0; + vnc_munge_des_rfb_key(key, sizeof(key)); cipher = qcrypto_cipher_new( - QCRYPTO_CIPHER_ALG_DES_RFB, + QCRYPTO_CIPHER_ALG_DES, QCRYPTO_CIPHER_MODE_ECB, key, G_N_ELEMENTS(key), &err); @@ -4045,9 +4059,9 @@ void vnc_display_open(const char *id, Error **errp) goto fail; } if (!qcrypto_cipher_supports( - QCRYPTO_CIPHER_ALG_DES_RFB, QCRYPTO_CIPHER_MODE_ECB)) { + QCRYPTO_CIPHER_ALG_DES, QCRYPTO_CIPHER_MODE_ECB)) { error_setg(errp, - "Cipher backend does not support DES RFB algorithm"); + "Cipher backend does not support DES algorithm"); goto fail; } } From 260a13d4726ce62bdc0ed3a7a13c34de3367f5e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 2 Jul 2021 14:18:12 +0100 Subject: [PATCH 092/531] crypto: flip priority of backends to prefer gcrypt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Originally we preferred to use nettle over gcrypt because gnutls already links to nettle and thus it minimizes the dependencies. In retrospect this was the wrong criteria to optimize for. Currently shipping versions of gcrypt have cipher impls that are massively faster than those in nettle and this is way more important. The nettle library is also not capable of enforcing FIPS compliance, since it considers that out of scope. It merely aims to provide general purpose impls of algorithms, and usage policy is left upto the layer above, such as GNUTLS. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- meson.build | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/meson.build b/meson.build index 8f899e1e9b..c3a6096820 100644 --- a/meson.build +++ b/meson.build @@ -823,22 +823,13 @@ if not get_option('gnutls').auto() or have_system kwargs: static_kwargs) endif -# Nettle has priority over gcrypt +# Gcrypt has priority over nettle gcrypt = not_found nettle = not_found xts = 'none' if get_option('nettle').enabled() and get_option('gcrypt').enabled() error('Only one of gcrypt & nettle can be enabled') -elif (not get_option('nettle').auto() or have_system) and not get_option('gcrypt').enabled() - nettle = dependency('nettle', version: '>=3.4', - method: 'pkg-config', - required: get_option('nettle'), - kwargs: static_kwargs) - if nettle.found() and not cc.has_header('nettle/xts.h', dependencies: nettle) - xts = 'private' - endif -endif -if (not get_option('gcrypt').auto() or have_system) and not nettle.found() +elif (not get_option('gcrypt').auto() or have_system) and not get_option('nettle').enabled() gcrypt = dependency('libgcrypt', version: '>=1.8', method: 'config-tool', required: get_option('gcrypt'), @@ -852,6 +843,15 @@ if (not get_option('gcrypt').auto() or have_system) and not nettle.found() cc.find_library('gpg-error', required: true, kwargs: static_kwargs)]) endif endif +if (not get_option('nettle').auto() or have_system) and not gcrypt.found() + nettle = dependency('nettle', version: '>=3.4', + method: 'pkg-config', + required: get_option('nettle'), + kwargs: static_kwargs) + if nettle.found() and not cc.has_header('nettle/xts.h', dependencies: nettle) + xts = 'private' + endif +endif gtk = not_found gtkx11 = not_found From cc4c7c738297958b3d1d16269f57d71d22f5a9ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 30 Jun 2021 17:20:02 +0100 Subject: [PATCH 093/531] crypto: introduce build system for gnutls crypto backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces the build logic needed to decide whether we can use gnutls as a crypto driver backend. The actual implementations will be introduced in following patches. We only wish to use gnutls if it has version 3.6.14 or newer, because that is what finally brings HW accelerated AES-XTS mode for x86_64. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- crypto/meson.build | 3 +++ meson.build | 36 ++++++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/crypto/meson.build b/crypto/meson.build index fc8de287e1..f3bab7c067 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -38,6 +38,9 @@ crypto_ss.add(when: gnutls, if_true: files('tls-cipher-suites.c')) util_ss.add(files('aes.c')) util_ss.add(files('init.c')) +if gnutls.found() + util_ss.add(gnutls) +endif if gcrypt.found() util_ss.add(gcrypt, files('random-gcrypt.c')) diff --git a/meson.build b/meson.build index c3a6096820..38b89d424b 100644 --- a/meson.build +++ b/meson.build @@ -816,11 +816,34 @@ if 'CONFIG_OPENGL' in config_host endif gnutls = not_found +gnutls_crypto = not_found if not get_option('gnutls').auto() or have_system - gnutls = dependency('gnutls', version: '>=3.5.18', - method: 'pkg-config', - required: get_option('gnutls'), - kwargs: static_kwargs) + # For general TLS support our min gnutls matches + # that implied by our platform support matrix + # + # For the crypto backends, we look for a newer + # gnutls: + # + # Version 3.6.8 is needed to get XTS + # Version 3.6.13 is needed to get PBKDF + # Version 3.6.14 is needed to get HW accelerated XTS + # + # If newer enough gnutls isn't available, we can + # still use a different crypto backend to satisfy + # the platform support requirements + gnutls_crypto = dependency('gnutls', version: '>=3.6.14', + method: 'pkg-config', + required: false, + kwargs: static_kwargs) + if gnutls_crypto.found() + gnutls = gnutls_crypto + else + # Our min version if all we need is TLS + gnutls = dependency('gnutls', version: '>=3.5.18', + method: 'pkg-config', + required: get_option('gnutls'), + kwargs: static_kwargs) + endif endif # Gcrypt has priority over nettle @@ -852,6 +875,9 @@ if (not get_option('nettle').auto() or have_system) and not gcrypt.found() xts = 'private' endif endif +if gcrypt.found() or nettle.found() + gnutls_crypto = not_found +endif gtk = not_found gtkx11 = not_found @@ -1236,6 +1262,7 @@ config_host_data.set('CONFIG_XKBCOMMON', xkbcommon.found()) config_host_data.set('CONFIG_KEYUTILS', keyutils.found()) config_host_data.set('CONFIG_GETTID', has_gettid) config_host_data.set('CONFIG_GNUTLS', gnutls.found()) +config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found()) config_host_data.set('CONFIG_GCRYPT', gcrypt.found()) config_host_data.set('CONFIG_NETTLE', nettle.found()) config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private') @@ -2958,6 +2985,7 @@ summary(summary_info, bool_yn: true, section: 'Block layer support') summary_info = {} summary_info += {'TLS priority': config_host['CONFIG_TLS_PRIORITY']} summary_info += {'GNUTLS support': gnutls.found()} +summary_info += {'GNUTLS crypto': gnutls_crypto.found()} # TODO: add back version summary_info += {'libgcrypt': gcrypt.found()} # TODO: add back version From 3d2b61ffcd4a5a8f5bfcdb2be5eac1a37f5caaa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 29 Jun 2021 13:25:55 +0100 Subject: [PATCH 094/531] crypto: add gnutls cipher provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an implementation of the QEMU cipher APIs to the gnutls crypto backend. XTS support is only available for gnutls version >= 3.6.8. Since ECB mode is not exposed by gnutls APIs, we can't use the private XTS code for compatibility. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- crypto/cipher-gnutls.c.inc | 335 +++++++++++++++++++++++++++++++++++++ crypto/cipher.c | 2 + 2 files changed, 337 insertions(+) create mode 100644 crypto/cipher-gnutls.c.inc diff --git a/crypto/cipher-gnutls.c.inc b/crypto/cipher-gnutls.c.inc new file mode 100644 index 0000000000..501e4e07a5 --- /dev/null +++ b/crypto/cipher-gnutls.c.inc @@ -0,0 +1,335 @@ +/* + * QEMU Crypto cipher gnutls algorithms + * + * Copyright (c) 2021 Red Hat, Inc. + * + * 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.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 + * 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 . + * + */ + +#include "qemu/osdep.h" +#include "cipherpriv.h" + +#include + +#if GNUTLS_VERSION_NUMBER >= 0x030608 +#define QEMU_GNUTLS_XTS +#endif + +bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode) +{ + + switch (mode) { + case QCRYPTO_CIPHER_MODE_ECB: + case QCRYPTO_CIPHER_MODE_CBC: + switch (alg) { + case QCRYPTO_CIPHER_ALG_AES_128: + case QCRYPTO_CIPHER_ALG_AES_192: + case QCRYPTO_CIPHER_ALG_AES_256: + case QCRYPTO_CIPHER_ALG_DES: + case QCRYPTO_CIPHER_ALG_3DES: + return true; + default: + return false; + } +#ifdef QEMU_GNUTLS_XTS + case QCRYPTO_CIPHER_MODE_XTS: + switch (alg) { + case QCRYPTO_CIPHER_ALG_AES_128: + case QCRYPTO_CIPHER_ALG_AES_256: + return true; + default: + return false; + } +#endif + default: + return false; + } +} + +typedef struct QCryptoCipherGnutls QCryptoCipherGnutls; +struct QCryptoCipherGnutls { + QCryptoCipher base; + gnutls_cipher_hd_t handle; /* XTS & CBC mode */ + gnutls_cipher_algorithm_t galg; /* ECB mode */ + guint8 *key; /* ECB mode */ + size_t nkey; /* ECB mode */ + size_t blocksize; +}; + + +static void +qcrypto_gnutls_cipher_free(QCryptoCipher *cipher) +{ + QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base); + + g_free(ctx->key); + if (ctx->handle) { + gnutls_cipher_deinit(ctx->handle); + } + g_free(ctx); +} + + +static int +qcrypto_gnutls_cipher_encrypt(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base); + int err; + + if (len % ctx->blocksize) { + error_setg(errp, "Length %zu must be a multiple of block size %zu", + len, ctx->blocksize); + return -1; + } + + if (ctx->handle) { /* CBC / XTS mode */ + err = gnutls_cipher_encrypt2(ctx->handle, + in, len, + out, len); + if (err != 0) { + error_setg(errp, "Cannot encrypt data: %s", + gnutls_strerror(err)); + return -1; + } + } else { /* ECB mode very inefficiently faked with CBC */ + g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize); + while (len) { + gnutls_cipher_hd_t handle; + gnutls_datum_t gkey = { (unsigned char *)ctx->key, ctx->nkey }; + int err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL); + if (err != 0) { + error_setg(errp, "Cannot initialize cipher: %s", + gnutls_strerror(err)); + return -1; + } + + gnutls_cipher_set_iv(handle, iv, ctx->blocksize); + + err = gnutls_cipher_encrypt2(handle, + in, ctx->blocksize, + out, ctx->blocksize); + if (err != 0) { + gnutls_cipher_deinit(handle); + error_setg(errp, "Cannot encrypt data: %s", + gnutls_strerror(err)); + return -1; + } + gnutls_cipher_deinit(handle); + + len -= ctx->blocksize; + in += ctx->blocksize; + out += ctx->blocksize; + } + } + + return 0; +} + + +static int +qcrypto_gnutls_cipher_decrypt(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base); + int err; + + if (len % ctx->blocksize) { + error_setg(errp, "Length %zu must be a multiple of block size %zu", + len, ctx->blocksize); + return -1; + } + + if (ctx->handle) { /* CBC / XTS mode */ + err = gnutls_cipher_decrypt2(ctx->handle, + in, len, + out, len); + + if (err != 0) { + error_setg(errp, "Cannot decrypt data: %s", + gnutls_strerror(err)); + return -1; + } + } else { /* ECB mode very inefficiently faked with CBC */ + g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize); + while (len) { + gnutls_cipher_hd_t handle; + gnutls_datum_t gkey = { (unsigned char *)ctx->key, ctx->nkey }; + int err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL); + if (err != 0) { + error_setg(errp, "Cannot initialize cipher: %s", + gnutls_strerror(err)); + return -1; + } + + gnutls_cipher_set_iv(handle, iv, ctx->blocksize); + + err = gnutls_cipher_decrypt2(handle, + in, ctx->blocksize, + out, ctx->blocksize); + if (err != 0) { + gnutls_cipher_deinit(handle); + error_setg(errp, "Cannot encrypt data: %s", + gnutls_strerror(err)); + return -1; + } + gnutls_cipher_deinit(handle); + + len -= ctx->blocksize; + in += ctx->blocksize; + out += ctx->blocksize; + } + } + + return 0; +} + +static int +qcrypto_gnutls_cipher_setiv(QCryptoCipher *cipher, + const uint8_t *iv, size_t niv, + Error **errp) +{ + QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base); + + if (niv != ctx->blocksize) { + error_setg(errp, "Expected IV size %zu not %zu", + ctx->blocksize, niv); + return -1; + } + + gnutls_cipher_set_iv(ctx->handle, (unsigned char *)iv, niv); + + return 0; +} + + +static struct QCryptoCipherDriver gnutls_driver = { + .cipher_encrypt = qcrypto_gnutls_cipher_encrypt, + .cipher_decrypt = qcrypto_gnutls_cipher_decrypt, + .cipher_setiv = qcrypto_gnutls_cipher_setiv, + .cipher_free = qcrypto_gnutls_cipher_free, +}; + +static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode, + const uint8_t *key, + size_t nkey, + Error **errp) +{ + QCryptoCipherGnutls *ctx; + gnutls_datum_t gkey = { (unsigned char *)key, nkey }; + gnutls_cipher_algorithm_t galg = GNUTLS_CIPHER_UNKNOWN; + int err; + + switch (mode) { +#ifdef QEMU_GNUTLS_XTS + case QCRYPTO_CIPHER_MODE_XTS: + switch (alg) { + case QCRYPTO_CIPHER_ALG_AES_128: + galg = GNUTLS_CIPHER_AES_128_XTS; + break; + case QCRYPTO_CIPHER_ALG_AES_256: + galg = GNUTLS_CIPHER_AES_256_XTS; + break; + default: + break; + } + break; +#endif + + case QCRYPTO_CIPHER_MODE_ECB: + case QCRYPTO_CIPHER_MODE_CBC: + switch (alg) { + case QCRYPTO_CIPHER_ALG_AES_128: + galg = GNUTLS_CIPHER_AES_128_CBC; + break; + case QCRYPTO_CIPHER_ALG_AES_192: + galg = GNUTLS_CIPHER_AES_192_CBC; + break; + case QCRYPTO_CIPHER_ALG_AES_256: + galg = GNUTLS_CIPHER_AES_256_CBC; + break; + case QCRYPTO_CIPHER_ALG_DES: + galg = GNUTLS_CIPHER_DES_CBC; + break; + case QCRYPTO_CIPHER_ALG_3DES: + galg = GNUTLS_CIPHER_3DES_CBC; + break; + default: + break; + } + break; + default: + break; + } + + if (galg == GNUTLS_CIPHER_UNKNOWN) { + error_setg(errp, "Unsupported cipher algorithm %s with %s mode", + QCryptoCipherAlgorithm_str(alg), + QCryptoCipherMode_str(mode)); + return NULL; + } + + if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { + return NULL; + } + + ctx = g_new0(QCryptoCipherGnutls, 1); + ctx->base.driver = &gnutls_driver; + + if (mode == QCRYPTO_CIPHER_MODE_ECB) { + ctx->key = g_new0(guint8, nkey); + memcpy(ctx->key, key, nkey); + ctx->nkey = nkey; + ctx->galg = galg; + } else { + err = gnutls_cipher_init(&ctx->handle, galg, &gkey, NULL); + if (err != 0) { + error_setg(errp, "Cannot initialize cipher: %s", + gnutls_strerror(err)); + goto error; + } + } + + if (alg == QCRYPTO_CIPHER_ALG_DES || + alg == QCRYPTO_CIPHER_ALG_3DES) + ctx->blocksize = 8; + else + ctx->blocksize = 16; + + /* + * Our API contract for requires iv to be optional + * but nettle gets unhappy when called by gnutls + * in this case, so we just force set a default + * all-zeros IV, to match behaviour of other backends. + */ + if (mode != QCRYPTO_CIPHER_MODE_ECB) { + g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize); + gnutls_cipher_set_iv(ctx->handle, iv, ctx->blocksize); + } + + return &ctx->base; + + error: + qcrypto_gnutls_cipher_free(&ctx->base); + return NULL; +} diff --git a/crypto/cipher.c b/crypto/cipher.c index 1f5528be49..74b09a5b26 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -136,6 +136,8 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg, #include "cipher-gcrypt.c.inc" #elif defined CONFIG_NETTLE #include "cipher-nettle.c.inc" +#elif defined CONFIG_GNUTLS_CRYPTO +#include "cipher-gnutls.c.inc" #else #include "cipher-builtin.c.inc" #endif From 9a85ca050aa4e7624615e9ae95cf54d5640c6804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 25 Jun 2021 18:32:14 +0100 Subject: [PATCH 095/531] crypto: add gnutls hash provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for using gnutls as a provider of the crypto hash APIs. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- crypto/hash-gnutls.c | 104 +++++++++++++++++++++++++++++++++++++++++++ crypto/meson.build | 2 + 2 files changed, 106 insertions(+) create mode 100644 crypto/hash-gnutls.c diff --git a/crypto/hash-gnutls.c b/crypto/hash-gnutls.c new file mode 100644 index 0000000000..17911ac5d1 --- /dev/null +++ b/crypto/hash-gnutls.c @@ -0,0 +1,104 @@ +/* + * QEMU Crypto hash algorithms + * + * Copyright (c) 2021 Red Hat, Inc. + * + * 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.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 + * 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 . + * + */ + +#include "qemu/osdep.h" +#include +#include "qapi/error.h" +#include "crypto/hash.h" +#include "hashpriv.h" + + +static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = { + [QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5, + [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1, + [QCRYPTO_HASH_ALG_SHA224] = GNUTLS_DIG_SHA224, + [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256, + [QCRYPTO_HASH_ALG_SHA384] = GNUTLS_DIG_SHA384, + [QCRYPTO_HASH_ALG_SHA512] = GNUTLS_DIG_SHA512, + [QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_DIG_RMD160, +}; + +gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg) +{ + size_t i; + const gnutls_digest_algorithm_t *algs; + if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_map) || + qcrypto_hash_alg_map[alg] == GNUTLS_DIG_UNKNOWN) { + return false; + } + algs = gnutls_digest_list(); + for (i = 0; algs[i] != GNUTLS_DIG_UNKNOWN; i++) { + if (algs[i] == qcrypto_hash_alg_map[alg]) { + return true; + } + } + return false; +} + + +static int +qcrypto_gnutls_hash_bytesv(QCryptoHashAlgorithm alg, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp) +{ + int i, ret; + gnutls_hash_hd_t hash; + + if (!qcrypto_hash_supports(alg)) { + error_setg(errp, + "Unknown hash algorithm %d", + alg); + return -1; + } + + ret = gnutls_hash_get_len(qcrypto_hash_alg_map[alg]); + if (*resultlen == 0) { + *resultlen = ret; + *result = g_new0(uint8_t, *resultlen); + } else if (*resultlen != ret) { + error_setg(errp, + "Result buffer size %zu is smaller than hash %d", + *resultlen, ret); + return -1; + } + + ret = gnutls_hash_init(&hash, qcrypto_hash_alg_map[alg]); + if (ret < 0) { + error_setg(errp, + "Unable to initialize hash algorithm: %s", + gnutls_strerror(ret)); + return -1; + } + + for (i = 0; i < niov; i++) { + gnutls_hash(hash, iov[i].iov_base, iov[i].iov_len); + } + + gnutls_hash_deinit(hash, *result); + return 0; +} + + +QCryptoHashDriver qcrypto_hash_lib_driver = { + .hash_bytesv = qcrypto_gnutls_hash_bytesv, +}; diff --git a/crypto/meson.build b/crypto/meson.build index f3bab7c067..e2f25810fc 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -28,6 +28,8 @@ if nettle.found() endif elif gcrypt.found() crypto_ss.add(gcrypt, files('hash-gcrypt.c', 'hmac-gcrypt.c', 'pbkdf-gcrypt.c')) +elif gnutls_crypto.found() + crypto_ss.add(gnutls, files('hash-gnutls.c', 'hmac-glib.c', 'pbkdf-stub.c') else crypto_ss.add(files('hash-glib.c', 'hmac-glib.c', 'pbkdf-stub.c')) endif From 678307b605da9ebbda3a6269b5a6ab2d3002e241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 25 Jun 2021 18:32:14 +0100 Subject: [PATCH 096/531] crypto: add gnutls hmac provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for using gnutls as a provider of the crypto hmac APIs. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- crypto/hmac-gnutls.c | 139 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 crypto/hmac-gnutls.c diff --git a/crypto/hmac-gnutls.c b/crypto/hmac-gnutls.c new file mode 100644 index 0000000000..24db383322 --- /dev/null +++ b/crypto/hmac-gnutls.c @@ -0,0 +1,139 @@ +/* + * QEMU Crypto hmac algorithms + * + * Copyright (c) 2021 Red Hat, Inc. + * + * Derived from hmac-gcrypt.c: + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + * + */ + +#include "qemu/osdep.h" +#include + +#include "qapi/error.h" +#include "crypto/hmac.h" +#include "hmacpriv.h" + +static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = { + [QCRYPTO_HASH_ALG_MD5] = GNUTLS_MAC_MD5, + [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_MAC_SHA1, + [QCRYPTO_HASH_ALG_SHA224] = GNUTLS_MAC_SHA224, + [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_MAC_SHA256, + [QCRYPTO_HASH_ALG_SHA384] = GNUTLS_MAC_SHA384, + [QCRYPTO_HASH_ALG_SHA512] = GNUTLS_MAC_SHA512, + [QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_MAC_RMD160, +}; + +typedef struct QCryptoHmacGnutls QCryptoHmacGnutls; +struct QCryptoHmacGnutls { + gnutls_hmac_hd_t handle; +}; + +bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) +{ + size_t i; + const gnutls_digest_algorithm_t *algs; + if (alg >= G_N_ELEMENTS(qcrypto_hmac_alg_map) || + qcrypto_hmac_alg_map[alg] == GNUTLS_DIG_UNKNOWN) { + return false; + } + algs = gnutls_digest_list(); + for (i = 0; algs[i] != GNUTLS_DIG_UNKNOWN; i++) { + if (algs[i] == qcrypto_hmac_alg_map[alg]) { + return true; + } + } + return false; +} + +void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg, + const uint8_t *key, size_t nkey, + Error **errp) +{ + QCryptoHmacGnutls *ctx; + int err; + + if (!qcrypto_hmac_supports(alg)) { + error_setg(errp, "Unsupported hmac algorithm %s", + QCryptoHashAlgorithm_str(alg)); + return NULL; + } + + ctx = g_new0(QCryptoHmacGnutls, 1); + + err = gnutls_hmac_init(&ctx->handle, + qcrypto_hmac_alg_map[alg], + (const void *)key, nkey); + if (err != 0) { + error_setg(errp, "Cannot initialize hmac: %s", + gnutls_strerror(err)); + goto error; + } + + return ctx; + +error: + g_free(ctx); + return NULL; +} + +static void +qcrypto_gnutls_hmac_ctx_free(QCryptoHmac *hmac) +{ + QCryptoHmacGnutls *ctx; + + ctx = hmac->opaque; + gnutls_hmac_deinit(ctx->handle, NULL); + + g_free(ctx); +} + +static int +qcrypto_gnutls_hmac_bytesv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp) +{ + QCryptoHmacGnutls *ctx; + uint32_t ret; + int i; + + ctx = hmac->opaque; + + for (i = 0; i < niov; i++) { + gnutls_hmac(ctx->handle, iov[i].iov_base, iov[i].iov_len); + } + + ret = gnutls_hmac_get_len(qcrypto_hmac_alg_map[hmac->alg]); + if (ret <= 0) { + error_setg(errp, "Unable to get hmac length: %s", + gnutls_strerror(ret)); + return -1; + } + + if (*resultlen == 0) { + *resultlen = ret; + *result = g_new0(uint8_t, *resultlen); + } else if (*resultlen != ret) { + error_setg(errp, "Result buffer size %zu is smaller than hmac %d", + *resultlen, ret); + return -1; + } + + gnutls_hmac_output(ctx->handle, *result); + + return 0; +} + +QCryptoHmacDriver qcrypto_hmac_lib_driver = { + .hmac_bytesv = qcrypto_gnutls_hmac_bytesv, + .hmac_free = qcrypto_gnutls_hmac_ctx_free, +}; From 8c1d3dc772352284e7f8757131f2ed3f483dd922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 25 Jun 2021 18:32:14 +0100 Subject: [PATCH 097/531] crypto: add gnutls pbkdf provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for using gnutls as a provider of the crypto pbkdf APIs. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- crypto/meson.build | 2 +- crypto/pbkdf-gnutls.c | 90 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 crypto/pbkdf-gnutls.c diff --git a/crypto/meson.build b/crypto/meson.build index e2f25810fc..95a6a83504 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -29,7 +29,7 @@ if nettle.found() elif gcrypt.found() crypto_ss.add(gcrypt, files('hash-gcrypt.c', 'hmac-gcrypt.c', 'pbkdf-gcrypt.c')) elif gnutls_crypto.found() - crypto_ss.add(gnutls, files('hash-gnutls.c', 'hmac-glib.c', 'pbkdf-stub.c') + crypto_ss.add(gnutls, files('hash-gnutls.c', 'hmac-gnutls.c', 'pbkdf-gnutls.c')) else crypto_ss.add(files('hash-glib.c', 'hmac-glib.c', 'pbkdf-stub.c')) endif diff --git a/crypto/pbkdf-gnutls.c b/crypto/pbkdf-gnutls.c new file mode 100644 index 0000000000..2dfbbd382c --- /dev/null +++ b/crypto/pbkdf-gnutls.c @@ -0,0 +1,90 @@ +/* + * QEMU Crypto PBKDF support (Password-Based Key Derivation Function) + * + * Copyright (c) 2021 Red Hat, Inc. + * + * 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.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 + * 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 . + * + */ + +#include "qemu/osdep.h" +#include +#include "qapi/error.h" +#include "crypto/pbkdf.h" + +bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash) +{ + switch (hash) { + case QCRYPTO_HASH_ALG_MD5: + case QCRYPTO_HASH_ALG_SHA1: + case QCRYPTO_HASH_ALG_SHA224: + case QCRYPTO_HASH_ALG_SHA256: + case QCRYPTO_HASH_ALG_SHA384: + case QCRYPTO_HASH_ALG_SHA512: + case QCRYPTO_HASH_ALG_RIPEMD160: + return true; + default: + return false; + } +} + +int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, + const uint8_t *key, size_t nkey, + const uint8_t *salt, size_t nsalt, + uint64_t iterations, + uint8_t *out, size_t nout, + Error **errp) +{ + static const int hash_map[QCRYPTO_HASH_ALG__MAX] = { + [QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5, + [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1, + [QCRYPTO_HASH_ALG_SHA224] = GNUTLS_DIG_SHA224, + [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256, + [QCRYPTO_HASH_ALG_SHA384] = GNUTLS_DIG_SHA384, + [QCRYPTO_HASH_ALG_SHA512] = GNUTLS_DIG_SHA512, + [QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_DIG_RMD160, + }; + int ret; + const gnutls_datum_t gkey = { (unsigned char *)key, nkey }; + const gnutls_datum_t gsalt = { (unsigned char *)salt, nsalt }; + + if (iterations > ULONG_MAX) { + error_setg_errno(errp, ERANGE, + "PBKDF iterations %llu must be less than %lu", + (long long unsigned)iterations, ULONG_MAX); + return -1; + } + + if (hash >= G_N_ELEMENTS(hash_map) || + hash_map[hash] == GNUTLS_DIG_UNKNOWN) { + error_setg_errno(errp, ENOSYS, + "PBKDF does not support hash algorithm %s", + QCryptoHashAlgorithm_str(hash)); + return -1; + } + + ret = gnutls_pbkdf2(hash_map[hash], + &gkey, + &gsalt, + iterations, + out, + nout); + if (ret != 0) { + error_setg(errp, "Cannot derive password: %s", + gnutls_strerror(ret)); + return -1; + } + + return 0; +} From 8bd0931f63008b1d50c8df75a611323a93c052bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 2 Jul 2021 17:38:33 +0100 Subject: [PATCH 098/531] crypto: prefer gnutls as the crypto backend if new enough MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we have gnutls >= 3.6.13, then it has enough functionality and performance that we can use it as the preferred crypto backend. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- meson.build | 59 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/meson.build b/meson.build index 38b89d424b..073269c59f 100644 --- a/meson.build +++ b/meson.build @@ -846,39 +846,50 @@ if not get_option('gnutls').auto() or have_system endif endif -# Gcrypt has priority over nettle +# We prefer use of gnutls for crypto, unless the options +# explicitly asked for nettle or gcrypt. +# +# If gnutls isn't available for crypto, then we'll prefer +# gcrypt over nettle for performance reasons. gcrypt = not_found nettle = not_found xts = 'none' + if get_option('nettle').enabled() and get_option('gcrypt').enabled() error('Only one of gcrypt & nettle can be enabled') -elif (not get_option('gcrypt').auto() or have_system) and not get_option('nettle').enabled() - gcrypt = dependency('libgcrypt', version: '>=1.8', - method: 'config-tool', - required: get_option('gcrypt'), - kwargs: static_kwargs) - # Debian has removed -lgpg-error from libgcrypt-config - # as it "spreads unnecessary dependencies" which in - # turn breaks static builds... - if gcrypt.found() and enable_static - gcrypt = declare_dependency(dependencies: [ - gcrypt, - cc.find_library('gpg-error', required: true, kwargs: static_kwargs)]) - endif endif -if (not get_option('nettle').auto() or have_system) and not gcrypt.found() - nettle = dependency('nettle', version: '>=3.4', - method: 'pkg-config', - required: get_option('nettle'), - kwargs: static_kwargs) - if nettle.found() and not cc.has_header('nettle/xts.h', dependencies: nettle) - xts = 'private' - endif -endif -if gcrypt.found() or nettle.found() + +# Explicit nettle/gcrypt request, so ignore gnutls for crypto +if get_option('nettle').enabled() or get_option('gcrypt').enabled() gnutls_crypto = not_found endif +if not gnutls_crypto.found() + if (not get_option('gcrypt').auto() or have_system) and not get_option('nettle').enabled() + gcrypt = dependency('libgcrypt', version: '>=1.8', + method: 'config-tool', + required: get_option('gcrypt'), + kwargs: static_kwargs) + # Debian has removed -lgpg-error from libgcrypt-config + # as it "spreads unnecessary dependencies" which in + # turn breaks static builds... + if gcrypt.found() and enable_static + gcrypt = declare_dependency(dependencies: [ + gcrypt, + cc.find_library('gpg-error', required: true, kwargs: static_kwargs)]) + endif + endif + if (not get_option('nettle').auto() or have_system) and not gcrypt.found() + nettle = dependency('nettle', version: '>=3.4', + method: 'pkg-config', + required: get_option('nettle'), + kwargs: static_kwargs) + if nettle.found() and not cc.has_header('nettle/xts.h', dependencies: nettle) + xts = 'private' + endif + endif +endif + gtk = not_found gtkx11 = not_found vte = not_found From 96916f36c4c86bd5f017cc58abca90b79693c878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 30 Apr 2021 12:59:06 +0100 Subject: [PATCH 099/531] net/rocker: use GDateTime for formatting timestamp in debug messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GDateTime APIs provided by GLib avoid portability pitfalls, such as some platforms where 'struct timeval.tv_sec' field is still 'long' instead of 'time_t'. When combined with automatic cleanup, GDateTime often results in simpler code too. Reviewed-by: Juan Quintela Signed-off-by: Daniel P. Berrangé --- hw/net/rocker/rocker.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/hw/net/rocker/rocker.h b/hw/net/rocker/rocker.h index 941c932265..412fa44d01 100644 --- a/hw/net/rocker/rocker.h +++ b/hw/net/rocker/rocker.h @@ -25,14 +25,9 @@ #if defined(DEBUG_ROCKER) # define DPRINTF(fmt, ...) \ do { \ - struct timeval tv; \ - char timestr[64]; \ - time_t now; \ - gettimeofday(&tv, NULL); \ - now = tv.tv_sec; \ - strftime(timestr, sizeof(timestr), "%T", localtime(&now)); \ - fprintf(stderr, "%s.%06ld ", timestr, tv.tv_usec); \ - fprintf(stderr, "ROCKER: " fmt, ## __VA_ARGS__); \ + g_autoptr(GDateTime) now = g_date_time_new_now_local(); \ + g_autofree char *nowstr = g_date_time_format(now, "%T.%f");\ + fprintf(stderr, "%s ROCKER: " fmt, nowstr, ## __VA_ARGS__);\ } while (0) #else static inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...) From cfb47f2178c2c9c81870aab0bc0c93e5758cff86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 30 Apr 2021 12:59:06 +0100 Subject: [PATCH 100/531] io: use GDateTime for formatting timestamp for websock headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GDateTime APIs provided by GLib avoid portability pitfalls, such as some platforms where 'struct timeval.tv_sec' field is still 'long' instead of 'time_t'. When combined with automatic cleanup, GDateTime often results in simpler code too. Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Daniel P. Berrangé --- io/channel-websock.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/io/channel-websock.c b/io/channel-websock.c index 03c1f7cb62..70889bb54d 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -177,15 +177,9 @@ qio_channel_websock_handshake_send_res(QIOChannelWebsock *ioc, static gchar *qio_channel_websock_date_str(void) { - struct tm tm; - time_t now = time(NULL); - char datebuf[128]; + g_autoptr(GDateTime) now = g_date_time_new_now_utc(); - gmtime_r(&now, &tm); - - strftime(datebuf, sizeof(datebuf), "%a, %d %b %Y %H:%M:%S GMT", &tm); - - return g_strdup(datebuf); + return g_date_time_format(now, "%a, %d %b %Y %H:%M:%S GMT"); } static void qio_channel_websock_handshake_send_res_err(QIOChannelWebsock *ioc, From 2ce949a4c187b2a6aa68ab03216ee271b408fa63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 30 Jun 2021 15:19:38 +0100 Subject: [PATCH 101/531] seccomp: don't block getters for resource control syscalls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recent GLibC calls sched_getaffinity in code paths related to malloc and when QEMU blocks access, it sends it off into a bad codepath resulting in stack exhaustion[1]. The GLibC bug is being fixed[2], but none the less, GLibC has valid reasons to want to use sched_getaffinity. It is not unreasonable for code to want to run many resource syscalls for information gathering, so it is a bit too harsh for QEMU to block them. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1975693 [2] https://sourceware.org/pipermail/libc-alpha/2021-June/128271.html Reviewed-by: Dr. David Alan Gilbert Acked-by: Eduardo Otubo Signed-off-by: Daniel P. Berrangé --- softmmu/qemu-seccomp.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/softmmu/qemu-seccomp.c b/softmmu/qemu-seccomp.c index 9c29d9cf00..f50026778c 100644 --- a/softmmu/qemu-seccomp.c +++ b/softmmu/qemu-seccomp.c @@ -97,17 +97,11 @@ static const struct QemuSeccompSyscall denylist[] = { { SCMP_SYS(vfork), QEMU_SECCOMP_SET_SPAWN }, { SCMP_SYS(execve), QEMU_SECCOMP_SET_SPAWN }, /* resource control */ - { SCMP_SYS(getpriority), QEMU_SECCOMP_SET_RESOURCECTL }, { SCMP_SYS(setpriority), QEMU_SECCOMP_SET_RESOURCECTL }, { SCMP_SYS(sched_setparam), QEMU_SECCOMP_SET_RESOURCECTL }, - { SCMP_SYS(sched_getparam), QEMU_SECCOMP_SET_RESOURCECTL }, { SCMP_SYS(sched_setscheduler), QEMU_SECCOMP_SET_RESOURCECTL, ARRAY_SIZE(sched_setscheduler_arg), sched_setscheduler_arg }, - { SCMP_SYS(sched_getscheduler), QEMU_SECCOMP_SET_RESOURCECTL }, { SCMP_SYS(sched_setaffinity), QEMU_SECCOMP_SET_RESOURCECTL }, - { SCMP_SYS(sched_getaffinity), QEMU_SECCOMP_SET_RESOURCECTL }, - { SCMP_SYS(sched_get_priority_max), QEMU_SECCOMP_SET_RESOURCECTL }, - { SCMP_SYS(sched_get_priority_min), QEMU_SECCOMP_SET_RESOURCECTL }, }; static inline __attribute__((unused)) int From 927fae0eb9af2bcde2cd2030d478d365f2edf7e9 Mon Sep 17 00:00:00 2001 From: Hyman Date: Wed, 10 Mar 2021 00:00:59 +0800 Subject: [PATCH 102/531] tests/migration: fix unix socket migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test aborts and error message as the following be throwed: "No such file or directory: '/var/tmp/qemu-migrate-{pid}.migrate", when the unix socket migration test nearly done. The reason is qemu removes the unix socket file after migration before guestperf.py script do it. So pre-check if the socket file exists when removing it to prevent the guestperf program from aborting. See also commit f9cc00346d3 ("tests/migration: fix unix socket batch migration"). Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Wainer dos Santos Moschetta Signed-off-by: Hyman Signed-off-by: Daniel P. Berrangé --- tests/migration/guestperf/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/migration/guestperf/engine.py b/tests/migration/guestperf/engine.py index 7c991c4407..87a6ab2009 100644 --- a/tests/migration/guestperf/engine.py +++ b/tests/migration/guestperf/engine.py @@ -423,7 +423,7 @@ class Engine(object): progress_history = ret[0] qemu_timings = ret[1] vcpu_timings = ret[2] - if uri[0:5] == "unix:": + if uri[0:5] == "unix:" and os.path.exists(uri[5:]): os.remove(uri[5:]) if os.path.exists(srcmonaddr): From 2edb76ea57a0cdf80076c8cf77e2acd60ce8c7f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 22 Jun 2021 15:19:55 +0100 Subject: [PATCH 103/531] docs: fix typo s/Intel/AMD/ in CPU model notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Pankaj Gupta Reviewed-by: Andrew Jones Reviewed-by: Yanan Wang Signed-off-by: Daniel P. Berrangé --- docs/system/cpu-models-x86.rst.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/system/cpu-models-x86.rst.inc b/docs/system/cpu-models-x86.rst.inc index f40ee03ecc..9119f5dff5 100644 --- a/docs/system/cpu-models-x86.rst.inc +++ b/docs/system/cpu-models-x86.rst.inc @@ -227,7 +227,7 @@ features are included if using "Host passthrough" or "Host model". Preferred CPU models for AMD x86 hosts ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The following CPU models are preferred for use on Intel hosts. +The following CPU models are preferred for use on AMD hosts. Administrators / applications are recommended to use the CPU model that matches the generation of the host CPUs in use. In a deployment with a mixture of host CPU models between machines, if live migration From ce8ee7c6264f18392f19113fd0a27326151b9d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 22 Jun 2021 15:30:43 +0100 Subject: [PATCH 104/531] qemu-options: re-arrange CPU topology options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The list of CPU topology options are presented in a fairly arbitrary order currently. Re-arrange them so that they're ordered from largest to smallest unit Reviewed-by: Pankaj Gupta Reviewed-by: Andrew Jones Reviewed-by: Yanan Wang Signed-off-by: Daniel P. Berrangé --- qemu-options.hx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 8965dabc83..6b72617844 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -196,17 +196,17 @@ SRST ERST DEF("smp", HAS_ARG, QEMU_OPTION_smp, - "-smp [cpus=]n[,maxcpus=cpus][,cores=cores][,threads=threads][,dies=dies][,sockets=sockets]\n" + "-smp [cpus=]n[,maxcpus=cpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]\n" " set the number of CPUs to 'n' [default=1]\n" - " maxcpus= maximum number of total cpus, including\n" + " maxcpus= maximum number of total CPUs, including\n" " offline CPUs for hotplug, etc\n" - " cores= number of CPU cores on one socket (for PC, it's on one die)\n" - " threads= number of threads on one CPU core\n" + " sockets= number of discrete sockets in the system\n" " dies= number of CPU dies on one socket (for PC only)\n" - " sockets= number of discrete sockets in the system\n", + " cores= number of CPU cores on one socket (for PC, it's on one die)\n" + " threads= number of threads on one CPU core\n", QEMU_ARCH_ALL) SRST -``-smp [cpus=]n[,cores=cores][,threads=threads][,dies=dies][,sockets=sockets][,maxcpus=maxcpus]`` +``-smp [cpus=]n[,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]`` Simulate an SMP system with n CPUs. On the PC target, up to 255 CPUs are supported. On Sparc32 target, Linux limits the number of usable CPUs to 4. For the PC target, the number of cores per die, the From b9361bdc1fb0968b13760cbf33afdd1dc602b9e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 22 Jun 2021 15:32:02 +0100 Subject: [PATCH 105/531] qemu-options: tweak to show that CPU count is optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The initial CPU count number is not required, if any of the topology options are given, since it can be computed. Reviewed-by: Pankaj Gupta Reviewed-by: Andrew Jones Reviewed-by: Yanan Wang Signed-off-by: Daniel P. Berrangé --- qemu-options.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 6b72617844..14ff35dd4e 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -196,7 +196,7 @@ SRST ERST DEF("smp", HAS_ARG, QEMU_OPTION_smp, - "-smp [cpus=]n[,maxcpus=cpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]\n" + "-smp [[cpus=]n][,maxcpus=cpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]\n" " set the number of CPUs to 'n' [default=1]\n" " maxcpus= maximum number of total CPUs, including\n" " offline CPUs for hotplug, etc\n" @@ -206,7 +206,7 @@ DEF("smp", HAS_ARG, QEMU_OPTION_smp, " threads= number of threads on one CPU core\n", QEMU_ARCH_ALL) SRST -``-smp [cpus=]n[,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]`` +``-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]`` Simulate an SMP system with n CPUs. On the PC target, up to 255 CPUs are supported. On Sparc32 target, Linux limits the number of usable CPUs to 4. For the PC target, the number of cores per die, the From 80d78357495837f1f0e53fbb6bca5fb793631d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 22 Jun 2021 16:17:09 +0100 Subject: [PATCH 106/531] qemu-options: rewrite help for -smp options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The -smp option help is peculiarly specific about mentioning the CPU upper limits, but these are wrong. The "PC" target has varying max CPU counts depending on the machine type picked. Notes about guest OS limits are inappropriate for QEMU docs. There are way too many machine types for it to be practical to mention actual limits, and some limits are even modified by downstream distribtions. Thus it is better to remove the specific limits entirely. The CPU topology reporting is also not neccessarily specific to the PC platform and descriptions around the rules of usage are somewhat terse. Expand this information with some examples to show effects of defaulting. Reviewed-by: Pankaj Gupta Reviewed-by: Andrew Jones Signed-off-by: Daniel P. Berrangé --- qemu-options.hx | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 14ff35dd4e..214c477dcc 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -207,14 +207,27 @@ DEF("smp", HAS_ARG, QEMU_OPTION_smp, QEMU_ARCH_ALL) SRST ``-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]`` - Simulate an SMP system with n CPUs. On the PC target, up to 255 CPUs - are supported. On Sparc32 target, Linux limits the number of usable - CPUs to 4. For the PC target, the number of cores per die, the - number of threads per cores, the number of dies per packages and the - total number of sockets can be specified. Missing values will be - computed. If any on the three values is given, the total number of - CPUs n can be omitted. maxcpus specifies the maximum number of - hotpluggable CPUs. + Simulate a SMP system with '\ ``n``\ ' CPUs initially present on + the machine type board. On boards supporting CPU hotplug, the optional + '\ ``maxcpus``\ ' parameter can be set to enable further CPUs to be + added at runtime. If omitted the maximum number of CPUs will be + set to match the initial CPU count. Both parameters are subject to + an upper limit that is determined by the specific machine type chosen. + + To control reporting of CPU topology information, the number of sockets, + dies per socket, cores per die, and threads per core can be specified. + The sum `` sockets * cores * dies * threads `` must be equal to the + maximum CPU count. CPU targets may only support a subset of the topology + parameters. Where a CPU target does not support use of a particular + topology parameter, its value should be assumed to be 1 for the purpose + of computing the CPU maximum count. + + Either the initial CPU count, or at least one of the topology parameters + must be specified. Values for any omitted parameters will be computed + from those which are given. Historically preference was given to the + coarsest topology parameters when computing missing values (ie sockets + preferred over cores, which were preferred over threads), however, this + behaviour is considered liable to change. ERST DEF("numa", HAS_ARG, QEMU_OPTION_numa, From b38a04f71f5bef5cb17c29eada99364b6a017e42 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Fri, 9 Jul 2021 15:29:26 +0100 Subject: [PATCH 107/531] Jobs based on custom runners: documentation and configuration placeholder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As described in the included documentation, the "custom runner" jobs extend the GitLab CI jobs already in place. One of their primary goals of catching and preventing regressions on a wider number of host systems than the ones provided by GitLab's shared runners. This sets the stage in which other community members can add their own machine configuration documentation/scripts, and accompanying job definitions. As a general rule, those newly added contributed jobs should run as "non-gating", until their reliability is verified (AKA "allow_failure: true"). Signed-off-by: Cleber Rosa Signed-off-by: Alex Bennée Reviewed-by: Alex Bennée Reviewed-by: Thomas Huth Reviewed-by: Willian Rampazzo Reviewed-by: Wainer dos Santos Moschetta Message-Id: <20210630012619.115262-2-crosa@redhat.com> Message-Id: <20210709143005.1554-2-alex.bennee@linaro.org> --- .gitlab-ci.d/custom-runners.yml | 14 ++++++++++++++ .gitlab-ci.d/qemu-project.yml | 1 + docs/devel/ci.rst | 32 ++++++++++++++++++++++++++++++++ docs/devel/index.rst | 1 + 4 files changed, 48 insertions(+) create mode 100644 .gitlab-ci.d/custom-runners.yml create mode 100644 docs/devel/ci.rst diff --git a/.gitlab-ci.d/custom-runners.yml b/.gitlab-ci.d/custom-runners.yml new file mode 100644 index 0000000000..a07b27384c --- /dev/null +++ b/.gitlab-ci.d/custom-runners.yml @@ -0,0 +1,14 @@ +# The CI jobs defined here require GitLab runners installed and +# registered on machines that match their operating system names, +# versions and architectures. This is in contrast to the other CI +# jobs that are intended to run on GitLab's "shared" runners. + +# Different than the default approach on "shared" runners, based on +# containers, the custom runners have no such *requirement*, as those +# jobs should be capable of running on operating systems with no +# compatible container implementation, or no support from +# gitlab-runner. To avoid problems that gitlab-runner can cause while +# reusing the GIT repository, let's enable the clone strategy, which +# guarantees a fresh repository on each job run. +variables: + GIT_STRATEGY: clone diff --git a/.gitlab-ci.d/qemu-project.yml b/.gitlab-ci.d/qemu-project.yml index 64cb2ba1da..dde8270301 100644 --- a/.gitlab-ci.d/qemu-project.yml +++ b/.gitlab-ci.d/qemu-project.yml @@ -9,3 +9,4 @@ include: - local: '/.gitlab-ci.d/crossbuilds.yml' - local: '/.gitlab-ci.d/buildtest.yml' - local: '/.gitlab-ci.d/static_checks.yml' + - local: '/.gitlab-ci.d/custom-runners.yml' diff --git a/docs/devel/ci.rst b/docs/devel/ci.rst new file mode 100644 index 0000000000..064ffa9988 --- /dev/null +++ b/docs/devel/ci.rst @@ -0,0 +1,32 @@ +== +CI +== + +QEMU has configurations enabled for a number of different CI services. +The most up to date information about them and their status can be +found at:: + + https://wiki.qemu.org/Testing/CI + +Jobs on Custom Runners +====================== + +Besides the jobs run under the various CI systems listed before, there +are a number additional jobs that will run before an actual merge. +These use the same GitLab CI's service/framework already used for all +other GitLab based CI jobs, but rely on additional systems, not the +ones provided by GitLab as "shared runners". + +The architecture of GitLab's CI service allows different machines to +be set up with GitLab's "agent", called gitlab-runner, which will take +care of running jobs created by events such as a push to a branch. +Here, the combination of a machine, properly configured with GitLab's +gitlab-runner, is called a "custom runner". + +The GitLab CI jobs definition for the custom runners are located under:: + + .gitlab-ci.d/custom-runners.yml + +Custom runners entail custom machines. To see a list of the machines +currently deployed in the QEMU GitLab CI and their maintainers, please +refer to the QEMU `wiki `__. diff --git a/docs/devel/index.rst b/docs/devel/index.rst index ba90badbbd..40a7e2ee6f 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -27,6 +27,7 @@ Contents: migration atomics stable-process + ci qtest decodetree secure-coding-practices From 159c5d177bf6f0caf1efb85b850b200ac7043c49 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Fri, 9 Jul 2021 15:29:27 +0100 Subject: [PATCH 108/531] Jobs based on custom runners: build environment docs and playbook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To run basic jobs on custom runners, the environment needs to be properly set up. The most common requirement is having the right packages installed. The playbook introduced here covers the QEMU's project s390x and aarch64 machines. At the time this is being proposed, those machines have already had this playbook applied to them. Signed-off-by: Cleber Rosa Signed-off-by: Alex Bennée Tested-by: Alex Bennée Tested-by: Willian Rampazzo Reviewed-by: Wainer dos Santos Moschetta Reviewed-by: Willian Rampazzo Reviewed-by: Alex Bennée Message-Id: <20210630012619.115262-3-crosa@redhat.com> Message-Id: <20210709143005.1554-3-alex.bennee@linaro.org> --- docs/devel/ci.rst | 40 +++++++++ scripts/ci/setup/.gitignore | 2 + scripts/ci/setup/build-environment.yml | 116 +++++++++++++++++++++++++ scripts/ci/setup/inventory.template | 1 + 4 files changed, 159 insertions(+) create mode 100644 scripts/ci/setup/.gitignore create mode 100644 scripts/ci/setup/build-environment.yml create mode 100644 scripts/ci/setup/inventory.template diff --git a/docs/devel/ci.rst b/docs/devel/ci.rst index 064ffa9988..bfedbb1025 100644 --- a/docs/devel/ci.rst +++ b/docs/devel/ci.rst @@ -30,3 +30,43 @@ The GitLab CI jobs definition for the custom runners are located under:: Custom runners entail custom machines. To see a list of the machines currently deployed in the QEMU GitLab CI and their maintainers, please refer to the QEMU `wiki `__. + +Machine Setup Howto +------------------- + +For all Linux based systems, the setup can be mostly automated by the +execution of two Ansible playbooks. Create an ``inventory`` file +under ``scripts/ci/setup``, such as this:: + + fully.qualified.domain + other.machine.hostname + +You may need to set some variables in the inventory file itself. One +very common need is to tell Ansible to use a Python 3 interpreter on +those hosts. This would look like:: + + fully.qualified.domain ansible_python_interpreter=/usr/bin/python3 + other.machine.hostname ansible_python_interpreter=/usr/bin/python3 + +Build environment +~~~~~~~~~~~~~~~~~ + +The ``scripts/ci/setup/build-environment.yml`` Ansible playbook will +set up machines with the environment needed to perform builds and run +QEMU tests. This playbook consists on the installation of various +required packages (and a general package update while at it). It +currently covers a number of different Linux distributions, but it can +be expanded to cover other systems. + +The minimum required version of Ansible successfully tested in this +playbook is 2.8.0 (a version check is embedded within the playbook +itself). To run the playbook, execute:: + + cd scripts/ci/setup + ansible-playbook -i inventory build-environment.yml + +Please note that most of the tasks in the playbook require superuser +privileges, such as those from the ``root`` account or those obtained +by ``sudo``. If necessary, please refer to ``ansible-playbook`` +options such as ``--become``, ``--become-method``, ``--become-user`` +and ``--ask-become-pass``. diff --git a/scripts/ci/setup/.gitignore b/scripts/ci/setup/.gitignore new file mode 100644 index 0000000000..ee088604d1 --- /dev/null +++ b/scripts/ci/setup/.gitignore @@ -0,0 +1,2 @@ +inventory + diff --git a/scripts/ci/setup/build-environment.yml b/scripts/ci/setup/build-environment.yml new file mode 100644 index 0000000000..581c1c75d1 --- /dev/null +++ b/scripts/ci/setup/build-environment.yml @@ -0,0 +1,116 @@ +# Copyright (c) 2021 Red Hat, Inc. +# +# Author: +# Cleber Rosa +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. +# +# This is an ansible playbook file. Run it to set up systems with the +# environment needed to build QEMU. +--- +- name: Installation of basic packages to build QEMU + hosts: all + tasks: + - name: Check for suitable ansible version + delegate_to: localhost + assert: + that: + - '((ansible_version.major == 2) and (ansible_version.minor >= 8)) or (ansible_version.major >= 3)' + msg: "Unsuitable ansible version, please use version 2.8.0 or later" + + - name: Update apt cache / upgrade packages via apt + apt: + update_cache: yes + upgrade: yes + when: + - ansible_facts['distribution'] == 'Ubuntu' + + - name: Install basic packages to build QEMU on Ubuntu 18.04/20.04 + package: + name: + # Originally from tests/docker/dockerfiles/ubuntu1804.docker + - ccache + - gcc + - gettext + - git + - glusterfs-common + - libaio-dev + - libattr1-dev + - libbrlapi-dev + - libbz2-dev + - libcacard-dev + - libcap-ng-dev + - libcurl4-gnutls-dev + - libdrm-dev + - libepoxy-dev + - libfdt-dev + - libgbm-dev + - libgtk-3-dev + - libibverbs-dev + - libiscsi-dev + - libjemalloc-dev + - libjpeg-turbo8-dev + - liblzo2-dev + - libncurses5-dev + - libncursesw5-dev + - libnfs-dev + - libnss3-dev + - libnuma-dev + - libpixman-1-dev + - librados-dev + - librbd-dev + - librdmacm-dev + - libsasl2-dev + - libsdl2-dev + - libseccomp-dev + - libsnappy-dev + - libspice-protocol-dev + - libssh-dev + - libusb-1.0-0-dev + - libusbredirhost-dev + - libvdeplug-dev + - libvte-2.91-dev + - libzstd-dev + - make + - python3-yaml + - python3-sphinx + - python3-sphinx-rtd-theme + - ninja-build + - sparse + - xfslibs-dev + state: present + when: + - ansible_facts['distribution'] == 'Ubuntu' + + - name: Install packages to build QEMU on Ubuntu 18.04/20.04 on non-s390x + package: + name: + - libspice-server-dev + - libxen-dev + state: present + when: + - ansible_facts['distribution'] == 'Ubuntu' + - ansible_facts['architecture'] != 's390x' + + - name: Install basic packages to build QEMU on Ubuntu 18.04 + package: + name: + # Originally from tests/docker/dockerfiles/ubuntu1804.docker + - clang + when: + - ansible_facts['distribution'] == 'Ubuntu' + - ansible_facts['distribution_version'] == '18.04' + + - name: Install basic packages to build QEMU on Ubuntu 20.04 + package: + name: + # Originally from tests/docker/dockerfiles/ubuntu2004.docker + - clang-10 + - genisoimage + - liblttng-ust-dev + - libslirp-dev + - netcat-openbsd + when: + - ansible_facts['distribution'] == 'Ubuntu' + - ansible_facts['distribution_version'] == '20.04' diff --git a/scripts/ci/setup/inventory.template b/scripts/ci/setup/inventory.template new file mode 100644 index 0000000000..2fbb50c4a8 --- /dev/null +++ b/scripts/ci/setup/inventory.template @@ -0,0 +1 @@ +localhost From 40de78c284b14a54fbdde78d588ddb6d766f2a5f Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Fri, 9 Jul 2021 15:29:28 +0100 Subject: [PATCH 109/531] Jobs based on custom runners: docs and gitlab-runner setup playbook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To have the jobs dispatched to custom runners, gitlab-runner must be installed, active as a service and properly configured. The variables file and playbook introduced here should help with those steps. The playbook introduced here covers the Linux distributions and has been primarily tested on OS/machines that the QEMU project has available to act as runners, namely: * Ubuntu 20.04 on aarch64 * Ubuntu 18.04 on s390x But, it should work on all other Linux distributions. Earlier versions were tested on FreeBSD too, so chances of success are high. Signed-off-by: Cleber Rosa Signed-off-by: Alex Bennée Tested-by: Willian Rampazzo Tested-by: Alex Bennée Reviewed-by: Willian Rampazzo Reviewed-by: Wainer dos Santos Moschetta Reviewed-by: Alex Bennée Message-Id: <20210630012619.115262-4-crosa@redhat.com> Message-Id: <20210709143005.1554-4-alex.bennee@linaro.org> --- docs/devel/ci.rst | 55 +++++++++++++++++++++++ scripts/ci/setup/.gitignore | 2 +- scripts/ci/setup/gitlab-runner.yml | 71 ++++++++++++++++++++++++++++++ scripts/ci/setup/vars.yml.template | 12 +++++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 scripts/ci/setup/gitlab-runner.yml create mode 100644 scripts/ci/setup/vars.yml.template diff --git a/docs/devel/ci.rst b/docs/devel/ci.rst index bfedbb1025..b3bf3ef615 100644 --- a/docs/devel/ci.rst +++ b/docs/devel/ci.rst @@ -70,3 +70,58 @@ privileges, such as those from the ``root`` account or those obtained by ``sudo``. If necessary, please refer to ``ansible-playbook`` options such as ``--become``, ``--become-method``, ``--become-user`` and ``--ask-become-pass``. + +gitlab-runner setup and registration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The gitlab-runner agent needs to be installed on each machine that +will run jobs. The association between a machine and a GitLab project +happens with a registration token. To find the registration token for +your repository/project, navigate on GitLab's web UI to: + + * Settings (the gears-like icon at the bottom of the left hand side + vertical toolbar), then + * CI/CD, then + * Runners, and click on the "Expand" button, then + * Under "Set up a specific Runner manually", look for the value under + "And this registration token:" + +Copy the ``scripts/ci/setup/vars.yml.template`` file to +``scripts/ci/setup/vars.yml``. Then, set the +``gitlab_runner_registration_token`` variable to the value obtained +earlier. + +To run the playbook, execute:: + + cd scripts/ci/setup + ansible-playbook -i inventory gitlab-runner.yml + +Following the registration, it's necessary to configure the runner tags, +and optionally other configurations on the GitLab UI. Navigate to: + + * Settings (the gears like icon), then + * CI/CD, then + * Runners, and click on the "Expand" button, then + * "Runners activated for this project", then + * Click on the "Edit" icon (next to the "Lock" Icon) + +Tags are very important as they are used to route specific jobs to +specific types of runners, so it's a good idea to double check that +the automatically created tags are consistent with the OS and +architecture. For instance, an Ubuntu 20.04 aarch64 system should +have tags set as:: + + ubuntu_20.04,aarch64 + +Because the job definition at ``.gitlab-ci.d/custom-runners.yml`` +would contain:: + + ubuntu-20.04-aarch64-all: + tags: + - ubuntu_20.04 + - aarch64 + +It's also recommended to: + + * increase the "Maximum job timeout" to something like ``2h`` + * give it a better Description diff --git a/scripts/ci/setup/.gitignore b/scripts/ci/setup/.gitignore index ee088604d1..f4a6183f1f 100644 --- a/scripts/ci/setup/.gitignore +++ b/scripts/ci/setup/.gitignore @@ -1,2 +1,2 @@ inventory - +vars.yml diff --git a/scripts/ci/setup/gitlab-runner.yml b/scripts/ci/setup/gitlab-runner.yml new file mode 100644 index 0000000000..1127db516f --- /dev/null +++ b/scripts/ci/setup/gitlab-runner.yml @@ -0,0 +1,71 @@ +# Copyright (c) 2021 Red Hat, Inc. +# +# Author: +# Cleber Rosa +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. +# +# This is an ansible playbook file. Run it to set up systems with the +# gitlab-runner agent. +--- +- name: Installation of gitlab-runner + hosts: all + vars_files: + - vars.yml + tasks: + - debug: + msg: 'Checking for a valid GitLab registration token' + failed_when: "gitlab_runner_registration_token == 'PLEASE_PROVIDE_A_VALID_TOKEN'" + + - name: Create a group for the gitlab-runner service + group: + name: gitlab-runner + + - name: Create a user for the gitlab-runner service + user: + user: gitlab-runner + group: gitlab-runner + comment: GitLab Runner + home: /home/gitlab-runner + shell: /bin/bash + + - name: Remove the .bash_logout file when on Ubuntu systems + file: + path: /home/gitlab-runner/.bash_logout + state: absent + when: "ansible_facts['distribution'] == 'Ubuntu'" + + - name: Set the Operating System for gitlab-runner + set_fact: + gitlab_runner_os: "{{ ansible_facts[\"system\"]|lower }}" + - debug: + msg: gitlab-runner OS is {{ gitlab_runner_os }} + + - name: Set the architecture for gitlab-runner + set_fact: + gitlab_runner_arch: "{{ ansible_to_gitlab_arch[ansible_facts[\"architecture\"]] }}" + - debug: + msg: gitlab-runner arch is {{ gitlab_runner_arch }} + + - name: Download the matching gitlab-runner + get_url: + dest: /usr/local/bin/gitlab-runner + url: "https://s3.amazonaws.com/gitlab-runner-downloads/v{{ gitlab_runner_version }}/binaries/gitlab-runner-{{ gitlab_runner_os }}-{{ gitlab_runner_arch }}" + owner: gitlab-runner + group: gitlab-runner + mode: u=rwx,g=rwx,o=rx + + - name: Register the gitlab-runner + command: "/usr/local/bin/gitlab-runner register --non-interactive --url {{ gitlab_runner_server_url }} --registration-token {{ gitlab_runner_registration_token }} --executor shell --tag-list {{ ansible_facts[\"architecture\"] }},{{ ansible_facts[\"distribution\"]|lower }}_{{ ansible_facts[\"distribution_version\"] }} --description '{{ ansible_facts[\"distribution\"] }} {{ ansible_facts[\"distribution_version\"] }} {{ ansible_facts[\"architecture\"] }} ({{ ansible_facts[\"os_family\"] }})'" + + - name: Install the gitlab-runner service using its own functionality + command: /usr/local/bin/gitlab-runner install --user gitlab-runner --working-directory /home/gitlab-runner + register: gitlab_runner_install_service_result + failed_when: "gitlab_runner_install_service_result.rc != 0 and \"already exists\" not in gitlab_runner_install_service_result.stderr" + + - name: Enable the gitlab-runner service + service: + name: gitlab-runner + state: started + enabled: yes diff --git a/scripts/ci/setup/vars.yml.template b/scripts/ci/setup/vars.yml.template new file mode 100644 index 0000000000..e48089761f --- /dev/null +++ b/scripts/ci/setup/vars.yml.template @@ -0,0 +1,12 @@ +# The version of the gitlab-runner to use +gitlab_runner_version: 13.12.0 +# The URL of the gitlab server to use, usually https://gitlab.com unless you're +# using a private GitLab instance +gitlab_runner_server_url: https://gitlab.com +# A mapping of the ansible to gitlab architecture nomenclature +ansible_to_gitlab_arch: + x86_64: amd64 + aarch64: arm64 + s390x: s390x +# A unique token made available by GitLab to your project for registering runners +gitlab_runner_registration_token: PLEASE_PROVIDE_A_VALID_TOKEN From 4799c2102333cee5ddc51051c035b1c6ea83c7f5 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Fri, 9 Jul 2021 15:29:29 +0100 Subject: [PATCH 110/531] Jobs based on custom runners: add job definitions for QEMU's machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QEMU project has two machines (aarch64 and s390x) that can be used for jobs that do build and run tests. This introduces those jobs, which are a mapping of custom scripts used for the same purpose. Signed-off-by: Cleber Rosa Signed-off-by: Alex Bennée Reviewed-by: Willian Rampazzo Reviewed-by: Wainer dos Santos Moschetta Message-Id: <20210630012619.115262-5-crosa@redhat.com> Message-Id: <20210709143005.1554-5-alex.bennee@linaro.org> --- .gitlab-ci.d/custom-runners.yml | 208 ++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) diff --git a/.gitlab-ci.d/custom-runners.yml b/.gitlab-ci.d/custom-runners.yml index a07b27384c..061d3cdfed 100644 --- a/.gitlab-ci.d/custom-runners.yml +++ b/.gitlab-ci.d/custom-runners.yml @@ -12,3 +12,211 @@ # guarantees a fresh repository on each job run. variables: GIT_STRATEGY: clone + +# All ubuntu-18.04 jobs should run successfully in an environment +# setup by the scripts/ci/setup/build-environment.yml task +# "Install basic packages to build QEMU on Ubuntu 18.04/20.04" +ubuntu-18.04-s390x-all-linux-static: + allow_failure: true + needs: [] + stage: build + tags: + - ubuntu_18.04 + - s390x + rules: + - if: '$CI_COMMIT_BRANCH =~ /^staging/' + script: + # --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763 + # --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages + - mkdir build + - cd build + - ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh + - make --output-sync -j`nproc` + - make --output-sync -j`nproc` check V=1 + - make --output-sync -j`nproc` check-tcg V=1 + +ubuntu-18.04-s390x-all: + allow_failure: true + needs: [] + stage: build + tags: + - ubuntu_18.04 + - s390x + rules: + - if: '$CI_COMMIT_BRANCH =~ /^staging/' + script: + - mkdir build + - cd build + - ../configure --disable-libssh + - make --output-sync -j`nproc` + - make --output-sync -j`nproc` check V=1 + +ubuntu-18.04-s390x-alldbg: + allow_failure: true + needs: [] + stage: build + tags: + - ubuntu_18.04 + - s390x + rules: + - if: '$CI_COMMIT_BRANCH =~ /^staging/' + script: + - mkdir build + - cd build + - ../configure --enable-debug --disable-libssh + - make clean + - make --output-sync -j`nproc` + - make --output-sync -j`nproc` check V=1 + +ubuntu-18.04-s390x-clang: + allow_failure: true + needs: [] + stage: build + tags: + - ubuntu_18.04 + - s390x + rules: + - if: '$CI_COMMIT_BRANCH =~ /^staging/' + when: manual + script: + - mkdir build + - cd build + - ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers + - make --output-sync -j`nproc` + - make --output-sync -j`nproc` check V=1 + +ubuntu-18.04-s390x-tci: + allow_failure: true + needs: [] + stage: build + tags: + - ubuntu_18.04 + - s390x + rules: + - if: '$CI_COMMIT_BRANCH =~ /^staging/' + script: + - mkdir build + - cd build + - ../configure --disable-libssh --enable-tcg-interpreter + - make --output-sync -j`nproc` + +ubuntu-18.04-s390x-notcg: + allow_failure: true + needs: [] + stage: build + tags: + - ubuntu_18.04 + - s390x + rules: + - if: '$CI_COMMIT_BRANCH =~ /^staging/' + when: manual + script: + - mkdir build + - cd build + - ../configure --disable-libssh --disable-tcg + - make --output-sync -j`nproc` + - make --output-sync -j`nproc` check V=1 + +# All ubuntu-20.04 jobs should run successfully in an environment +# setup by the scripts/ci/setup/qemu/build-environment.yml task +# "Install basic packages to build QEMU on Ubuntu 18.04/20.04" +ubuntu-20.04-aarch64-all-linux-static: + allow_failure: true + needs: [] + stage: build + tags: + - ubuntu_20.04 + - aarch64 + rules: + - if: '$CI_COMMIT_BRANCH =~ /^staging/' + script: + # --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763 + # --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages + - mkdir build + - cd build + - ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh + - make --output-sync -j`nproc` + - make --output-sync -j`nproc` check V=1 + - make --output-sync -j`nproc` check-tcg V=1 + +ubuntu-20.04-aarch64-all: + allow_failure: true + needs: [] + stage: build + tags: + - ubuntu_20.04 + - aarch64 + rules: + - if: '$CI_COMMIT_BRANCH =~ /^staging/' + script: + - mkdir build + - cd build + - ../configure --disable-libssh + - make --output-sync -j`nproc` + - make --output-sync -j`nproc` check V=1 + +ubuntu-20.04-aarch64-alldbg: + allow_failure: true + needs: [] + stage: build + tags: + - ubuntu_20.04 + - aarch64 + rules: + - if: '$CI_COMMIT_BRANCH =~ /^staging/' + script: + - mkdir build + - cd build + - ../configure --enable-debug --disable-libssh + - make clean + - make --output-sync -j`nproc` + - make --output-sync -j`nproc` check V=1 + +ubuntu-20.04-aarch64-clang: + allow_failure: true + needs: [] + stage: build + tags: + - ubuntu_20.04 + - aarch64 + rules: + - if: '$CI_COMMIT_BRANCH =~ /^staging/' + when: manual + script: + - mkdir build + - cd build + - ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers + - make --output-sync -j`nproc` + - make --output-sync -j`nproc` check V=1 + +ubuntu-20.04-aarch64-tci: + allow_failure: true + needs: [] + stage: build + tags: + - ubuntu_20.04 + - aarch64 + rules: + - if: '$CI_COMMIT_BRANCH =~ /^staging/' + script: + - mkdir build + - cd build + - ../configure --disable-libssh --enable-tcg-interpreter + - make --output-sync -j`nproc` + +ubuntu-20.04-aarch64-notcg: + allow_failure: true + needs: [] + stage: build + tags: + - ubuntu_20.04 + - aarch64 + rules: + - if: '$CI_COMMIT_BRANCH =~ /^staging/' + when: manual + script: + - mkdir build + - cd build + - ../configure --disable-libssh --disable-tcg + - make --output-sync -j`nproc` + - make --output-sync -j`nproc` check V=1 From 0f1ea9c7a602f0349137672f14c4c2a9671ef28e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 9 Jul 2021 15:29:30 +0100 Subject: [PATCH 111/531] tests/tcg: also disable the signals test for plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will be more important when plugins is enabled by default. Fixes: eba61056e4 ("tests/tcg: generalise the disabling of the signals test") Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20210709143005.1554-6-alex.bennee@linaro.org> --- tests/tcg/i386/Makefile.target | 3 +++ tests/tcg/multiarch/Makefile.target | 2 ++ 2 files changed, 5 insertions(+) diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target index f7efaab918..b0a2128980 100644 --- a/tests/tcg/i386/Makefile.target +++ b/tests/tcg/i386/Makefile.target @@ -65,6 +65,9 @@ run-plugin-%-with-libinsn.so: -d plugin -D $*-with-libinsn.so.pout $*, \ "$* (inline) on $(TARGET_NAME)") +run-plugin-signals-with-libinsn.so: + $(call skip-test, $<, "BROKEN awaiting sigframe clean-ups and vdso support") + # Update TESTS I386_TESTS:=$(filter-out $(SKIP_I386_TESTS), $(ALL_X86_TESTS)) TESTS=$(MULTIARCH_TESTS) $(I386_TESTS) diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index d57a115873..85a6fb7a2e 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -37,6 +37,8 @@ signals: LDFLAGS+=-lrt -lpthread run-signals: signals $(call skip-test, $<, "BROKEN awaiting sigframe clean-ups and vdso support") +run-plugin-signals-with-%: + $(call skip-test, $<, "BROKEN awaiting sigframe clean-ups and vdso support") # We define the runner for test-mmap after the individual # architectures have defined their supported pages sizes. If no From 3cfafd317c97558b66d93b6f338b95c695ad8d39 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 12 Jul 2021 17:18:10 +0200 Subject: [PATCH 112/531] meson: fix condition for io_uring stubs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CONFIG_LINUX_IO_URING is not included in config-host.mak and therefore is not usable in "when" clauses. Check the availability of the library, which matches the condition for the non-stubbed version block/io_uring.c. At this point, the difference between libraries that have config-host.mak entries and those that do not is quite confusing. The remaining ~dozen should be converted in 6.2. Signed-off-by: Paolo Bonzini Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210712151810.508249-1-pbonzini@redhat.com> Signed-off-by: Alex Bennée --- stubs/meson.build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stubs/meson.build b/stubs/meson.build index 2e79ff9f4d..d3fa8646b3 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -15,7 +15,9 @@ stub_ss.add(files('fdset.c')) stub_ss.add(files('fw_cfg.c')) stub_ss.add(files('gdbstub.c')) stub_ss.add(files('get-vm-name.c')) -stub_ss.add(when: 'CONFIG_LINUX_IO_URING', if_true: files('io_uring.c')) +if linux_io_uring.found() + stub_ss.add(files('io_uring.c')) +endif stub_ss.add(files('iothread-lock.c')) stub_ss.add(files('isa-bus.c')) stub_ss.add(files('is-daemonized.c')) From a1b176f9046a94ae963099a055cde2323dc7c012 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 12 Jul 2021 14:22:08 +0200 Subject: [PATCH 113/531] disable modular TCG on Darwin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accelerator modularity does not work on Darwin: ld: illegal thread local variable reference to regular symbol _current_cpu for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) Fix by avoiding modular TCG builds. Signed-off-by: Paolo Bonzini Message-Id: <20210712122208.456264-1-pbonzini@redhat.com> [AJB: manually merged typo fix] Signed-off-by: Alex Bennée --- meson.build | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index b0e2b9a8a0..512ee2e926 100644 --- a/meson.build +++ b/meson.build @@ -92,7 +92,11 @@ if cpu in ['x86', 'x86_64'] } endif -modular_tcg = ['i386-softmmu', 'x86_64-softmmu'] +modular_tcg = [] +# Darwin does not support references to thread-local variables in modules +if targetos != 'darwin' + modular_tcg = ['i386-softmmu', 'x86_64-softmmu'] +endif edk2_targets = [ 'arm-softmmu', 'aarch64-softmmu', 'i386-softmmu', 'x86_64-softmmu' ] install_edk2_blobs = false From 8f4aea712ffc4f2c20c293dac26df8688f497a9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:31 +0100 Subject: [PATCH 114/531] build: validate that system capstone works before using it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some versions of capstone have shipped a broken pkg-config file which puts the -I path without the trailing '/capstone' suffix. This breaks the ability to "#include ". Upstream and most distros have fixed this, but a few stragglers remain, notably FreeBSD. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Reviewed-by: Willian Rampazzo Reviewed-by: Richard Henderson Message-Id: <20210625172211.451010-2-berrange@redhat.com> Message-Id: <20210709143005.1554-7-alex.bennee@linaro.org> --- meson.build | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/meson.build b/meson.build index 512ee2e926..89c09ed7ea 100644 --- a/meson.build +++ b/meson.build @@ -1657,6 +1657,19 @@ if capstone_opt in ['enabled', 'auto', 'system'] kwargs: static_kwargs, method: 'pkg-config', required: capstone_opt == 'system' or capstone_opt == 'enabled' and not have_internal) + + # Some versions of capstone have broken pkg-config file + # that reports a wrong -I path, causing the #include to + # fail later. If the system has such a broken version + # do not use it. + if capstone.found() and not cc.compiles('#include ', + dependencies: [capstone]) + capstone = not_found + if capstone_opt == 'system' + error('system capstone requested, it does not appear to work') + endif + endif + if capstone.found() capstone_opt = 'system' elif have_internal From 0e103a65ba1c56871cad3ab4be3aee1d984d65f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:32 +0100 Subject: [PATCH 115/531] gitlab: support for FreeBSD 12, 13 and macOS 11 via cirrus-run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for running 4 jobs via Cirrus CI runners: * FreeBSD 12 * FreeBSD 13 * macOS 11 with default XCode * macOS 11 with latest XCode The gitlab job uses a container published by the libvirt-ci project (https://gitlab.com/libvirt/libvirt-ci) that contains the 'cirrus-run' command. This accepts a short yaml file that describes a single Cirrus CI job, runs it using the Cirrus CI REST API, and reports any output to the console. In this way Cirrus CI is effectively working as an indirect custom runner for GitLab CI pipelines. The key benefit is that Cirrus CI job results affect the GitLab CI pipeline result and so the user only has look at one CI dashboard. [AJB: remove $TEMPORARILY_DISABLED condition, s/py37/py38/] Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Message-Id: <20210625172211.451010-3-berrange@redhat.com> Message-Id: <20210709143005.1554-8-alex.bennee@linaro.org> --- .gitlab-ci.d/cirrus.yml | 102 ++++++++++++++++++++++++++++ .gitlab-ci.d/cirrus/README.rst | 54 +++++++++++++++ .gitlab-ci.d/cirrus/build.yml | 35 ++++++++++ .gitlab-ci.d/cirrus/freebsd-12.vars | 13 ++++ .gitlab-ci.d/cirrus/freebsd-13.vars | 13 ++++ .gitlab-ci.d/cirrus/macos-11.vars | 15 ++++ .gitlab-ci.d/qemu-project.yml | 1 + 7 files changed, 233 insertions(+) create mode 100644 .gitlab-ci.d/cirrus.yml create mode 100644 .gitlab-ci.d/cirrus/README.rst create mode 100644 .gitlab-ci.d/cirrus/build.yml create mode 100644 .gitlab-ci.d/cirrus/freebsd-12.vars create mode 100644 .gitlab-ci.d/cirrus/freebsd-13.vars create mode 100644 .gitlab-ci.d/cirrus/macos-11.vars diff --git a/.gitlab-ci.d/cirrus.yml b/.gitlab-ci.d/cirrus.yml new file mode 100644 index 0000000000..60b13ed83f --- /dev/null +++ b/.gitlab-ci.d/cirrus.yml @@ -0,0 +1,102 @@ +# Jobs that we delegate to Cirrus CI because they require an operating +# system other than Linux. These jobs will only run if the required +# setup has been performed on the GitLab account. +# +# The Cirrus CI configuration is generated by replacing target-specific +# variables in a generic template: some of these variables are provided +# when the GitLab CI job is defined, others are taken from a shell +# snippet generated using lcitool. +# +# Note that the $PATH environment variable has to be treated with +# special care, because we can't just override it at the GitLab CI job +# definition level or we risk breaking it completely. +.cirrus_build_job: + stage: build + image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master + needs: [] + allow_failure: true + script: + - source .gitlab-ci.d/cirrus/$NAME.vars + - sed -e "s|[@]CI_REPOSITORY_URL@|$CI_REPOSITORY_URL|g" + -e "s|[@]CI_COMMIT_REF_NAME@|$CI_COMMIT_REF_NAME|g" + -e "s|[@]CI_COMMIT_SHA@|$CI_COMMIT_SHA|g" + -e "s|[@]CIRRUS_VM_INSTANCE_TYPE@|$CIRRUS_VM_INSTANCE_TYPE|g" + -e "s|[@]CIRRUS_VM_IMAGE_SELECTOR@|$CIRRUS_VM_IMAGE_SELECTOR|g" + -e "s|[@]CIRRUS_VM_IMAGE_NAME@|$CIRRUS_VM_IMAGE_NAME|g" + -e "s|[@]CIRRUS_VM_CPUS@|$CIRRUS_VM_CPUS|g" + -e "s|[@]CIRRUS_VM_RAM@|$CIRRUS_VM_RAM|g" + -e "s|[@]UPDATE_COMMAND@|$UPDATE_COMMAND|g" + -e "s|[@]INSTALL_COMMAND@|$INSTALL_COMMAND|g" + -e "s|[@]PATH@|$PATH_EXTRA${PATH_EXTRA:+:}\$PATH|g" + -e "s|[@]PKG_CONFIG_PATH@|$PKG_CONFIG_PATH|g" + -e "s|[@]PKGS@|$PKGS|g" + -e "s|[@]MAKE@|$MAKE|g" + -e "s|[@]PYTHON@|$PYTHON|g" + -e "s|[@]PIP3@|$PIP3|g" + -e "s|[@]PYPI_PKGS@|$PYPI_PKGS|g" + -e "s|[@]CONFIGURE_ARGS@|$CONFIGURE_ARGS|g" + -e "s|[@]TEST_TARGETSS@|$TEST_TARGETSS|g" + <.gitlab-ci.d/cirrus/build.yml >.gitlab-ci.d/cirrus/$NAME.yml + - cat .gitlab-ci.d/cirrus/$NAME.yml + - cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml + rules: + - if: "$CIRRUS_GITHUB_REPO && $CIRRUS_API_TOKEN" + +x64-freebsd-12-build: + extends: .cirrus_build_job + variables: + NAME: freebsd-12 + CIRRUS_VM_INSTANCE_TYPE: freebsd_instance + CIRRUS_VM_IMAGE_SELECTOR: image_family + CIRRUS_VM_IMAGE_NAME: freebsd-12-2 + CIRRUS_VM_CPUS: 8 + CIRRUS_VM_RAM: 8G + UPDATE_COMMAND: pkg update + INSTALL_COMMAND: pkg install -y + # TODO: Enable gnutls again once FreeBSD's libtasn1 got fixed + # See: https://gitlab.com/gnutls/libtasn1/-/merge_requests/71 + CONFIGURE_ARGS: --disable-gnutls + TEST_TARGETS: check + +x64-freebsd-13-build: + extends: .cirrus_build_job + variables: + NAME: freebsd-13 + CIRRUS_VM_INSTANCE_TYPE: freebsd_instance + CIRRUS_VM_IMAGE_SELECTOR: image_family + CIRRUS_VM_IMAGE_NAME: freebsd-13-0 + CIRRUS_VM_CPUS: 8 + CIRRUS_VM_RAM: 8G + UPDATE_COMMAND: pkg update + INSTALL_COMMAND: pkg install -y + TEST_TARGETS: check + +x64-macos-11-base-build: + extends: .cirrus_build_job + variables: + NAME: macos-11 + CIRRUS_VM_INSTANCE_TYPE: osx_instance + CIRRUS_VM_IMAGE_SELECTOR: image + CIRRUS_VM_IMAGE_NAME: big-sur-base + CIRRUS_VM_CPUS: 12 + CIRRUS_VM_RAM: 24G + UPDATE_COMMAND: brew update + INSTALL_COMMAND: brew install + PATH_EXTRA: /usr/local/opt/ccache/libexec:/usr/local/opt/gettext/bin + PKG_CONFIG_PATH: /usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/ncurses/lib/pkgconfig:/usr/local/opt/readline/lib/pkgconfig + TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64 + +x64-macos-11-xcode-build: + extends: .cirrus_build_job + variables: + NAME: macos-11 + CIRRUS_VM_INSTANCE_TYPE: osx_instance + CIRRUS_VM_IMAGE_SELECTOR: image + CIRRUS_VM_IMAGE_NAME: big-sur-xcode + CIRRUS_VM_CPUS: 12 + CIRRUS_VM_RAM: 24G + UPDATE_COMMAND: brew update + INSTALL_COMMAND: brew install + PATH_EXTRA: /usr/local/opt/ccache/libexec:/usr/local/opt/gettext/bin + PKG_CONFIG_PATH: /usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/ncurses/lib/pkgconfig:/usr/local/opt/readline/lib/pkgconfig + TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64 diff --git a/.gitlab-ci.d/cirrus/README.rst b/.gitlab-ci.d/cirrus/README.rst new file mode 100644 index 0000000000..657b0706d7 --- /dev/null +++ b/.gitlab-ci.d/cirrus/README.rst @@ -0,0 +1,54 @@ +Cirrus CI integration +===================== + +GitLab CI shared runners only provide a docker environment running on Linux. +While it is possible to provide private runners for non-Linux platforms this +is not something most contributors/maintainers will wish to do. + +To work around this limitation, we take advantage of `Cirrus CI`_'s free +offering: more specifically, we use the `cirrus-run`_ script to trigger Cirrus +CI jobs from GitLab CI jobs so that Cirrus CI job output is integrated into +the main GitLab CI pipeline dashboard. + +There is, however, some one-time setup required. If you want FreeBSD and macOS +builds to happen when you push to your GitLab repository, you need to + +* set up a GitHub repository for the project, eg. ``yourusername/qemu``. + This repository needs to exist for cirrus-run to work, but it doesn't need to + be kept up to date, so you can create it and then forget about it; + +* enable the `Cirrus CI GitHub app`_ for your GitHub account; + +* sign up for Cirrus CI. It's enough to log into the website using your GitHub + account; + +* grab an API token from the `Cirrus CI settings`_ page; + +* it may be necessary to push an empty ``.cirrus.yml`` file to your github fork + for Cirrus CI to properly recognize the project. You can check whether + Cirrus CI knows about your project by navigating to: + + ``https://cirrus-ci.com/yourusername/qemu`` + +* in the *CI/CD / Variables* section of the settings page for your GitLab + repository, create two new variables: + + * ``CIRRUS_GITHUB_REPO``, containing the name of the GitHub repository + created earlier, eg. ``yourusername/qemu``; + + * ``CIRRUS_API_TOKEN``, containing the Cirrus CI API token generated earlier. + This variable **must** be marked as *Masked*, because anyone with knowledge + of it can impersonate you as far as Cirrus CI is concerned. + + Neither of these variables should be marked as *Protected*, because in + general you'll want to be able to trigger Cirrus CI builds from non-protected + branches. + +Once this one-time setup is complete, you can just keep pushing to your GitLab +repository as usual and you'll automatically get the additional CI coverage. + + +.. _Cirrus CI GitHub app: https://github.com/marketplace/cirrus-ci +.. _Cirrus CI settings: https://cirrus-ci.com/settings/profile/ +.. _Cirrus CI: https://cirrus-ci.com/ +.. _cirrus-run: https://github.com/sio/cirrus-run/ diff --git a/.gitlab-ci.d/cirrus/build.yml b/.gitlab-ci.d/cirrus/build.yml new file mode 100644 index 0000000000..857bdc5536 --- /dev/null +++ b/.gitlab-ci.d/cirrus/build.yml @@ -0,0 +1,35 @@ +@CIRRUS_VM_INSTANCE_TYPE@: + @CIRRUS_VM_IMAGE_SELECTOR@: @CIRRUS_VM_IMAGE_NAME@ + cpu: @CIRRUS_VM_CPUS@ + memory: @CIRRUS_VM_RAM@ + +env: + CIRRUS_CLONE_DEPTH: 1 + CI_REPOSITORY_URL: "@CI_REPOSITORY_URL@" + CI_COMMIT_REF_NAME: "@CI_COMMIT_REF_NAME@" + CI_COMMIT_SHA: "@CI_COMMIT_SHA@" + PATH: "@PATH@" + PKG_CONFIG_PATH: "@PKG_CONFIG_PATH@" + PYTHON: "@PYTHON@" + MAKE: "@MAKE@" + CONFIGURE_ARGS: "@CONFIGURE_ARGS@" + +build_task: + install_script: + - @UPDATE_COMMAND@ + - @INSTALL_COMMAND@ @PKGS@ + - if test -n "@PYPI_PKGS@" ; then @PIP3@ install @PYPI_PKGS@ ; fi + clone_script: + - git clone --depth 100 "$CI_REPOSITORY_URL" . + - git fetch origin "$CI_COMMIT_REF_NAME" + - git reset --hard "$CI_COMMIT_SHA" + build_script: + - mkdir build + - cd build + - ../configure --enable-werror $CONFIGURE_ARGS + || { cat config.log meson-logs/meson-log.txt; exit 1; } + - $MAKE -j$(sysctl -n hw.ncpu) + - for TARGET in $TEST_TARGETS ; + do + $MAKE -j$(sysctl -n hw.ncpu) $TARGET V=1 ; + done diff --git a/.gitlab-ci.d/cirrus/freebsd-12.vars b/.gitlab-ci.d/cirrus/freebsd-12.vars new file mode 100644 index 0000000000..2099b21354 --- /dev/null +++ b/.gitlab-ci.d/cirrus/freebsd-12.vars @@ -0,0 +1,13 @@ +# THIS FILE WAS AUTO-GENERATED +# +# $ lcitool variables freebsd-12 qemu +# +# https://gitlab.com/libvirt/libvirt-ci/-/commit/c7e275ab27ac0dcd09da290817b9adeea1fd1eb1 + +PACKAGING_COMMAND='pkg' +CCACHE='/usr/local/bin/ccache' +MAKE='/usr/local/bin/gmake' +NINJA='/usr/local/bin/ninja' +PYTHON='/usr/local/bin/python3' +PIP3='/usr/local/bin/pip-3.8' +PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' diff --git a/.gitlab-ci.d/cirrus/freebsd-13.vars b/.gitlab-ci.d/cirrus/freebsd-13.vars new file mode 100644 index 0000000000..323fe806d5 --- /dev/null +++ b/.gitlab-ci.d/cirrus/freebsd-13.vars @@ -0,0 +1,13 @@ +# THIS FILE WAS AUTO-GENERATED +# +# $ lcitool variables freebsd-13 qemu +# +# https://gitlab.com/libvirt/libvirt-ci/-/commit/c7e275ab27ac0dcd09da290817b9adeea1fd1eb1 + +PACKAGING_COMMAND='pkg' +CCACHE='/usr/local/bin/ccache' +MAKE='/usr/local/bin/gmake' +NINJA='/usr/local/bin/ninja' +PYTHON='/usr/local/bin/python3' +PIP3='/usr/local/bin/pip-3.8' +PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' diff --git a/.gitlab-ci.d/cirrus/macos-11.vars b/.gitlab-ci.d/cirrus/macos-11.vars new file mode 100644 index 0000000000..cbec8a44a3 --- /dev/null +++ b/.gitlab-ci.d/cirrus/macos-11.vars @@ -0,0 +1,15 @@ +# THIS FILE WAS AUTO-GENERATED +# +# $ lcitool variables macos-11 qemu +# +# https://gitlab.com/libvirt/libvirt-ci/-/commit/c7e275ab27ac0dcd09da290817b9adeea1fd1eb1 + +PACKAGING_COMMAND='brew' +CCACHE='/usr/local/bin/ccache' +MAKE='/usr/local/bin/gmake' +NINJA='/usr/local/bin/ninja' +PYTHON='/usr/local/bin/python3' +PIP3='/usr/local/bin/pip3' +PKGS='bash bc bzip2 capstone ccache cpanminus ctags curl dbus diffutils gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb libxml2 llvm lzo make meson ncurses nettle ninja perl pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 zlib zstd' +PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme virtualenv' +CPAN_PKGS='Test::Harness' diff --git a/.gitlab-ci.d/qemu-project.yml b/.gitlab-ci.d/qemu-project.yml index dde8270301..b3d79bc429 100644 --- a/.gitlab-ci.d/qemu-project.yml +++ b/.gitlab-ci.d/qemu-project.yml @@ -10,3 +10,4 @@ include: - local: '/.gitlab-ci.d/buildtest.yml' - local: '/.gitlab-ci.d/static_checks.yml' - local: '/.gitlab-ci.d/custom-runners.yml' + - local: '/.gitlab-ci.d/cirrus.yml' From b92da9acb14bd927fbe4c4fd200cf528dc03ecfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:33 +0100 Subject: [PATCH 116/531] cirrus: delete FreeBSD and macOS jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The builds for these two platforms can now be performed from GitLab CI using cirrus-run. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Reviewed-by: Willian Rampazzo Reviewed-by: Wainer dos Santos Moschetta Message-Id: <20210625172211.451010-4-berrange@redhat.com> Message-Id: <20210709143005.1554-9-alex.bennee@linaro.org> --- .cirrus.yml | 55 ----------------------------------------------------- 1 file changed, 55 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index f4bf49b704..02c43a074a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,61 +1,6 @@ env: CIRRUS_CLONE_DEPTH: 1 -freebsd_12_task: - freebsd_instance: - image_family: freebsd-12-2 - cpu: 8 - memory: 8G - install_script: - - ASSUME_ALWAYS_YES=yes pkg bootstrap -f ; - - pkg install -y bash curl cyrus-sasl git glib gmake gnutls gsed - nettle perl5 pixman pkgconf png usbredir ninja - script: - - mkdir build - - cd build - # TODO: Enable gnutls again once FreeBSD's libtasn1 got fixed - # See: https://gitlab.com/gnutls/libtasn1/-/merge_requests/71 - - ../configure --enable-werror --disable-gnutls - || { cat config.log meson-logs/meson-log.txt; exit 1; } - - gmake -j$(sysctl -n hw.ncpu) - - gmake -j$(sysctl -n hw.ncpu) check V=1 - -macos_task: - osx_instance: - image: catalina-base - install_script: - - brew install pkg-config python gnu-sed glib pixman make sdl2 bash ninja - script: - - mkdir build - - cd build - - ../configure --python=/usr/local/bin/python3 --enable-werror - --extra-cflags='-Wno-error=deprecated-declarations' - || { cat config.log meson-logs/meson-log.txt; exit 1; } - - gmake -j$(sysctl -n hw.ncpu) - - gmake check-unit V=1 - - gmake check-block V=1 - - gmake check-qapi-schema V=1 - - gmake check-softfloat V=1 - - gmake check-qtest-x86_64 V=1 - -macos_xcode_task: - osx_instance: - # this is an alias for the latest Xcode - image: catalina-xcode - install_script: - - brew install pkg-config gnu-sed glib pixman make sdl2 bash ninja - script: - - mkdir build - - cd build - - ../configure --extra-cflags='-Wno-error=deprecated-declarations' --enable-modules - --enable-werror --cc=clang || { cat config.log meson-logs/meson-log.txt; exit 1; } - - gmake -j$(sysctl -n hw.ncpu) - - gmake check-unit V=1 - - gmake check-block V=1 - - gmake check-qapi-schema V=1 - - gmake check-softfloat V=1 - - gmake check-qtest-x86_64 V=1 - windows_msys2_task: timeout_in: 90m windows_container: From 51f5c849c1036203f5979ea40f61c08f3897908e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:34 +0100 Subject: [PATCH 117/531] hw/usb/ccid: remove references to NSS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NSS package was previously pre-requisite for building CCID related features, however, this became obsolete when the libcacard library was spun off to a separate project: commit 7b02f5447c64d1854468f758398c9f6fe9e5721f Author: Marc-André Lureau Date: Sun Aug 30 11:48:40 2015 +0200 libcacard: use the standalone project Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Wainer dos Santos Moschetta Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Willian Rampazzo Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-2-berrange@redhat.com> Message-Id: <20210709143005.1554-10-alex.bennee@linaro.org> --- .travis.yml | 12 ++++++------ docs/ccid.txt | 15 +++++++-------- scripts/coverity-scan/coverity-scan.docker | 1 - tests/docker/dockerfiles/fedora.docker | 2 +- tests/docker/dockerfiles/ubuntu.docker | 1 - tests/docker/dockerfiles/ubuntu1804.docker | 1 - tests/docker/dockerfiles/ubuntu2004.docker | 1 - 7 files changed, 14 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4609240b5a..0faddf7b4e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,7 @@ addons: - libattr1-dev - libbrlapi-dev - libcap-ng-dev + - libcacard-dev - libgcc-7-dev - libgnutls28-dev - libgtk-3-dev @@ -34,7 +35,6 @@ addons: - liblttng-ust-dev - libncurses5-dev - libnfs-dev - - libnss3-dev - libpixman-1-dev - libpng-dev - librados-dev @@ -129,6 +129,7 @@ jobs: - libaio-dev - libattr1-dev - libbrlapi-dev + - libcacard-dev - libcap-ng-dev - libgcrypt20-dev - libgnutls28-dev @@ -137,7 +138,6 @@ jobs: - liblttng-ust-dev - libncurses5-dev - libnfs-dev - - libnss3-dev - libpixman-1-dev - libpng-dev - librados-dev @@ -163,6 +163,7 @@ jobs: - libaio-dev - libattr1-dev - libbrlapi-dev + - libcacard-dev - libcap-ng-dev - libgcrypt20-dev - libgnutls28-dev @@ -171,7 +172,6 @@ jobs: - liblttng-ust-dev - libncurses5-dev - libnfs-dev - - libnss3-dev - libpixman-1-dev - libpng-dev - librados-dev @@ -196,6 +196,7 @@ jobs: - libaio-dev - libattr1-dev - libbrlapi-dev + - libcacard-dev - libcap-ng-dev - libgcrypt20-dev - libgnutls28-dev @@ -204,7 +205,6 @@ jobs: - liblttng-ust-dev - libncurses5-dev - libnfs-dev - - libnss3-dev - libpixman-1-dev - libpng-dev - librados-dev @@ -238,6 +238,7 @@ jobs: apt_packages: - libaio-dev - libattr1-dev + - libcacard-dev - libcap-ng-dev - libgnutls28-dev - libiscsi-dev @@ -245,7 +246,6 @@ jobs: - liblzo2-dev - libncurses-dev - libnfs-dev - - libnss3-dev - libpixman-1-dev - libsdl2-dev - libsdl2-image-dev @@ -281,6 +281,7 @@ jobs: - libaio-dev - libattr1-dev - libbrlapi-dev + - libcacard-dev - libcap-ng-dev - libgcrypt20-dev - libgnutls28-dev @@ -289,7 +290,6 @@ jobs: - liblttng-ust-dev - libncurses5-dev - libnfs-dev - - libnss3-dev - libpixman-1-dev - libpng-dev - librados-dev diff --git a/docs/ccid.txt b/docs/ccid.txt index c97fbd2de0..2b85b1bd42 100644 --- a/docs/ccid.txt +++ b/docs/ccid.txt @@ -34,15 +34,14 @@ reader and smart card (i.e. not backed by a physical device) using this device. 2. Building -The cryptographic functions and access to the physical card is done via NSS. - -Installing NSS: +The cryptographic functions and access to the physical card is done via the +libcacard library, whose development package must be installed prior to +building QEMU: In redhat/fedora: - yum install nss-devel -In ubuntu/debian: - apt-get install libnss3-dev - (not tested on ubuntu) + yum install libcacard-devel +In ubuntu: + apt-get install libcacard-dev Configuring and building: ./configure --enable-smartcard && make @@ -51,7 +50,7 @@ Configuring and building: 3. Using ccid-card-emulated with hardware Assuming you have a working smartcard on the host with the current -user, using NSS, qemu acts as another NSS client using ccid-card-emulated: +user, using libcacard, QEMU acts as another client using ccid-card-emulated: qemu -usb -device usb-ccid -device ccid-card-emulated diff --git a/scripts/coverity-scan/coverity-scan.docker b/scripts/coverity-scan/coverity-scan.docker index 501ac67233..ecff6ac5b4 100644 --- a/scripts/coverity-scan/coverity-scan.docker +++ b/scripts/coverity-scan/coverity-scan.docker @@ -93,7 +93,6 @@ ENV PACKAGES \ mingw64-SDL2 \ ncurses-devel \ nettle-devel \ - nss-devel \ numactl-devel \ perl \ perl-Test-Harness \ diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index 00cac5d61c..9dde3f6a78 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -28,6 +28,7 @@ ENV PACKAGES \ libasan \ libattr-devel \ libblockdev-mpath-devel \ + libcacard-devel \ libcap-ng-devel \ libcurl-devel \ libepoxy-devel \ @@ -82,7 +83,6 @@ ENV PACKAGES \ ncurses-devel \ nettle-devel \ ninja-build \ - nss-devel \ numactl-devel \ perl \ perl-Test-Harness \ diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker index 24d1647a65..100cfa76e3 100644 --- a/tests/docker/dockerfiles/ubuntu.docker +++ b/tests/docker/dockerfiles/ubuntu.docker @@ -40,7 +40,6 @@ ENV PACKAGES \ libncurses5-dev \ libncursesw5-dev \ libnfs-dev \ - libnss3-dev \ libnuma-dev \ libpixman-1-dev \ libpng-dev \ diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker index 2f1ec7c42b..86114be23a 100644 --- a/tests/docker/dockerfiles/ubuntu1804.docker +++ b/tests/docker/dockerfiles/ubuntu1804.docker @@ -27,7 +27,6 @@ ENV PACKAGES \ libncurses5-dev \ libncursesw5-dev \ libnfs-dev \ - libnss3-dev \ libnuma-dev \ libpixman-1-dev \ librados-dev \ diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index fe993fe2a3..b33ed139d9 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -31,7 +31,6 @@ ENV PACKAGES flex bison \ libncurses5-dev \ libncursesw5-dev \ libnfs-dev \ - libnss3-dev \ libnuma-dev \ libpixman-1-dev \ librados-dev \ From 6ddc3dc7a882f2e7200fa7fecf505a8d0d8bbea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:35 +0100 Subject: [PATCH 118/531] tests/docker: don't use BUILDKIT in GitLab either MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using BUILDKIT breaks with certain container registries such as CentOS, with docker build reporting an error such as failed to solve with frontend dockerfile.v0: failed to build LLB: failed to load cache key: unexpected status code https://registry.centos.org/v2/centos/manifests/7: 403 Forbidden Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Willian Rampazzo Message-Id: <20210623142245.307776-3-berrange@redhat.com> Message-Id: <20210709143005.1554-11-alex.bennee@linaro.org> --- tests/docker/docker.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/docker/docker.py b/tests/docker/docker.py index 4d9bb7c7ed..78dd13171e 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -228,7 +228,9 @@ class Docker(object): def __init__(self): self._command = _guess_engine_command() - if "docker" in self._command and "TRAVIS" not in os.environ: + if ("docker" in self._command and + "TRAVIS" not in os.environ and + "GITLAB_CI" not in os.environ): os.environ["DOCKER_BUILDKIT"] = "1" self._buildkit = True else: From 102cd5c294dcb251c814fff65e3024fac503f680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:36 +0100 Subject: [PATCH 119/531] tests/docker: use project specific container registries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since Docker Hub has started to enforce pull rate limits on clients, it is preferrable to use project specific container registries where they are available. Fedora and OpenSUSE projects provide registries. The images in these registries are also refreshed on a more regular basis than the ones in docker hub, so the package update should generally be faster. While CentOS also has a registry it is considerably outdated compared to docker.io, and also only provides x86 images, while docker.io images are multi-arch. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Wainer dos Santos Moschetta Reviewed-by: Willian Rampazzo Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-4-berrange@redhat.com> Message-Id: <20210709143005.1554-12-alex.bennee@linaro.org> --- tests/docker/dockerfiles/fedora-cris-cross.docker | 2 +- tests/docker/dockerfiles/fedora-i386-cross.docker | 2 +- tests/docker/dockerfiles/fedora-win32-cross.docker | 2 +- tests/docker/dockerfiles/fedora-win64-cross.docker | 2 +- tests/docker/dockerfiles/fedora.docker | 2 +- tests/docker/dockerfiles/opensuse-leap.docker | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/docker/dockerfiles/fedora-cris-cross.docker b/tests/docker/dockerfiles/fedora-cris-cross.docker index 1dfff6e0b9..91c373fdd3 100644 --- a/tests/docker/dockerfiles/fedora-cris-cross.docker +++ b/tests/docker/dockerfiles/fedora-cris-cross.docker @@ -2,7 +2,7 @@ # Cross compiler for cris system tests # -FROM fedora:33 +FROM registry.fedoraproject.org/fedora:33 ENV PACKAGES gcc-cris-linux-gnu RUN dnf install -y $PACKAGES RUN rpm -q $PACKAGES | sort > /packages.txt diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker index 8004fd8ee5..dbb8195eb1 100644 --- a/tests/docker/dockerfiles/fedora-i386-cross.docker +++ b/tests/docker/dockerfiles/fedora-i386-cross.docker @@ -1,4 +1,4 @@ -FROM fedora:33 +FROM registry.fedoraproject.org/fedora:33 ENV PACKAGES \ bzip2 \ ccache \ diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index a638afb525..9fed35f4e1 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -1,4 +1,4 @@ -FROM fedora:33 +FROM registry.fedoraproject.org/fedora:33 # Please keep this list sorted alphabetically ENV PACKAGES \ diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index f53007ac86..fb641f6104 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -1,4 +1,4 @@ -FROM fedora:33 +FROM registry.fedoraproject.org/fedora:33 # Please keep this list sorted alphabetically ENV PACKAGES \ diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index 9dde3f6a78..a506e68d33 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -1,4 +1,4 @@ -FROM fedora:33 +FROM registry.fedoraproject.org/fedora:33 # Please keep this list sorted alphabetically ENV PACKAGES \ diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index f7e1cbfbe6..7ebff1b3a8 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -1,4 +1,4 @@ -FROM opensuse/leap:15.2 +FROM registry.opensuse.org/opensuse/leap:15.2 # Please keep this list sorted alphabetically ENV PACKAGES \ From 1ae2786c7c91aadbdc15d4106e951bc15b46b585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:37 +0100 Subject: [PATCH 120/531] tests/docker: use explicit docker.io registry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is good practice to use an explicit registry for referencing the base image. This is because some distros will inject their own registries into the search path. For example registry.fedoraproject.org comes ahead of docker.io. Using an explicit registry avoids wasting time querying multiple registries for images that they won't have. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Wainer dos Santos Moschetta Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-5-berrange@redhat.com> Message-Id: <20210709143005.1554-13-alex.bennee@linaro.org> --- tests/docker/dockerfiles/centos8.docker | 2 +- tests/docker/dockerfiles/debian-xtensa-cross.docker | 2 +- tests/docker/dockerfiles/debian10.docker | 2 +- tests/docker/dockerfiles/debian11.docker | 2 +- tests/docker/dockerfiles/ubuntu.docker | 2 +- tests/docker/dockerfiles/ubuntu1804.docker | 2 +- tests/docker/dockerfiles/ubuntu2004.docker | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index 03e0440e03..8f810810f3 100644 --- a/tests/docker/dockerfiles/centos8.docker +++ b/tests/docker/dockerfiles/centos8.docker @@ -1,4 +1,4 @@ -FROM centos:8.3.2011 +FROM docker.io/centos:8 RUN dnf -y update ENV PACKAGES \ diff --git a/tests/docker/dockerfiles/debian-xtensa-cross.docker b/tests/docker/dockerfiles/debian-xtensa-cross.docker index ba4148299c..2f11b3b7bc 100644 --- a/tests/docker/dockerfiles/debian-xtensa-cross.docker +++ b/tests/docker/dockerfiles/debian-xtensa-cross.docker @@ -5,7 +5,7 @@ # using a prebuilt toolchains for Xtensa cores from: # https://github.com/foss-xtensa/toolchain/releases # -FROM debian:stretch-slim +FROM docker.io/library/debian:stretch-slim RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \ diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker index 4ffe47671e..a27b88df55 100644 --- a/tests/docker/dockerfiles/debian10.docker +++ b/tests/docker/dockerfiles/debian10.docker @@ -7,7 +7,7 @@ # On its own you can't build much but the docker-foo-cross targets # build on top of the base debian image. # -FROM debian:buster-slim +FROM docker.io/library/debian:buster-slim # Duplicate deb line as deb-src RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list diff --git a/tests/docker/dockerfiles/debian11.docker b/tests/docker/dockerfiles/debian11.docker index 5adfd62d55..febf884f8f 100644 --- a/tests/docker/dockerfiles/debian11.docker +++ b/tests/docker/dockerfiles/debian11.docker @@ -8,7 +8,7 @@ # On its own you can't build much but the docker-foo-cross targets # build on top of the base debian image. # -FROM debian:bullseye-slim +FROM docker.io/library/debian:bullseye-slim # Duplicate deb line as deb-src RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker index 100cfa76e3..e0ff425c01 100644 --- a/tests/docker/dockerfiles/ubuntu.docker +++ b/tests/docker/dockerfiles/ubuntu.docker @@ -9,7 +9,7 @@ # system won't pick up that it has changed. # -FROM ubuntu:20.04 +FROM docker.io/library/ubuntu:20.04 ENV PACKAGES \ ccache \ clang \ diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker index 86114be23a..adcdef8244 100644 --- a/tests/docker/dockerfiles/ubuntu1804.docker +++ b/tests/docker/dockerfiles/ubuntu1804.docker @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM docker.io/library/ubuntu:18.04 ENV PACKAGES \ ccache \ clang \ diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index b33ed139d9..78755bc2e3 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -1,4 +1,4 @@ -FROM ubuntu:20.04 +FROM docker.io/library/ubuntu:20.04 ENV PACKAGES flex bison \ bsdmainutils \ ccache \ From 888673bbb9f5dc8e35c4747ddd1addba251a9a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:38 +0100 Subject: [PATCH 121/531] tests/docker: remove FEATURES env var from templates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for switching to auto-generated dockerfiles, remove the FEATURES env variable. The equivalent functionality can be achieved in most cases by just looking for existance of a binary. The cases which don't correspond to binaries are simply dropped because configure/meson will probe for any requested feature anyway. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Willian Rampazzo Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-6-berrange@redhat.com> Message-Id: <20210709143005.1554-14-alex.bennee@linaro.org> --- tests/docker/common.rc | 19 ++++++++++++++----- tests/docker/dockerfiles/debian10.docker | 2 -- .../dockerfiles/fedora-win32-cross.docker | 1 - .../dockerfiles/fedora-win64-cross.docker | 1 - tests/docker/dockerfiles/fedora.docker | 1 - tests/docker/dockerfiles/ubuntu.docker | 1 - tests/docker/dockerfiles/ubuntu1804.docker | 1 - tests/docker/dockerfiles/ubuntu2004.docker | 1 - tests/docker/run | 3 --- tests/docker/test-clang | 2 +- tests/docker/test-debug | 2 +- tests/docker/test-mingw | 3 ++- tests/docker/test-misc | 2 +- tests/docker/test-tsan | 2 +- 14 files changed, 20 insertions(+), 21 deletions(-) diff --git a/tests/docker/common.rc b/tests/docker/common.rc index ebc5b97ecf..c5cc33d366 100755 --- a/tests/docker/common.rc +++ b/tests/docker/common.rc @@ -15,14 +15,23 @@ # overriden by TARGET_LIST if the user sets it. DEF_TARGET_LIST=${DEF_TARGET_LIST:-"x86_64-softmmu,aarch64-softmmu"} -requires() +requires_binary() { + found=0 for c in $@; do - if ! echo "$FEATURES" | grep -wq -e "$c"; then - echo "Prerequisite '$c' not present, skip" - exit 0 - fi + for d in /bin /usr/bin /usr/local/bin + do + if test -f "$d/$c" + then + found=1 + fi + done done + if test "$found" != "1" + then + echo "Prerequisite '$c' not present, skip" + exit 0 + fi } configure_qemu() diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker index a27b88df55..b414af1b9f 100644 --- a/tests/docker/dockerfiles/debian10.docker +++ b/tests/docker/dockerfiles/debian10.docker @@ -35,5 +35,3 @@ RUN apt update && \ python3-sphinx \ python3-sphinx-rtd-theme \ $(apt-get -s build-dep --arch-only qemu | egrep ^Inst | fgrep '[all]' | cut -d\ -f2) - -ENV FEATURES docs diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index 9fed35f4e1..5a03e1af43 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -37,7 +37,6 @@ ENV PACKAGES \ RUN dnf install -y $PACKAGES RUN rpm -q $PACKAGES | sort > /packages.txt -ENV FEATURES mingw # Specify the cross prefix for this image (see tests/docker/common.rc) ENV QEMU_CONFIGURE_OPTS --cross-prefix=i686-w64-mingw32- diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index fb641f6104..ff706040c4 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -33,7 +33,6 @@ ENV PACKAGES \ RUN dnf install -y $PACKAGES RUN rpm -q $PACKAGES | sort > /packages.txt -ENV FEATURES mingw # Specify the cross prefix for this image (see tests/docker/common.rc) ENV QEMU_CONFIGURE_OPTS --cross-prefix=x86_64-w64-mingw32- --disable-capstone diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index a506e68d33..64a413f5e0 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -117,4 +117,3 @@ ENV QEMU_CONFIGURE_OPTS --python=/usr/bin/python3 RUN dnf install -y $PACKAGES RUN rpm -q $PACKAGES | sort > /packages.txt ENV PATH $PATH:/usr/libexec/python3-sphinx/ -ENV FEATURES mingw clang pyyaml asan docs diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker index e0ff425c01..f0e0180d21 100644 --- a/tests/docker/dockerfiles/ubuntu.docker +++ b/tests/docker/dockerfiles/ubuntu.docker @@ -69,4 +69,3 @@ ENV PACKAGES \ RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES RUN dpkg -l $PACKAGES | sort > /packages.txt -ENV FEATURES clang pyyaml sdl2 docs diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker index adcdef8244..0acdb0d9ad 100644 --- a/tests/docker/dockerfiles/ubuntu1804.docker +++ b/tests/docker/dockerfiles/ubuntu1804.docker @@ -55,7 +55,6 @@ ENV PACKAGES \ RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES RUN dpkg -l $PACKAGES | sort > /packages.txt -ENV FEATURES clang pyyaml sdl2 docs # https://bugs.launchpad.net/qemu/+bug/1838763 ENV QEMU_CONFIGURE_OPTS --disable-libssh diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index 78755bc2e3..88b3cfa136 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -70,7 +70,6 @@ ENV PACKAGES flex bison \ RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES RUN dpkg -l $PACKAGES | sort > /packages.txt -ENV FEATURES clang tsan pyyaml sdl2 # Apply patch https://reviews.llvm.org/D75820 # This is required for TSan in clang-10 to compile with QEMU. diff --git a/tests/docker/run b/tests/docker/run index 8edc7026ee..421393046b 100755 --- a/tests/docker/run +++ b/tests/docker/run @@ -30,9 +30,6 @@ mkdir -p $TEST_DIR/{src,build,install} # Extract the source tarballs tar -C $TEST_DIR/src -xf $BASE/qemu.tar || { echo "Failed to untar source"; exit 2; } -if test -f $TEST_DIR/src/Makefile; then - export FEATURES="$FEATURES dtc" -fi if test -n "$SHOW_ENV"; then if test -f /packages.txt; then diff --git a/tests/docker/test-clang b/tests/docker/test-clang index 8c51ead518..b57e0119d9 100755 --- a/tests/docker/test-clang +++ b/tests/docker/test-clang @@ -13,7 +13,7 @@ . common.rc -requires clang +requires_binary clang cd "$BUILD_DIR" diff --git a/tests/docker/test-debug b/tests/docker/test-debug index c050fa0d93..f52f16328c 100755 --- a/tests/docker/test-debug +++ b/tests/docker/test-debug @@ -14,7 +14,7 @@ . common.rc -requires clang asan +requires_binary clang cd "$BUILD_DIR" diff --git a/tests/docker/test-mingw b/tests/docker/test-mingw index c30eb654eb..0bc6d78872 100755 --- a/tests/docker/test-mingw +++ b/tests/docker/test-mingw @@ -13,7 +13,8 @@ . common.rc -requires mingw dtc +requires_binary x86_64-w64-mingw32-gcc +requires_binary i686-w64-mingw32-gcc cd "$BUILD_DIR" diff --git a/tests/docker/test-misc b/tests/docker/test-misc index cc94a738dd..2a3c2c2e1c 100755 --- a/tests/docker/test-misc +++ b/tests/docker/test-misc @@ -14,7 +14,7 @@ . common.rc -requires docs +requires_binary sphinx-build-3 sphinx-build cd "$BUILD_DIR" diff --git a/tests/docker/test-tsan b/tests/docker/test-tsan index eb40ac45b7..53d90d2f79 100755 --- a/tests/docker/test-tsan +++ b/tests/docker/test-tsan @@ -17,7 +17,7 @@ setup_tsan() { - requires clang tsan + requires_binary clang tsan_log_dir="/tmp/qemu-test/build/tsan" mkdir -p $tsan_log_dir > /dev/null || true EXTRA_CONFIGURE_OPTS="${EXTRA_CONFIGURE_OPTS} --enable-tsan \ From 52dab556578eda2ecf6ac1d67ee6149acfb8e832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:39 +0100 Subject: [PATCH 122/531] tests/docker: fix sorting in package lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will make diffs in later patches clearer. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Wainer dos Santos Moschetta Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-7-berrange@redhat.com> Message-Id: <20210709143005.1554-15-alex.bennee@linaro.org> --- tests/docker/dockerfiles/centos8.docker | 2 +- tests/docker/dockerfiles/fedora.docker | 4 ++-- tests/docker/dockerfiles/opensuse-leap.docker | 16 ++++++++-------- tests/docker/dockerfiles/ubuntu1804.docker | 4 ++-- tests/docker/dockerfiles/ubuntu2004.docker | 8 +++++--- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index 8f810810f3..ee52305646 100644 --- a/tests/docker/dockerfiles/centos8.docker +++ b/tests/docker/dockerfiles/centos8.docker @@ -22,9 +22,9 @@ ENV PACKAGES \ lzo-devel \ make \ mesa-libEGL-devel \ - nmap-ncat \ nettle-devel \ ninja-build \ + nmap-ncat \ perl-Test-Harness \ pixman-devel \ python36 \ diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index 64a413f5e0..4a0a84eb43 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -2,6 +2,7 @@ FROM registry.fedoraproject.org/fedora:33 # Please keep this list sorted alphabetically ENV PACKAGES \ + SDL2-devel \ bc \ brlapi-devel \ bzip2 \ @@ -79,10 +80,10 @@ ENV PACKAGES \ mingw64-pixman \ mingw64-pkg-config \ mingw64-SDL2 \ - nmap-ncat \ ncurses-devel \ nettle-devel \ ninja-build \ + nmap-ncat \ numactl-devel \ perl \ perl-Test-Harness \ @@ -97,7 +98,6 @@ ENV PACKAGES \ python3-sphinx_rtd_theme \ python3-virtualenv \ rdma-core-devel \ - SDL2-devel \ snappy-devel \ sparse \ spice-server-devel \ diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index 7ebff1b3a8..6011447181 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -9,46 +9,46 @@ ENV PACKAGES \ cyrus-sasl-devel \ gcc \ gcc-c++ \ - mkisofs \ gettext-runtime \ git \ glib2-devel \ glusterfs-devel \ - libgnutls-devel \ gtk3-devel \ + libSDL2-devel \ + libSDL2_image-devel \ libaio-devel \ libattr-devel \ libcap-ng-devel \ libepoxy-devel \ libfdt-devel \ + libgnutls-devel \ libiscsi-devel \ libjpeg8-devel \ + libnuma-devel \ + libpixman-1-0-devel \ libpmem-devel \ libpng16-devel \ librbd-devel \ libseccomp-devel \ + libspice-server-devel \ libssh-devel \ lzo-devel \ make \ - libSDL2_image-devel \ + mkisofs \ ncurses-devel \ ninja \ - libnuma-devel \ perl \ - libpixman-1-0-devel \ python3-base \ python3-virtualenv \ rdma-core-devel \ - libSDL2-devel \ snappy-devel \ - libspice-server-devel \ systemd-devel \ systemtap-sdt-devel \ tar \ usbredir-devel \ virglrenderer-devel \ - xen-devel \ vte-devel \ + xen-devel \ zlib-devel ENV QEMU_CONFIGURE_OPTS --python=/usr/bin/python3.6 diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker index 0acdb0d9ad..a50a35e6fe 100644 --- a/tests/docker/dockerfiles/ubuntu1804.docker +++ b/tests/docker/dockerfiles/ubuntu1804.docker @@ -46,10 +46,10 @@ ENV PACKAGES \ libxen-dev \ libzstd-dev \ make \ - python3-yaml \ + ninja-build \ python3-sphinx \ python3-sphinx-rtd-theme \ - ninja-build \ + python3-yaml \ sparse \ xfslibs-dev RUN apt-get update && \ diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index 88b3cfa136..eee2ef3cac 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -1,8 +1,10 @@ FROM docker.io/library/ubuntu:20.04 -ENV PACKAGES flex bison \ +ENV PACKAGES \ + bison \ bsdmainutils \ ccache \ clang-10\ + flex \ gcc \ gcovr \ genisoimage \ @@ -65,8 +67,8 @@ ENV PACKAGES flex bison \ sparse \ tesseract-ocr \ tesseract-ocr-eng \ - xfslibs-dev\ - vim + vim \ + xfslibs-dev RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES RUN dpkg -l $PACKAGES | sort > /packages.txt From 1d3a56d7f16020ce00d2c712a03579d4ea33db2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:40 +0100 Subject: [PATCH 123/531] tests/docker: fix mistakes in centos package lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mesa-libEGL-devel is not used in QEMU at all, but mesa-libgbm-devel is. spice-glib-devel is not use in QEMU at all, but spice-protocol is. We also need the -devel package for spice-server, not the runtime. There is no need to specifically refer to python36, we can just use python3 as in other distros. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Wainer dos Santos Moschetta Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-8-berrange@redhat.com> Message-Id: <20210709143005.1554-16-alex.bennee@linaro.org> --- tests/docker/dockerfiles/centos8.docker | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index ee52305646..5f1c57b4ad 100644 --- a/tests/docker/dockerfiles/centos8.docker +++ b/tests/docker/dockerfiles/centos8.docker @@ -21,16 +21,16 @@ ENV PACKAGES \ libgcrypt-devel \ lzo-devel \ make \ - mesa-libEGL-devel \ + mesa-libgbm-devel \ nettle-devel \ ninja-build \ nmap-ncat \ perl-Test-Harness \ pixman-devel \ - python36 \ + python3 \ rdma-core-devel \ - spice-glib-devel \ - spice-server \ + spice-protocol \ + spice-server-devel \ systemtap-sdt-devel \ tar \ zlib-devel From e053de7e63c0b4437ec963bf42caca59b9cf38bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:41 +0100 Subject: [PATCH 124/531] tests/docker: fix mistakes in fedora package list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit libblockdev-mpath-devel is not used by QEMU, rather it wants device-mapper-multipath-devel. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Wainer dos Santos Moschetta Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-9-berrange@redhat.com> Message-Id: <20210709143005.1554-17-alex.bennee@linaro.org> --- tests/docker/dockerfiles/fedora.docker | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index 4a0a84eb43..f667f03cc5 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -28,7 +28,6 @@ ENV PACKAGES \ libaio-devel \ libasan \ libattr-devel \ - libblockdev-mpath-devel \ libcacard-devel \ libcap-ng-devel \ libcurl-devel \ From dfaaacc67f82dc660ea59052d0458938a7f8d6f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:42 +0100 Subject: [PATCH 125/531] tests/docker: fix mistakes in ubuntu package lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit librados-dev is not required by QEMU directly, only librbd-dev. glusterfs-common is not directly needed by QEMU. QEMU uses ncursesw only on non-Windows hosts. The clang package is clang 10. flex and bison are not required by QEMU. Standardize on nmap ncat implementation to match Fedora/CentOS. Remove vim since it is not a build pre-requisite and no other containers include it. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Wainer dos Santos Moschetta Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-10-berrange@redhat.com> Message-Id: <20210709143005.1554-18-alex.bennee@linaro.org> --- tests/docker/dockerfiles/ubuntu1804.docker | 3 --- tests/docker/dockerfiles/ubuntu2004.docker | 10 ++-------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker index a50a35e6fe..ee8545e4b1 100644 --- a/tests/docker/dockerfiles/ubuntu1804.docker +++ b/tests/docker/dockerfiles/ubuntu1804.docker @@ -5,7 +5,6 @@ ENV PACKAGES \ gcc \ gettext \ git \ - glusterfs-common \ libaio-dev \ libattr1-dev \ libbrlapi-dev \ @@ -24,12 +23,10 @@ ENV PACKAGES \ libjemalloc-dev \ libjpeg-turbo8-dev \ liblzo2-dev \ - libncurses5-dev \ libncursesw5-dev \ libnfs-dev \ libnuma-dev \ libpixman-1-dev \ - librados-dev \ librbd-dev \ librdmacm-dev \ libsasl2-dev \ diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index eee2ef3cac..25f56adfb2 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -1,16 +1,13 @@ FROM docker.io/library/ubuntu:20.04 ENV PACKAGES \ - bison \ bsdmainutils \ ccache \ - clang-10\ - flex \ + clang \ gcc \ gcovr \ genisoimage \ gettext \ git \ - glusterfs-common \ libaio-dev \ libattr1-dev \ libbrlapi-dev \ @@ -30,12 +27,10 @@ ENV PACKAGES \ libjpeg-turbo8-dev \ liblttng-ust-dev \ liblzo2-dev \ - libncurses5-dev \ libncursesw5-dev \ libnfs-dev \ libnuma-dev \ libpixman-1-dev \ - librados-dev \ librbd-dev \ librdmacm-dev \ libsasl2-dev \ @@ -53,7 +48,7 @@ ENV PACKAGES \ libxen-dev \ libzstd-dev \ make \ - netcat-openbsd \ + ncat \ ninja-build \ python3-numpy \ python3-opencv \ @@ -67,7 +62,6 @@ ENV PACKAGES \ sparse \ tesseract-ocr \ tesseract-ocr-eng \ - vim \ xfslibs-dev RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES From 52141ab37de49daca3adee7a72065834a696c693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:43 +0100 Subject: [PATCH 126/531] tests/docker: remove mingw packages from Fedora MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are dedicated containers providing mingw packages for Fedora. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-11-berrange@redhat.com> Message-Id: <20210709143005.1554-19-alex.bennee@linaro.org> --- tests/docker/dockerfiles/fedora.docker | 27 -------------------------- 1 file changed, 27 deletions(-) diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index f667f03cc5..5849ea7617 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -52,33 +52,6 @@ ENV PACKAGES \ lzo-devel \ make \ meson \ - mingw32-bzip2 \ - mingw32-curl \ - mingw32-glib2 \ - mingw32-gmp \ - mingw32-gnutls \ - mingw32-gtk3 \ - mingw32-libjpeg-turbo \ - mingw32-libpng \ - mingw32-libtasn1 \ - mingw32-nettle \ - mingw32-nsis \ - mingw32-pixman \ - mingw32-pkg-config \ - mingw32-SDL2 \ - mingw64-bzip2 \ - mingw64-curl \ - mingw64-glib2 \ - mingw64-gmp \ - mingw64-gnutls \ - mingw64-gtk3 \ - mingw64-libjpeg-turbo \ - mingw64-libpng \ - mingw64-libtasn1 \ - mingw64-nettle \ - mingw64-pixman \ - mingw64-pkg-config \ - mingw64-SDL2 \ ncurses-devel \ nettle-devel \ ninja-build \ From b5883710c4bb0e2181ad30b89888a35ba9073206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:44 +0100 Subject: [PATCH 127/531] tests/docker: expand centos8 package list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the fully expanded list of build pre-requisites QEMU can conceivably use in any scenario. [AJB: added centos-release-advanced-virtualization/epel-release] Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-12-berrange@redhat.com> Message-Id: <20210709143005.1554-20-alex.bennee@linaro.org> --- tests/docker/dockerfiles/centos8.docker | 70 +++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index 5f1c57b4ad..46398c61ee 100644 --- a/tests/docker/dockerfiles/centos8.docker +++ b/tests/docker/dockerfiles/centos8.docker @@ -3,39 +3,109 @@ FROM docker.io/centos:8 RUN dnf -y update ENV PACKAGES \ SDL2-devel \ + alsa-lib-devel \ + bc \ + brlapi-devel \ bzip2 \ bzip2-devel \ + ca-certificates \ + capstone-devel \ + ccache \ + clang \ + ctags \ + cyrus-sasl-devel \ + daxctl-devel \ dbus-daemon \ + device-mapper-multipath-devel \ diffutils \ + findutils \ gcc \ gcc-c++ \ genisoimage \ gettext \ git \ glib2-devel \ + glibc-langpack-en \ + glibc-static \ + glusterfs-api-devel \ + gnutls-devel \ + gtk3-devel \ + hostname \ + jemalloc-devel \ libaio-devel \ + libasan \ + libattr-devel \ libbpf-devel \ + libcacard-devel \ + libcap-ng-devel \ + libcurl-devel \ + libdrm-devel \ libepoxy-devel \ libfdt-devel \ libffi-devel \ libgcrypt-devel \ + libiscsi-devel \ + libjpeg-devel \ + libnfs-devel \ + libpmem-devel \ + libpng-devel \ + librbd-devel \ + libseccomp-devel \ + libslirp-devel \ + libssh-devel \ + libtasn1-devel \ + libubsan \ + libudev-devel \ + libusbx-devel \ + libxml2-devel \ + libzstd-devel \ + llvm \ lzo-devel \ make \ mesa-libgbm-devel \ + ncurses-devel \ nettle-devel \ ninja-build \ nmap-ncat \ + numactl-devel \ + openssh-clients \ + pam-devel \ + perl \ perl-Test-Harness \ pixman-devel \ + pkgconfig \ + pulseaudio-libs-devel \ python3 \ + python3-PyYAML \ + python3-numpy \ + python3-pillow \ + python3-pip \ + python3-setuptools \ + python3-sphinx \ + python3-sphinx_rtd_theme \ + python3-virtualenv \ + python3-wheel \ rdma-core-devel \ + rpm \ + sed \ + snappy-devel \ spice-protocol \ spice-server-devel \ + systemd-devel \ systemtap-sdt-devel \ tar \ + texinfo \ + usbredir-devel \ + util-linux \ + virglrenderer-devel \ + vte291-devel \ + which \ + xfsprogs-devel \ zlib-devel RUN dnf install -y dnf-plugins-core && \ dnf config-manager --set-enabled powertools && \ + dnf install -y centos-release-advanced-virtualization && \ + dnf install -y epel-release && \ dnf install -y $PACKAGES RUN rpm -q $PACKAGES | sort > /packages.txt From 5a9c1498e36f32e2e30aeac96991802e8496436d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:45 +0100 Subject: [PATCH 128/531] tests/docker: expand fedora package list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the fully expanded list of build pre-requisites QEMU can conceivably use in any scenario. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-13-berrange@redhat.com> Message-Id: <20210709143005.1554-21-alex.bennee@linaro.org> --- tests/docker/dockerfiles/fedora.docker | 30 ++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index 5849ea7617..eec1add7f6 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -3,63 +3,83 @@ FROM registry.fedoraproject.org/fedora:33 # Please keep this list sorted alphabetically ENV PACKAGES \ SDL2-devel \ + SDL2_image-devel \ + alsa-lib-devel \ bc \ brlapi-devel \ bzip2 \ bzip2-devel \ + ca-certificates \ capstone-devel \ ccache \ clang \ + ctags \ cyrus-sasl-devel \ + daxctl-devel \ dbus-daemon \ device-mapper-multipath-devel \ diffutils \ findutils \ gcc \ gcc-c++ \ + gcovr \ genisoimage \ gettext \ git \ glib2-devel \ + glibc-langpack-en \ + glibc-static \ glusterfs-api-devel \ gnutls-devel \ gtk3-devel \ hostname \ + jemalloc-devel \ libaio-devel \ libasan \ libattr-devel \ + libbpf-devel \ libcacard-devel \ libcap-ng-devel \ libcurl-devel \ + libdrm-devel \ libepoxy-devel \ libfdt-devel \ - libbpf-devel \ libffi-devel \ + libgcrypt-devel \ libiscsi-devel \ libjpeg-devel \ + libnfs-devel \ libpmem-devel \ libpng-devel \ librbd-devel \ libseccomp-devel \ libslirp-devel \ libssh-devel \ + libtasn1-devel \ libubsan \ libudev-devel \ + liburing-devel \ libusbx-devel \ libxml2-devel \ libzstd-devel \ llvm \ + lttng-ust-devel \ lzo-devel \ make \ + mesa-libgbm-devel \ meson \ ncurses-devel \ nettle-devel \ ninja-build \ nmap-ncat \ numactl-devel \ - perl \ + openssh-clients \ + pam-devel \ perl-Test-Harness \ + perl-base \ pixman-devel \ + pkgconfig \ + pulseaudio-libs-devel \ python3 \ python3-PyYAML \ python3-numpy \ @@ -70,19 +90,25 @@ ENV PACKAGES \ python3-sphinx_rtd_theme \ python3-virtualenv \ rdma-core-devel \ + rpm \ + sed \ snappy-devel \ sparse \ + spice-protocol \ spice-server-devel \ systemd-devel \ systemtap-sdt-devel \ tar \ tesseract \ tesseract-langpack-eng \ + texinfo \ usbredir-devel \ + util-linux \ virglrenderer-devel \ vte291-devel \ which \ xen-devel \ + xfsprogs-devel \ zlib-devel ENV QEMU_CONFIGURE_OPTS --python=/usr/bin/python3 From 0fef572e4343afb4083b3c42bda152beb9ccd883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:46 +0100 Subject: [PATCH 129/531] tests/docker: expand ubuntu1804 package list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the fully expanded list of build pre-requisites QEMU can conceivably use in any scenario. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-14-berrange@redhat.com> Message-Id: <20210709143005.1554-22-alex.bennee@linaro.org> --- tests/docker/dockerfiles/ubuntu1804.docker | 61 +++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker index ee8545e4b1..0880bf3e29 100644 --- a/tests/docker/dockerfiles/ubuntu1804.docker +++ b/tests/docker/dockerfiles/ubuntu1804.docker @@ -1,54 +1,113 @@ FROM docker.io/library/ubuntu:18.04 ENV PACKAGES \ + bc \ + bsdmainutils \ + bzip2 \ + ca-certificates \ ccache \ clang \ + dbus \ + debianutils \ + diffutils \ + exuberant-ctags \ + findutils \ + g++ \ gcc \ + gcovr \ + genisoimage \ gettext \ git \ + glusterfs-common \ + hostname \ libaio-dev \ + libasan5 \ + libasound2-dev \ libattr1-dev \ libbrlapi-dev \ libbz2-dev \ + libc6-dev \ libcacard-dev \ libcap-ng-dev \ + libcapstone-dev \ libcurl4-gnutls-dev \ + libdaxctl-dev \ libdrm-dev \ libepoxy-dev \ libfdt-dev \ libffi-dev \ libgbm-dev \ + libgcrypt20-dev \ + libglib2.0-dev \ + libgnutls28-dev \ libgtk-3-dev \ libibverbs-dev \ libiscsi-dev \ libjemalloc-dev \ libjpeg-turbo8-dev \ + liblttng-ust-dev \ liblzo2-dev \ libncursesw5-dev \ libnfs-dev \ libnuma-dev \ + libpam0g-dev \ libpixman-1-dev \ + libpmem-dev \ + libpng-dev \ + libpulse-dev \ librbd-dev \ librdmacm-dev \ libsasl2-dev \ libsdl2-dev \ + libsdl2-image-dev \ libseccomp-dev \ libsnappy-dev \ libspice-protocol-dev \ libspice-server-dev \ libssh-dev \ + libsystemd-dev \ + libtasn1-6-dev \ + libtest-harness-perl \ + libubsan1 \ + libudev-dev \ libusb-1.0-0-dev \ libusbredirhost-dev \ libvdeplug-dev \ + libvirglrenderer-dev \ libvte-2.91-dev \ libxen-dev \ + libxml2-dev \ libzstd-dev \ + llvm \ + locales \ make \ + multipath-tools \ + netcat-openbsd \ + nettle-dev \ ninja-build \ + openssh-client \ + perl-base \ + pkgconf \ + python3 \ + python3-numpy \ + python3-opencv \ + python3-pillow \ + python3-pip \ + python3-setuptools \ python3-sphinx \ python3-sphinx-rtd-theme \ + python3-venv \ + python3-wheel \ python3-yaml \ + rpm2cpio \ + sed \ sparse \ - xfslibs-dev + systemtap-sdt-dev \ + tar \ + tesseract-ocr \ + tesseract-ocr-eng \ + texinfo \ + xfslibs-dev \ + zlib1g-dev RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES RUN dpkg -l $PACKAGES | sort > /packages.txt From bc4a117b79b03cbbeea0d22807c2566c579d2b8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:47 +0100 Subject: [PATCH 130/531] tests/docker: expand ubuntu2004 package list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the fully expanded list of build pre-requisites QEMU can conceivably use in any scenario. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-15-berrange@redhat.com> Message-Id: <20210709143005.1554-23-alex.bennee@linaro.org> --- tests/docker/dockerfiles/ubuntu2004.docker | 50 +++++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index 25f56adfb2..39de63d012 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -1,25 +1,44 @@ FROM docker.io/library/ubuntu:20.04 ENV PACKAGES \ + bc \ bsdmainutils \ + bzip2 \ + ca-certificates \ ccache \ clang \ + dbus \ + debianutils \ + diffutils \ + exuberant-ctags \ + findutils \ + g++ \ gcc \ gcovr \ genisoimage \ gettext \ git \ + hostname \ libaio-dev \ + libasan5 \ + libasound2-dev \ libattr1-dev \ libbrlapi-dev \ libbz2-dev \ + libc6-dev \ libcacard-dev \ libcap-ng-dev \ + libcapstone-dev \ libcurl4-gnutls-dev \ + libdaxctl-dev \ libdrm-dev \ libepoxy-dev \ libfdt-dev \ libffi-dev \ libgbm-dev \ + libgcrypt20-dev \ + libglib2.0-dev \ + libglusterfs-dev \ + libgnutls28-dev \ libgtk-3-dev \ libibverbs-dev \ libiscsi-dev \ @@ -30,39 +49,66 @@ ENV PACKAGES \ libncursesw5-dev \ libnfs-dev \ libnuma-dev \ + libpam0g-dev \ libpixman-1-dev \ + libpmem-dev \ + libpng-dev \ + libpulse-dev \ librbd-dev \ librdmacm-dev \ libsasl2-dev \ libsdl2-dev \ + libsdl2-image-dev \ libseccomp-dev \ libslirp-dev \ libsnappy-dev \ libspice-protocol-dev \ libspice-server-dev \ libssh-dev \ + libsystemd-dev \ + libtasn1-6-dev \ + libtest-harness-perl \ + libubsan1 \ + libudev-dev \ libusb-1.0-0-dev \ libusbredirhost-dev \ libvdeplug-dev \ + libvirglrenderer-dev \ libvte-2.91-dev \ libxen-dev \ + libxml2-dev \ libzstd-dev \ + llvm \ + locales \ make \ + multipath-tools \ ncat \ + nettle-dev \ ninja-build \ + openssh-client \ + perl-base \ + pkgconf \ + python3 \ python3-numpy \ python3-opencv \ - python3-pil \ + python3-pillow \ python3-pip \ + python3-setuptools \ python3-sphinx \ python3-sphinx-rtd-theme \ python3-venv \ + python3-wheel \ python3-yaml \ rpm2cpio \ + sed \ sparse \ + systemtap-sdt-dev \ + tar \ tesseract-ocr \ tesseract-ocr-eng \ - xfslibs-dev + texinfo \ + xfslibs-dev \ + zlib1g-dev RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES RUN dpkg -l $PACKAGES | sort > /packages.txt From 5606ce9ee4db7175cc93ee9335d3c9f9e1a60d00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 9 Jul 2021 15:29:48 +0100 Subject: [PATCH 131/531] tests/docker: expand opensuse-leap package list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the fully expanded list of build pre-requisites QEMU can conceivably use in any scenario. Signed-off-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-Id: <20210623142245.307776-16-berrange@redhat.com> Message-Id: <20210709143005.1554-24-alex.bennee@linaro.org> --- tests/docker/dockerfiles/opensuse-leap.docker | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index 6011447181..5a8bee0289 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -2,53 +2,110 @@ FROM registry.opensuse.org/opensuse/leap:15.2 # Please keep this list sorted alphabetically ENV PACKAGES \ + Mesa-devel \ + alsa-lib-devel \ bc \ brlapi-devel \ bzip2 \ + ca-certificates \ ccache \ + clang \ + ctags \ cyrus-sasl-devel \ + dbus-1 \ + diffutils \ + findutils \ gcc \ gcc-c++ \ + gcovr \ gettext-runtime \ git \ glib2-devel \ + glibc-locale \ + glibc-static \ glusterfs-devel \ gtk3-devel \ + hostname \ + jemalloc-devel \ libSDL2-devel \ libSDL2_image-devel \ libaio-devel \ + libasan6 \ libattr-devel \ + libbpf-devel \ + libbz2-devel \ + libcacard-devel \ libcap-ng-devel \ + libcurl-devel \ + libdrm-devel \ libepoxy-devel \ libfdt-devel \ + libffi-devel \ + libgcrypt-devel \ libgnutls-devel \ libiscsi-devel \ libjpeg8-devel \ + libndctl-devel \ + libnettle-devel \ + libnfs-devel \ libnuma-devel \ libpixman-1-0-devel \ libpmem-devel \ libpng16-devel \ + libpulse-devel \ librbd-devel \ libseccomp-devel \ libspice-server-devel \ libssh-devel \ + libtasn1-devel \ + libubsan1 \ + libudev-devel \ + libusb-1_0-devel \ + libxml2-devel \ + libzstd-devel \ + llvm \ + lttng-ust-devel \ lzo-devel \ make \ mkisofs \ + ncat \ ncurses-devel \ ninja \ - perl \ + openssh \ + pam-devel \ + perl-Test-Harness \ + perl-base \ + pkgconfig \ + python3-Pillow \ + python3-PyYAML \ + python3-Sphinx \ python3-base \ + python3-numpy \ + python3-opencv \ + python3-pip \ + python3-setuptools \ + python3-sphinx_rtd_theme \ python3-virtualenv \ + python3-wheel \ rdma-core-devel \ + rpm \ + sed \ snappy-devel \ + sparse \ + spice-protocol-devel \ systemd-devel \ systemtap-sdt-devel \ tar \ + tesseract-ocr \ + tesseract-ocr-traineddata-english \ + texinfo \ usbredir-devel \ + util-linux \ virglrenderer-devel \ vte-devel \ + which \ xen-devel \ + xfsprogs-devel \ zlib-devel ENV QEMU_CONFIGURE_OPTS --python=/usr/bin/python3.6 From 2b36d741b4f2583c8f45ff96a6223c950f86523b Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Fri, 9 Jul 2021 15:29:49 +0100 Subject: [PATCH 132/531] tests/vm: update NetBSD to 9.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tests/vm: update NetBSD to 9.2 Signed-off-by: Brad Smith Signed-off-by: Alex Bennée Tested-by: Gerd Hoffmann Reviewed-by: Wainer dos Santos Moschetta Acked-by: Philippe Mathieu-Daudé Message-Id: Message-Id: <20210709143005.1554-25-alex.bennee@linaro.org> --- tests/vm/netbsd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/vm/netbsd b/tests/vm/netbsd index b9efc269d2..4cc58df130 100755 --- a/tests/vm/netbsd +++ b/tests/vm/netbsd @@ -22,8 +22,8 @@ class NetBSDVM(basevm.BaseVM): name = "netbsd" arch = "x86_64" - link = "https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.1/images/NetBSD-9.1-amd64.iso" - csum = "65bddc95945991c3b2021f9c8ded7f34c25f0a7611b7aa15a15fe23399e902307e926ae97fcd01dc1662ac67b5f6e4be643c6a2b581692ddcb616d30125066f9" + link = "https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.2/images/NetBSD-9.2-amd64.iso" + csum = "5ee0ea101f73386b9b424f5d1041e371db3c42fdd6f4e4518dc79c4a08f31d43091ebe93425c9f0dcaaed2b51131836fe6774f33f89030b58d64709b35fda72f" size = "20G" pkgs = [ # tools From 396c9984fd18e4243d02f78bc4942a825c78dca2 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Fri, 9 Jul 2021 15:29:50 +0100 Subject: [PATCH 133/531] tests/vm: update openbsd to release 6.9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tests/vm: update openbsd to release 6.9 Signed-off-by: Brad Smith Signed-off-by: Alex Bennée Tested-by: Gerd Hoffmann Acked-by: Philippe Mathieu-Daudé Message-Id: Message-Id: <20210709143005.1554-26-alex.bennee@linaro.org> --- tests/vm/openbsd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/vm/openbsd b/tests/vm/openbsd index 4d1399378e..c4c78a80f1 100755 --- a/tests/vm/openbsd +++ b/tests/vm/openbsd @@ -22,8 +22,8 @@ class OpenBSDVM(basevm.BaseVM): name = "openbsd" arch = "x86_64" - link = "https://cdn.openbsd.org/pub/OpenBSD/6.8/amd64/install68.iso" - csum = "47e291fcc2d0c1a8ae0b66329f040b33af755b6adbd21739e20bb5ad56f62b6c" + link = "https://cdn.openbsd.org/pub/OpenBSD/6.9/amd64/install69.iso" + csum = "140d26548aec680e34bb5f82295414228e7f61e4f5e7951af066014fda2d6e43" size = "20G" pkgs = [ # tools From e2bcd3ad093a6bd4a045d5b5d22f0b92243d0da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 9 Jul 2021 15:29:51 +0100 Subject: [PATCH 134/531] tests/tcg: make test-mmap a little less aggressive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The check_aligned_anonymous_unfixed_mmaps and check_aligned_anonymous_unfixed_colliding_mmaps do a lot of mmap's and copying of data. This is especially unfriendly to targets like hexagon which have quite large pages and need to do sanity checks on each memory access. While we are at it clean-up the white space and style issues from the legacy code. As we no longer do quite so much needless memory access we can also remove the hexagon timeout hack. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Reviewed-by: Taylor Simpson Message-Id: <20210709143005.1554-27-alex.bennee@linaro.org> --- tests/tcg/hexagon/Makefile.target | 9 -- tests/tcg/multiarch/test-mmap.c | 190 +++++++++++++++--------------- 2 files changed, 95 insertions(+), 104 deletions(-) diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target index 0992787d50..050cd61c1a 100644 --- a/tests/tcg/hexagon/Makefile.target +++ b/tests/tcg/hexagon/Makefile.target @@ -18,15 +18,6 @@ # Hexagon doesn't support gdb, so skip the EXTRA_RUNS EXTRA_RUNS = -# Hexagon has 64K pages, so increase the timeout to keep -# test-mmap from timing out -ifeq ($(CONFIG_DEBUG_TCG),y) -TIMEOUT=800 -else -TIMEOUT=500 -endif - - CFLAGS += -Wno-incompatible-pointer-types -Wno-undefined-internal CFLAGS += -fno-unroll-loops diff --git a/tests/tcg/multiarch/test-mmap.c b/tests/tcg/multiarch/test-mmap.c index 11d0e777b1..96257f8ebe 100644 --- a/tests/tcg/multiarch/test-mmap.c +++ b/tests/tcg/multiarch/test-mmap.c @@ -49,64 +49,62 @@ size_t test_fsize; void check_aligned_anonymous_unfixed_mmaps(void) { - void *p1; - void *p2; - void *p3; - void *p4; - void *p5; - uintptr_t p; - int i; + void *p1; + void *p2; + void *p3; + void *p4; + void *p5; + uintptr_t p; + int i; + fprintf(stdout, "%s", __func__); + for (i = 0; i < 8; i++) { + size_t len; + len = pagesize + (pagesize * i); + p1 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + p2 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + p3 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + p4 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + p5 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - fprintf(stdout, "%s", __func__); - for (i = 0; i < 0x1fff; i++) - { - size_t len; + /* + * Make sure we get pages aligned with the pagesize. The + * target expects this. + */ + fail_unless(p1 != MAP_FAILED); + fail_unless(p2 != MAP_FAILED); + fail_unless(p3 != MAP_FAILED); + fail_unless(p4 != MAP_FAILED); + fail_unless(p5 != MAP_FAILED); + p = (uintptr_t) p1; + D(printf("p=%x\n", p)); + fail_unless((p & pagemask) == 0); + p = (uintptr_t) p2; + fail_unless((p & pagemask) == 0); + p = (uintptr_t) p3; + fail_unless((p & pagemask) == 0); + p = (uintptr_t) p4; + fail_unless((p & pagemask) == 0); + p = (uintptr_t) p5; + fail_unless((p & pagemask) == 0); - len = pagesize + (pagesize * i & 7); - p1 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - p2 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - p3 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - p4 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - p5 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - /* Make sure we get pages aligned with the pagesize. The - target expects this. */ - fail_unless (p1 != MAP_FAILED); - fail_unless (p2 != MAP_FAILED); - fail_unless (p3 != MAP_FAILED); - fail_unless (p4 != MAP_FAILED); - fail_unless (p5 != MAP_FAILED); - p = (uintptr_t) p1; - D(printf ("p=%x\n", p)); - fail_unless ((p & pagemask) == 0); - p = (uintptr_t) p2; - fail_unless ((p & pagemask) == 0); - p = (uintptr_t) p3; - fail_unless ((p & pagemask) == 0); - p = (uintptr_t) p4; - fail_unless ((p & pagemask) == 0); - p = (uintptr_t) p5; - fail_unless ((p & pagemask) == 0); - - /* Make sure we can read from the entire area. */ - memcpy (dummybuf, p1, pagesize); - memcpy (dummybuf, p2, pagesize); - memcpy (dummybuf, p3, pagesize); - memcpy (dummybuf, p4, pagesize); - memcpy (dummybuf, p5, pagesize); - - munmap (p1, len); - munmap (p2, len); - munmap (p3, len); - munmap (p4, len); - munmap (p5, len); - } - fprintf(stdout, " passed\n"); + /* Make sure we can read from the entire area. */ + memcpy(dummybuf, p1, pagesize); + memcpy(dummybuf, p2, pagesize); + memcpy(dummybuf, p3, pagesize); + memcpy(dummybuf, p4, pagesize); + memcpy(dummybuf, p5, pagesize); + munmap(p1, len); + munmap(p2, len); + munmap(p3, len); + munmap(p4, len); + munmap(p5, len); + } + fprintf(stdout, " passed\n"); } void check_large_anonymous_unfixed_mmap(void) @@ -135,52 +133,54 @@ void check_large_anonymous_unfixed_mmap(void) void check_aligned_anonymous_unfixed_colliding_mmaps(void) { - char *p1; - char *p2; - char *p3; - uintptr_t p; - int i; + char *p1; + char *p2; + char *p3; + uintptr_t p; + int i; - fprintf(stdout, "%s", __func__); - for (i = 0; i < 0x2fff; i++) - { - int nlen; - p1 = mmap(NULL, pagesize, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - fail_unless (p1 != MAP_FAILED); - p = (uintptr_t) p1; - fail_unless ((p & pagemask) == 0); - memcpy (dummybuf, p1, pagesize); + fprintf(stdout, "%s", __func__); + for (i = 0; i < 2; i++) { + int nlen; + p1 = mmap(NULL, pagesize, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + fail_unless(p1 != MAP_FAILED); + p = (uintptr_t) p1; + fail_unless((p & pagemask) == 0); + memcpy(dummybuf, p1, pagesize); - p2 = mmap(NULL, pagesize, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - fail_unless (p2 != MAP_FAILED); - p = (uintptr_t) p2; - fail_unless ((p & pagemask) == 0); - memcpy (dummybuf, p2, pagesize); + p2 = mmap(NULL, pagesize, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + fail_unless(p2 != MAP_FAILED); + p = (uintptr_t) p2; + fail_unless((p & pagemask) == 0); + memcpy(dummybuf, p2, pagesize); - munmap (p1, pagesize); - nlen = pagesize * 8; - p3 = mmap(NULL, nlen, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - fail_unless (p3 != MAP_FAILED); + munmap(p1, pagesize); + nlen = pagesize * 8; + p3 = mmap(NULL, nlen, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + fail_unless(p3 != MAP_FAILED); - /* Check if the mmaped areas collide. */ - if (p3 < p2 - && (p3 + nlen) > p2) - fail_unless (0); + /* Check if the mmaped areas collide. */ + if (p3 < p2 + && (p3 + nlen) > p2) { + fail_unless(0); + } - memcpy (dummybuf, p3, pagesize); + memcpy(dummybuf, p3, pagesize); - /* Make sure we get pages aligned with the pagesize. The - target expects this. */ - p = (uintptr_t) p3; - fail_unless ((p & pagemask) == 0); - munmap (p2, pagesize); - munmap (p3, nlen); - } - fprintf(stdout, " passed\n"); + /* + * Make sure we get pages aligned with the pagesize. The + * target expects this. + */ + p = (uintptr_t) p3; + fail_unless((p & pagemask) == 0); + munmap(p2, pagesize); + munmap(p3, nlen); + } + fprintf(stdout, " passed\n"); } void check_aligned_anonymous_fixed_mmaps(void) From 2d932039980ab78b39030a7a80ad5eb7a93c894f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 9 Jul 2021 15:29:52 +0100 Subject: [PATCH 135/531] plugins: fix-up handling of internal hostaddr for 32 bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The compiler rightly complains when we build on 32 bit that casting uint64_t into a void is a bad idea. We are really dealing with a host pointer at this point so treat it as such. This does involve a uintptr_t cast of the result of the TLB addend as we know that has to point to the host memory. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20210709143005.1554-28-alex.bennee@linaro.org> --- accel/tcg/cputlb.c | 2 +- include/qemu/plugin-memory.h | 2 +- plugins/api.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index b6d5fc6326..b4e15b6aad 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1728,7 +1728,7 @@ bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx, data->v.io.offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; } else { data->is_io = false; - data->v.ram.hostaddr = addr + tlbe->addend; + data->v.ram.hostaddr = (void *)((uintptr_t)addr + tlbe->addend); } return true; } else { diff --git a/include/qemu/plugin-memory.h b/include/qemu/plugin-memory.h index b36def27d7..0f59226727 100644 --- a/include/qemu/plugin-memory.h +++ b/include/qemu/plugin-memory.h @@ -18,7 +18,7 @@ struct qemu_plugin_hwaddr { hwaddr offset; } io; struct { - uint64_t hostaddr; + void *hostaddr; } ram; } v; }; diff --git a/plugins/api.c b/plugins/api.c index 332e2c60e2..78b563c5c5 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -308,11 +308,11 @@ uint64_t qemu_plugin_hwaddr_phys_addr(const struct qemu_plugin_hwaddr *haddr) if (!haddr->is_io) { RAMBlock *block; ram_addr_t offset; - void *hostaddr = (void *) haddr->v.ram.hostaddr; + void *hostaddr = haddr->v.ram.hostaddr; block = qemu_ram_block_from_host(hostaddr, false, &offset); if (!block) { - error_report("Bad ram pointer %"PRIx64"", haddr->v.ram.hostaddr); + error_report("Bad host ram pointer %p", haddr->v.ram.hostaddr); abort(); } From 029aa68fdcc5a5bbf28f0044b9394dabde2b88e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 9 Jul 2021 15:29:53 +0100 Subject: [PATCH 136/531] meson.build: move TCG plugin summary output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's put it with the rest of the TCG related output with the accelerator. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210709143005.1554-29-alex.bennee@linaro.org> --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 89c09ed7ea..c6dd70c400 100644 --- a/meson.build +++ b/meson.build @@ -2833,7 +2833,6 @@ summary_info += {'module support': config_host.has_key('CONFIG_MODULES')} if config_host.has_key('CONFIG_MODULES') summary_info += {'alternative module path': config_host.has_key('CONFIG_MODULE_UPGRADES')} endif -summary_info += {'plugin support': config_host.has_key('CONFIG_PLUGIN')} summary_info += {'fuzzing support': config_host.has_key('CONFIG_FUZZ')} if have_system summary_info += {'Audio drivers': config_host['CONFIG_AUDIO_DRIVERS']} @@ -2949,6 +2948,7 @@ if config_all.has_key('CONFIG_TCG') else summary_info += {'TCG backend': 'native (@0@)'.format(cpu)} endif + summary_info += {'TCG plugins': config_host.has_key('CONFIG_PLUGIN')} summary_info += {'TCG debug enabled': config_host.has_key('CONFIG_DEBUG_TCG')} endif summary_info += {'target list': ' '.join(target_dirs)} From e8575f2532e74cea6d9c750f6b4404071aa47917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 14 Jul 2021 11:15:36 +0100 Subject: [PATCH 137/531] meson.build: relax the libdl test to one for the function dlopen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the *BSD family dlopen is already part of libc so it's not a hard dependency to have a libdl.so library. Signed-off-by: Alex Bennée Reviewed-by: Paolo Bonzini Message-Id: <20210714101536.16016-1-alex.bennee@linaro.org> --- meson.build | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index c6dd70c400..e5de144233 100644 --- a/meson.build +++ b/meson.build @@ -455,7 +455,10 @@ endif rt = cc.find_library('rt', required: false) libdl = not_found if 'CONFIG_PLUGIN' in config_host - libdl = cc.find_library('dl', required: true) + libdl = cc.find_library('dl', required: false) + if not cc.has_function('dlopen', dependencies: libdl) + error('dlopen not found') + endif endif libiscsi = not_found if not get_option('libiscsi').auto() or have_block From 2572ac1b224359dc2d58543d071ed977ed7c616c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 14 Jul 2021 11:16:23 +0100 Subject: [PATCH 138/531] tcg/plugins: remove some stale entries from the symbol list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OSX linker is a lot fussier about these missing symbols. Signed-off-by: Alex Bennée Message-Id: <20210714101623.17046-1-alex.bennee@linaro.org> --- plugins/qemu-plugins.symbols | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols index 4bdb381f48..40b4ff3821 100644 --- a/plugins/qemu-plugins.symbols +++ b/plugins/qemu-plugins.symbols @@ -8,9 +8,7 @@ qemu_plugin_register_vcpu_insn_exec_cb; qemu_plugin_register_vcpu_insn_exec_inline; qemu_plugin_register_vcpu_mem_cb; - qemu_plugin_register_vcpu_mem_haddr_cb; qemu_plugin_register_vcpu_mem_inline; - qemu_plugin_ram_addr_from_host; qemu_plugin_register_vcpu_tb_trans_cb; qemu_plugin_register_vcpu_tb_exec_cb; qemu_plugin_register_vcpu_tb_exec_inline; @@ -32,7 +30,6 @@ qemu_plugin_mem_is_store; qemu_plugin_get_hwaddr; qemu_plugin_hwaddr_is_io; - qemu_plugin_hwaddr_to_raddr; qemu_plugin_vcpu_for_each; qemu_plugin_n_vcpus; qemu_plugin_n_max_vcpus; From d1a142572d8e3cf932647120d0a72c9942667e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 9 Jul 2021 15:29:54 +0100 Subject: [PATCH 139/531] configure: don't allow plugins to be enabled for a non-TCG build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20210709143005.1554-30-alex.bennee@linaro.org> --- configure | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/configure b/configure index 4d0a2bfdd8..e2a353ce1c 100755 --- a/configure +++ b/configure @@ -1110,6 +1110,7 @@ for opt do --enable-cap-ng) cap_ng="enabled" ;; --disable-tcg) tcg="disabled" + plugins="no" ;; --enable-tcg) tcg="enabled" ;; @@ -1575,6 +1576,11 @@ for opt do esac done +# test for any invalid configuration combinations +if test "$plugins" = "yes" -a "$tcg" = "disabled"; then + error_exit "Can't enable plugins on non-TCG builds" +fi + case $git_submodules_action in update|validate) if test ! -e "$source_path/.git"; then From 5f2453ac749d2765d81ada38c29d3d10c1ef2bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 9 Jul 2021 15:29:55 +0100 Subject: [PATCH 140/531] configure: add an explicit static and plugins check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moving this check earlier will make the later re-factor for enabling by default a bit neater. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20210709143005.1554-31-alex.bennee@linaro.org> --- configure | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/configure b/configure index e2a353ce1c..2c39ccf8e1 100755 --- a/configure +++ b/configure @@ -2197,11 +2197,14 @@ if test "$modules" = "no" && test "$module_upgrades" = "yes" ; then error_exit "Can't enable module-upgrades as Modules are not enabled" fi -# Static linking is not possible with modules or PIE +# Static linking is not possible with plugins, modules or PIE if test "$static" = "yes" ; then if test "$modules" = "yes" ; then error_exit "static and modules are mutually incompatible" fi + if test "$plugins" = "yes"; then + error_exit "static and plugins are mutually incompatible" + fi fi # Unconditional check for compiler __thread support @@ -3979,7 +3982,7 @@ if test "$plugins" = "yes" && "Plugin support requires dynamic linking and specifying a set of symbols " \ "that are exported to plugins. Unfortunately your linker doesn't " \ "support the flag (--dynamic-list or -exported_symbols_list) used " \ - "for this purpose. You can't build with --static." + "for this purpose." fi ######################################## From 9b8e4298517fc265b7dea93d79eb53a9b3315ddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 9 Jul 2021 15:29:56 +0100 Subject: [PATCH 141/531] configure: stop user enabling plugins on Windows for now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are some patches on the list that enable plugins on Windows but they still need some changes to be ready: https://patchew.org/QEMU/20201013002806.1447-1-luoyonggang@gmail.com/ In the meantime lets stop the user from being able to configure the support so they don't get confused by the weird linker error messages later. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Cc: Yonggang Luo Message-Id: <20210709143005.1554-32-alex.bennee@linaro.org> --- configure | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 2c39ccf8e1..e7f2fcd02c 100755 --- a/configure +++ b/configure @@ -708,6 +708,7 @@ MINGW32*) audio_drv_list="" fi supported_os="yes" + plugins="no" pie="no" ;; GNU/kFreeBSD) @@ -1522,7 +1523,11 @@ for opt do ;; --disable-xkbcommon) xkbcommon="disabled" ;; - --enable-plugins) plugins="yes" + --enable-plugins) if test "$mingw32" = "yes"; then + error_exit "TCG plugins not currently supported on Windows platforms" + else + plugins="yes" + fi ;; --disable-plugins) plugins="no" ;; From ba4dd2aabc35bc5385739e13f14e3a10a223ede0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 9 Jul 2021 15:29:57 +0100 Subject: [PATCH 142/531] tcg/plugins: enable by default for most TCG builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aside from a minor bloat to file size the ability to have TCG plugins has no real impact on performance unless a plugin is actively loaded. Even then the libempty.so plugin shows only a minor degradation in performance caused by the extra book keeping the TCG has to do to keep track of instructions. As it's a useful feature lets just enable it by default and reduce our testing matrix a little. We need to move our linker testing earlier so we can be sure we can enable the loader module required. As we have ruled out static & plugins in an earlier patch we can also reduce the indent a little. Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Cc: Paolo Bonzini Message-Id: <20210709143005.1554-33-alex.bennee@linaro.org> --- .gitlab-ci.d/buildtest.yml | 23 ------- configure | 124 ++++++++++++++++++++----------------- docs/devel/tcg-plugins.rst | 3 +- 3 files changed, 69 insertions(+), 81 deletions(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index d9b834c848..89df51517c 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -354,29 +354,6 @@ build-some-softmmu: TARGETS: xtensa-softmmu arm-softmmu aarch64-softmmu alpha-softmmu MAKE_CHECK_ARGS: check-tcg -# Run check-tcg against linux-user (with plugins) -# we skip sparc64-linux-user until it has been fixed somewhat -# we skip cris-linux-user as it doesn't use the common run loop -build-user-plugins: - extends: .native_build_job_template - needs: - job: amd64-debian-user-cross-container - variables: - IMAGE: debian-all-test-cross - CONFIGURE_ARGS: --disable-tools --disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user - MAKE_CHECK_ARGS: check-tcg - timeout: 1h 30m - -build-some-softmmu-plugins: - extends: .native_build_job_template - needs: - job: amd64-debian-user-cross-container - variables: - IMAGE: debian-all-test-cross - CONFIGURE_ARGS: --disable-tools --disable-user --enable-plugins --enable-debug-tcg - TARGETS: xtensa-softmmu arm-softmmu aarch64-softmmu alpha-softmmu - MAKE_CHECK_ARGS: check-tcg - clang-system: extends: .native_build_job_template needs: diff --git a/configure b/configure index e7f2fcd02c..49b5481139 100755 --- a/configure +++ b/configure @@ -429,7 +429,7 @@ libxml2="auto" debug_mutex="no" libpmem="auto" default_devices="true" -plugins="no" +plugins="$default_feature" fuzzing="no" rng_none="no" secret_keyring="$default_feature" @@ -2209,6 +2209,8 @@ if test "$static" = "yes" ; then fi if test "$plugins" = "yes"; then error_exit "static and plugins are mutually incompatible" + else + plugins="no" fi fi @@ -3102,6 +3104,69 @@ for drv in $audio_drv_list; do esac done +########################################## +# plugin linker support probe + +if test "$plugins" != "no"; then + + ######################################### + # See if --dynamic-list is supported by the linker + + ld_dynamic_list="no" + cat > $TMPTXT < $TMPC < +void foo(void); + +void foo(void) +{ + printf("foo\n"); +} + +int main(void) +{ + foo(); + return 0; +} +EOF + + if compile_prog "" "-Wl,--dynamic-list=$TMPTXT" ; then + ld_dynamic_list="yes" + fi + + ######################################### + # See if -exported_symbols_list is supported by the linker + + ld_exported_symbols_list="no" + cat > $TMPTXT < $TMPTXT < $TMPC < -void foo(void); - -void foo(void) -{ - printf("foo\n"); -} - -int main(void) -{ - foo(); - return 0; -} -EOF - - if compile_prog "" "-Wl,--dynamic-list=$TMPTXT" ; then - ld_dynamic_list="yes" - fi -fi - -######################################### -# See if -exported_symbols_list is supported by the linker - -ld_exported_symbols_list="no" -if test "$static" = "no" ; then - cat > $TMPTXT < Date: Fri, 9 Jul 2021 15:29:58 +0100 Subject: [PATCH 143/531] contrib/plugins: enable -Wall for building plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lets spot the obvious errors. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Message-Id: <20210709143005.1554-34-alex.bennee@linaro.org> --- contrib/plugins/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile index b9d7935e5e..3431bc1ce9 100644 --- a/contrib/plugins/Makefile +++ b/contrib/plugins/Makefile @@ -24,7 +24,7 @@ SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES))) # The main QEMU uses Glib extensively so it's perfectly fine to use it # in plugins (which many example do). CFLAGS = $(GLIB_CFLAGS) -CFLAGS += -fPIC +CFLAGS += -fPIC -Wall $(filter -W%, $(QEMU_CFLAGS)) CFLAGS += $(if $(findstring no-psabi,$(QEMU_CFLAGS)),-Wpsabi) CFLAGS += -I$(SRC_PATH)/include/qemu From 3d7caf145e69b61d17f7cada8713f37af2aaebf1 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 9 Jul 2021 15:29:59 +0100 Subject: [PATCH 144/531] contrib/plugins: add execlog to log instruction execution and memory access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Log instruction execution and memory access to a file. This plugin can be used for reverse engineering or for side-channel analysis using QEMU. Signed-off-by: Alexandre Iooss Signed-off-by: Alex Bennée Reviewed-by: Alex Bennée Message-Id: <20210702081307.1653644-2-erdnaxe@crans.org> Message-Id: <20210709143005.1554-35-alex.bennee@linaro.org> --- MAINTAINERS | 1 + contrib/plugins/Makefile | 1 + contrib/plugins/execlog.c | 153 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 contrib/plugins/execlog.c diff --git a/MAINTAINERS b/MAINTAINERS index c340bb02b0..83b55030ad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3017,6 +3017,7 @@ F: include/tcg/ TCG Plugins M: Alex Bennée +R: Alexandre Iooss S: Maintained F: docs/devel/tcg-plugins.rst F: plugins/ diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile index 3431bc1ce9..3c9209b6b0 100644 --- a/contrib/plugins/Makefile +++ b/contrib/plugins/Makefile @@ -13,6 +13,7 @@ include $(BUILD_DIR)/config-host.mak VPATH += $(SRC_PATH)/contrib/plugins NAMES := +NAMES += execlog NAMES += hotblocks NAMES += hotpages NAMES += howvec diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c new file mode 100644 index 0000000000..2de9f0d7d4 --- /dev/null +++ b/contrib/plugins/execlog.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2021, Alexandre Iooss + * + * Log instruction execution with memory access. + * + * License: GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include +#include +#include +#include +#include +#include + +#include + +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + +/* Store last executed instruction on each vCPU as a GString */ +GArray *last_exec; + +/** + * Add memory read or write information to current instruction log + */ +static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t info, + uint64_t vaddr, void *udata) +{ + GString *s; + + /* Find vCPU in array */ + g_assert(cpu_index < last_exec->len); + s = g_array_index(last_exec, GString *, cpu_index); + + /* Indicate type of memory access */ + if (qemu_plugin_mem_is_store(info)) { + g_string_append(s, ", store"); + } else { + g_string_append(s, ", load"); + } + + /* If full system emulation log physical address and device name */ + struct qemu_plugin_hwaddr *hwaddr = qemu_plugin_get_hwaddr(info, vaddr); + if (hwaddr) { + uint64_t addr = qemu_plugin_hwaddr_phys_addr(hwaddr); + const char *name = qemu_plugin_hwaddr_device_name(hwaddr); + g_string_append_printf(s, ", 0x%08"PRIx64", %s", addr, name); + } else { + g_string_append_printf(s, ", 0x%08"PRIx64, vaddr); + } +} + +/** + * Log instruction execution + */ +static void vcpu_insn_exec(unsigned int cpu_index, void *udata) +{ + GString *s; + + /* Find or create vCPU in array */ + while (cpu_index >= last_exec->len) { + s = g_string_new(NULL); + g_array_append_val(last_exec, s); + } + s = g_array_index(last_exec, GString *, cpu_index); + + /* Print previous instruction in cache */ + if (s->len) { + qemu_plugin_outs(s->str); + qemu_plugin_outs("s\n"); + } + + /* Store new instruction in cache */ + /* vcpu_mem will add memory access information to last_exec */ + g_string_printf(s, "%u, ", cpu_index); + g_string_append(s, (char *)udata); +} + +/** + * On translation block new translation + * + * QEMU convert code by translation block (TB). By hooking here we can then hook + * a callback on each instruction and memory access. + */ +static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) +{ + struct qemu_plugin_insn *insn; + uint64_t insn_vaddr; + uint32_t insn_opcode; + char *insn_disas; + + size_t n = qemu_plugin_tb_n_insns(tb); + for (size_t i = 0; i < n; i++) { + /* + * `insn` is shared between translations in QEMU, copy needed data here. + * `output` is never freed as it might be used multiple times during + * the emulation lifetime. + * We only consider the first 32 bits of the instruction, this may be + * a limitation for CISC architectures. + */ + insn = qemu_plugin_tb_get_insn(tb, i); + insn_vaddr = qemu_plugin_insn_vaddr(insn); + insn_opcode = *((uint32_t *)qemu_plugin_insn_data(insn)); + insn_disas = qemu_plugin_insn_disas(insn); + char *output = g_strdup_printf("0x%"PRIx64", 0x%"PRIx32", \"%s\"", + insn_vaddr, insn_opcode, insn_disas); + + /* Register callback on memory read or write */ + qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem, + QEMU_PLUGIN_CB_NO_REGS, + QEMU_PLUGIN_MEM_RW, NULL); + + /* Register callback on instruction */ + qemu_plugin_register_vcpu_insn_exec_cb(insn, vcpu_insn_exec, + QEMU_PLUGIN_CB_NO_REGS, output); + } +} + +/** + * On plugin exit, print last instruction in cache + */ +static void plugin_exit(qemu_plugin_id_t id, void *p) +{ + guint i; + GString *s; + for (i = 0; i < last_exec->len; i++) { + s = g_array_index(last_exec, GString *, i); + if (s->str) { + qemu_plugin_outs(s->str); + qemu_plugin_outs("\n"); + } + } +} + +/** + * Install the plugin + */ +QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, + const qemu_info_t *info, int argc, + char **argv) +{ + /* + * Initialize dynamic array to cache vCPU instruction. In user mode + * we don't know the size before emulation. + */ + last_exec = g_array_new(FALSE, FALSE, sizeof(GString *)); + + /* Register translation block and exit callbacks */ + qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); + qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); + + return 0; +} From 307ce0aaeb5799d05f63b76a91135466f6b15302 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 9 Jul 2021 15:30:00 +0100 Subject: [PATCH 145/531] docs/devel: tcg-plugins: add execlog plugin description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds description of the execlog TCG plugin with an example. Signed-off-by: Alexandre Iooss Signed-off-by: Alex Bennée Message-Id: <20210702081307.1653644-3-erdnaxe@crans.org> Message-Id: <20210709143005.1554-36-alex.bennee@linaro.org> --- docs/devel/tcg-plugins.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst index 0cd77c77d2..179867e9c1 100644 --- a/docs/devel/tcg-plugins.rst +++ b/docs/devel/tcg-plugins.rst @@ -320,3 +320,27 @@ the user to see what hardware is accessed how often. It has a number of options: off:0000001c, 1, 2 off:00000020, 1, 2 ... + +- contrib/plugins/execlog.c + +The execlog tool traces executed instructions with memory access. It can be used +for debugging and security analysis purposes. +Please be aware that this will generate a lot of output. + +The plugin takes no argument:: + + qemu-system-arm $(QEMU_ARGS) \ + -plugin ./contrib/plugins/libexeclog.so -d plugin + +which will output an execution trace following this structure:: + + # vCPU, vAddr, opcode, disassembly[, load/store, memory addr, device]... + 0, 0xa12, 0xf8012400, "movs r4, #0" + 0, 0xa14, 0xf87f42b4, "cmp r4, r6" + 0, 0xa16, 0xd206, "bhs #0xa26" + 0, 0xa18, 0xfff94803, "ldr r0, [pc, #0xc]", load, 0x00010a28, RAM + 0, 0xa1a, 0xf989f000, "bl #0xd30" + 0, 0xd30, 0xfff9b510, "push {r4, lr}", store, 0x20003ee0, RAM, store, 0x20003ee4, RAM + 0, 0xd32, 0xf9893014, "adds r0, #0x14" + 0, 0xd34, 0xf9c8f000, "bl #0x10c8" + 0, 0x10c8, 0xfff96c43, "ldr r3, [r0, #0x44]", load, 0x200000e4, RAM From e2c5557ce1329f58efd8e1f27c3548acaa82e196 Mon Sep 17 00:00:00 2001 From: Mahmoud Mandour Date: Fri, 9 Jul 2021 15:30:01 +0100 Subject: [PATCH 146/531] plugins: Added a new cache modelling plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a cache modelling plugin that uses a static configuration used in many of the commercial microprocessors and uses random eviction policy. The purpose of the plugin is to identify the most cache-thrashing instructions for both instruction cache and data cache. Signed-off-by: Mahmoud Mandour Signed-off-by: Alex Bennée Message-Id: <20210623125458.450462-2-ma.mandourr@gmail.com> Message-Id: <20210709143005.1554-37-alex.bennee@linaro.org> --- contrib/plugins/Makefile | 1 + contrib/plugins/cache.c | 419 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 420 insertions(+) create mode 100644 contrib/plugins/cache.c diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile index 3c9209b6b0..54ac5ccd9f 100644 --- a/contrib/plugins/Makefile +++ b/contrib/plugins/Makefile @@ -19,6 +19,7 @@ NAMES += hotpages NAMES += howvec NAMES += lockstep NAMES += hwprofile +NAMES += cache SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES))) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c new file mode 100644 index 0000000000..e9955cdc3a --- /dev/null +++ b/contrib/plugins/cache.c @@ -0,0 +1,419 @@ +/* + * Copyright (C) 2021, Mahmoud Mandour + * + * License: GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include + +#include + +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + +static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW; + +static GHashTable *miss_ht; + +static GMutex mtx; +static GRand *rng; + +static int limit; +static bool sys; + +static uint64_t dmem_accesses; +static uint64_t dmisses; + +static uint64_t imem_accesses; +static uint64_t imisses; + +/* + * A CacheSet is a set of cache blocks. A memory block that maps to a set can be + * put in any of the blocks inside the set. The number of block per set is + * called the associativity (assoc). + * + * Each block contains the the stored tag and a valid bit. Since this is not + * a functional simulator, the data itself is not stored. We only identify + * whether a block is in the cache or not by searching for its tag. + * + * In order to search for memory data in the cache, the set identifier and tag + * are extracted from the address and the set is probed to see whether a tag + * match occur. + * + * An address is logically divided into three portions: The block offset, + * the set number, and the tag. + * + * The set number is used to identify the set in which the block may exist. + * The tag is compared against all the tags of a set to search for a match. If a + * match is found, then the access is a hit. + */ + +typedef struct { + uint64_t tag; + bool valid; +} CacheBlock; + +typedef struct { + CacheBlock *blocks; +} CacheSet; + +typedef struct { + CacheSet *sets; + int num_sets; + int cachesize; + int assoc; + int blksize_shift; + uint64_t set_mask; + uint64_t tag_mask; +} Cache; + +typedef struct { + char *disas_str; + const char *symbol; + uint64_t addr; + uint64_t dmisses; + uint64_t imisses; +} InsnData; + +Cache *dcache, *icache; + +static int pow_of_two(int num) +{ + g_assert((num & (num - 1)) == 0); + int ret = 0; + while (num /= 2) { + ret++; + } + return ret; +} + +static inline uint64_t extract_tag(Cache *cache, uint64_t addr) +{ + return addr & cache->tag_mask; +} + +static inline uint64_t extract_set(Cache *cache, uint64_t addr) +{ + return (addr & cache->set_mask) >> cache->blksize_shift; +} + +static Cache *cache_init(int blksize, int assoc, int cachesize) +{ + Cache *cache; + int i; + uint64_t blk_mask; + + cache = g_new(Cache, 1); + cache->assoc = assoc; + cache->cachesize = cachesize; + cache->num_sets = cachesize / (blksize * assoc); + cache->sets = g_new(CacheSet, cache->num_sets); + cache->blksize_shift = pow_of_two(blksize); + + for (i = 0; i < cache->num_sets; i++) { + cache->sets[i].blocks = g_new0(CacheBlock, assoc); + } + + blk_mask = blksize - 1; + cache->set_mask = ((cache->num_sets - 1) << cache->blksize_shift); + cache->tag_mask = ~(cache->set_mask | blk_mask); + return cache; +} + +static int get_invalid_block(Cache *cache, uint64_t set) +{ + int i; + + for (i = 0; i < cache->assoc; i++) { + if (!cache->sets[set].blocks[i].valid) { + return i; + } + } + + return -1; +} + +static int get_replaced_block(Cache *cache) +{ + return g_rand_int_range(rng, 0, cache->assoc); +} + +static bool in_cache(Cache *cache, uint64_t addr) +{ + int i; + uint64_t tag, set; + + tag = extract_tag(cache, addr); + set = extract_set(cache, addr); + + for (i = 0; i < cache->assoc; i++) { + if (cache->sets[set].blocks[i].tag == tag && + cache->sets[set].blocks[i].valid) { + return true; + } + } + + return false; +} + +/** + * access_cache(): Simulate a cache access + * @cache: The cache under simulation + * @addr: The address of the requested memory location + * + * Returns true if the requsted data is hit in the cache and false when missed. + * The cache is updated on miss for the next access. + */ +static bool access_cache(Cache *cache, uint64_t addr) +{ + uint64_t tag, set; + int replaced_blk; + + if (in_cache(cache, addr)) { + return true; + } + + tag = extract_tag(cache, addr); + set = extract_set(cache, addr); + + replaced_blk = get_invalid_block(cache, set); + + if (replaced_blk == -1) { + replaced_blk = get_replaced_block(cache); + } + + cache->sets[set].blocks[replaced_blk].tag = tag; + cache->sets[set].blocks[replaced_blk].valid = true; + + return false; +} + +static void vcpu_mem_access(unsigned int vcpu_index, qemu_plugin_meminfo_t info, + uint64_t vaddr, void *userdata) +{ + uint64_t effective_addr; + struct qemu_plugin_hwaddr *hwaddr; + InsnData *insn; + + g_mutex_lock(&mtx); + hwaddr = qemu_plugin_get_hwaddr(info, vaddr); + if (hwaddr && qemu_plugin_hwaddr_is_io(hwaddr)) { + g_mutex_unlock(&mtx); + return; + } + + effective_addr = hwaddr ? qemu_plugin_hwaddr_phys_addr(hwaddr) : vaddr; + + if (!access_cache(dcache, effective_addr)) { + insn = (InsnData *) userdata; + insn->dmisses++; + dmisses++; + } + dmem_accesses++; + g_mutex_unlock(&mtx); +} + +static void vcpu_insn_exec(unsigned int vcpu_index, void *userdata) +{ + uint64_t insn_addr; + InsnData *insn; + + g_mutex_lock(&mtx); + insn_addr = ((InsnData *) userdata)->addr; + + if (!access_cache(icache, insn_addr)) { + insn = (InsnData *) userdata; + insn->imisses++; + imisses++; + } + imem_accesses++; + g_mutex_unlock(&mtx); +} + +static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) +{ + size_t n_insns; + size_t i; + InsnData *data; + + n_insns = qemu_plugin_tb_n_insns(tb); + for (i = 0; i < n_insns; i++) { + struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i); + uint64_t effective_addr; + + if (sys) { + effective_addr = (uint64_t) qemu_plugin_insn_haddr(insn); + } else { + effective_addr = (uint64_t) qemu_plugin_insn_vaddr(insn); + } + + /* + * Instructions might get translated multiple times, we do not create + * new entries for those instructions. Instead, we fetch the same + * entry from the hash table and register it for the callback again. + */ + g_mutex_lock(&mtx); + data = g_hash_table_lookup(miss_ht, GUINT_TO_POINTER(effective_addr)); + if (data == NULL) { + data = g_new0(InsnData, 1); + data->disas_str = qemu_plugin_insn_disas(insn); + data->symbol = qemu_plugin_insn_symbol(insn); + data->addr = effective_addr; + g_hash_table_insert(miss_ht, GUINT_TO_POINTER(effective_addr), + (gpointer) data); + } + g_mutex_unlock(&mtx); + + qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem_access, + QEMU_PLUGIN_CB_NO_REGS, + rw, data); + + qemu_plugin_register_vcpu_insn_exec_cb(insn, vcpu_insn_exec, + QEMU_PLUGIN_CB_NO_REGS, data); + } +} + +static void insn_free(gpointer data) +{ + InsnData *insn = (InsnData *) data; + g_free(insn->disas_str); + g_free(insn); +} + +static void cache_free(Cache *cache) +{ + for (int i = 0; i < cache->num_sets; i++) { + g_free(cache->sets[i].blocks); + } + + g_free(cache->sets); + g_free(cache); +} + +static int dcmp(gconstpointer a, gconstpointer b) +{ + InsnData *insn_a = (InsnData *) a; + InsnData *insn_b = (InsnData *) b; + + return insn_a->dmisses < insn_b->dmisses ? 1 : -1; +} + +static int icmp(gconstpointer a, gconstpointer b) +{ + InsnData *insn_a = (InsnData *) a; + InsnData *insn_b = (InsnData *) b; + + return insn_a->imisses < insn_b->imisses ? 1 : -1; +} + +static void log_stats() +{ + g_autoptr(GString) rep = g_string_new(""); + g_string_append_printf(rep, + "Data accesses: %lu, Misses: %lu\nMiss rate: %lf%%\n\n", + dmem_accesses, + dmisses, + ((double) dmisses / (double) dmem_accesses) * 100.0); + + g_string_append_printf(rep, + "Instruction accesses: %lu, Misses: %lu\nMiss rate: %lf%%\n\n", + imem_accesses, + imisses, + ((double) imisses / (double) imem_accesses) * 100.0); + + qemu_plugin_outs(rep->str); +} + +static void log_top_insns() +{ + int i; + GList *curr, *miss_insns; + InsnData *insn; + + miss_insns = g_hash_table_get_values(miss_ht); + miss_insns = g_list_sort(miss_insns, dcmp); + g_autoptr(GString) rep = g_string_new(""); + g_string_append_printf(rep, "%s", "address, data misses, instruction\n"); + + for (curr = miss_insns, i = 0; curr && i < limit; i++, curr = curr->next) { + insn = (InsnData *) curr->data; + g_string_append_printf(rep, "0x%" PRIx64, insn->addr); + if (insn->symbol) { + g_string_append_printf(rep, " (%s)", insn->symbol); + } + g_string_append_printf(rep, ", %ld, %s\n", insn->dmisses, + insn->disas_str); + } + + miss_insns = g_list_sort(miss_insns, icmp); + g_string_append_printf(rep, "%s", "\naddress, fetch misses, instruction\n"); + + for (curr = miss_insns, i = 0; curr && i < limit; i++, curr = curr->next) { + insn = (InsnData *) curr->data; + g_string_append_printf(rep, "0x%" PRIx64, insn->addr); + if (insn->symbol) { + g_string_append_printf(rep, " (%s)", insn->symbol); + } + g_string_append_printf(rep, ", %ld, %s\n", insn->imisses, + insn->disas_str); + } + + qemu_plugin_outs(rep->str); + g_list_free(miss_insns); +} + +static void plugin_exit(qemu_plugin_id_t id, void *p) +{ + log_stats(); + log_top_insns(); + + cache_free(dcache); + cache_free(icache); + + g_hash_table_destroy(miss_ht); +} + +QEMU_PLUGIN_EXPORT +int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, + int argc, char **argv) +{ + int i; + int iassoc, iblksize, icachesize; + int dassoc, dblksize, dcachesize; + + limit = 32; + sys = info->system_emulation; + + dassoc = 8; + dblksize = 64; + dcachesize = dblksize * dassoc * 32; + + iassoc = 8; + iblksize = 64; + icachesize = iblksize * iassoc * 32; + + + for (i = 0; i < argc; i++) { + char *opt = argv[i]; + if (g_str_has_prefix(opt, "limit=")) { + limit = g_ascii_strtoll(opt + 6, NULL, 10); + } else { + fprintf(stderr, "option parsing failed: %s\n", opt); + return -1; + } + } + + dcache = cache_init(dblksize, dassoc, dcachesize); + icache = cache_init(iblksize, iassoc, icachesize); + + rng = g_rand_new(); + + qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); + qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); + + miss_ht = g_hash_table_new_full(NULL, g_direct_equal, NULL, insn_free); + + return 0; +} From 86ae3a1daad3c5b7ca039770d505574c08647e07 Mon Sep 17 00:00:00 2001 From: Mahmoud Mandour Date: Fri, 9 Jul 2021 15:30:02 +0100 Subject: [PATCH 147/531] plugins/cache: Enable cache parameterization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabled configuring both icache and dcache parameters using plugin parameters. Signed-off-by: Mahmoud Mandour Signed-off-by: Alex Bennée Message-Id: <20210623125458.450462-3-ma.mandourr@gmail.com> Message-Id: <20210709143005.1554-38-alex.bennee@linaro.org> --- contrib/plugins/cache.c | 47 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index e9955cdc3a..b550ef31b0 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -99,8 +99,28 @@ static inline uint64_t extract_set(Cache *cache, uint64_t addr) return (addr & cache->set_mask) >> cache->blksize_shift; } +static const char *cache_config_error(int blksize, int assoc, int cachesize) +{ + if (cachesize % blksize != 0) { + return "cache size must be divisible by block size"; + } else if (cachesize % (blksize * assoc) != 0) { + return "cache size must be divisible by set size (assoc * block size)"; + } else { + return NULL; + } +} + +static bool bad_cache_params(int blksize, int assoc, int cachesize) +{ + return (cachesize % blksize) != 0 || (cachesize % (blksize * assoc) != 0); +} + static Cache *cache_init(int blksize, int assoc, int cachesize) { + if (bad_cache_params(blksize, assoc, cachesize)) { + return NULL; + } + Cache *cache; int i; uint64_t blk_mask; @@ -397,7 +417,19 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, for (i = 0; i < argc; i++) { char *opt = argv[i]; - if (g_str_has_prefix(opt, "limit=")) { + if (g_str_has_prefix(opt, "iblksize=")) { + iblksize = g_ascii_strtoll(opt + 9, NULL, 10); + } else if (g_str_has_prefix(opt, "iassoc=")) { + iassoc = g_ascii_strtoll(opt + 7, NULL, 10); + } else if (g_str_has_prefix(opt, "icachesize=")) { + icachesize = g_ascii_strtoll(opt + 11, NULL, 10); + } else if (g_str_has_prefix(opt, "dblksize=")) { + dblksize = g_ascii_strtoll(opt + 9, NULL, 10); + } else if (g_str_has_prefix(opt, "dassoc=")) { + dassoc = g_ascii_strtoll(opt + 7, NULL, 10); + } else if (g_str_has_prefix(opt, "dcachesize=")) { + dcachesize = g_ascii_strtoll(opt + 11, NULL, 10); + } else if (g_str_has_prefix(opt, "limit=")) { limit = g_ascii_strtoll(opt + 6, NULL, 10); } else { fprintf(stderr, "option parsing failed: %s\n", opt); @@ -406,7 +438,20 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, } dcache = cache_init(dblksize, dassoc, dcachesize); + if (!dcache) { + const char *err = cache_config_error(dblksize, dassoc, dcachesize); + fprintf(stderr, "dcache cannot be constructed from given parameters\n"); + fprintf(stderr, "%s\n", err); + return -1; + } + icache = cache_init(iblksize, iassoc, icachesize); + if (!icache) { + const char *err = cache_config_error(iblksize, iassoc, icachesize); + fprintf(stderr, "icache cannot be constructed from given parameters\n"); + fprintf(stderr, "%s\n", err); + return -1; + } rng = g_rand_new(); From 40c4a5533f2d6f268947acdb3e506d81a53ebe66 Mon Sep 17 00:00:00 2001 From: Mahmoud Mandour Date: Fri, 9 Jul 2021 15:30:03 +0100 Subject: [PATCH 148/531] plugins/cache: Added FIFO and LRU eviction policies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implemented FIFO and LRU eviction policies. Now one of the three eviction policies can be chosen as an argument. On not specifying an argument, LRU is used by default. Signed-off-by: Mahmoud Mandour Signed-off-by: Alex Bennée Message-Id: <20210623125458.450462-4-ma.mandourr@gmail.com> Message-Id: <20210709143005.1554-39-alex.bennee@linaro.org> --- contrib/plugins/cache.c | 203 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 190 insertions(+), 13 deletions(-) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index b550ef31b0..bf0d2f6097 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -29,6 +29,14 @@ static uint64_t dmisses; static uint64_t imem_accesses; static uint64_t imisses; +enum EvictionPolicy { + LRU, + FIFO, + RAND, +}; + +enum EvictionPolicy policy; + /* * A CacheSet is a set of cache blocks. A memory block that maps to a set can be * put in any of the blocks inside the set. The number of block per set is @@ -48,6 +56,8 @@ static uint64_t imisses; * The set number is used to identify the set in which the block may exist. * The tag is compared against all the tags of a set to search for a match. If a * match is found, then the access is a hit. + * + * The CacheSet also contains bookkeaping information about eviction details. */ typedef struct { @@ -57,6 +67,9 @@ typedef struct { typedef struct { CacheBlock *blocks; + uint64_t *lru_priorities; + uint64_t lru_gen_counter; + GQueue *fifo_queue; } CacheSet; typedef struct { @@ -77,6 +90,12 @@ typedef struct { uint64_t imisses; } InsnData; +void (*update_hit)(Cache *cache, int set, int blk); +void (*update_miss)(Cache *cache, int set, int blk); + +void (*metadata_init)(Cache *cache); +void (*metadata_destroy)(Cache *cache); + Cache *dcache, *icache; static int pow_of_two(int num) @@ -89,6 +108,103 @@ static int pow_of_two(int num) return ret; } +/* + * LRU evection policy: For each set, a generation counter is maintained + * alongside a priority array. + * + * On each set access, the generation counter is incremented. + * + * On a cache hit: The hit-block is assigned the current generation counter, + * indicating that it is the most recently used block. + * + * On a cache miss: The block with the least priority is searched and replaced + * with the newly-cached block, of which the priority is set to the current + * generation number. + */ + +static void lru_priorities_init(Cache *cache) +{ + int i; + + for (i = 0; i < cache->num_sets; i++) { + cache->sets[i].lru_priorities = g_new0(uint64_t, cache->assoc); + cache->sets[i].lru_gen_counter = 0; + } +} + +static void lru_update_blk(Cache *cache, int set_idx, int blk_idx) +{ + CacheSet *set = &cache->sets[set_idx]; + set->lru_priorities[blk_idx] = cache->sets[set_idx].lru_gen_counter; + set->lru_gen_counter++; +} + +static int lru_get_lru_block(Cache *cache, int set_idx) +{ + int i, min_idx, min_priority; + + min_priority = cache->sets[set_idx].lru_priorities[0]; + min_idx = 0; + + for (i = 1; i < cache->assoc; i++) { + if (cache->sets[set_idx].lru_priorities[i] < min_priority) { + min_priority = cache->sets[set_idx].lru_priorities[i]; + min_idx = i; + } + } + return min_idx; +} + +static void lru_priorities_destroy(Cache *cache) +{ + int i; + + for (i = 0; i < cache->num_sets; i++) { + g_free(cache->sets[i].lru_priorities); + } +} + +/* + * FIFO eviction policy: a FIFO queue is maintained for each CacheSet that + * stores accesses to the cache. + * + * On a compulsory miss: The block index is enqueued to the fifo_queue to + * indicate that it's the latest cached block. + * + * On a conflict miss: The first-in block is removed from the cache and the new + * block is put in its place and enqueued to the FIFO queue. + */ + +static void fifo_init(Cache *cache) +{ + int i; + + for (i = 0; i < cache->num_sets; i++) { + cache->sets[i].fifo_queue = g_queue_new(); + } +} + +static int fifo_get_first_block(Cache *cache, int set) +{ + GQueue *q = cache->sets[set].fifo_queue; + return GPOINTER_TO_INT(g_queue_pop_tail(q)); +} + +static void fifo_update_on_miss(Cache *cache, int set, int blk_idx) +{ + GQueue *q = cache->sets[set].fifo_queue; + g_queue_push_head(q, GINT_TO_POINTER(blk_idx)); +} + +static void fifo_destroy(Cache *cache) +{ + int i; + + for (i = 0; i < cache->assoc; i++) { + g_queue_free(cache->sets[i].fifo_queue); + } +} + static inline uint64_t extract_tag(Cache *cache, uint64_t addr) { return addr & cache->tag_mask; @@ -139,6 +255,11 @@ static Cache *cache_init(int blksize, int assoc, int cachesize) blk_mask = blksize - 1; cache->set_mask = ((cache->num_sets - 1) << cache->blksize_shift); cache->tag_mask = ~(cache->set_mask | blk_mask); + + if (metadata_init) { + metadata_init(cache); + } + return cache; } @@ -155,12 +276,21 @@ static int get_invalid_block(Cache *cache, uint64_t set) return -1; } -static int get_replaced_block(Cache *cache) +static int get_replaced_block(Cache *cache, int set) { - return g_rand_int_range(rng, 0, cache->assoc); + switch (policy) { + case RAND: + return g_rand_int_range(rng, 0, cache->assoc); + case LRU: + return lru_get_lru_block(cache, set); + case FIFO: + return fifo_get_first_block(cache, set); + default: + g_assert_not_reached(); + } } -static bool in_cache(Cache *cache, uint64_t addr) +static int in_cache(Cache *cache, uint64_t addr) { int i; uint64_t tag, set; @@ -171,11 +301,11 @@ static bool in_cache(Cache *cache, uint64_t addr) for (i = 0; i < cache->assoc; i++) { if (cache->sets[set].blocks[i].tag == tag && cache->sets[set].blocks[i].valid) { - return true; + return i; } } - return false; + return -1; } /** @@ -188,20 +318,28 @@ static bool in_cache(Cache *cache, uint64_t addr) */ static bool access_cache(Cache *cache, uint64_t addr) { + int hit_blk, replaced_blk; uint64_t tag, set; - int replaced_blk; - - if (in_cache(cache, addr)) { - return true; - } tag = extract_tag(cache, addr); set = extract_set(cache, addr); + hit_blk = in_cache(cache, addr); + if (hit_blk != -1) { + if (update_hit) { + update_hit(cache, set, hit_blk); + } + return true; + } + replaced_blk = get_invalid_block(cache, set); if (replaced_blk == -1) { - replaced_blk = get_replaced_block(cache); + replaced_blk = get_replaced_block(cache, set); + } + + if (update_miss) { + update_miss(cache, set, replaced_blk); } cache->sets[set].blocks[replaced_blk].tag = tag; @@ -308,6 +446,10 @@ static void cache_free(Cache *cache) g_free(cache->sets[i].blocks); } + if (metadata_destroy) { + metadata_destroy(cache); + } + g_free(cache->sets); g_free(cache); } @@ -395,6 +537,28 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) g_hash_table_destroy(miss_ht); } +static void policy_init() +{ + switch (policy) { + case LRU: + update_hit = lru_update_blk; + update_miss = lru_update_blk; + metadata_init = lru_priorities_init; + metadata_destroy = lru_priorities_destroy; + break; + case FIFO: + update_miss = fifo_update_on_miss; + metadata_init = fifo_init; + metadata_destroy = fifo_destroy; + break; + case RAND: + rng = g_rand_new(); + break; + default: + g_assert_not_reached(); + } +} + QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, int argc, char **argv) @@ -414,6 +578,7 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, iblksize = 64; icachesize = iblksize * iassoc * 32; + policy = LRU; for (i = 0; i < argc; i++) { char *opt = argv[i]; @@ -431,12 +596,26 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, dcachesize = g_ascii_strtoll(opt + 11, NULL, 10); } else if (g_str_has_prefix(opt, "limit=")) { limit = g_ascii_strtoll(opt + 6, NULL, 10); + } else if (g_str_has_prefix(opt, "evict=")) { + gchar *p = opt + 6; + if (g_strcmp0(p, "rand") == 0) { + policy = RAND; + } else if (g_strcmp0(p, "lru") == 0) { + policy = LRU; + } else if (g_strcmp0(p, "fifo") == 0) { + policy = FIFO; + } else { + fprintf(stderr, "invalid eviction policy: %s\n", opt); + return -1; + } } else { fprintf(stderr, "option parsing failed: %s\n", opt); return -1; } } + policy_init(); + dcache = cache_init(dblksize, dassoc, dcachesize); if (!dcache) { const char *err = cache_config_error(dblksize, dassoc, dcachesize); @@ -453,8 +632,6 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, return -1; } - rng = g_rand_new(); - qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); From 4c125f3b7591758ebd96c3ac3ff469480b7aaea2 Mon Sep 17 00:00:00 2001 From: Mahmoud Mandour Date: Fri, 9 Jul 2021 15:30:04 +0100 Subject: [PATCH 149/531] docs/devel: Added cache plugin to the plugins docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mahmoud Mandour Signed-off-by: Alex Bennée Message-Id: <20210628053808.17422-1-ma.mandourr@gmail.com> Message-Id: <20210709143005.1554-40-alex.bennee@linaro.org> --- docs/devel/tcg-plugins.rst | 59 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst index 179867e9c1..7e54f12837 100644 --- a/docs/devel/tcg-plugins.rst +++ b/docs/devel/tcg-plugins.rst @@ -344,3 +344,62 @@ which will output an execution trace following this structure:: 0, 0xd32, 0xf9893014, "adds r0, #0x14" 0, 0xd34, 0xf9c8f000, "bl #0x10c8" 0, 0x10c8, 0xfff96c43, "ldr r3, [r0, #0x44]", load, 0x200000e4, RAM + +- contrib/plugins/cache + +Cache modelling plugin that measures the performance of a given cache +configuration when a given working set is run:: + + qemu-x86_64 -plugin ./contrib/plugins/libcache.so \ + -d plugin -D cache.log ./tests/tcg/x86_64-linux-user/float_convs + +will report the following:: + + Data accesses: 996479, Misses: 507 + Miss rate: 0.050879% + + Instruction accesses: 2641737, Misses: 18617 + Miss rate: 0.704726% + + address, data misses, instruction + 0x424f1e (_int_malloc), 109, movq %rax, 8(%rcx) + 0x41f395 (_IO_default_xsputn), 49, movb %dl, (%rdi, %rax) + 0x42584d (ptmalloc_init.part.0), 33, movaps %xmm0, (%rax) + 0x454d48 (__tunables_init), 20, cmpb $0, (%r8) + ... + + address, fetch misses, instruction + 0x4160a0 (__vfprintf_internal), 744, movl $1, %ebx + 0x41f0a0 (_IO_setb), 744, endbr64 + 0x415882 (__vfprintf_internal), 744, movq %r12, %rdi + 0x4268a0 (__malloc), 696, andq $0xfffffffffffffff0, %rax + ... + +The plugin has a number of arguments, all of them are optional: + + * arg="limit=N" + + Print top N icache and dcache thrashing instructions along with their + address, number of misses, and its disassembly. (default: 32) + + * arg="icachesize=N" + * arg="iblksize=B" + * arg="iassoc=A" + + Instruction cache configuration arguments. They specify the cache size, block + size, and associativity of the instruction cache, respectively. + (default: N = 16384, B = 64, A = 8) + + * arg="dcachesize=N" + * arg="dblksize=B" + * arg="dassoc=A" + + Data cache configuration arguments. They specify the cache size, block size, + and associativity of the data cache, respectively. + (default: N = 16384, B = 64, A = 8) + + * arg="evict=POLICY" + + Sets the eviction policy to POLICY. Available policies are: :code:`lru`, + :code:`fifo`, and :code:`rand`. The plugin will use the specified policy for + both instruction and data caches. (default: POLICY = :code:`lru`) From a6b95a9733a94f38b289430bf46987809f53ab16 Mon Sep 17 00:00:00 2001 From: Mahmoud Mandour Date: Fri, 9 Jul 2021 15:30:05 +0100 Subject: [PATCH 150/531] MAINTAINERS: Added myself as a reviewer for TCG Plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mahmoud Mandour Signed-off-by: Alex Bennée Message-Id: <20210623125458.450462-6-ma.mandourr@gmail.com> Message-Id: <20210709143005.1554-41-alex.bennee@linaro.org> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 83b55030ad..c4439a9488 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3018,6 +3018,7 @@ F: include/tcg/ TCG Plugins M: Alex Bennée R: Alexandre Iooss +R: Mahmoud Mandour S: Maintained F: docs/devel/tcg-plugins.rst F: plugins/ From a5dba9bc0552785b91315d457b9397ebd833224b Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Mon, 12 Jul 2021 10:31:35 +0200 Subject: [PATCH 151/531] vfio: Fix CID 1458134 in vfio_register_ram_discard_listener() CID 1458134: Integer handling issues (BAD_SHIFT) In expression "1 << ctz64(container->pgsizes)", left shifting by more than 31 bits has undefined behavior. The shift amount, "ctz64(container->pgsizes)", is 64. Commit 5e3b981c330c ("vfio: Support for RamDiscardManager in the !vIOMMU case") added an assertion that our granularity is at least as big as the page size. Although unlikely, we could have a page size that does not fit into 32 bit. In that case, we'd try shifting by more than 31 bit. Let's use 1ULL instead and make sure we're not shifting by more than 63 bit by asserting that any bit in container->pgsizes is set. Fixes: CID 1458134 Cc: Alex Williamson Cc: Eduardo Habkost Cc: "Michael S. Tsirkin" Cc: Paolo Bonzini Cc: Dr. David Alan Gilbert Cc: Igor Mammedov Cc: Pankaj Gupta Cc: Peter Xu Cc: Auger Eric Cc: Wei Yang Cc: teawater Cc: Marek Kedzierski Signed-off-by: David Hildenbrand Reviewed-by: Igor Mammedov Reviewed-by: Pankaj Gupta Link: https://lore.kernel.org/r/20210712083135.15755-1-david@redhat.com Signed-off-by: Alex Williamson --- hw/vfio/common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 3f0d111360..8728d4d5c2 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -783,7 +783,8 @@ static void vfio_register_ram_discard_listener(VFIOContainer *container, section->mr); g_assert(vrdl->granularity && is_power_of_2(vrdl->granularity)); - g_assert(vrdl->granularity >= 1 << ctz64(container->pgsizes)); + g_assert(container->pgsizes && + vrdl->granularity >= 1ULL << ctz64(container->pgsizes)); ram_discard_listener_init(&vrdl->listener, vfio_ram_discard_notify_populate, From 936555bc4f9efce1a9d35466845169c2c7566794 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 13 Jul 2021 09:48:31 +0800 Subject: [PATCH 152/531] vfio/pci: Change to use vfio_pci_is() Make use of vfio_pci_is() helper function. Signed-off-by: Cai Huoqing Link: https://lore.kernel.org/r/20210713014831.742-1-caihuoqing@baidu.com [aw: commit log wording] Signed-off-by: Alex Williamson --- hw/vfio/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index ab4077aad2..971273fd45 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -3058,14 +3058,14 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) } } - if (vdev->vendor_id == PCI_VENDOR_ID_NVIDIA) { + if (vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID)) { ret = vfio_pci_nvidia_v100_ram_init(vdev, errp); if (ret && ret != -ENODEV) { error_report("Failed to setup NVIDIA V100 GPU RAM"); } } - if (vdev->vendor_id == PCI_VENDOR_ID_IBM) { + if (vfio_pci_is(vdev, PCI_VENDOR_ID_IBM, PCI_ANY_ID)) { ret = vfio_pci_nvlink2_init(vdev, errp); if (ret && ret != -ENODEV) { error_report("Failed to setup NVlink2 bridge"); From 1bd9f1b14d1e9c1498bb03faf4e2bb945cf6542d Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 13 Jul 2021 17:37:43 +0800 Subject: [PATCH 153/531] vfio/pci: Add pba_offset PCI quirk for BAIDU KUNLUN AI processor Fix pba_offset initialization value for BAIDU KUNLUN Virtual Function device. The KUNLUN hardware returns an incorrect value for the VF PBA offset, and add a quirk to instead return a hardcoded value of 0xb400. Signed-off-by: Cai Huoqing Link: https://lore.kernel.org/r/20210713093743.942-1-caihuoqing@baidu.com [aw: comment & whitespace tuning] Signed-off-by: Alex Williamson --- hw/vfio/pci.c | 8 ++++++++ include/hw/pci/pci_ids.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 971273fd45..e1ea1d8a23 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -1499,6 +1499,14 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp) if (vdev->vendor_id == PCI_VENDOR_ID_CHELSIO && (vdev->device_id & 0xff00) == 0x5800) { msix->pba_offset = 0x1000; + /* + * BAIDU KUNLUN Virtual Function devices for KUNLUN AI processor + * return an incorrect value of 0x460000 for the VF PBA offset while + * the BAR itself is only 0x10000. The correct value is 0xb400. + */ + } else if (vfio_pci_is(vdev, PCI_VENDOR_ID_BAIDU, + PCI_DEVICE_ID_KUNLUN_VF)) { + msix->pba_offset = 0xb400; } else if (vdev->msix_relo == OFF_AUTOPCIBAR_OFF) { error_setg(errp, "hardware reports invalid configuration, " "MSIX PBA outside of specified BAR"); diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index 5c14681b82..11abe22d46 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -227,6 +227,9 @@ #define PCI_VENDOR_ID_FREESCALE 0x1957 #define PCI_DEVICE_ID_MPC8533E 0x0030 +#define PCI_VENDOR_ID_BAIDU 0x1d22 +#define PCI_DEVICE_ID_KUNLUN_VF 0x3685 + #define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_DEVICE_ID_INTEL_82378 0x0484 #define PCI_DEVICE_ID_INTEL_82441 0x1237 From ac0595cf6b36cc39f2a926bd519416c32cb5667d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 14 Jul 2021 11:56:02 +0200 Subject: [PATCH 154/531] gitlab-ci: Extract EDK2 job rules to reusable section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All jobs depending on 'docker-edk2' job must use at most all the rules that triggers it. The simplest way to ensure that is to always use the same rules. Extract all the rules to a reusable section, and include this section (with the 'extends' keyword) in both 'docker-edk2' and 'build-edk2' jobs. The problem was introduced in commit 71920809cea ("gitlab-ci.yml: Add jobs to build EDK2 firmware binaries"), but was revealed in commit 1925468ddbf ("docker: EDK2 build job depends on EDK2 container") and eventually failed on CI: https://gitlab.com/qemu-project/qemu/-/pipelines/335995843 Reported-by: Daniel P. Berrangé Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Willian Rampazzo Message-Id: <20210714101003.3113726-1-philmd@redhat.com> --- .gitlab-ci.d/edk2.yml | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.d/edk2.yml b/.gitlab-ci.d/edk2.yml index ba7280605c..aae2f7ad88 100644 --- a/.gitlab-ci.d/edk2.yml +++ b/.gitlab-ci.d/edk2.yml @@ -1,10 +1,22 @@ -docker-edk2: - stage: containers - rules: # Only run this job when the Dockerfile is modified +# All jobs needing docker-edk2 must use the same rules it uses. +.edk2_job_rules: + rules: # Only run this job when ... - changes: + # this file is modified - .gitlab-ci.d/edk2.yml + # or the Dockerfile is modified - .gitlab-ci.d/edk2/Dockerfile + # or roms/edk2/ is modified (submodule updated) + - roms/edk2/* when: always + - if: '$CI_COMMIT_REF_NAME =~ /^edk2/' # or the branch/tag starts with 'edk2' + when: always + - if: '$CI_COMMIT_MESSAGE =~ /edk2/i' # or last commit description contains 'EDK2' + when: always + +docker-edk2: + extends: .edk2_job_rules + stage: containers image: docker:19.03.1 services: - docker:19.03.1-dind @@ -24,16 +36,9 @@ docker-edk2: - docker push $IMAGE_TAG build-edk2: + extends: .edk2_job_rules stage: build needs: ['docker-edk2'] - rules: # Only run this job when ... - - changes: # ... roms/edk2/ is modified (submodule updated) - - roms/edk2/* - when: always - - if: '$CI_COMMIT_REF_NAME =~ /^edk2/' # or the branch/tag starts with 'edk2' - when: always - - if: '$CI_COMMIT_MESSAGE =~ /edk2/i' # or last commit description contains 'EDK2' - when: always artifacts: paths: # 'artifacts.zip' will contains the following files: - pc-bios/edk2*bz2 From 35ebc321b476c0b9e573bc6fb412d773fb4a36d5 Mon Sep 17 00:00:00 2001 From: Dov Murik Date: Thu, 1 Jul 2021 05:27:48 +0000 Subject: [PATCH 155/531] hw/i386/pc: pc_system_ovmf_table_find: Assert that flash was parsed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add assertion in pc_system_ovmf_table_find that verifies that the flash was indeed previously parsed (looking for the OVMF table) by pc_system_parse_ovmf_flash. Now pc_system_ovmf_table_find distinguishes between "no one called pc_system_parse_ovmf_flash" (which will abort due to assertion failure) and "the flash was parsed but no OVMF table was found, or it is invalid" (which will return false). Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Dov Murik Reviewed-by: Tom Lendacky Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210701052749.934744-2-dovmurik@linux.ibm.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/i386/pc_sysfw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index 6ce37a2b05..e353f2a4e9 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -126,6 +126,7 @@ void pc_system_flash_cleanup_unused(PCMachineState *pcms) #define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d" +static bool ovmf_flash_parsed; static uint8_t *ovmf_table; static int ovmf_table_len; @@ -136,10 +137,12 @@ static void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size) int tot_len; /* should only be called once */ - if (ovmf_table) { + if (ovmf_flash_parsed) { return; } + ovmf_flash_parsed = true; + if (flash_size < TARGET_PAGE_SIZE) { return; } @@ -183,6 +186,8 @@ bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, int tot_len = ovmf_table_len; QemuUUID entry_guid; + assert(ovmf_flash_parsed); + if (qemu_uuid_parse(entry, &entry_guid) < 0) { return false; } From 2165542c8d21c01d1f470560ab7d86b3fee8eac4 Mon Sep 17 00:00:00 2001 From: Dov Murik Date: Thu, 1 Jul 2021 05:27:49 +0000 Subject: [PATCH 156/531] hw/i386/pc: Document pc_system_ovmf_table_find MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Dov Murik Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210701052749.934744-3-dovmurik@linux.ibm.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/i386/pc_sysfw.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index e353f2a4e9..6ddce92a86 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -179,6 +179,17 @@ static void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size) ovmf_table += tot_len; } +/** + * pc_system_ovmf_table_find - Find the data associated with an entry in OVMF's + * reset vector GUIDed table. + * + * @entry: GUID string of the entry to lookup + * @data: Filled with a pointer to the entry's value (if not NULL) + * @data_len: Filled with the length of the entry's value (if not NULL). Pass + * NULL here if the length of data is known. + * + * Return: true if the entry was found in the OVMF table; false otherwise. + */ bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, int *data_len) { From b5b318608e20464c7136eb5a5f5f3307e9f90510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 21 May 2021 15:34:07 +0200 Subject: [PATCH 157/531] hw/i386: Introduce X86_FW_OVMF Kconfig symbol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce the X86_FW_OVMF Kconfig symbol for OVMF-specific code. Move the OVMF-specific code from pc_sysfw.c to pc_sysfw_ovmf.c, adding a pair of stubs. Update MAINTAINERS to reach OVMF maintainers when these new files are modified. This fixes when building the microvm machine standalone: /usr/bin/ld: libqemu-i386-softmmu.fa.p/target_i386_monitor.c.o: in function `qmp_sev_inject_launch_secret': target/i386/monitor.c:749: undefined reference to `pc_system_ovmf_table_find' Fixes: f522cef9b35 ("sev: update sev-inject-launch-secret to make gpa optional") Signed-off-by: Philippe Mathieu-Daudé Acked-by: Michael S. Tsirkin Message-Id: <20210616204328.2611406-22-philmd@redhat.com> --- MAINTAINERS | 1 + hw/i386/Kconfig | 4 + hw/i386/meson.build | 2 + hw/i386/pc_sysfw.c | 123 --------------------------- hw/i386/pc_sysfw_ovmf-stubs.c | 26 ++++++ hw/i386/pc_sysfw_ovmf.c | 151 ++++++++++++++++++++++++++++++++++ include/hw/i386/pc.h | 1 + 7 files changed, 185 insertions(+), 123 deletions(-) create mode 100644 hw/i386/pc_sysfw_ovmf-stubs.c create mode 100644 hw/i386/pc_sysfw_ovmf.c diff --git a/MAINTAINERS b/MAINTAINERS index 148153d74f..2250cd1b36 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2945,6 +2945,7 @@ EDK2 Firmware M: Laszlo Ersek M: Philippe Mathieu-Daudé S: Supported +F: hw/i386/*ovmf* F: pc-bios/descriptors/??-edk2-*.json F: pc-bios/edk2-* F: roms/Makefile.edk2 diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index aacb6f6d96..bad6cf5b4e 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -1,5 +1,9 @@ +config X86_FW_OVMF + bool + config SEV bool + select X86_FW_OVMF depends on KVM config PC diff --git a/hw/i386/meson.build b/hw/i386/meson.build index e5d109f5c6..80dad29f2b 100644 --- a/hw/i386/meson.build +++ b/hw/i386/meson.build @@ -24,6 +24,8 @@ i386_ss.add(when: 'CONFIG_PC', if_true: files( 'pc_sysfw.c', 'acpi-build.c', 'port92.c')) +i386_ss.add(when: 'CONFIG_X86_FW_OVMF', if_true: files('pc_sysfw_ovmf.c'), + if_false: files('pc_sysfw_ovmf-stubs.c')) subdir('kvm') subdir('xen') diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index 6ddce92a86..68d6b1f783 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -124,129 +124,6 @@ void pc_system_flash_cleanup_unused(PCMachineState *pcms) } } -#define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d" - -static bool ovmf_flash_parsed; -static uint8_t *ovmf_table; -static int ovmf_table_len; - -static void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size) -{ - uint8_t *ptr; - QemuUUID guid; - int tot_len; - - /* should only be called once */ - if (ovmf_flash_parsed) { - return; - } - - ovmf_flash_parsed = true; - - if (flash_size < TARGET_PAGE_SIZE) { - return; - } - - /* - * if this is OVMF there will be a table footer - * guid 48 bytes before the end of the flash file. If it's - * not found, silently abort the flash parsing. - */ - qemu_uuid_parse(OVMF_TABLE_FOOTER_GUID, &guid); - guid = qemu_uuid_bswap(guid); /* guids are LE */ - ptr = flash_ptr + flash_size - 48; - if (!qemu_uuid_is_equal((QemuUUID *)ptr, &guid)) { - return; - } - - /* if found, just before is two byte table length */ - ptr -= sizeof(uint16_t); - tot_len = le16_to_cpu(*(uint16_t *)ptr) - sizeof(guid) - sizeof(uint16_t); - - if (tot_len <= 0) { - return; - } - - ovmf_table = g_malloc(tot_len); - ovmf_table_len = tot_len; - - /* - * ptr is the foot of the table, so copy it all to the newly - * allocated ovmf_table and then set the ovmf_table pointer - * to the table foot - */ - memcpy(ovmf_table, ptr - tot_len, tot_len); - ovmf_table += tot_len; -} - -/** - * pc_system_ovmf_table_find - Find the data associated with an entry in OVMF's - * reset vector GUIDed table. - * - * @entry: GUID string of the entry to lookup - * @data: Filled with a pointer to the entry's value (if not NULL) - * @data_len: Filled with the length of the entry's value (if not NULL). Pass - * NULL here if the length of data is known. - * - * Return: true if the entry was found in the OVMF table; false otherwise. - */ -bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, - int *data_len) -{ - uint8_t *ptr = ovmf_table; - int tot_len = ovmf_table_len; - QemuUUID entry_guid; - - assert(ovmf_flash_parsed); - - if (qemu_uuid_parse(entry, &entry_guid) < 0) { - return false; - } - - if (!ptr) { - return false; - } - - entry_guid = qemu_uuid_bswap(entry_guid); /* guids are LE */ - while (tot_len >= sizeof(QemuUUID) + sizeof(uint16_t)) { - int len; - QemuUUID *guid; - - /* - * The data structure is - * arbitrary length data - * 2 byte length of entire entry - * 16 byte guid - */ - guid = (QemuUUID *)(ptr - sizeof(QemuUUID)); - len = le16_to_cpu(*(uint16_t *)(ptr - sizeof(QemuUUID) - - sizeof(uint16_t))); - - /* - * just in case the table is corrupt, wouldn't want to spin in - * the zero case - */ - if (len < sizeof(QemuUUID) + sizeof(uint16_t)) { - return false; - } else if (len > tot_len) { - return false; - } - - ptr -= len; - tot_len -= len; - if (qemu_uuid_is_equal(guid, &entry_guid)) { - if (data) { - *data = ptr; - } - if (data_len) { - *data_len = len - sizeof(QemuUUID) - sizeof(uint16_t); - } - return true; - } - } - return false; -} - /* * Map the pcms->flash[] from 4GiB downward, and realize. * Map them in descending order, i.e. pcms->flash[0] at the top, diff --git a/hw/i386/pc_sysfw_ovmf-stubs.c b/hw/i386/pc_sysfw_ovmf-stubs.c new file mode 100644 index 0000000000..aabe78b271 --- /dev/null +++ b/hw/i386/pc_sysfw_ovmf-stubs.c @@ -0,0 +1,26 @@ +/* + * QEMU PC System Firmware (OVMF stubs) + * + * Copyright (c) 2021 Red Hat, Inc. + * + * Author: + * Philippe Mathieu-Daudé + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/i386/pc.h" + +bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, int *data_len) +{ + g_assert_not_reached(); +} + +void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size) +{ + g_assert_not_reached(); +} diff --git a/hw/i386/pc_sysfw_ovmf.c b/hw/i386/pc_sysfw_ovmf.c new file mode 100644 index 0000000000..f4dd92c588 --- /dev/null +++ b/hw/i386/pc_sysfw_ovmf.c @@ -0,0 +1,151 @@ +/* + * QEMU PC System Firmware (OVMF specific) + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2011-2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/i386/pc.h" +#include "cpu.h" + +#define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d" + +static bool ovmf_flash_parsed; +static uint8_t *ovmf_table; +static int ovmf_table_len; + +void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size) +{ + uint8_t *ptr; + QemuUUID guid; + int tot_len; + + /* should only be called once */ + if (ovmf_flash_parsed) { + return; + } + + ovmf_flash_parsed = true; + + if (flash_size < TARGET_PAGE_SIZE) { + return; + } + + /* + * if this is OVMF there will be a table footer + * guid 48 bytes before the end of the flash file. If it's + * not found, silently abort the flash parsing. + */ + qemu_uuid_parse(OVMF_TABLE_FOOTER_GUID, &guid); + guid = qemu_uuid_bswap(guid); /* guids are LE */ + ptr = flash_ptr + flash_size - 48; + if (!qemu_uuid_is_equal((QemuUUID *)ptr, &guid)) { + return; + } + + /* if found, just before is two byte table length */ + ptr -= sizeof(uint16_t); + tot_len = le16_to_cpu(*(uint16_t *)ptr) - sizeof(guid) - sizeof(uint16_t); + + if (tot_len <= 0) { + return; + } + + ovmf_table = g_malloc(tot_len); + ovmf_table_len = tot_len; + + /* + * ptr is the foot of the table, so copy it all to the newly + * allocated ovmf_table and then set the ovmf_table pointer + * to the table foot + */ + memcpy(ovmf_table, ptr - tot_len, tot_len); + ovmf_table += tot_len; +} + +/** + * pc_system_ovmf_table_find - Find the data associated with an entry in OVMF's + * reset vector GUIDed table. + * + * @entry: GUID string of the entry to lookup + * @data: Filled with a pointer to the entry's value (if not NULL) + * @data_len: Filled with the length of the entry's value (if not NULL). Pass + * NULL here if the length of data is known. + * + * Return: true if the entry was found in the OVMF table; false otherwise. + */ +bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, + int *data_len) +{ + uint8_t *ptr = ovmf_table; + int tot_len = ovmf_table_len; + QemuUUID entry_guid; + + assert(ovmf_flash_parsed); + + if (qemu_uuid_parse(entry, &entry_guid) < 0) { + return false; + } + + if (!ptr) { + return false; + } + + entry_guid = qemu_uuid_bswap(entry_guid); /* guids are LE */ + while (tot_len >= sizeof(QemuUUID) + sizeof(uint16_t)) { + int len; + QemuUUID *guid; + + /* + * The data structure is + * arbitrary length data + * 2 byte length of entire entry + * 16 byte guid + */ + guid = (QemuUUID *)(ptr - sizeof(QemuUUID)); + len = le16_to_cpu(*(uint16_t *)(ptr - sizeof(QemuUUID) - + sizeof(uint16_t))); + + /* + * just in case the table is corrupt, wouldn't want to spin in + * the zero case + */ + if (len < sizeof(QemuUUID) + sizeof(uint16_t)) { + return false; + } else if (len > tot_len) { + return false; + } + + ptr -= len; + tot_len -= len; + if (qemu_uuid_is_equal(guid, &entry_guid)) { + if (data) { + *data = ptr; + } + if (data_len) { + *data_len = len - sizeof(QemuUUID) - sizeof(uint16_t); + } + return true; + } + } + return false; +} diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 87294f2632..0775f945d7 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -188,6 +188,7 @@ void pc_system_flash_cleanup_unused(PCMachineState *pcms); void pc_system_firmware_init(PCMachineState *pcms, MemoryRegion *rom_memory); bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, int *data_len); +void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size); /* acpi-build.c */ From 2669350db2c3df33f4e68c518e9f31f91502a83d Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Thu, 8 Jul 2021 09:14:09 +0200 Subject: [PATCH 158/531] MAINTAINERS: remove Laszlo Ersek's entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've relinquished my edk2 roles with the following commit message [1] [2] [3]: > Maintainers.txt: remove Laszlo Ersek's entries > > I'm relinquishing all my roles listed in "Maintainers.txt", for personal > reasons. > > My email address remains functional. > > To my understanding, my employer is working to assign others engineers > to the edk2 project (at their discretion). [1] https://edk2.groups.io/g/devel/message/77585 [2] https://listman.redhat.com/archives/edk2-devel-archive/2021-July/msg00202.html [3] http://mid.mail-archive.com/20210708070916.8937-1-lersek@redhat.com Accordingly, remove my entries from QEMU's MAINTAINERS file as well, which all relate to guest firmware. Cc: Daniel P. Berrange Cc: Gerd Hoffmann Cc: Kashyap Chamarthy Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Signed-off-by: Laszlo Ersek Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210708071409.9671-1-lersek@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 3 --- 1 file changed, 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 2250cd1b36..4181ee75ba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2202,7 +2202,6 @@ F: include/hw/southbridge/piix.h Firmware configuration (fw_cfg) M: Philippe Mathieu-Daudé -R: Laszlo Ersek R: Gerd Hoffmann S: Supported F: docs/specs/fw_cfg.txt @@ -2934,7 +2933,6 @@ F: include/hw/i2c/smbus_slave.h F: include/hw/i2c/smbus_eeprom.h Firmware schema specifications -M: Laszlo Ersek M: Philippe Mathieu-Daudé R: Daniel P. Berrange R: Kashyap Chamarthy @@ -2942,7 +2940,6 @@ S: Maintained F: docs/interop/firmware.json EDK2 Firmware -M: Laszlo Ersek M: Philippe Mathieu-Daudé S: Supported F: hw/i386/*ovmf* From b4cb178efbafaff22558c9cad7d2e1b8f351bdc3 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 27 Jun 2021 19:57:16 +0800 Subject: [PATCH 159/531] target/riscv: pmp: Fix some typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit %s/CSP/CSR %s/thie/the Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20210627115716.3552-1-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- target/riscv/pmp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 82ed020b10..54abf42583 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -456,7 +456,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, } /* - * Handle a write to a pmpcfg CSP + * Handle a write to a pmpcfg CSR */ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index, target_ulong val) @@ -483,7 +483,7 @@ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index, /* - * Handle a read from a pmpcfg CSP + * Handle a read from a pmpcfg CSR */ target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index) { @@ -502,7 +502,7 @@ target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index) /* - * Handle a write to a pmpaddr CSP + * Handle a write to a pmpaddr CSR */ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, target_ulong val) @@ -540,7 +540,7 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, /* - * Handle a read from a pmpaddr CSP + * Handle a read from a pmpaddr CSR */ target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index) { @@ -593,7 +593,7 @@ target_ulong mseccfg_csr_read(CPURISCVState *env) /* * Calculate the TLB size if the start address or the end address of - * PMP entry is presented in thie TLB page. + * PMP entry is presented in the TLB page. */ static target_ulong pmp_get_tlb_size(CPURISCVState *env, int pmp_index, target_ulong tlb_sa, target_ulong tlb_ea) From 232a2c8c85541e3b491f61b90f151f1edcdb3944 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 27 Jun 2021 20:06:04 +0800 Subject: [PATCH 160/531] target/riscv: csr: Remove redundant check in fp csr read/write routines The following check: if (!env->debugger && !riscv_cpu_fp_enabled(env)) { return -RISCV_EXCP_ILLEGAL_INST; } is redundant in fflags/frm/fcsr read/write routines, as the check was already done in fs(). Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20210627120604.11116-1-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- target/riscv/csr.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index fe5628fea6..62b968326c 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -215,11 +215,6 @@ static RISCVException epmp(CPURISCVState *env, int csrno) static RISCVException read_fflags(CPURISCVState *env, int csrno, target_ulong *val) { -#if !defined(CONFIG_USER_ONLY) - if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return RISCV_EXCP_ILLEGAL_INST; - } -#endif *val = riscv_cpu_get_fflags(env); return RISCV_EXCP_NONE; } @@ -228,9 +223,6 @@ static RISCVException write_fflags(CPURISCVState *env, int csrno, target_ulong val) { #if !defined(CONFIG_USER_ONLY) - if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return RISCV_EXCP_ILLEGAL_INST; - } env->mstatus |= MSTATUS_FS; #endif riscv_cpu_set_fflags(env, val & (FSR_AEXC >> FSR_AEXC_SHIFT)); @@ -240,11 +232,6 @@ static RISCVException write_fflags(CPURISCVState *env, int csrno, static RISCVException read_frm(CPURISCVState *env, int csrno, target_ulong *val) { -#if !defined(CONFIG_USER_ONLY) - if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return RISCV_EXCP_ILLEGAL_INST; - } -#endif *val = env->frm; return RISCV_EXCP_NONE; } @@ -253,9 +240,6 @@ static RISCVException write_frm(CPURISCVState *env, int csrno, target_ulong val) { #if !defined(CONFIG_USER_ONLY) - if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return RISCV_EXCP_ILLEGAL_INST; - } env->mstatus |= MSTATUS_FS; #endif env->frm = val & (FSR_RD >> FSR_RD_SHIFT); @@ -265,11 +249,6 @@ static RISCVException write_frm(CPURISCVState *env, int csrno, static RISCVException read_fcsr(CPURISCVState *env, int csrno, target_ulong *val) { -#if !defined(CONFIG_USER_ONLY) - if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return RISCV_EXCP_ILLEGAL_INST; - } -#endif *val = (riscv_cpu_get_fflags(env) << FSR_AEXC_SHIFT) | (env->frm << FSR_RD_SHIFT); if (vs(env, csrno) >= 0) { @@ -283,9 +262,6 @@ static RISCVException write_fcsr(CPURISCVState *env, int csrno, target_ulong val) { #if !defined(CONFIG_USER_ONLY) - if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return RISCV_EXCP_ILLEGAL_INST; - } env->mstatus |= MSTATUS_FS; #endif env->frm = (val & FSR_RD) >> FSR_RD_SHIFT; From d3745751009bc7c56741ea04c4d3ca5619f845f2 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 27 Jun 2021 22:28:15 +0800 Subject: [PATCH 161/531] docs/system: riscv: Fix CLINT name in the sifive_u doc It's Core *Local* Interruptor, not 'Level'. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20210627142816.19789-1-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- docs/system/riscv/sifive_u.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/system/riscv/sifive_u.rst b/docs/system/riscv/sifive_u.rst index 32d0a1b85d..01108b5ecc 100644 --- a/docs/system/riscv/sifive_u.rst +++ b/docs/system/riscv/sifive_u.rst @@ -11,7 +11,7 @@ The ``sifive_u`` machine supports the following devices: * 1 E51 / E31 core * Up to 4 U54 / U34 cores -* Core Level Interruptor (CLINT) +* Core Local Interruptor (CLINT) * Platform-Level Interrupt Controller (PLIC) * Power, Reset, Clock, Interrupt (PRCI) * L2 Loosely Integrated Memory (L2-LIM) From 85198f189e41c9d9ebe340d2feecf7d668499bc4 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 27 Jun 2021 22:28:16 +0800 Subject: [PATCH 162/531] docs/system: riscv: Add documentation for virt machine This adds detailed documentation for RISC-V `virt` machine, including the following information: - Supported devices - Hardware configuration information - Boot options - Running Linux kernel - Running U-Boot Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20210627142816.19789-2-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- docs/system/riscv/virt.rst | 138 +++++++++++++++++++++++++++++++++++ docs/system/target-riscv.rst | 1 + 2 files changed, 139 insertions(+) create mode 100644 docs/system/riscv/virt.rst diff --git a/docs/system/riscv/virt.rst b/docs/system/riscv/virt.rst new file mode 100644 index 0000000000..3709f05797 --- /dev/null +++ b/docs/system/riscv/virt.rst @@ -0,0 +1,138 @@ +'virt' Generic Virtual Platform (``virt``) +========================================== + +The `virt` board is a platform which does not correspond to any real hardware; +it is designed for use in virtual machines. It is the recommended board type +if you simply want to run a guest such as Linux and do not care about +reproducing the idiosyncrasies and limitations of a particular bit of +real-world hardware. + +Supported devices +----------------- + +The ``virt`` machine supports the following devices: + +* Up to 8 generic RV32GC/RV64GC cores, with optional extensions +* Core Local Interruptor (CLINT) +* Platform-Level Interrupt Controller (PLIC) +* CFI parallel NOR flash memory +* 1 NS16550 compatible UART +* 1 Google Goldfish RTC +* 1 SiFive Test device +* 8 virtio-mmio transport devices +* 1 generic PCIe host bridge +* The fw_cfg device that allows a guest to obtain data from QEMU + +Note that the default CPU is a generic RV32GC/RV64GC. Optional extensions +can be enabled via command line parameters, e.g.: ``-cpu rv64,x-h=true`` +enables the hypervisor extension for RV64. + +Hardware configuration information +---------------------------------- + +The ``virt`` machine automatically generates a device tree blob ("dtb") +which it passes to the guest, if there is no ``-dtb`` option. This provides +information about the addresses, interrupt lines and other configuration of +the various devices in the system. Guest software should discover the devices +that are present in the generated DTB. + +If users want to provide their own DTB, they can use the ``-dtb`` option. +These DTBs should have the following requirements: + +* The number of subnodes of the /cpus node should match QEMU's ``-smp`` option +* The /memory reg size should match QEMU’s selected ram_size via ``-m`` +* Should contain a node for the CLINT device with a compatible string + "riscv,clint0" if using with OpenSBI BIOS images + +Boot options +------------ + +The ``virt`` machine can start using the standard -kernel functionality +for loading a Linux kernel, a VxWorks kernel, an S-mode U-Boot bootloader +with the default OpenSBI firmware image as the -bios. It also supports +the recommended RISC-V bootflow: U-Boot SPL (M-mode) loads OpenSBI fw_dynamic +firmware and U-Boot proper (S-mode), using the standard -bios functionality. + +Running Linux kernel +-------------------- + +Linux mainline v5.12 release is tested at the time of writing. To build a +Linux mainline kernel that can be booted by the ``virt`` machine in +64-bit mode, simply configure the kernel using the defconfig configuration: + +.. code-block:: bash + + $ export ARCH=riscv + $ export CROSS_COMPILE=riscv64-linux- + $ make defconfig + $ make + +To boot the newly built Linux kernel in QEMU with the ``virt`` machine: + +.. code-block:: bash + + $ qemu-system-riscv64 -M virt -smp 4 -m 2G \ + -display none -serial stdio \ + -kernel arch/riscv/boot/Image \ + -initrd /path/to/rootfs.cpio \ + -append "root=/dev/ram" + +To build a Linux mainline kernel that can be booted by the ``virt`` machine +in 32-bit mode, use the rv32_defconfig configuration. A patch is required to +fix the 32-bit boot issue for Linux kernel v5.12. + +.. code-block:: bash + + $ export ARCH=riscv + $ export CROSS_COMPILE=riscv64-linux- + $ curl https://patchwork.kernel.org/project/linux-riscv/patch/20210627135117.28641-1-bmeng.cn@gmail.com/mbox/ > riscv.patch + $ git am riscv.patch + $ make rv32_defconfig + $ make + +Replace ``qemu-system-riscv64`` with ``qemu-system-riscv32`` in the command +line above to boot the 32-bit Linux kernel. A rootfs image containing 32-bit +applications shall be used in order for kernel to boot to user space. + +Running U-Boot +-------------- + +U-Boot mainline v2021.04 release is tested at the time of writing. To build an +S-mode U-Boot bootloader that can be booted by the ``virt`` machine, use +the qemu-riscv64_smode_defconfig with similar commands as described above for Linux: + +.. code-block:: bash + + $ export CROSS_COMPILE=riscv64-linux- + $ make qemu-riscv64_smode_defconfig + +Boot the 64-bit U-Boot S-mode image directly: + +.. code-block:: bash + + $ qemu-system-riscv64 -M virt -smp 4 -m 2G \ + -display none -serial stdio \ + -kernel /path/to/u-boot.bin + +To test booting U-Boot SPL which in M-mode, which in turn loads a FIT image +that bundles OpenSBI fw_dynamic firmware and U-Boot proper (S-mode) together, +build the U-Boot images using riscv64_spl_defconfig: + +.. code-block:: bash + + $ export CROSS_COMPILE=riscv64-linux- + $ export OPENSBI=/path/to/opensbi-riscv64-generic-fw_dynamic.bin + $ make qemu-riscv64_spl_defconfig + +The minimal QEMU commands to run U-Boot SPL are: + +.. code-block:: bash + + $ qemu-system-riscv64 -M virt -smp 4 -m 2G \ + -display none -serial stdio \ + -bios /path/to/u-boot-spl \ + -device loader,file=/path/to/u-boot.itb,addr=0x80200000 + +To test 32-bit U-Boot images, switch to use qemu-riscv32_smode_defconfig and +riscv32_spl_defconfig builds, and replace ``qemu-system-riscv64`` with +``qemu-system-riscv32`` in the command lines above to boot the 32-bit U-Boot. diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst index a5cc06b726..89a866e4f4 100644 --- a/docs/system/target-riscv.rst +++ b/docs/system/target-riscv.rst @@ -69,6 +69,7 @@ undocumented; you can get a complete list by running riscv/microchip-icicle-kit riscv/shakti-c riscv/sifive_u + riscv/virt RISC-V CPU firmware ------------------- From bc083a51cafff73ad6113fcc81f2f40639d7c8c6 Mon Sep 17 00:00:00 2001 From: Jose Martins Date: Sat, 22 May 2021 16:59:02 +0100 Subject: [PATCH 163/531] target/riscv: hardwire bits in hideleg and hedeleg The specification mandates for certain bits to be hardwired in the hypervisor delegation registers. This was not being enforced. Signed-off-by: Jose Martins Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-id: 20210522155902.374439-1-josemartins90@gmail.com [ Changes by AF: - Improve indentation - Convert delegable_excps to a #define to avoid failures with GCC 8 ] Signed-off-by: Alistair Francis --- target/riscv/csr.c | 54 ++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 62b968326c..9a4ed18ac5 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -411,28 +411,36 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno, static const target_ulong delegable_ints = S_MODE_INTERRUPTS | VS_MODE_INTERRUPTS; +static const target_ulong vs_delegable_ints = VS_MODE_INTERRUPTS; static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | VS_MODE_INTERRUPTS; -static const target_ulong delegable_excps = - (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) | - (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) | - (1ULL << (RISCV_EXCP_ILLEGAL_INST)) | - (1ULL << (RISCV_EXCP_BREAKPOINT)) | - (1ULL << (RISCV_EXCP_LOAD_ADDR_MIS)) | - (1ULL << (RISCV_EXCP_LOAD_ACCESS_FAULT)) | - (1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS)) | - (1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT)) | - (1ULL << (RISCV_EXCP_U_ECALL)) | - (1ULL << (RISCV_EXCP_S_ECALL)) | - (1ULL << (RISCV_EXCP_VS_ECALL)) | - (1ULL << (RISCV_EXCP_M_ECALL)) | - (1ULL << (RISCV_EXCP_INST_PAGE_FAULT)) | - (1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT)) | - (1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)) | - (1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) | - (1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) | - (1ULL << (RISCV_EXCP_VIRT_INSTRUCTION_FAULT)) | - (1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT)); +#define DELEGABLE_EXCPS ((1ULL << (RISCV_EXCP_INST_ADDR_MIS)) | \ + (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) | \ + (1ULL << (RISCV_EXCP_ILLEGAL_INST)) | \ + (1ULL << (RISCV_EXCP_BREAKPOINT)) | \ + (1ULL << (RISCV_EXCP_LOAD_ADDR_MIS)) | \ + (1ULL << (RISCV_EXCP_LOAD_ACCESS_FAULT)) | \ + (1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS)) | \ + (1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT)) | \ + (1ULL << (RISCV_EXCP_U_ECALL)) | \ + (1ULL << (RISCV_EXCP_S_ECALL)) | \ + (1ULL << (RISCV_EXCP_VS_ECALL)) | \ + (1ULL << (RISCV_EXCP_M_ECALL)) | \ + (1ULL << (RISCV_EXCP_INST_PAGE_FAULT)) | \ + (1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT)) | \ + (1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)) | \ + (1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) | \ + (1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) | \ + (1ULL << (RISCV_EXCP_VIRT_INSTRUCTION_FAULT)) | \ + (1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT))) +static const target_ulong vs_delegable_excps = DELEGABLE_EXCPS & + ~((1ULL << (RISCV_EXCP_S_ECALL)) | + (1ULL << (RISCV_EXCP_VS_ECALL)) | + (1ULL << (RISCV_EXCP_M_ECALL)) | + (1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) | + (1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) | + (1ULL << (RISCV_EXCP_VIRT_INSTRUCTION_FAULT)) | + (1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT))); static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | SSTATUS_SUM | SSTATUS_MXR; @@ -620,7 +628,7 @@ static RISCVException read_medeleg(CPURISCVState *env, int csrno, static RISCVException write_medeleg(CPURISCVState *env, int csrno, target_ulong val) { - env->medeleg = (env->medeleg & ~delegable_excps) | (val & delegable_excps); + env->medeleg = (env->medeleg & ~DELEGABLE_EXCPS) | (val & DELEGABLE_EXCPS); return RISCV_EXCP_NONE; } @@ -1039,7 +1047,7 @@ static RISCVException read_hedeleg(CPURISCVState *env, int csrno, static RISCVException write_hedeleg(CPURISCVState *env, int csrno, target_ulong val) { - env->hedeleg = val; + env->hedeleg = val & vs_delegable_excps; return RISCV_EXCP_NONE; } @@ -1053,7 +1061,7 @@ static RISCVException read_hideleg(CPURISCVState *env, int csrno, static RISCVException write_hideleg(CPURISCVState *env, int csrno, target_ulong val) { - env->hideleg = val; + env->hideleg = val & vs_delegable_ints; return RISCV_EXCP_NONE; } From 6165dcb55f0ab4b2a241e49859ce6262157887e7 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 6 Jul 2021 17:50:45 +0800 Subject: [PATCH 164/531] docs/system: riscv: Update Microchip Icicle Kit for direct kernel boot This adds a new section in the documentation to demonstrate how to use the new direct kernel boot feature for Microchip Icicle Kit, other than the HSS bootflow, using an upstream U-Boot v2021.07 image as an example. It also updates the truth table to have a new '-dtb' column which is required by direct kernel boot. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20210706095045.1917913-1-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- docs/system/riscv/microchip-icicle-kit.rst | 54 +++++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/docs/system/riscv/microchip-icicle-kit.rst b/docs/system/riscv/microchip-icicle-kit.rst index 54ced661e3..817d2aec9c 100644 --- a/docs/system/riscv/microchip-icicle-kit.rst +++ b/docs/system/riscv/microchip-icicle-kit.rst @@ -47,13 +47,13 @@ The user provided DTB should have the following requirements: QEMU follows below truth table to select which payload to execute: -===== ========== ======= --bios -kernel payload -===== ========== ======= - N N HSS - Y don't care HSS - N Y kernel -===== ========== ======= +===== ========== ========== ======= +-bios -kernel -dtb payload +===== ========== ========== ======= + N N don't care HSS + Y don't care don't care HSS + N Y Y kernel +===== ========== ========== ======= The memory is set to 1537 MiB by default which is the minimum required high memory size by HSS. A sanity check on ram size is performed in the machine @@ -106,4 +106,44 @@ HSS output is on the first serial port (stdio) and U-Boot outputs on the second serial port. U-Boot will automatically load the Linux kernel from the SD card image. +Direct Kernel Boot +------------------ + +Sometimes we just want to test booting a new kernel, and transforming the +kernel image to the format required by the HSS bootflow is tedious. We can +use '-kernel' for direct kernel booting just like other RISC-V machines do. + +In this mode, the OpenSBI fw_dynamic BIOS image for 'generic' platform is +used to boot an S-mode payload like U-Boot or OS kernel directly. + +For example, the following commands show building a U-Boot image from U-Boot +mainline v2021.07 for the Microchip Icicle Kit board: + +.. code-block:: bash + + $ export CROSS_COMPILE=riscv64-linux- + $ make microchip_mpfs_icicle_defconfig + +Then we can boot the machine by: + +.. code-block:: bash + + $ qemu-system-riscv64 -M microchip-icicle-kit -smp 5 -m 2G \ + -sd path/to/sdcard.img \ + -nic user,model=cadence_gem \ + -nic tap,ifname=tap,model=cadence_gem,script=no \ + -display none -serial stdio \ + -kernel path/to/u-boot/build/dir/u-boot.bin \ + -dtb path/to/u-boot/build/dir/u-boot.dtb + +CAVEATS: + +* Check the "stdout-path" property in the /chosen node in the DTB to determine + which serial port is used for the serial console, e.g.: if the console is set + to the second serial port, change to use "-serial null -serial stdio". +* The default U-Boot configuration uses CONFIG_OF_SEPARATE hence the ELF image + ``u-boot`` cannot be passed to "-kernel" as it does not contain the DTB hence + ``u-boot.bin`` has to be used which does contain one. To use the ELF image, + we need to change to CONFIG_OF_EMBED or CONFIG_OF_PRIOR_STAGE. + .. _HSS: https://github.com/polarfire-soc/hart-software-services From 074ca702e64dcea15c9c3b2c1931351cf397debe Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 6 Jul 2021 18:26:16 +0800 Subject: [PATCH 165/531] hw/riscv: sifive_u: Correct the CLINT timebase frequency At present the CLINT timebase frequency is set to 10MHz on sifive_u, but on the real hardware the timebase frequency is 1Mhz. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20210706102616.1922469-1-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 273c86418c..e75ca38783 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -62,6 +62,9 @@ #include +/* CLINT timebase frequency */ +#define CLINT_TIMEBASE_FREQ 1000000 + static const MemMapEntry sifive_u_memmap[] = { [SIFIVE_U_DEV_DEBUG] = { 0x0, 0x100 }, [SIFIVE_U_DEV_MROM] = { 0x1000, 0xf000 }, @@ -165,7 +168,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, qemu_fdt_add_subnode(fdt, "/cpus"); qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency", - SIFIVE_CLINT_TIMEBASE_FREQ); + CLINT_TIMEBASE_FREQ); qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0); qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1); @@ -847,7 +850,7 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) sifive_clint_create(memmap[SIFIVE_U_DEV_CLINT].base, memmap[SIFIVE_U_DEV_CLINT].size, 0, ms->smp.cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, - SIFIVE_CLINT_TIMEBASE_FREQ, false); + CLINT_TIMEBASE_FREQ, false); if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) { return; From 623d53cb017fc1506eed71dd01792bef1062a877 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 8 Jul 2021 22:33:19 +0800 Subject: [PATCH 166/531] hw/riscv: sifive_u: Make sure firmware info is 8-byte aligned Currently the firmware dynamic info (fw_dyn) is put right after the reset vector, which is not 8-byte aligned on RV64. OpenSBI fw_dynamic uses ld to read contents from 'struct fw_dynamic_info', which expects fw_dyn to be on the 8-byte boundary, otherwise the misaligned load exception may happen. Fortunately this does not cause any issue on QEMU, as QEMU does support misaligned load. RV32 does not have any issue as it is 4-byte aligned already. Change to make sure it is 8-byte aligned which works for both RV32 and RV64. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20210708143319.10441-1-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index e75ca38783..87bbd10b21 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -602,10 +602,10 @@ static void sifive_u_machine_init(MachineState *machine) } /* reset vector */ - uint32_t reset_vec[11] = { + uint32_t reset_vec[12] = { s->msel, /* MSEL pin state */ 0x00000297, /* 1: auipc t0, %pcrel_hi(fw_dyn) */ - 0x02828613, /* addi a2, t0, %pcrel_lo(1b) */ + 0x02c28613, /* addi a2, t0, %pcrel_lo(1b) */ 0xf1402573, /* csrr a0, mhartid */ 0, 0, @@ -613,6 +613,7 @@ static void sifive_u_machine_init(MachineState *machine) start_addr, /* start: .dword */ start_addr_hi32, fdt_load_addr, /* fdt_laddr: .dword */ + 0x00000000, 0x00000000, /* fw_dyn: */ }; From 24bfb98d0642aa7c5e8564750de34448f2f39ec5 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 9 Jul 2021 13:38:30 +1000 Subject: [PATCH 167/531] char: ibex_uart: Update the register layout Update the register layout to match the latest OpenTitan bitstream. Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: 25c8377d32f3e0f0a1a862c8a5092f8a9e3f9928.1625801868.git.alistair.francis@wdc.com --- hw/char/ibex_uart.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c index fe4b6c3c9e..6b0c9330bf 100644 --- a/hw/char/ibex_uart.c +++ b/hw/char/ibex_uart.c @@ -42,7 +42,8 @@ REG32(INTR_STATE, 0x00) FIELD(INTR_STATE, RX_OVERFLOW, 3, 1) REG32(INTR_ENABLE, 0x04) REG32(INTR_TEST, 0x08) -REG32(CTRL, 0x0C) +REG32(ALERT_TEST, 0x0C) +REG32(CTRL, 0x10) FIELD(CTRL, TX_ENABLE, 0, 1) FIELD(CTRL, RX_ENABLE, 1, 1) FIELD(CTRL, NF, 2, 1) @@ -52,25 +53,25 @@ REG32(CTRL, 0x0C) FIELD(CTRL, PARITY_ODD, 7, 1) FIELD(CTRL, RXBLVL, 8, 2) FIELD(CTRL, NCO, 16, 16) -REG32(STATUS, 0x10) +REG32(STATUS, 0x14) FIELD(STATUS, TXFULL, 0, 1) FIELD(STATUS, RXFULL, 1, 1) FIELD(STATUS, TXEMPTY, 2, 1) FIELD(STATUS, RXIDLE, 4, 1) FIELD(STATUS, RXEMPTY, 5, 1) -REG32(RDATA, 0x14) -REG32(WDATA, 0x18) -REG32(FIFO_CTRL, 0x1c) +REG32(RDATA, 0x18) +REG32(WDATA, 0x1C) +REG32(FIFO_CTRL, 0x20) FIELD(FIFO_CTRL, RXRST, 0, 1) FIELD(FIFO_CTRL, TXRST, 1, 1) FIELD(FIFO_CTRL, RXILVL, 2, 3) FIELD(FIFO_CTRL, TXILVL, 5, 2) -REG32(FIFO_STATUS, 0x20) +REG32(FIFO_STATUS, 0x24) FIELD(FIFO_STATUS, TXLVL, 0, 5) FIELD(FIFO_STATUS, RXLVL, 16, 5) -REG32(OVRD, 0x24) -REG32(VAL, 0x28) -REG32(TIMEOUT_CTRL, 0x2c) +REG32(OVRD, 0x28) +REG32(VAL, 0x2C) +REG32(TIMEOUT_CTRL, 0x30) static void ibex_uart_update_irqs(IbexUartState *s) { From 5ee257649f1a69d952c56f0a7084653e51971ce5 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 9 Jul 2021 13:38:39 +1000 Subject: [PATCH 168/531] hw/riscv: opentitan: Add the unimplement rv_core_ibex_peri Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: ed707782e84118e1b06a32fd79b70fecfb54ff82.1625801868.git.alistair.francis@wdc.com --- hw/riscv/opentitan.c | 3 +++ include/hw/riscv/opentitan.h | 1 + 2 files changed, 4 insertions(+) diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index c5a7e3bacb..933c211b11 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -58,6 +58,7 @@ static const MemMapEntry ibex_memmap[] = { [IBEX_DEV_ALERT_HANDLER] = { 0x411b0000, 0x1000 }, [IBEX_DEV_NMI_GEN] = { 0x411c0000, 0x1000 }, [IBEX_DEV_OTBN] = { 0x411d0000, 0x10000 }, + [IBEX_DEV_PERI] = { 0x411f0000, 0x10000 }, }; static void opentitan_board_init(MachineState *machine) @@ -217,6 +218,8 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) memmap[IBEX_DEV_NMI_GEN].base, memmap[IBEX_DEV_NMI_GEN].size); create_unimplemented_device("riscv.lowrisc.ibex.otbn", memmap[IBEX_DEV_OTBN].base, memmap[IBEX_DEV_OTBN].size); + create_unimplemented_device("riscv.lowrisc.ibex.peri", + memmap[IBEX_DEV_PERI].base, memmap[IBEX_DEV_PERI].size); } static void lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data) diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h index 86cceef698..a488f5e8ec 100644 --- a/include/hw/riscv/opentitan.h +++ b/include/hw/riscv/opentitan.h @@ -81,6 +81,7 @@ enum { IBEX_DEV_ALERT_HANDLER, IBEX_DEV_NMI_GEN, IBEX_DEV_OTBN, + IBEX_DEV_PERI, }; enum { From bb7e0cde3cbd59e8b7d6e0e9c67e11f76cbe64d4 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 9 Jul 2021 13:38:48 +1000 Subject: [PATCH 169/531] hw/riscv: opentitan: Add the flash alias OpenTitan has an alias of flash avaliable which is called virtual flash. Add support for that in the QEMU model. Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: c9cfbd2dd840fd0076877b8ea4d6dcfce60db5e9.1625801868.git.alistair.francis@wdc.com --- hw/riscv/opentitan.c | 6 ++++++ include/hw/riscv/opentitan.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 933c211b11..36a41c8b5b 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -59,6 +59,7 @@ static const MemMapEntry ibex_memmap[] = { [IBEX_DEV_NMI_GEN] = { 0x411c0000, 0x1000 }, [IBEX_DEV_OTBN] = { 0x411d0000, 0x10000 }, [IBEX_DEV_PERI] = { 0x411f0000, 0x10000 }, + [IBEX_DEV_FLASH_VIRTUAL] = { 0x80000000, 0x80000 }, }; static void opentitan_board_init(MachineState *machine) @@ -134,8 +135,13 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) /* Flash memory */ memory_region_init_rom(&s->flash_mem, OBJECT(dev_soc), "riscv.lowrisc.ibex.flash", memmap[IBEX_DEV_FLASH].size, &error_fatal); + memory_region_init_alias(&s->flash_alias, OBJECT(dev_soc), + "riscv.lowrisc.ibex.flash_virtual", &s->flash_mem, 0, + memmap[IBEX_DEV_FLASH_VIRTUAL].size); memory_region_add_subregion(sys_mem, memmap[IBEX_DEV_FLASH].base, &s->flash_mem); + memory_region_add_subregion(sys_mem, memmap[IBEX_DEV_FLASH_VIRTUAL].base, + &s->flash_alias); /* PLIC */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->plic), errp)) { diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h index a488f5e8ec..9f93bebdac 100644 --- a/include/hw/riscv/opentitan.h +++ b/include/hw/riscv/opentitan.h @@ -40,6 +40,7 @@ struct LowRISCIbexSoCState { MemoryRegion flash_mem; MemoryRegion rom; + MemoryRegion flash_alias; }; typedef struct OpenTitanState { @@ -54,6 +55,7 @@ enum { IBEX_DEV_ROM, IBEX_DEV_RAM, IBEX_DEV_FLASH, + IBEX_DEV_FLASH_VIRTUAL, IBEX_DEV_UART, IBEX_DEV_GPIO, IBEX_DEV_SPI, From b3d8aa20692b1baed299790f4a65d6b0cfb1a0bc Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 15 Jul 2021 09:01:22 +1000 Subject: [PATCH 170/531] hw/riscv/boot: Check the error of fdt_pack() Coverity reports that we don't check the error result of fdt_pack(), so let's save the result and assert that it is 0. Fixes: Coverity CID 1458136 Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: 07325315b49d5555269f76094e4bc5296e0643b9.1626303527.git.alistair.francis@wdc.com --- hw/riscv/boot.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 0d38bb7426..993bf89064 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -182,7 +182,7 @@ uint32_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) { uint32_t temp, fdt_addr; hwaddr dram_end = dram_base + mem_size; - int fdtsize = fdt_totalsize(fdt); + int ret, fdtsize = fdt_totalsize(fdt); if (fdtsize <= 0) { error_report("invalid device-tree"); @@ -198,7 +198,9 @@ uint32_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) temp = MIN(dram_end, 3072 * MiB); fdt_addr = QEMU_ALIGN_DOWN(temp - fdtsize, 16 * MiB); - fdt_pack(fdt); + ret = fdt_pack(fdt); + /* Should only fail if we've built a corrupted tree */ + g_assert(ret == 0); /* copy in the device tree */ qemu_fdt_dumpdtb(fdt, fdtsize); From a0c7b99bf75d85b616fa219a7d866fc72970f327 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Jun 2021 09:21:21 +0200 Subject: [PATCH 171/531] qapi: Fix crash on missing enum member name New test case enum-dict-no-name.json crashes: $ python3 scripts/qapi-gen.py tests/qapi-schema/enum-dict-no-name.json Traceback (most recent call last): [...] File "/work/armbru/qemu/scripts/qapi/expr.py", line 458, in check_enum member_name = member['name'] KeyError: 'name' Root cause: we try to retrieve member 'name' before we check for missing members. With that fixed, we get the expected error "'data' member misses key 'name'". Fixes: 0825f62c842f2c07c5471391c6d7fd3f4fe83732 Signed-off-by: Markus Armbruster Message-Id: <20210616072121.626431-1-armbru@redhat.com> Reviewed-by: Eric Blake Reviewed-by: John Snow --- scripts/qapi/expr.py | 2 +- tests/qapi-schema/enum-dict-no-name.err | 2 ++ tests/qapi-schema/enum-dict-no-name.json | 2 ++ tests/qapi-schema/enum-dict-no-name.out | 0 4 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 tests/qapi-schema/enum-dict-no-name.err create mode 100644 tests/qapi-schema/enum-dict-no-name.json create mode 100644 tests/qapi-schema/enum-dict-no-name.out diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 496f7e0333..cf98923fa6 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -455,8 +455,8 @@ def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> None: for m in members] for member in members: source = "'data' member" - member_name = member['name'] check_keys(member, info, source, ['name'], ['if']) + member_name = member['name'] check_name_is_str(member_name, info, source) source = "%s '%s'" % (source, member_name) # Enum members may start with a digit diff --git a/tests/qapi-schema/enum-dict-no-name.err b/tests/qapi-schema/enum-dict-no-name.err new file mode 100644 index 0000000000..3ce0c16987 --- /dev/null +++ b/tests/qapi-schema/enum-dict-no-name.err @@ -0,0 +1,2 @@ +enum-dict-no-name.json: In enum 'Enum': +enum-dict-no-name.json:2: 'data' member misses key 'name' diff --git a/tests/qapi-schema/enum-dict-no-name.json b/tests/qapi-schema/enum-dict-no-name.json new file mode 100644 index 0000000000..5952a8662e --- /dev/null +++ b/tests/qapi-schema/enum-dict-no-name.json @@ -0,0 +1,2 @@ +# enum member lacking a name +{ 'enum': 'Enum', 'data': [ {} ] } diff --git a/tests/qapi-schema/enum-dict-no-name.out b/tests/qapi-schema/enum-dict-no-name.out new file mode 100644 index 0000000000..e69de29bb2 From caf108bc587908f7608729f39639dccdfa53010b Mon Sep 17 00:00:00 2001 From: Julia Suvorova Date: Tue, 13 Jul 2021 02:42:00 +0200 Subject: [PATCH 172/531] hw/i386/acpi-build: Add ACPI PCI hot-plug methods to Q35 Implement notifications and gpe to support q35 ACPI PCI hot-plug. Use 0xcc4 - 0xcd7 range for 'acpi-pci-hotplug' io ports. Signed-off-by: Julia Suvorova Reviewed-by: Igor Mammedov Reviewed-by: Marcel Apfelbaum Message-Id: <20210713004205.775386-2-jusual@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: David Gibson --- hw/acpi/pcihp.c | 6 +++--- hw/acpi/piix4.c | 4 +++- hw/i386/acpi-build.c | 30 +++++++++++++++++++----------- hw/i386/acpi-build.h | 4 ++++ include/hw/acpi/ich9.h | 2 ++ include/hw/acpi/pcihp.h | 3 ++- 6 files changed, 33 insertions(+), 16 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index 4999277d57..d98a284b7a 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -37,7 +37,6 @@ #include "qom/qom-qobject.h" #include "trace.h" -#define ACPI_PCIHP_ADDR 0xae00 #define ACPI_PCIHP_SIZE 0x0018 #define PCI_UP_BASE 0x0000 #define PCI_DOWN_BASE 0x0004 @@ -488,10 +487,11 @@ static const MemoryRegionOps acpi_pcihp_io_ops = { }; void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus, - MemoryRegion *address_space_io, bool bridges_enabled) + MemoryRegion *address_space_io, bool bridges_enabled, + uint16_t io_base) { s->io_len = ACPI_PCIHP_SIZE; - s->io_base = ACPI_PCIHP_ADDR; + s->io_base = io_base; s->root = root_bus; s->legacy_piix = !bridges_enabled; diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 0bd23d74e2..48f7a1edbc 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -49,6 +49,8 @@ #define GPE_BASE 0xafe0 #define GPE_LEN 4 +#define ACPI_PCIHP_ADDR_PIIX4 0xae00 + struct pci_status { uint32_t up; /* deprecated, maintained for migration compatibility */ uint32_t down; @@ -607,7 +609,7 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, if (s->use_acpi_hotplug_bridge || s->use_acpi_root_pci_hotplug) { acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent, - s->use_acpi_hotplug_bridge); + s->use_acpi_hotplug_bridge, ACPI_PCIHP_ADDR_PIIX4); } s->cpu_hotplug_legacy = true; diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 357437ff1d..e1c246d6e8 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -219,10 +219,6 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm) /* w2k requires FADT(rev1) or it won't boot, keep PC compatible */ pm->fadt.rev = 1; pm->cpu_hp_io_base = PIIX4_CPU_HOTPLUG_IO_BASE; - pm->pcihp_io_base = - object_property_get_uint(obj, ACPI_PCIHP_IO_BASE_PROP, NULL); - pm->pcihp_io_len = - object_property_get_uint(obj, ACPI_PCIHP_IO_LEN_PROP, NULL); } if (lpc) { uint64_t smi_features = object_property_get_uint(lpc, @@ -238,6 +234,10 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm) pm->smi_on_cpu_unplug = !!(smi_features & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT)); } + pm->pcihp_io_base = + object_property_get_uint(obj, ACPI_PCIHP_IO_BASE_PROP, NULL); + pm->pcihp_io_len = + object_property_get_uint(obj, ACPI_PCIHP_IO_LEN_PROP, NULL); /* The above need not be conditional on machine type because the reset port * happens to be the same on PIIX (pc) and ICH9 (q35). */ @@ -392,6 +392,9 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, if (!pdev) { if (bsel) { /* add hotplug slots for non present devices */ + if (pci_bus_is_express(bus) && slot > 0) { + break; + } dev = aml_device("S%.02X", PCI_DEVFN(slot, 0)); aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); aml_append(dev, aml_name_decl("_ADR", aml_int(slot << 16))); @@ -521,7 +524,7 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, QLIST_FOREACH(sec, &bus->child, sibling) { int32_t devfn = sec->parent_dev->devfn; - if (pci_bus_is_root(sec) || pci_bus_is_express(sec)) { + if (pci_bus_is_root(sec)) { continue; } @@ -1251,7 +1254,7 @@ static void build_piix4_isa_bridge(Aml *table) aml_append(table, scope); } -static void build_piix4_pci_hotplug(Aml *table) +static void build_x86_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr) { Aml *scope; Aml *field; @@ -1260,20 +1263,22 @@ static void build_piix4_pci_hotplug(Aml *table) scope = aml_scope("_SB.PCI0"); aml_append(scope, - aml_operation_region("PCST", AML_SYSTEM_IO, aml_int(0xae00), 0x08)); + aml_operation_region("PCST", AML_SYSTEM_IO, aml_int(pcihp_addr), 0x08)); field = aml_field("PCST", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); aml_append(field, aml_named_field("PCIU", 32)); aml_append(field, aml_named_field("PCID", 32)); aml_append(scope, field); aml_append(scope, - aml_operation_region("SEJ", AML_SYSTEM_IO, aml_int(0xae08), 0x04)); + aml_operation_region("SEJ", AML_SYSTEM_IO, + aml_int(pcihp_addr + ACPI_PCIHP_SEJ_BASE), 0x04)); field = aml_field("SEJ", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); aml_append(field, aml_named_field("B0EJ", 32)); aml_append(scope, field); aml_append(scope, - aml_operation_region("BNMR", AML_SYSTEM_IO, aml_int(0xae10), 0x08)); + aml_operation_region("BNMR", AML_SYSTEM_IO, + aml_int(pcihp_addr + ACPI_PCIHP_BNMR_BASE), 0x08)); field = aml_field("BNMR", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); aml_append(field, aml_named_field("BNUM", 32)); aml_append(field, aml_named_field("PIDX", 32)); @@ -1407,7 +1412,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, build_piix4_isa_bridge(dsdt); build_isa_devices_aml(dsdt); if (pm->pcihp_bridge_en || pm->pcihp_root_en) { - build_piix4_pci_hotplug(dsdt); + build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base); } build_piix4_pci0_int(dsdt); } else { @@ -1455,6 +1460,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, } build_q35_isa_bridge(dsdt); build_isa_devices_aml(dsdt); + if (pm->pcihp_bridge_en) { + build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base); + } build_q35_pci0_int(dsdt); if (pcms->smbus && !pcmc->do_not_add_smb_acpi) { build_smb0(dsdt, pcms->smbus, ICH9_SMB_DEV, ICH9_SMB_FUNC); @@ -1489,7 +1497,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, { aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006"))); - if (misc->is_piix4 && (pm->pcihp_bridge_en || pm->pcihp_root_en)) { + if (pm->pcihp_bridge_en || pm->pcihp_root_en) { method = aml_method("_E01", 0, AML_NOTSERIALIZED); aml_append(method, aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF)); diff --git a/hw/i386/acpi-build.h b/hw/i386/acpi-build.h index 74df5fc612..487ec7710f 100644 --- a/hw/i386/acpi-build.h +++ b/hw/i386/acpi-build.h @@ -5,6 +5,10 @@ extern const struct AcpiGenericAddress x86_nvdimm_acpi_dsmio; +/* PCI Hot-plug registers bases. See docs/spec/acpi_pci_hotplug.txt */ +#define ACPI_PCIHP_SEJ_BASE 0x8 +#define ACPI_PCIHP_BNMR_BASE 0x10 + void acpi_setup(void); #endif diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h index df519e40b5..596120d97f 100644 --- a/include/hw/acpi/ich9.h +++ b/include/hw/acpi/ich9.h @@ -28,6 +28,8 @@ #include "hw/acpi/acpi_dev_interface.h" #include "hw/acpi/tco.h" +#define ACPI_PCIHP_ADDR_ICH9 0x0cc4 + typedef struct ICH9LPCPMRegs { /* * In ich9 spec says that pm1_cnt register is 32bit width and diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h index 2dd90aea30..af1a169fc3 100644 --- a/include/hw/acpi/pcihp.h +++ b/include/hw/acpi/pcihp.h @@ -55,7 +55,8 @@ typedef struct AcpiPciHpState { } AcpiPciHpState; void acpi_pcihp_init(Object *owner, AcpiPciHpState *, PCIBus *root, - MemoryRegion *address_space_io, bool bridges_enabled); + MemoryRegion *address_space_io, bool bridges_enabled, + uint16_t io_base); void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); From c0e427d6eb5fefc5382ab01e78611740db1b5d06 Mon Sep 17 00:00:00 2001 From: Julia Suvorova Date: Tue, 13 Jul 2021 02:42:01 +0200 Subject: [PATCH 173/531] hw/acpi/ich9: Enable ACPI PCI hot-plug Add acpi_pcihp to ich9_pm as part of 'acpi-pci-hotplug-with-bridge-support' option. Set default to false. Signed-off-by: Julia Suvorova Signed-off-by: Marcel Apfelbaum Reviewed-by: Igor Mammedov Message-Id: <20210713004205.775386-3-jusual@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: David Gibson --- hw/acpi/acpi-x86-stub.c | 6 ++++ hw/acpi/ich9.c | 70 +++++++++++++++++++++++++++++++++++++++++ hw/acpi/pcihp.c | 12 +++++-- hw/i386/acpi-build.c | 14 ++++++--- hw/i386/acpi-build.h | 1 + include/hw/acpi/ich9.h | 3 ++ 6 files changed, 100 insertions(+), 6 deletions(-) diff --git a/hw/acpi/acpi-x86-stub.c b/hw/acpi/acpi-x86-stub.c index f88d6a090b..e9e46c5c5f 100644 --- a/hw/acpi/acpi-x86-stub.c +++ b/hw/acpi/acpi-x86-stub.c @@ -1,7 +1,13 @@ #include "qemu/osdep.h" #include "hw/i386/pc.h" +#include "hw/i386/acpi-build.h" void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, const CPUArchIdList *apic_ids, GArray *entry) { } + +Object *acpi_get_i386_pci_host(void) +{ + return NULL; +} diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 4daa79ec8d..2f4eb453ac 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -217,6 +217,26 @@ static const VMStateDescription vmstate_cpuhp_state = { } }; +static bool vmstate_test_use_pcihp(void *opaque) +{ + ICH9LPCPMRegs *s = opaque; + + return s->use_acpi_hotplug_bridge; +} + +static const VMStateDescription vmstate_pcihp_state = { + .name = "ich9_pm/pcihp", + .version_id = 1, + .minimum_version_id = 1, + .needed = vmstate_test_use_pcihp, + .fields = (VMStateField[]) { + VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, + ICH9LPCPMRegs, + NULL, NULL), + VMSTATE_END_OF_LIST() + } +}; + const VMStateDescription vmstate_ich9_pm = { .name = "ich9_pm", .version_id = 1, @@ -238,6 +258,7 @@ const VMStateDescription vmstate_ich9_pm = { &vmstate_memhp_state, &vmstate_tco_io_state, &vmstate_cpuhp_state, + &vmstate_pcihp_state, NULL } }; @@ -259,6 +280,10 @@ static void pm_reset(void *opaque) } pm->smi_en_wmask = ~0; + if (pm->use_acpi_hotplug_bridge) { + acpi_pcihp_reset(&pm->acpi_pci_hotplug, true); + } + acpi_update_sci(&pm->acpi_regs, pm->irq); } @@ -297,6 +322,18 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, pm->enable_tco = true; acpi_pm_tco_init(&pm->tco_regs, &pm->io); + if (pm->use_acpi_hotplug_bridge) { + acpi_pcihp_init(OBJECT(lpc_pci), + &pm->acpi_pci_hotplug, + pci_get_bus(lpc_pci), + pci_address_space_io(lpc_pci), + true, + ACPI_PCIHP_ADDR_ICH9); + + qbus_set_hotplug_handler(BUS(pci_get_bus(lpc_pci)), + OBJECT(lpc_pci)); + } + pm->irq = sci_irq; qemu_register_reset(pm_reset, pm); pm->powerdown_notifier.notify = pm_powerdown_req; @@ -368,6 +405,20 @@ static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp) s->pm.enable_tco = value; } +static bool ich9_pm_get_acpi_pci_hotplug(Object *obj, Error **errp) +{ + ICH9LPCState *s = ICH9_LPC_DEVICE(obj); + + return s->pm.use_acpi_hotplug_bridge; +} + +static void ich9_pm_set_acpi_pci_hotplug(Object *obj, bool value, Error **errp) +{ + ICH9LPCState *s = ICH9_LPC_DEVICE(obj); + + s->pm.use_acpi_hotplug_bridge = value; +} + void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm) { static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN; @@ -376,6 +427,7 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm) pm->disable_s3 = 0; pm->disable_s4 = 0; pm->s4_val = 2; + pm->use_acpi_hotplug_bridge = false; object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, &pm->pm_io_base, OBJ_PROP_FLAG_READ); @@ -399,6 +451,9 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm) object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED, ich9_pm_get_enable_tco, ich9_pm_set_enable_tco); + object_property_add_bool(obj, "acpi-pci-hotplug-with-bridge-support", + ich9_pm_get_acpi_pci_hotplug, + ich9_pm_set_acpi_pci_hotplug); } void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, @@ -406,6 +461,11 @@ void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, { ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); + if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp); + return; + } + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) && !lpc->pm.acpi_memory_hotplug.is_enabled) { error_setg(errp, @@ -441,6 +501,9 @@ void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, } else { acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.cpuhp_state, dev, errp); } + } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + acpi_pcihp_device_plug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug, + dev, errp); } else { error_setg(errp, "acpi: device plug request for not supported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -473,6 +536,10 @@ void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev, acpi_cpu_unplug_request_cb(hotplug_dev, &lpc->pm.cpuhp_state, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + acpi_pcihp_device_unplug_request_cb(hotplug_dev, + &lpc->pm.acpi_pci_hotplug, + dev, errp); } else { error_setg(errp, "acpi: device unplug request for not supported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -490,6 +557,9 @@ void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && !lpc->pm.cpu_hotplug_legacy) { acpi_cpu_unplug_cb(&lpc->pm.cpuhp_state, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + acpi_pcihp_device_unplug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug, + dev, errp); } else { error_setg(errp, "acpi: device unplug for not supported device" " type: %s", object_get_typename(OBJECT(dev))); diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index d98a284b7a..9fdc6342b0 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -30,6 +30,8 @@ #include "hw/pci-host/i440fx.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_host.h" +#include "hw/i386/acpi-build.h" #include "hw/acpi/acpi.h" #include "hw/pci/pci_bus.h" #include "migration/vmstate.h" @@ -103,6 +105,7 @@ static void *acpi_set_bsel(PCIBus *bus, void *opaque) static void acpi_set_pci_info(void) { static bool bsel_is_set; + Object *host = acpi_get_i386_pci_host(); PCIBus *bus; unsigned bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT; @@ -111,7 +114,11 @@ static void acpi_set_pci_info(void) } bsel_is_set = true; - bus = find_i440fx(); /* TODO: Q35 support */ + if (!host) { + return; + } + + bus = PCI_HOST_BRIDGE(host)->bus; if (bus) { /* Scan all PCI buses. Set property to enable acpi based hotplug. */ pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &bsel_alloc); @@ -121,13 +128,14 @@ static void acpi_set_pci_info(void) static void acpi_pcihp_disable_root_bus(void) { static bool root_hp_disabled; + Object *host = acpi_get_i386_pci_host(); PCIBus *bus; if (root_hp_disabled) { return; } - bus = find_i440fx(); + bus = PCI_HOST_BRIDGE(host)->bus; if (bus) { /* setting the hotplug handler to NULL makes the bus non-hotpluggable */ qbus_set_hotplug_handler(BUS(bus), NULL); diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index e1c246d6e8..bc966a4110 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -299,7 +299,7 @@ static void acpi_get_misc_info(AcpiMiscInfo *info) * Because of the PXB hosts we cannot simply query TYPE_PCI_HOST_BRIDGE. * On i386 arch we only have two pci hosts, so we can look only for them. */ -static Object *acpi_get_i386_pci_host(void) +Object *acpi_get_i386_pci_host(void) { PCIHostState *host; @@ -320,7 +320,10 @@ static void acpi_get_pci_holes(Range *hole, Range *hole64) Object *pci_host; pci_host = acpi_get_i386_pci_host(); - g_assert(pci_host); + + if (!pci_host) { + return; + } range_set_bounds1(hole, object_property_get_uint(pci_host, @@ -1765,6 +1768,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, PCIBus *bus = NULL; pci_host = acpi_get_i386_pci_host(); + if (pci_host) { bus = PCI_HOST_BRIDGE(pci_host)->bus; } @@ -2321,7 +2325,9 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) QObject *o; pci_host = acpi_get_i386_pci_host(); - g_assert(pci_host); + if (!pci_host) { + return false; + } o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_BASE, NULL); if (!o) { @@ -2351,7 +2357,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) AcpiPmInfo pm; AcpiMiscInfo misc; AcpiMcfgInfo mcfg; - Range pci_hole, pci_hole64; + Range pci_hole = {}, pci_hole64 = {}; uint8_t *u; size_t aml_len = 0; GArray *tables_blob = tables->table_data; diff --git a/hw/i386/acpi-build.h b/hw/i386/acpi-build.h index 487ec7710f..0dce155c8c 100644 --- a/hw/i386/acpi-build.h +++ b/hw/i386/acpi-build.h @@ -10,5 +10,6 @@ extern const struct AcpiGenericAddress x86_nvdimm_acpi_dsmio; #define ACPI_PCIHP_BNMR_BASE 0x10 void acpi_setup(void); +Object *acpi_get_i386_pci_host(void); #endif diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h index 596120d97f..a329ce43ab 100644 --- a/include/hw/acpi/ich9.h +++ b/include/hw/acpi/ich9.h @@ -24,6 +24,7 @@ #include "hw/acpi/acpi.h" #include "hw/acpi/cpu_hotplug.h" #include "hw/acpi/cpu.h" +#include "hw/acpi/pcihp.h" #include "hw/acpi/memory_hotplug.h" #include "hw/acpi/acpi_dev_interface.h" #include "hw/acpi/tco.h" @@ -55,6 +56,8 @@ typedef struct ICH9LPCPMRegs { AcpiCpuHotplug gpe_cpu; CPUHotplugState cpuhp_state; + bool use_acpi_hotplug_bridge; + AcpiPciHpState acpi_pci_hotplug; MemHotplugState acpi_memory_hotplug; uint8_t disable_s3; From 3f3cbbb2369ebba67cccf8c60d6a0043b315e17c Mon Sep 17 00:00:00 2001 From: Julia Suvorova Date: Tue, 13 Jul 2021 02:42:02 +0200 Subject: [PATCH 174/531] hw/pci/pcie: Do not set HPC flag if acpihp is used Instead of changing the hot-plug type in _OSC register, do not set the 'Hot-Plug Capable' flag. This way guest will choose ACPI hot-plug if it is preferred and leave the option to use SHPC with pcie-pci-bridge. The ability to control hot-plug for each downstream port is retained, while 'hotplug=off' on the port means all hot-plug types are disabled. Signed-off-by: Julia Suvorova Reviewed-by: Igor Mammedov Reviewed-by: Marcel Apfelbaum Reviewed-by: David Gibson Message-Id: <20210713004205.775386-4-jusual@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/pcihp.c | 8 ++++++++ hw/core/machine.c | 1 - hw/i386/pc_q35.c | 11 +++++++++++ hw/pci/pcie.c | 8 +++++++- hw/pci/pcie_port.c | 1 + include/hw/pci/pcie_port.h | 5 ++++- 6 files changed, 31 insertions(+), 3 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index 9fdc6342b0..f4d706e47d 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -31,6 +31,7 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_host.h" +#include "hw/pci/pcie_port.h" #include "hw/i386/acpi-build.h" #include "hw/acpi/acpi.h" #include "hw/pci/pci_bus.h" @@ -336,6 +337,13 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) { PCIBus *sec = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev)); + /* Remove all hot-plug handlers if hot-plug is disabled on slot */ + if (object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT) && + !PCIE_SLOT(pdev)->hotplug) { + qbus_set_hotplug_handler(BUS(sec), NULL); + return; + } + qbus_set_hotplug_handler(BUS(sec), OBJECT(hotplug_dev)); /* We don't have to overwrite any other hotplug handler yet */ assert(QLIST_EMPTY(&sec->child)); diff --git a/hw/core/machine.c b/hw/core/machine.c index 6f59fb0b7f..775add0795 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -584,7 +584,6 @@ static void machine_set_memdev(Object *obj, const char *value, Error **errp) ms->ram_memdev_id = g_strdup(value); } - static void machine_init_notify(Notifier *notifier, void *data) { MachineState *machine = MACHINE(qdev_get_machine()); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 46a0f196f4..04b4a4788d 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -37,6 +37,7 @@ #include "sysemu/kvm.h" #include "hw/kvm/clock.h" #include "hw/pci-host/q35.h" +#include "hw/pci/pcie_port.h" #include "hw/qdev-properties.h" #include "hw/i386/x86.h" #include "hw/i386/pc.h" @@ -136,6 +137,7 @@ static void pc_q35_init(MachineState *machine) ram_addr_t lowmem; DriveInfo *hd[MAX_SATA_PORTS]; MachineClass *mc = MACHINE_GET_CLASS(machine); + bool acpi_pcihp; /* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory * and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping @@ -236,6 +238,15 @@ static void pc_q35_init(MachineState *machine) object_property_set_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, OBJECT(lpc), &error_abort); + acpi_pcihp = object_property_get_bool(OBJECT(lpc), + "acpi-pci-hotplug-with-bridge-support", + NULL); + + if (acpi_pcihp) { + object_register_sugar_prop(TYPE_PCIE_SLOT, "native-hotplug", + "false", true); + } + /* irq lines */ gsi_state = pc_gsi_create(&x86ms->gsi, pcmc->pci_enabled); diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index fd0fa157e8..6e95d82903 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -529,7 +529,13 @@ void pcie_cap_slot_init(PCIDevice *dev, PCIESlot *s) PCI_EXP_SLTCAP_PIP | PCI_EXP_SLTCAP_AIP | PCI_EXP_SLTCAP_ABP); - if (s->hotplug) { + + /* + * Enable native hot-plug on all hot-plugged bridges unless + * hot-plug is disabled on the slot. + */ + if (s->hotplug && + (s->native_hotplug || DEVICE(dev)->hotplugged)) { pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP, PCI_EXP_SLTCAP_HPS | PCI_EXP_SLTCAP_HPC); diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index eb563ad435..da850e8dde 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -148,6 +148,7 @@ static Property pcie_slot_props[] = { DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), DEFINE_PROP_BOOL("hotplug", PCIESlot, hotplug, true), + DEFINE_PROP_BOOL("native-hotplug", PCIESlot, native_hotplug, true), DEFINE_PROP_END_OF_LIST() }; diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h index bea8ecad0f..e25b289ce8 100644 --- a/include/hw/pci/pcie_port.h +++ b/include/hw/pci/pcie_port.h @@ -57,8 +57,11 @@ struct PCIESlot { /* Disable ACS (really for a pcie_root_port) */ bool disable_acs; - /* Indicates whether hot-plug is enabled on the slot */ + /* Indicates whether any type of hot-plug is allowed on the slot */ bool hotplug; + + bool native_hotplug; + QLIST_ENTRY(PCIESlot) next; }; From 383d11f217feca0f9947f790f2deafc09fe69ec5 Mon Sep 17 00:00:00 2001 From: Julia Suvorova Date: Tue, 13 Jul 2021 02:42:03 +0200 Subject: [PATCH 175/531] bios-tables-test: Allow changes in DSDT ACPI tables All DSDT Q35 tables will be modified because ACPI hot-plug is enabled by default. Signed-off-by: Julia Suvorova Reviewed-by: Igor Mammedov Reviewed-by: Marcel Apfelbaum Message-Id: <20210713004205.775386-5-jusual@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..c5167f48af 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,12 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/q35/DSDT", +"tests/data/acpi/q35/DSDT.tis", +"tests/data/acpi/q35/DSDT.bridge", +"tests/data/acpi/q35/DSDT.mmio64", +"tests/data/acpi/q35/DSDT.ipmibt", +"tests/data/acpi/q35/DSDT.cphp", +"tests/data/acpi/q35/DSDT.memhp", +"tests/data/acpi/q35/DSDT.acpihmat", +"tests/data/acpi/q35/DSDT.numamem", +"tests/data/acpi/q35/DSDT.dimmpxm", +"tests/data/acpi/q35/DSDT.nohpet", From 17858a169508609ca9063c544833e5a1adeb7b52 Mon Sep 17 00:00:00 2001 From: Julia Suvorova Date: Tue, 13 Jul 2021 02:42:04 +0200 Subject: [PATCH 176/531] hw/acpi/ich9: Set ACPI PCI hot-plug as default on Q35 Q35 has three different types of PCI devices hot-plug: PCIe Native, SHPC Native and ACPI hot-plug. This patch changes the default choice for cold-plugged bridges from PCIe Native to ACPI Hot-plug with ability to use SHPC and PCIe Native for hot-plugged bridges. This is a list of the PCIe Native hot-plug issues that led to this change: * no racy behavior during boot (see 110c477c2ed) * no delay during deleting - after the actual power off software must wait at least 1 second before indicating about it. This case is quite important for users, it even has its own bug: https://bugzilla.redhat.com/show_bug.cgi?id=1594168 * no timer-based behavior - in addition to the previous example, the attention button has a 5-second waiting period, during which the operation can be canceled with a second press. While this looks fine for manual button control, automation will result in the need to queue or drop events, and the software receiving events in all sort of unspecified combinations of attention/power indicator states, which is racy and uppredictable. * fixes: * https://bugzilla.redhat.com/show_bug.cgi?id=1752465 * https://bugzilla.redhat.com/show_bug.cgi?id=1690256 To return to PCIe Native hot-plug: -global ICH9-LPC.acpi-pci-hotplug-with-bridge-support=off Known issue: older linux guests need the following flag to allow hotplugged pci express devices to use io: -device pcie-root-port,io-reserve=4096. io is unusual for pci express so this seems minor. We'll fix this by a follow up patch. Signed-off-by: Julia Suvorova Reviewed-by: Igor Mammedov Message-Id: <20210713004205.775386-6-jusual@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: David Gibson --- hw/acpi/ich9.c | 2 +- hw/i386/pc.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 2f4eb453ac..778e27b659 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -427,7 +427,7 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm) pm->disable_s3 = 0; pm->disable_s4 = 0; pm->s4_val = 2; - pm->use_acpi_hotplug_bridge = false; + pm->use_acpi_hotplug_bridge = true; object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, &pm->pm_io_base, OBJ_PROP_FLAG_READ); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index aa79c5e0e6..f4c7a78362 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -99,6 +99,7 @@ GlobalProperty pc_compat_6_0[] = { { "qemu64" "-" TYPE_X86_CPU, "model", "6" }, { "qemu64" "-" TYPE_X86_CPU, "stepping", "3" }, { TYPE_X86_CPU, "x-vendor-cpuid-only", "off" }, + { "ICH9-LPC", "acpi-pci-hotplug-with-bridge-support", "off" }, }; const size_t pc_compat_6_0_len = G_N_ELEMENTS(pc_compat_6_0); From 1580b897c7b2f794fff7ba140ab757be1f6efadc Mon Sep 17 00:00:00 2001 From: Julia Suvorova Date: Tue, 13 Jul 2021 02:42:05 +0200 Subject: [PATCH 177/531] bios-tables-test: Update golden binaries Add ACPI hot-plug registers to DSDT Q35 tables. Changes in the tables: + Scope (_SB.PCI0) + { + OperationRegion (PCST, SystemIO, 0x0CC4, 0x08) + Field (PCST, DWordAcc, NoLock, WriteAsZeros) + { + PCIU, 32, + PCID, 32 + } + + OperationRegion (SEJ, SystemIO, 0x0CCC, 0x04) + Field (SEJ, DWordAcc, NoLock, WriteAsZeros) + { + B0EJ, 32 + } + + OperationRegion (BNMR, SystemIO, 0x0CD4, 0x08) + Field (BNMR, DWordAcc, NoLock, WriteAsZeros) + { + BNUM, 32, + PIDX, 32 + } + + Mutex (BLCK, 0x00) + Method (PCEJ, 2, NotSerialized) + { + Acquire (BLCK, 0xFFFF) + BNUM = Arg0 + B0EJ = (One << Arg1) + Release (BLCK) + Return (Zero) + } + + Method (AIDX, 2, NotSerialized) + { + Acquire (BLCK, 0xFFFF) + BNUM = Arg0 + PIDX = (One << Arg1) + Local0 = PIDX /* \_SB_.PCI0.PIDX */ + Release (BLCK) + Return (Local0) + } + + Method (PDSM, 6, Serialized) + { + If ((Arg0 == ToUUID ("e5c937d0-3553-4d7a-9117-ea4d19c3434d") /* Device Labeling Interface */)) + { + Local0 = AIDX (Arg4, Arg5) + If ((Arg2 == Zero)) + { + If ((Arg1 == 0x02)) + { + If (!((Local0 == Zero) | (Local0 == 0xFFFFFFFF))) + { + Return (Buffer (One) + { + 0x81 // . + }) + } + } + + Return (Buffer (One) + { + 0x00 // . + }) + } + ElseIf ((Arg2 == 0x07)) + { + Local1 = Package (0x02) + { + Zero, + "" + } + Local1 [Zero] = Local0 + Return (Local1) + } + } + } + } + ... Scope (_GPE) { Name (_HID, "ACPI0006" /* GPE Block Device */) // _HID: Hardware ID + Method (_E01, 0, NotSerialized) // _Exx: Edge-Triggered GPE, xx=0x00-0xFF + { + Acquire (\_SB.PCI0.BLCK, 0xFFFF) + \_SB.PCI0.PCNT () + Release (\_SB.PCI0.BLCK) + } ... + + Device (PHPR) + { + Name (_HID, "PNP0A06" /* Generic Container Device */) // _HID: Hardware ID + Name (_UID, "PCI Hotplug resources") // _UID: Unique ID + Name (_STA, 0x0B) // _STA: Status + Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings + { + IO (Decode16, + 0x0CC4, // Range Minimum + 0x0CC4, // Range Maximum + 0x01, // Alignment + 0x18, // Length + ) + }) + } } ... And if there is a port in configuration: Device (S10) { Name (_ADR, 0x00020000) // _ADR: Address + Name (BSEL, Zero) + Device (S00) + { + Name (_SUN, Zero) // _SUN: Slot User Number + Name (_ADR, Zero) // _ADR: Address + Method (_EJ0, 1, NotSerialized) // _EJx: Eject Device, x=0-9 + { + PCEJ (BSEL, _SUN) + } + + Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method + { + Return (PDSM (Arg0, Arg1, Arg2, Arg3, BSEL, _SUN)) + } + } + ... + Method (DVNT, 2, NotSerialized) + { + If ((Arg0 & One)) + { + Notify (S00, Arg1) + } ... Signed-off-by: Julia Suvorova Message-Id: <20210713004205.775386-7-jusual@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/q35/DSDT | Bin 7859 -> 8289 bytes tests/data/acpi/q35/DSDT.acpihmat | Bin 9184 -> 9614 bytes tests/data/acpi/q35/DSDT.bridge | Bin 7877 -> 11003 bytes tests/data/acpi/q35/DSDT.cphp | Bin 8323 -> 8753 bytes tests/data/acpi/q35/DSDT.dimmpxm | Bin 9513 -> 9943 bytes tests/data/acpi/q35/DSDT.ipmibt | Bin 7934 -> 8364 bytes tests/data/acpi/q35/DSDT.memhp | Bin 9218 -> 9648 bytes tests/data/acpi/q35/DSDT.mmio64 | Bin 8990 -> 9419 bytes tests/data/acpi/q35/DSDT.nohpet | Bin 7717 -> 8147 bytes tests/data/acpi/q35/DSDT.numamem | Bin 7865 -> 8295 bytes tests/data/acpi/q35/DSDT.tis | Bin 8465 -> 8894 bytes tests/qtest/bios-tables-test-allowed-diff.h | 11 ----------- 12 files changed, 11 deletions(-) diff --git a/tests/data/acpi/q35/DSDT b/tests/data/acpi/q35/DSDT index cccf92f0466fa4eaf2e9e06675b3b102c7a8eb86..842533f53e6db40935c3cdecd1d182edba6c17d4 100644 GIT binary patch delta 466 zcmdmN`_O^QCDauXIPPtIak zAUQdci)n%Iq}s^|43iUh{sRHS5=B8~#>OQ;f?=Wf0@2A?TpzYIYyru7HSX=AqfOH`-McSBME?12>6O_{w~AM zs2<(q#S-8V5X2Gh;pxH~;1^)vXkf;`5g!WTIeRL2LFaQ7^vWU|F delta 57 zcmaFpu-TT&CD*D+yKS90tV5j&1XHSFZh5+Z_5Jv7JJX{>njRGK! zGf+HK0Z6zgL^lMxdc`wxpW)$RiEiWuah#nDT)lu2PJX^YjNDfs+CUsOVt(t-l7wM diff --git a/tests/data/acpi/q35/DSDT.bridge b/tests/data/acpi/q35/DSDT.bridge index eb5d27d95b2cdeda5f7e1f6b151cfea02e6bd907..55ad4bd7ab4759d68031b2f1d0307355a7332fe7 100644 GIT binary patch delta 3198 zcmb7{PjBNy7{Ebzd(?3;ItCjk3cyfap1s>(;m2R;mDzf?)%1mvr$RXI0q}wJmcRyGxq%P zuaBe_71=%4P#92N&%?#cyB()e z^@POlsv^1P2^2=TP^p4ZwrWR0;?LkV6h_&q*Yfs(`BB~#%7@1LOn==rDpk>4M|FMO zZeor0*IZ~Zgt!}6-edZkCAjH-)u0x_+IVS%bsM@lW1CKGzIzz=o2j&-{ju}g-_F)I zweK_k)Uv-AwKlSzeAei$`=_j%^;?SAP5%-q`jNitRSFN7yZ-pC7>!!cp`ilXu#Vl0p#rR- z)s~+Bx3VB?xEEE)-nWlrZ~wqd+Lm1?6}Fk|)lnG-`TftoXg~S#6aPgnH*=|8s=~4_ zt)9+3dyMUAd(Zr@R^R2;PtJpaCwnFHNM%f9a@naIGWX&gr+~#y-2x(*OkeaW)q;Ry zk5$moGaihZ+QYGHwoX5#a`&PnIfY_yyFhGV6oQXul%*gUG^B_G5l2BLGr}B7j2N*Y z2A`rc5ajJ}EEI_#(hy`y1_g-|BhGXlWmF-^CIy)x$V}uQn-pYL_IU8zXCp%%QV^Mf z$k7=^kN00OWsV?oks(_YL?MO}fx#{J0)};qh9p6dL4h2~t$ii62I7X3zXvENNGWg_m1cDSPNQxk-n~+-> zyA))R7>gl;Pr0B$kX;IrCP+GRkP-#aLk4GhbO;4mq999=8RaktSMCtxPIL$b$q*wG zmBAf@hGdx_%TXbYK|!*_$WF=N{f(@@2ACA&E?lZtPL|bof*dM;kuPGKeUd;ZsM#d zu%~z`X?4}JrXr#!hC%`X$C$v8QIMm7fZaQA@+ipJ1F^};>Yzd^dDcuYYzcO_P+?OK z2OhQsn@;FqW3YRK3R{DHAXL~KEa;)a_F!oa6}AU!EN^ue&YE!Y5*QS~f=OEJYrHw| zCDgEvk(T@Vm9L?O<%RrwU%&GAP{XVzzth)6J}Bt-873oDfV1FJoLB>m{f0R*(AaZx z$j83Jt2^-XsE7PL(C|hL{0?dyR(%c6xvb6bAde3lzZ8VttC4dw%|4LxXsZct@8Y9tH*`1^^Ot5>o&G diff --git a/tests/data/acpi/q35/DSDT.cphp b/tests/data/acpi/q35/DSDT.cphp index e55d12990c98d8eed760b858ce18a036b612da1c..ccde2add9f87db0c0eaf0cc155717d5744e4ef40 100644 GIT binary patch delta 466 zcmZp6+~~sP66_LUsKmg)=(&;WH&eZUpP*iRuv2`1v!_9HLx6K|2qX6q9xjgPMgb7V z87LmA03=)#q8ox;z2X_U&+u@uL^pDSIL=N6u3kV1CqLgHM(!&RZ6J=blV7N>LV%}B zghDi|3JX7L{X5Lv2h8IU|1-=Ky-2z7khyaD-#1RLt;TfM$Fl2~Uj?rg^g&M>|NCE-Qej(B7NCF@g0=}Y~kIV5h zsz*0@u>^Po1aZWBc)IWg_yrg^8kjL~#D{`-&YlV$`6UH8rRkG5%FD7H;W@&?C^7kp Zd?uG4OAN?D0XLS(ZVI;SB5WXA7y#g;hnxTa delta 57 zcmdn!((K6P66_MvtiZs)7_^b=H`8VnmetaXB9kx53o{Ei3T{?Z;Afm%qnOU=#u5`B N>=Z9xH~FoiEdbPr5E}ph diff --git a/tests/data/acpi/q35/DSDT.dimmpxm b/tests/data/acpi/q35/DSDT.dimmpxm index 95901f94c0d445919cb84dd1f6d98c646ae8176e..b062e30117f955c7a2ac9629a0512324bbd28bf2 100644 GIT binary patch delta 500 zcmZ4Kb={ZCCDauXIPPtIak zAUQdci)n%Iq}s^|43iUh{sRHS5=B8~#>OQ;f?=Wf0@2A?T6g=`v3UW%*Cx@%ZvK`?$!ow&rxk@FI%a0`nG&EEVc?F8u9J{t{m|mo-VwO&H~3^jZa^I-tdz5?tSm&`@XmD^P=GxwR;r+n0^pBTugx@MNxhi+R{7=Is)ae{Qa zZmGCv?5hOoWwZyBMU2c+h-5h%4*eE)_@@`J4R{F2alH?er92z@XJalN=5z3Vy`Ex3 zu;EyfL3x6oj4YpLbq~EDOFJM))3z82Qn%;S1Jsj-?1BD5 zG7Nit2HQ7IEKms&<@45*_wY1#%*wp>$N z10>s64gcM6wBDG2kzFIXF@ZZ|Yvxg(pMp7ZRT6LkS4YX%##){Q$J{#WVOLiRN5_8m iauXIPPtIak zAUQdci)n%Iq}s^|43iUh{sRHS5=B8~#>OQ;f?=Wf0@2A?T<+5bHs-N?E!|mf=7NyK~8DaL66_Mfq{6_!cz+|;Z>G&EEL!s7BJu74t{m|mo-VwO&H4 b7bx>HPX4Wu&gsSy6CdmpFJL!0N7WVpu^|&B diff --git a/tests/data/acpi/q35/DSDT.mmio64 b/tests/data/acpi/q35/DSDT.mmio64 index 77d46369e48efca9a9e5024542c77cd26144beff..2e0a772a85275c9c3b4c9317d98cc7c3d27417f3 100644 GIT binary patch delta 479 zcmZWl%}T>S7~Ji@Y1C9x)PoXRr3XPH_=Db>O|+>dU78kztt36!iee6WP!L;BUUlyh zp)Vjlg1v}>9()BazJiCkOBDq7Ffg<8&G3D<8_%YoJ9_1L1^`I!g|E&)Y6Qrp|k$q^kRffs;{un1nv#XYZ zO?^ipP}@dZK%T|OD27OuvtG|{aEE_-0h@q_kQ~=LK%UF9p?@~!;$c1q@5k%OdJOB1 zH56<|X(Kf%NN=l8AI|cbbv^cJO*|sY=UE4bUXZ2xAef*{Ary?>oKp`_PwcS=I@75z zY89Gf~gPY5jIs-T>1(DGmt(vHd;|L@ije>S delta 71 zcmX@@InRyDCDauXIPPtIak zAUQdci)n%Iq}s^|43iUh{sRHS5=B8~#>OQ;f?=Wf0@2A?TqMI{i_!+&To4i;8JOY9sCI|Qh7&rnA=7D+yKS90tV5j&1XHSFZh5+Z_5Jv7JJX{>njRGK! zGf+HK0Z6zgL^lMxdc`wxpW)$RiEiWuah#nDT)lu2PJX^YjNDfs+CUsylgPr07oIMSq8v>kzLm0V_@NjWNHwu6_ z&Oq@{1t8&~5Zw^$>J`t(eTIjNCAyIt#Bp{qaP+slXajMao%}+56#_h6 zA{3$-oqU|V8AMbAoL#+`qLo3s|NjdzKq?9<>lrf{K!!xCgT$9Gh-f>7t;daNwt#`7$zt1{09PtC5nQ~jEzfx1j9n{1)`I)xY!GXSeY1j84?Q;IuaQe zmLzUwWxg%RBR&+wbM{p5$S*0#DNUdJR#ukn2+t87Mv2J+ da+#d|nlT^?1>7e$$=R`quz@Vuyk9Pe2>{`!ixL0; delta 62 zcmdnzI?;*CCD Date: Fri, 9 Jul 2021 10:30:16 +0530 Subject: [PATCH 178/531] hw/virtio: add boilerplate for vhost-user-i2c device This creates the QEMU side of the vhost-user-i2c device which connects to the remote daemon. It is based of vhost-user-fs code. Signed-off-by: Viresh Kumar Message-Id: Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Kconfig | 5 + hw/virtio/meson.build | 1 + hw/virtio/vhost-user-i2c.c | 288 +++++++++++++++++++++++++++++ include/hw/virtio/vhost-user-i2c.h | 28 +++ 4 files changed, 322 insertions(+) create mode 100644 hw/virtio/vhost-user-i2c.c create mode 100644 include/hw/virtio/vhost-user-i2c.h diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig index 0eda25c4e1..35ab45e209 100644 --- a/hw/virtio/Kconfig +++ b/hw/virtio/Kconfig @@ -58,3 +58,8 @@ config VIRTIO_MEM depends on LINUX depends on VIRTIO_MEM_SUPPORTED select MEM_DEVICE + +config VHOST_USER_I2C + bool + default y + depends on VIRTIO && VHOST_USER diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index fbff9bc9d4..1a0d736a0d 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -25,6 +25,7 @@ virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock. virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c')) +virtio_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c.c')) virtio_pci_ss = ss.source_set() virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c')) diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c new file mode 100644 index 0000000000..d172632bb0 --- /dev/null +++ b/hw/virtio/vhost-user-i2c.c @@ -0,0 +1,288 @@ +/* + * Vhost-user i2c virtio device + * + * Copyright (c) 2021 Viresh Kumar + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/vhost-user-i2c.h" +#include "qemu/error-report.h" +#include "standard-headers/linux/virtio_ids.h" + +/* Remove this once the header is updated in Linux kernel */ +#ifndef VIRTIO_ID_I2C_ADAPTER +#define VIRTIO_ID_I2C_ADAPTER 34 +#endif + +static void vu_i2c_start(VirtIODevice *vdev) +{ + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VHostUserI2C *i2c = VHOST_USER_I2C(vdev); + int ret, i; + + if (!k->set_guest_notifiers) { + error_report("binding does not support guest notifiers"); + return; + } + + ret = vhost_dev_enable_notifiers(&i2c->vhost_dev, vdev); + if (ret < 0) { + error_report("Error enabling host notifiers: %d", -ret); + return; + } + + ret = k->set_guest_notifiers(qbus->parent, i2c->vhost_dev.nvqs, true); + if (ret < 0) { + error_report("Error binding guest notifier: %d", -ret); + goto err_host_notifiers; + } + + i2c->vhost_dev.acked_features = vdev->guest_features; + + ret = vhost_dev_start(&i2c->vhost_dev, vdev); + if (ret < 0) { + error_report("Error starting vhost-user-i2c: %d", -ret); + goto err_guest_notifiers; + } + + /* + * guest_notifier_mask/pending not used yet, so just unmask + * everything here. virtio-pci will do the right thing by + * enabling/disabling irqfd. + */ + for (i = 0; i < i2c->vhost_dev.nvqs; i++) { + vhost_virtqueue_mask(&i2c->vhost_dev, vdev, i, false); + } + + return; + +err_guest_notifiers: + k->set_guest_notifiers(qbus->parent, i2c->vhost_dev.nvqs, false); +err_host_notifiers: + vhost_dev_disable_notifiers(&i2c->vhost_dev, vdev); +} + +static void vu_i2c_stop(VirtIODevice *vdev) +{ + VHostUserI2C *i2c = VHOST_USER_I2C(vdev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + int ret; + + if (!k->set_guest_notifiers) { + return; + } + + vhost_dev_stop(&i2c->vhost_dev, vdev); + + ret = k->set_guest_notifiers(qbus->parent, i2c->vhost_dev.nvqs, false); + if (ret < 0) { + error_report("vhost guest notifier cleanup failed: %d", ret); + return; + } + + vhost_dev_disable_notifiers(&i2c->vhost_dev, vdev); +} + +static void vu_i2c_set_status(VirtIODevice *vdev, uint8_t status) +{ + VHostUserI2C *i2c = VHOST_USER_I2C(vdev); + bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; + + if (!vdev->vm_running) { + should_start = false; + } + + if (i2c->vhost_dev.started == should_start) { + return; + } + + if (should_start) { + vu_i2c_start(vdev); + } else { + vu_i2c_stop(vdev); + } +} + +static uint64_t vu_i2c_get_features(VirtIODevice *vdev, + uint64_t requested_features, Error **errp) +{ + /* No feature bits used yet */ + return requested_features; +} + +static void vu_i2c_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + /* + * Not normally called; it's the daemon that handles the queue; + * however virtio's cleanup path can call this. + */ +} + +static void vu_i2c_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) +{ + VHostUserI2C *i2c = VHOST_USER_I2C(vdev); + + vhost_virtqueue_mask(&i2c->vhost_dev, vdev, idx, mask); +} + +static bool vu_i2c_guest_notifier_pending(VirtIODevice *vdev, int idx) +{ + VHostUserI2C *i2c = VHOST_USER_I2C(vdev); + + return vhost_virtqueue_pending(&i2c->vhost_dev, idx); +} + +static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserI2C *i2c) +{ + vhost_user_cleanup(&i2c->vhost_user); + virtio_delete_queue(i2c->vq); + virtio_cleanup(vdev); + g_free(i2c->vhost_dev.vqs); + i2c->vhost_dev.vqs = NULL; +} + +static int vu_i2c_connect(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserI2C *i2c = VHOST_USER_I2C(vdev); + + if (i2c->connected) { + return 0; + } + i2c->connected = true; + + /* restore vhost state */ + if (virtio_device_started(vdev, vdev->status)) { + vu_i2c_start(vdev); + } + + return 0; +} + +static void vu_i2c_disconnect(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserI2C *i2c = VHOST_USER_I2C(vdev); + + if (!i2c->connected) { + return; + } + i2c->connected = false; + + if (i2c->vhost_dev.started) { + vu_i2c_stop(vdev); + } +} + +static void vu_i2c_event(void *opaque, QEMUChrEvent event) +{ + DeviceState *dev = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserI2C *i2c = VHOST_USER_I2C(vdev); + + switch (event) { + case CHR_EVENT_OPENED: + if (vu_i2c_connect(dev) < 0) { + qemu_chr_fe_disconnect(&i2c->chardev); + return; + } + break; + case CHR_EVENT_CLOSED: + vu_i2c_disconnect(dev); + break; + case CHR_EVENT_BREAK: + case CHR_EVENT_MUX_IN: + case CHR_EVENT_MUX_OUT: + /* Ignore */ + break; + } +} + +static void vu_i2c_device_realize(DeviceState *dev, Error **errp) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserI2C *i2c = VHOST_USER_I2C(dev); + int ret; + + if (!i2c->chardev.chr) { + error_setg(errp, "vhost-user-i2c: missing chardev"); + return; + } + + if (!vhost_user_init(&i2c->vhost_user, &i2c->chardev, errp)) { + return; + } + + virtio_init(vdev, "vhost-user-i2c", VIRTIO_ID_I2C_ADAPTER, 0); + + i2c->vhost_dev.nvqs = 1; + i2c->vq = virtio_add_queue(vdev, 4, vu_i2c_handle_output); + i2c->vhost_dev.vqs = g_new0(struct vhost_virtqueue, i2c->vhost_dev.nvqs); + + ret = vhost_dev_init(&i2c->vhost_dev, &i2c->vhost_user, + VHOST_BACKEND_TYPE_USER, 0, errp); + if (ret < 0) { + do_vhost_user_cleanup(vdev, i2c); + } + + qemu_chr_fe_set_handlers(&i2c->chardev, NULL, NULL, vu_i2c_event, NULL, + dev, NULL, true); +} + +static void vu_i2c_device_unrealize(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserI2C *i2c = VHOST_USER_I2C(dev); + + /* This will stop vhost backend if appropriate. */ + vu_i2c_set_status(vdev, 0); + vhost_dev_cleanup(&i2c->vhost_dev); + do_vhost_user_cleanup(vdev, i2c); +} + +static const VMStateDescription vu_i2c_vmstate = { + .name = "vhost-user-i2c", + .unmigratable = 1, +}; + +static Property vu_i2c_properties[] = { + DEFINE_PROP_CHR("chardev", VHostUserI2C, chardev), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vu_i2c_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + + device_class_set_props(dc, vu_i2c_properties); + dc->vmsd = &vu_i2c_vmstate; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + vdc->realize = vu_i2c_device_realize; + vdc->unrealize = vu_i2c_device_unrealize; + vdc->get_features = vu_i2c_get_features; + vdc->set_status = vu_i2c_set_status; + vdc->guest_notifier_mask = vu_i2c_guest_notifier_mask; + vdc->guest_notifier_pending = vu_i2c_guest_notifier_pending; +} + +static const TypeInfo vu_i2c_info = { + .name = TYPE_VHOST_USER_I2C, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VHostUserI2C), + .class_init = vu_i2c_class_init, +}; + +static void vu_i2c_register_types(void) +{ + type_register_static(&vu_i2c_info); +} + +type_init(vu_i2c_register_types) diff --git a/include/hw/virtio/vhost-user-i2c.h b/include/hw/virtio/vhost-user-i2c.h new file mode 100644 index 0000000000..deae47a76d --- /dev/null +++ b/include/hw/virtio/vhost-user-i2c.h @@ -0,0 +1,28 @@ +/* + * Vhost-user i2c virtio device + * + * Copyright (c) 2021 Viresh Kumar + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef _QEMU_VHOST_USER_I2C_H +#define _QEMU_VHOST_USER_I2C_H + +#include "hw/virtio/vhost.h" +#include "hw/virtio/vhost-user.h" + +#define TYPE_VHOST_USER_I2C "vhost-user-i2c-device" +OBJECT_DECLARE_SIMPLE_TYPE(VHostUserI2C, VHOST_USER_I2C) + +struct VHostUserI2C { + VirtIODevice parent; + CharBackend chardev; + struct vhost_virtqueue *vhost_vq; + struct vhost_dev vhost_dev; + VhostUserState vhost_user; + VirtQueue *vq; + bool connected; +}; + +#endif /* _QEMU_VHOST_USER_I2C_H */ From 538bb6f1219c1711538d73143f005e62c3d20f7b Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 9 Jul 2021 10:30:17 +0530 Subject: [PATCH 179/531] hw/virtio: add vhost-user-i2c-pci boilerplate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows is to instantiate a vhost-user-i2c device as part of a PCI bus. It is mostly boilerplate which looks pretty similar to the vhost-user-fs-pci device. Reviewed-by: Alex Bennée Signed-off-by: Viresh Kumar Message-Id: <8a083eaa57d93feaab12acd1f94b225879212f20.1625806763.git.viresh.kumar@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/meson.build | 1 + hw/virtio/vhost-user-i2c-pci.c | 69 ++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 hw/virtio/vhost-user-i2c-pci.c diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index 1a0d736a0d..bc352a6009 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -26,6 +26,7 @@ virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c')) virtio_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c.c')) +virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_I2C'], if_true: files('vhost-user-i2c-pci.c')) virtio_pci_ss = ss.source_set() virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c')) diff --git a/hw/virtio/vhost-user-i2c-pci.c b/hw/virtio/vhost-user-i2c-pci.c new file mode 100644 index 0000000000..70b7b65fd9 --- /dev/null +++ b/hw/virtio/vhost-user-i2c-pci.c @@ -0,0 +1,69 @@ +/* + * Vhost-user i2c virtio device PCI glue + * + * Copyright (c) 2021 Viresh Kumar + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/vhost-user-i2c.h" +#include "virtio-pci.h" + +struct VHostUserI2CPCI { + VirtIOPCIProxy parent_obj; + VHostUserI2C vdev; +}; + +typedef struct VHostUserI2CPCI VHostUserI2CPCI; + +#define TYPE_VHOST_USER_I2C_PCI "vhost-user-i2c-pci-base" + +DECLARE_INSTANCE_CHECKER(VHostUserI2CPCI, VHOST_USER_I2C_PCI, + TYPE_VHOST_USER_I2C_PCI) + +static void vhost_user_i2c_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostUserI2CPCI *dev = VHOST_USER_I2C_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + vpci_dev->nvectors = 1; + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); +} + +static void vhost_user_i2c_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = vhost_user_i2c_pci_realize; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */ + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; +} + +static void vhost_user_i2c_pci_instance_init(Object *obj) +{ + VHostUserI2CPCI *dev = VHOST_USER_I2C_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_USER_I2C); +} + +static const VirtioPCIDeviceTypeInfo vhost_user_i2c_pci_info = { + .base_name = TYPE_VHOST_USER_I2C_PCI, + .non_transitional_name = "vhost-user-i2c-pci", + .instance_size = sizeof(VHostUserI2CPCI), + .instance_init = vhost_user_i2c_pci_instance_init, + .class_init = vhost_user_i2c_pci_class_init, +}; + +static void vhost_user_i2c_pci_register(void) +{ + virtio_pci_types_register(&vhost_user_i2c_pci_info); +} + +type_init(vhost_user_i2c_pci_register); From 7395b3e3e70031b1efff7941cbef6a1ceb6f2ffd Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 7 Jul 2021 11:41:14 -0400 Subject: [PATCH 180/531] docs: Add '-device intel-iommu' entry The parameters of intel-iommu device are non-trivial to understand. Add an entry for it so that people can reference to it when using. There're actually a few more options there, but I hide them explicitly because they shouldn't be used by normal QEMU users. Cc: Chao Yang Cc: Lei Yang Cc: Jing Zhao Cc: Jason Wang Cc: Michael S. Tsirkin Cc: Alex Williamson Reviewed-by: Jason Wang Reviewed-by: Yi Liu Signed-off-by: Peter Xu Message-Id: <20210707154114.197580-1-peterx@redhat.com> Reviewed-by: Maxim Levitsky Reviewed-by: Eric Auger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- qemu-options.hx | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/qemu-options.hx b/qemu-options.hx index 214c477dcc..0c9ddc0274 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -939,6 +939,39 @@ SRST ``-device pci-ipmi-bt,bmc=id`` Like the KCS interface, but defines a BT interface on the PCI bus. + +``-device intel-iommu[,option=...]`` + This is only supported by ``-machine q35``, which will enable Intel VT-d + emulation within the guest. It supports below options: + + ``intremap=on|off`` (default: auto) + This enables interrupt remapping feature. It's required to enable + complete x2apic. Currently it only supports kvm kernel-irqchip modes + ``off`` or ``split``, while full kernel-irqchip is not yet supported. + The default value is "auto", which will be decided by the mode of + kernel-irqchip. + + ``caching-mode=on|off`` (default: off) + This enables caching mode for the VT-d emulated device. When + caching-mode is enabled, each guest DMA buffer mapping will generate an + IOTLB invalidation from the guest IOMMU driver to the vIOMMU device in + a synchronous way. It is required for ``-device vfio-pci`` to work + with the VT-d device, because host assigned devices requires to setup + the DMA mapping on the host before guest DMA starts. + + ``device-iotlb=on|off`` (default: off) + This enables device-iotlb capability for the emulated VT-d device. So + far virtio/vhost should be the only real user for this parameter, + paired with ats=on configured for the device. + + ``aw-bits=39|48`` (default: 39) + This decides the address width of IOVA address space. The address + space has 39 bits width for 3-level IOMMU page tables, and 48 bits for + 4-level IOMMU page tables. + + Please also refer to the wiki page for general scenarios of VT-d + emulation in QEMU: https://wiki.qemu.org/Features/VT-d. + ERST DEF("name", HAS_ARG, QEMU_OPTION_name, From 2d64b7bbb2a2e945635633486ef9a060cb2c89bc Mon Sep 17 00:00:00 2001 From: Xingang Wang Date: Thu, 8 Jul 2021 12:55:11 +0000 Subject: [PATCH 181/531] hw/pci/pci_host: Allow PCI host to bypass iommu Add a new bypass_iommu property for PCI host and use it to check whether devices attached to the PCI root bus will bypass iommu. In pci_device_iommu_address_space(), check the property and avoid getting iommu address space for devices bypass iommu. Signed-off-by: Xingang Wang Reviewed-by: Eric Auger Message-Id: <1625748919-52456-2-git-send-email-wangxingang5@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 18 +++++++++++++++++- hw/pci/pci_host.c | 1 + include/hw/pci/pci.h | 1 + include/hw/pci/pci_host.h | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 377084f1a8..27d588e268 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -416,6 +416,22 @@ const char *pci_root_bus_path(PCIDevice *dev) return rootbus->qbus.name; } +bool pci_bus_bypass_iommu(PCIBus *bus) +{ + PCIBus *rootbus = bus; + PCIHostState *host_bridge; + + if (!pci_bus_is_root(bus)) { + rootbus = pci_device_root_bus(bus->parent_dev); + } + + host_bridge = PCI_HOST_BRIDGE(rootbus->qbus.parent); + + assert(host_bridge->bus == rootbus); + + return host_bridge->bypass_iommu; +} + static void pci_root_bus_init(PCIBus *bus, DeviceState *parent, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, @@ -2718,7 +2734,7 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) iommu_bus = parent_bus; } - if (iommu_bus && iommu_bus->iommu_fn) { + if (!pci_bus_bypass_iommu(bus) && iommu_bus && iommu_bus->iommu_fn) { return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, devfn); } return &address_space_memory; diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c index 8ca5fadcbd..cf02f0d6a5 100644 --- a/hw/pci/pci_host.c +++ b/hw/pci/pci_host.c @@ -222,6 +222,7 @@ const VMStateDescription vmstate_pcihost = { static Property pci_host_properties_common[] = { DEFINE_PROP_BOOL("x-config-reg-migration-enabled", PCIHostState, mig_enabled, true), + DEFINE_PROP_BOOL("bypass-iommu", PCIHostState, bypass_iommu, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 6be4e0c460..f4d51b672b 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -480,6 +480,7 @@ void pci_for_each_bus(PCIBus *bus, PCIBus *pci_device_root_bus(const PCIDevice *d); const char *pci_root_bus_path(PCIDevice *dev); +bool pci_bus_bypass_iommu(PCIBus *bus); PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn); int pci_qdev_find_device(const char *id, PCIDevice **pdev); void pci_bus_get_w64_range(PCIBus *bus, Range *range); diff --git a/include/hw/pci/pci_host.h b/include/hw/pci/pci_host.h index 52e038c019..c6f4eb4585 100644 --- a/include/hw/pci/pci_host.h +++ b/include/hw/pci/pci_host.h @@ -43,6 +43,7 @@ struct PCIHostState { uint32_t config_reg; bool mig_enabled; PCIBus *bus; + bool bypass_iommu; QLIST_ENTRY(PCIHostState) next; }; From 91528f40ba3dda110927f11b47620bb24f8d601b Mon Sep 17 00:00:00 2001 From: Xingang Wang Date: Thu, 8 Jul 2021 12:55:12 +0000 Subject: [PATCH 182/531] hw/pxb: Add a bypass iommu property Add a bypass_iommu property for pci_expander_bridge, the property is used to indicate whether pxb root bus will bypass iommu. By default the bypass_iommu is disabled, and it can be enabled with: qemu -device pxb-pcie,bus_nr=0x10,addr=0x1,bypass_iommu=true Signed-off-by: Xingang Wang Reviewed-by: Eric Auger Message-Id: <1625748919-52456-3-git-send-email-wangxingang5@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-bridge/pci_expander_bridge.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index aedded1064..7112dc3062 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -57,6 +57,7 @@ struct PXBDev { uint8_t bus_nr; uint16_t numa_node; + bool bypass_iommu; }; static PXBDev *convert_to_pxb(PCIDevice *dev) @@ -255,6 +256,7 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) bus->map_irq = pxb_map_irq_fn; PCI_HOST_BRIDGE(ds)->bus = bus; + PCI_HOST_BRIDGE(ds)->bypass_iommu = pxb->bypass_iommu; pxb_register_bus(dev, bus, &local_err); if (local_err) { @@ -301,6 +303,7 @@ static Property pxb_dev_properties[] = { /* Note: 0 is not a legal PXB bus number. */ DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0), DEFINE_PROP_UINT16("numa_node", PXBDev, numa_node, NUMA_NODE_UNASSIGNED), + DEFINE_PROP_BOOL("bypass_iommu", PXBDev, bypass_iommu, false), DEFINE_PROP_END_OF_LIST(), }; From 6d7a85483a069b99ad4b018509643437b8f9a4f7 Mon Sep 17 00:00:00 2001 From: Xingang Wang Date: Thu, 8 Jul 2021 12:55:13 +0000 Subject: [PATCH 183/531] hw/arm/virt: Add default_bus_bypass_iommu machine option Add a default_bus_bypass_iommu machine option to enable/disable bypass_iommu for default root bus. The option is disabled by default and can be enabled with: $QEMU -machine virt,iommu=smmuv3,default_bus_bypass_iommu=true Signed-off-by: Xingang Wang Message-Id: <1625748919-52456-4-git-send-email-wangxingang5@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/virt.c | 26 ++++++++++++++++++++++++++ include/hw/arm/virt.h | 1 + 2 files changed, 27 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 93ab9d21ea..81eda46b0b 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1367,6 +1367,7 @@ static void create_pcie(VirtMachineState *vms) } pci = PCI_HOST_BRIDGE(dev); + pci->bypass_iommu = vms->default_bus_bypass_iommu; vms->bus = pci->bus; if (vms->bus) { for (i = 0; i < nb_nics; i++) { @@ -2322,6 +2323,21 @@ static void virt_set_iommu(Object *obj, const char *value, Error **errp) } } +static bool virt_get_default_bus_bypass_iommu(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->default_bus_bypass_iommu; +} + +static void virt_set_default_bus_bypass_iommu(Object *obj, bool value, + Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->default_bus_bypass_iommu = value; +} + static CpuInstanceProperties virt_cpu_index_to_props(MachineState *ms, unsigned cpu_index) { @@ -2661,6 +2677,13 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) "Set the IOMMU type. " "Valid values are none and smmuv3"); + object_class_property_add_bool(oc, "default_bus_bypass_iommu", + virt_get_default_bus_bypass_iommu, + virt_set_default_bus_bypass_iommu); + object_class_property_set_description(oc, "default_bus_bypass_iommu", + "Set on/off to enable/disable " + "bypass_iommu for default root bus"); + object_class_property_add_bool(oc, "ras", virt_get_ras, virt_set_ras); object_class_property_set_description(oc, "ras", @@ -2728,6 +2751,9 @@ static void virt_instance_init(Object *obj) /* Default disallows iommu instantiation */ vms->iommu = VIRT_IOMMU_NONE; + /* The default root bus is attached to iommu by default */ + vms->default_bus_bypass_iommu = false; + /* Default disallows RAS instantiation */ vms->ras = false; diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 921416f918..9661c46699 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -147,6 +147,7 @@ struct VirtMachineState { OnOffAuto acpi; VirtGICType gic_version; VirtIOMMUType iommu; + bool default_bus_bypass_iommu; VirtMSIControllerType msi_controller; uint16_t virtio_iommu_bdf; struct arm_boot_info bootinfo; From c9e96b04fc192fb38622694947dae091bbbdf28f Mon Sep 17 00:00:00 2001 From: Xingang Wang Date: Thu, 8 Jul 2021 12:55:14 +0000 Subject: [PATCH 184/531] hw/i386: Add a default_bus_bypass_iommu pc machine option Add a default_bus_bypass_iommu pc machine option to enable/disable bypass_iommu for default root bus. The option is disabled by default and can be enabled with: $QEMU -machine q35,default_bus_bypass_iommu=true Signed-off-by: Xingang Wang Message-Id: <1625748919-52456-5-git-send-email-wangxingang5@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 20 ++++++++++++++++++++ hw/pci-host/q35.c | 2 ++ include/hw/i386/pc.h | 1 + 3 files changed, 23 insertions(+) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index f4c7a78362..c2b9d62a35 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1524,6 +1524,21 @@ static void pc_machine_set_hpet(Object *obj, bool value, Error **errp) pcms->hpet_enabled = value; } +static bool pc_machine_get_default_bus_bypass_iommu(Object *obj, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + return pcms->default_bus_bypass_iommu; +} + +static void pc_machine_set_default_bus_bypass_iommu(Object *obj, bool value, + Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + pcms->default_bus_bypass_iommu = value; +} + static void pc_machine_get_max_ram_below_4g(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) @@ -1623,6 +1638,7 @@ static void pc_machine_initfn(Object *obj) #ifdef CONFIG_HPET pcms->hpet_enabled = true; #endif + pcms->default_bus_bypass_iommu = false; pc_system_flash_create(pcms); pcms->pcspk = isa_new(TYPE_PC_SPEAKER); @@ -1747,6 +1763,10 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "hpet", pc_machine_get_hpet, pc_machine_set_hpet); + object_class_property_add_bool(oc, "default_bus_bypass_iommu", + pc_machine_get_default_bus_bypass_iommu, + pc_machine_set_default_bus_bypass_iommu); + object_class_property_add(oc, PC_MACHINE_MAX_FW_SIZE, "size", pc_machine_get_max_fw_size, pc_machine_set_max_fw_size, NULL, NULL); diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 0f37cf056a..ab5a47aff5 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -65,6 +65,8 @@ static void q35_host_realize(DeviceState *dev, Error **errp) s->mch.address_space_io, 0, TYPE_PCIE_BUS); PC_MACHINE(qdev_get_machine())->bus = pci->bus; + pci->bypass_iommu = + PC_MACHINE(qdev_get_machine())->default_bus_bypass_iommu; qdev_realize(DEVICE(&s->mch), BUS(pci->bus), &error_fatal); } diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 0775f945d7..88dffe7517 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -44,6 +44,7 @@ typedef struct PCMachineState { bool sata_enabled; bool pit_enabled; bool hpet_enabled; + bool default_bus_bypass_iommu; uint64_t max_fw_size; /* NUMA information: */ From 500db1daf3079c3d0222bd3963cf4e5bf6175175 Mon Sep 17 00:00:00 2001 From: Xingang Wang Date: Thu, 8 Jul 2021 12:55:15 +0000 Subject: [PATCH 185/531] hw/pci: Add pci_bus_range() to get PCI bus number range This helps to get the min and max bus number of a PCI bus hierarchy. Signed-off-by: Xingang Wang Reviewed-by: Eric Auger Message-Id: <1625748919-52456-6-git-send-email-wangxingang5@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 16 ++++++++++++++++ include/hw/pci/pci.h | 1 + 2 files changed, 17 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 27d588e268..23d2ae2ab2 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -537,6 +537,22 @@ int pci_bus_num(PCIBus *s) return PCI_BUS_GET_CLASS(s)->bus_num(s); } +/* Returns the min and max bus numbers of a PCI bus hierarchy */ +void pci_bus_range(PCIBus *bus, int *min_bus, int *max_bus) +{ + int i; + *min_bus = *max_bus = pci_bus_num(bus); + + for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { + PCIDevice *dev = bus->devices[i]; + + if (dev && PCI_DEVICE_GET_CLASS(dev)->is_bridge) { + *min_bus = MIN(*min_bus, dev->config[PCI_SECONDARY_BUS]); + *max_bus = MAX(*max_bus, dev->config[PCI_SUBORDINATE_BUS]); + } + } +} + int pci_bus_numa_node(PCIBus *bus) { return PCI_BUS_GET_CLASS(bus)->numa_node(bus); diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index f4d51b672b..d0f4266e37 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -450,6 +450,7 @@ static inline PCIBus *pci_get_bus(const PCIDevice *dev) return PCI_BUS(qdev_get_parent_bus(DEVICE(dev))); } int pci_bus_num(PCIBus *s); +void pci_bus_range(PCIBus *bus, int *min_bus, int *max_bus); static inline int pci_dev_bus_num(const PCIDevice *dev) { return pci_bus_num(pci_get_bus(dev)); From 42e0f050e3a513f070b1c2e885890ac2095337e8 Mon Sep 17 00:00:00 2001 From: Xingang Wang Date: Thu, 8 Jul 2021 12:55:16 +0000 Subject: [PATCH 186/531] hw/arm/virt-acpi-build: Add IORT support to bypass SMMUv3 When we build IORT table with SMMUv3 and bypass iommu feature enabled, we can no longer setup one map from RC to SMMUv3 covering the whole RIDs. We need to walk the PCI bus and check whether the root bus will bypass iommu, setup RC -> SMMUv3 -> ITS map for RC which will not bypass iommu. When a SMMUv3 node exist, we setup the idmap from SMMUv3 to ITS covering the whole RIDs, and only modify the map from RC to SMMUv3. We build RC -> SMMUv3 -> ITS map for root bus with bypass_iommu disabled, and build idmap from RC to ITS directly for the rest of the whole RID space. For example we run qemu with command line: qemu/build/aarch64-softmmu/qemu-system-aarch64 \ -kernel arch/arm64/boot/Image \ -enable-kvm \ -cpu host \ -m 8G \ -smp 8,sockets=2,cores=4,threads=1 \ -machine virt,kernel_irqchip=on,gic-version=3,iommu=smmuv3,default_bus_bypass_iommu=true \ -drive file=./QEMU_EFI-pflash.raw,if=pflash,format=raw,unit=0,readonly=on \ -device pxb-pcie,bus_nr=0x10,id=pci.10,bus=pcie.0,addr=0x3.0x1 \ -device pxb-pcie,bus_nr=0x20,id=pci.20,bus=pcie.0,addr=0x3.0x2,bypass_iommu=true \ -device pcie-root-port,port=0x20,chassis=1,id=pci.1,bus=pcie.0,addr=0x2 \ -device pcie-root-port,port=0x20,chassis=11,id=pci.11,bus=pci.10,addr=0x1 \ -device pcie-root-port,port=0x20,chassis=21,id=pci.21,bus=pci.20,addr=0x1 \ -device virtio-scsi-pci,id=scsi0,bus=pci.1,addr=0x1 \ -device virtio-scsi-pci,id=scsi1,bus=pci.11,addr=0x1 \ -device virtio-scsi-pci,id=scsi2,bus=pci.21,addr=0x1 \ -initrd /mnt/davinci/wxg/kill-linux/rootfs/mfs.cpio.gz \ -nographic \ -append "rdinit=init console=ttyAMA0 earlycon=pl011,0x9000000 nokaslr" \ And we get guest configuration: -+-[0000:20]---01.0-[21]-- +-[0000:10]---01.0-[11]-- \-[0000:00]-+-00.0 Device 1b36:0008 +-01.0 Device 1af4:1000 \-02.0-[01]-- With bypass_iommu enabled, the attached devices will bypass iommu. /sys/class/iommu/smmu3.0x0000000009050000/ |-- device -> ../../../arm-smmu-v3.0.auto |-- devices | `-- 0000:10:01.0 -> ../../../../../pci0000:10/0000:10:01.0 Signed-off-by: Xingang Wang Message-Id: <1625748919-52456-7-git-send-email-wangxingang5@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/virt-acpi-build.c | 114 +++++++++++++++++++++++++++++++++++---- 1 file changed, 103 insertions(+), 11 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index f1024843dd..037cc1fd82 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -44,6 +44,7 @@ #include "hw/acpi/tpm.h" #include "hw/pci/pcie_host.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" #include "hw/pci-host/gpex.h" #include "hw/arm/virt.h" #include "hw/mem/nvdimm.h" @@ -239,23 +240,89 @@ static void acpi_dsdt_add_tpm(Aml *scope, VirtMachineState *vms) } #endif +/* Build the iort ID mapping to SMMUv3 for a given PCI host bridge */ +static int +iort_host_bridges(Object *obj, void *opaque) +{ + GArray *idmap_blob = opaque; + + if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) { + PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus; + + if (bus && !pci_bus_bypass_iommu(bus)) { + int min_bus, max_bus; + + pci_bus_range(bus, &min_bus, &max_bus); + + AcpiIortIdMapping idmap = { + .input_base = min_bus << 8, + .id_count = (max_bus - min_bus + 1) << 8, + }; + g_array_append_val(idmap_blob, idmap); + } + } + + return 0; +} + +static int iort_idmap_compare(gconstpointer a, gconstpointer b) +{ + AcpiIortIdMapping *idmap_a = (AcpiIortIdMapping *)a; + AcpiIortIdMapping *idmap_b = (AcpiIortIdMapping *)b; + + return idmap_a->input_base - idmap_b->input_base; +} + static void build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { - int nb_nodes, iort_start = table_data->len; + int i, nb_nodes, rc_mapping_count, iort_start = table_data->len; AcpiIortIdMapping *idmap; AcpiIortItsGroup *its; AcpiIortTable *iort; AcpiIortSmmu3 *smmu; size_t node_size, iort_node_offset, iort_length, smmu_offset = 0; AcpiIortRC *rc; + GArray *smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping)); + GArray *its_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping)); iort = acpi_data_push(table_data, sizeof(*iort)); if (vms->iommu == VIRT_IOMMU_SMMUV3) { + AcpiIortIdMapping next_range = {0}; + + object_child_foreach_recursive(object_get_root(), + iort_host_bridges, smmu_idmaps); + + /* Sort the smmu idmap by input_base */ + g_array_sort(smmu_idmaps, iort_idmap_compare); + + /* + * Split the whole RIDs by mapping from RC to SMMU, + * build the ID mapping from RC to ITS directly. + */ + for (i = 0; i < smmu_idmaps->len; i++) { + idmap = &g_array_index(smmu_idmaps, AcpiIortIdMapping, i); + + if (next_range.input_base < idmap->input_base) { + next_range.id_count = idmap->input_base - next_range.input_base; + g_array_append_val(its_idmaps, next_range); + } + + next_range.input_base = idmap->input_base + idmap->id_count; + } + + /* Append the last RC -> ITS ID mapping */ + if (next_range.input_base < 0xFFFF) { + next_range.id_count = 0xFFFF - next_range.input_base; + g_array_append_val(its_idmaps, next_range); + } + nb_nodes = 3; /* RC, ITS, SMMUv3 */ + rc_mapping_count = smmu_idmaps->len + its_idmaps->len; } else { nb_nodes = 2; /* RC, ITS */ + rc_mapping_count = 1; } iort_length = sizeof(*iort); @@ -307,13 +374,13 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) } /* Root Complex Node */ - node_size = sizeof(*rc) + sizeof(*idmap); + node_size = sizeof(*rc) + sizeof(*idmap) * rc_mapping_count; iort_length += node_size; rc = acpi_data_push(table_data, node_size); rc->type = ACPI_IORT_NODE_PCI_ROOT_COMPLEX; rc->length = cpu_to_le16(node_size); - rc->mapping_count = cpu_to_le32(1); + rc->mapping_count = cpu_to_le32(rc_mapping_count); rc->mapping_offset = cpu_to_le32(sizeof(*rc)); /* fully coherent device */ @@ -321,20 +388,45 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) rc->memory_properties.memory_flags = 0x3; /* CCA = CPM = DCAS = 1 */ rc->pci_segment_number = 0; /* MCFG pci_segment */ - /* Identity RID mapping covering the whole input RID range */ - idmap = &rc->id_mapping_array[0]; - idmap->input_base = 0; - idmap->id_count = cpu_to_le32(0xFFFF); - idmap->output_base = 0; - if (vms->iommu == VIRT_IOMMU_SMMUV3) { - /* output IORT node is the smmuv3 node */ - idmap->output_reference = cpu_to_le32(smmu_offset); + AcpiIortIdMapping *range; + + /* translated RIDs connect to SMMUv3 node: RC -> SMMUv3 -> ITS */ + for (i = 0; i < smmu_idmaps->len; i++) { + idmap = &rc->id_mapping_array[i]; + range = &g_array_index(smmu_idmaps, AcpiIortIdMapping, i); + + idmap->input_base = cpu_to_le32(range->input_base); + idmap->id_count = cpu_to_le32(range->id_count); + idmap->output_base = cpu_to_le32(range->input_base); + /* output IORT node is the smmuv3 node */ + idmap->output_reference = cpu_to_le32(smmu_offset); + } + + /* bypassed RIDs connect to ITS group node directly: RC -> ITS */ + for (i = 0; i < its_idmaps->len; i++) { + idmap = &rc->id_mapping_array[smmu_idmaps->len + i]; + range = &g_array_index(its_idmaps, AcpiIortIdMapping, i); + + idmap->input_base = cpu_to_le32(range->input_base); + idmap->id_count = cpu_to_le32(range->id_count); + idmap->output_base = cpu_to_le32(range->input_base); + /* output IORT node is the ITS group node (the first node) */ + idmap->output_reference = cpu_to_le32(iort_node_offset); + } } else { + /* Identity RID mapping covering the whole input RID range */ + idmap = &rc->id_mapping_array[0]; + idmap->input_base = cpu_to_le32(0); + idmap->id_count = cpu_to_le32(0xFFFF); + idmap->output_base = cpu_to_le32(0); /* output IORT node is the ITS group node (the first node) */ idmap->output_reference = cpu_to_le32(iort_node_offset); } + g_array_free(smmu_idmaps, true); + g_array_free(its_idmaps, true); + /* * Update the pointer address in case table_data->data moves during above * acpi_data_push operations. From 26863366b29ab638711bbe0fa741dcf355eddb54 Mon Sep 17 00:00:00 2001 From: Xingang Wang Date: Thu, 8 Jul 2021 12:55:17 +0000 Subject: [PATCH 187/531] hw/i386/acpi-build: Add DMAR support to bypass iommu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In DMAR table, the drhd is set to cover all PCI devices when intel_iommu is on. To support bypass iommu feature, we need to walk the PCI bus with bypass_iommu disabled and add explicit scope data in DMAR drhd structure. /mnt/sdb/wxg/qemu-next/qemu/build/x86_64-softmmu/qemu-system-x86_64 \ -machine q35,accel=kvm,default_bus_bypass_iommu=true \ -cpu host \ -m 16G \ -smp 36,sockets=2,cores=18,threads=1 \ -device pxb-pcie,bus_nr=0x10,id=pci.10,bus=pcie.0,addr=0x3 \ -device pxb-pcie,bus_nr=0x20,id=pci.20,bus=pcie.0,addr=0x4,bypass_iommu=true \ -device pcie-root-port,port=0x1,chassis=1,id=pci.11,bus=pci.10,addr=0x0 \ -device pcie-root-port,port=0x2,chassis=2,id=pci.21,bus=pci.20,addr=0x0 \ -device virtio-scsi-pci,id=scsi0,bus=pci.11,addr=0x0 \ -device virtio-scsi-pci,id=scsi1,bus=pci.21,addr=0x0 \ -drive file=/mnt/sdb/wxg/fedora-48g.qcow2,format=qcow2,if=none,id=drive-scsi0-0-0-0,cache=none,aio=native \ -device scsi-hd,bus=scsi1.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=1 \ -device intel-iommu \ -nographic \ And we get the guest configuration: ~ lspci -vt -+-[0000:20]---00.0-[21]----00.0 Red Hat, Inc. Virtio SCSI +-[0000:10]---00.0-[11]----00.0 Red Hat, Inc. Virtio SCSI \-[0000:00]-+-00.0 Intel Corporation 82G33/G31/P35/P31 Express DRAM Controller +-01.0 Device 1234:1111 +-02.0 Intel Corporation 82574L Gigabit Network Connection +-03.0 Red Hat, Inc. QEMU PCIe Expander bridge +-04.0 Red Hat, Inc. QEMU PCIe Expander bridge +-1f.0 Intel Corporation 82801IB (ICH9) LPC Interface Controller +-1f.2 Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode] \-1f.3 Intel Corporation 82801I (ICH9 Family) SMBus Controller With bypass_iommu enabled on root bus, the attached devices will bypass iommu: /sys/class/iommu/dmar0 ├── devices │   ├── 0000:10:00.0 -> ../../../../pci0000:10/0000:10:00.0 │   └── 0000:11:00.0 -> ../../../../pci0000:10/0000:10:00.0/0000:11:00.0 Signed-off-by: Xingang Wang Message-Id: <1625748919-52456-8-git-send-email-wangxingang5@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 68 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index bc966a4110..7efc6285ac 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2022,6 +2022,56 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) x86ms->oem_table_id); } +/* + * Insert DMAR scope for PCI bridges and endpoint devcie + */ +static void +insert_scope(PCIBus *bus, PCIDevice *dev, void *opaque) +{ + GArray *scope_blob = opaque; + AcpiDmarDeviceScope *scope = NULL; + + if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) { + /* Dmar Scope Type: 0x02 for PCI Bridge */ + build_append_int_noprefix(scope_blob, 0x02, 1); + } else { + /* Dmar Scope Type: 0x01 for PCI Endpoint Device */ + build_append_int_noprefix(scope_blob, 0x01, 1); + } + + /* length */ + build_append_int_noprefix(scope_blob, + sizeof(*scope) + sizeof(scope->path[0]), 1); + /* reserved */ + build_append_int_noprefix(scope_blob, 0, 2); + /* enumeration_id */ + build_append_int_noprefix(scope_blob, 0, 1); + /* bus */ + build_append_int_noprefix(scope_blob, pci_bus_num(bus), 1); + /* device */ + build_append_int_noprefix(scope_blob, PCI_SLOT(dev->devfn), 1); + /* function */ + build_append_int_noprefix(scope_blob, PCI_FUNC(dev->devfn), 1); +} + +/* For a given PCI host bridge, walk and insert DMAR scope */ +static int +dmar_host_bridges(Object *obj, void *opaque) +{ + GArray *scope_blob = opaque; + + if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) { + PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus; + + if (bus && !pci_bus_bypass_iommu(bus)) { + pci_for_each_device(bus, pci_bus_num(bus), insert_scope, + scope_blob); + } + } + + return 0; +} + /* * VT-d spec 8.1 DMA Remapping Reporting Structure * (version Oct. 2014 or later) @@ -2041,6 +2091,15 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker, const char *oem_id, /* Root complex IOAPIC use one path[0] only */ size_t ioapic_scope_size = sizeof(*scope) + sizeof(scope->path[0]); IntelIOMMUState *intel_iommu = INTEL_IOMMU_DEVICE(iommu); + GArray *scope_blob = g_array_new(false, true, 1); + + /* + * A PCI bus walk, for each PCI host bridge. + * Insert scope for each PCI bridge and endpoint device which + * is attached to a bus with iommu enabled. + */ + object_child_foreach_recursive(object_get_root(), + dmar_host_bridges, scope_blob); assert(iommu); if (x86_iommu_ir_supported(iommu)) { @@ -2054,8 +2113,9 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker, const char *oem_id, /* DMAR Remapping Hardware Unit Definition structure */ drhd = acpi_data_push(table_data, sizeof(*drhd) + ioapic_scope_size); drhd->type = cpu_to_le16(ACPI_DMAR_TYPE_HARDWARE_UNIT); - drhd->length = cpu_to_le16(sizeof(*drhd) + ioapic_scope_size); - drhd->flags = ACPI_DMAR_INCLUDE_PCI_ALL; + drhd->length = + cpu_to_le16(sizeof(*drhd) + ioapic_scope_size + scope_blob->len); + drhd->flags = 0; /* Don't include all pci device */ drhd->pci_segment = cpu_to_le16(0); drhd->address = cpu_to_le64(Q35_HOST_BRIDGE_IOMMU_ADDR); @@ -2069,6 +2129,10 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker, const char *oem_id, scope->path[0].device = PCI_SLOT(Q35_PSEUDO_DEVFN_IOAPIC); scope->path[0].function = PCI_FUNC(Q35_PSEUDO_DEVFN_IOAPIC); + /* Add scope found above */ + g_array_append_vals(table_data, scope_blob->data, scope_blob->len); + g_array_free(scope_blob, true); + if (iommu->dt_supported) { atsr = acpi_data_push(table_data, sizeof(*atsr)); atsr->type = cpu_to_le16(ACPI_DMAR_TYPE_ATSR); From dec2f5636e9b590a5d2d2e20e821e9899f7c63bf Mon Sep 17 00:00:00 2001 From: Xingang Wang Date: Thu, 8 Jul 2021 12:55:18 +0000 Subject: [PATCH 188/531] hw/i386/acpi-build: Add IVRS support to bypass iommu Check bypass_iommu to exclude the devices which will bypass iommu. Signed-off-by: Xingang Wang Message-Id: <1625748919-52456-9-git-send-email-wangxingang5@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 7efc6285ac..17836149fe 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2263,7 +2263,7 @@ ivrs_host_bridges(Object *obj, void *opaque) if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) { PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus; - if (bus) { + if (bus && !pci_bus_bypass_iommu(bus)) { pci_for_each_device(bus, pci_bus_num(bus), insert_ivhd, ivhd_blob); } } From 732de3e72d8872b34b82afb3a5b063b2e0c1c85b Mon Sep 17 00:00:00 2001 From: Xingang Wang Date: Thu, 8 Jul 2021 12:55:19 +0000 Subject: [PATCH 189/531] docs: Add documentation for iommu bypass Signed-off-by: Xingang Wang Message-Id: <1625748919-52456-10-git-send-email-wangxingang5@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/bypass-iommu.txt | 89 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 docs/bypass-iommu.txt diff --git a/docs/bypass-iommu.txt b/docs/bypass-iommu.txt new file mode 100644 index 0000000000..e6677bddd3 --- /dev/null +++ b/docs/bypass-iommu.txt @@ -0,0 +1,89 @@ +BYPASS IOMMU PROPERTY +===================== + +Description +=========== +Traditionally, there is a global switch to enable/disable vIOMMU. All +devices in the system can only support go through vIOMMU or not, which +is not flexible. We introduce this bypass iommu property to support +coexist of devices go through vIOMMU and devices not. This is useful to +passthrough devices with no-iommu mode and devices go through vIOMMU in +the same virtual machine. + +PCI host bridges have a bypass_iommu property. This property is used to +determine whether the devices attached on the PCI host bridge will bypass +virtual iommu. The bypass_iommu property is valid only when there is a +virtual iommu in the system, it is implemented to allow some devices to +bypass vIOMMU. When bypass_iommu property is not set for a host bridge, +the attached devices will go through vIOMMU by default. + +Usage +===== +The bypass iommu feature support PXB host bridge and default main host +bridge, we add a bypass_iommu property for PXB and default_bus_bypass_iommu +for machine. Note that default_bus_bypass_iommu is available only when +the 'q35' machine type on x86 architecture and the 'virt' machine type +on AArch64. Other machine types do not support bypass iommu for default +root bus. + +1. The following is the bypass iommu options: + (1) PCI expander bridge + qemu -device pxb-pcie,bus_nr=0x10,addr=0x1,bypass_iommu=true + (2) Arm default host bridge + qemu -machine virt,iommu=smmuv3,default_bus_bypass_iommu=true + (3) X86 default root bus bypass iommu: + qemu -machine q35,default_bus_bypass_iommu=true + +2. Here is the detailed qemu command line for 'virt' machine with PXB on +AArch64: + +qemu-system-aarch64 \ + -machine virt,kernel_irqchip=on,iommu=smmuv3,default_bus_bypass_iommu=true \ + -device pxb-pcie,bus_nr=0x10,id=pci.10,bus=pcie.0,addr=0x3.0x1 \ + -device pxb-pcie,bus_nr=0x20,id=pci.20,bus=pcie.0,addr=0x3.0x2,bypass_iommu=true \ + +And we got: + - a default host bridge which bypass SMMUv3 + - a pxb host bridge which go through SMMUv3 + - a pxb host bridge which bypass SMMUv3 + +3. Here is the detailed qemu command line for 'q35' machine with PXB on +x86 architecture: + +qemu-system-x86_64 \ + -machine q35,accel=kvm,default_bus_bypass_iommu=true \ + -device pxb-pcie,bus_nr=0x10,id=pci.10,bus=pcie.0,addr=0x3 \ + -device pxb-pcie,bus_nr=0x20,id=pci.20,bus=pcie.0,addr=0x4,bypass_iommu=true \ + -device intel-iommu \ + +And we got: + - a default host bridge which bypass iommu + - a pxb host bridge which go through iommu + - a pxb host bridge which bypass iommu + +Limitations +=========== +There might be potential security risk when devices bypass iommu, because +devices might send malicious dma request to virtual machine if there is no +iommu isolation. So it would be necessary to only bypass iommu for trusted +device. + +Implementation +============== +The bypass iommu feature includes: + - Address space + Add bypass iommu property check of PCI Host and do not get iommu address + space for devices bypass iommu. + - Arm SMMUv3 support + We traverse all PCI root bus and get bus number ranges, then build explicit + RID mapping for devices which do not bypass iommu. + - X86 IOMMU support + To support Intel iommu, we traverse all PCI host bridge and get information + of devices which do not bypass iommu, then fill the DMAR drhd struct with + explicit device scope info. To support AMD iommu, add check of bypass iommu + when traverse the PCI hsot bridge. + - Machine and PXB options + We add bypass iommu options in machine option for default root bus, and add + option for PXB also. Note that the default value of bypass iommu is false, + so that the devices will by default go through iommu if there exist one. + From 1e08fd0a465d70ad30d2928c66537c816f0af7f8 Mon Sep 17 00:00:00 2001 From: Arseny Krasnov Date: Tue, 22 Jun 2021 17:47:47 +0300 Subject: [PATCH 190/531] vhost-vsock: SOCK_SEQPACKET feature bit support This adds processing of VIRTIO_VSOCK_F_SEQPACKET features bit. Guest negotiates it with vhost, thus both will know that SOCK_SEQPACKET supported by peer. Signed-off-by: Arseny Krasnov Message-Id: <20210622144747.2949134-1-arseny.krasnov@kaspersky.com> Reviewed-by: Stefano Garzarella Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vsock.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index 777cafe70d..1b1a5c70ed 100644 --- a/hw/virtio/vhost-vsock.c +++ b/hw/virtio/vhost-vsock.c @@ -21,6 +21,11 @@ #include "hw/virtio/vhost-vsock.h" #include "monitor/monitor.h" +const int feature_bits[] = { + VIRTIO_VSOCK_F_SEQPACKET, + VHOST_INVALID_FEATURE_BIT +}; + static void vhost_vsock_get_config(VirtIODevice *vdev, uint8_t *config) { VHostVSock *vsock = VHOST_VSOCK(vdev); @@ -108,8 +113,11 @@ static uint64_t vhost_vsock_get_features(VirtIODevice *vdev, uint64_t requested_features, Error **errp) { - /* No feature bits used yet */ - return requested_features; + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + + virtio_add_feature(&requested_features, VIRTIO_VSOCK_F_SEQPACKET); + return vhost_get_features(&vvc->vhost_dev, feature_bits, + requested_features); } static const VMStateDescription vmstate_virtio_vhost_vsock = { From d102058e795229f53a443a58d10d8b457e96acb4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 9 Jul 2021 16:06:21 -0700 Subject: [PATCH 191/531] target/arm: Fix offsets for TTBCR The functions vmsa_ttbcr_write and vmsa_ttbcr_raw_write expect the offset to be for the complete TCR structure, not the offset to the low 32-bits of a uint64_t. Using offsetoflow32 in this case breaks big-endian hosts. For TTBCR2, we do want the high 32-bits of a uint64_t. Use cp15.tcr_el[*].raw_tcr as the offsetofhigh32 argument to clarify this. Buglink: https://gitlab.com/qemu-project/qemu/-/issues/187 Signed-off-by: Richard Henderson Message-id: 20210709230621.938821-2-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 910ace4274..0c07ca9837 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4106,8 +4106,9 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { .access = PL1_RW, .accessfn = access_tvm_trvm, .type = ARM_CP_ALIAS, .writefn = vmsa_ttbcr_write, .raw_writefn = vmsa_ttbcr_raw_write, - .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tcr_el[3]), - offsetoflow32(CPUARMState, cp15.tcr_el[1])} }, + /* No offsetoflow32 -- pass the entire TCR to writefn/raw_writefn. */ + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.tcr_el[3]), + offsetof(CPUARMState, cp15.tcr_el[1])} }, REGINFO_SENTINEL }; @@ -4118,8 +4119,10 @@ static const ARMCPRegInfo ttbcr2_reginfo = { .name = "TTBCR2", .cp = 15, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 3, .access = PL1_RW, .accessfn = access_tvm_trvm, .type = ARM_CP_ALIAS, - .bank_fieldoffsets = { offsetofhigh32(CPUARMState, cp15.tcr_el[3]), - offsetofhigh32(CPUARMState, cp15.tcr_el[1]) }, + .bank_fieldoffsets = { + offsetofhigh32(CPUARMState, cp15.tcr_el[3].raw_tcr), + offsetofhigh32(CPUARMState, cp15.tcr_el[1].raw_tcr), + }, }; static void omap_ticonfig_write(CPUARMState *env, const ARMCPRegInfo *ri, From 955990af736a8cb2af7839d53b26ed8bb3b0633a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 5 Jul 2021 10:55:41 +0100 Subject: [PATCH 192/531] docs: Fix documentation Copyright date MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 6d8980a38fa we updated the copyright string we present to the user in -version output, About dialogs, etc, but we forgot that the Sphinx manuals have a separate copyright string setting. Update that one too. Signed-off-by: Peter Maydell Acked-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Message-id: 20210705095547.15790-2-peter.maydell@linaro.org --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 42729e22bb..ff6e92c6e2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -87,7 +87,7 @@ master_doc = 'index' # General information about the project. project = u'QEMU' -copyright = u'2020, The QEMU Project Developers' +copyright = u'2021, The QEMU Project Developers' author = u'The QEMU Project Developers' # The version info for the project you're documenting, acts as replacement for From b4634487c44bd1cc664f45b63c98161dfd170784 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 5 Jul 2021 10:55:42 +0100 Subject: [PATCH 193/531] docs: Stop calling the top level subsections of our manual 'manuals' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We merged our previous multiple-manual setup into a single Sphinx manual, but we left some text in the various index.rst lines that still calls the top level subsections separate 'manuals'. Update them to talk about "this section of the manual" instead, and remove now-obsolete comments about how the index.rst files are the "top level page for the 'foo' manual". Signed-off-by: Peter Maydell Acked-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Message-id: 20210705095547.15790-3-peter.maydell@linaro.org --- docs/devel/index.rst | 5 +---- docs/interop/index.rst | 7 ++----- docs/specs/index.rst | 5 ++--- docs/system/index.rst | 5 +---- docs/tools/index.rst | 5 ++--- docs/user/index.rst | 5 +---- 6 files changed, 9 insertions(+), 23 deletions(-) diff --git a/docs/devel/index.rst b/docs/devel/index.rst index 40a7e2ee6f..9299d2a502 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -1,10 +1,7 @@ -.. This is the top level page for the 'devel' manual. - - Developer Information ===================== -This manual documents various parts of the internals of QEMU. +This section of the manual documents various parts of the internals of QEMU. You only need to read it if you are interested in reading or modifying QEMU's source code. diff --git a/docs/interop/index.rst b/docs/interop/index.rst index 219a5e5fc5..8b34da6f55 100644 --- a/docs/interop/index.rst +++ b/docs/interop/index.rst @@ -1,11 +1,8 @@ -.. This is the top level page for the 'interop' manual. - - System Emulation Management and Interoperability ================================================ -This manual contains documents and specifications that are useful -for making QEMU interoperate with other software. +This section of the manual contains documents and specifications that +are useful for making QEMU interoperate with other software. Contents: diff --git a/docs/specs/index.rst b/docs/specs/index.rst index 7b08314d33..4c0d2a37cb 100644 --- a/docs/specs/index.rst +++ b/docs/specs/index.rst @@ -1,9 +1,8 @@ -.. This is the top level page for the 'specs' manual - - System Emulation Guest Hardware Specifications ============================================== +This section of the manual contains specifications of +guest hardware that is specific to QEMU. Contents: diff --git a/docs/system/index.rst b/docs/system/index.rst index 6092eb2d91..2a9bd75980 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -1,10 +1,7 @@ -.. This is the top level page for the 'system' manual. - - System Emulation ================ -This manual is the overall guide for users using QEMU +This section of the manual is the overall guide for users using QEMU for full system emulation (as opposed to user-mode emulation). This includes working with hypervisors such as KVM, Xen, Hax or Hypervisor.Framework. diff --git a/docs/tools/index.rst b/docs/tools/index.rst index d923834a73..ffb14b9690 100644 --- a/docs/tools/index.rst +++ b/docs/tools/index.rst @@ -1,9 +1,8 @@ -.. This is the top level page for the 'tools' manual - - Tools ===== +This section of the manual documents QEMU's "tools": its +command line utilities and other standalone programs. Contents: diff --git a/docs/user/index.rst b/docs/user/index.rst index a5b47459ec..6ac2ac089f 100644 --- a/docs/user/index.rst +++ b/docs/user/index.rst @@ -1,10 +1,7 @@ -.. This is the top level page for the 'user' manual. - - User Mode Emulation =================== -This manual is the overall guide for users using QEMU +This section of the manual is the overall guide for users using QEMU for user-mode emulation. In this mode, QEMU can launch processes compiled for one CPU on another CPU. From 21b6c26d632482a6633604f8c05c89669f37441f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 5 Jul 2021 10:55:43 +0100 Subject: [PATCH 194/531] docs: Remove "Contents:" lines from top-level subsections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the top-level subsections aren't self-contained manuals any more, the "Contents:" lines at the top of each of their index pages look a bit odd; remove them. Signed-off-by: Peter Maydell Acked-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Message-id: 20210705095547.15790-4-peter.maydell@linaro.org --- docs/devel/index.rst | 2 -- docs/interop/index.rst | 2 -- docs/specs/index.rst | 2 -- docs/system/index.rst | 2 -- docs/tools/index.rst | 2 -- docs/user/index.rst | 2 -- 6 files changed, 12 deletions(-) diff --git a/docs/devel/index.rst b/docs/devel/index.rst index 9299d2a502..153979caf4 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -5,8 +5,6 @@ This section of the manual documents various parts of the internals of QEMU. You only need to read it if you are interested in reading or modifying QEMU's source code. -Contents: - .. toctree:: :maxdepth: 2 :includehidden: diff --git a/docs/interop/index.rst b/docs/interop/index.rst index 8b34da6f55..b1bab81e2e 100644 --- a/docs/interop/index.rst +++ b/docs/interop/index.rst @@ -4,8 +4,6 @@ System Emulation Management and Interoperability This section of the manual contains documents and specifications that are useful for making QEMU interoperate with other software. -Contents: - .. toctree:: :maxdepth: 2 diff --git a/docs/specs/index.rst b/docs/specs/index.rst index 4c0d2a37cb..b7b08ea30d 100644 --- a/docs/specs/index.rst +++ b/docs/specs/index.rst @@ -4,8 +4,6 @@ System Emulation Guest Hardware Specifications This section of the manual contains specifications of guest hardware that is specific to QEMU. -Contents: - .. toctree:: :maxdepth: 2 diff --git a/docs/system/index.rst b/docs/system/index.rst index 2a9bd75980..058cabd36c 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -6,8 +6,6 @@ for full system emulation (as opposed to user-mode emulation). This includes working with hypervisors such as KVM, Xen, Hax or Hypervisor.Framework. -Contents: - .. toctree:: :maxdepth: 3 diff --git a/docs/tools/index.rst b/docs/tools/index.rst index ffb14b9690..ef6041a490 100644 --- a/docs/tools/index.rst +++ b/docs/tools/index.rst @@ -4,8 +4,6 @@ Tools This section of the manual documents QEMU's "tools": its command line utilities and other standalone programs. -Contents: - .. toctree:: :maxdepth: 2 diff --git a/docs/user/index.rst b/docs/user/index.rst index 6ac2ac089f..9faa4badd7 100644 --- a/docs/user/index.rst +++ b/docs/user/index.rst @@ -5,8 +5,6 @@ This section of the manual is the overall guide for users using QEMU for user-mode emulation. In this mode, QEMU can launch processes compiled for one CPU on another CPU. -Contents: - .. toctree:: :maxdepth: 2 From f347839258a1ace57d0b59e89bf01352b8d1c13b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 5 Jul 2021 10:55:44 +0100 Subject: [PATCH 195/531] docs: Move deprecation, build and license info out of system/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we have a single Sphinx manual rather than multiple manuals, we can provide a better place for "common to all of QEMU" information like the deprecation notices, build platforms, license information, which we currently have in the system/ manual even though it applies to all of QEMU. Create a new directory about/ on the same level as system/, user/, etc, and move these documents there. Signed-off-by: Peter Maydell Acked-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Message-id: 20210705095547.15790-5-peter.maydell@linaro.org --- docs/{system => about}/build-platforms.rst | 0 docs/{system => about}/deprecated.rst | 0 docs/about/index.rst | 10 ++++++++++ docs/{system => about}/license.rst | 0 docs/{system => about}/removed-features.rst | 0 docs/index.rst | 1 + docs/system/index.rst | 4 ---- 7 files changed, 11 insertions(+), 4 deletions(-) rename docs/{system => about}/build-platforms.rst (100%) rename docs/{system => about}/deprecated.rst (100%) create mode 100644 docs/about/index.rst rename docs/{system => about}/license.rst (100%) rename docs/{system => about}/removed-features.rst (100%) diff --git a/docs/system/build-platforms.rst b/docs/about/build-platforms.rst similarity index 100% rename from docs/system/build-platforms.rst rename to docs/about/build-platforms.rst diff --git a/docs/system/deprecated.rst b/docs/about/deprecated.rst similarity index 100% rename from docs/system/deprecated.rst rename to docs/about/deprecated.rst diff --git a/docs/about/index.rst b/docs/about/index.rst new file mode 100644 index 0000000000..cd44456a6b --- /dev/null +++ b/docs/about/index.rst @@ -0,0 +1,10 @@ +About QEMU +========== + +.. toctree:: + :maxdepth: 2 + + build-platforms + deprecated + removed-features + license diff --git a/docs/system/license.rst b/docs/about/license.rst similarity index 100% rename from docs/system/license.rst rename to docs/about/license.rst diff --git a/docs/system/removed-features.rst b/docs/about/removed-features.rst similarity index 100% rename from docs/system/removed-features.rst rename to docs/about/removed-features.rst diff --git a/docs/index.rst b/docs/index.rst index 763e3d0426..5f7eaaa632 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -10,6 +10,7 @@ Welcome to QEMU's documentation! :maxdepth: 2 :caption: Contents: + about/index system/index user/index tools/index diff --git a/docs/system/index.rst b/docs/system/index.rst index 058cabd36c..fda4b1b705 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -35,7 +35,3 @@ or Hypervisor.Framework. targets security multi-process - deprecated - removed-features - build-platforms - license From 4a43fa3af926bb2ceef8f7ed188a41c70e0e8477 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 5 Jul 2021 10:55:45 +0100 Subject: [PATCH 196/531] docs: Add some actual About text to about/index.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add some text to About to act as a brief introduction to the QEMU manual and to make the about page a bit less of an abrupt start to it. Signed-off-by: Peter Maydell Acked-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Message-id: 20210705095547.15790-6-peter.maydell@linaro.org --- docs/about/index.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/about/index.rst b/docs/about/index.rst index cd44456a6b..689a9861dc 100644 --- a/docs/about/index.rst +++ b/docs/about/index.rst @@ -1,6 +1,23 @@ About QEMU ========== +QEMU is a generic and open source machine emulator and virtualizer. + +QEMU can be used in several different ways. The most common is for +"system emulation", where it provides a virtual model of an +entire machine (CPU, memory and emulated devices) to run a guest OS. +In this mode the CPU may be fully emulated, or it may work with +a hypervisor such as KVM, Xen, Hax or Hypervisor.Framework to +allow the guest to run directly on the host CPU. + +The second supported way to use QEMU is "user mode emulation", +where QEMU can launch processes compiled for one CPU on another CPU. +In this mode the CPU is always emulated. + +QEMU also provides a number of standalone commandline utilities, +such as the `qemu-img` disk image utility that allows you to create, +convert and modify disk images. + .. toctree:: :maxdepth: 2 From 13f934e79fa72d28a2c7de584a45c646b65d524f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 5 Jul 2021 10:55:46 +0100 Subject: [PATCH 197/531] docs: Add license note to the HTML page footer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The standard Sphinx/RTD HTML page footer gives a copyright line (based on the 'copyright' variable set in conf.py) and a line "Built with Sphinx using a theme provided by Read the Docs" (which can be disabled via the html_show_sphinx variable, but we leave it enabled). As a free software project, we'd like to also mention the license QEMU and its manual are released under. Add a template footer.html which defines the 'extrafooter' block that the RtD theme provides for this purpose. The new line of text will go below the existing copyright and sphinx-acknowledgement lines. (Unfortunately the RTD footer template does not permit putting it after the copyright but before the sphinx-acknowledgement.) We use the templating functionality to make the new text also be a hyperlink to the about/license.html page of the manual. Unlike rst files, HTML template files are not reported to our depfile plugin, so we maintain a manual list in meson.build. New template files should be rare, so not being able to auto-generate the dependency info is not too awkward. Signed-off-by: Peter Maydell Acked-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Message-id: 20210705095547.15790-7-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/_templates/footer.html | 12 ++++++++++++ docs/meson.build | 3 ++- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 docs/_templates/footer.html diff --git a/MAINTAINERS b/MAINTAINERS index 9100f9a043..814d103fe1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3451,6 +3451,7 @@ S: Maintained F: docs/conf.py F: docs/*/conf.py F: docs/sphinx/ +F: docs/_templates/ Miscellaneous ------------- diff --git a/docs/_templates/footer.html b/docs/_templates/footer.html new file mode 100644 index 0000000000..4c15e17d2a --- /dev/null +++ b/docs/_templates/footer.html @@ -0,0 +1,12 @@ +{% extends "!footer.html" %} +{% block extrafooter %} + + +

+ +{% trans path=pathto('about/license') %} +

QEMU and this manual are released under the +GNU General Public License, version 2.

+{% endtrans %} +{{ super() }} +{% endblock %} diff --git a/docs/meson.build b/docs/meson.build index 855e3916e9..300b134329 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -44,6 +44,7 @@ if build_docs meson.source_root() / 'docs/sphinx/qapidoc.py', meson.source_root() / 'docs/sphinx/qmp_lexer.py', qapi_gen_depends ] + sphinx_template_files = [ meson.source_root() / 'docs/_templates/footer.html' ] have_ga = have_tools and config_host.has_key('CONFIG_GUEST_AGENT') @@ -76,7 +77,7 @@ if build_docs output: 'docs.stamp', input: files('conf.py'), depfile: 'docs.d', - depend_files: sphinx_extn_depends, + depend_files: [ sphinx_extn_depends, sphinx_template_files ], command: [SPHINX_ARGS, '-Ddepfile=@DEPFILE@', '-Ddepfile_stamp=@OUTPUT0@', '-b', 'html', '-d', private_dir, From 3a50c8f3067aaf344a568b8de6a68887ee55bc21 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 5 Jul 2021 10:55:47 +0100 Subject: [PATCH 198/531] docs: Add QEMU version information to HTML footer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a line to the HTML document footer mentioning the QEMU version. The version information is already provided in very faint text below the QEMU logo in the sidebar, but that is rather inconspicious, so repeating it in the footer seems useful. Signed-off-by: Peter Maydell Acked-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Message-id: 20210705095547.15790-8-peter.maydell@linaro.org --- docs/_templates/footer.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/_templates/footer.html b/docs/_templates/footer.html index 4c15e17d2a..977053b541 100644 --- a/docs/_templates/footer.html +++ b/docs/_templates/footer.html @@ -4,6 +4,8 @@

+

This documentation is for QEMU version {{ version }}.

+ {% trans path=pathto('about/license') %}

QEMU and this manual are released under the GNU General Public License, version 2.

From d4a7c362fe50bbdfd0a02b1a2c1fdf57e98bba79 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 13 Jul 2021 15:22:24 +0100 Subject: [PATCH 199/531] docs: Add skeletal documentation of cubieboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add skeletal documentation of the cubieboard machine. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210713142226.19155-2-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/system/arm/cubieboard.rst | 16 ++++++++++++++++ docs/system/target-arm.rst | 1 + 3 files changed, 18 insertions(+) create mode 100644 docs/system/arm/cubieboard.rst diff --git a/MAINTAINERS b/MAINTAINERS index 814d103fe1..1596b352b4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -560,6 +560,7 @@ S: Odd Fixes F: hw/*/allwinner* F: include/hw/*/allwinner* F: hw/arm/cubieboard.c +F: docs/system/arm/cubieboard.rst Allwinner-h3 M: Niek Linnenbank diff --git a/docs/system/arm/cubieboard.rst b/docs/system/arm/cubieboard.rst new file mode 100644 index 0000000000..344ff8cef9 --- /dev/null +++ b/docs/system/arm/cubieboard.rst @@ -0,0 +1,16 @@ +Cubietech Cubieboard (``cubieboard``) +===================================== + +The ``cubieboard`` model emulates the Cubietech Cubieboard, +which is a Cortex-A8 based single-board computer using +the AllWinner A10 SoC. + +Emulated devices: + +- Timer +- UART +- RTC +- EMAC +- SDHCI +- USB controller +- SATA controller diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index 705b8835e4..e2fcb64872 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -85,6 +85,7 @@ undocumented; you can get a complete list by running arm/aspeed arm/sabrelite arm/digic + arm/cubieboard arm/musicpal arm/gumstix arm/nrf From 3f65df38e8a5e75ccfd5a641d252ad8882c9e68c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 13 Jul 2021 15:22:25 +0100 Subject: [PATCH 200/531] docs: Add skeletal documentation of the emcraft-sf2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add skeletal documentation of the emcraft-sf2 machine. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210713142226.19155-3-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/system/arm/emcraft-sf2.rst | 15 +++++++++++++++ docs/system/target-arm.rst | 1 + 3 files changed, 17 insertions(+) create mode 100644 docs/system/arm/emcraft-sf2.rst diff --git a/MAINTAINERS b/MAINTAINERS index 1596b352b4..1504951823 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1024,6 +1024,7 @@ M: Peter Maydell L: qemu-arm@nongnu.org S: Maintained F: hw/arm/msf2-som.c +F: docs/system/arm/emcraft-sf2.rst ASPEED BMCs M: Cédric Le Goater diff --git a/docs/system/arm/emcraft-sf2.rst b/docs/system/arm/emcraft-sf2.rst new file mode 100644 index 0000000000..377e248720 --- /dev/null +++ b/docs/system/arm/emcraft-sf2.rst @@ -0,0 +1,15 @@ +Emcraft SmartFusion2 SOM kit (``emcraft-sf2``) +============================================== + +The ``emcraft-sf2`` board emulates the SmartFusion2 SOM kit from +Emcraft (M2S010). This is a System-on-Module from EmCraft systems, +based on the SmartFusion2 SoC FPGA from Microsemi Corporation. +The SoC is based on a Cortex-M4 processor. + +Emulated devices: + +- System timer +- System registers +- SPI controller +- UART +- EMAC diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index e2fcb64872..c52902acda 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -86,6 +86,7 @@ undocumented; you can get a complete list by running arm/sabrelite arm/digic arm/cubieboard + arm/emcraft-sf2 arm/musicpal arm/gumstix arm/nrf From c90df7ce4ef50f9cea3c42daea4fc167bb0d9d2e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 13 Jul 2021 15:22:26 +0100 Subject: [PATCH 201/531] docs: Add skeletal documentation of highbank and midway MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add skeletal documentation for the highbank and midway machines. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210713142226.19155-4-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/system/arm/highbank.rst | 19 +++++++++++++++++++ docs/system/target-arm.rst | 1 + 3 files changed, 21 insertions(+) create mode 100644 docs/system/arm/highbank.rst diff --git a/MAINTAINERS b/MAINTAINERS index 1504951823..4256ad1adb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -643,6 +643,7 @@ L: qemu-arm@nongnu.org S: Odd Fixes F: hw/arm/highbank.c F: hw/net/xgmac.c +F: docs/system/arm/highbank.rst Canon DIGIC M: Antony Pavlov diff --git a/docs/system/arm/highbank.rst b/docs/system/arm/highbank.rst new file mode 100644 index 0000000000..bb4965b367 --- /dev/null +++ b/docs/system/arm/highbank.rst @@ -0,0 +1,19 @@ +Calxeda Highbank and Midway (``highbank``, ``midway``) +====================================================== + +``highbank`` is a model of the Calxeda Highbank (ECX-1000) system, +which has four Cortex-A9 cores. + +``midway`` is a model of the Calxeda Midway (ECX-2000) system, +which has four Cortex-A15 cores. + +Emulated devices: + +- L2x0 cache controller +- SP804 dual timer +- PL011 UART +- PL061 GPIOs +- PL031 RTC +- PL022 synchronous serial port controller +- AHCI +- XGMAC ethernet controllers diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index c52902acda..c0c2585c0a 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -87,6 +87,7 @@ undocumented; you can get a complete list by running arm/digic arm/cubieboard arm/emcraft-sf2 + arm/highbank arm/musicpal arm/gumstix arm/nrf From 8fe612a183dec4c63afdc57537079bc742d024ca Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 15 Jul 2021 10:53:41 +0100 Subject: [PATCH 202/531] target/arm: Remove duplicate 'plus1' function from Neon and SVE decode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Neon and SVE decoders use private 'plus1' functions to implement "add one" for the !function decoder syntax. We have a generic "plus_1" function in translate.h, so use that instead. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210715095341.701-1-peter.maydell@linaro.org --- target/arm/neon-ls.decode | 4 ++-- target/arm/neon-shared.decode | 2 +- target/arm/sve.decode | 2 +- target/arm/translate-neon.c | 5 ----- target/arm/translate-sve.c | 5 ----- 5 files changed, 4 insertions(+), 14 deletions(-) diff --git a/target/arm/neon-ls.decode b/target/arm/neon-ls.decode index 0a2a0e15db..c5f364cbc0 100644 --- a/target/arm/neon-ls.decode +++ b/target/arm/neon-ls.decode @@ -41,8 +41,8 @@ VLD_all_lanes 1111 0100 1 . 1 0 rn:4 .... 11 n:2 size:2 t:1 a:1 rm:4 \ vd=%vd_dp # Neon load/store single structure to one lane -%imm1_5_p1 5:1 !function=plus1 -%imm1_6_p1 6:1 !function=plus1 +%imm1_5_p1 5:1 !function=plus_1 +%imm1_6_p1 6:1 !function=plus_1 VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 00 n:2 reg_idx:3 align:1 rm:4 \ vd=%vd_dp size=0 stride=1 diff --git a/target/arm/neon-shared.decode b/target/arm/neon-shared.decode index df80e6ebf6..8e6bd0b61f 100644 --- a/target/arm/neon-shared.decode +++ b/target/arm/neon-shared.decode @@ -38,7 +38,7 @@ # which is 0 for fp16 and 1 for fp32 into a MO_* constant. # (Note that this is the reverse of the sense of the 1-bit size # field in the 3same_fp Neon insns.) -%vcadd_size 20:1 !function=plus1 +%vcadd_size 20:1 !function=plus_1 VCMLA 1111 110 rot:2 . 1 . .... .... 1000 . q:1 . 0 .... \ vm=%vm_dp vn=%vn_dp vd=%vd_dp size=%vcadd_size diff --git a/target/arm/sve.decode b/target/arm/sve.decode index a62c169f1a..c60b9f0fec 100644 --- a/target/arm/sve.decode +++ b/target/arm/sve.decode @@ -22,7 +22,7 @@ ########################################################################### # Named fields. These are primarily for disjoint fields. -%imm4_16_p1 16:4 !function=plus1 +%imm4_16_p1 16:4 !function=plus_1 %imm6_22_5 22:1 5:5 %imm7_22_16 22:2 16:5 %imm8_16_10 16:5 10:3 diff --git a/target/arm/translate-neon.c b/target/arm/translate-neon.c index a45616cb63..c53ab20fa4 100644 --- a/target/arm/translate-neon.c +++ b/target/arm/translate-neon.c @@ -28,11 +28,6 @@ #include "translate.h" #include "translate-a32.h" -static inline int plus1(DisasContext *s, int x) -{ - return x + 1; -} - static inline int neon_3same_fp_size(DisasContext *s, int x) { /* Convert 0==fp32, 1==fp16 into a MO_* value */ diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 35d838aa06..bc91a64171 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -70,11 +70,6 @@ static int tszimm_shl(DisasContext *s, int x) return x - (8 << tszimm_esz(s, 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(DisasContext *s, int x) { From 8619b5ddb56f562c751bcdac2328abcbff37fdeb Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 23 Jun 2021 11:11:35 +0200 Subject: [PATCH 203/531] ci: build & store windows installer Build windows installer for qemu in gitlab CI, store the result as artifact. Signed-off-by: Gerd Hoffmann Reviewed-by: Willian Rampazzo Reviewed-by: Thomas Huth Message-Id: <20210623091137.1156959-2-kraxel@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/crossbuild-template.yml | 5 +++++ .gitlab-ci.d/crossbuilds.yml | 6 ++++++ tests/docker/dockerfiles/fedora-win64-cross.docker | 1 + 3 files changed, 12 insertions(+) diff --git a/.gitlab-ci.d/crossbuild-template.yml b/.gitlab-ci.d/crossbuild-template.yml index 1be541174c..7d3ad00a1e 100644 --- a/.gitlab-ci.d/crossbuild-template.yml +++ b/.gitlab-ci.d/crossbuild-template.yml @@ -11,6 +11,11 @@ i386-softmmu microblaze-softmmu mips-softmmu mipsel-softmmu mips64-softmmu ppc-softmmu sh4-softmmu xtensa-softmmu" - make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS + - if grep -q "EXESUF=.exe" config-host.mak; + then make installer; + version="$(git describe --match v[0-9]*)"; + mv -v qemu-setup*.exe qemu-setup-${version}.exe; + fi # Job to cross-build specific accelerators. # diff --git a/.gitlab-ci.d/crossbuilds.yml b/.gitlab-ci.d/crossbuilds.yml index 6b3865c9e8..4ff3aa3cfc 100644 --- a/.gitlab-ci.d/crossbuilds.yml +++ b/.gitlab-ci.d/crossbuilds.yml @@ -160,6 +160,9 @@ cross-win32-system: job: win32-fedora-cross-container variables: IMAGE: fedora-win32-cross + artifacts: + paths: + - build/qemu-setup*.exe cross-win64-system: extends: .cross_system_build_job @@ -167,6 +170,9 @@ cross-win64-system: job: win64-fedora-cross-container variables: IMAGE: fedora-win64-cross + artifacts: + paths: + - build/qemu-setup*.exe cross-amd64-xen-only: extends: .cross_accel_build_job diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index ff706040c4..d3f13666e8 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -13,6 +13,7 @@ ENV PACKAGES \ hostname \ make \ meson \ + mingw32-nsis \ mingw64-bzip2 \ mingw64-curl \ mingw64-glib2 \ From 659eb157a55666bf379f5362238a86d855e262e2 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 15 Jul 2021 10:39:28 +0200 Subject: [PATCH 204/531] configure: Fix endianess test with LTO If a user is trying to compile QEMU with link-time optimization enabled by running the configure script like this: .../configure --extra-cflags="-flto" then the endianess test is failing since the magic values do not show up in the intermediate object files there. If the host is a big endian machine (like s390x), the QEMU binary is then unusable since the corresponding variable "bigendian" is pre-initialized with "no". To fix this issue, we should rather create a full binary and look for the magic strings there instead. And we really should not continue the build if the endianess check failed, to make it clear right from the start that something went wrong here, thus let's also add some "exit 1" statements here after emitting the error message. Message-Id: <20210715083928.933806-1-thuth@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth --- configure | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/configure b/configure index 49b5481139..63f38fa94c 100755 --- a/configure +++ b/configure @@ -2365,24 +2365,27 @@ feature_not_found() { # --- # big/little endian test cat > $TMPC << EOF +#include short big_endian[] = { 0x4269, 0x4765, 0x4e64, 0x4961, 0x4e00, 0, }; short little_endian[] = { 0x694c, 0x7454, 0x654c, 0x6e45, 0x6944, 0x6e41, 0, }; -extern int foo(short *, short *); -int main(int argc, char *argv[]) { - return foo(big_endian, little_endian); +int main(int argc, char *argv[]) +{ + return printf("%s %s\n", (char *)big_endian, (char *)little_endian); } EOF -if compile_object ; then - if strings -a $TMPO | grep -q BiGeNdIaN ; then +if compile_prog ; then + if strings -a $TMPE | grep -q BiGeNdIaN ; then bigendian="yes" - elif strings -a $TMPO | grep -q LiTtLeEnDiAn ; then + elif strings -a $TMPE | grep -q LiTtLeEnDiAn ; then bigendian="no" else echo big/little test failed + exit 1 fi else echo big/little test failed + exit 1 fi ########################################## From 6a932c4ed8748b08c58cdba3fc9485d5549aacca Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 15 Jul 2021 12:37:55 +0200 Subject: [PATCH 205/531] hw/net/vmxnet3: Do not abort if the guest is trying to use an invalid TX queue QEMU should never abort just because the guest is doing something odd. Let's simply log the error and ignore the bad transmit queue instead. Buglink: https://bugs.launchpad.net/qemu/+bug/1926111 Message-Id: <20210715103755.1035566-1-thuth@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth --- hw/net/vmxnet3.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index eff299f629..f6bd8c53b1 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -23,6 +23,7 @@ #include "net/checksum.h" #include "sysemu/sysemu.h" #include "qemu/bswap.h" +#include "qemu/log.h" #include "qemu/module.h" #include "hw/pci/msix.h" #include "hw/pci/msi.h" @@ -1093,8 +1094,12 @@ vmxnet3_io_bar0_write(void *opaque, hwaddr addr, int tx_queue_idx = VMW_MULTIREG_IDX_BY_ADDR(addr, VMXNET3_REG_TXPROD, VMXNET3_REG_ALIGN); - assert(tx_queue_idx <= s->txq_num); - vmxnet3_process_tx_queue(s, tx_queue_idx); + if (tx_queue_idx <= s->txq_num) { + vmxnet3_process_tx_queue(s, tx_queue_idx); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "vmxnet3: Illegal TX queue %d/%d\n", + tx_queue_idx, s->txq_num); + } return; } From 283f0a05e24a5e5fab78305f783f06215390d620 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 15 Jul 2021 21:32:19 +0200 Subject: [PATCH 206/531] hw/net/net_tx_pkt: Fix crash detected by fuzzer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU currently crashes when it's started like this: cat << EOF | ./qemu-system-i386 -device vmxnet3 -nodefaults -qtest stdio outl 0xcf8 0x80001014 outl 0xcfc 0xe0001000 outl 0xcf8 0x80001018 outl 0xcf8 0x80001004 outw 0xcfc 0x7 outl 0xcf8 0x80001083 write 0x0 0x1 0xe1 write 0x1 0x1 0xfe write 0x2 0x1 0xbe write 0x3 0x1 0xba writeq 0xe0001020 0xefefff5ecafe0000 writeq 0xe0001020 0xffff5e5ccafe0002 EOF It hits this assertion: qemu-system-i386: ../qemu/hw/net/net_tx_pkt.c:453: net_tx_pkt_reset: Assertion `pkt->raw' failed. This happens because net_tx_pkt_init() is called with max_frags == 0 and thus the allocation p->raw = g_new(struct iovec, max_frags); results in a NULL pointer that causes the assert(pkt->raw); in net_tx_pkt_reset() to fail later. To fix this issue we can check that max_raw_frags was not zero before asserting that pkt->raw is a non-NULL pointer. Buglink: https://bugs.launchpad.net/qemu/+bug/1890157 Message-Id: <20210715193219.1132571-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pankaj Gupta Signed-off-by: Thomas Huth --- hw/net/net_tx_pkt.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c index 1f9aa59eca..1cb1125d9f 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/net_tx_pkt.c @@ -450,11 +450,13 @@ void net_tx_pkt_reset(struct NetTxPkt *pkt) pkt->payload_len = 0; pkt->payload_frags = 0; - assert(pkt->raw); - for (i = 0; i < pkt->raw_frags; i++) { - assert(pkt->raw[i].iov_base); - pci_dma_unmap(pkt->pci_dev, pkt->raw[i].iov_base, pkt->raw[i].iov_len, - DMA_DIRECTION_TO_DEVICE, 0); + if (pkt->max_raw_frags > 0) { + assert(pkt->raw); + for (i = 0; i < pkt->raw_frags; i++) { + assert(pkt->raw[i].iov_base); + pci_dma_unmap(pkt->pci_dev, pkt->raw[i].iov_base, + pkt->raw[i].iov_len, DMA_DIRECTION_TO_DEVICE, 0); + } } pkt->raw_frags = 0; From 9405d87be25db6dff4d7b5ab48a81bbf6d083e47 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 16 Apr 2021 14:52:56 +0200 Subject: [PATCH 207/531] hw/ide: Fix crash when plugging a piix3-ide device into the x-remote machine QEMU currently crashes when the user tries to do something like: qemu-system-x86_64 -M x-remote -device piix3-ide This happens because the "isabus" variable is not initialized with the x-remote machine yet. Add a proper check for this condition and propagate the error to the caller, so we can fail there gracefully. Message-Id: <20210416125256.2039734-1-thuth@redhat.com> Reviewed-by: John Snow Signed-off-by: Thomas Huth --- hw/ide/ioport.c | 16 ++++++++++------ hw/ide/piix.c | 22 +++++++++++++++++----- hw/isa/isa-bus.c | 14 ++++++++++---- include/hw/ide/internal.h | 2 +- include/hw/isa/isa.h | 13 ++++++++----- 5 files changed, 46 insertions(+), 21 deletions(-) diff --git a/hw/ide/ioport.c b/hw/ide/ioport.c index b613ff3bba..e6caa537fa 100644 --- a/hw/ide/ioport.c +++ b/hw/ide/ioport.c @@ -50,15 +50,19 @@ static const MemoryRegionPortio ide_portio2_list[] = { PORTIO_END_OF_LIST(), }; -void ide_init_ioport(IDEBus *bus, ISADevice *dev, int iobase, int iobase2) +int ide_init_ioport(IDEBus *bus, ISADevice *dev, int iobase, int iobase2) { + int ret; + /* ??? Assume only ISA and PCI configurations, and that the PCI-ISA bridge has been setup properly to always register with ISA. */ - isa_register_portio_list(dev, &bus->portio_list, - iobase, ide_portio_list, bus, "ide"); + ret = isa_register_portio_list(dev, &bus->portio_list, + iobase, ide_portio_list, bus, "ide"); - if (iobase2) { - isa_register_portio_list(dev, &bus->portio2_list, - iobase2, ide_portio2_list, bus, "ide"); + if (ret == 0 && iobase2) { + ret = isa_register_portio_list(dev, &bus->portio2_list, + iobase2, ide_portio2_list, bus, "ide"); } + + return ret; } diff --git a/hw/ide/piix.c b/hw/ide/piix.c index b9860e35a5..d3e738320b 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "hw/pci/pci.h" #include "migration/vmstate.h" +#include "qapi/error.h" #include "qemu/module.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" @@ -123,7 +124,8 @@ static void piix_ide_reset(DeviceState *dev) pci_conf[0x20] = 0x01; /* BMIBA: 20-23h */ } -static void pci_piix_init_ports(PCIIDEState *d) { +static int pci_piix_init_ports(PCIIDEState *d) +{ static const struct { int iobase; int iobase2; @@ -132,24 +134,30 @@ static void pci_piix_init_ports(PCIIDEState *d) { {0x1f0, 0x3f6, 14}, {0x170, 0x376, 15}, }; - int i; + int i, ret; for (i = 0; i < 2; i++) { ide_bus_new(&d->bus[i], sizeof(d->bus[i]), DEVICE(d), i, 2); - ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase, - port_info[i].iobase2); + ret = ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase, + port_info[i].iobase2); + if (ret) { + return ret; + } ide_init2(&d->bus[i], isa_get_irq(NULL, port_info[i].isairq)); bmdma_init(&d->bus[i], &d->bmdma[i], d); d->bmdma[i].bus = &d->bus[i]; ide_register_restart_cb(&d->bus[i]); } + + return 0; } static void pci_piix_ide_realize(PCIDevice *dev, Error **errp) { PCIIDEState *d = PCI_IDE(dev); uint8_t *pci_conf = dev->config; + int rc; pci_conf[PCI_CLASS_PROG] = 0x80; // legacy ATA mode @@ -158,7 +166,11 @@ static void pci_piix_ide_realize(PCIDevice *dev, Error **errp) vmstate_register(VMSTATE_IF(dev), 0, &vmstate_ide_pci, d); - pci_piix_init_ports(d); + rc = pci_piix_init_ports(d); + if (rc) { + error_setg_errno(errp, -rc, "Failed to realize %s", + object_get_typename(OBJECT(dev))); + } } int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux) diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 7820068e6e..cffaa35e9c 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -131,13 +131,17 @@ void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start) isa_init_ioport(dev, start); } -void isa_register_portio_list(ISADevice *dev, - PortioList *piolist, uint16_t start, - const MemoryRegionPortio *pio_start, - void *opaque, const char *name) +int isa_register_portio_list(ISADevice *dev, + PortioList *piolist, uint16_t start, + const MemoryRegionPortio *pio_start, + void *opaque, const char *name) { assert(piolist && !piolist->owner); + if (!isabus) { + return -ENODEV; + } + /* START is how we should treat DEV, regardless of the actual contents of the portio array. This is how the old code actually handled e.g. the FDC device. */ @@ -145,6 +149,8 @@ void isa_register_portio_list(ISADevice *dev, portio_list_init(piolist, OBJECT(dev), pio_start, opaque, name); portio_list_add(piolist, isabus->address_space_io, start); + + return 0; } static void isa_device_init(Object *obj) diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h index 2d09162eeb..79172217cc 100644 --- a/include/hw/ide/internal.h +++ b/include/hw/ide/internal.h @@ -624,7 +624,7 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, int chs_trans, Error **errp); void ide_init2(IDEBus *bus, qemu_irq irq); void ide_exit(IDEState *s); -void ide_init_ioport(IDEBus *bus, ISADevice *isa, int iobase, int iobase2); +int ide_init_ioport(IDEBus *bus, ISADevice *isa, int iobase, int iobase2); void ide_register_restart_cb(IDEBus *bus); void ide_exec_cmd(IDEBus *bus, uint32_t val); diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index ddaae89a85..d4417b34b6 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -132,12 +132,15 @@ void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start); * @portio: the ports, sorted by offset. * @opaque: passed into the portio callbacks. * @name: passed into memory_region_init_io. + * + * Returns: 0 on success, negative error code otherwise (e.g. if the + * ISA bus is not available) */ -void isa_register_portio_list(ISADevice *dev, - PortioList *piolist, - uint16_t start, - const MemoryRegionPortio *portio, - void *opaque, const char *name); +int isa_register_portio_list(ISADevice *dev, + PortioList *piolist, + uint16_t start, + const MemoryRegionPortio *portio, + void *opaque, const char *name); static inline ISABus *isa_bus_from_device(ISADevice *d) { From 69d0690c10083f21c7daaac544a44589a3ee34fc Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Mon, 14 Jun 2021 10:29:26 +0200 Subject: [PATCH 208/531] blkdebug: refactor removal of a suspended request Extract to a separate function. Do not rely on FOREACH_SAFE, which is only "safe" if the *current* node is removed---not if another node is removed. Instead, just walk the entire list from the beginning when asked to resume all suspended requests with a given tag. Co-developed-by: Paolo Bonzini Signed-off-by: Emanuele Giuseppe Esposito Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20210614082931.24925-2-eesposit@redhat.com> Signed-off-by: Max Reitz --- block/blkdebug.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/block/blkdebug.c b/block/blkdebug.c index 2c0b9b0ee8..5ccbfcab42 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -793,7 +793,6 @@ static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) printf("blkdebug: Resuming request '%s'\n", r.tag); } - QLIST_REMOVE(&r, next); g_free(r.tag); } @@ -869,25 +868,40 @@ static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, return 0; } -static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) +static int resume_req_by_tag(BDRVBlkdebugState *s, const char *tag, bool all) { - BDRVBlkdebugState *s = bs->opaque; - BlkdebugSuspendedReq *r, *next; + BlkdebugSuspendedReq *r; - QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) { +retry: + /* + * No need for _SAFE, since a different coroutine can remove another node + * (not the current one) in this list, and when the current one is removed + * the iteration starts back from beginning anyways. + */ + QLIST_FOREACH(r, &s->suspended_reqs, next) { if (!strcmp(r->tag, tag)) { + QLIST_REMOVE(r, next); qemu_coroutine_enter(r->co); + if (all) { + goto retry; + } return 0; } } return -ENOENT; } +static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) +{ + BDRVBlkdebugState *s = bs->opaque; + + return resume_req_by_tag(s, tag, false); +} + static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs, const char *tag) { BDRVBlkdebugState *s = bs->opaque; - BlkdebugSuspendedReq *r, *r_next; BlkdebugRule *rule, *next; int i, ret = -ENOENT; @@ -900,11 +914,8 @@ static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs, } } } - QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) { - if (!strcmp(r->tag, tag)) { - qemu_coroutine_enter(r->co); - ret = 0; - } + if (resume_req_by_tag(s, tag, true) == 0) { + ret = 0; } return ret; } From f48ff5af13eed0d2b39fdb91a37ed45fa3429e89 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Mon, 14 Jun 2021 10:29:27 +0200 Subject: [PATCH 209/531] blkdebug: move post-resume handling to resume_req_by_tag We want to move qemu_coroutine_yield() after the loop on rules, because QLIST_FOREACH_SAFE is wrong if the rule list is modified while the coroutine has yielded. Therefore move the suspended request to the heap and clean it up from the remove side. All that is left is for blkdebug_debug_event to handle the yielding. Co-developed-by: Paolo Bonzini Signed-off-by: Emanuele Giuseppe Esposito Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20210614082931.24925-3-eesposit@redhat.com> Signed-off-by: Max Reitz --- block/blkdebug.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/block/blkdebug.c b/block/blkdebug.c index 5ccbfcab42..e8fdf7b056 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -775,25 +775,20 @@ static void blkdebug_close(BlockDriverState *bs) static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) { BDRVBlkdebugState *s = bs->opaque; - BlkdebugSuspendedReq r; + BlkdebugSuspendedReq *r; - r = (BlkdebugSuspendedReq) { - .co = qemu_coroutine_self(), - .tag = g_strdup(rule->options.suspend.tag), - }; + r = g_new(BlkdebugSuspendedReq, 1); + + r->co = qemu_coroutine_self(); + r->tag = g_strdup(rule->options.suspend.tag); remove_rule(rule); - QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next); + QLIST_INSERT_HEAD(&s->suspended_reqs, r, next); if (!qtest_enabled()) { - printf("blkdebug: Suspended request '%s'\n", r.tag); + printf("blkdebug: Suspended request '%s'\n", r->tag); } qemu_coroutine_yield(); - if (!qtest_enabled()) { - printf("blkdebug: Resuming request '%s'\n", r.tag); - } - - g_free(r.tag); } static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, @@ -880,8 +875,18 @@ retry: */ QLIST_FOREACH(r, &s->suspended_reqs, next) { if (!strcmp(r->tag, tag)) { + Coroutine *co = r->co; + + if (!qtest_enabled()) { + printf("blkdebug: Resuming request '%s'\n", r->tag); + } + QLIST_REMOVE(r, next); - qemu_coroutine_enter(r->co); + g_free(r->tag); + g_free(r); + + qemu_coroutine_enter(co); + if (all) { goto retry; } From 51a463680d5620c15b8e88e73c75e4692553c3b5 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Mon, 14 Jun 2021 10:29:28 +0200 Subject: [PATCH 210/531] blkdebug: track all actions Add a counter for each action that a rule can trigger. This is mainly used to keep track of how many coroutine_yield() we need to perform after processing all rules in the list. Co-developed-by: Paolo Bonzini Signed-off-by: Emanuele Giuseppe Esposito Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20210614082931.24925-4-eesposit@redhat.com> Signed-off-by: Max Reitz --- block/blkdebug.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/block/blkdebug.c b/block/blkdebug.c index e8fdf7b056..6bdeb2c7b3 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -74,6 +74,7 @@ enum { ACTION_INJECT_ERROR, ACTION_SET_STATE, ACTION_SUSPEND, + ACTION__MAX, }; typedef struct BlkdebugRule { @@ -791,22 +792,22 @@ static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) qemu_coroutine_yield(); } -static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, - bool injected) +static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, + int *action_count) { BDRVBlkdebugState *s = bs->opaque; /* Only process rules for the current state */ if (rule->state && rule->state != s->state) { - return injected; + return; } /* Take the action */ + action_count[rule->action]++; switch (rule->action) { case ACTION_INJECT_ERROR: - if (!injected) { + if (action_count[ACTION_INJECT_ERROR] == 1) { QSIMPLEQ_INIT(&s->active_rules); - injected = true; } QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); break; @@ -819,21 +820,19 @@ static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, suspend_request(bs, rule); break; } - return injected; } static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event) { BDRVBlkdebugState *s = bs->opaque; struct BlkdebugRule *rule, *next; - bool injected; + int actions_count[ACTION__MAX] = { 0 }; assert((int)event >= 0 && event < BLKDBG__MAX); - injected = false; s->new_state = s->state; QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { - injected = process_rule(bs, rule, injected); + process_rule(bs, rule, actions_count); } s->state = s->new_state; } From 2196c341f7d0df161d412d3d7ea81545ab60ea2b Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Mon, 14 Jun 2021 10:29:29 +0200 Subject: [PATCH 211/531] blkdebug: do not suspend in the middle of QLIST_FOREACH_SAFE That would be unsafe in case a rule other than the current one is removed while the coroutine has yielded. Keep FOREACH_SAFE because suspend_request deletes the current rule. After this patch, *all* matching rules are deleted before suspending the coroutine, rather than just one. This doesn't affect the existing testcases. Use actions_count to see how many yield to issue. Co-developed-by: Paolo Bonzini Signed-off-by: Emanuele Giuseppe Esposito Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20210614082931.24925-5-eesposit@redhat.com> Signed-off-by: Max Reitz --- block/blkdebug.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/block/blkdebug.c b/block/blkdebug.c index 6bdeb2c7b3..dd82131d1e 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -789,7 +789,6 @@ static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) if (!qtest_enabled()) { printf("blkdebug: Suspended request '%s'\n", r->tag); } - qemu_coroutine_yield(); } static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, @@ -834,6 +833,12 @@ static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event) QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { process_rule(bs, rule, actions_count); } + + while (actions_count[ACTION_SUSPEND] > 0) { + qemu_coroutine_yield(); + actions_count[ACTION_SUSPEND]--; + } + s->state = s->new_state; } From 4153b553bd81e5b270b816699184df5d74c46805 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Mon, 14 Jun 2021 10:29:30 +0200 Subject: [PATCH 212/531] block/blkdebug: remove new_state field and instead use a local variable There seems to be no benefit in using a field. Replace it with a local variable, and move the state update before the yields. The state update has do be done before the yields because now using a local variable does not allow the new updated state to be visible by the other yields. Signed-off-by: Emanuele Giuseppe Esposito Message-Id: <20210614082931.24925-6-eesposit@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Max Reitz --- block/blkdebug.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/block/blkdebug.c b/block/blkdebug.c index dd82131d1e..b47c3fd97c 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -40,7 +40,6 @@ typedef struct BDRVBlkdebugState { int state; - int new_state; uint64_t align; uint64_t max_transfer; uint64_t opt_write_zero; @@ -792,7 +791,7 @@ static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) } static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, - int *action_count) + int *action_count, int *new_state) { BDRVBlkdebugState *s = bs->opaque; @@ -812,7 +811,7 @@ static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, break; case ACTION_SET_STATE: - s->new_state = rule->options.set_state.new_state; + *new_state = rule->options.set_state.new_state; break; case ACTION_SUSPEND: @@ -825,21 +824,21 @@ static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event) { BDRVBlkdebugState *s = bs->opaque; struct BlkdebugRule *rule, *next; + int new_state; int actions_count[ACTION__MAX] = { 0 }; assert((int)event >= 0 && event < BLKDBG__MAX); - s->new_state = s->state; + new_state = s->state; QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { - process_rule(bs, rule, actions_count); + process_rule(bs, rule, actions_count, &new_state); } + s->state = new_state; while (actions_count[ACTION_SUSPEND] > 0) { qemu_coroutine_yield(); actions_count[ACTION_SUSPEND]--; } - - s->state = s->new_state; } static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, From 36109bff171ba0811fa4c723cecdf6c3561fa318 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Mon, 14 Jun 2021 10:29:31 +0200 Subject: [PATCH 213/531] blkdebug: protect rules and suspended_reqs with a lock First, categorize the structure fields to identify what needs to be protected and what doesn't. We essentially need to protect only .state, and the 3 lists in BDRVBlkdebugState. Then, add the lock and mark the functions accordingly. Co-developed-by: Paolo Bonzini Signed-off-by: Emanuele Giuseppe Esposito Message-Id: <20210614082931.24925-7-eesposit@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Max Reitz --- block/blkdebug.c | 49 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/block/blkdebug.c b/block/blkdebug.c index b47c3fd97c..8b67554bec 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -38,24 +38,27 @@ #include "qapi/qobject-input-visitor.h" #include "sysemu/qtest.h" +/* All APIs are thread-safe */ + typedef struct BDRVBlkdebugState { - int state; + /* IN: initialized in blkdebug_open() and never changed */ uint64_t align; uint64_t max_transfer; uint64_t opt_write_zero; uint64_t max_write_zero; uint64_t opt_discard; uint64_t max_discard; - + char *config_file; /* For blkdebug_refresh_filename() */ + /* initialized in blkdebug_parse_perms() */ uint64_t take_child_perms; uint64_t unshare_child_perms; - /* For blkdebug_refresh_filename() */ - char *config_file; - + /* State. Protected by lock */ + int state; QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX]; QSIMPLEQ_HEAD(, BlkdebugRule) active_rules; QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs; + QemuMutex lock; } BDRVBlkdebugState; typedef struct BlkdebugAIOCB { @@ -64,8 +67,11 @@ typedef struct BlkdebugAIOCB { } BlkdebugAIOCB; typedef struct BlkdebugSuspendedReq { + /* IN: initialized in suspend_request() */ Coroutine *co; char *tag; + + /* List entry protected BDRVBlkdebugState's lock */ QLIST_ENTRY(BlkdebugSuspendedReq) next; } BlkdebugSuspendedReq; @@ -77,6 +83,7 @@ enum { }; typedef struct BlkdebugRule { + /* IN: initialized in add_rule() or blkdebug_debug_breakpoint() */ BlkdebugEvent event; int action; int state; @@ -95,6 +102,8 @@ typedef struct BlkdebugRule { char *tag; } suspend; } options; + + /* List entries protected BDRVBlkdebugState's lock */ QLIST_ENTRY(BlkdebugRule) next; QSIMPLEQ_ENTRY(BlkdebugRule) active_next; } BlkdebugRule; @@ -244,11 +253,14 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp) }; /* Add the rule */ + qemu_mutex_lock(&s->lock); QLIST_INSERT_HEAD(&s->rules[event], rule, next); + qemu_mutex_unlock(&s->lock); return 0; } +/* Called with lock held or from .bdrv_close */ static void remove_rule(BlkdebugRule *rule) { switch (rule->action) { @@ -467,6 +479,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, int ret; uint64_t align; + qemu_mutex_init(&s->lock); opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; @@ -567,6 +580,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, ret = 0; out: if (ret < 0) { + qemu_mutex_destroy(&s->lock); g_free(s->config_file); } qemu_opts_del(opts); @@ -581,6 +595,7 @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes, int error; bool immediately; + qemu_mutex_lock(&s->lock); QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { uint64_t inject_offset = rule->options.inject.offset; @@ -594,6 +609,7 @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes, } if (!rule || !rule->options.inject.error) { + qemu_mutex_unlock(&s->lock); return 0; } @@ -605,6 +621,7 @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes, remove_rule(rule); } + qemu_mutex_unlock(&s->lock); if (!immediately) { aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self()); qemu_coroutine_yield(); @@ -770,8 +787,10 @@ static void blkdebug_close(BlockDriverState *bs) } g_free(s->config_file); + qemu_mutex_destroy(&s->lock); } +/* Called with lock held. */ static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) { BDRVBlkdebugState *s = bs->opaque; @@ -790,6 +809,7 @@ static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) } } +/* Called with lock held. */ static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, int *action_count, int *new_state) { @@ -829,11 +849,13 @@ static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event) assert((int)event >= 0 && event < BLKDBG__MAX); - new_state = s->state; - QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { - process_rule(bs, rule, actions_count, &new_state); + WITH_QEMU_LOCK_GUARD(&s->lock) { + new_state = s->state; + QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { + process_rule(bs, rule, actions_count, &new_state); + } + s->state = new_state; } - s->state = new_state; while (actions_count[ACTION_SUSPEND] > 0) { qemu_coroutine_yield(); @@ -861,11 +883,14 @@ static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, .options.suspend.tag = g_strdup(tag), }; + qemu_mutex_lock(&s->lock); QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next); + qemu_mutex_unlock(&s->lock); return 0; } +/* Called with lock held. May temporarily release lock. */ static int resume_req_by_tag(BDRVBlkdebugState *s, const char *tag, bool all) { BlkdebugSuspendedReq *r; @@ -888,7 +913,9 @@ retry: g_free(r->tag); g_free(r); + qemu_mutex_unlock(&s->lock); qemu_coroutine_enter(co); + qemu_mutex_lock(&s->lock); if (all) { goto retry; @@ -902,7 +929,7 @@ retry: static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) { BDRVBlkdebugState *s = bs->opaque; - + QEMU_LOCK_GUARD(&s->lock); return resume_req_by_tag(s, tag, false); } @@ -913,6 +940,7 @@ static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs, BlkdebugRule *rule, *next; int i, ret = -ENOENT; + QEMU_LOCK_GUARD(&s->lock); for (i = 0; i < BLKDBG__MAX; i++) { QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { if (rule->action == ACTION_SUSPEND && @@ -933,6 +961,7 @@ static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) BDRVBlkdebugState *s = bs->opaque; BlkdebugSuspendedReq *r; + QEMU_LOCK_GUARD(&s->lock); QLIST_FOREACH(r, &s->suspended_reqs, next) { if (!strcmp(r->tag, tag)) { return true; From ead3f1bff99f4a4227975a1f026f4091e50f199f Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 3 Jul 2021 00:16:34 +0300 Subject: [PATCH 214/531] block/mirror: set .co for active-write MirrorOp objects This field is unused, but it very helpful for debugging. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20210702211636.228981-2-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block/mirror.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/mirror.c b/block/mirror.c index 019f6deaa5..ad6aac2f95 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1343,6 +1343,7 @@ static MirrorOp *coroutine_fn active_write_prepare(MirrorBlockJob *s, .bytes = bytes, .is_active_write = true, .is_in_flight = true, + .co = qemu_coroutine_self(), }; qemu_co_queue_init(&op->waiting_requests); QTAILQ_INSERT_TAIL(&s->ops_in_flight, op, next); From e0f69d83d5c5c039b133b60b5a7130dedeeaca42 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 3 Jul 2021 00:16:35 +0300 Subject: [PATCH 215/531] iotest 151: add test-case that shows active mirror dead-lock There is a dead-lock in active mirror: when we have parallel intersecting requests (note that non intersecting requests may be considered intersecting after aligning to mirror granularity), it may happen that request A waits request B in mirror_wait_on_conflicts() and request B waits for A. Look at the test for details. Test now dead-locks, that's why it's disabled. Next commit will fix mirror and enable the test. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20210702211636.228981-3-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/151 | 62 ++++++++++++++++++++++++++++++++++++-- tests/qemu-iotests/151.out | 4 +-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/tests/qemu-iotests/151 b/tests/qemu-iotests/151 index 182f6b5321..ab46c5e8ba 100755 --- a/tests/qemu-iotests/151 +++ b/tests/qemu-iotests/151 @@ -38,8 +38,9 @@ class TestActiveMirror(iotests.QMPTestCase): 'if': 'none', 'node-name': 'source-node', 'driver': iotests.imgfmt, - 'file': {'driver': 'file', - 'filename': source_img}} + 'file': {'driver': 'blkdebug', + 'image': {'driver': 'file', + 'filename': source_img}}} blk_target = {'node-name': 'target-node', 'driver': iotests.imgfmt, @@ -141,6 +142,63 @@ class TestActiveMirror(iotests.QMPTestCase): self.potential_writes_in_flight = False + def testIntersectingActiveIO(self): + # FIXME: test-case is dead-locking. To reproduce dead-lock just drop + # this return statement + return + + # Fill the source image + result = self.vm.hmp_qemu_io('source', 'write -P 1 0 2M') + + # Start the block job (very slowly) + result = self.vm.qmp('blockdev-mirror', + job_id='mirror', + filter_node_name='mirror-node', + device='source-node', + target='target-node', + sync='full', + copy_mode='write-blocking', + speed=1) + + self.vm.hmp_qemu_io('source', 'break write_aio A') + self.vm.hmp_qemu_io('source', 'aio_write 0 1M') # 1 + self.vm.hmp_qemu_io('source', 'wait_break A') + self.vm.hmp_qemu_io('source', 'aio_write 0 2M') # 2 + self.vm.hmp_qemu_io('source', 'aio_write 0 2M') # 3 + + # Now 2 and 3 are in mirror_wait_on_conflicts, waiting for 1 + + self.vm.hmp_qemu_io('source', 'break write_aio B') + self.vm.hmp_qemu_io('source', 'aio_write 1M 2M') # 4 + self.vm.hmp_qemu_io('source', 'wait_break B') + + # 4 doesn't wait for 2 and 3, because they didn't yet set + # in_flight_bitmap. So, nothing prevents 4 to go except for our + # break-point B. + + self.vm.hmp_qemu_io('source', 'resume A') + + # Now we resumed 1, so 2 and 3 goes to the next iteration of while loop + # in mirror_wait_on_conflicts(). They don't exit, as bitmap is dirty + # due to request 4. And they start to wait: 2 wait for 3, 3 wait for 2 + # - DEAD LOCK. + # Note that it's important that we add request 4 at last: requests are + # appended to the list, so we are sure that 4 is last in the list, so 2 + # and 3 now waits for each other, not for 4. + + self.vm.hmp_qemu_io('source', 'resume B') + + # Resuming 4 doesn't help, 2 and 3 already dead-locked + # To check the dead-lock run: + # gdb -p $(pidof qemu-system-x86_64) -ex 'set $job=(MirrorBlockJob *)jobs.lh_first' -ex 'p *$job->ops_in_flight.tqh_first' -ex 'p *$job->ops_in_flight.tqh_first->next.tqe_next' + # You'll see two MirrorOp objects waiting on each other + + result = self.vm.qmp('block-job-set-speed', device='mirror', speed=0) + self.assert_qmp(result, 'return', {}) + self.complete_and_wait(drive='mirror') + + self.potential_writes_in_flight = False + if __name__ == '__main__': iotests.main(supported_fmts=['qcow2', 'raw'], diff --git a/tests/qemu-iotests/151.out b/tests/qemu-iotests/151.out index 8d7e996700..89968f35d7 100644 --- a/tests/qemu-iotests/151.out +++ b/tests/qemu-iotests/151.out @@ -1,5 +1,5 @@ -... +.... ---------------------------------------------------------------------- -Ran 3 tests +Ran 4 tests OK From d44dae1a7cf782ec9235746ebb0e6c1a20dd7288 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 3 Jul 2021 00:16:36 +0300 Subject: [PATCH 216/531] block/mirror: fix active mirror dead-lock in mirror_wait_on_conflicts It's possible that requests start to wait each other in mirror_wait_on_conflicts(). To avoid it let's use same technique as in block/io.c in bdrv_wait_serialising_requests_locked() / bdrv_find_conflicting_request(): don't wait on intersecting request if it is already waiting for some other request. For details of the dead-lock look at testIntersectingActiveIO() test-case which we actually fixing now. Fixes: d06107ade0ce74dc39739bac80de84b51ec18546 Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20210702211636.228981-4-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block/mirror.c | 12 ++++++++++++ tests/qemu-iotests/151 | 18 +++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index ad6aac2f95..98fc66eabf 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -107,6 +107,7 @@ struct MirrorOp { bool is_in_flight; CoQueue waiting_requests; Coroutine *co; + MirrorOp *waiting_for_op; QTAILQ_ENTRY(MirrorOp) next; }; @@ -159,7 +160,18 @@ static void coroutine_fn mirror_wait_on_conflicts(MirrorOp *self, if (ranges_overlap(self_start_chunk, self_nb_chunks, op_start_chunk, op_nb_chunks)) { + /* + * If the operation is already (indirectly) waiting for us, or + * will wait for us as soon as it wakes up, then just go on + * (instead of producing a deadlock in the former case). + */ + if (op->waiting_for_op) { + continue; + } + + self->waiting_for_op = op; qemu_co_queue_wait(&op->waiting_requests, NULL); + self->waiting_for_op = NULL; break; } } diff --git a/tests/qemu-iotests/151 b/tests/qemu-iotests/151 index ab46c5e8ba..93d14193d0 100755 --- a/tests/qemu-iotests/151 +++ b/tests/qemu-iotests/151 @@ -143,10 +143,6 @@ class TestActiveMirror(iotests.QMPTestCase): self.potential_writes_in_flight = False def testIntersectingActiveIO(self): - # FIXME: test-case is dead-locking. To reproduce dead-lock just drop - # this return statement - return - # Fill the source image result = self.vm.hmp_qemu_io('source', 'write -P 1 0 2M') @@ -180,18 +176,14 @@ class TestActiveMirror(iotests.QMPTestCase): # Now we resumed 1, so 2 and 3 goes to the next iteration of while loop # in mirror_wait_on_conflicts(). They don't exit, as bitmap is dirty - # due to request 4. And they start to wait: 2 wait for 3, 3 wait for 2 - # - DEAD LOCK. - # Note that it's important that we add request 4 at last: requests are - # appended to the list, so we are sure that 4 is last in the list, so 2 - # and 3 now waits for each other, not for 4. + # due to request 4. + # In the past at that point 2 and 3 would wait for each other producing + # a dead-lock. Now this is fixed and they will wait for request 4. self.vm.hmp_qemu_io('source', 'resume B') - # Resuming 4 doesn't help, 2 and 3 already dead-locked - # To check the dead-lock run: - # gdb -p $(pidof qemu-system-x86_64) -ex 'set $job=(MirrorBlockJob *)jobs.lh_first' -ex 'p *$job->ops_in_flight.tqh_first' -ex 'p *$job->ops_in_flight.tqh_first->next.tqe_next' - # You'll see two MirrorOp objects waiting on each other + # After resuming 4, one of 2 and 3 goes first and set in_flight_bitmap, + # so the other will wait for it. result = self.vm.qmp('block-job-set-speed', device='mirror', speed=0) self.assert_qmp(result, 'return', {}) From e5f05f8c375157211c7da625a0d3f3ccdb4957d5 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 9 Jul 2021 18:41:41 +0200 Subject: [PATCH 217/531] block: Add option to use driver whitelist even in tools Currently, the block driver whitelists are only applied for the system emulator. All other binaries still give unrestricted access to all block drivers. There are use cases where this made sense because the main concern was avoiding customers running VMs on less optimised block drivers and getting bad performance. Allowing the same image format e.g. as a target for 'qemu-img convert' is not a problem then. However, if the concern is the supportability of the driver in general, either in full or when used read-write, not applying the list driver whitelist in tools doesn't help - especially since qemu-nbd and qemu-storage-daemon now give access to more or less the same operations in block drivers as running a system emulator. In order to address this, introduce a new configure option that enforces the driver whitelist in all binaries. Signed-off-by: Kevin Wolf Message-Id: <20210709164141.254097-1-kwolf@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 3 +++ configure | 14 ++++++++++++-- meson.build | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index be083f389e..e97ce0b1c8 100644 --- a/block.c +++ b/block.c @@ -6162,6 +6162,9 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, void bdrv_init(void) { +#ifdef CONFIG_BDRV_WHITELIST_TOOLS + use_bdrv_whitelist = 1; +#endif module_call_init(MODULE_INIT_BLOCK); } diff --git a/configure b/configure index 63f38fa94c..232c54dcc1 100755 --- a/configure +++ b/configure @@ -243,6 +243,7 @@ cross_prefix="" audio_drv_list="" block_drv_rw_whitelist="" block_drv_ro_whitelist="" +block_drv_whitelist_tools="no" host_cc="cc" audio_win_int="" libs_qga="" @@ -1016,6 +1017,10 @@ for opt do ;; --block-drv-ro-whitelist=*) block_drv_ro_whitelist=$(echo "$optarg" | sed -e 's/,/ /g') ;; + --enable-block-drv-whitelist-in-tools) block_drv_whitelist_tools="yes" + ;; + --disable-block-drv-whitelist-in-tools) block_drv_whitelist_tools="no" + ;; --enable-debug-tcg) debug_tcg="yes" ;; --disable-debug-tcg) debug_tcg="no" @@ -1800,10 +1805,12 @@ Advanced options (experts only): --block-drv-whitelist=L Same as --block-drv-rw-whitelist=L --block-drv-rw-whitelist=L set block driver read-write whitelist - (affects only QEMU, not qemu-img) + (by default affects only QEMU, not tools like qemu-img) --block-drv-ro-whitelist=L set block driver read-only whitelist - (affects only QEMU, not qemu-img) + (by default affects only QEMU, not tools like qemu-img) + --enable-block-drv-whitelist-in-tools + use block whitelist also in tools instead of only QEMU --enable-trace-backends=B Set trace backend Available backends: $trace_backend_list --with-trace-file=NAME Full PATH,NAME of file to store traces @@ -4583,6 +4590,9 @@ if test "$audio_win_int" = "yes" ; then fi echo "CONFIG_BDRV_RW_WHITELIST=$block_drv_rw_whitelist" >> $config_host_mak echo "CONFIG_BDRV_RO_WHITELIST=$block_drv_ro_whitelist" >> $config_host_mak +if test "$block_drv_whitelist_tools" = "yes" ; then + echo "CONFIG_BDRV_WHITELIST_TOOLS=y" >> $config_host_mak +fi if test "$xfs" = "yes" ; then echo "CONFIG_XFS=y" >> $config_host_mak fi diff --git a/meson.build b/meson.build index 6e4d2d8034..2f377098d7 100644 --- a/meson.build +++ b/meson.build @@ -2996,6 +2996,7 @@ summary_info += {'coroutine pool': config_host['CONFIG_COROUTINE_POOL'] == '1 if have_block summary_info += {'Block whitelist (rw)': config_host['CONFIG_BDRV_RW_WHITELIST']} summary_info += {'Block whitelist (ro)': config_host['CONFIG_BDRV_RO_WHITELIST']} + summary_info += {'Use block whitelist in tools': config_host.has_key('CONFIG_BDRV_WHITELIST_TOOLS')} summary_info += {'VirtFS support': have_virtfs} summary_info += {'build virtiofs daemon': have_virtiofsd} summary_info += {'Live block migration': config_host.has_key('CONFIG_LIVE_BLOCK_MIGRATION')} From 2321d971b6f0a87507d6ca44055864158763309b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 10 Mar 2019 02:07:58 +0100 Subject: [PATCH 218/531] hw/mips: Add dependency MIPS_CPS -> MIPS_ITU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Inter-Thread Communication Unit (ITU, introduced in commit 34fa7e83e11) is part of the Coherent Processing System (CPS), as describe in commit 408294352ad: Make ITU available in the system if CPU supports multithreading and is part of CPS. Have CPS select ITU in Kconfig to avoid the following build failure: /usr/bin/ld: libqemu-mips64el-softmmu.fa.p/hw_mips_cps.c.o: in function `mips_cps_realize': hw/mips/cps.c:104: undefined reference to `mips_itu_get_tag_region' Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20190311005618.19007-5-philmd@redhat.com> --- hw/mips/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index c245e881a2..1d4051fcf0 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -47,6 +47,7 @@ config LOONGSON3V config MIPS_CPS bool select PTIMER + select MIPS_ITU config MIPS_BOSTON bool From 39f6049e47bc1c53687af06e065d9b83311fa216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 3 Feb 2019 21:24:10 +0100 Subject: [PATCH 219/531] hw/mips: Express dependencies of the Boston machine with Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Boston is built around a Xilinx FPGA, which includes a PCIe root port and an UART. An Intel EG20T PCH connects the I/O peripherals, but only the SATA bus is emulated. Reviewed-by: Thomas Huth Reviewed-by: Paul Burton Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20190311005618.19007-6-philmd@redhat.com> --- configs/devices/mips64el-softmmu/default.mak | 4 ---- hw/mips/Kconfig | 5 +++++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/configs/devices/mips64el-softmmu/default.mak b/configs/devices/mips64el-softmmu/default.mak index c511a061ba..c610749ac1 100644 --- a/configs/devices/mips64el-softmmu/default.mak +++ b/configs/devices/mips64el-softmmu/default.mak @@ -8,8 +8,4 @@ CONFIG_ATI_VGA=y CONFIG_RTL8139_PCI=y CONFIG_JAZZ=y CONFIG_VT82C686=y -CONFIG_AHCI=y CONFIG_MIPS_BOSTON=y -CONFIG_FITLOADER=y -CONFIG_PCI_EXPRESS=y -CONFIG_PCI_EXPRESS_XILINX=y diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index 1d4051fcf0..b4c5549ce8 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -51,6 +51,11 @@ config MIPS_CPS config MIPS_BOSTON bool + select FITLOADER + select MIPS_CPS + select PCI_EXPRESS_XILINX + select AHCI_ICH9 + select SERIAL config FW_CFG_MIPS bool From 0afdee11d6267dc37335122afa9a6b7080522d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 21 May 2021 16:01:36 +0200 Subject: [PATCH 220/531] hw/acpi: Do not restrict ACPI core routines to x86 architecture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ACPI core routines (in core.c) are not really x86-specific. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Michael S. Tsirkin Message-Id: <20210616204328.2611406-21-philmd@redhat.com> --- hw/acpi/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build index 9b7fa75719..29f804d13e 100644 --- a/hw/acpi/meson.build +++ b/hw/acpi/meson.build @@ -3,6 +3,7 @@ acpi_ss.add(files( 'acpi_interface.c', 'aml-build.c', 'bios-linker-loader.c', + 'core.c', 'utils.c', )) acpi_ss.add(when: 'CONFIG_ACPI_CPU_HOTPLUG', if_true: files('cpu.c')) @@ -14,7 +15,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_VMGENID', if_true: files('vmgenid.c')) acpi_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device.c')) acpi_ss.add(when: 'CONFIG_ACPI_HMAT', if_true: files('hmat.c')) acpi_ss.add(when: 'CONFIG_ACPI_APEI', if_true: files('ghes.c'), if_false: files('ghes-stub.c')) -acpi_ss.add(when: 'CONFIG_ACPI_X86', if_true: files('core.c', 'piix4.c', 'pcihp.c'), if_false: files('acpi-stub.c')) +acpi_ss.add(when: 'CONFIG_ACPI_X86', if_true: files('piix4.c', 'pcihp.c')) acpi_ss.add(when: 'CONFIG_ACPI_X86_ICH', if_true: files('ich9.c', 'tco.c')) acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c')) acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c')) From 36b79e3219d89df0d4f59c6648a0a3b391b2e045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 21 May 2021 15:53:57 +0200 Subject: [PATCH 221/531] hw/acpi/Kconfig: Add missing Kconfig dependencies (build error) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'microvm' machine misses various dependencies: /usr/bin/ld: libqemu-i386-softmmu.fa.p/hw_i386_acpi-microvm.c.o: in function `acpi_setup_microvm': hw/i386/acpi-microvm.c:247: undefined reference to `acpi_build_tables_init' /usr/bin/ld: libqemu-i386-softmmu.fa.p/hw_i386_acpi-microvm.c.o: in function `acpi_build_microvm': hw/i386/acpi-microvm.c:192: undefined reference to `bios_linker_loader_alloc' /usr/bin/ld: libqemu-i386-softmmu.fa.p/hw_i386_acpi-microvm.c.o: in function `build_dsdt_microvm': hw/i386/acpi-microvm.c:121: undefined reference to `init_aml_allocator' /usr/bin/ld: hw/i386/acpi-microvm.c:124: undefined reference to `acpi_data_push' /usr/bin/ld: hw/i386/acpi-microvm.c:126: undefined reference to `aml_scope' /usr/bin/ld: hw/i386/acpi-microvm.c:129: undefined reference to `build_ged_aml' /usr/bin/ld: hw/i386/acpi-microvm.c:131: undefined reference to `acpi_dsdt_add_power_button' /usr/bin/ld: libqemu-i386-softmmu.fa.p/hw_i386_acpi-microvm.c.o: in function `acpi_dsdt_add_virtio': hw/i386/acpi-microvm.c:77: undefined reference to `aml_string' /usr/bin/ld: libqemu-i386-softmmu.fa.p/hw_i386_acpi-microvm.c.o: in function `build_dsdt_microvm': hw/i386/acpi-microvm.c:138: undefined reference to `aml_scope' /usr/bin/ld: hw/i386/acpi-microvm.c:149: undefined reference to `build_header' /usr/bin/ld: hw/i386/acpi-microvm.c:152: undefined reference to `free_aml_allocator' /usr/bin/ld: libqemu-i386-softmmu.fa.p/hw_i386_acpi-microvm.c.o: in function `acpi_build_microvm': hw/i386/acpi-microvm.c:202: undefined reference to `acpi_add_table' /usr/bin/ld: hw/i386/acpi-microvm.c:203: undefined reference to `build_fadt' /usr/bin/ld: hw/i386/acpi-microvm.c:206: undefined reference to `acpi_add_table' /usr/bin/ld: hw/i386/acpi-microvm.c:207: undefined reference to `acpi_build_madt' /usr/bin/ld: hw/i386/acpi-microvm.c:212: undefined reference to `build_xsdt' /usr/bin/ld: hw/i386/acpi-microvm.c:224: undefined reference to `build_rsdp' /usr/bin/ld: libqemu-i386-softmmu.fa.p/hw_i386_acpi-microvm.c.o: in function `acpi_setup_microvm': hw/i386/acpi-microvm.c:251: undefined reference to `acpi_add_rom_blob' /usr/bin/ld: hw/i386/acpi-microvm.c:253: undefined reference to `acpi_add_rom_blob' /usr/bin/ld: hw/i386/acpi-microvm.c:255: undefined reference to `acpi_add_rom_blob' /usr/bin/ld: hw/i386/acpi-microvm.c:258: undefined reference to `acpi_build_tables_cleanup' /usr/bin/ld: libqemu-i386-softmmu.fa.p/hw_i386_acpi-microvm.c.o: in function `acpi_dsdt_add_pci': hw/i386/acpi-microvm.c:105: undefined reference to `acpi_dsdt_add_gpex' collect2: error: ld returned 1 exit status ninja: build stopped: subcommand failed. Update the ACPI_HW_REDUCED symbol to select ACPI_MEMORY_HOTPLUG / ACPI_NVDIMM / ACPI. Fixes: 8045df14bcc ("microvm/acpi: add minimal acpi support") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Message-Id: <20210616204328.2611406-23-philmd@redhat.com> --- hw/acpi/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 1932f66af8..cfc4ede8d9 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -42,3 +42,7 @@ config ACPI_VMGENID depends on PC config ACPI_HW_REDUCED + bool + select ACPI + select ACPI_MEMORY_HOTPLUG + select ACPI_NVDIMM From df90457cf51687a2b699ab07c5240a52c0915404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Jun 2021 14:55:53 +0200 Subject: [PATCH 222/531] hw/i386/Kconfig: Add missing Kconfig dependency (runtime error) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building the 'microvm' machine stand-alone we get: $ qemu-system-x86_64 -M microvm ** ERROR:qom/object.c:714:object_new_with_type: assertion failed: (type != NULL) Bail out! ERROR:qom/object.c:714:object_new_with_type: assertion failed: (type != NULL) Aborted (core dumped) Looking at the backtrace: (gdb) bt #3 0x00007ff2330492ff in g_assertion_message_expr () at /lib64/libglib-2.0.so.0 #4 0x000055a878c18341 in object_new_with_type (type=) at qom/object.c:714 #5 0x000055a878c18399 in object_new (typename=typename@entry=0x55a878dec36a "isa-pit") at qom/object.c:747 #6 0x000055a878cc8146 in qdev_new (name=name@entry=0x55a878dec36a "isa-pit") at hw/core/qdev.c:153 #7 0x000055a878a8b439 in isa_new (name=name@entry=0x55a878dec36a "isa-pit") at hw/isa/isa-bus.c:160 #8 0x000055a878adb782 in i8254_pit_init (base=64, isa_irq=0, alt_irq=0x0, bus=0x55a87ab38760) at include/hw/timer/i8254.h:54 #9 microvm_devices_init (mms=0x55a87ac36800) at hw/i386/microvm.c:263 #10 microvm_machine_state_init (machine=) at hw/i386/microvm.c:471 #11 0x000055a878a944ab in machine_run_board_init (machine=machine@entry=0x55a87ac36800) at hw/core/machine.c:1239 The "isa-pit" type (TYPE_I8254) is missing. Add it. Fixes: 0ebf007ddac ("hw/i386: Introduce the microvm machine type") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Message-Id: <20210616204328.2611406-24-philmd@redhat.com> --- hw/i386/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index bad6cf5b4e..ddedcef0b2 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -111,6 +111,7 @@ config MICROVM select ACPI_HW_REDUCED select PCI_EXPRESS_GENERIC_BRIDGE select USB_XHCI_SYSBUS + select I8254 config X86_IOMMU bool From 27d764c9c0749027578351cf018e02d25e8e3f71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 13 May 2021 09:34:33 +0200 Subject: [PATCH 223/531] hw/ide/Kconfig: Add missing dependency PCI -> IDE_QDEV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pci_ide_create_devs() function is declared i hw/ide/qdev.c: $ git grep ide_create_drive hw/ide/pci.c:491: ide_create_drive(d->bus + bus[i], unit[i], hd_table[i]); hw/ide/qdev.c:127:IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive) include/hw/ide/internal.h:653:IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive); Fix the correct symbol dependency to avoid build failure when deselecting some machines: /usr/bin/ld: libcommon.fa.p/hw_ide_pci.c.o: in function `pci_ide_create_devs': hw/ide/pci.c:491: undefined reference to `ide_create_drive' Fixes: 8f01b41e109 ("ide: express dependencies with Kconfig") Acked-by: Paolo Bonzini Reviewed-by: Bin Meng Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210515173716.358295-3-philmd@redhat.com> Acked-by: John Snow --- hw/ide/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide/Kconfig b/hw/ide/Kconfig index 8e2c893454..dd85fa3619 100644 --- a/hw/ide/Kconfig +++ b/hw/ide/Kconfig @@ -8,7 +8,7 @@ config IDE_QDEV config IDE_PCI bool depends on PCI - select IDE_CORE + select IDE_QDEV config IDE_ISA bool From d43bb04c844dc6de78aa14e8e944d8302e24200a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 13 May 2021 08:55:50 +0200 Subject: [PATCH 224/531] hw/arm/Kconfig: Add missing dependency NPCM7XX -> SMBUS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TYPE_NPCM7XX_SMBUS device model exposes an SMBus, but this isn't advertised with proper Kconfig symbol, leading to an early build failure when building NPCM7XX machines standalone: The following clauses were found for AT24C config AT24C depends on I2C select AT24C if NPCM7XX Fix by adding SMBUS to NPCM7XX. Fixes: 94e77879395 ("hw/i2c: Implement NPCM7XX SMBus Module Single Mode") Reviewed-by: Hao Wu Acked-by: Paolo Bonzini Reviewed-by: Bin Meng Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210515173716.358295-4-philmd@redhat.com> --- hw/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 90b19c0861..4a994f35e3 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -388,6 +388,7 @@ config NPCM7XX select A9MPCORE select ADM1272 select ARM_GIC + select SMBUS select AT24C # EEPROM select MAX34451 select PL310 # cache controller From 7795b6e1523e7c8b50103df7ea1c9f325200d78b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 13 May 2021 15:17:06 +0200 Subject: [PATCH 225/531] hw/arm/Kconfig: Remove unused DS1338 symbol from i.MX25 PDK Board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit c4f00daa5b3 ("imx25-pdk: create ds1338 for qtest inside the test") we removed the DS1338 device from the i.MX25 machine but forgot to remove it in the machine Kconfig definitions, do it now. Acked-by: Paolo Bonzini Reviewed-by: Bin Meng Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210515173716.358295-5-philmd@redhat.com> --- hw/arm/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 4a994f35e3..30967da2e1 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -404,7 +404,6 @@ config FSL_IMX25 select IMX_FEC select IMX_I2C select WDT_IMX2 - select DS1338 config FSL_IMX31 bool From ee9ffe0c8efac4f194aed288563949b09705b0de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 13 May 2021 15:20:23 +0200 Subject: [PATCH 226/531] hw/arm/Kconfig: Add missing SDHCI symbol to FSL_IMX25 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit bfae1772c43 ("hw/arm/fsl-imx25: Wire up eSDHC controllers") added a dependency on the TYPE_IMX_USDHC model, but forgot to add the Kconfig selector. Fix that to solve when built stand-alone: $ qemu-system-arm -M imx25-pdk qemu-system-arm: missing object type 'imx-usdhc' Aborted (core dumped) Fixes: bfae1772c43 ("hw/arm/fsl-imx25: Wire up eSDHC controllers") Acked-by: Paolo Bonzini Reviewed-by: Bin Meng Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210515173716.358295-6-philmd@redhat.com> --- hw/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 30967da2e1..4ba0aca067 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -404,6 +404,7 @@ config FSL_IMX25 select IMX_FEC select IMX_I2C select WDT_IMX2 + select SDHCI config FSL_IMX31 bool From 8cbb537ea979c5312cbcb2770d1afae3779be7a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 13 May 2021 07:50:27 +0200 Subject: [PATCH 227/531] hw/riscv/Kconfig: Add missing dependency MICROCHIP_PFSOC -> SERIAL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit a8fb0a500a6 ("hw/char: Add Microchip PolarFire SoC MMUART emulation") added a dependency on the SERIAL model, but forgot to add the Kconfig selector. Add the dependency to the MCHP_PFSOC_MMUART symbol to fix when building the MICROCHIP_PFSOC machine stand-alone: /usr/bin/ld: libcommon.fa.p/hw_char_mchp_pfsoc_mmuart.c.o: in function `mchp_pfsoc_mmuart_create': hw/char/mchp_pfsoc_mmuart.c:79: undefined reference to `serial_mm_init' Fixes: a8fb0a500a6 ("hw/char: Add Microchip PolarFire SoC MMUART emulation") Acked-by: Paolo Bonzini Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210515173716.358295-7-philmd@redhat.com> Reviewed-by: Alistair Francis Reviewed-by: Bin Meng --- hw/char/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/char/Kconfig b/hw/char/Kconfig index 4cf36ac637..2e4f620b13 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig @@ -61,6 +61,7 @@ config AVR_USART config MCHP_PFSOC_MMUART bool + select SERIAL config SIFIVE_UART bool From 6e4dd94f77d769daa5a56d1b02b9c6a697db5270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 13 May 2021 08:07:56 +0200 Subject: [PATCH 228/531] hw/riscv/Kconfig: Restrict NUMA to Virt & Spike machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only the Virt and Spike machines use NUMA. Add a RISCV_NUMA Kconfig symbol and only have these machines select it. Adapt the Meson file to only built it if required. Acked-by: Paolo Bonzini Reviewed-by: Bin Meng Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210515173716.358295-8-philmd@redhat.com> Reviewed-by: Alistair Francis --- hw/riscv/Kconfig | 5 +++++ hw/riscv/meson.build | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 86957ec7b0..0590f443fd 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -1,3 +1,6 @@ +config RISCV_NUMA + bool + config IBEX bool @@ -34,6 +37,7 @@ config RISCV_VIRT imply PCI_DEVICES imply VIRTIO_VGA imply TEST_DEVICES + select RISCV_NUMA select GOLDFISH_RTC select MSI_NONBROKEN select PCI @@ -74,6 +78,7 @@ config SIFIVE_U config SPIKE bool + select RISCV_NUMA select HTIF select MSI_NONBROKEN select SIFIVE_CLINT diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index a97454661c..ab6cae57ea 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -1,6 +1,6 @@ riscv_ss = ss.source_set() riscv_ss.add(files('boot.c'), fdt) -riscv_ss.add(files('numa.c')) +riscv_ss.add(when: 'CONFIG_RISCV_NUMA', if_true: files('numa.c')) riscv_ss.add(files('riscv_hart.c')) riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c')) riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c')) From ed2543a256684df1e6de6706c78c76136f163861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 13 May 2021 15:13:54 +0200 Subject: [PATCH 229/531] hw/ppc/Kconfig: Add missing dependency E500 -> DS1338 RTC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 7abb479c7ab ("PPC: E500: Add FSL I2C controller and integrate RTC with it") added a global dependency on the DS1338 model, instead of a machine one (via Kconfig). This gives trouble when building standalone machines not exposing I2C bus: The following clauses were found for DS1338 CONFIG_DS1338=y config DS1338 depends on I2C Fix by selecting the DS1338 symbol in the single machine requiring it, the E500. Fixes: 7abb479c7ab ("PPC: E500: Add FSL I2C controller and integrate RTC with it") Acked-by: Paolo Bonzini Acked-by: David Gibson Reviewed-by: Bin Meng Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210513163858.3928976-9-philmd@redhat.com> --- configs/devices/ppc-softmmu/default.mak | 1 - hw/ppc/Kconfig | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/devices/ppc-softmmu/default.mak b/configs/devices/ppc-softmmu/default.mak index 4535993d8d..658a454426 100644 --- a/configs/devices/ppc-softmmu/default.mak +++ b/configs/devices/ppc-softmmu/default.mak @@ -1,7 +1,6 @@ # Default configuration for ppc-softmmu # For embedded PPCs: -CONFIG_DS1338=y CONFIG_E500=y CONFIG_PPC405=y CONFIG_PPC440=y diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig index 322a7eb031..85b9c93f02 100644 --- a/hw/ppc/Kconfig +++ b/hw/ppc/Kconfig @@ -130,6 +130,7 @@ config E500 select SERIAL select MPC_I2C select FDT_PPC + select DS1338 config VIRTEX bool From 1e12ecfd2cd38d06278ee7424fa2ab0bf3c10e93 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Sun, 18 Jul 2021 16:48:24 +0200 Subject: [PATCH 230/531] replication: Remove s->active_disk s->active_disk is bs->file. Remove it and use local variables instead. Signed-off-by: Lukas Straub Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <2534f867ea9be5b666dfce19744b7d4e2b96c976.1626619393.git.lukasstraub2@web.de> Reviewed-by: Zhang Chen Signed-off-by: Kevin Wolf --- block/replication.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/block/replication.c b/block/replication.c index 774e15df16..9ad2dfdc69 100644 --- a/block/replication.c +++ b/block/replication.c @@ -35,7 +35,6 @@ typedef enum { typedef struct BDRVReplicationState { ReplicationMode mode; ReplicationStage stage; - BdrvChild *active_disk; BlockJob *commit_job; BdrvChild *hidden_disk; BdrvChild *secondary_disk; @@ -307,8 +306,10 @@ out: return ret; } -static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp) +static void secondary_do_checkpoint(BlockDriverState *bs, Error **errp) { + BDRVReplicationState *s = bs->opaque; + BdrvChild *active_disk = bs->file; Error *local_err = NULL; int ret; @@ -323,13 +324,13 @@ static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp) return; } - if (!s->active_disk->bs->drv) { + if (!active_disk->bs->drv) { error_setg(errp, "Active disk %s is ejected", - s->active_disk->bs->node_name); + active_disk->bs->node_name); return; } - ret = bdrv_make_empty(s->active_disk, errp); + ret = bdrv_make_empty(active_disk, errp); if (ret < 0) { return; } @@ -458,6 +459,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, BlockDriverState *bs = rs->opaque; BDRVReplicationState *s; BlockDriverState *top_bs; + BdrvChild *active_disk; int64_t active_length, hidden_length, disk_length; AioContext *aio_context; Error *local_err = NULL; @@ -495,15 +497,14 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, case REPLICATION_MODE_PRIMARY: break; case REPLICATION_MODE_SECONDARY: - s->active_disk = bs->file; - if (!s->active_disk || !s->active_disk->bs || - !s->active_disk->bs->backing) { + active_disk = bs->file; + if (!active_disk || !active_disk->bs || !active_disk->bs->backing) { error_setg(errp, "Active disk doesn't have backing file"); aio_context_release(aio_context); return; } - s->hidden_disk = s->active_disk->bs->backing; + s->hidden_disk = active_disk->bs->backing; if (!s->hidden_disk->bs || !s->hidden_disk->bs->backing) { error_setg(errp, "Hidden disk doesn't have backing file"); aio_context_release(aio_context); @@ -518,7 +519,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, } /* verify the length */ - active_length = bdrv_getlength(s->active_disk->bs); + active_length = bdrv_getlength(active_disk->bs); hidden_length = bdrv_getlength(s->hidden_disk->bs); disk_length = bdrv_getlength(s->secondary_disk->bs); if (active_length < 0 || hidden_length < 0 || disk_length < 0 || @@ -530,9 +531,9 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, } /* Must be true, or the bdrv_getlength() calls would have failed */ - assert(s->active_disk->bs->drv && s->hidden_disk->bs->drv); + assert(active_disk->bs->drv && s->hidden_disk->bs->drv); - if (!s->active_disk->bs->drv->bdrv_make_empty || + if (!active_disk->bs->drv->bdrv_make_empty || !s->hidden_disk->bs->drv->bdrv_make_empty) { error_setg(errp, "Active disk or hidden disk doesn't support make_empty"); @@ -586,7 +587,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, s->stage = BLOCK_REPLICATION_RUNNING; if (s->mode == REPLICATION_MODE_SECONDARY) { - secondary_do_checkpoint(s, errp); + secondary_do_checkpoint(bs, errp); } s->error = 0; @@ -615,7 +616,7 @@ static void replication_do_checkpoint(ReplicationState *rs, Error **errp) } if (s->mode == REPLICATION_MODE_SECONDARY) { - secondary_do_checkpoint(s, errp); + secondary_do_checkpoint(bs, errp); } aio_context_release(aio_context); } @@ -652,7 +653,6 @@ static void replication_done(void *opaque, int ret) if (ret == 0) { s->stage = BLOCK_REPLICATION_DONE; - s->active_disk = NULL; s->secondary_disk = NULL; s->hidden_disk = NULL; s->error = 0; @@ -705,7 +705,7 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp) } if (!failover) { - secondary_do_checkpoint(s, errp); + secondary_do_checkpoint(bs, errp); s->stage = BLOCK_REPLICATION_DONE; aio_context_release(aio_context); return; @@ -713,7 +713,7 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp) s->stage = BLOCK_REPLICATION_FAILOVER; s->commit_job = commit_active_start( - NULL, s->active_disk->bs, s->secondary_disk->bs, + NULL, bs->file->bs, s->secondary_disk->bs, JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT, NULL, replication_done, bs, true, errp); break; From a990a42b39338ffd12fb9640d792276313f75ed5 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Sun, 18 Jul 2021 16:48:29 +0200 Subject: [PATCH 231/531] replication: Reduce usage of s->hidden_disk and s->secondary_disk In preparation for the next patch, initialize s->hidden_disk and s->secondary_disk later and replace access to them with local variables in the places where they aren't initialized yet. Signed-off-by: Lukas Straub Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <1eb9dc179267207d9c7eccaeb30761758e32e9ab.1626619393.git.lukasstraub2@web.de> Signed-off-by: Kevin Wolf --- block/replication.c | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/block/replication.c b/block/replication.c index 9ad2dfdc69..25bbdf5d4b 100644 --- a/block/replication.c +++ b/block/replication.c @@ -366,27 +366,35 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, Error **errp) { BDRVReplicationState *s = bs->opaque; + BdrvChild *hidden_disk, *secondary_disk; BlockReopenQueue *reopen_queue = NULL; + /* + * s->hidden_disk and s->secondary_disk may not be set yet, as they will + * only be set after the children are writable. + */ + hidden_disk = bs->file->bs->backing; + secondary_disk = hidden_disk->bs->backing; + if (writable) { - s->orig_hidden_read_only = bdrv_is_read_only(s->hidden_disk->bs); - s->orig_secondary_read_only = bdrv_is_read_only(s->secondary_disk->bs); + s->orig_hidden_read_only = bdrv_is_read_only(hidden_disk->bs); + s->orig_secondary_read_only = bdrv_is_read_only(secondary_disk->bs); } - bdrv_subtree_drained_begin(s->hidden_disk->bs); - bdrv_subtree_drained_begin(s->secondary_disk->bs); + bdrv_subtree_drained_begin(hidden_disk->bs); + bdrv_subtree_drained_begin(secondary_disk->bs); if (s->orig_hidden_read_only) { QDict *opts = qdict_new(); qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable); - reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, + reopen_queue = bdrv_reopen_queue(reopen_queue, hidden_disk->bs, opts, true); } if (s->orig_secondary_read_only) { QDict *opts = qdict_new(); qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable); - reopen_queue = bdrv_reopen_queue(reopen_queue, s->secondary_disk->bs, + reopen_queue = bdrv_reopen_queue(reopen_queue, secondary_disk->bs, opts, true); } @@ -401,8 +409,8 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, } } - bdrv_subtree_drained_end(s->hidden_disk->bs); - bdrv_subtree_drained_end(s->secondary_disk->bs); + bdrv_subtree_drained_end(hidden_disk->bs); + bdrv_subtree_drained_end(secondary_disk->bs); } static void backup_job_cleanup(BlockDriverState *bs) @@ -459,7 +467,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, BlockDriverState *bs = rs->opaque; BDRVReplicationState *s; BlockDriverState *top_bs; - BdrvChild *active_disk; + BdrvChild *active_disk, *hidden_disk, *secondary_disk; int64_t active_length, hidden_length, disk_length; AioContext *aio_context; Error *local_err = NULL; @@ -504,15 +512,15 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, return; } - s->hidden_disk = active_disk->bs->backing; - if (!s->hidden_disk->bs || !s->hidden_disk->bs->backing) { + hidden_disk = active_disk->bs->backing; + if (!hidden_disk->bs || !hidden_disk->bs->backing) { error_setg(errp, "Hidden disk doesn't have backing file"); aio_context_release(aio_context); return; } - s->secondary_disk = s->hidden_disk->bs->backing; - if (!s->secondary_disk->bs || !bdrv_has_blk(s->secondary_disk->bs)) { + secondary_disk = hidden_disk->bs->backing; + if (!secondary_disk->bs || !bdrv_has_blk(secondary_disk->bs)) { error_setg(errp, "The secondary disk doesn't have block backend"); aio_context_release(aio_context); return; @@ -520,8 +528,8 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, /* verify the length */ active_length = bdrv_getlength(active_disk->bs); - hidden_length = bdrv_getlength(s->hidden_disk->bs); - disk_length = bdrv_getlength(s->secondary_disk->bs); + hidden_length = bdrv_getlength(hidden_disk->bs); + disk_length = bdrv_getlength(secondary_disk->bs); if (active_length < 0 || hidden_length < 0 || disk_length < 0 || active_length != hidden_length || hidden_length != disk_length) { error_setg(errp, "Active disk, hidden disk, secondary disk's length" @@ -531,10 +539,10 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, } /* Must be true, or the bdrv_getlength() calls would have failed */ - assert(active_disk->bs->drv && s->hidden_disk->bs->drv); + assert(active_disk->bs->drv && hidden_disk->bs->drv); if (!active_disk->bs->drv->bdrv_make_empty || - !s->hidden_disk->bs->drv->bdrv_make_empty) { + !hidden_disk->bs->drv->bdrv_make_empty) { error_setg(errp, "Active disk or hidden disk doesn't support make_empty"); aio_context_release(aio_context); @@ -549,6 +557,9 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, return; } + s->hidden_disk = hidden_disk; + s->secondary_disk = secondary_disk; + /* start backup job now */ error_setg(&s->blocker, "Block device is in use by internal backup job"); From 3b78420bb14f7e439a079aee28eeec997a229c5e Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Sun, 18 Jul 2021 16:48:33 +0200 Subject: [PATCH 232/531] replication: Properly attach children The replication driver needs access to the children block-nodes of it's child so it can issue bdrv_make_empty() and bdrv_co_pwritev() to manage the replication. However, it does this by directly copying the BdrvChilds, which is wrong. Fix this by properly attaching the block-nodes with bdrv_attach_child() and requesting the required permissions. This ultimatively fixes a potential crash in replication_co_writev(), because it may write to s->secondary_disk if it is in state BLOCK_REPLICATION_FAILOVER_FAILED, without requesting write permissions first. And now the workaround in secondary_do_checkpoint() can be removed. Signed-off-by: Lukas Straub Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <5d0539d729afb8072d0d7cde977c5066285591b4.1626619393.git.lukasstraub2@web.de> Signed-off-by: Kevin Wolf --- block/replication.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/block/replication.c b/block/replication.c index 25bbdf5d4b..b74192f795 100644 --- a/block/replication.c +++ b/block/replication.c @@ -165,7 +165,12 @@ static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { - *nperm = BLK_PERM_CONSISTENT_READ; + if (role & BDRV_CHILD_PRIMARY) { + *nperm = BLK_PERM_CONSISTENT_READ; + } else { + *nperm = 0; + } + if ((bs->open_flags & (BDRV_O_INACTIVE | BDRV_O_RDWR)) == BDRV_O_RDWR) { *nperm |= BLK_PERM_WRITE; } @@ -557,8 +562,25 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, return; } - s->hidden_disk = hidden_disk; - s->secondary_disk = secondary_disk; + bdrv_ref(hidden_disk->bs); + s->hidden_disk = bdrv_attach_child(bs, hidden_disk->bs, "hidden disk", + &child_of_bds, BDRV_CHILD_DATA, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + aio_context_release(aio_context); + return; + } + + bdrv_ref(secondary_disk->bs); + s->secondary_disk = bdrv_attach_child(bs, secondary_disk->bs, + "secondary disk", &child_of_bds, + BDRV_CHILD_DATA, &local_err); + if (local_err) { + error_propagate(errp, local_err); + aio_context_release(aio_context); + return; + } /* start backup job now */ error_setg(&s->blocker, @@ -664,7 +686,9 @@ static void replication_done(void *opaque, int ret) if (ret == 0) { s->stage = BLOCK_REPLICATION_DONE; + bdrv_unref_child(bs, s->secondary_disk); s->secondary_disk = NULL; + bdrv_unref_child(bs, s->hidden_disk); s->hidden_disk = NULL; s->error = 0; } else { From c2cf0ecab5455f41ab56c131b21e153a3befa8b0 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Sun, 18 Jul 2021 16:48:42 +0200 Subject: [PATCH 233/531] replication: Remove workaround Remove the workaround introduced in commit 6ecbc6c52672db5c13805735ca02784879ce8285 "replication: Avoid blk_make_empty() on read-only child". It is not needed anymore since s->hidden_disk is guaranteed to be writable when secondary_do_checkpoint() runs. Because replication_start(), _do_checkpoint() and _stop() are only called by COLO migration code and COLO-migration activates all disks via bdrv_invalidate_cache_all() before it calls these functions. Signed-off-by: Lukas Straub Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: Signed-off-by: Kevin Wolf --- block/replication.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/block/replication.c b/block/replication.c index b74192f795..32444b9a8f 100644 --- a/block/replication.c +++ b/block/replication.c @@ -346,17 +346,7 @@ static void secondary_do_checkpoint(BlockDriverState *bs, Error **errp) return; } - BlockBackend *blk = blk_new(qemu_get_current_aio_context(), - BLK_PERM_WRITE, BLK_PERM_ALL); - blk_insert_bs(blk, s->hidden_disk->bs, &local_err); - if (local_err) { - error_propagate(errp, local_err); - blk_unref(blk); - return; - } - - ret = blk_make_empty(blk, errp); - blk_unref(blk); + ret = bdrv_make_empty(s->hidden_disk, errp); if (ret < 0) { return; } From 6af72274efd580fbfc048aad75d3e9af44614590 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 15 Jul 2021 15:48:53 +0300 Subject: [PATCH 234/531] block/vvfat: fix: drop backing Most probably this fake backing child doesn't work anyway (see notes about it in a8a4d15c1c34d). Still, since 25f78d9e2de528473d52 drivers are required to set .supports_backing if they want to call bdrv_set_backing_hd, so now vvfat just doesn't work because of this check. Let's finally drop this fake backing file. Fixes: 25f78d9e2de528473d52acfcf7acdfb64e3453d4 Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20210715124853.13335-1-vsementsov@virtuozzo.com> Tested-by: John Arbuckle Signed-off-by: Kevin Wolf --- block/vvfat.c | 43 ++++--------------------------------------- 1 file changed, 4 insertions(+), 39 deletions(-) diff --git a/block/vvfat.c b/block/vvfat.c index ae9d387da7..34bf1e3a86 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3098,26 +3098,6 @@ static int coroutine_fn vvfat_co_block_status(BlockDriverState *bs, return BDRV_BLOCK_DATA; } -static int coroutine_fn -write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes, - QEMUIOVector *qiov, int flags) -{ - int ret; - - BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque); - qemu_co_mutex_lock(&s->lock); - ret = try_commit(s); - qemu_co_mutex_unlock(&s->lock); - - return ret; -} - -static BlockDriver vvfat_write_target = { - .format_name = "vvfat_write_target", - .instance_size = sizeof(void*), - .bdrv_co_pwritev = write_target_commit, -}; - static void vvfat_qcow_options(BdrvChildRole role, bool parent_is_format, int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) @@ -3133,7 +3113,6 @@ static int enable_write_target(BlockDriverState *bs, Error **errp) { BDRVVVFATState *s = bs->opaque; BlockDriver *bdrv_qcow = NULL; - BlockDriverState *backing; QemuOpts *opts = NULL; int ret; int size = sector2cluster(s, s->sector_count); @@ -3184,13 +3163,6 @@ static int enable_write_target(BlockDriverState *bs, Error **errp) unlink(s->qcow_filename); #endif - backing = bdrv_new_open_driver(&vvfat_write_target, NULL, BDRV_O_ALLOW_RDWR, - &error_abort); - *(void**) backing->opaque = s; - - bdrv_set_backing_hd(s->bs, backing, &error_abort); - bdrv_unref(backing); - return 0; err: @@ -3205,17 +3177,10 @@ static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { - if (role & BDRV_CHILD_DATA) { - /* This is a private node, nobody should try to attach to it */ - *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; - *nshared = BLK_PERM_WRITE_UNCHANGED; - } else { - assert(role & BDRV_CHILD_COW); - /* The backing file is there so 'commit' can use it. vvfat doesn't - * access it in any way. */ - *nperm = 0; - *nshared = BLK_PERM_ALL; - } + assert(role & BDRV_CHILD_DATA); + /* This is a private node, nobody should try to attach to it */ + *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; + *nshared = BLK_PERM_WRITE_UNCHANGED; } static void vvfat_close(BlockDriverState *bs) From 8573823f3ba2b63926f82d5732473e0cd73c1213 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Thu, 24 Jun 2021 10:38:24 +0200 Subject: [PATCH 235/531] block/export: Conditionally ignore set-context error When invoking block-export-add with some iothread and fixed-iothread=false, and changing the node's iothread fails, the error is supposed to be ignored. However, it is still stored in *errp, which is wrong. If a second error occurs, the "*errp must be NULL" assertion in error_setv() fails: qemu-system-x86_64: ../util/error.c:59: error_setv: Assertion `*errp == NULL' failed. So if fixed-iothread=false, we should ignore the error by passing NULL to bdrv_try_set_aio_context(). Fixes: f51d23c80af73c95e0ce703ad06a300f1b3d63ef ("block/export: add iothread and fixed-iothread options") Signed-off-by: Max Reitz Message-Id: <20210624083825.29224-2-mreitz@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Kevin Wolf --- block/export/export.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/block/export/export.c b/block/export/export.c index fec7d9f738..6d3b9964c8 100644 --- a/block/export/export.c +++ b/block/export/export.c @@ -111,6 +111,7 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp) if (export->has_iothread) { IOThread *iothread; AioContext *new_ctx; + Error **set_context_errp; iothread = iothread_by_id(export->iothread); if (!iothread) { @@ -120,7 +121,9 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp) new_ctx = iothread_get_aio_context(iothread); - ret = bdrv_try_set_aio_context(bs, new_ctx, errp); + /* Ignore errors with fixed-iothread=false */ + set_context_errp = fixed_iothread ? errp : NULL; + ret = bdrv_try_set_aio_context(bs, new_ctx, set_context_errp); if (ret == 0) { aio_context_release(ctx); aio_context_acquire(new_ctx); From d21471696b07f30cb00453709d055a25c1afde85 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Thu, 24 Jun 2021 10:38:25 +0200 Subject: [PATCH 236/531] iotests/307: Test iothread conflict for exports Passing fixed-iothread=true should make iothread conflicts fatal, whereas fixed-iothread=false should not. Combine the second case with an error condition that is checked after the iothread is handled, to verify that qemu does not crash if there is such an error after changing the iothread failed. Signed-off-by: Max Reitz Message-Id: <20210624083825.29224-3-mreitz@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Tested-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Kevin Wolf --- tests/qemu-iotests/307 | 15 +++++++++++++++ tests/qemu-iotests/307.out | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/tests/qemu-iotests/307 b/tests/qemu-iotests/307 index c7685347bc..b429b5aa50 100755 --- a/tests/qemu-iotests/307 +++ b/tests/qemu-iotests/307 @@ -41,9 +41,11 @@ with iotests.FilePath('image') as img, \ iotests.log('=== Launch VM ===') vm.add_object('iothread,id=iothread0') + vm.add_object('iothread,id=iothread1') vm.add_blockdev(f'file,filename={img},node-name=file') vm.add_blockdev(f'{iotests.imgfmt},file=file,node-name=fmt') vm.add_blockdev('raw,file=file,node-name=ro,read-only=on') + vm.add_blockdev('null-co,node-name=null') vm.add_device(f'id=scsi0,driver=virtio-scsi,iothread=iothread0') vm.launch() @@ -74,6 +76,19 @@ with iotests.FilePath('image') as img, \ vm.qmp_log('query-block-exports') iotests.qemu_nbd_list_log('-k', socket) + iotests.log('\n=== Add export with conflicting iothread ===') + + vm.qmp_log('device_add', id='sdb', driver='scsi-hd', drive='null') + + # Should fail because of fixed-iothread + vm.qmp_log('block-export-add', id='export1', type='nbd', node_name='null', + iothread='iothread1', fixed_iothread=True, writable=True) + + # Should ignore the iothread conflict, but then fail because of the + # permission conflict (and not crash) + vm.qmp_log('block-export-add', id='export1', type='nbd', node_name='null', + iothread='iothread1', fixed_iothread=False, writable=True) + iotests.log('\n=== Add a writable export ===') # This fails because share-rw=off diff --git a/tests/qemu-iotests/307.out b/tests/qemu-iotests/307.out index 4b0c7e155a..ec8d2be0e0 100644 --- a/tests/qemu-iotests/307.out +++ b/tests/qemu-iotests/307.out @@ -51,6 +51,14 @@ exports available: 1 base:allocation +=== Add export with conflicting iothread === +{"execute": "device_add", "arguments": {"drive": "null", "driver": "scsi-hd", "id": "sdb"}} +{"return": {}} +{"execute": "block-export-add", "arguments": {"fixed-iothread": true, "id": "export1", "iothread": "iothread1", "node-name": "null", "type": "nbd", "writable": true}} +{"error": {"class": "GenericError", "desc": "Cannot change iothread of active block backend"}} +{"execute": "block-export-add", "arguments": {"fixed-iothread": false, "id": "export1", "iothread": "iothread1", "node-name": "null", "type": "nbd", "writable": true}} +{"error": {"class": "GenericError", "desc": "Permission conflict on node 'null': permissions 'write' are both required by an unnamed block device (uses node 'null' as 'root' child) and unshared by block device 'sdb' (uses node 'null' as 'root' child)."}} + === Add a writable export === {"execute": "block-export-add", "arguments": {"description": "This is the writable second export", "id": "export1", "name": "export1", "node-name": "fmt", "type": "nbd", "writable": true, "writethrough": true}} {"error": {"class": "GenericError", "desc": "Permission conflict on node 'fmt': permissions 'write' are both required by an unnamed block device (uses node 'fmt' as 'root' child) and unshared by block device 'sda' (uses node 'fmt' as 'root' child)."}} From e72f9524febb78ee5ae2a201245cd7b1fb97ad08 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jul 2021 19:14:37 +0200 Subject: [PATCH 237/531] qemu-config: never call the callback after an error, fix leak Ensure that the callback to qemu_config_foreach is never called upon an error, by moving the invocation before the "out" label. Cc: armbru@redhat.com Fixes: 3770141139 ("qemu-config: parse configuration files to a QDict", 2021-06-04) Signed-off-by: Paolo Bonzini --- util/qemu-config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/qemu-config.c b/util/qemu-config.c index 84ee6dc4ea..7db810f1e0 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -417,12 +417,12 @@ static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque, return res; } res = count; -out: if (qdict) { cb(group, qdict, opaque, errp); - qobject_unref(qdict); } +out: loc_pop(&loc); + qobject_unref(qdict); return res; } From 461fea9bf1db0e122cfc18ea07958ddebea5d9a3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jul 2021 19:14:37 +0200 Subject: [PATCH 238/531] qemu-config: fix memory leak on ferror() The leak is basically impossible to reach, since the only common way to get ferror(fp) is by passing a directory to -readconfig. In that case, the error occurs before qdict is set to anything non-NULL. However, it's theoretically possible to get there after an EIO. Cc: armbru@redhat.com Reported-by: Peter Maydell Fixes: f7544edcd3 ("qemu-config: add error propagation to qemu_config_parse", 2021-03-06) Signed-off-by: Paolo Bonzini --- util/qemu-config.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/qemu-config.c b/util/qemu-config.c index 7db810f1e0..fdf6cd69fc 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -414,7 +414,7 @@ static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque, if (ferror(fp)) { loc_pop(&loc); error_setg_errno(errp, errno, "Cannot read config file"); - return res; + goto out_no_loc; } res = count; if (qdict) { @@ -422,6 +422,7 @@ static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque, } out: loc_pop(&loc); +out_no_loc: qobject_unref(qdict); return res; } From dadafe6785ada3ec4a2d11410c691458b3c2b39f Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Mon, 12 Jul 2021 22:15:52 -0400 Subject: [PATCH 239/531] vl: Parse legacy default_machine_opts qemu can't start a xen vm after commit d8fb7d0969d5 "vl: switch -M parsing to keyval" with: $ ./qemu-system-i386 -M xenfv Unexpected error in object_property_find_err() at ../qom/object.c:1298: qemu-system-i386: Property 'xenfv-3.1-machine.accel' not found Aborted (core dumped) The default_machine_opts handling doesn't process the legacy machine options like "accel". Call qemu_apply_legacy_machine_options to provide the legacy handling. Signed-off-by: Jason Andryuk Message-Id: <20210713021552.19110-1-jandryuk@gmail.com> Signed-off-by: Paolo Bonzini --- softmmu/vl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/softmmu/vl.c b/softmmu/vl.c index 4df1496101..f4d8630fc6 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2126,6 +2126,7 @@ static void qemu_create_machine(QDict *qdict) QDict *default_opts = keyval_parse(machine_class->default_machine_opts, NULL, NULL, &error_abort); + qemu_apply_legacy_machine_options(default_opts); object_set_properties_from_keyval(OBJECT(current_machine), default_opts, false, &error_abort); qobject_unref(default_opts); From d2c7c18cc7f3ce6c1ac54d02e11d7bb7df9b913b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 14 May 2021 11:44:34 +0200 Subject: [PATCH 240/531] hw/pci-host/Kconfig: Add missing dependency MV64361 -> I8259 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looking at the MV64341 model source, there is a dependency on the 8259 interrupt controller: 523 case MV64340_PCI_1_INTERRUPT_ACKNOWLEDGE_VIRTUAL_REG: 524 /* FIXME: Should this be sent via the PCI bus somehow? */ 525 if (s->gpp_int_level && (s->gpp_value & BIT(31))) { 526 ret = pic_read_irq(isa_pic); 527 } 528 break; Add it to Kconfig to avoid the following build failure: /usr/bin/ld: libcommon.fa.p/hw_pci-host_mv64361.c.o: in function `mv64361_read': hw/pci-host/mv64361.c:526: undefined reference to `isa_pic' /usr/bin/ld: hw/pci-host/mv64361.c:526: undefined reference to `pic_read_irq' Fixes: dcdf98a9015 ("hw/pci-host: Add emulation of Marvell MV64361 PPC system controller") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: BALATON Zoltan Reviewed-by: Bin Meng Acked-by: David Gibson Message-Id: <20210515173716.358295-10-philmd@redhat.com> --- hw/pci-host/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index 84494400b8..2b5f7d58cc 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -76,3 +76,4 @@ config SH_PCI config MV64361 bool select PCI + select I8259 From 16c67cae843d29ac29cf632b47bc1f961a90b1e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 14 May 2021 11:50:03 +0200 Subject: [PATCH 241/531] hw/isa/vt82c686: Add missing Kconfig dependencies (build error) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VT82C686 device model misses various dependencies: /usr/bin/ld: libcommon.fa.p/hw_isa_vt82c686.c.o: in function `vt82c686b_realize': hw/isa/vt82c686.c:622: undefined reference to `i8259_init' /usr/bin/ld: hw/isa/vt82c686.c:624: undefined reference to `i8257_dma_init' /usr/bin/ld: hw/isa/vt82c686.c:627: undefined reference to `mc146818_rtc_init' Add them. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: BALATON Zoltan Reviewed-by: Bin Meng Message-Id: <20210515173716.358295-11-philmd@redhat.com> --- hw/isa/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig index 96db170eff..f99df0e20b 100644 --- a/hw/isa/Kconfig +++ b/hw/isa/Kconfig @@ -50,6 +50,9 @@ config VT82C686 select FDC_ISA select USB_UHCI select APM + select I8257 + select I8259 + select MC146818RTC config SMC37C669 bool From ba4253cef26ba612d3a4413744c86c625e46bb2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 14 May 2021 11:56:57 +0200 Subject: [PATCH 242/531] hw/isa/vt82c686: Add missing Kconfig dependency (runtime error) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building the Pegasos2 machine stand-alone we get: $ qemu-system-ppc -M pegasos2 -bios pegasos2.rom ERROR:qom/object.c:714:object_new_with_type: assertion failed: (type != NULL) Bail out! ERROR:qom/object.c:714:object_new_with_type: assertion failed: (type != NULL) Looking at the backtraces: Thread 1 "qemu-system-ppc" received signal SIGABRT, Aborted. (gdb) bt #0 0x00007ffff53877d5 in raise () at /lib64/libc.so.6 #1 0x00007ffff5370895 in abort () at /lib64/libc.so.6 #2 0x00007ffff6dc4b6c in g_assertion_message_expr.cold () at /lib64/libglib-2.0.so.0 #3 0x00007ffff6e229ff in g_assertion_message_expr () at /lib64/libglib-2.0.so.0 #4 0x0000555555a0c8f4 in object_new_with_type (type=0x0) at qom/object.c:714 #5 0x0000555555a0c9d5 in object_new (typename=0x555555c7afe4 "isa-pit") at qom/object.c:747 #6 0x0000555555a053b8 in qdev_new (name=0x555555c7afe4 "isa-pit") at hw/core/qdev.c:153 #7 0x00005555557cdd05 in isa_new (name=0x555555c7afe4 "isa-pit") at hw/isa/isa-bus.c:160 #8 0x00005555557cf518 in i8254_pit_init (bus=0x55555603d140, base=64, isa_irq=0, alt_irq=0x0) at include/hw/timer/i8254.h:54 #9 0x00005555557d12f9 in vt8231_realize (d=0x5555563d9770, errp=0x7fffffffcc28) at hw/isa/vt82c686.c:704 (gdb) bt #0 0x00007ffff54bd7d5 in raise () at /lib64/libc.so.6 #1 0x00007ffff54a6895 in abort () at /lib64/libc.so.6 #2 0x00005555558f7796 in object_new (typename=0x555555ad4889 "isa-parallel") at qom/object.c:749 #3 object_new (typename=type0x555555ad4889 "isa-parallel") at qom/object.c:743 #4 0x00005555558f0d46 in qdev_new (name=0x555555ad4889 "isa-parallel") at hw/core/qdev.c:153 #5 0x000055555576b669 in isa_new (name=0x555555ad4889 "isa-parallel") at hw/isa/isa-bus.c:160 #6 0x000055555576bbe8 in isa_superio_realize (dev=0x555555f15910, errp=) at hw/isa/isa-superio.c:54 #7 0x000055555576d5ed in via_superio_realize (d=0x555555f15910, errp=0x7fffffffcb30) at hw/isa/vt82c686.c:292 #8 0x00005555558f12c1 in device_set_realized (obj=, ...) at hw/core/qdev.c:761 #9 0x00005555558f5066 in property_set_bool (obj=0x555555f15910, ..., errp=0x7fffffffcbb0) at qom/object.c:2262 #10 0x00005555558f7f38 in object_property_set (obj=0x555555f15910, name=0x555555b1b1e3 "realized", ...) at qom/object.c:1407 #11 0x00005555558fb2d0 in object_property_set_qobject (obj=0x555555f15910, name=0x555555b1b1e3 "realized", ...) at qom/qom-qobject.c:28 #12 0x00005555558f8525 in object_property_set_bool (obj=0x555555f15910, name=0x555555b1b1e3 "realized", ...) at qom/object.c:1477 #13 0x00005555558f18ee in qdev_realize (dev=0x555555f15910, bus=0x55555602a610, errp=) at hw/core/qdev.c:389 #14 0x00005555558f197f in qdev_realize_and_unref (dev=0x555555f15910, bus=0x55555602a610, errp=) at hw/core/qdev.c:396 #15 0x000055555576b709 in isa_realize_and_unref (errp=, bus=0x55555602a610, dev=0x555555f15910) at hw/isa/isa-bus.c:179 #16 isa_create_simple (bus=0x55555602a610, name=0x555555adc33b "vt8231-superio") at hw/isa/isa-bus.c:173 #17 0x000055555576d9b7 in vt8231_realize (d=0x555556186a50, errp=) at hw/isa/vt82c686.c:706 The "isa-pit" type (TYPE_I8254) and "isa-parallel" are missing. Add them. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: BALATON Zoltan Reviewed-by: Bin Meng Message-Id: <20210515173716.358295-12-philmd@redhat.com> [PMD: Added "isa-parallel" later] --- hw/isa/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig index f99df0e20b..d42143a991 100644 --- a/hw/isa/Kconfig +++ b/hw/isa/Kconfig @@ -50,9 +50,11 @@ config VT82C686 select FDC_ISA select USB_UHCI select APM + select I8254 select I8257 select I8259 select MC146818RTC + select PARALLEL config SMC37C669 bool From d1751d8b5d9bb0eb876c8b7226b18c1d6eedd179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 14 May 2021 11:53:20 +0200 Subject: [PATCH 243/531] hw/ppc/Kconfig: Add dependency PEGASOS2 -> ATI_VGA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ATI VGA device isn't a requisite for the Pegasos2 machine because Linux only uses the serial console; see commit ba7e5ac18e7 ("hw/ppc: Add emulation of Genesi/bPlan Pegasos II") for rationale. Using the default devices we don't have any problem: $ qemu-system-ppc -M pegasos2 qemu-system-ppc: standard VGA not available But when trying to explicitly use the ATI device we get an error: $ qemu-system-ppc -M pegasos2 -vga none -bios pegasos2.rom -device ati-vga,romfile= qemu-system-ppc: -device ati-vga,romfile=: 'ati-vga' is not a valid device model name Add it as an implicit Kconfig dependency. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210515173716.358295-13-philmd@redhat.com> Acked-by: BALATON Zoltan Reviewed-by: Bin Meng Acked-by: David Gibson --- hw/ppc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig index 85b9c93f02..400511c6b7 100644 --- a/hw/ppc/Kconfig +++ b/hw/ppc/Kconfig @@ -79,6 +79,7 @@ config PEGASOS2 select VOF # This should come with VT82C686 select ACPI_X86 + imply ATI_VGA config PREP bool From 8ea754386545d0edde1e270f581e4827baa85ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 20 Jul 2021 12:40:55 +0100 Subject: [PATCH 244/531] hw/tricore: fix inclusion of tricore_testboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because commit f4063f9c319e39 ("meson: Introduce target-specific Kconfig") ended being merged after commit 582079c9d27fc8cfff9f49 ("hw/tricore: Add testdevice for tests in tests/tcg/"), we inadvertently added a symbol clash causing the build not to include the testboard needed for check-tcg. Fixes: f4063f9c31 ("meson: Introduce target-specific Kconfig") Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20210720114057.32053-2-alex.bennee@linaro.org> [PMD: Updated description mentioning commits merged] Signed-off-by: Philippe Mathieu-Daudé --- configs/devices/tricore-softmmu/default.mak | 1 + hw/tricore/Kconfig | 3 +-- hw/tricore/meson.build | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configs/devices/tricore-softmmu/default.mak b/configs/devices/tricore-softmmu/default.mak index 5cc91cebce..cb8fc286eb 100644 --- a/configs/devices/tricore-softmmu/default.mak +++ b/configs/devices/tricore-softmmu/default.mak @@ -1 +1,2 @@ +CONFIG_TRICORE_TESTBOARD=y CONFIG_TRIBOARD=y diff --git a/hw/tricore/Kconfig b/hw/tricore/Kconfig index 506e6183c1..33c1e852c3 100644 --- a/hw/tricore/Kconfig +++ b/hw/tricore/Kconfig @@ -1,9 +1,8 @@ -config TRICORE +config TRICORE_TESTBOARD bool config TRIBOARD bool - select TRICORE select TC27X_SOC config TC27X_SOC diff --git a/hw/tricore/meson.build b/hw/tricore/meson.build index 47e36bb077..7e3585daf8 100644 --- a/hw/tricore/meson.build +++ b/hw/tricore/meson.build @@ -1,6 +1,6 @@ tricore_ss = ss.source_set() -tricore_ss.add(when: 'CONFIG_TRICORE', if_true: files('tricore_testboard.c')) -tricore_ss.add(when: 'CONFIG_TRICORE', if_true: files('tricore_testdevice.c')) +tricore_ss.add(when: 'CONFIG_TRICORE_TESTBOARD', if_true: files('tricore_testboard.c')) +tricore_ss.add(when: 'CONFIG_TRICORE_TESTBOARD', if_true: files('tricore_testdevice.c')) tricore_ss.add(when: 'CONFIG_TRIBOARD', if_true: files('triboard.c')) tricore_ss.add(when: 'CONFIG_TC27X_SOC', if_true: files('tc27x_soc.c')) From 8ee6e2811db7bc5efb4b75bfc68e6e06b5cf520e Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Wed, 14 Jul 2021 13:40:46 -0400 Subject: [PATCH 245/531] tests/acceptance/virtio-gpu.py: use require_accelerator() Since efe30d501 there's a shorthand for requiring specific accelerators, and canceling the test if it's not available. Signed-off-by: Cleber Rosa Message-Id: <20210714174051.28164-2-crosa@redhat.com> Reviewed-by: Willian Rampazzo Signed-off-by: Cleber Rosa --- tests/acceptance/virtio-gpu.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/acceptance/virtio-gpu.py b/tests/acceptance/virtio-gpu.py index 589332c1b7..42602a240a 100644 --- a/tests/acceptance/virtio-gpu.py +++ b/tests/acceptance/virtio-gpu.py @@ -17,10 +17,6 @@ import socket import subprocess -ACCEL_NOT_AVAILABLE_FMT = "%s accelerator does not seem to be available" -KVM_NOT_AVAILABLE = ACCEL_NOT_AVAILABLE_FMT % "KVM" - - def pick_default_vug_bin(): relative_path = "./contrib/vhost-user-gpu/vhost-user-gpu" if is_readable_executable_file(relative_path): @@ -66,8 +62,7 @@ class VirtioGPUx86(Test): self.KERNEL_COMMON_COMMAND_LINE + "console=ttyS0 rdinit=/bin/bash" ) # FIXME: should check presence of virtio, virgl etc - if not kvm_available(self.arch, self.qemu_bin): - self.cancel(KVM_NOT_AVAILABLE) + self.require_accelerator('kvm') kernel_path = self.fetch_asset(self.KERNEL_URL) initrd_path = self.fetch_asset(self.INITRD_URL) @@ -107,8 +102,7 @@ class VirtioGPUx86(Test): self.KERNEL_COMMON_COMMAND_LINE + "console=ttyS0 rdinit=/bin/bash" ) # FIXME: should check presence of vhost-user-gpu, virgl, memfd etc - if not kvm_available(self.arch, self.qemu_bin): - self.cancel(KVM_NOT_AVAILABLE) + self.require_accelerator('kvm') vug = pick_default_vug_bin() if not vug: From cc6a2457a1e09729af013a91ff7c456560d96b2b Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Wed, 14 Jul 2021 13:40:47 -0400 Subject: [PATCH 246/531] tests/acceptance/virtio-gpu.py: combine x86_64 arch tags The test class in question is x86_64 specific, so it's possible to set the tags at the class level. Signed-off-by: Cleber Rosa Message-Id: <20210714174051.28164-3-crosa@redhat.com> Reviewed-by: Willian Rampazzo Signed-off-by: Cleber Rosa --- tests/acceptance/virtio-gpu.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/acceptance/virtio-gpu.py b/tests/acceptance/virtio-gpu.py index 42602a240a..729b99b2e5 100644 --- a/tests/acceptance/virtio-gpu.py +++ b/tests/acceptance/virtio-gpu.py @@ -30,6 +30,7 @@ def pick_default_vug_bin(): class VirtioGPUx86(Test): """ :avocado: tags=virtio-gpu + :avocado: tags=arch:x86_64 """ KERNEL_COMMON_COMMAND_LINE = "printk.time=0 " @@ -54,7 +55,6 @@ class VirtioGPUx86(Test): def test_virtio_vga_virgl(self): """ - :avocado: tags=arch:x86_64 :avocado: tags=device:virtio-vga :avocado: tags=cpu:host """ @@ -94,7 +94,6 @@ class VirtioGPUx86(Test): def test_vhost_user_vga_virgl(self): """ - :avocado: tags=arch:x86_64 :avocado: tags=device:vhost-user-vga :avocado: tags=cpu:host """ From 3c6eb9c6f03ed5d28bf1b3c344b06f72d18cc670 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Wed, 14 Jul 2021 13:40:48 -0400 Subject: [PATCH 247/531] tests/acceptance/virtio-gpu.py: combine CPU tags Like previously done with the arch tags, all tests use the same CPU value so it's possible to combine them at the class level. Signed-off-by: Cleber Rosa Message-Id: <20210714174051.28164-4-crosa@redhat.com> Reviewed-by: Willian Rampazzo Signed-off-by: Cleber Rosa --- tests/acceptance/virtio-gpu.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/acceptance/virtio-gpu.py b/tests/acceptance/virtio-gpu.py index 729b99b2e5..20a59fabf3 100644 --- a/tests/acceptance/virtio-gpu.py +++ b/tests/acceptance/virtio-gpu.py @@ -31,6 +31,7 @@ class VirtioGPUx86(Test): """ :avocado: tags=virtio-gpu :avocado: tags=arch:x86_64 + :avocado: tags=cpu:host """ KERNEL_COMMON_COMMAND_LINE = "printk.time=0 " @@ -56,7 +57,6 @@ class VirtioGPUx86(Test): def test_virtio_vga_virgl(self): """ :avocado: tags=device:virtio-vga - :avocado: tags=cpu:host """ kernel_command_line = ( self.KERNEL_COMMON_COMMAND_LINE + "console=ttyS0 rdinit=/bin/bash" @@ -95,7 +95,6 @@ class VirtioGPUx86(Test): def test_vhost_user_vga_virgl(self): """ :avocado: tags=device:vhost-user-vga - :avocado: tags=cpu:host """ kernel_command_line = ( self.KERNEL_COMMON_COMMAND_LINE + "console=ttyS0 rdinit=/bin/bash" From 532835d02289134450ec22c8958b7c9f7212bdb4 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Wed, 14 Jul 2021 13:40:49 -0400 Subject: [PATCH 248/531] tests/acceptance/virtio-gpu.py: combine kernel command line Both tests use the same kernel command line arguments, so there's no need to have a common and then an additional set of arguments. Signed-off-by: Cleber Rosa Message-Id: <20210714174051.28164-5-crosa@redhat.com> Reviewed-by: Willian Rampazzo Signed-off-by: Cleber Rosa --- tests/acceptance/virtio-gpu.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/acceptance/virtio-gpu.py b/tests/acceptance/virtio-gpu.py index 20a59fabf3..fbde278705 100644 --- a/tests/acceptance/virtio-gpu.py +++ b/tests/acceptance/virtio-gpu.py @@ -34,7 +34,7 @@ class VirtioGPUx86(Test): :avocado: tags=cpu:host """ - KERNEL_COMMON_COMMAND_LINE = "printk.time=0 " + KERNEL_COMMAND_LINE = "printk.time=0 console=ttyS0 rdinit=/bin/bash" KERNEL_URL = ( "https://archives.fedoraproject.org/pub/fedora" "/linux/releases/33/Everything/x86_64/os/images" @@ -58,9 +58,6 @@ class VirtioGPUx86(Test): """ :avocado: tags=device:virtio-vga """ - kernel_command_line = ( - self.KERNEL_COMMON_COMMAND_LINE + "console=ttyS0 rdinit=/bin/bash" - ) # FIXME: should check presence of virtio, virgl etc self.require_accelerator('kvm') @@ -78,7 +75,7 @@ class VirtioGPUx86(Test): "-initrd", initrd_path, "-append", - kernel_command_line, + self.KERNEL_COMMAND_LINE, ) try: self.vm.launch() @@ -96,9 +93,6 @@ class VirtioGPUx86(Test): """ :avocado: tags=device:vhost-user-vga """ - kernel_command_line = ( - self.KERNEL_COMMON_COMMAND_LINE + "console=ttyS0 rdinit=/bin/bash" - ) # FIXME: should check presence of vhost-user-gpu, virgl, memfd etc self.require_accelerator('kvm') @@ -145,7 +139,7 @@ class VirtioGPUx86(Test): "-initrd", initrd_path, "-append", - kernel_command_line, + self.KERNEL_COMMAND_LINE, ) self.vm.launch() self.wait_for_console_pattern("as init process") From 3a05eee2fea17a0248307cbd627de469b91affb6 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Wed, 14 Jul 2021 13:40:50 -0400 Subject: [PATCH 249/531] tests/acceptance/virtio-gpu.py: use virtio-vga-gl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 49afbca3b, the use of an optional virgl renderer is not available anymore, and since b36eb8860f, the way to choose a GL based rendered is to use the "virtio-vga-gl" device. Signed-off-by: Cleber Rosa Message-Id: <20210714174051.28164-6-crosa@redhat.com> Reviewed-by: Willian Rampazzo Reviewed-by: Marc-André Lureau Signed-off-by: Cleber Rosa --- tests/acceptance/virtio-gpu.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/acceptance/virtio-gpu.py b/tests/acceptance/virtio-gpu.py index fbde278705..0f84affe82 100644 --- a/tests/acceptance/virtio-gpu.py +++ b/tests/acceptance/virtio-gpu.py @@ -56,7 +56,7 @@ class VirtioGPUx86(Test): def test_virtio_vga_virgl(self): """ - :avocado: tags=device:virtio-vga + :avocado: tags=device:virtio-vga-gl """ # FIXME: should check presence of virtio, virgl etc self.require_accelerator('kvm') @@ -67,7 +67,7 @@ class VirtioGPUx86(Test): self.vm.set_console() self.vm.add_args("-m", "2G") self.vm.add_args("-machine", "pc,accel=kvm") - self.vm.add_args("-device", "virtio-vga,virgl=on") + self.vm.add_args("-device", "virtio-vga-gl") self.vm.add_args("-display", "egl-headless") self.vm.add_args( "-kernel", From 074fca10c01a2e76d5bb3bf0cec377e809066a47 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Wed, 14 Jul 2021 13:40:51 -0400 Subject: [PATCH 250/531] tests/acceptance/virtio-gpu.py: provide kernel and initrd hashes By providing kernel and initrd hashes, the test guarantees the integrity of the images used and avoids the warnings set by fetch_asset() when hashes are lacking. Signed-off-by: Cleber Rosa Message-Id: <20210714174051.28164-7-crosa@redhat.com> Reviewed-by: Willian Rampazzo Signed-off-by: Cleber Rosa --- tests/acceptance/virtio-gpu.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/acceptance/virtio-gpu.py b/tests/acceptance/virtio-gpu.py index 0f84affe82..4acc1e6d5f 100644 --- a/tests/acceptance/virtio-gpu.py +++ b/tests/acceptance/virtio-gpu.py @@ -40,11 +40,13 @@ class VirtioGPUx86(Test): "/linux/releases/33/Everything/x86_64/os/images" "/pxeboot/vmlinuz" ) + KERNEL_HASH = '1433cfe3f2ffaa44de4ecfb57ec25dc2399cdecf' INITRD_URL = ( "https://archives.fedoraproject.org/pub/fedora" "/linux/releases/33/Everything/x86_64/os/images" "/pxeboot/initrd.img" ) + INITRD_HASH = 'c828d68a027b53e5220536585efe03412332c2d9' def wait_for_console_pattern(self, success_message, vm=None): wait_for_console_pattern( @@ -61,8 +63,8 @@ class VirtioGPUx86(Test): # FIXME: should check presence of virtio, virgl etc self.require_accelerator('kvm') - kernel_path = self.fetch_asset(self.KERNEL_URL) - initrd_path = self.fetch_asset(self.INITRD_URL) + kernel_path = self.fetch_asset(self.KERNEL_URL, self.KERNEL_HASH) + initrd_path = self.fetch_asset(self.INITRD_URL, self.INITRD_HASH) self.vm.set_console() self.vm.add_args("-m", "2G") @@ -100,8 +102,8 @@ class VirtioGPUx86(Test): if not vug: self.cancel("Could not find vhost-user-gpu") - kernel_path = self.fetch_asset(self.KERNEL_URL) - initrd_path = self.fetch_asset(self.INITRD_URL) + kernel_path = self.fetch_asset(self.KERNEL_URL, self.KERNEL_HASH) + initrd_path = self.fetch_asset(self.INITRD_URL, self.INITRD_HASH) # Create socketpair to connect proxy and remote processes qemu_sock, vug_sock = socket.socketpair( From f4a3fda43e389fa26d41ec9cd24f42c5fe20ba9d Mon Sep 17 00:00:00 2001 From: Yang Zhong Date: Fri, 9 Jul 2021 13:28:00 +0800 Subject: [PATCH 251/531] remote/memory: Replace share parameter with ram_flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: d5015b801340 ("softmmu/memory: Pass ram_flags to qemu_ram_alloc_from_fd()") Signed-off-by: Yang Zhong Reviewed-by: David Hildenbrand Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pankaj Gupta Reviewed-by: Peter Xu Message-Id: <20210709052800.63588-1-yang.zhong@intel.com> Signed-off-by: Cleber Rosa --- hw/remote/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/remote/memory.c b/hw/remote/memory.c index 472ed2a272..6e21ab1a45 100644 --- a/hw/remote/memory.c +++ b/hw/remote/memory.c @@ -46,7 +46,7 @@ void remote_sysmem_reconfig(MPQemuMsg *msg, Error **errp) subregion = g_new(MemoryRegion, 1); memory_region_init_ram_from_fd(subregion, NULL, name, sysmem_info->sizes[region], - true, msg->fds[region], + RAM_SHARED, msg->fds[region], sysmem_info->offsets[region], errp); From 0445409d7497bededa1047f0d8298b0d4bb3b1a3 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Wed, 21 Jul 2021 11:42:09 +0200 Subject: [PATCH 252/531] iothread: generalize iothread_set_param/iothread_get_param Changes in preparation for next patches where we add a new parameter not related to the poll mechanism. Let's add two new generic functions (iothread_set_param and iothread_get_param) that we use to set and get IOThread parameters. Signed-off-by: Stefano Garzarella Message-id: 20210721094211.69853-2-sgarzare@redhat.com Signed-off-by: Stefan Hajnoczi --- iothread.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/iothread.c b/iothread.c index 2c5ccd7367..103679a16b 100644 --- a/iothread.c +++ b/iothread.c @@ -213,7 +213,7 @@ static PollParamInfo poll_shrink_info = { "poll-shrink", offsetof(IOThread, poll_shrink), }; -static void iothread_get_poll_param(Object *obj, Visitor *v, +static void iothread_get_param(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { IOThread *iothread = IOTHREAD(obj); @@ -223,7 +223,7 @@ static void iothread_get_poll_param(Object *obj, Visitor *v, visit_type_int64(v, name, field, errp); } -static void iothread_set_poll_param(Object *obj, Visitor *v, +static bool iothread_set_param(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { IOThread *iothread = IOTHREAD(obj); @@ -232,17 +232,36 @@ static void iothread_set_poll_param(Object *obj, Visitor *v, int64_t value; if (!visit_type_int64(v, name, &value, errp)) { - return; + return false; } if (value < 0) { error_setg(errp, "%s value must be in range [0, %" PRId64 "]", info->name, INT64_MAX); - return; + return false; } *field = value; + return true; +} + +static void iothread_get_poll_param(Object *obj, Visitor *v, + const char *name, void *opaque, Error **errp) +{ + + iothread_get_param(obj, v, name, opaque, errp); +} + +static void iothread_set_poll_param(Object *obj, Visitor *v, + const char *name, void *opaque, Error **errp) +{ + IOThread *iothread = IOTHREAD(obj); + + if (!iothread_set_param(obj, v, name, opaque, errp)) { + return; + } + if (iothread->ctx) { aio_context_set_poll_params(iothread->ctx, iothread->poll_max_ns, From 1793ad0247cad35db1ebbc04fbea0446c30a27ca Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Wed, 21 Jul 2021 11:42:10 +0200 Subject: [PATCH 253/531] iothread: add aio-max-batch parameter The `aio-max-batch` parameter will be propagated to AIO engines and it will be used to control the maximum number of queued requests. When there are in queue a number of requests equal to `aio-max-batch`, the engine invokes the system call to forward the requests to the kernel. This parameter allows us to control the maximum batch size to reduce the latency that requests might accumulate while queued in the AIO engine queue. If `aio-max-batch` is equal to 0 (default value), the AIO engine will use its default maximum batch size value. Signed-off-by: Stefano Garzarella Message-id: 20210721094211.69853-3-sgarzare@redhat.com Signed-off-by: Stefan Hajnoczi --- include/block/aio.h | 12 +++++++++ include/sysemu/iothread.h | 3 +++ iothread.c | 55 +++++++++++++++++++++++++++++++++++---- monitor/hmp-cmds.c | 2 ++ qapi/misc.json | 6 ++++- qapi/qom.json | 7 ++++- qemu-options.hx | 8 ++++-- util/aio-posix.c | 12 +++++++++ util/aio-win32.c | 5 ++++ util/async.c | 2 ++ 10 files changed, 103 insertions(+), 9 deletions(-) diff --git a/include/block/aio.h b/include/block/aio.h index 807edce9b5..47fbe9d81f 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -232,6 +232,9 @@ struct AioContext { int64_t poll_grow; /* polling time growth factor */ int64_t poll_shrink; /* polling time shrink factor */ + /* AIO engine parameters */ + int64_t aio_max_batch; /* maximum number of requests in a batch */ + /* * List of handlers participating in userspace polling. Protected by * ctx->list_lock. Iterated and modified mostly by the event loop thread @@ -755,4 +758,13 @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, int64_t grow, int64_t shrink, Error **errp); +/** + * aio_context_set_aio_params: + * @ctx: the aio context + * @max_batch: maximum number of requests in a batch, 0 means that the + * engine will use its default + */ +void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch, + Error **errp); + #endif diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h index f177142f16..7f714bd136 100644 --- a/include/sysemu/iothread.h +++ b/include/sysemu/iothread.h @@ -37,6 +37,9 @@ struct IOThread { int64_t poll_max_ns; int64_t poll_grow; int64_t poll_shrink; + + /* AioContext AIO engine parameters */ + int64_t aio_max_batch; }; typedef struct IOThread IOThread; diff --git a/iothread.c b/iothread.c index 103679a16b..ddbbde61f7 100644 --- a/iothread.c +++ b/iothread.c @@ -152,6 +152,24 @@ static void iothread_init_gcontext(IOThread *iothread) iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE); } +static void iothread_set_aio_context_params(IOThread *iothread, Error **errp) +{ + ERRP_GUARD(); + + aio_context_set_poll_params(iothread->ctx, + iothread->poll_max_ns, + iothread->poll_grow, + iothread->poll_shrink, + errp); + if (*errp) { + return; + } + + aio_context_set_aio_params(iothread->ctx, + iothread->aio_max_batch, + errp); +} + static void iothread_complete(UserCreatable *obj, Error **errp) { Error *local_error = NULL; @@ -171,11 +189,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp) */ iothread_init_gcontext(iothread); - aio_context_set_poll_params(iothread->ctx, - iothread->poll_max_ns, - iothread->poll_grow, - iothread->poll_shrink, - &local_error); + iothread_set_aio_context_params(iothread, &local_error); if (local_error) { error_propagate(errp, local_error); aio_context_unref(iothread->ctx); @@ -212,6 +226,9 @@ static PollParamInfo poll_grow_info = { static PollParamInfo poll_shrink_info = { "poll-shrink", offsetof(IOThread, poll_shrink), }; +static PollParamInfo aio_max_batch_info = { + "aio-max-batch", offsetof(IOThread, aio_max_batch), +}; static void iothread_get_param(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) @@ -271,6 +288,29 @@ static void iothread_set_poll_param(Object *obj, Visitor *v, } } +static void iothread_get_aio_param(Object *obj, Visitor *v, + const char *name, void *opaque, Error **errp) +{ + + iothread_get_param(obj, v, name, opaque, errp); +} + +static void iothread_set_aio_param(Object *obj, Visitor *v, + const char *name, void *opaque, Error **errp) +{ + IOThread *iothread = IOTHREAD(obj); + + if (!iothread_set_param(obj, v, name, opaque, errp)) { + return; + } + + if (iothread->ctx) { + aio_context_set_aio_params(iothread->ctx, + iothread->aio_max_batch, + errp); + } +} + static void iothread_class_init(ObjectClass *klass, void *class_data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); @@ -288,6 +328,10 @@ static void iothread_class_init(ObjectClass *klass, void *class_data) iothread_get_poll_param, iothread_set_poll_param, NULL, &poll_shrink_info); + object_class_property_add(klass, "aio-max-batch", "int", + iothread_get_aio_param, + iothread_set_aio_param, + NULL, &aio_max_batch_info); } static const TypeInfo iothread_info = { @@ -337,6 +381,7 @@ static int query_one_iothread(Object *object, void *opaque) info->poll_max_ns = iothread->poll_max_ns; info->poll_grow = iothread->poll_grow; info->poll_shrink = iothread->poll_shrink; + info->aio_max_batch = iothread->aio_max_batch; QAPI_LIST_APPEND(*tail, info); return 0; diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 0942027208..e00255f7ee 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -1893,6 +1893,8 @@ void hmp_info_iothreads(Monitor *mon, const QDict *qdict) monitor_printf(mon, " poll-max-ns=%" PRId64 "\n", value->poll_max_ns); monitor_printf(mon, " poll-grow=%" PRId64 "\n", value->poll_grow); monitor_printf(mon, " poll-shrink=%" PRId64 "\n", value->poll_shrink); + monitor_printf(mon, " aio-max-batch=%" PRId64 "\n", + value->aio_max_batch); } qapi_free_IOThreadInfoList(info_list); diff --git a/qapi/misc.json b/qapi/misc.json index 156f98203e..5c2ca3b556 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -86,6 +86,9 @@ # @poll-shrink: how many ns will be removed from polling time, 0 means that # it's not configured (since 2.9) # +# @aio-max-batch: maximum number of requests in a batch for the AIO engine, +# 0 means that the engine will use its default (since 6.1) +# # Since: 2.0 ## { 'struct': 'IOThreadInfo', @@ -93,7 +96,8 @@ 'thread-id': 'int', 'poll-max-ns': 'int', 'poll-grow': 'int', - 'poll-shrink': 'int' } } + 'poll-shrink': 'int', + 'aio-max-batch': 'int' } } ## # @query-iothreads: diff --git a/qapi/qom.json b/qapi/qom.json index 652be317b8..6d5f4a88e6 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -516,12 +516,17 @@ # algorithm detects it is spending too long polling without # encountering events. 0 selects a default behaviour (default: 0) # +# @aio-max-batch: maximum number of requests in a batch for the AIO engine, +# 0 means that the engine will use its default +# (default:0, since 6.1) +# # Since: 2.0 ## { 'struct': 'IothreadProperties', 'data': { '*poll-max-ns': 'int', '*poll-grow': 'int', - '*poll-shrink': 'int' } } + '*poll-shrink': 'int', + '*aio-max-batch': 'int' } } ## # @MemoryBackendProperties: diff --git a/qemu-options.hx b/qemu-options.hx index 0c9ddc0274..99ed5ec5f1 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -5301,7 +5301,7 @@ SRST CN=laptop.example.com,O=Example Home,L=London,ST=London,C=GB - ``-object iothread,id=id,poll-max-ns=poll-max-ns,poll-grow=poll-grow,poll-shrink=poll-shrink`` + ``-object iothread,id=id,poll-max-ns=poll-max-ns,poll-grow=poll-grow,poll-shrink=poll-shrink,aio-max-batch=aio-max-batch`` Creates a dedicated event loop thread that devices can be assigned to. This is known as an IOThread. By default device emulation happens in vCPU threads or the main event loop thread. @@ -5337,7 +5337,11 @@ SRST the polling time when the algorithm detects it is spending too long polling without encountering events. - The polling parameters can be modified at run-time using the + The ``aio-max-batch`` parameter is the maximum number of requests + in a batch for the AIO engine, 0 means that the engine will use + its default. + + The IOThread parameters can be modified at run-time using the ``qom-set`` command (where ``iothread1`` is the IOThread's ``id``): diff --git a/util/aio-posix.c b/util/aio-posix.c index 30f5354b1e..2b86777e91 100644 --- a/util/aio-posix.c +++ b/util/aio-posix.c @@ -716,3 +716,15 @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, aio_notify(ctx); } + +void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch, + Error **errp) +{ + /* + * No thread synchronization here, it doesn't matter if an incorrect value + * is used once. + */ + ctx->aio_max_batch = max_batch; + + aio_notify(ctx); +} diff --git a/util/aio-win32.c b/util/aio-win32.c index 168717b51b..d5b09a1193 100644 --- a/util/aio-win32.c +++ b/util/aio-win32.c @@ -440,3 +440,8 @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, error_setg(errp, "AioContext polling is not implemented on Windows"); } } + +void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch, + Error **errp) +{ +} diff --git a/util/async.c b/util/async.c index 9a41591319..6f6717a34b 100644 --- a/util/async.c +++ b/util/async.c @@ -554,6 +554,8 @@ AioContext *aio_context_new(Error **errp) ctx->poll_grow = 0; ctx->poll_shrink = 0; + ctx->aio_max_batch = 0; + return ctx; fail: g_source_destroy(&ctx->source); From d7ddd0a1618a75b31dc308bb37365ce1da972154 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Wed, 21 Jul 2021 11:42:11 +0200 Subject: [PATCH 254/531] linux-aio: limit the batch size using `aio-max-batch` parameter When there are multiple queues attached to the same AIO context, some requests may experience high latency, since in the worst case the AIO engine queue is only flushed when it is full (MAX_EVENTS) or there are no more queues plugged. Commit 2558cb8dd4 ("linux-aio: increasing MAX_EVENTS to a larger hardcoded value") changed MAX_EVENTS from 128 to 1024, to increase the number of in-flight requests. But this change also increased the potential maximum batch to 1024 elements. When there is a single queue attached to the AIO context, the issue is mitigated from laio_io_unplug() that will flush the queue every time is invoked since there can't be others queue plugged. Let's use the new `aio-max-batch` IOThread parameter to mitigate this issue, limiting the number of requests in a batch. We also define a default value (32): this value is obtained running some benchmarks and it represents a good tradeoff between the latency increase while a request is queued and the cost of the io_submit(2) system call. Signed-off-by: Stefano Garzarella Message-id: 20210721094211.69853-4-sgarzare@redhat.com Signed-off-by: Stefan Hajnoczi --- block/linux-aio.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/block/linux-aio.c b/block/linux-aio.c index 3c0527c2bf..0dab507b71 100644 --- a/block/linux-aio.c +++ b/block/linux-aio.c @@ -28,6 +28,9 @@ */ #define MAX_EVENTS 1024 +/* Maximum number of requests in a batch. (default value) */ +#define DEFAULT_MAX_BATCH 32 + struct qemu_laiocb { Coroutine *co; LinuxAioState *ctx; @@ -351,6 +354,10 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset, LinuxAioState *s = laiocb->ctx; struct iocb *iocbs = &laiocb->iocb; QEMUIOVector *qiov = laiocb->qiov; + int64_t max_batch = s->aio_context->aio_max_batch ?: DEFAULT_MAX_BATCH; + + /* limit the batch with the number of available events */ + max_batch = MIN_NON_ZERO(MAX_EVENTS - s->io_q.in_flight, max_batch); switch (type) { case QEMU_AIO_WRITE: @@ -371,7 +378,7 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset, s->io_q.in_queue++; if (!s->io_q.blocked && (!s->io_q.plugged || - s->io_q.in_flight + s->io_q.in_queue >= MAX_EVENTS)) { + s->io_q.in_queue >= max_batch)) { ioq_submit(s); } From e77c8b8b8e933414ef07dbed04e02973fccffeb0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 21 Jul 2021 17:10:15 +0100 Subject: [PATCH 255/531] Update version for v6.1.0-rc0 release Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index cc94f6b803..7d5e1d8670 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.50 +6.0.90 From 952fd6710e01037746de24f41e63cb4d8cbd49bc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 11 Jul 2021 08:46:37 -0700 Subject: [PATCH 256/531] qemu/atomic: Use macros for CONFIG_ATOMIC64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clang warnings about questionable atomic usage get localized to the inline function in atomic.h. By using a macro, we get the full traceback to the original use that caused the warning. Tested-by: Cole Robinson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/qemu/atomic.h | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index 3ccf84fd46..a7654d2a33 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -457,26 +457,15 @@ /* Abstractions to access atomically (i.e. "once") i64/u64 variables */ #ifdef CONFIG_ATOMIC64 -static inline int64_t qatomic_read_i64(const int64_t *ptr) -{ - /* use __nocheck because sizeof(void *) might be < sizeof(u64) */ - return qatomic_read__nocheck(ptr); -} - -static inline uint64_t qatomic_read_u64(const uint64_t *ptr) -{ - return qatomic_read__nocheck(ptr); -} - -static inline void qatomic_set_i64(int64_t *ptr, int64_t val) -{ - qatomic_set__nocheck(ptr, val); -} - -static inline void qatomic_set_u64(uint64_t *ptr, uint64_t val) -{ - qatomic_set__nocheck(ptr, val); -} +/* Use __nocheck because sizeof(void *) might be < sizeof(u64) */ +#define qatomic_read_i64(P) \ + _Generic(*(P), int64_t: qatomic_read__nocheck(P)) +#define qatomic_read_u64(P) \ + _Generic(*(P), uint64_t: qatomic_read__nocheck(P)) +#define qatomic_set_i64(P, V) \ + _Generic(*(P), int64_t: qatomic_set__nocheck(P, V)) +#define qatomic_set_u64(P, V) \ + _Generic(*(P), uint64_t: qatomic_set__nocheck(P, V)) static inline void qatomic64_init(void) { From 47345e7124709d280f14551113a20fd81ad2bf20 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 11 Jul 2021 08:41:28 -0700 Subject: [PATCH 257/531] qemu/atomic: Remove pre-C11 atomic fallbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now require c11, so the fallbacks are now dead code Tested-by: Cole Robinson Reviewed-by: Alex Bennée Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- configure | 7 -- include/qemu/atomic.h | 204 +++--------------------------------------- 2 files changed, 10 insertions(+), 201 deletions(-) diff --git a/configure b/configure index 232c54dcc1..b5965b159f 100755 --- a/configure +++ b/configure @@ -3991,18 +3991,11 @@ cat > $TMPC << EOF int main(void) { uint64_t x = 0, y = 0; -#ifdef __ATOMIC_RELAXED y = __atomic_load_n(&x, __ATOMIC_RELAXED); __atomic_store_n(&x, y, __ATOMIC_RELAXED); __atomic_compare_exchange_n(&x, &y, x, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); __atomic_exchange_n(&x, y, __ATOMIC_RELAXED); __atomic_fetch_add(&x, y, __ATOMIC_RELAXED); -#else - typedef char is_host64[sizeof(void *) >= sizeof(uint64_t) ? 1 : -1]; - __sync_lock_test_and_set(&x, y); - __sync_val_compare_and_swap(&x, y, 0); - __sync_fetch_and_add(&x, y); -#endif return 0; } EOF diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index a7654d2a33..fe5467d193 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -60,8 +60,9 @@ (unsigned short)1, \ (expr)+0)))))) -#ifdef __ATOMIC_RELAXED -/* For C11 atomic ops */ +#ifndef __ATOMIC_RELAXED +#error "Expecting C11 atomic ops" +#endif /* Manual memory barriers * @@ -239,193 +240,8 @@ #define qatomic_xor(ptr, n) \ ((void) __atomic_fetch_xor(ptr, n, __ATOMIC_SEQ_CST)) -#else /* __ATOMIC_RELAXED */ - -#ifdef __alpha__ -#define smp_read_barrier_depends() asm volatile("mb":::"memory") -#endif - -#if defined(__i386__) || defined(__x86_64__) || defined(__s390x__) - -/* - * Because of the strongly ordered storage model, wmb() and rmb() are nops - * here (a compiler barrier only). QEMU doesn't do accesses to write-combining - * qemu memory or non-temporal load/stores from C code. - */ -#define smp_mb_release() barrier() -#define smp_mb_acquire() barrier() - -/* - * __sync_lock_test_and_set() is documented to be an acquire barrier only, - * but it is a full barrier at the hardware level. Add a compiler barrier - * to make it a full barrier also at the compiler level. - */ -#define qatomic_xchg(ptr, i) (barrier(), __sync_lock_test_and_set(ptr, i)) - -#elif defined(_ARCH_PPC) - -/* - * We use an eieio() for wmb() on powerpc. This assumes we don't - * need to order cacheable and non-cacheable stores with respect to - * each other. - * - * smp_mb has the same problem as on x86 for not-very-new GCC - * (http://patchwork.ozlabs.org/patch/126184/, Nov 2011). - */ -#define smp_wmb() ({ asm volatile("eieio" ::: "memory"); (void)0; }) -#if defined(__powerpc64__) -#define smp_mb_release() ({ asm volatile("lwsync" ::: "memory"); (void)0; }) -#define smp_mb_acquire() ({ asm volatile("lwsync" ::: "memory"); (void)0; }) -#else -#define smp_mb_release() ({ asm volatile("sync" ::: "memory"); (void)0; }) -#define smp_mb_acquire() ({ asm volatile("sync" ::: "memory"); (void)0; }) -#endif -#define smp_mb() ({ asm volatile("sync" ::: "memory"); (void)0; }) - -#endif /* _ARCH_PPC */ - -/* - * For (host) platforms we don't have explicit barrier definitions - * for, we use the gcc __sync_synchronize() primitive to generate a - * full barrier. This should be safe on all platforms, though it may - * be overkill for smp_mb_acquire() and smp_mb_release(). - */ -#ifndef smp_mb -#define smp_mb() __sync_synchronize() -#endif - -#ifndef smp_mb_acquire -#define smp_mb_acquire() __sync_synchronize() -#endif - -#ifndef smp_mb_release -#define smp_mb_release() __sync_synchronize() -#endif - -#ifndef smp_read_barrier_depends -#define smp_read_barrier_depends() barrier() -#endif - -#ifndef signal_barrier -#define signal_barrier() barrier() -#endif - -/* These will only be atomic if the processor does the fetch or store - * in a single issue memory operation - */ -#define qatomic_read__nocheck(p) (*(__typeof__(*(p)) volatile*) (p)) -#define qatomic_set__nocheck(p, i) ((*(__typeof__(*(p)) volatile*) (p)) = (i)) - -#define qatomic_read(ptr) qatomic_read__nocheck(ptr) -#define qatomic_set(ptr, i) qatomic_set__nocheck(ptr,i) - -/** - * qatomic_rcu_read - reads a RCU-protected pointer to a local variable - * into a RCU read-side critical section. The pointer can later be safely - * dereferenced within the critical section. - * - * This ensures that the pointer copy is invariant thorough the whole critical - * section. - * - * Inserts memory barriers on architectures that require them (currently only - * Alpha) and documents which pointers are protected by RCU. - * - * qatomic_rcu_read also includes a compiler barrier to ensure that - * value-speculative optimizations (e.g. VSS: Value Speculation - * Scheduling) does not perform the data read before the pointer read - * by speculating the value of the pointer. - * - * Should match qatomic_rcu_set(), qatomic_xchg(), qatomic_cmpxchg(). - */ -#define qatomic_rcu_read(ptr) ({ \ - typeof(*ptr) _val = qatomic_read(ptr); \ - smp_read_barrier_depends(); \ - _val; \ -}) - -/** - * qatomic_rcu_set - assigns (publicizes) a pointer to a new data structure - * meant to be read by RCU read-side critical sections. - * - * Documents which pointers will be dereferenced by RCU read-side critical - * sections and adds the required memory barriers on architectures requiring - * them. It also makes sure the compiler does not reorder code initializing the - * data structure before its publication. - * - * Should match qatomic_rcu_read(). - */ -#define qatomic_rcu_set(ptr, i) do { \ - smp_wmb(); \ - qatomic_set(ptr, i); \ -} while (0) - -#define qatomic_load_acquire(ptr) ({ \ - typeof(*ptr) _val = qatomic_read(ptr); \ - smp_mb_acquire(); \ - _val; \ -}) - -#define qatomic_store_release(ptr, i) do { \ - smp_mb_release(); \ - qatomic_set(ptr, i); \ -} while (0) - -#ifndef qatomic_xchg -#if defined(__clang__) -#define qatomic_xchg(ptr, i) __sync_swap(ptr, i) -#else -/* __sync_lock_test_and_set() is documented to be an acquire barrier only. */ -#define qatomic_xchg(ptr, i) (smp_mb(), __sync_lock_test_and_set(ptr, i)) -#endif -#endif -#define qatomic_xchg__nocheck qatomic_xchg - -/* Provide shorter names for GCC atomic builtins. */ -#define qatomic_fetch_inc(ptr) __sync_fetch_and_add(ptr, 1) -#define qatomic_fetch_dec(ptr) __sync_fetch_and_add(ptr, -1) - -#define qatomic_fetch_add(ptr, n) __sync_fetch_and_add(ptr, n) -#define qatomic_fetch_sub(ptr, n) __sync_fetch_and_sub(ptr, n) -#define qatomic_fetch_and(ptr, n) __sync_fetch_and_and(ptr, n) -#define qatomic_fetch_or(ptr, n) __sync_fetch_and_or(ptr, n) -#define qatomic_fetch_xor(ptr, n) __sync_fetch_and_xor(ptr, n) - -#define qatomic_inc_fetch(ptr) __sync_add_and_fetch(ptr, 1) -#define qatomic_dec_fetch(ptr) __sync_add_and_fetch(ptr, -1) -#define qatomic_add_fetch(ptr, n) __sync_add_and_fetch(ptr, n) -#define qatomic_sub_fetch(ptr, n) __sync_sub_and_fetch(ptr, n) -#define qatomic_and_fetch(ptr, n) __sync_and_and_fetch(ptr, n) -#define qatomic_or_fetch(ptr, n) __sync_or_and_fetch(ptr, n) -#define qatomic_xor_fetch(ptr, n) __sync_xor_and_fetch(ptr, n) - -#define qatomic_cmpxchg(ptr, old, new) \ - __sync_val_compare_and_swap(ptr, old, new) -#define qatomic_cmpxchg__nocheck(ptr, old, new) qatomic_cmpxchg(ptr, old, new) - -/* And even shorter names that return void. */ -#define qatomic_inc(ptr) ((void) __sync_fetch_and_add(ptr, 1)) -#define qatomic_dec(ptr) ((void) __sync_fetch_and_add(ptr, -1)) -#define qatomic_add(ptr, n) ((void) __sync_fetch_and_add(ptr, n)) -#define qatomic_sub(ptr, n) ((void) __sync_fetch_and_sub(ptr, n)) -#define qatomic_and(ptr, n) ((void) __sync_fetch_and_and(ptr, n)) -#define qatomic_or(ptr, n) ((void) __sync_fetch_and_or(ptr, n)) -#define qatomic_xor(ptr, n) ((void) __sync_fetch_and_xor(ptr, n)) - -#endif /* __ATOMIC_RELAXED */ - -#ifndef smp_wmb #define smp_wmb() smp_mb_release() -#endif -#ifndef smp_rmb #define smp_rmb() smp_mb_acquire() -#endif - -/* This is more efficient than a store plus a fence. */ -#if !defined(__SANITIZE_THREAD__) -#if defined(__i386__) || defined(__x86_64__) || defined(__s390x__) -#define qatomic_mb_set(ptr, i) ((void)qatomic_xchg(ptr, i)) -#endif -#endif /* qatomic_mb_read/set semantics map Java volatile variables. They are * less expensive on some platforms (notably POWER) than fully @@ -435,16 +251,16 @@ * use. See docs/devel/atomics.rst for more discussion. */ -#ifndef qatomic_mb_read #define qatomic_mb_read(ptr) \ qatomic_load_acquire(ptr) -#endif -#ifndef qatomic_mb_set -#define qatomic_mb_set(ptr, i) do { \ - qatomic_store_release(ptr, i); \ - smp_mb(); \ -} while(0) +#if !defined(__SANITIZE_THREAD__) && \ + (defined(__i386__) || defined(__x86_64__) || defined(__s390x__)) +/* This is more efficient than a store plus a fence. */ +# define qatomic_mb_set(ptr, i) ((void)qatomic_xchg(ptr, i)) +#else +# define qatomic_mb_set(ptr, i) \ + ({ qatomic_store_release(ptr, i); smp_mb(); }) #endif #define qatomic_fetch_inc_nonzero(ptr) ({ \ From 9ef0c6d6a7d81992a2326416a9ce12eef2824861 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Jul 2021 08:17:18 -0700 Subject: [PATCH 258/531] qemu/atomic: Add aligned_{int64,uint64}_t types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use it to avoid some clang-12 -Watomic-alignment errors, forcing some structures to be aligned and as a pointer when we have ensured that the address is aligned. Tested-by: Cole Robinson Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/atomic_template.h | 4 ++-- include/qemu/atomic.h | 14 +++++++++++++- include/qemu/stats64.h | 2 +- linux-user/hppa/cpu_loop.c | 2 +- softmmu/timers-state.h | 2 +- util/qsp.c | 4 ++-- 6 files changed, 20 insertions(+), 8 deletions(-) diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h index afa8a9daf3..d347462af5 100644 --- a/accel/tcg/atomic_template.h +++ b/accel/tcg/atomic_template.h @@ -28,8 +28,8 @@ # define SHIFT 4 #elif DATA_SIZE == 8 # define SUFFIX q -# define DATA_TYPE uint64_t -# define SDATA_TYPE int64_t +# define DATA_TYPE aligned_uint64_t +# define SDATA_TYPE aligned_int64_t # define BSWAP bswap64 # define SHIFT 3 #elif DATA_SIZE == 4 diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index fe5467d193..112a29910b 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -271,7 +271,19 @@ _oldn; \ }) -/* Abstractions to access atomically (i.e. "once") i64/u64 variables */ +/* + * Abstractions to access atomically (i.e. "once") i64/u64 variables. + * + * The i386 abi is odd in that by default members are only aligned to + * 4 bytes, which means that 8-byte types can wind up mis-aligned. + * Clang will then warn about this, and emit a call into libatomic. + * + * Use of these types in structures when they will be used with atomic + * operations can avoid this. + */ +typedef int64_t aligned_int64_t __attribute__((aligned(8))); +typedef uint64_t aligned_uint64_t __attribute__((aligned(8))); + #ifdef CONFIG_ATOMIC64 /* Use __nocheck because sizeof(void *) might be < sizeof(u64) */ #define qatomic_read_i64(P) \ diff --git a/include/qemu/stats64.h b/include/qemu/stats64.h index fdd3d1b8f9..802402254b 100644 --- a/include/qemu/stats64.h +++ b/include/qemu/stats64.h @@ -21,7 +21,7 @@ typedef struct Stat64 { #ifdef CONFIG_ATOMIC64 - uint64_t value; + aligned_uint64_t value; #else uint32_t low, high; uint32_t lock; diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c index 3aaaf3337c..82d8183821 100644 --- a/linux-user/hppa/cpu_loop.c +++ b/linux-user/hppa/cpu_loop.c @@ -82,7 +82,7 @@ static abi_ulong hppa_lws(CPUHPPAState *env) o64 = *(uint64_t *)g2h(cs, old); n64 = *(uint64_t *)g2h(cs, new); #ifdef CONFIG_ATOMIC64 - r64 = qatomic_cmpxchg__nocheck((uint64_t *)g2h(cs, addr), + r64 = qatomic_cmpxchg__nocheck((aligned_uint64_t *)g2h(cs, addr), o64, n64); ret = r64 != o64; #else diff --git a/softmmu/timers-state.h b/softmmu/timers-state.h index 8c262ce139..94bb7394c5 100644 --- a/softmmu/timers-state.h +++ b/softmmu/timers-state.h @@ -47,7 +47,7 @@ typedef struct TimersState { int64_t last_delta; /* Compensate for varying guest execution speed. */ - int64_t qemu_icount_bias; + aligned_int64_t qemu_icount_bias; int64_t vm_clock_warp_start; int64_t cpu_clock_offset; diff --git a/util/qsp.c b/util/qsp.c index bacc5fa2f6..8562b14a87 100644 --- a/util/qsp.c +++ b/util/qsp.c @@ -83,8 +83,8 @@ typedef struct QSPCallSite QSPCallSite; struct QSPEntry { void *thread_ptr; const QSPCallSite *callsite; - uint64_t n_acqs; - uint64_t ns; + aligned_uint64_t n_acqs; + aligned_uint64_t ns; unsigned int n_objs; /* count of coalesced objs; only used for reporting */ }; typedef struct QSPEntry QSPEntry; From be9568b4e02100681af14ab2d17522c3d497f511 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Jul 2021 14:20:49 -0700 Subject: [PATCH 259/531] tcg: Rename helper_atomic_*_mmu and provide for user-only Always provide the atomic interface using TCGMemOpIdx oi and uintptr_t retaddr. Rename from helper_* to cpu_* so as to (mostly) match the exec/cpu_ldst.h functions, and to emphasize that they are not callable from TCG directly. Tested-by: Cole Robinson Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 8 ++-- accel/tcg/user-exec.c | 59 ++++++++++++++++---------- include/tcg/tcg.h | 78 ++++++++++++++++------------------- target/arm/helper-a64.c | 8 ++-- target/i386/tcg/mem_helper.c | 15 +------ target/m68k/op_helper.c | 19 +++------ target/ppc/mem_helper.c | 16 +++---- target/s390x/tcg/mem_helper.c | 19 ++++----- 8 files changed, 104 insertions(+), 118 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index b4e15b6aad..63da1cc96f 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2686,12 +2686,14 @@ void cpu_stq_le_data(CPUArchState *env, target_ulong ptr, uint64_t val) cpu_stq_le_data_ra(env, ptr, val, 0); } -/* First set of helpers allows passing in of OI and RETADDR. This makes - them callable from other helpers. */ +/* + * First set of functions passes in OI and RETADDR. + * This makes them callable from other helpers. + */ #define EXTRA_ARGS , TCGMemOpIdx oi, uintptr_t retaddr #define ATOMIC_NAME(X) \ - HELPER(glue(glue(glue(atomic_ ## X, SUFFIX), END), _mmu)) + glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu) #define ATOMIC_MMU_DECLS #define ATOMIC_MMU_LOOKUP_RW \ atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ | PAGE_WRITE, retaddr) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index ba09fd0413..82dbe06f08 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1234,19 +1234,23 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, return ret; } -/* Macro to call the above, with local variables from the use context. */ -#define ATOMIC_MMU_DECLS do {} while (0) -#define ATOMIC_MMU_LOOKUP_RW atomic_mmu_lookup(env, addr, DATA_SIZE, GETPC()) +#include "atomic_common.c.inc" + +/* + * First set of functions passes in OI and RETADDR. + * This makes them callable from other helpers. + */ + +#define EXTRA_ARGS , TCGMemOpIdx oi, uintptr_t retaddr +#define ATOMIC_NAME(X) \ + glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu) +#define ATOMIC_MMU_DECLS +#define ATOMIC_MMU_LOOKUP_RW atomic_mmu_lookup(env, addr, DATA_SIZE, retaddr) #define ATOMIC_MMU_LOOKUP_R ATOMIC_MMU_LOOKUP_RW #define ATOMIC_MMU_LOOKUP_W ATOMIC_MMU_LOOKUP_RW #define ATOMIC_MMU_CLEANUP do { clear_helper_retaddr(); } while (0) #define ATOMIC_MMU_IDX MMU_USER_IDX -#define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END)) -#define EXTRA_ARGS - -#include "atomic_common.c.inc" - #define DATA_SIZE 1 #include "atomic_template.h" @@ -1261,20 +1265,33 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, #include "atomic_template.h" #endif -/* The following is only callable from other helpers, and matches up - with the softmmu version. */ - #if HAVE_ATOMIC128 || HAVE_CMPXCHG128 - -#undef EXTRA_ARGS -#undef ATOMIC_NAME -#undef ATOMIC_MMU_LOOKUP_RW - -#define EXTRA_ARGS , TCGMemOpIdx oi, uintptr_t retaddr -#define ATOMIC_NAME(X) \ - HELPER(glue(glue(glue(atomic_ ## X, SUFFIX), END), _mmu)) -#define ATOMIC_MMU_LOOKUP_RW atomic_mmu_lookup(env, addr, DATA_SIZE, retaddr) - #define DATA_SIZE 16 #include "atomic_template.h" #endif + +/* + * Second set of functions is directly callable from TCG. + */ + +#undef EXTRA_ARGS +#undef ATOMIC_NAME +#undef ATOMIC_MMU_DECLS + +#define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END)) +#define EXTRA_ARGS +#define ATOMIC_MMU_DECLS uintptr_t retaddr = GETPC() + +#define DATA_SIZE 1 +#include "atomic_template.h" + +#define DATA_SIZE 2 +#include "atomic_template.h" + +#define DATA_SIZE 4 +#include "atomic_template.h" + +#ifdef CONFIG_ATOMIC64 +#define DATA_SIZE 8 +#include "atomic_template.h" +#endif diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 25dd19d6e1..44ccd86f3e 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -1341,31 +1341,32 @@ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, # define helper_ret_stl_mmu helper_le_stl_mmu # define helper_ret_stq_mmu helper_le_stq_mmu #endif +#endif /* CONFIG_SOFTMMU */ -uint32_t helper_atomic_cmpxchgb_mmu(CPUArchState *env, target_ulong addr, +uint32_t cpu_atomic_cmpxchgb_mmu(CPUArchState *env, target_ulong addr, + uint32_t cmpv, uint32_t newv, + TCGMemOpIdx oi, uintptr_t retaddr); +uint32_t cpu_atomic_cmpxchgw_le_mmu(CPUArchState *env, target_ulong addr, uint32_t cmpv, uint32_t newv, TCGMemOpIdx oi, uintptr_t retaddr); -uint32_t helper_atomic_cmpxchgw_le_mmu(CPUArchState *env, target_ulong addr, - uint32_t cmpv, uint32_t newv, - TCGMemOpIdx oi, uintptr_t retaddr); -uint32_t helper_atomic_cmpxchgl_le_mmu(CPUArchState *env, target_ulong addr, - uint32_t cmpv, uint32_t newv, - TCGMemOpIdx oi, uintptr_t retaddr); -uint64_t helper_atomic_cmpxchgq_le_mmu(CPUArchState *env, target_ulong addr, - uint64_t cmpv, uint64_t newv, - TCGMemOpIdx oi, uintptr_t retaddr); -uint32_t helper_atomic_cmpxchgw_be_mmu(CPUArchState *env, target_ulong addr, - uint32_t cmpv, uint32_t newv, - TCGMemOpIdx oi, uintptr_t retaddr); -uint32_t helper_atomic_cmpxchgl_be_mmu(CPUArchState *env, target_ulong addr, - uint32_t cmpv, uint32_t newv, - TCGMemOpIdx oi, uintptr_t retaddr); -uint64_t helper_atomic_cmpxchgq_be_mmu(CPUArchState *env, target_ulong addr, - uint64_t cmpv, uint64_t newv, - TCGMemOpIdx oi, uintptr_t retaddr); +uint32_t cpu_atomic_cmpxchgl_le_mmu(CPUArchState *env, target_ulong addr, + uint32_t cmpv, uint32_t newv, + TCGMemOpIdx oi, uintptr_t retaddr); +uint64_t cpu_atomic_cmpxchgq_le_mmu(CPUArchState *env, target_ulong addr, + uint64_t cmpv, uint64_t newv, + TCGMemOpIdx oi, uintptr_t retaddr); +uint32_t cpu_atomic_cmpxchgw_be_mmu(CPUArchState *env, target_ulong addr, + uint32_t cmpv, uint32_t newv, + TCGMemOpIdx oi, uintptr_t retaddr); +uint32_t cpu_atomic_cmpxchgl_be_mmu(CPUArchState *env, target_ulong addr, + uint32_t cmpv, uint32_t newv, + TCGMemOpIdx oi, uintptr_t retaddr); +uint64_t cpu_atomic_cmpxchgq_be_mmu(CPUArchState *env, target_ulong addr, + uint64_t cmpv, uint64_t newv, + TCGMemOpIdx oi, uintptr_t retaddr); #define GEN_ATOMIC_HELPER(NAME, TYPE, SUFFIX) \ -TYPE helper_atomic_ ## NAME ## SUFFIX ## _mmu \ +TYPE cpu_atomic_ ## NAME ## SUFFIX ## _mmu \ (CPUArchState *env, target_ulong addr, TYPE val, \ TCGMemOpIdx oi, uintptr_t retaddr); @@ -1411,31 +1412,22 @@ GEN_ATOMIC_HELPER_ALL(xchg) #undef GEN_ATOMIC_HELPER_ALL #undef GEN_ATOMIC_HELPER -#endif /* CONFIG_SOFTMMU */ -/* - * These aren't really a "proper" helpers because TCG cannot manage Int128. - * However, use the same format as the others, for use by the backends. - * - * The cmpxchg functions are only defined if HAVE_CMPXCHG128; - * the ld/st functions are only defined if HAVE_ATOMIC128, - * as defined by . - */ -Int128 helper_atomic_cmpxchgo_le_mmu(CPUArchState *env, target_ulong addr, - Int128 cmpv, Int128 newv, - TCGMemOpIdx oi, uintptr_t retaddr); -Int128 helper_atomic_cmpxchgo_be_mmu(CPUArchState *env, target_ulong addr, - Int128 cmpv, Int128 newv, - TCGMemOpIdx oi, uintptr_t retaddr); +Int128 cpu_atomic_cmpxchgo_le_mmu(CPUArchState *env, target_ulong addr, + Int128 cmpv, Int128 newv, + TCGMemOpIdx oi, uintptr_t retaddr); +Int128 cpu_atomic_cmpxchgo_be_mmu(CPUArchState *env, target_ulong addr, + Int128 cmpv, Int128 newv, + TCGMemOpIdx oi, uintptr_t retaddr); -Int128 helper_atomic_ldo_le_mmu(CPUArchState *env, target_ulong addr, - TCGMemOpIdx oi, uintptr_t retaddr); -Int128 helper_atomic_ldo_be_mmu(CPUArchState *env, target_ulong addr, - TCGMemOpIdx oi, uintptr_t retaddr); -void helper_atomic_sto_le_mmu(CPUArchState *env, target_ulong addr, Int128 val, - TCGMemOpIdx oi, uintptr_t retaddr); -void helper_atomic_sto_be_mmu(CPUArchState *env, target_ulong addr, Int128 val, - TCGMemOpIdx oi, uintptr_t retaddr); +Int128 cpu_atomic_ldo_le_mmu(CPUArchState *env, target_ulong addr, + TCGMemOpIdx oi, uintptr_t retaddr); +Int128 cpu_atomic_ldo_be_mmu(CPUArchState *env, target_ulong addr, + TCGMemOpIdx oi, uintptr_t retaddr); +void cpu_atomic_sto_le_mmu(CPUArchState *env, target_ulong addr, Int128 val, + TCGMemOpIdx oi, uintptr_t retaddr); +void cpu_atomic_sto_be_mmu(CPUArchState *env, target_ulong addr, Int128 val, + TCGMemOpIdx oi, uintptr_t retaddr); #ifdef CONFIG_DEBUG_TCG void tcg_assert_listed_vecop(TCGOpcode); diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c index ac5c4452d5..26f79f9141 100644 --- a/target/arm/helper-a64.c +++ b/target/arm/helper-a64.c @@ -564,7 +564,7 @@ uint64_t HELPER(paired_cmpxchg64_le_parallel)(CPUARMState *env, uint64_t addr, cmpv = int128_make128(env->exclusive_val, env->exclusive_high); newv = int128_make128(new_lo, new_hi); - oldv = helper_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, oi, ra); + oldv = cpu_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, oi, ra); success = int128_eq(oldv, cmpv); return !success; @@ -638,7 +638,7 @@ uint64_t HELPER(paired_cmpxchg64_be_parallel)(CPUARMState *env, uint64_t addr, */ cmpv = int128_make128(env->exclusive_high, env->exclusive_val); newv = int128_make128(new_hi, new_lo); - oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra); + oldv = cpu_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra); success = int128_eq(oldv, cmpv); return !success; @@ -660,7 +660,7 @@ void HELPER(casp_le_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr, cmpv = int128_make128(env->xregs[rs], env->xregs[rs + 1]); newv = int128_make128(new_lo, new_hi); - oldv = helper_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, oi, ra); + oldv = cpu_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, oi, ra); env->xregs[rs] = int128_getlo(oldv); env->xregs[rs + 1] = int128_gethi(oldv); @@ -681,7 +681,7 @@ void HELPER(casp_be_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr, cmpv = int128_make128(env->xregs[rs + 1], env->xregs[rs]); newv = int128_make128(new_lo, new_hi); - oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra); + oldv = cpu_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra); env->xregs[rs + 1] = int128_getlo(oldv); env->xregs[rs] = int128_gethi(oldv); diff --git a/target/i386/tcg/mem_helper.c b/target/i386/tcg/mem_helper.c index 591f512bff..2da3cd14b6 100644 --- a/target/i386/tcg/mem_helper.c +++ b/target/i386/tcg/mem_helper.c @@ -64,22 +64,12 @@ void helper_cmpxchg8b(CPUX86State *env, target_ulong a0) cmpv = deposit64(env->regs[R_EAX], 32, 32, env->regs[R_EDX]); newv = deposit64(env->regs[R_EBX], 32, 32, env->regs[R_ECX]); -#ifdef CONFIG_USER_ONLY - { - uint64_t *haddr = g2h(env_cpu(env), a0); - cmpv = cpu_to_le64(cmpv); - newv = cpu_to_le64(newv); - oldv = qatomic_cmpxchg__nocheck(haddr, cmpv, newv); - oldv = le64_to_cpu(oldv); - } -#else { uintptr_t ra = GETPC(); int mem_idx = cpu_mmu_index(env, false); TCGMemOpIdx oi = make_memop_idx(MO_TEQ, mem_idx); - oldv = helper_atomic_cmpxchgq_le_mmu(env, a0, cmpv, newv, oi, ra); + oldv = cpu_atomic_cmpxchgq_le_mmu(env, a0, cmpv, newv, oi, ra); } -#endif if (oldv == cmpv) { eflags |= CC_Z; @@ -147,8 +137,7 @@ void helper_cmpxchg16b(CPUX86State *env, target_ulong a0) int mem_idx = cpu_mmu_index(env, false); TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx); - Int128 oldv = helper_atomic_cmpxchgo_le_mmu(env, a0, cmpv, - newv, oi, ra); + Int128 oldv = cpu_atomic_cmpxchgo_le_mmu(env, a0, cmpv, newv, oi, ra); if (int128_eq(oldv, cmpv)) { eflags |= CC_Z; diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index ae1ba4b437..d006d1cb3e 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -22,6 +22,7 @@ #include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "semihosting/semihost.h" +#include "tcg/tcg.h" #if defined(CONFIG_USER_ONLY) @@ -782,9 +783,9 @@ static void do_cas2l(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2, uint32_t u2 = env->dregs[Du2]; uint32_t l1, l2; uintptr_t ra = GETPC(); -#if defined(CONFIG_ATOMIC64) && !defined(CONFIG_USER_ONLY) +#if defined(CONFIG_ATOMIC64) int mmu_idx = cpu_mmu_index(env, 0); - TCGMemOpIdx oi; + TCGMemOpIdx oi = make_memop_idx(MO_BEQ, mmu_idx); #endif if (parallel) { @@ -794,23 +795,13 @@ static void do_cas2l(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2, if ((a1 & 7) == 0 && a2 == a1 + 4) { c = deposit64(c2, 32, 32, c1); u = deposit64(u2, 32, 32, u1); -#ifdef CONFIG_USER_ONLY - l = helper_atomic_cmpxchgq_be(env, a1, c, u); -#else - oi = make_memop_idx(MO_BEQ, mmu_idx); - l = helper_atomic_cmpxchgq_be_mmu(env, a1, c, u, oi, ra); -#endif + l = cpu_atomic_cmpxchgq_be_mmu(env, a1, c, u, oi, ra); l1 = l >> 32; l2 = l; } else if ((a2 & 7) == 0 && a1 == a2 + 4) { c = deposit64(c1, 32, 32, c2); u = deposit64(u1, 32, 32, u2); -#ifdef CONFIG_USER_ONLY - l = helper_atomic_cmpxchgq_be(env, a2, c, u); -#else - oi = make_memop_idx(MO_BEQ, mmu_idx); - l = helper_atomic_cmpxchgq_be_mmu(env, a2, c, u, oi, ra); -#endif + l = cpu_atomic_cmpxchgq_be_mmu(env, a2, c, u, oi, ra); l2 = l >> 32; l1 = l; } else diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index 444b2a30ef..e2282baa8d 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -376,7 +376,7 @@ uint64_t helper_lq_le_parallel(CPUPPCState *env, target_ulong addr, /* We will have raised EXCP_ATOMIC from the translator. */ assert(HAVE_ATOMIC128); - ret = helper_atomic_ldo_le_mmu(env, addr, opidx, GETPC()); + ret = cpu_atomic_ldo_le_mmu(env, addr, opidx, GETPC()); env->retxh = int128_gethi(ret); return int128_getlo(ret); } @@ -388,7 +388,7 @@ uint64_t helper_lq_be_parallel(CPUPPCState *env, target_ulong addr, /* We will have raised EXCP_ATOMIC from the translator. */ assert(HAVE_ATOMIC128); - ret = helper_atomic_ldo_be_mmu(env, addr, opidx, GETPC()); + ret = cpu_atomic_ldo_be_mmu(env, addr, opidx, GETPC()); env->retxh = int128_gethi(ret); return int128_getlo(ret); } @@ -401,7 +401,7 @@ void helper_stq_le_parallel(CPUPPCState *env, target_ulong addr, /* We will have raised EXCP_ATOMIC from the translator. */ assert(HAVE_ATOMIC128); val = int128_make128(lo, hi); - helper_atomic_sto_le_mmu(env, addr, val, opidx, GETPC()); + cpu_atomic_sto_le_mmu(env, addr, val, opidx, GETPC()); } void helper_stq_be_parallel(CPUPPCState *env, target_ulong addr, @@ -412,7 +412,7 @@ void helper_stq_be_parallel(CPUPPCState *env, target_ulong addr, /* We will have raised EXCP_ATOMIC from the translator. */ assert(HAVE_ATOMIC128); val = int128_make128(lo, hi); - helper_atomic_sto_be_mmu(env, addr, val, opidx, GETPC()); + cpu_atomic_sto_be_mmu(env, addr, val, opidx, GETPC()); } uint32_t helper_stqcx_le_parallel(CPUPPCState *env, target_ulong addr, @@ -429,8 +429,8 @@ uint32_t helper_stqcx_le_parallel(CPUPPCState *env, target_ulong addr, cmpv = int128_make128(env->reserve_val2, env->reserve_val); newv = int128_make128(new_lo, new_hi); - oldv = helper_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, - opidx, GETPC()); + oldv = cpu_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, + opidx, GETPC()); success = int128_eq(oldv, cmpv); } env->reserve_addr = -1; @@ -451,8 +451,8 @@ uint32_t helper_stqcx_be_parallel(CPUPPCState *env, target_ulong addr, cmpv = int128_make128(env->reserve_val2, env->reserve_val); newv = int128_make128(new_lo, new_hi); - oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, - opidx, GETPC()); + oldv = cpu_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, + opidx, GETPC()); success = int128_eq(oldv, cmpv); } env->reserve_addr = -1; diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index 9bae13ecf0..21a4de4067 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -1811,7 +1811,7 @@ void HELPER(cdsg_parallel)(CPUS390XState *env, uint64_t addr, mem_idx = cpu_mmu_index(env, false); oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx); - oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra); + oldv = cpu_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra); fail = !int128_eq(oldv, cmpv); env->cc_op = fail; @@ -1884,7 +1884,7 @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1, ov = qatomic_cmpxchg__nocheck(haddr, cv, nv); #else TCGMemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mem_idx); - ov = helper_atomic_cmpxchgl_be_mmu(env, a1, cv, nv, oi, ra); + ov = cpu_atomic_cmpxchgl_be_mmu(env, a1, cv, nv, oi, ra); #endif } else { ov = cpu_ldl_data_ra(env, a1, ra); @@ -1903,13 +1903,8 @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1, if (parallel) { #ifdef CONFIG_ATOMIC64 -# ifdef CONFIG_USER_ONLY - uint64_t *haddr = g2h(env_cpu(env), a1); - ov = qatomic_cmpxchg__nocheck(haddr, cv, nv); -# else TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN, mem_idx); - ov = helper_atomic_cmpxchgq_be_mmu(env, a1, cv, nv, oi, ra); -# endif + ov = cpu_atomic_cmpxchgq_be_mmu(env, a1, cv, nv, oi, ra); #else /* Note that we asserted !parallel above. */ g_assert_not_reached(); @@ -1945,7 +1940,7 @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1, cpu_stq_data_ra(env, a1 + 8, int128_getlo(nv), ra); } else if (HAVE_CMPXCHG128) { TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx); - ov = helper_atomic_cmpxchgo_be_mmu(env, a1, cv, nv, oi, ra); + ov = cpu_atomic_cmpxchgo_be_mmu(env, a1, cv, nv, oi, ra); cc = !int128_eq(ov, cv); } else { /* Note that we asserted !parallel above. */ @@ -1985,7 +1980,7 @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1, } else if (HAVE_ATOMIC128) { TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx); Int128 sv = int128_make128(svl, svh); - helper_atomic_sto_be_mmu(env, a2, sv, oi, ra); + cpu_atomic_sto_be_mmu(env, a2, sv, oi, ra); } else { /* Note that we asserted !parallel above. */ g_assert_not_reached(); @@ -2486,7 +2481,7 @@ uint64_t HELPER(lpq_parallel)(CPUS390XState *env, uint64_t addr) mem_idx = cpu_mmu_index(env, false); oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx); - v = helper_atomic_ldo_be_mmu(env, addr, oi, ra); + v = cpu_atomic_ldo_be_mmu(env, addr, oi, ra); hi = int128_gethi(v); lo = int128_getlo(v); @@ -2518,7 +2513,7 @@ void HELPER(stpq_parallel)(CPUS390XState *env, uint64_t addr, mem_idx = cpu_mmu_index(env, false); oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx); v = int128_make128(low, high); - helper_atomic_sto_be_mmu(env, addr, v, oi, ra); + cpu_atomic_sto_be_mmu(env, addr, v, oi, ra); } /* Execute instruction. This instruction executes an insn modified with From e28a86643842014d2a1cacb4fe9370ef53e28dc6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Jul 2021 15:51:32 -0700 Subject: [PATCH 260/531] accel/tcg: Standardize atomic helpers on softmmu api Reduce the amount of code duplication by always passing the TCGMemOpIdx argument to helper_atomic_*. This is not currently used for user-only, but it's easy to ignore. Tested-by: Cole Robinson Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- accel/tcg/atomic_common.c.inc | 70 +++++++++++++++++++++++++++++++++++ accel/tcg/cputlb.c | 32 ---------------- accel/tcg/tcg-runtime.h | 46 ----------------------- accel/tcg/user-exec.c | 26 ------------- tcg/tcg-op.c | 51 ++++++------------------- 5 files changed, 82 insertions(+), 143 deletions(-) diff --git a/accel/tcg/atomic_common.c.inc b/accel/tcg/atomic_common.c.inc index 344525b0bb..a668cf0d6f 100644 --- a/accel/tcg/atomic_common.c.inc +++ b/accel/tcg/atomic_common.c.inc @@ -52,3 +52,73 @@ void atomic_trace_st_post(CPUArchState *env, target_ulong addr, uint16_t info) { qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info); } + +/* + * Atomic helpers callable from TCG. + * These have a common interface and all defer to cpu_atomic_* + * using the host return address from GETPC(). + */ + +#define CMPXCHG_HELPER(OP, TYPE) \ + TYPE HELPER(atomic_##OP)(CPUArchState *env, target_ulong addr, \ + TYPE oldv, TYPE newv, uint32_t oi) \ + { return cpu_atomic_##OP##_mmu(env, addr, oldv, newv, oi, GETPC()); } + +CMPXCHG_HELPER(cmpxchgb, uint32_t) +CMPXCHG_HELPER(cmpxchgw_be, uint32_t) +CMPXCHG_HELPER(cmpxchgw_le, uint32_t) +CMPXCHG_HELPER(cmpxchgl_be, uint32_t) +CMPXCHG_HELPER(cmpxchgl_le, uint32_t) + +#ifdef CONFIG_ATOMIC64 +CMPXCHG_HELPER(cmpxchgq_be, uint64_t) +CMPXCHG_HELPER(cmpxchgq_le, uint64_t) +#endif + +#undef CMPXCHG_HELPER + +#define ATOMIC_HELPER(OP, TYPE) \ + TYPE HELPER(glue(atomic_,OP))(CPUArchState *env, target_ulong addr, \ + TYPE val, uint32_t oi) \ + { return glue(glue(cpu_atomic_,OP),_mmu)(env, addr, val, oi, GETPC()); } + +#ifdef CONFIG_ATOMIC64 +#define GEN_ATOMIC_HELPERS(OP) \ + ATOMIC_HELPER(glue(OP,b), uint32_t) \ + ATOMIC_HELPER(glue(OP,w_be), uint32_t) \ + ATOMIC_HELPER(glue(OP,w_le), uint32_t) \ + ATOMIC_HELPER(glue(OP,l_be), uint32_t) \ + ATOMIC_HELPER(glue(OP,l_le), uint32_t) \ + ATOMIC_HELPER(glue(OP,q_be), uint64_t) \ + ATOMIC_HELPER(glue(OP,q_le), uint64_t) +#else +#define GEN_ATOMIC_HELPERS(OP) \ + ATOMIC_HELPER(glue(OP,b), uint32_t) \ + ATOMIC_HELPER(glue(OP,w_be), uint32_t) \ + ATOMIC_HELPER(glue(OP,w_le), uint32_t) \ + ATOMIC_HELPER(glue(OP,l_be), uint32_t) \ + ATOMIC_HELPER(glue(OP,l_le), uint32_t) +#endif + +GEN_ATOMIC_HELPERS(fetch_add) +GEN_ATOMIC_HELPERS(fetch_and) +GEN_ATOMIC_HELPERS(fetch_or) +GEN_ATOMIC_HELPERS(fetch_xor) +GEN_ATOMIC_HELPERS(fetch_smin) +GEN_ATOMIC_HELPERS(fetch_umin) +GEN_ATOMIC_HELPERS(fetch_smax) +GEN_ATOMIC_HELPERS(fetch_umax) + +GEN_ATOMIC_HELPERS(add_fetch) +GEN_ATOMIC_HELPERS(and_fetch) +GEN_ATOMIC_HELPERS(or_fetch) +GEN_ATOMIC_HELPERS(xor_fetch) +GEN_ATOMIC_HELPERS(smin_fetch) +GEN_ATOMIC_HELPERS(umin_fetch) +GEN_ATOMIC_HELPERS(smax_fetch) +GEN_ATOMIC_HELPERS(umax_fetch) + +GEN_ATOMIC_HELPERS(xchg) + +#undef ATOMIC_HELPER +#undef GEN_ATOMIC_HELPERS diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 63da1cc96f..842cf4b572 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2725,38 +2725,6 @@ void cpu_stq_le_data(CPUArchState *env, target_ulong ptr, uint64_t val) #include "atomic_template.h" #endif -/* Second set of helpers are directly callable from TCG as helpers. */ - -#undef EXTRA_ARGS -#undef ATOMIC_NAME -#undef ATOMIC_MMU_LOOKUP_RW -#undef ATOMIC_MMU_LOOKUP_R -#undef ATOMIC_MMU_LOOKUP_W - -#define EXTRA_ARGS , TCGMemOpIdx oi -#define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END)) -#define ATOMIC_MMU_LOOKUP_RW \ - atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ | PAGE_WRITE, GETPC()) -#define ATOMIC_MMU_LOOKUP_R \ - atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ, GETPC()) -#define ATOMIC_MMU_LOOKUP_W \ - atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_WRITE, GETPC()) - -#define DATA_SIZE 1 -#include "atomic_template.h" - -#define DATA_SIZE 2 -#include "atomic_template.h" - -#define DATA_SIZE 4 -#include "atomic_template.h" - -#ifdef CONFIG_ATOMIC64 -#define DATA_SIZE 8 -#include "atomic_template.h" -#endif -#undef ATOMIC_MMU_IDX - /* Code access functions. */ static uint64_t full_ldub_code(CPUArchState *env, target_ulong addr, diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h index 91a5b7e85f..37cbd722bf 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h @@ -39,8 +39,6 @@ DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env) DEF_HELPER_FLAGS_3(memset, TCG_CALL_NO_RWG, ptr, ptr, int, ptr) #endif /* IN_HELPER_PROTO */ -#ifdef CONFIG_SOFTMMU - DEF_HELPER_FLAGS_5(atomic_cmpxchgb, TCG_CALL_NO_WG, i32, env, tl, i32, i32, i32) DEF_HELPER_FLAGS_5(atomic_cmpxchgw_be, TCG_CALL_NO_WG, @@ -88,50 +86,6 @@ DEF_HELPER_FLAGS_5(atomic_cmpxchgq_le, TCG_CALL_NO_WG, TCG_CALL_NO_WG, i32, env, tl, i32, i32) #endif /* CONFIG_ATOMIC64 */ -#else - -DEF_HELPER_FLAGS_4(atomic_cmpxchgb, TCG_CALL_NO_WG, i32, env, tl, i32, i32) -DEF_HELPER_FLAGS_4(atomic_cmpxchgw_be, TCG_CALL_NO_WG, i32, env, tl, i32, i32) -DEF_HELPER_FLAGS_4(atomic_cmpxchgw_le, TCG_CALL_NO_WG, i32, env, tl, i32, i32) -DEF_HELPER_FLAGS_4(atomic_cmpxchgl_be, TCG_CALL_NO_WG, i32, env, tl, i32, i32) -DEF_HELPER_FLAGS_4(atomic_cmpxchgl_le, TCG_CALL_NO_WG, i32, env, tl, i32, i32) -#ifdef CONFIG_ATOMIC64 -DEF_HELPER_FLAGS_4(atomic_cmpxchgq_be, TCG_CALL_NO_WG, i64, env, tl, i64, i64) -DEF_HELPER_FLAGS_4(atomic_cmpxchgq_le, TCG_CALL_NO_WG, i64, env, tl, i64, i64) -#endif - -#ifdef CONFIG_ATOMIC64 -#define GEN_ATOMIC_HELPERS(NAME) \ - DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), b), \ - TCG_CALL_NO_WG, i32, env, tl, i32) \ - DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), w_le), \ - TCG_CALL_NO_WG, i32, env, tl, i32) \ - DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), w_be), \ - TCG_CALL_NO_WG, i32, env, tl, i32) \ - DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), l_le), \ - TCG_CALL_NO_WG, i32, env, tl, i32) \ - DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), l_be), \ - TCG_CALL_NO_WG, i32, env, tl, i32) \ - DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), q_le), \ - TCG_CALL_NO_WG, i64, env, tl, i64) \ - DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), q_be), \ - TCG_CALL_NO_WG, i64, env, tl, i64) -#else -#define GEN_ATOMIC_HELPERS(NAME) \ - DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), b), \ - TCG_CALL_NO_WG, i32, env, tl, i32) \ - DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), w_le), \ - TCG_CALL_NO_WG, i32, env, tl, i32) \ - DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), w_be), \ - TCG_CALL_NO_WG, i32, env, tl, i32) \ - DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), l_le), \ - TCG_CALL_NO_WG, i32, env, tl, i32) \ - DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), l_be), \ - TCG_CALL_NO_WG, i32, env, tl, i32) -#endif /* CONFIG_ATOMIC64 */ - -#endif /* CONFIG_SOFTMMU */ - GEN_ATOMIC_HELPERS(fetch_add) GEN_ATOMIC_HELPERS(fetch_and) GEN_ATOMIC_HELPERS(fetch_or) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 82dbe06f08..7e92d6b875 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1269,29 +1269,3 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, #define DATA_SIZE 16 #include "atomic_template.h" #endif - -/* - * Second set of functions is directly callable from TCG. - */ - -#undef EXTRA_ARGS -#undef ATOMIC_NAME -#undef ATOMIC_MMU_DECLS - -#define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END)) -#define EXTRA_ARGS -#define ATOMIC_MMU_DECLS uintptr_t retaddr = GETPC() - -#define DATA_SIZE 1 -#include "atomic_template.h" - -#define DATA_SIZE 2 -#include "atomic_template.h" - -#define DATA_SIZE 4 -#include "atomic_template.h" - -#ifdef CONFIG_ATOMIC64 -#define DATA_SIZE 8 -#include "atomic_template.h" -#endif diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 0c561fb253..75eaa910c9 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -3084,7 +3084,6 @@ static void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, MemOp opc) } } -#ifdef CONFIG_SOFTMMU typedef void (*gen_atomic_cx_i32)(TCGv_i32, TCGv_env, TCGv, TCGv_i32, TCGv_i32, TCGv_i32); typedef void (*gen_atomic_cx_i64)(TCGv_i64, TCGv_env, TCGv, @@ -3093,12 +3092,6 @@ typedef void (*gen_atomic_op_i32)(TCGv_i32, TCGv_env, TCGv, TCGv_i32, TCGv_i32); typedef void (*gen_atomic_op_i64)(TCGv_i64, TCGv_env, TCGv, TCGv_i64, TCGv_i32); -#else -typedef void (*gen_atomic_cx_i32)(TCGv_i32, TCGv_env, TCGv, TCGv_i32, TCGv_i32); -typedef void (*gen_atomic_cx_i64)(TCGv_i64, TCGv_env, TCGv, TCGv_i64, TCGv_i64); -typedef void (*gen_atomic_op_i32)(TCGv_i32, TCGv_env, TCGv, TCGv_i32); -typedef void (*gen_atomic_op_i64)(TCGv_i64, TCGv_env, TCGv, TCGv_i64); -#endif #ifdef CONFIG_ATOMIC64 # define WITH_ATOMIC64(X) X, @@ -3140,18 +3133,13 @@ void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv, tcg_temp_free_i32(t1); } else { gen_atomic_cx_i32 gen; + TCGMemOpIdx oi; gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)]; tcg_debug_assert(gen != NULL); -#ifdef CONFIG_SOFTMMU - { - TCGMemOpIdx oi = make_memop_idx(memop & ~MO_SIGN, idx); - gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); - } -#else - gen(retv, cpu_env, addr, cmpv, newv); -#endif + oi = make_memop_idx(memop & ~MO_SIGN, idx); + gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); if (memop & MO_SIGN) { tcg_gen_ext_i32(retv, retv, memop); @@ -3184,18 +3172,13 @@ void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv, } else if ((memop & MO_SIZE) == MO_64) { #ifdef CONFIG_ATOMIC64 gen_atomic_cx_i64 gen; + TCGMemOpIdx oi; gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)]; tcg_debug_assert(gen != NULL); -#ifdef CONFIG_SOFTMMU - { - TCGMemOpIdx oi = make_memop_idx(memop, idx); - gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); - } -#else - gen(retv, cpu_env, addr, cmpv, newv); -#endif + oi = make_memop_idx(memop, idx); + gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); #else gen_helper_exit_atomic(cpu_env); /* Produce a result, so that we have a well-formed opcode stream @@ -3245,20 +3228,15 @@ static void do_atomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val, TCGArg idx, MemOp memop, void * const table[]) { gen_atomic_op_i32 gen; + TCGMemOpIdx oi; memop = tcg_canonicalize_memop(memop, 0, 0); gen = table[memop & (MO_SIZE | MO_BSWAP)]; tcg_debug_assert(gen != NULL); -#ifdef CONFIG_SOFTMMU - { - TCGMemOpIdx oi = make_memop_idx(memop & ~MO_SIGN, idx); - gen(ret, cpu_env, addr, val, tcg_constant_i32(oi)); - } -#else - gen(ret, cpu_env, addr, val); -#endif + oi = make_memop_idx(memop & ~MO_SIGN, idx); + gen(ret, cpu_env, addr, val, tcg_constant_i32(oi)); if (memop & MO_SIGN) { tcg_gen_ext_i32(ret, ret, memop); @@ -3292,18 +3270,13 @@ static void do_atomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val, if ((memop & MO_SIZE) == MO_64) { #ifdef CONFIG_ATOMIC64 gen_atomic_op_i64 gen; + TCGMemOpIdx oi; gen = table[memop & (MO_SIZE | MO_BSWAP)]; tcg_debug_assert(gen != NULL); -#ifdef CONFIG_SOFTMMU - { - TCGMemOpIdx oi = make_memop_idx(memop & ~MO_SIGN, idx); - gen(ret, cpu_env, addr, val, tcg_constant_i32(oi)); - } -#else - gen(ret, cpu_env, addr, val); -#endif + oi = make_memop_idx(memop & ~MO_SIGN, idx); + gen(ret, cpu_env, addr, val, tcg_constant_i32(oi)); #else gen_helper_exit_atomic(cpu_env); /* Produce a result, so that we have a well-formed opcode stream From 48688fafeb6e9f462837abb39a9c286e39d398e4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Jul 2021 15:57:02 -0700 Subject: [PATCH 261/531] accel/tcg: Fold EXTRA_ARGS into atomic_template.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All instances of EXTRA_ARGS are now identical. Tested-by: Cole Robinson Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/atomic_template.h | 36 ++++++++++++++++++++---------------- accel/tcg/cputlb.c | 1 - accel/tcg/user-exec.c | 1 - 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h index d347462af5..52fb26a274 100644 --- a/accel/tcg/atomic_template.h +++ b/accel/tcg/atomic_template.h @@ -71,7 +71,8 @@ #endif ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, - ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) + ABI_TYPE cmpv, ABI_TYPE newv, + TCGMemOpIdx oi, uintptr_t retaddr) { ATOMIC_MMU_DECLS; DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; @@ -92,7 +93,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, #if DATA_SIZE >= 16 #if HAVE_ATOMIC128 -ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) +ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, + TCGMemOpIdx oi, uintptr_t retaddr) { ATOMIC_MMU_DECLS; DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP_R; @@ -106,8 +108,8 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) return val; } -void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, - ABI_TYPE val EXTRA_ARGS) +void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, + TCGMemOpIdx oi, uintptr_t retaddr) { ATOMIC_MMU_DECLS; DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_W; @@ -121,8 +123,8 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, } #endif #else -ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, - ABI_TYPE val EXTRA_ARGS) +ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, + TCGMemOpIdx oi, uintptr_t retaddr) { ATOMIC_MMU_DECLS; DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; @@ -139,7 +141,7 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, #define GEN_ATOMIC_HELPER(X) \ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ - ABI_TYPE val EXTRA_ARGS) \ + ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \ { \ ATOMIC_MMU_DECLS; \ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ @@ -173,7 +175,7 @@ GEN_ATOMIC_HELPER(xor_fetch) */ #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ - ABI_TYPE xval EXTRA_ARGS) \ + ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \ { \ ATOMIC_MMU_DECLS; \ XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ @@ -218,7 +220,8 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) #endif ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, - ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) + ABI_TYPE cmpv, ABI_TYPE newv, + TCGMemOpIdx oi, uintptr_t retaddr) { ATOMIC_MMU_DECLS; DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; @@ -239,7 +242,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, #if DATA_SIZE >= 16 #if HAVE_ATOMIC128 -ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) +ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, + TCGMemOpIdx oi, uintptr_t retaddr) { ATOMIC_MMU_DECLS; DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP_R; @@ -253,8 +257,8 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) return BSWAP(val); } -void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, - ABI_TYPE val EXTRA_ARGS) +void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, + TCGMemOpIdx oi, uintptr_t retaddr) { ATOMIC_MMU_DECLS; DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_W; @@ -270,8 +274,8 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, } #endif #else -ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, - ABI_TYPE val EXTRA_ARGS) +ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, + TCGMemOpIdx oi, uintptr_t retaddr) { ATOMIC_MMU_DECLS; DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; @@ -288,7 +292,7 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, #define GEN_ATOMIC_HELPER(X) \ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ - ABI_TYPE val EXTRA_ARGS) \ + ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \ { \ ATOMIC_MMU_DECLS; \ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ @@ -320,7 +324,7 @@ GEN_ATOMIC_HELPER(xor_fetch) */ #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ - ABI_TYPE xval EXTRA_ARGS) \ + ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \ { \ ATOMIC_MMU_DECLS; \ XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 842cf4b572..cc0e673222 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2691,7 +2691,6 @@ void cpu_stq_le_data(CPUArchState *env, target_ulong ptr, uint64_t val) * This makes them callable from other helpers. */ -#define EXTRA_ARGS , TCGMemOpIdx oi, uintptr_t retaddr #define ATOMIC_NAME(X) \ glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu) #define ATOMIC_MMU_DECLS diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 7e92d6b875..f6f8ddeb60 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1241,7 +1241,6 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, * This makes them callable from other helpers. */ -#define EXTRA_ARGS , TCGMemOpIdx oi, uintptr_t retaddr #define ATOMIC_NAME(X) \ glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu) #define ATOMIC_MMU_DECLS From fcff001441b413ae45d50fe7b301d7bb3217ebc7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Jul 2021 15:59:09 -0700 Subject: [PATCH 262/531] accel/tcg: Remove ATOMIC_MMU_DECLS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All definitions are now empty. Tested-by: Cole Robinson Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/atomic_template.h | 12 ------------ accel/tcg/cputlb.c | 1 - accel/tcg/user-exec.c | 1 - 3 files changed, 14 deletions(-) diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h index 52fb26a274..ae6b6a03be 100644 --- a/accel/tcg/atomic_template.h +++ b/accel/tcg/atomic_template.h @@ -74,7 +74,6 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, ABI_TYPE cmpv, ABI_TYPE newv, TCGMemOpIdx oi, uintptr_t retaddr) { - ATOMIC_MMU_DECLS; DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; DATA_TYPE ret; uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, @@ -96,7 +95,6 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - ATOMIC_MMU_DECLS; DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP_R; uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, ATOMIC_MMU_IDX); @@ -111,7 +109,6 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) { - ATOMIC_MMU_DECLS; DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_W; uint16_t info = trace_mem_build_info(SHIFT, false, 0, true, ATOMIC_MMU_IDX); @@ -126,7 +123,6 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) { - ATOMIC_MMU_DECLS; DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; DATA_TYPE ret; uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, @@ -143,7 +139,6 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \ { \ - ATOMIC_MMU_DECLS; \ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ DATA_TYPE ret; \ uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \ @@ -177,7 +172,6 @@ GEN_ATOMIC_HELPER(xor_fetch) ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \ { \ - ATOMIC_MMU_DECLS; \ XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ XDATA_TYPE cmp, old, new, val = xval; \ uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \ @@ -223,7 +217,6 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, ABI_TYPE cmpv, ABI_TYPE newv, TCGMemOpIdx oi, uintptr_t retaddr) { - ATOMIC_MMU_DECLS; DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; DATA_TYPE ret; uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, @@ -245,7 +238,6 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - ATOMIC_MMU_DECLS; DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP_R; uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, ATOMIC_MMU_IDX); @@ -260,7 +252,6 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) { - ATOMIC_MMU_DECLS; DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_W; uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, true, ATOMIC_MMU_IDX); @@ -277,7 +268,6 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) { - ATOMIC_MMU_DECLS; DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; ABI_TYPE ret; uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, @@ -294,7 +284,6 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \ { \ - ATOMIC_MMU_DECLS; \ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ DATA_TYPE ret; \ uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \ @@ -326,7 +315,6 @@ GEN_ATOMIC_HELPER(xor_fetch) ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \ { \ - ATOMIC_MMU_DECLS; \ XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ XDATA_TYPE ldo, ldn, old, new, val = xval; \ uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \ diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index cc0e673222..dc646e964a 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2693,7 +2693,6 @@ void cpu_stq_le_data(CPUArchState *env, target_ulong ptr, uint64_t val) #define ATOMIC_NAME(X) \ glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu) -#define ATOMIC_MMU_DECLS #define ATOMIC_MMU_LOOKUP_RW \ atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ | PAGE_WRITE, retaddr) #define ATOMIC_MMU_LOOKUP_R \ diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index f6f8ddeb60..bc4a38b4df 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1243,7 +1243,6 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, #define ATOMIC_NAME(X) \ glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu) -#define ATOMIC_MMU_DECLS #define ATOMIC_MMU_LOOKUP_RW atomic_mmu_lookup(env, addr, DATA_SIZE, retaddr) #define ATOMIC_MMU_LOOKUP_R ATOMIC_MMU_LOOKUP_RW #define ATOMIC_MMU_LOOKUP_W ATOMIC_MMU_LOOKUP_RW From a754f7f34e9c74adf65a0149c5e2382077a6e594 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Jul 2021 17:49:09 -0700 Subject: [PATCH 263/531] accel/tcg: Expand ATOMIC_MMU_LOOKUP_* Unify the parameters of atomic_mmu_lookup between cputlb.c and user-exec.c. Call the function directly, and remove the macros. Tested-by: Cole Robinson Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- accel/tcg/atomic_template.h | 41 +++++++++++++++++++++++++------------ accel/tcg/cputlb.c | 7 +------ accel/tcg/user-exec.c | 12 ++++++----- 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h index ae6b6a03be..6ee0158c5f 100644 --- a/accel/tcg/atomic_template.h +++ b/accel/tcg/atomic_template.h @@ -74,7 +74,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, ABI_TYPE cmpv, ABI_TYPE newv, TCGMemOpIdx oi, uintptr_t retaddr) { - DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; + DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, + PAGE_READ | PAGE_WRITE, retaddr); DATA_TYPE ret; uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, ATOMIC_MMU_IDX); @@ -95,7 +96,9 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP_R; + DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, + PAGE_READ, retaddr); + DATA_TYPE val; uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, ATOMIC_MMU_IDX); @@ -109,7 +112,8 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) { - DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_W; + DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, + PAGE_WRITE, retaddr); uint16_t info = trace_mem_build_info(SHIFT, false, 0, true, ATOMIC_MMU_IDX); @@ -123,7 +127,8 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) { - DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; + DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, + PAGE_READ | PAGE_WRITE, retaddr); DATA_TYPE ret; uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, ATOMIC_MMU_IDX); @@ -139,7 +144,8 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \ { \ - DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ + DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ + PAGE_READ | PAGE_WRITE, retaddr); \ DATA_TYPE ret; \ uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \ ATOMIC_MMU_IDX); \ @@ -161,7 +167,8 @@ GEN_ATOMIC_HELPER(xor_fetch) #undef GEN_ATOMIC_HELPER -/* These helpers are, as a whole, full barriers. Within the helper, +/* + * These helpers are, as a whole, full barriers. Within the helper, * the leading barrier is explicit and the trailing barrier is within * cmpxchg primitive. * @@ -172,7 +179,8 @@ GEN_ATOMIC_HELPER(xor_fetch) ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \ { \ - XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ + XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ + PAGE_READ | PAGE_WRITE, retaddr); \ XDATA_TYPE cmp, old, new, val = xval; \ uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \ ATOMIC_MMU_IDX); \ @@ -217,7 +225,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, ABI_TYPE cmpv, ABI_TYPE newv, TCGMemOpIdx oi, uintptr_t retaddr) { - DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; + DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, + PAGE_READ | PAGE_WRITE, retaddr); DATA_TYPE ret; uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, ATOMIC_MMU_IDX); @@ -238,7 +247,9 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP_R; + DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, + PAGE_READ, retaddr); + DATA_TYPE val; uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, ATOMIC_MMU_IDX); @@ -252,7 +263,8 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) { - DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_W; + DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, + PAGE_WRITE, retaddr); uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, true, ATOMIC_MMU_IDX); @@ -268,7 +280,8 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) { - DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; + DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, + PAGE_READ | PAGE_WRITE, retaddr); ABI_TYPE ret; uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, ATOMIC_MMU_IDX); @@ -284,7 +297,8 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \ { \ - DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ + DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ + PAGE_READ | PAGE_WRITE, retaddr); \ DATA_TYPE ret; \ uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \ false, ATOMIC_MMU_IDX); \ @@ -315,7 +329,8 @@ GEN_ATOMIC_HELPER(xor_fetch) ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \ { \ - XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ + XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ + PAGE_READ | PAGE_WRITE, retaddr); \ XDATA_TYPE ldo, ldn, old, new, val = xval; \ uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \ false, ATOMIC_MMU_IDX); \ diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index dc646e964a..b1e5471f94 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2693,12 +2693,7 @@ void cpu_stq_le_data(CPUArchState *env, target_ulong ptr, uint64_t val) #define ATOMIC_NAME(X) \ glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu) -#define ATOMIC_MMU_LOOKUP_RW \ - atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ | PAGE_WRITE, retaddr) -#define ATOMIC_MMU_LOOKUP_R \ - atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ, retaddr) -#define ATOMIC_MMU_LOOKUP_W \ - atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_WRITE, retaddr) + #define ATOMIC_MMU_CLEANUP #define ATOMIC_MMU_IDX get_mmuidx(oi) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index bc4a38b4df..90d1a2d327 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1221,9 +1221,14 @@ uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr) return ret; } -/* Do not allow unaligned operations to proceed. Return the host address. */ +/* + * Do not allow unaligned operations to proceed. Return the host address. + * + * @prot may be PAGE_READ, PAGE_WRITE, or PAGE_READ|PAGE_WRITE. + */ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, - int size, uintptr_t retaddr) + TCGMemOpIdx oi, int size, int prot, + uintptr_t retaddr) { /* Enforce qemu required alignment. */ if (unlikely(addr & (size - 1))) { @@ -1243,9 +1248,6 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, #define ATOMIC_NAME(X) \ glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu) -#define ATOMIC_MMU_LOOKUP_RW atomic_mmu_lookup(env, addr, DATA_SIZE, retaddr) -#define ATOMIC_MMU_LOOKUP_R ATOMIC_MMU_LOOKUP_RW -#define ATOMIC_MMU_LOOKUP_W ATOMIC_MMU_LOOKUP_RW #define ATOMIC_MMU_CLEANUP do { clear_helper_retaddr(); } while (0) #define ATOMIC_MMU_IDX MMU_USER_IDX From 785ea711b114452889016f0d292b8f9e9da31752 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Jul 2021 18:04:32 -0700 Subject: [PATCH 264/531] trace: Fold mem-internal.h into mem.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the last thing that mem.h does is include mem-internal.h, the symbols are not actually private. Tested-by: Cole Robinson Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- plugins/core.c | 2 +- trace/mem-internal.h | 50 -------------------------------------------- trace/mem.h | 50 ++++++++++++++++++++++++++++++++++---------- 3 files changed, 40 insertions(+), 62 deletions(-) delete mode 100644 trace/mem-internal.h diff --git a/plugins/core.c b/plugins/core.c index e1bcdb570d..474db287cb 100644 --- a/plugins/core.c +++ b/plugins/core.c @@ -27,7 +27,7 @@ #include "exec/helper-proto.h" #include "tcg/tcg.h" #include "tcg/tcg-op.h" -#include "trace/mem-internal.h" /* mem_info macros */ +#include "trace/mem.h" /* mem_info macros */ #include "plugin.h" #include "qemu/compiler.h" diff --git a/trace/mem-internal.h b/trace/mem-internal.h deleted file mode 100644 index 8b72b678fa..0000000000 --- a/trace/mem-internal.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Helper functions for guest memory tracing - * - * Copyright (C) 2016 Lluís Vilanova - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#ifndef TRACE__MEM_INTERNAL_H -#define TRACE__MEM_INTERNAL_H - -#define TRACE_MEM_SZ_SHIFT_MASK 0xf /* size shift mask */ -#define TRACE_MEM_SE (1ULL << 4) /* sign extended (y/n) */ -#define TRACE_MEM_BE (1ULL << 5) /* big endian (y/n) */ -#define TRACE_MEM_ST (1ULL << 6) /* store (y/n) */ -#define TRACE_MEM_MMU_SHIFT 8 /* mmu idx */ - -static inline uint16_t trace_mem_build_info( - int size_shift, bool sign_extend, MemOp endianness, - bool store, unsigned int mmu_idx) -{ - uint16_t res; - - res = size_shift & TRACE_MEM_SZ_SHIFT_MASK; - if (sign_extend) { - res |= TRACE_MEM_SE; - } - if (endianness == MO_BE) { - res |= TRACE_MEM_BE; - } - if (store) { - res |= TRACE_MEM_ST; - } -#ifdef CONFIG_SOFTMMU - res |= mmu_idx << TRACE_MEM_MMU_SHIFT; -#endif - return res; -} - -static inline uint16_t trace_mem_get_info(MemOp op, - unsigned int mmu_idx, - bool store) -{ - return trace_mem_build_info(op & MO_SIZE, !!(op & MO_SIGN), - op & MO_BSWAP, store, - mmu_idx); -} - -#endif /* TRACE__MEM_INTERNAL_H */ diff --git a/trace/mem.h b/trace/mem.h index 9644f592b4..2f27e7bdf0 100644 --- a/trace/mem.h +++ b/trace/mem.h @@ -12,24 +12,52 @@ #include "tcg/tcg.h" - -/** - * trace_mem_get_info: - * - * Return a value for the 'info' argument in guest memory access traces. - */ -static uint16_t trace_mem_get_info(MemOp op, unsigned int mmu_idx, bool store); +#define TRACE_MEM_SZ_SHIFT_MASK 0xf /* size shift mask */ +#define TRACE_MEM_SE (1ULL << 4) /* sign extended (y/n) */ +#define TRACE_MEM_BE (1ULL << 5) /* big endian (y/n) */ +#define TRACE_MEM_ST (1ULL << 6) /* store (y/n) */ +#define TRACE_MEM_MMU_SHIFT 8 /* mmu idx */ /** * trace_mem_build_info: * * Return a value for the 'info' argument in guest memory access traces. */ -static uint16_t trace_mem_build_info(int size_shift, bool sign_extend, - MemOp endianness, bool store, - unsigned int mmuidx); +static inline uint16_t trace_mem_build_info(int size_shift, bool sign_extend, + MemOp endianness, bool store, + unsigned int mmu_idx) +{ + uint16_t res; + + res = size_shift & TRACE_MEM_SZ_SHIFT_MASK; + if (sign_extend) { + res |= TRACE_MEM_SE; + } + if (endianness == MO_BE) { + res |= TRACE_MEM_BE; + } + if (store) { + res |= TRACE_MEM_ST; + } +#ifdef CONFIG_SOFTMMU + res |= mmu_idx << TRACE_MEM_MMU_SHIFT; +#endif + return res; +} -#include "trace/mem-internal.h" +/** + * trace_mem_get_info: + * + * Return a value for the 'info' argument in guest memory access traces. + */ +static inline uint16_t trace_mem_get_info(MemOp op, + unsigned int mmu_idx, + bool store) +{ + return trace_mem_build_info(op & MO_SIZE, !!(op & MO_SIGN), + op & MO_BSWAP, store, + mmu_idx); +} #endif /* TRACE__MEM_H */ From f3e182b10013c042b8ab555e4220da7b163862b9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Jul 2021 18:27:13 -0700 Subject: [PATCH 265/531] accel/tcg: Push trace info building into atomic_common.c.inc Use trace_mem_get_info instead of trace_mem_build_info, using the TCGMemOpIdx that we already have. Do this in the atomic_trace_*_pre function as common subroutines. Tested-by: Cole Robinson Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- accel/tcg/atomic_common.c.inc | 37 ++++++++++++++++++--------- accel/tcg/atomic_template.h | 48 +++++++++-------------------------- 2 files changed, 37 insertions(+), 48 deletions(-) diff --git a/accel/tcg/atomic_common.c.inc b/accel/tcg/atomic_common.c.inc index a668cf0d6f..6c0339f610 100644 --- a/accel/tcg/atomic_common.c.inc +++ b/accel/tcg/atomic_common.c.inc @@ -13,45 +13,58 @@ * See the COPYING file in the top-level directory. */ -static inline -void atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr, uint16_t info) +static uint16_t atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr, + TCGMemOpIdx oi) { CPUState *cpu = env_cpu(env); + uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), false); trace_guest_mem_before_exec(cpu, addr, info); trace_guest_mem_before_exec(cpu, addr, info | TRACE_MEM_ST); + + return info; } -static inline void -atomic_trace_rmw_post(CPUArchState *env, target_ulong addr, uint16_t info) +static void atomic_trace_rmw_post(CPUArchState *env, target_ulong addr, + uint16_t info) { qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info | TRACE_MEM_ST); } -static inline -void atomic_trace_ld_pre(CPUArchState *env, target_ulong addr, uint16_t info) +#if HAVE_ATOMIC128 +static uint16_t atomic_trace_ld_pre(CPUArchState *env, target_ulong addr, + TCGMemOpIdx oi) { + uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), false); + trace_guest_mem_before_exec(env_cpu(env), addr, info); + + return info; } -static inline -void atomic_trace_ld_post(CPUArchState *env, target_ulong addr, uint16_t info) +static void atomic_trace_ld_post(CPUArchState *env, target_ulong addr, + uint16_t info) { qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info); } -static inline -void atomic_trace_st_pre(CPUArchState *env, target_ulong addr, uint16_t info) +static uint16_t atomic_trace_st_pre(CPUArchState *env, target_ulong addr, + TCGMemOpIdx oi) { + uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), true); + trace_guest_mem_before_exec(env_cpu(env), addr, info); + + return info; } -static inline -void atomic_trace_st_post(CPUArchState *env, target_ulong addr, uint16_t info) +static void atomic_trace_st_post(CPUArchState *env, target_ulong addr, + uint16_t info) { qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info); } +#endif /* * Atomic helpers callable from TCG. diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h index 6ee0158c5f..d89af4cc1e 100644 --- a/accel/tcg/atomic_template.h +++ b/accel/tcg/atomic_template.h @@ -77,10 +77,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ | PAGE_WRITE, retaddr); DATA_TYPE ret; - uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, - ATOMIC_MMU_IDX); + uint16_t info = atomic_trace_rmw_pre(env, addr, oi); - atomic_trace_rmw_pre(env, addr, info); #if DATA_SIZE == 16 ret = atomic16_cmpxchg(haddr, cmpv, newv); #else @@ -99,10 +97,8 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ, retaddr); DATA_TYPE val; - uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, - ATOMIC_MMU_IDX); + uint16_t info = atomic_trace_ld_pre(env, addr, oi); - atomic_trace_ld_pre(env, addr, info); val = atomic16_read(haddr); ATOMIC_MMU_CLEANUP; atomic_trace_ld_post(env, addr, info); @@ -114,10 +110,8 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, { DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_WRITE, retaddr); - uint16_t info = trace_mem_build_info(SHIFT, false, 0, true, - ATOMIC_MMU_IDX); + uint16_t info = atomic_trace_st_pre(env, addr, oi); - atomic_trace_st_pre(env, addr, info); atomic16_set(haddr, val); ATOMIC_MMU_CLEANUP; atomic_trace_st_post(env, addr, info); @@ -130,10 +124,8 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ | PAGE_WRITE, retaddr); DATA_TYPE ret; - uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, - ATOMIC_MMU_IDX); + uint16_t info = atomic_trace_rmw_pre(env, addr, oi); - atomic_trace_rmw_pre(env, addr, info); ret = qatomic_xchg__nocheck(haddr, val); ATOMIC_MMU_CLEANUP; atomic_trace_rmw_post(env, addr, info); @@ -147,9 +139,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ PAGE_READ | PAGE_WRITE, retaddr); \ DATA_TYPE ret; \ - uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \ - ATOMIC_MMU_IDX); \ - atomic_trace_rmw_pre(env, addr, info); \ + uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \ ret = qatomic_##X(haddr, val); \ ATOMIC_MMU_CLEANUP; \ atomic_trace_rmw_post(env, addr, info); \ @@ -182,9 +172,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ PAGE_READ | PAGE_WRITE, retaddr); \ XDATA_TYPE cmp, old, new, val = xval; \ - uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \ - ATOMIC_MMU_IDX); \ - atomic_trace_rmw_pre(env, addr, info); \ + uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \ smp_mb(); \ cmp = qatomic_read__nocheck(haddr); \ do { \ @@ -228,10 +216,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ | PAGE_WRITE, retaddr); DATA_TYPE ret; - uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, - ATOMIC_MMU_IDX); + uint16_t info = atomic_trace_rmw_pre(env, addr, oi); - atomic_trace_rmw_pre(env, addr, info); #if DATA_SIZE == 16 ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv)); #else @@ -250,10 +236,8 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ, retaddr); DATA_TYPE val; - uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, - ATOMIC_MMU_IDX); + uint16_t info = atomic_trace_ld_pre(env, addr, oi); - atomic_trace_ld_pre(env, addr, info); val = atomic16_read(haddr); ATOMIC_MMU_CLEANUP; atomic_trace_ld_post(env, addr, info); @@ -265,11 +249,9 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, { DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_WRITE, retaddr); - uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, true, - ATOMIC_MMU_IDX); + uint16_t info = atomic_trace_st_pre(env, addr, oi); val = BSWAP(val); - atomic_trace_st_pre(env, addr, info); val = BSWAP(val); atomic16_set(haddr, val); ATOMIC_MMU_CLEANUP; @@ -283,10 +265,8 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ | PAGE_WRITE, retaddr); ABI_TYPE ret; - uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, - ATOMIC_MMU_IDX); + uint16_t info = atomic_trace_rmw_pre(env, addr, oi); - atomic_trace_rmw_pre(env, addr, info); ret = qatomic_xchg__nocheck(haddr, BSWAP(val)); ATOMIC_MMU_CLEANUP; atomic_trace_rmw_post(env, addr, info); @@ -300,9 +280,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ PAGE_READ | PAGE_WRITE, retaddr); \ DATA_TYPE ret; \ - uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \ - false, ATOMIC_MMU_IDX); \ - atomic_trace_rmw_pre(env, addr, info); \ + uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \ ret = qatomic_##X(haddr, BSWAP(val)); \ ATOMIC_MMU_CLEANUP; \ atomic_trace_rmw_post(env, addr, info); \ @@ -332,9 +310,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ PAGE_READ | PAGE_WRITE, retaddr); \ XDATA_TYPE ldo, ldn, old, new, val = xval; \ - uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \ - false, ATOMIC_MMU_IDX); \ - atomic_trace_rmw_pre(env, addr, info); \ + uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \ smp_mb(); \ ldn = qatomic_read__nocheck(haddr); \ do { \ From 78ff82bb1b67c0d79113688e4b3427fc99cab9d4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 17 Jul 2021 15:18:39 -0700 Subject: [PATCH 266/531] accel/tcg: Reduce CF_COUNT_MASK to match TCG_MAX_INSNS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The space reserved for CF_COUNT_MASK was overly large. Reduce to free up cflags bits and eliminate an extra test. Tested-by: Mark Cave-Ayland Signed-off-by: Richard Henderson Reviewed-by: Alex Bennée Reviewed-by: Peter Maydell Message-Id: <20210717221851.2124573-2-richard.henderson@linaro.org> --- accel/tcg/translate-all.c | 5 ++--- include/exec/exec-all.h | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 4df26de858..5cc01d693b 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -1428,11 +1428,10 @@ TranslationBlock *tb_gen_code(CPUState *cpu, max_insns = cflags & CF_COUNT_MASK; if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } - if (max_insns > TCG_MAX_INSNS) { max_insns = TCG_MAX_INSNS; } + QEMU_BUILD_BUG_ON(CF_COUNT_MASK + 1 != TCG_MAX_INSNS); + if (cpu->singlestep_enabled || singlestep) { max_insns = 1; } diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 754f4130c9..dfe82ed19c 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -492,7 +492,9 @@ struct TranslationBlock { target_ulong cs_base; /* CS base for this block */ uint32_t flags; /* flags defining in which context the code was generated */ uint32_t cflags; /* compile flags */ -#define CF_COUNT_MASK 0x00007fff + +/* Note that TCG_MAX_INSNS is 512; we validate this match elsewhere. */ +#define CF_COUNT_MASK 0x000001ff #define CF_LAST_IO 0x00008000 /* Last insn may be an IO access. */ #define CF_MEMI_ONLY 0x00010000 /* Only instrument memory ops */ #define CF_USE_ICOUNT 0x00020000 From 043e35d98c0865a7396783b57b74359cfab85c40 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 17 Jul 2021 15:18:40 -0700 Subject: [PATCH 267/531] accel/tcg: Move curr_cflags into cpu-exec.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will shortly have more than a simple member read here, with stuff not necessarily exposed to exec/exec-all.h. Tested-by: Mark Cave-Ayland Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210717221851.2124573-3-richard.henderson@linaro.org> --- accel/tcg/cpu-exec.c | 5 +++++ include/exec/exec-all.h | 5 +---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index e22bcb99f7..ef4214d893 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -145,6 +145,11 @@ static void init_delay_params(SyncClocks *sc, const CPUState *cpu) } #endif /* CONFIG USER ONLY */ +uint32_t curr_cflags(CPUState *cpu) +{ + return cpu->tcg_cflags; +} + /* Might cause an exception, so have a longjmp destination ready */ static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc, target_ulong cs_base, diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index dfe82ed19c..ae7603ca75 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -565,10 +565,7 @@ static inline uint32_t tb_cflags(const TranslationBlock *tb) } /* current cflags for hashing/comparison */ -static inline uint32_t curr_cflags(CPUState *cpu) -{ - return cpu->tcg_cflags; -} +uint32_t curr_cflags(CPUState *cpu); /* TranslationBlock invalidate API */ #if defined(CONFIG_USER_ONLY) From 288a5fe980f75c1c6c8a65fc9367c2902f44f4fa Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 18 Jul 2021 15:24:29 -1000 Subject: [PATCH 268/531] target/alpha: Drop goto_tb path in gen_call_pal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are certain of a page crossing here, entering the PALcode image, so the call to use_goto_tb that should have been here will never succeed. We are shortly going to add an assert to tcg_gen_goto_tb that would trigger for this case. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/alpha/translate.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 103c6326a2..949ba6ffde 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -1207,19 +1207,8 @@ static DisasJumpType gen_call_pal(DisasContext *ctx, int palcode) ? 0x2000 + (palcode - 0x80) * 64 : 0x1000 + palcode * 64); - /* Since the destination is running in PALmode, we don't really - need the page permissions check. We'll see the existence of - the page when we create the TB, and we'll flush all TBs if - we change the PAL base register. */ - if (!ctx->base.singlestep_enabled) { - tcg_gen_goto_tb(0); - tcg_gen_movi_i64(cpu_pc, entry); - tcg_gen_exit_tb(ctx->base.tb, 0); - return DISAS_NORETURN; - } else { - tcg_gen_movi_i64(cpu_pc, entry); - return DISAS_PC_UPDATED; - } + tcg_gen_movi_i64(cpu_pc, entry); + return DISAS_PC_UPDATED; } #endif } From 84f1561629ba5b6942b6edd825a1d14c9f51a25c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 17 Jul 2021 15:18:41 -0700 Subject: [PATCH 269/531] accel/tcg: Add CF_NO_GOTO_TB and CF_NO_GOTO_PTR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the -d nochain check to bits on tb->cflags. These will be used for more than -d nochain shortly. Set bits during curr_cflags, test them in translator_use_goto_tb, assert we're not doing anything odd in tcg_gen_goto_tb. The test in tcg_gen_exit_tb is redundant with the assert for goto_tb_issue_mask. Tested-by: Mark Cave-Ayland Signed-off-by: Richard Henderson Reviewed-by: Alex Bennée Reviewed-by: Peter Maydell Message-Id: <20210717221851.2124573-4-richard.henderson@linaro.org> --- accel/tcg/cpu-exec.c | 8 +++++++- accel/tcg/translator.c | 5 +++++ include/exec/exec-all.h | 16 +++++++++------- tcg/tcg-op.c | 28 ++++++++++++---------------- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index ef4214d893..d3232d5764 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -147,7 +147,13 @@ static void init_delay_params(SyncClocks *sc, const CPUState *cpu) uint32_t curr_cflags(CPUState *cpu) { - return cpu->tcg_cflags; + uint32_t cflags = cpu->tcg_cflags; + + if (qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { + cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR; + } + + return cflags; } /* Might cause an exception, so have a longjmp destination ready */ diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 59804af37b..2ea5a74f30 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -33,6 +33,11 @@ void translator_loop_temp_check(DisasContextBase *db) bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest) { + /* Suppress goto_tb if requested. */ + if (tb_cflags(db->tb) & CF_NO_GOTO_TB) { + return false; + } + /* Suppress goto_tb in the case of single-steping. */ if (db->singlestep_enabled || singlestep) { return false; diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index ae7603ca75..6873cce8df 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -494,13 +494,15 @@ struct TranslationBlock { uint32_t cflags; /* compile flags */ /* Note that TCG_MAX_INSNS is 512; we validate this match elsewhere. */ -#define CF_COUNT_MASK 0x000001ff -#define CF_LAST_IO 0x00008000 /* Last insn may be an IO access. */ -#define CF_MEMI_ONLY 0x00010000 /* Only instrument memory ops */ -#define CF_USE_ICOUNT 0x00020000 -#define CF_INVALID 0x00040000 /* TB is stale. Set with @jmp_lock held */ -#define CF_PARALLEL 0x00080000 /* Generate code for a parallel context */ -#define CF_CLUSTER_MASK 0xff000000 /* Top 8 bits are cluster ID */ +#define CF_COUNT_MASK 0x000001ff +#define CF_NO_GOTO_TB 0x00000200 /* Do not chain with goto_tb */ +#define CF_NO_GOTO_PTR 0x00000400 /* Do not chain with goto_ptr */ +#define CF_LAST_IO 0x00008000 /* Last insn may be an IO access. */ +#define CF_MEMI_ONLY 0x00010000 /* Only instrument memory ops */ +#define CF_USE_ICOUNT 0x00020000 +#define CF_INVALID 0x00040000 /* TB is stale. Set with @jmp_lock held */ +#define CF_PARALLEL 0x00080000 /* Generate code for a parallel context */ +#define CF_CLUSTER_MASK 0xff000000 /* Top 8 bits are cluster ID */ #define CF_CLUSTER_SHIFT 24 /* Per-vCPU dynamic tracing state used to generate this TB */ diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 75eaa910c9..c754396575 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -2723,10 +2723,6 @@ void tcg_gen_exit_tb(const TranslationBlock *tb, unsigned idx) seen this numbered exit before, via tcg_gen_goto_tb. */ tcg_debug_assert(tcg_ctx->goto_tb_issue_mask & (1 << idx)); #endif - /* When not chaining, exit without indicating a link. */ - if (qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { - val = 0; - } } else { /* This is an exit via the exitreq label. */ tcg_debug_assert(idx == TB_EXIT_REQUESTED); @@ -2738,6 +2734,8 @@ void tcg_gen_exit_tb(const TranslationBlock *tb, unsigned idx) void tcg_gen_goto_tb(unsigned idx) { + /* We tested CF_NO_GOTO_TB in translator_use_goto_tb. */ + tcg_debug_assert(!(tcg_ctx->tb_cflags & CF_NO_GOTO_TB)); /* We only support two chained exits. */ tcg_debug_assert(idx <= TB_EXIT_IDXMAX); #ifdef CONFIG_DEBUG_TCG @@ -2746,25 +2744,23 @@ void tcg_gen_goto_tb(unsigned idx) tcg_ctx->goto_tb_issue_mask |= 1 << idx; #endif plugin_gen_disable_mem_helpers(); - /* When not chaining, we simply fall through to the "fallback" exit. */ - if (!qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { - tcg_gen_op1i(INDEX_op_goto_tb, idx); - } + tcg_gen_op1i(INDEX_op_goto_tb, idx); } void tcg_gen_lookup_and_goto_ptr(void) { - if (!qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { - TCGv_ptr ptr; + TCGv_ptr ptr; - plugin_gen_disable_mem_helpers(); - ptr = tcg_temp_new_ptr(); - gen_helper_lookup_tb_ptr(ptr, cpu_env); - tcg_gen_op1i(INDEX_op_goto_ptr, tcgv_ptr_arg(ptr)); - tcg_temp_free_ptr(ptr); - } else { + if (tcg_ctx->tb_cflags & CF_NO_GOTO_PTR) { tcg_gen_exit_tb(NULL, 0); + return; } + + plugin_gen_disable_mem_helpers(); + ptr = tcg_temp_new_ptr(); + gen_helper_lookup_tb_ptr(ptr, cpu_env); + tcg_gen_op1i(INDEX_op_goto_ptr, tcgv_ptr_arg(ptr)); + tcg_temp_free_ptr(ptr); } static inline MemOp tcg_canonicalize_memop(MemOp op, bool is64, bool st) From fb957011324bd5e2aa2cdc4e276e8e2a3fb6a167 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 17 Jul 2021 15:18:42 -0700 Subject: [PATCH 270/531] accel/tcg: Drop CF_NO_GOTO_PTR from -d nochain The purpose of suppressing goto_ptr from -d nochain had been to return to the main loop so that -d cpu would be recognized. But we now include -d cpu logging in helper_lookup_tb_ptr so there is no need to exclude goto_ptr. Tested-by: Mark Cave-Ayland Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-Id: <20210717221851.2124573-5-richard.henderson@linaro.org> --- accel/tcg/cpu-exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index d3232d5764..70ea3c7d68 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -150,7 +150,7 @@ uint32_t curr_cflags(CPUState *cpu) uint32_t cflags = cpu->tcg_cflags; if (qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { - cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR; + cflags |= CF_NO_GOTO_TB; } return cflags; From 04f5b647ed07fa9a0c3fcbd439c24d971b60f533 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 17 Jul 2021 15:18:43 -0700 Subject: [PATCH 271/531] accel/tcg: Handle -singlestep in curr_cflags Exchange the test in translator_use_goto_tb for CF_NO_GOTO_TB, and the test in tb_gen_code for setting CF_COUNT_MASK to 1. Tested-by: Mark Cave-Ayland Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-Id: <20210717221851.2124573-6-richard.henderson@linaro.org> --- accel/tcg/cpu-exec.c | 8 +++++++- accel/tcg/translate-all.c | 2 +- accel/tcg/translator.c | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 70ea3c7d68..2206c463f5 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -149,7 +149,13 @@ uint32_t curr_cflags(CPUState *cpu) { uint32_t cflags = cpu->tcg_cflags; - if (qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { + /* + * For singlestep and -d nochain, suppress goto_tb so that + * we can log -d cpu,exec after every TB. + */ + if (singlestep) { + cflags |= CF_NO_GOTO_TB | 1; + } else if (qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { cflags |= CF_NO_GOTO_TB; } diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 5cc01d693b..bf82c15aab 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -1432,7 +1432,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, } QEMU_BUILD_BUG_ON(CF_COUNT_MASK + 1 != TCG_MAX_INSNS); - if (cpu->singlestep_enabled || singlestep) { + if (cpu->singlestep_enabled) { max_insns = 1; } diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 2ea5a74f30..a59eb7c11b 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -39,7 +39,7 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest) } /* Suppress goto_tb in the case of single-steping. */ - if (db->singlestep_enabled || singlestep) { + if (db->singlestep_enabled) { return false; } From 258afb487f33267d8dcbbaee6555b2633f74cc7d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 17 Jul 2021 15:18:44 -0700 Subject: [PATCH 272/531] accel/tcg: Use CF_NO_GOTO_{TB, PTR} in cpu_exec_step_atomic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Request that the one TB returns immediately, so that we release the exclusive lock as soon as possible. Tested-by: Mark Cave-Ayland Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Reviewed-by: Alex Bennée Message-Id: <20210717221851.2124573-7-richard.henderson@linaro.org> --- accel/tcg/cpu-exec.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 2206c463f5..5bb099174f 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -330,8 +330,7 @@ void cpu_exec_step_atomic(CPUState *cpu) CPUArchState *env = (CPUArchState *)cpu->env_ptr; TranslationBlock *tb; target_ulong cs_base, pc; - uint32_t flags; - uint32_t cflags = (curr_cflags(cpu) & ~CF_PARALLEL) | 1; + uint32_t flags, cflags; int tb_exit; if (sigsetjmp(cpu->jmp_env, 0) == 0) { @@ -341,8 +340,14 @@ void cpu_exec_step_atomic(CPUState *cpu) cpu->running = true; cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); - tb = tb_lookup(cpu, pc, cs_base, flags, cflags); + cflags = curr_cflags(cpu); + /* Execute in a serial context. */ + cflags &= ~CF_PARALLEL; + /* After 1 insn, return and release the exclusive lock. */ + cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR | 1; + + tb = tb_lookup(cpu, pc, cs_base, flags, cflags); if (tb == NULL) { mmap_lock(); tb = tb_gen_code(cpu, pc, cs_base, flags, cflags); From e3f7c801f1b21b01066c5293f7659f1054c4d63b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Jul 2021 08:14:30 -1000 Subject: [PATCH 273/531] hw/core: Introduce TCGCPUOps.debug_check_breakpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New hook to return true when an architectural breakpoint is to be recognized and false when it should be suppressed. First use must wait until other pieces are in place. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/hw/core/tcg-cpu-ops.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/hw/core/tcg-cpu-ops.h b/include/hw/core/tcg-cpu-ops.h index 72d791438c..eab27d0c03 100644 --- a/include/hw/core/tcg-cpu-ops.h +++ b/include/hw/core/tcg-cpu-ops.h @@ -88,6 +88,12 @@ struct TCGCPUOps { */ bool (*debug_check_watchpoint)(CPUState *cpu, CPUWatchpoint *wp); + /** + * @debug_check_breakpoint: return true if the architectural + * breakpoint whose PC has matched should really fire. + */ + bool (*debug_check_breakpoint)(CPUState *cpu); + /** * @io_recompile_replay_branch: Callback for cpu_io_recompile. * From b00d86bc8bfe54fd9e4343cfa1f77fbbcbe32d95 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Jul 2021 08:19:26 -1000 Subject: [PATCH 274/531] target/arm: Implement debug_check_breakpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reuse the code at the bottom of helper_check_breakpoints, which is what we currently call from *_tr_breakpoint_check. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/arm/cpu.c | 1 + target/arm/cpu_tcg.c | 1 + target/arm/debug_helper.c | 7 +++---- target/arm/internals.h | 3 +++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 9cddfd6a44..752b15bb79 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1984,6 +1984,7 @@ static const struct TCGCPUOps arm_tcg_ops = { .do_unaligned_access = arm_cpu_do_unaligned_access, .adjust_watchpoint_address = arm_adjust_watchpoint_address, .debug_check_watchpoint = arm_debug_check_watchpoint, + .debug_check_breakpoint = arm_debug_check_breakpoint, #endif /* !CONFIG_USER_ONLY */ }; #endif /* CONFIG_TCG */ diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index d2d97115ea..ed444bf436 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -911,6 +911,7 @@ static const struct TCGCPUOps arm_v7m_tcg_ops = { .do_unaligned_access = arm_cpu_do_unaligned_access, .adjust_watchpoint_address = arm_adjust_watchpoint_address, .debug_check_watchpoint = arm_debug_check_watchpoint, + .debug_check_breakpoint = arm_debug_check_breakpoint, #endif /* !CONFIG_USER_ONLY */ }; #endif /* CONFIG_TCG */ diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index 2ff72d47d1..4a0c479527 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -216,8 +216,9 @@ static bool check_watchpoints(ARMCPU *cpu) return false; } -static bool check_breakpoints(ARMCPU *cpu) +bool arm_debug_check_breakpoint(CPUState *cs) { + ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; int n; @@ -240,9 +241,7 @@ static bool check_breakpoints(ARMCPU *cpu) void HELPER(check_breakpoints)(CPUARMState *env) { - ARMCPU *cpu = env_archcpu(env); - - if (check_breakpoints(cpu)) { + if (arm_debug_check_breakpoint(env_cpu(env))) { HELPER(exception_internal(env, EXCP_DEBUG)); } } diff --git a/target/arm/internals.h b/target/arm/internals.h index 3ba86e8af8..11a72013f5 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -282,6 +282,9 @@ void hw_breakpoint_update(ARMCPU *cpu, int n); */ void hw_breakpoint_update_all(ARMCPU *cpu); +/* Callback function for checking if a breakpoint should trigger. */ +bool arm_debug_check_breakpoint(CPUState *cs); + /* Callback function for checking if a watchpoint should trigger. */ bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp); From 7b9810ea4269fea04c3b95951fb279dc72db4132 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Jul 2021 08:22:47 -1000 Subject: [PATCH 275/531] target/i386: Implement debug_check_breakpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return false for RF set, as we do in i386_tr_breakpoint_check. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- target/i386/tcg/tcg-cpu.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index e96ec9bbcc..238e3a9395 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -54,6 +54,17 @@ static void x86_cpu_synchronize_from_tb(CPUState *cs, cpu->env.eip = tb->pc - tb->cs_base; } +#ifndef CONFIG_USER_ONLY +static bool x86_debug_check_breakpoint(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + /* RF disables all architectural breakpoints. */ + return !(env->eflags & RF_MASK); +} +#endif + #include "hw/core/tcg-cpu-ops.h" static const struct TCGCPUOps x86_tcg_ops = { @@ -66,6 +77,7 @@ static const struct TCGCPUOps x86_tcg_ops = { .tlb_fill = x86_cpu_tlb_fill, #ifndef CONFIG_USER_ONLY .debug_excp_handler = breakpoint_handler, + .debug_check_breakpoint = x86_debug_check_breakpoint, #endif /* !CONFIG_USER_ONLY */ }; From 5bc31e944019e46daeb7dd4d19280e8333aa448d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 20 Jul 2021 05:47:23 -1000 Subject: [PATCH 276/531] hw/core: Introduce CPUClass.gdb_adjust_breakpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow a breakpoint hack to move out of AVR's translator. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- cpu.c | 10 ++++++++++ include/hw/core/cpu.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/cpu.c b/cpu.c index 83059537d7..91d9e38acb 100644 --- a/cpu.c +++ b/cpu.c @@ -267,8 +267,13 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc) int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags, CPUBreakpoint **breakpoint) { + CPUClass *cc = CPU_GET_CLASS(cpu); CPUBreakpoint *bp; + if (cc->gdb_adjust_breakpoint) { + pc = cc->gdb_adjust_breakpoint(cpu, pc); + } + bp = g_malloc(sizeof(*bp)); bp->pc = pc; @@ -294,8 +299,13 @@ int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags, /* Remove a specific breakpoint. */ int cpu_breakpoint_remove(CPUState *cpu, vaddr pc, int flags) { + CPUClass *cc = CPU_GET_CLASS(cpu); CPUBreakpoint *bp; + if (cc->gdb_adjust_breakpoint) { + pc = cc->gdb_adjust_breakpoint(cpu, pc); + } + QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { if (bp->pc == pc && bp->flags == flags) { cpu_breakpoint_remove_by_ref(cpu, bp); diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 4e0ea68efc..bc864564ce 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -103,6 +103,9 @@ struct SysemuCPUOps; * also implement the synchronize_from_tb hook. * @gdb_read_register: Callback for letting GDB read a register. * @gdb_write_register: Callback for letting GDB write a register. + * @gdb_adjust_breakpoint: Callback for adjusting the address of a + * breakpoint. Used by AVR to handle a gdb mis-feature with + * its Harvard architecture split code and data. * @gdb_num_core_regs: Number of core registers accessible to GDB. * @gdb_core_xml_file: File name for core registers GDB XML description. * @gdb_stop_before_watchpoint: Indicates whether GDB expects the CPU to stop @@ -137,6 +140,7 @@ struct CPUClass { void (*set_pc)(CPUState *cpu, vaddr value); int (*gdb_read_register)(CPUState *cpu, GByteArray *buf, int reg); int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg); + vaddr (*gdb_adjust_breakpoint)(CPUState *cpu, vaddr addr); const char *gdb_core_xml_file; gchar * (*gdb_arch_name)(CPUState *cpu); From e64cb6c231e0de00f88d4cd0c4dd3481dacfc0d9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 20 Jul 2021 05:48:46 -1000 Subject: [PATCH 277/531] target/avr: Implement gdb_adjust_breakpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure at registration that all breakpoints are in code space, not data space. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/avr/cpu.c | 1 + target/avr/cpu.h | 1 + target/avr/gdbstub.c | 13 +++++++++++++ target/avr/translate.c | 14 -------------- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 57e3fab4a0..ea14175ca5 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -223,6 +223,7 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) cc->disas_set_info = avr_cpu_disas_set_info; cc->gdb_read_register = avr_cpu_gdb_read_register; cc->gdb_write_register = avr_cpu_gdb_write_register; + cc->gdb_adjust_breakpoint = avr_cpu_gdb_adjust_breakpoint; cc->gdb_num_core_regs = 35; cc->gdb_core_xml_file = "avr-cpu.xml"; cc->tcg_ops = &avr_tcg_ops; diff --git a/target/avr/cpu.h b/target/avr/cpu.h index d148e8c75a..93e3faa0a9 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -162,6 +162,7 @@ hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int avr_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int avr_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); int avr_print_insn(bfd_vma addr, disassemble_info *info); +vaddr avr_cpu_gdb_adjust_breakpoint(CPUState *cpu, vaddr addr); static inline int avr_feature(CPUAVRState *env, AVRFeature feature) { diff --git a/target/avr/gdbstub.c b/target/avr/gdbstub.c index c28ed67efe..1c1b908c92 100644 --- a/target/avr/gdbstub.c +++ b/target/avr/gdbstub.c @@ -82,3 +82,16 @@ int avr_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) return 0; } + +vaddr avr_cpu_gdb_adjust_breakpoint(CPUState *cpu, vaddr addr) +{ + /* + * This is due to some strange GDB behavior + * Let's assume main has address 0x100: + * b main - sets breakpoint at address 0x00000100 (code) + * b *0x100 - sets breakpoint at address 0x00800100 (data) + * + * Force all breakpoints into code space. + */ + return addr % OFFSET_DATA; +} diff --git a/target/avr/translate.c b/target/avr/translate.c index 8237a03c23..f7202a646b 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -2958,20 +2958,6 @@ static void avr_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) DisasContext *ctx = container_of(dcbase, DisasContext, base); TCGLabel *skip_label = NULL; - /* - * This is due to some strange GDB behavior - * Let's assume main has address 0x100: - * b main - sets breakpoint at address 0x00000100 (code) - * b *0x100 - sets breakpoint at address 0x00800100 (data) - * - * The translator driver has already taken care of the code pointer. - */ - if (!ctx->base.singlestep_enabled && - cpu_breakpoint_test(cs, OFFSET_DATA + ctx->base.pc_next, BP_ANY)) { - gen_breakpoint(ctx); - return; - } - /* Conditionally skip the next instruction, if indicated. */ if (ctx->skip_cond != TCG_COND_NEVER) { skip_label = gen_new_label(); From 11c1d5f8ca7a72818b3c24093a2c40856022fe0f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Jul 2021 12:40:57 -1000 Subject: [PATCH 278/531] accel/tcg: Merge tb_find into its only caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are going to want two things: (1) check for breakpoints will want to break out of the loop here, (2) cflags can only be calculated with pc in hand. Tested-by: Mark Cave-Ayland Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 83 ++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 5bb099174f..cde7069eb7 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -500,41 +500,6 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, return; } -static inline TranslationBlock *tb_find(CPUState *cpu, - TranslationBlock *last_tb, - int tb_exit, uint32_t cflags) -{ - CPUArchState *env = (CPUArchState *)cpu->env_ptr; - TranslationBlock *tb; - target_ulong cs_base, pc; - uint32_t flags; - - cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); - - tb = tb_lookup(cpu, pc, cs_base, flags, cflags); - if (tb == NULL) { - mmap_lock(); - tb = tb_gen_code(cpu, pc, cs_base, flags, cflags); - mmap_unlock(); - /* We add the TB in the virtual pc hash table for the fast lookup */ - qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb); - } -#ifndef CONFIG_USER_ONLY - /* We don't take care of direct jumps when address mapping changes in - * system emulation. So it's not safe to make a direct jump to a TB - * spanning two pages because the mapping for the second page can change. - */ - if (tb->page_addr[1] != -1) { - last_tb = NULL; - } -#endif - /* See if we can patch the calling TB. */ - if (last_tb) { - tb_add_jump(last_tb, tb_exit, tb); - } - return tb; -} - static inline bool cpu_handle_halt(CPUState *cpu) { if (cpu->halted) { @@ -868,22 +833,56 @@ int cpu_exec(CPUState *cpu) int tb_exit = 0; while (!cpu_handle_interrupt(cpu, &last_tb)) { - uint32_t cflags = cpu->cflags_next_tb; TranslationBlock *tb; + target_ulong cs_base, pc; + uint32_t flags, cflags; - /* When requested, use an exact setting for cflags for the next - execution. This is used for icount, precise smc, and stop- - after-access watchpoints. Since this request should never - have CF_INVALID set, -1 is a convenient invalid value that - does not require tcg headers for cpu_common_reset. */ + /* + * When requested, use an exact setting for cflags for the next + * execution. This is used for icount, precise smc, and stop- + * after-access watchpoints. Since this request should never + * have CF_INVALID set, -1 is a convenient invalid value that + * does not require tcg headers for cpu_common_reset. + */ + cflags = cpu->cflags_next_tb; if (cflags == -1) { cflags = curr_cflags(cpu); } else { cpu->cflags_next_tb = -1; } - tb = tb_find(cpu, last_tb, tb_exit, cflags); + cpu_get_tb_cpu_state(cpu->env_ptr, &pc, &cs_base, &flags); + + tb = tb_lookup(cpu, pc, cs_base, flags, cflags); + if (tb == NULL) { + mmap_lock(); + tb = tb_gen_code(cpu, pc, cs_base, flags, cflags); + mmap_unlock(); + /* + * We add the TB in the virtual pc hash table + * for the fast lookup + */ + qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb); + } + +#ifndef CONFIG_USER_ONLY + /* + * We don't take care of direct jumps when address mapping + * changes in system emulation. So it's not safe to make a + * direct jump to a TB spanning two pages because the mapping + * for the second page can change. + */ + if (tb->page_addr[1] != -1) { + last_tb = NULL; + } +#endif + /* See if we can patch the calling TB. */ + if (last_tb) { + tb_add_jump(last_tb, tb_exit, tb); + } + cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit); + /* Try to align the host and virtual clocks if the guest is in advance */ align_clocks(&sc, cpu); From 10c37828b213cd490bd20e243916e96f5d588c8d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Jul 2021 09:03:21 -1000 Subject: [PATCH 279/531] accel/tcg: Move breakpoint recognition outside translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trigger breakpoints before beginning translation of a TB that would begin with a BP. Thus we never generate code for the BP at all. Single-step instructions within a page containing a BP so that we are sure to check each insn for the BP as above. We no longer need to flush any TBs when changing BPs. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/286 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/404 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/489 Tested-by: Mark Cave-Ayland Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 91 ++++++++++++++++++++++++++++++++++++++++-- accel/tcg/translator.c | 24 +---------- cpu.c | 20 ---------- 3 files changed, 89 insertions(+), 46 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index cde7069eb7..5cc6363f4c 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -222,6 +222,76 @@ static inline void log_cpu_exec(target_ulong pc, CPUState *cpu, } } +static bool check_for_breakpoints(CPUState *cpu, target_ulong pc, + uint32_t *cflags) +{ + CPUBreakpoint *bp; + bool match_page = false; + + if (likely(QTAILQ_EMPTY(&cpu->breakpoints))) { + return false; + } + + /* + * Singlestep overrides breakpoints. + * This requirement is visible in the record-replay tests, where + * we would fail to make forward progress in reverse-continue. + * + * TODO: gdb singlestep should only override gdb breakpoints, + * so that one could (gdb) singlestep into the guest kernel's + * architectural breakpoint handler. + */ + if (cpu->singlestep_enabled) { + return false; + } + + QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { + /* + * If we have an exact pc match, trigger the breakpoint. + * Otherwise, note matches within the page. + */ + if (pc == bp->pc) { + bool match_bp = false; + + if (bp->flags & BP_GDB) { + match_bp = true; + } else if (bp->flags & BP_CPU) { +#ifdef CONFIG_USER_ONLY + g_assert_not_reached(); +#else + CPUClass *cc = CPU_GET_CLASS(cpu); + assert(cc->tcg_ops->debug_check_breakpoint); + match_bp = cc->tcg_ops->debug_check_breakpoint(cpu); +#endif + } + + if (match_bp) { + cpu->exception_index = EXCP_DEBUG; + return true; + } + } else if (((pc ^ bp->pc) & TARGET_PAGE_MASK) == 0) { + match_page = true; + } + } + + /* + * Within the same page as a breakpoint, single-step, + * returning to helper_lookup_tb_ptr after each insn looking + * for the actual breakpoint. + * + * TODO: Perhaps better to record all of the TBs associated + * with a given virtual page that contains a breakpoint, and + * then invalidate them when a new overlapping breakpoint is + * set on the page. Non-overlapping TBs would not be + * invalidated, nor would any TB need to be invalidated as + * breakpoints are removed. + */ + if (match_page) { + *cflags = (*cflags & ~CF_COUNT_MASK) | CF_NO_GOTO_TB | 1; + } + return false; +} + /** * helper_lookup_tb_ptr: quick check for next tb * @env: current cpu state @@ -235,11 +305,16 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env) CPUState *cpu = env_cpu(env); TranslationBlock *tb; target_ulong cs_base, pc; - uint32_t flags; + uint32_t flags, cflags; cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); - tb = tb_lookup(cpu, pc, cs_base, flags, curr_cflags(cpu)); + cflags = curr_cflags(cpu); + if (check_for_breakpoints(cpu, pc, &cflags)) { + cpu_loop_exit(cpu); + } + + tb = tb_lookup(cpu, pc, cs_base, flags, cflags); if (tb == NULL) { return tcg_code_gen_epilogue; } @@ -346,6 +421,12 @@ void cpu_exec_step_atomic(CPUState *cpu) cflags &= ~CF_PARALLEL; /* After 1 insn, return and release the exclusive lock. */ cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR | 1; + /* + * No need to check_for_breakpoints here. + * We only arrive in cpu_exec_step_atomic after beginning execution + * of an insn that includes an atomic operation we can't handle. + * Any breakpoint for this insn will have been recognized earlier. + */ tb = tb_lookup(cpu, pc, cs_base, flags, cflags); if (tb == NULL) { @@ -837,6 +918,8 @@ int cpu_exec(CPUState *cpu) target_ulong cs_base, pc; uint32_t flags, cflags; + cpu_get_tb_cpu_state(cpu->env_ptr, &pc, &cs_base, &flags); + /* * When requested, use an exact setting for cflags for the next * execution. This is used for icount, precise smc, and stop- @@ -851,7 +934,9 @@ int cpu_exec(CPUState *cpu) cpu->cflags_next_tb = -1; } - cpu_get_tb_cpu_state(cpu->env_ptr, &pc, &cs_base, &flags); + if (check_for_breakpoints(cpu, pc, &cflags)) { + break; + } tb = tb_lookup(cpu, pc, cs_base, flags, cflags); if (tb == NULL) { diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index a59eb7c11b..4f3728c278 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -50,7 +50,6 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest) void translator_loop(const TranslatorOps *ops, DisasContextBase *db, CPUState *cpu, TranslationBlock *tb, int max_insns) { - int bp_insn = 0; bool plugin_enabled; /* Initialize DisasContext */ @@ -85,27 +84,6 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db, plugin_gen_insn_start(cpu, db); } - /* Pass breakpoint hits to target for further processing */ - if (!db->singlestep_enabled - && unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) { - CPUBreakpoint *bp; - QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { - if (bp->pc == db->pc_next) { - if (ops->breakpoint_check(db, cpu, bp)) { - bp_insn = 1; - break; - } - } - } - /* The breakpoint_check hook may use DISAS_TOO_MANY to indicate - that only one more instruction is to be executed. Otherwise - it should use DISAS_NORETURN when generating an exception, - but may use a DISAS_TARGET_* value for Something Else. */ - if (db->is_jmp > DISAS_TOO_MANY) { - break; - } - } - /* Disassemble one instruction. The translate_insn hook should update db->pc_next and db->is_jmp to indicate what should be done next -- either exiting this loop or locate the start of @@ -144,7 +122,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db, /* Emit code to exit the TB, as indicated by db->is_jmp. */ ops->tb_stop(db, cpu); - gen_tb_end(db->tb, db->num_insns - bp_insn); + gen_tb_end(db->tb, db->num_insns); if (plugin_enabled) { plugin_gen_tb_end(cpu); diff --git a/cpu.c b/cpu.c index 91d9e38acb..d6ae5ae581 100644 --- a/cpu.c +++ b/cpu.c @@ -225,11 +225,6 @@ void tb_invalidate_phys_addr(target_ulong addr) tb_invalidate_phys_page_range(addr, addr + 1); mmap_unlock(); } - -static void breakpoint_invalidate(CPUState *cpu, target_ulong pc) -{ - tb_invalidate_phys_addr(pc); -} #else void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs) { @@ -250,17 +245,6 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs) ram_addr = memory_region_get_ram_addr(mr) + addr; tb_invalidate_phys_page_range(ram_addr, ram_addr + 1); } - -static void breakpoint_invalidate(CPUState *cpu, target_ulong pc) -{ - /* - * There may not be a virtual to physical translation for the pc - * right now, but there may exist cached TB for this pc. - * Flush the whole TB cache to force re-translation of such TBs. - * This is heavyweight, but we're debugging anyway. - */ - tb_flush(cpu); -} #endif /* Add a breakpoint. */ @@ -286,8 +270,6 @@ int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags, QTAILQ_INSERT_TAIL(&cpu->breakpoints, bp, entry); } - breakpoint_invalidate(cpu, pc); - if (breakpoint) { *breakpoint = bp; } @@ -320,8 +302,6 @@ void cpu_breakpoint_remove_by_ref(CPUState *cpu, CPUBreakpoint *bp) { QTAILQ_REMOVE(&cpu->breakpoints, bp, entry); - breakpoint_invalidate(cpu, bp->pc); - trace_breakpoint_remove(cpu->cpu_index, bp->pc, bp->flags); g_free(bp); } From b5cf74284166c1ecd119388c31b6eca8e1d7b4a6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Jul 2021 09:39:49 -1000 Subject: [PATCH 280/531] accel/tcg: Remove TranslatorOps.breakpoint_check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hook is now unused, with breakpoints checked outside translation. Tested-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- include/exec/translator.h | 11 ----------- target/alpha/translate.c | 16 ---------------- target/arm/debug_helper.c | 7 ------- target/arm/helper.h | 2 -- target/arm/translate-a64.c | 25 ------------------------- target/arm/translate.c | 29 ----------------------------- target/avr/translate.c | 18 ------------------ target/cris/translate.c | 20 -------------------- target/hexagon/translate.c | 17 ----------------- target/hppa/translate.c | 11 ----------- target/i386/tcg/translate.c | 28 ---------------------------- target/m68k/translate.c | 18 ------------------ target/microblaze/translate.c | 18 ------------------ target/mips/tcg/translate.c | 19 ------------------- target/nios2/translate.c | 27 --------------------------- target/openrisc/translate.c | 17 ----------------- target/ppc/translate.c | 18 ------------------ target/riscv/translate.c | 17 ----------------- target/rx/translate.c | 14 -------------- target/s390x/tcg/translate.c | 24 ------------------------ target/sh4/translate.c | 18 ------------------ target/sparc/translate.c | 17 ----------------- target/tricore/translate.c | 16 ---------------- target/xtensa/translate.c | 17 ----------------- 24 files changed, 424 deletions(-) diff --git a/include/exec/translator.h b/include/exec/translator.h index dd9c06d40d..d318803267 100644 --- a/include/exec/translator.h +++ b/include/exec/translator.h @@ -89,15 +89,6 @@ typedef struct DisasContextBase { * @insn_start: * Emit the tcg_gen_insn_start opcode. * - * @breakpoint_check: - * When called, the breakpoint has already been checked to match the PC, - * but the target may decide the breakpoint missed the address - * (e.g., due to conditions encoded in their flags). Return true to - * indicate that the breakpoint did hit, in which case no more breakpoints - * are checked. If the breakpoint did hit, emit any code required to - * signal the exception, and set db->is_jmp as necessary to terminate - * the main loop. - * * @translate_insn: * Disassemble one instruction and set db->pc_next for the start * of the following instruction. Set db->is_jmp as necessary to @@ -113,8 +104,6 @@ typedef struct TranslatorOps { void (*init_disas_context)(DisasContextBase *db, CPUState *cpu); void (*tb_start)(DisasContextBase *db, CPUState *cpu); void (*insn_start)(DisasContextBase *db, CPUState *cpu); - bool (*breakpoint_check)(DisasContextBase *db, CPUState *cpu, - const CPUBreakpoint *bp); void (*translate_insn)(DisasContextBase *db, CPUState *cpu); void (*tb_stop)(DisasContextBase *db, CPUState *cpu); void (*disas_log)(const DisasContextBase *db, CPUState *cpu); diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 949ba6ffde..de6c0a8439 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -2967,21 +2967,6 @@ static void alpha_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) tcg_gen_insn_start(dcbase->pc_next); } -static bool alpha_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, - const CPUBreakpoint *bp) -{ - DisasContext *ctx = container_of(dcbase, DisasContext, base); - - ctx->base.is_jmp = gen_excp(ctx, EXCP_DEBUG, 0); - - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size below does the right thing. */ - ctx->base.pc_next += 4; - return true; -} - static void alpha_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *ctx = container_of(dcbase, DisasContext, base); @@ -3040,7 +3025,6 @@ static const TranslatorOps alpha_tr_ops = { .init_disas_context = alpha_tr_init_disas_context, .tb_start = alpha_tr_tb_start, .insn_start = alpha_tr_insn_start, - .breakpoint_check = alpha_tr_breakpoint_check, .translate_insn = alpha_tr_translate_insn, .tb_stop = alpha_tr_tb_stop, .disas_log = alpha_tr_disas_log, diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index 4a0c479527..2983e36dd3 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -239,13 +239,6 @@ bool arm_debug_check_breakpoint(CPUState *cs) return false; } -void HELPER(check_breakpoints)(CPUARMState *env) -{ - if (arm_debug_check_breakpoint(env_cpu(env))) { - HELPER(exception_internal(env, EXCP_DEBUG)); - } -} - bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) { /* diff --git a/target/arm/helper.h b/target/arm/helper.h index db87d7d537..248569b0cd 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -54,8 +54,6 @@ DEF_HELPER_1(yield, void, env) DEF_HELPER_1(pre_hvc, void, env) DEF_HELPER_2(pre_smc, void, env, i32) -DEF_HELPER_1(check_breakpoints, void, env) - DEF_HELPER_3(cpsr_write, void, env, i32, i32) DEF_HELPER_2(cpsr_write_eret, void, env, i32) DEF_HELPER_1(cpsr_read, i32, env) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index ca11a5fecd..422e2ac0c9 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -14844,30 +14844,6 @@ static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) dc->insn_start = tcg_last_op(); } -static bool aarch64_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, - const CPUBreakpoint *bp) -{ - DisasContext *dc = container_of(dcbase, DisasContext, base); - - if (bp->flags & BP_CPU) { - gen_a64_set_pc_im(dc->base.pc_next); - gen_helper_check_breakpoints(cpu_env); - /* End the TB early; it likely won't be executed */ - dc->base.is_jmp = DISAS_TOO_MANY; - } else { - gen_exception_internal_insn(dc, dc->base.pc_next, EXCP_DEBUG); - /* The address covered by the breakpoint must be - included in [tb->pc, tb->pc + tb->size) in order - to for it to be properly cleared -- thus we - increment the PC here so that the logic setting - tb->size below does the right thing. */ - dc->base.pc_next += 4; - dc->base.is_jmp = DISAS_NORETURN; - } - - return true; -} - static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); @@ -14982,7 +14958,6 @@ const TranslatorOps aarch64_translator_ops = { .init_disas_context = aarch64_tr_init_disas_context, .tb_start = aarch64_tr_tb_start, .insn_start = aarch64_tr_insn_start, - .breakpoint_check = aarch64_tr_breakpoint_check, .translate_insn = aarch64_tr_translate_insn, .tb_stop = aarch64_tr_tb_stop, .disas_log = aarch64_tr_disas_log, diff --git a/target/arm/translate.c b/target/arm/translate.c index e1a8152598..351afa43a2 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -9438,33 +9438,6 @@ static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) dc->insn_start = tcg_last_op(); } -static bool arm_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, - const CPUBreakpoint *bp) -{ - DisasContext *dc = container_of(dcbase, DisasContext, base); - - if (bp->flags & BP_CPU) { - gen_set_condexec(dc); - gen_set_pc_im(dc, dc->base.pc_next); - gen_helper_check_breakpoints(cpu_env); - /* End the TB early; it's likely not going to be executed */ - dc->base.is_jmp = DISAS_TOO_MANY; - } else { - gen_exception_internal_insn(dc, dc->base.pc_next, EXCP_DEBUG); - /* The address covered by the breakpoint must be - included in [tb->pc, tb->pc + tb->size) in order - to for it to be properly cleared -- thus we - increment the PC here so that the logic setting - tb->size below does the right thing. */ - /* TODO: Advance PC by correct instruction length to - * avoid disassembler error messages */ - dc->base.pc_next += 2; - dc->base.is_jmp = DISAS_NORETURN; - } - - return true; -} - static bool arm_pre_translate_insn(DisasContext *dc) { #ifdef CONFIG_USER_ONLY @@ -9827,7 +9800,6 @@ static const TranslatorOps arm_translator_ops = { .init_disas_context = arm_tr_init_disas_context, .tb_start = arm_tr_tb_start, .insn_start = arm_tr_insn_start, - .breakpoint_check = arm_tr_breakpoint_check, .translate_insn = arm_tr_translate_insn, .tb_stop = arm_tr_tb_stop, .disas_log = arm_tr_disas_log, @@ -9837,7 +9809,6 @@ static const TranslatorOps thumb_translator_ops = { .init_disas_context = arm_tr_init_disas_context, .tb_start = arm_tr_tb_start, .insn_start = arm_tr_insn_start, - .breakpoint_check = arm_tr_breakpoint_check, .translate_insn = thumb_tr_translate_insn, .tb_stop = arm_tr_tb_stop, .disas_log = arm_tr_disas_log, diff --git a/target/avr/translate.c b/target/avr/translate.c index f7202a646b..1111e08b83 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -2900,14 +2900,6 @@ static bool canonicalize_skip(DisasContext *ctx) return true; } -static void gen_breakpoint(DisasContext *ctx) -{ - canonicalize_skip(ctx); - tcg_gen_movi_tl(cpu_pc, ctx->npc); - gen_helper_debug(cpu_env); - ctx->base.is_jmp = DISAS_NORETURN; -} - static void avr_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); @@ -2944,15 +2936,6 @@ static void avr_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) tcg_gen_insn_start(ctx->npc); } -static bool avr_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, - const CPUBreakpoint *bp) -{ - DisasContext *ctx = container_of(dcbase, DisasContext, base); - - gen_breakpoint(ctx); - return true; -} - static void avr_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); @@ -3055,7 +3038,6 @@ static const TranslatorOps avr_tr_ops = { .init_disas_context = avr_tr_init_disas_context, .tb_start = avr_tr_tb_start, .insn_start = avr_tr_insn_start, - .breakpoint_check = avr_tr_breakpoint_check, .translate_insn = avr_tr_translate_insn, .tb_stop = avr_tr_tb_stop, .disas_log = avr_tr_disas_log, diff --git a/target/cris/translate.c b/target/cris/translate.c index 9258c13e9f..a84b753349 100644 --- a/target/cris/translate.c +++ b/target/cris/translate.c @@ -3118,25 +3118,6 @@ static void cris_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) tcg_gen_insn_start(dc->delayed_branch == 1 ? dc->ppc | 1 : dc->pc); } -static bool cris_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, - const CPUBreakpoint *bp) -{ - DisasContext *dc = container_of(dcbase, DisasContext, base); - - cris_evaluate_flags(dc); - tcg_gen_movi_tl(env_pc, dc->pc); - t_gen_raise_exception(EXCP_DEBUG); - dc->base.is_jmp = DISAS_NORETURN; - /* - * The address covered by the breakpoint must be included in - * [tb->pc, tb->pc + tb->size) in order to for it to be - * properly cleared -- thus we increment the PC here so that - * the logic setting tb->size below does the right thing. - */ - dc->pc += 2; - return true; -} - static void cris_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *dc = container_of(dcbase, DisasContext, base); @@ -3315,7 +3296,6 @@ static const TranslatorOps cris_tr_ops = { .init_disas_context = cris_tr_init_disas_context, .tb_start = cris_tr_tb_start, .insn_start = cris_tr_insn_start, - .breakpoint_check = cris_tr_breakpoint_check, .translate_insn = cris_tr_translate_insn, .tb_stop = cris_tr_tb_stop, .disas_log = cris_tr_disas_log, diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index b23d36adf5..54fdcaa5e8 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -540,22 +540,6 @@ static void hexagon_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) tcg_gen_insn_start(ctx->base.pc_next); } -static bool hexagon_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, - const CPUBreakpoint *bp) -{ - DisasContext *ctx = container_of(dcbase, DisasContext, base); - - gen_exception_end_tb(ctx, EXCP_DEBUG); - /* - * The address covered by the breakpoint must be included in - * [tb->pc, tb->pc + tb->size) in order to for it to be - * properly cleared -- thus we increment the PC here so that - * the logic setting tb->size below does the right thing. - */ - ctx->base.pc_next += 4; - return true; -} - static bool pkt_crosses_page(CPUHexagonState *env, DisasContext *ctx) { target_ulong page_start = ctx->base.pc_first & TARGET_PAGE_MASK; @@ -631,7 +615,6 @@ static const TranslatorOps hexagon_tr_ops = { .init_disas_context = hexagon_tr_init_disas_context, .tb_start = hexagon_tr_tb_start, .insn_start = hexagon_tr_insn_start, - .breakpoint_check = hexagon_tr_breakpoint_check, .translate_insn = hexagon_tr_translate_packet, .tb_stop = hexagon_tr_tb_stop, .disas_log = hexagon_tr_disas_log, diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 2552747138..b18150ef8d 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -4159,16 +4159,6 @@ static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b); } -static bool hppa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, - const CPUBreakpoint *bp) -{ - DisasContext *ctx = container_of(dcbase, DisasContext, base); - - gen_excp(ctx, EXCP_DEBUG); - ctx->base.pc_next += 4; - return true; -} - static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); @@ -4330,7 +4320,6 @@ static const TranslatorOps hppa_tr_ops = { .init_disas_context = hppa_tr_init_disas_context, .tb_start = hppa_tr_tb_start, .insn_start = hppa_tr_insn_start, - .breakpoint_check = hppa_tr_breakpoint_check, .translate_insn = hppa_tr_translate_insn, .tb_stop = hppa_tr_tb_stop, .disas_log = hppa_tr_disas_log, diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 8520d5a1e2..aacb605eee 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -2604,14 +2604,6 @@ static void gen_interrupt(DisasContext *s, int intno, s->base.is_jmp = DISAS_NORETURN; } -static void gen_debug(DisasContext *s) -{ - gen_update_cc_op(s); - gen_jmp_im(s, s->base.pc_next - s->cs_base); - gen_helper_debug(cpu_env); - s->base.is_jmp = DISAS_NORETURN; -} - static void gen_set_hflag(DisasContext *s, uint32_t mask) { if ((s->flags & mask) == 0) { @@ -8635,25 +8627,6 @@ static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) tcg_gen_insn_start(dc->base.pc_next, dc->cc_op); } -static bool i386_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, - const CPUBreakpoint *bp) -{ - DisasContext *dc = container_of(dcbase, DisasContext, base); - /* If RF is set, suppress an internally generated breakpoint. */ - int flags = dc->base.tb->flags & HF_RF_MASK ? BP_GDB : BP_ANY; - if (bp->flags & flags) { - gen_debug(dc); - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the generic logic setting tb->size later does the right thing. */ - dc->base.pc_next += 1; - return true; - } else { - return false; - } -} - static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); @@ -8721,7 +8694,6 @@ static const TranslatorOps i386_tr_ops = { .init_disas_context = i386_tr_init_disas_context, .tb_start = i386_tr_tb_start, .insn_start = i386_tr_insn_start, - .breakpoint_check = i386_tr_breakpoint_check, .translate_insn = i386_tr_translate_insn, .tb_stop = i386_tr_tb_stop, .disas_log = i386_tr_disas_log, diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 1fee04b8dd..c34d9aed61 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -6208,23 +6208,6 @@ static void m68k_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) tcg_gen_insn_start(dc->base.pc_next, dc->cc_op); } -static bool m68k_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, - const CPUBreakpoint *bp) -{ - DisasContext *dc = container_of(dcbase, DisasContext, base); - - gen_exception(dc, dc->base.pc_next, EXCP_DEBUG); - /* - * The address covered by the breakpoint must be included in - * [tb->pc, tb->pc + tb->size) in order to for it to be - * properly cleared -- thus we increment the PC here so that - * the logic setting tb->size below does the right thing. - */ - dc->base.pc_next += 2; - - return true; -} - static void m68k_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); @@ -6310,7 +6293,6 @@ static const TranslatorOps m68k_tr_ops = { .init_disas_context = m68k_tr_init_disas_context, .tb_start = m68k_tr_tb_start, .insn_start = m68k_tr_insn_start, - .breakpoint_check = m68k_tr_breakpoint_check, .translate_insn = m68k_tr_translate_insn, .tb_stop = m68k_tr_tb_stop, .disas_log = m68k_tr_disas_log, diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index c68a84a219..a14ffed784 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1673,23 +1673,6 @@ static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) dc->insn_start = tcg_last_op(); } -static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs, - const CPUBreakpoint *bp) -{ - DisasContext *dc = container_of(dcb, DisasContext, base); - - gen_raise_exception_sync(dc, EXCP_DEBUG); - - /* - * The address covered by the breakpoint must be included in - * [tb->pc, tb->pc + tb->size) in order to for it to be - * properly cleared -- thus we increment the PC here so that - * the logic setting tb->size below does the right thing. - */ - dc->base.pc_next += 4; - return true; -} - static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) { DisasContext *dc = container_of(dcb, DisasContext, base); @@ -1854,7 +1837,6 @@ static const TranslatorOps mb_tr_ops = { .init_disas_context = mb_tr_init_disas_context, .tb_start = mb_tr_tb_start, .insn_start = mb_tr_insn_start, - .breakpoint_check = mb_tr_breakpoint_check, .translate_insn = mb_tr_translate_insn, .tb_stop = mb_tr_tb_stop, .disas_log = mb_tr_disas_log, diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index fd980ea966..5b03545f09 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -16178,24 +16178,6 @@ static void mips_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) ctx->btarget); } -static bool mips_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, - const CPUBreakpoint *bp) -{ - DisasContext *ctx = container_of(dcbase, DisasContext, base); - - save_cpu_state(ctx, 1); - ctx->base.is_jmp = DISAS_NORETURN; - gen_helper_raise_exception_debug(cpu_env); - /* - * The address covered by the breakpoint must be included in - * [tb->pc, tb->pc + tb->size) in order to for it to be - * properly cleared -- thus we increment the PC here so that - * the logic setting tb->size below does the right thing. - */ - ctx->base.pc_next += 4; - return true; -} - static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { CPUMIPSState *env = cs->env_ptr; @@ -16303,7 +16285,6 @@ static const TranslatorOps mips_tr_ops = { .init_disas_context = mips_tr_init_disas_context, .tb_start = mips_tr_tb_start, .insn_start = mips_tr_insn_start, - .breakpoint_check = mips_tr_breakpoint_check, .translate_insn = mips_tr_translate_insn, .tb_stop = mips_tr_tb_stop, .disas_log = mips_tr_disas_log, diff --git a/target/nios2/translate.c b/target/nios2/translate.c index 17742cebc7..08d7ac5398 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -744,16 +744,6 @@ static const char * const regnames[] = { #include "exec/gen-icount.h" -static void gen_exception(DisasContext *dc, uint32_t excp) -{ - TCGv_i32 tmp = tcg_const_i32(excp); - - tcg_gen_movi_tl(cpu_R[R_PC], dc->pc); - gen_helper_raise_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); - dc->base.is_jmp = DISAS_NORETURN; -} - /* generate intermediate code for basic block 'tb'. */ static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { @@ -777,22 +767,6 @@ static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) tcg_gen_insn_start(dcbase->pc_next); } -static bool nios2_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, - const CPUBreakpoint *bp) -{ - DisasContext *dc = container_of(dcbase, DisasContext, base); - - gen_exception(dc, EXCP_DEBUG); - /* - * The address covered by the breakpoint must be included in - * [tb->pc, tb->pc + tb->size) in order to for it to be - * properly cleared -- thus we increment the PC here so that - * the logic setting tb->size below does the right thing. - */ - dc->base.pc_next += 4; - return true; -} - static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *dc = container_of(dcbase, DisasContext, base); @@ -870,7 +844,6 @@ static const TranslatorOps nios2_tr_ops = { .init_disas_context = nios2_tr_init_disas_context, .tb_start = nios2_tr_tb_start, .insn_start = nios2_tr_insn_start, - .breakpoint_check = nios2_tr_breakpoint_check, .translate_insn = nios2_tr_translate_insn, .tb_stop = nios2_tr_tb_stop, .disas_log = nios2_tr_disas_log, diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 059da48475..d6ea536744 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -1609,22 +1609,6 @@ static void openrisc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) | (dc->base.num_insns > 1 ? 2 : 0)); } -static bool openrisc_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, - const CPUBreakpoint *bp) -{ - DisasContext *dc = container_of(dcbase, DisasContext, base); - - tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); - gen_exception(dc, EXCP_DEBUG); - dc->base.is_jmp = DISAS_NORETURN; - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size below does the right thing. */ - dc->base.pc_next += 4; - return true; -} - static void openrisc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *dc = container_of(dcbase, DisasContext, base); @@ -1727,7 +1711,6 @@ static const TranslatorOps openrisc_tr_ops = { .init_disas_context = openrisc_tr_init_disas_context, .tb_start = openrisc_tr_tb_start, .insn_start = openrisc_tr_insn_start, - .breakpoint_check = openrisc_tr_breakpoint_check, .translate_insn = openrisc_tr_translate_insn, .tb_stop = openrisc_tr_tb_stop, .disas_log = openrisc_tr_disas_log, diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 0a55cb7181..171b216e17 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -8565,23 +8565,6 @@ static void ppc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) tcg_gen_insn_start(dcbase->pc_next); } -static bool ppc_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, - const CPUBreakpoint *bp) -{ - DisasContext *ctx = container_of(dcbase, DisasContext, base); - - gen_update_nip(ctx, ctx->base.pc_next); - gen_debug_exception(ctx); - /* - * The address covered by the breakpoint must be included in - * [tb->pc, tb->pc + tb->size) in order to for it to be properly - * cleared -- thus we increment the PC here so that the logic - * setting tb->size below does the right thing. - */ - ctx->base.pc_next += 4; - return true; -} - static bool is_prefix_insn(DisasContext *ctx, uint32_t insn) { REQUIRE_INSNS_FLAGS2(ctx, ISA310); @@ -8710,7 +8693,6 @@ static const TranslatorOps ppc_tr_ops = { .init_disas_context = ppc_tr_init_disas_context, .tb_start = ppc_tr_tb_start, .insn_start = ppc_tr_insn_start, - .breakpoint_check = ppc_tr_breakpoint_check, .translate_insn = ppc_tr_translate_insn, .tb_stop = ppc_tr_tb_stop, .disas_log = ppc_tr_disas_log, diff --git a/target/riscv/translate.c b/target/riscv/translate.c index deda0c8a44..6983be5723 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -961,22 +961,6 @@ static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) tcg_gen_insn_start(ctx->base.pc_next); } -static bool riscv_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, - const CPUBreakpoint *bp) -{ - DisasContext *ctx = container_of(dcbase, DisasContext, base); - - tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); - ctx->base.is_jmp = DISAS_NORETURN; - gen_exception_debug(); - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size below does the right thing. */ - ctx->base.pc_next += 4; - return true; -} - static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *ctx = container_of(dcbase, DisasContext, base); @@ -1029,7 +1013,6 @@ static const TranslatorOps riscv_tr_ops = { .init_disas_context = riscv_tr_init_disas_context, .tb_start = riscv_tr_tb_start, .insn_start = riscv_tr_insn_start, - .breakpoint_check = riscv_tr_breakpoint_check, .translate_insn = riscv_tr_translate_insn, .tb_stop = riscv_tr_tb_stop, .disas_log = riscv_tr_disas_log, diff --git a/target/rx/translate.c b/target/rx/translate.c index 23a626438a..a3cf720455 100644 --- a/target/rx/translate.c +++ b/target/rx/translate.c @@ -2309,19 +2309,6 @@ static void rx_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) tcg_gen_insn_start(ctx->base.pc_next); } -static bool rx_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, - const CPUBreakpoint *bp) -{ - DisasContext *ctx = container_of(dcbase, DisasContext, base); - - /* We have hit a breakpoint - make sure PC is up-to-date */ - tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next); - gen_helper_debug(cpu_env); - ctx->base.is_jmp = DISAS_NORETURN; - ctx->base.pc_next += 1; - return true; -} - static void rx_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); @@ -2373,7 +2360,6 @@ static const TranslatorOps rx_tr_ops = { .init_disas_context = rx_tr_init_disas_context, .tb_start = rx_tr_tb_start, .insn_start = rx_tr_insn_start, - .breakpoint_check = rx_tr_breakpoint_check, .translate_insn = rx_tr_translate_insn, .tb_stop = rx_tr_tb_stop, .disas_log = rx_tr_disas_log, diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 92fa7656c2..0632b0374b 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -6552,29 +6552,6 @@ static void s390x_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) { } -static bool s390x_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, - const CPUBreakpoint *bp) -{ - DisasContext *dc = container_of(dcbase, DisasContext, base); - - /* - * Emit an insn_start to accompany the breakpoint exception. - * The ILEN value is a dummy, since this does not result in - * an s390x exception, but an internal qemu exception which - * brings us back to interact with the gdbstub. - */ - tcg_gen_insn_start(dc->base.pc_next, dc->cc_op, 2); - - dc->base.is_jmp = DISAS_PC_STALE; - dc->do_debug = true; - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size does the right thing. */ - dc->base.pc_next += 2; - return true; -} - static void s390x_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { CPUS390XState *env = cs->env_ptr; @@ -6642,7 +6619,6 @@ static const TranslatorOps s390x_tr_ops = { .init_disas_context = s390x_tr_init_disas_context, .tb_start = s390x_tr_tb_start, .insn_start = s390x_tr_insn_start, - .breakpoint_check = s390x_tr_breakpoint_check, .translate_insn = s390x_tr_translate_insn, .tb_stop = s390x_tr_tb_stop, .disas_log = s390x_tr_disas_log, diff --git a/target/sh4/translate.c b/target/sh4/translate.c index 40898e2393..8704fea1ca 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -2289,23 +2289,6 @@ static void sh4_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) tcg_gen_insn_start(ctx->base.pc_next, ctx->envflags); } -static bool sh4_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, - const CPUBreakpoint *bp) -{ - DisasContext *ctx = container_of(dcbase, DisasContext, base); - - /* We have hit a breakpoint - make sure PC is up-to-date */ - gen_save_cpu_state(ctx, true); - gen_helper_debug(cpu_env); - ctx->base.is_jmp = DISAS_NORETURN; - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size below does the right thing. */ - ctx->base.pc_next += 2; - return true; -} - static void sh4_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { CPUSH4State *env = cs->env_ptr; @@ -2369,7 +2352,6 @@ static const TranslatorOps sh4_tr_ops = { .init_disas_context = sh4_tr_init_disas_context, .tb_start = sh4_tr_tb_start, .insn_start = sh4_tr_insn_start, - .breakpoint_check = sh4_tr_breakpoint_check, .translate_insn = sh4_tr_translate_insn, .tb_stop = sh4_tr_tb_stop, .disas_log = sh4_tr_disas_log, diff --git a/target/sparc/translate.c b/target/sparc/translate.c index e530cb4aa8..11de5a4963 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -5854,22 +5854,6 @@ static void sparc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) } } -static bool sparc_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, - const CPUBreakpoint *bp) -{ - DisasContext *dc = container_of(dcbase, DisasContext, base); - - if (dc->pc != dc->base.pc_first) { - save_state(dc); - } - gen_helper_debug(cpu_env); - tcg_gen_exit_tb(NULL, 0); - dc->base.is_jmp = DISAS_NORETURN; - /* update pc_next so that the current instruction is included in tb->size */ - dc->base.pc_next += 4; - return true; -} - static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *dc = container_of(dcbase, DisasContext, base); @@ -5932,7 +5916,6 @@ static const TranslatorOps sparc_tr_ops = { .init_disas_context = sparc_tr_init_disas_context, .tb_start = sparc_tr_tb_start, .insn_start = sparc_tr_insn_start, - .breakpoint_check = sparc_tr_breakpoint_check, .translate_insn = sparc_tr_translate_insn, .tb_stop = sparc_tr_tb_stop, .disas_log = sparc_tr_disas_log, diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 865020754d..a0cc0f1cb3 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -8810,21 +8810,6 @@ static void tricore_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) tcg_gen_insn_start(ctx->base.pc_next); } -static bool tricore_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, - const CPUBreakpoint *bp) -{ - DisasContext *ctx = container_of(dcbase, DisasContext, base); - generate_qemu_excp(ctx, EXCP_DEBUG); - /* - * The address covered by the breakpoint must be included in - * [tb->pc, tb->pc + tb->size) in order to for it to be - * properly cleared -- thus we increment the PC here so that - * the logic setting tb->size below does the right thing. - */ - ctx->base.pc_next += 4; - return true; -} - static bool insn_crosses_page(CPUTriCoreState *env, DisasContext *ctx) { /* @@ -8898,7 +8883,6 @@ static const TranslatorOps tricore_tr_ops = { .init_disas_context = tricore_tr_init_disas_context, .tb_start = tricore_tr_tb_start, .insn_start = tricore_tr_insn_start, - .breakpoint_check = tricore_tr_breakpoint_check, .translate_insn = tricore_tr_translate_insn, .tb_stop = tricore_tr_tb_stop, .disas_log = tricore_tr_disas_log, diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 7094cfcf1d..20399d6a04 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -1232,22 +1232,6 @@ static void xtensa_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) tcg_gen_insn_start(dcbase->pc_next); } -static bool xtensa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, - const CPUBreakpoint *bp) -{ - DisasContext *dc = container_of(dcbase, DisasContext, base); - - tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); - gen_exception(dc, EXCP_DEBUG); - dc->base.is_jmp = DISAS_NORETURN; - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size below does the right thing. */ - dc->base.pc_next += 2; - return true; -} - static void xtensa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); @@ -1330,7 +1314,6 @@ static const TranslatorOps xtensa_translator_ops = { .init_disas_context = xtensa_tr_init_disas_context, .tb_start = xtensa_tr_tb_start, .insn_start = xtensa_tr_insn_start, - .breakpoint_check = xtensa_tr_breakpoint_check, .translate_insn = xtensa_tr_translate_insn, .tb_stop = xtensa_tr_tb_stop, .disas_log = xtensa_tr_disas_log, From d40c5c79764db01cb7e495bfcec62df9be481bce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 29 Jun 2021 19:04:34 -0700 Subject: [PATCH 281/531] accel/tcg: Hoist tb_cflags to a local in translator_loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The access internal to tb_cflags() is atomic. Avoid re-reading it as such for the multiple uses. Tested-by: Mark Cave-Ayland Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/translator.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 4f3728c278..b45337f3ba 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -50,6 +50,7 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest) void translator_loop(const TranslatorOps *ops, DisasContextBase *db, CPUState *cpu, TranslationBlock *tb, int max_insns) { + uint32_t cflags = tb_cflags(tb); bool plugin_enabled; /* Initialize DisasContext */ @@ -72,8 +73,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db, ops->tb_start(db, cpu); tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ - plugin_enabled = plugin_gen_tb_start(cpu, tb, - tb_cflags(db->tb) & CF_MEMI_ONLY); + plugin_enabled = plugin_gen_tb_start(cpu, tb, cflags & CF_MEMI_ONLY); while (true) { db->num_insns++; @@ -88,14 +88,13 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db, update db->pc_next and db->is_jmp to indicate what should be done next -- either exiting this loop or locate the start of the next instruction. */ - if (db->num_insns == db->max_insns - && (tb_cflags(db->tb) & CF_LAST_IO)) { + if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) { /* Accept I/O on the last instruction. */ gen_io_start(); ops->translate_insn(db, cpu); } else { /* we should only see CF_MEMI_ONLY for io_recompile */ - tcg_debug_assert(!(tb_cflags(db->tb) & CF_MEMI_ONLY)); + tcg_debug_assert(!(cflags & CF_MEMI_ONLY)); ops->translate_insn(db, cpu); } From c2ffd7549b14373e9ca68eccd84fab141ffde646 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Jul 2021 10:43:46 -1000 Subject: [PATCH 282/531] accel/tcg: Record singlestep_enabled in tb->cflags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set CF_SINGLE_STEP when single-stepping is enabled. This avoids the need to flush all tb's when turning single-stepping on or off. Tested-by: Mark Cave-Ayland Reviewed-by: Alex Bennée Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 7 ++++++- accel/tcg/translate-all.c | 4 ---- accel/tcg/translator.c | 7 +------ cpu.c | 4 ---- include/exec/exec-all.h | 1 + 5 files changed, 8 insertions(+), 15 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 5cc6363f4c..fc895cf51e 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -150,10 +150,15 @@ uint32_t curr_cflags(CPUState *cpu) uint32_t cflags = cpu->tcg_cflags; /* + * Record gdb single-step. We should be exiting the TB by raising + * EXCP_DEBUG, but to simplify other tests, disable chaining too. + * * For singlestep and -d nochain, suppress goto_tb so that * we can log -d cpu,exec after every TB. */ - if (singlestep) { + if (unlikely(cpu->singlestep_enabled)) { + cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR | CF_SINGLE_STEP | 1; + } else if (singlestep) { cflags |= CF_NO_GOTO_TB | 1; } else if (qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { cflags |= CF_NO_GOTO_TB; diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index bf82c15aab..bbfcfb698c 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -1432,10 +1432,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, } QEMU_BUILD_BUG_ON(CF_COUNT_MASK + 1 != TCG_MAX_INSNS); - if (cpu->singlestep_enabled) { - max_insns = 1; - } - buffer_overflow: tb = tcg_tb_alloc(tcg_ctx); if (unlikely(!tb)) { diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index b45337f3ba..c53a7f8e44 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -38,11 +38,6 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest) return false; } - /* Suppress goto_tb in the case of single-steping. */ - if (db->singlestep_enabled) { - return false; - } - /* Check for the dest on the same page as the start of the TB. */ return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0; } @@ -60,7 +55,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db, db->is_jmp = DISAS_NEXT; db->num_insns = 0; db->max_insns = max_insns; - db->singlestep_enabled = cpu->singlestep_enabled; + db->singlestep_enabled = cflags & CF_SINGLE_STEP; ops->init_disas_context(db, cpu); tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ diff --git a/cpu.c b/cpu.c index d6ae5ae581..e1799a15bc 100644 --- a/cpu.c +++ b/cpu.c @@ -326,10 +326,6 @@ void cpu_single_step(CPUState *cpu, int enabled) cpu->singlestep_enabled = enabled; if (kvm_enabled()) { kvm_update_guest_debug(cpu, 0); - } else { - /* must flush all the translated code to avoid inconsistencies */ - /* XXX: only flush what is necessary */ - tb_flush(cpu); } trace_breakpoint_singlestep(cpu->cpu_index, enabled); } diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 6873cce8df..5d1b6d80fb 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -497,6 +497,7 @@ struct TranslationBlock { #define CF_COUNT_MASK 0x000001ff #define CF_NO_GOTO_TB 0x00000200 /* Do not chain with goto_tb */ #define CF_NO_GOTO_PTR 0x00000400 /* Do not chain with goto_ptr */ +#define CF_SINGLE_STEP 0x00000800 /* gdbstub single-step in effect */ #define CF_LAST_IO 0x00008000 /* Last insn may be an IO access. */ #define CF_MEMI_ONLY 0x00010000 /* Only instrument memory ops */ #define CF_USE_ICOUNT 0x00020000 From 94075c28eea0755173939dfaf1eae688b224a74e Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 Jul 2021 10:39:49 -0500 Subject: [PATCH 283/531] iotests: Improve and rename test 291 to qemu-img-bitmap Enhance the test to demonstrate existing less-than-stellar behavior of qemu-img with a qcow2 image containing an inconsistent bitmap: we don't diagnose the problem until after copying the entire image (a potentially long time), and when we do diagnose the failure, we still end up leaving an empty bitmap in the destination. This mess will be cleaned up in the next patch. While at it, rename the test now that we support useful iotest names, and fix a missing newline in the error message thus exposed. Signed-off-by: Eric Blake Message-Id: <20210709153951.2801666-2-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Nir Soffer --- block/dirty-bitmap.c | 2 +- .../{291 => tests/qemu-img-bitmaps} | 21 +++++++- .../{291.out => tests/qemu-img-bitmaps.out} | 49 ++++++++++++++++++- 3 files changed, 69 insertions(+), 3 deletions(-) rename tests/qemu-iotests/{291 => tests/qemu-img-bitmaps} (87%) rename tests/qemu-iotests/{291.out => tests/qemu-img-bitmaps.out} (76%) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index 68d295d6e3..0ef46163e3 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -193,7 +193,7 @@ int bdrv_dirty_bitmap_check(const BdrvDirtyBitmap *bitmap, uint32_t flags, error_setg(errp, "Bitmap '%s' is inconsistent and cannot be used", bitmap->name); error_append_hint(errp, "Try block-dirty-bitmap-remove to delete" - " this bitmap from disk"); + " this bitmap from disk\n"); return -1; } diff --git a/tests/qemu-iotests/291 b/tests/qemu-iotests/tests/qemu-img-bitmaps similarity index 87% rename from tests/qemu-iotests/291 rename to tests/qemu-iotests/tests/qemu-img-bitmaps index 20efb080a6..409c4497a3 100755 --- a/tests/qemu-iotests/291 +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps @@ -3,7 +3,7 @@ # # Test qemu-img bitmap handling # -# Copyright (C) 2018-2020 Red Hat, Inc. +# Copyright (C) 2018-2021 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 @@ -27,11 +27,13 @@ status=1 # failure is the default! _cleanup() { _cleanup_test_img + _rm_test_img "$TEST_IMG.copy" nbd_server_stop } trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks +cd .. . ./common.rc . ./common.filter . ./common.nbd @@ -129,6 +131,23 @@ $QEMU_IMG map --output=json --image-opts \ nbd_server_stop +echo +echo "=== Check handling of inconsistent bitmap ===" +echo + +# Prepare image with corrupted bitmap +$QEMU_IO -c abort "$TEST_IMG" 2>/dev/null +$QEMU_IMG bitmap --add "$TEST_IMG" b4 +$QEMU_IMG bitmap --remove "$TEST_IMG" b1 +_img_info --format-specific | _filter_irrelevant_img_info +echo +$QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" "$TEST_IMG.copy" && + echo "unexpected success" +# Bug - even though we failed at conversion, we left a file around with +# a bitmap marked as not corrupt +TEST_IMG=$TEST_IMG.copy _img_info --format-specific \ + | _filter_irrelevant_img_info + # success, all done echo '*** done' rm -f $seq.full diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/tests/qemu-img-bitmaps.out similarity index 76% rename from tests/qemu-iotests/291.out rename to tests/qemu-iotests/tests/qemu-img-bitmaps.out index 018d6b103f..6824d41128 100644 --- a/tests/qemu-iotests/291.out +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps.out @@ -1,4 +1,4 @@ -QA output created by 291 +QA output created by qemu-img-bitmaps === Initial image setup === @@ -115,4 +115,51 @@ Format specific information: [{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, { "start": 2097152, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false}, { "start": 3145728, "length": 7340032, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] + +=== Check handling of inconsistent bitmap === + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 10 MiB (10485760 bytes) +cluster_size: 65536 +backing file: TEST_DIR/t.IMGFMT.base +backing file format: IMGFMT +Format specific information: + bitmaps: + [0]: + flags: + [0]: in-use + [1]: auto + name: b2 + granularity: 65536 + [1]: + flags: + [0]: in-use + name: b0 + granularity: 65536 + [2]: + flags: + [0]: auto + name: b4 + granularity: 65536 + corrupt: false + +qemu-img: Failed to populate bitmap b0: Bitmap 'b0' is inconsistent and cannot be used +Try block-dirty-bitmap-remove to delete this bitmap from disk +image: TEST_DIR/t.IMGFMT.copy +file format: IMGFMT +virtual size: 10 MiB (10485760 bytes) +cluster_size: 65536 +Format specific information: + bitmaps: + [0]: + flags: + name: b0 + granularity: 65536 + [1]: + flags: + [0]: auto + name: b4 + granularity: 65536 + corrupt: false *** done From 74a4320f30632fa539507861b3835698282e462e Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 Jul 2021 10:39:50 -0500 Subject: [PATCH 284/531] qemu-img: Fail fast on convert --bitmaps with inconsistent bitmap Waiting until the end of the convert operation (a potentially time-consuming task) to finally detect that we can't copy a bitmap is bad, comparing to failing fast up front. Furthermore, this prevents us from leaving a file behind with a bitmap that is not marked as inconsistent even though it does not have sane contents. This fixes the problems exposed in the previous patch to the iotest: it adds a fast failure up front, and even if we don't fail early, it ensures that any bitmap we add but do not properly populate is removed again rather than left behind incomplete. Signed-off-by: Eric Blake Message-Id: <20210709153951.2801666-3-eblake@redhat.com> [eblake: add a hint to the warning message, simplify name computation] Reviewed-by: Nir Soffer Reviewed-by: Vladimir Sementsov-Ogievskiy --- qemu-img.c | 29 +++++++++++++++++-- tests/qemu-iotests/tests/qemu-img-bitmaps | 3 +- tests/qemu-iotests/tests/qemu-img-bitmaps.out | 21 ++------------ 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 797742a443..c5496e82e0 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2101,6 +2101,29 @@ static int convert_do_copy(ImgConvertState *s) return s->ret; } +/* Check that bitmaps can be copied, or output an error */ +static int convert_check_bitmaps(BlockDriverState *src) +{ + BdrvDirtyBitmap *bm; + + if (!bdrv_supports_persistent_dirty_bitmap(src)) { + error_report("Source lacks bitmap support"); + return -1; + } + FOR_EACH_DIRTY_BITMAP(src, bm) { + if (!bdrv_dirty_bitmap_get_persistence(bm)) { + continue; + } + if (bdrv_dirty_bitmap_inconsistent(bm)) { + error_report("Cannot copy inconsistent bitmap '%s'", + bdrv_dirty_bitmap_name(bm)); + error_printf("Try 'qemu-img bitmap --remove' to delete it\n"); + return -1; + } + } + return 0; +} + static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst) { BdrvDirtyBitmap *bm; @@ -2127,6 +2150,7 @@ static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst) &err); if (err) { error_reportf_err(err, "Failed to populate bitmap %s: ", name); + qmp_block_dirty_bitmap_remove(dst->node_name, name, NULL); return -1; } } @@ -2554,9 +2578,8 @@ static int img_convert(int argc, char **argv) ret = -1; goto out; } - if (!bdrv_supports_persistent_dirty_bitmap(blk_bs(s.src[0]))) { - error_report("Source lacks bitmap support"); - ret = -1; + ret = convert_check_bitmaps(blk_bs(s.src[0])); + if (ret < 0) { goto out; } } diff --git a/tests/qemu-iotests/tests/qemu-img-bitmaps b/tests/qemu-iotests/tests/qemu-img-bitmaps index 409c4497a3..09c3d395d1 100755 --- a/tests/qemu-iotests/tests/qemu-img-bitmaps +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps @@ -140,11 +140,10 @@ $QEMU_IO -c abort "$TEST_IMG" 2>/dev/null $QEMU_IMG bitmap --add "$TEST_IMG" b4 $QEMU_IMG bitmap --remove "$TEST_IMG" b1 _img_info --format-specific | _filter_irrelevant_img_info +# Proof that we fail fast if bitmaps can't be copied echo $QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" "$TEST_IMG.copy" && echo "unexpected success" -# Bug - even though we failed at conversion, we left a file around with -# a bitmap marked as not corrupt TEST_IMG=$TEST_IMG.copy _img_info --format-specific \ | _filter_irrelevant_img_info diff --git a/tests/qemu-iotests/tests/qemu-img-bitmaps.out b/tests/qemu-iotests/tests/qemu-img-bitmaps.out index 6824d41128..d99c279d0c 100644 --- a/tests/qemu-iotests/tests/qemu-img-bitmaps.out +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps.out @@ -144,22 +144,7 @@ Format specific information: granularity: 65536 corrupt: false -qemu-img: Failed to populate bitmap b0: Bitmap 'b0' is inconsistent and cannot be used -Try block-dirty-bitmap-remove to delete this bitmap from disk -image: TEST_DIR/t.IMGFMT.copy -file format: IMGFMT -virtual size: 10 MiB (10485760 bytes) -cluster_size: 65536 -Format specific information: - bitmaps: - [0]: - flags: - name: b0 - granularity: 65536 - [1]: - flags: - [0]: auto - name: b4 - granularity: 65536 - corrupt: false +qemu-img: Cannot copy inconsistent bitmap 'b0' +Try 'qemu-img bitmap --remove' to delete it +qemu-img: Could not open 'TEST_DIR/t.IMGFMT.copy': Could not open 'TEST_DIR/t.IMGFMT.copy': No such file or directory *** done From 955171e4417bf39edb5503e694501e082a757731 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 21 Jul 2021 10:53:48 -0500 Subject: [PATCH 285/531] qemu-img: Add --skip-broken-bitmaps for 'convert --bitmaps' The point of 'qemu-img convert --bitmaps' is to be a convenience for actions that are already possible through a string of smaller 'qemu-img bitmap' sub-commands. One situation not accounted for already is that if a source image contains an inconsistent bitmap (for example, because a qemu process died abruptly before flushing bitmap state), the user MUST delete those inconsistent bitmaps before anything else useful can be done with the image. We don't want to delete inconsistent bitmaps by default: although a corrupt bitmap is only a loss of optimization rather than a corruption of user-visible data, it is still nice to require the user to opt in to the fact that they are aware of the loss of the bitmap. Still, requiring the user to check 'qemu-img info' to see whether bitmaps are consistent, then use 'qemu-img bitmap --remove' to remove offenders, all before using 'qemu-img convert', is a lot more work than just adding a knob 'qemu-img convert --bitmaps --skip-broken-bitmaps' which opts in to skipping the broken bitmaps. After testing the new option, also demonstrate the way to manually fix things (either deleting bad bitmaps, or re-creating them as empty) so that it is possible to convert without the option. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1946084 Signed-off-by: Eric Blake Message-Id: <20210709153951.2801666-4-eblake@redhat.com> [eblake: warning message tweak, test enhancements] Reviewed-by: Vladimir Sementsov-Ogievskiy --- docs/tools/qemu-img.rst | 8 ++++- qemu-img.c | 29 +++++++++++---- tests/qemu-iotests/tests/qemu-img-bitmaps | 16 ++++++++- tests/qemu-iotests/tests/qemu-img-bitmaps.out | 35 ++++++++++++++++++- 4 files changed, 79 insertions(+), 9 deletions(-) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index 1d8470eada..b7d602a288 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -414,7 +414,7 @@ Command description: 4 Error on reading data -.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME +.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps [--skip-broken-bitmaps]] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM* to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can @@ -456,6 +456,12 @@ Command description: *NUM_COROUTINES* specifies how many coroutines work in parallel during the convert process (defaults to 8). + Use of ``--bitmaps`` requests that any persistent bitmaps present in + the original are also copied to the destination. If any bitmap is + inconsistent in the source, the conversion will fail unless + ``--skip-broken-bitmaps`` is also specified to copy only the + consistent bitmaps. + .. option:: create [--object OBJECTDEF] [-q] [-f FMT] [-b BACKING_FILE] [-F BACKING_FMT] [-u] [-o OPTIONS] FILENAME [SIZE] Create the new disk image *FILENAME* of size *SIZE* and format diff --git a/qemu-img.c b/qemu-img.c index c5496e82e0..908fd0cce5 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -82,6 +82,7 @@ enum { OPTION_MERGE = 274, OPTION_BITMAPS = 275, OPTION_FORCE = 276, + OPTION_SKIP_BROKEN = 277, }; typedef enum OutputFormat { @@ -2102,7 +2103,7 @@ static int convert_do_copy(ImgConvertState *s) } /* Check that bitmaps can be copied, or output an error */ -static int convert_check_bitmaps(BlockDriverState *src) +static int convert_check_bitmaps(BlockDriverState *src, bool skip_broken) { BdrvDirtyBitmap *bm; @@ -2114,17 +2115,19 @@ static int convert_check_bitmaps(BlockDriverState *src) if (!bdrv_dirty_bitmap_get_persistence(bm)) { continue; } - if (bdrv_dirty_bitmap_inconsistent(bm)) { + if (!skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) { error_report("Cannot copy inconsistent bitmap '%s'", bdrv_dirty_bitmap_name(bm)); - error_printf("Try 'qemu-img bitmap --remove' to delete it\n"); + error_printf("Try --skip-broken-bitmaps, or " + "use 'qemu-img bitmap --remove' to delete it\n"); return -1; } } return 0; } -static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst) +static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst, + bool skip_broken) { BdrvDirtyBitmap *bm; Error *err = NULL; @@ -2136,6 +2139,10 @@ static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst) continue; } name = bdrv_dirty_bitmap_name(bm); + if (skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) { + warn_report("Skipping inconsistent bitmap '%s'", name); + continue; + } qmp_block_dirty_bitmap_add(dst->node_name, name, true, bdrv_dirty_bitmap_granularity(bm), true, true, @@ -2191,6 +2198,7 @@ static int img_convert(int argc, char **argv) bool force_share = false; bool explict_min_sparse = false; bool bitmaps = false; + bool skip_broken = false; int64_t rate_limit = 0; ImgConvertState s = (ImgConvertState) { @@ -2212,6 +2220,7 @@ static int img_convert(int argc, char **argv) {"salvage", no_argument, 0, OPTION_SALVAGE}, {"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO}, {"bitmaps", no_argument, 0, OPTION_BITMAPS}, + {"skip-broken-bitmaps", no_argument, 0, OPTION_SKIP_BROKEN}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WUr:", @@ -2340,6 +2349,9 @@ static int img_convert(int argc, char **argv) case OPTION_BITMAPS: bitmaps = true; break; + case OPTION_SKIP_BROKEN: + skip_broken = true; + break; } } @@ -2347,6 +2359,11 @@ static int img_convert(int argc, char **argv) out_fmt = "raw"; } + if (skip_broken && !bitmaps) { + error_report("Use of --skip-broken-bitmaps requires --bitmaps"); + goto fail_getopt; + } + if (s.compressed && s.copy_range) { error_report("Cannot enable copy offloading when -c is used"); goto fail_getopt; @@ -2578,7 +2595,7 @@ static int img_convert(int argc, char **argv) ret = -1; goto out; } - ret = convert_check_bitmaps(blk_bs(s.src[0])); + ret = convert_check_bitmaps(blk_bs(s.src[0]), skip_broken); if (ret < 0) { goto out; } @@ -2703,7 +2720,7 @@ static int img_convert(int argc, char **argv) /* Now copy the bitmaps */ if (bitmaps && ret == 0) { - ret = convert_copy_bitmaps(blk_bs(s.src[0]), out_bs); + ret = convert_copy_bitmaps(blk_bs(s.src[0]), out_bs, skip_broken); } out: diff --git a/tests/qemu-iotests/tests/qemu-img-bitmaps b/tests/qemu-iotests/tests/qemu-img-bitmaps index 09c3d395d1..7a3fe8c3d3 100755 --- a/tests/qemu-iotests/tests/qemu-img-bitmaps +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps @@ -144,7 +144,21 @@ _img_info --format-specific | _filter_irrelevant_img_info echo $QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" "$TEST_IMG.copy" && echo "unexpected success" -TEST_IMG=$TEST_IMG.copy _img_info --format-specific \ +TEST_IMG="$TEST_IMG.copy" _img_info --format-specific \ + | _filter_irrelevant_img_info +# Skipping the broken bitmaps works,... +echo +$QEMU_IMG convert --bitmaps --skip-broken-bitmaps \ + -O qcow2 "$TEST_IMG" "$TEST_IMG.copy" +TEST_IMG="$TEST_IMG.copy" _img_info --format-specific \ + | _filter_irrelevant_img_info +# ...as does removing them +echo +_rm_test_img "$TEST_IMG.copy" +$QEMU_IMG bitmap --remove "$TEST_IMG" b0 +$QEMU_IMG bitmap --remove --add "$TEST_IMG" b2 +$QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" "$TEST_IMG.copy" +TEST_IMG="$TEST_IMG.copy" _img_info --format-specific \ | _filter_irrelevant_img_info # success, all done diff --git a/tests/qemu-iotests/tests/qemu-img-bitmaps.out b/tests/qemu-iotests/tests/qemu-img-bitmaps.out index d99c279d0c..e851f0320e 100644 --- a/tests/qemu-iotests/tests/qemu-img-bitmaps.out +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps.out @@ -145,6 +145,39 @@ Format specific information: corrupt: false qemu-img: Cannot copy inconsistent bitmap 'b0' -Try 'qemu-img bitmap --remove' to delete it +Try --skip-broken-bitmaps, or use 'qemu-img bitmap --remove' to delete it qemu-img: Could not open 'TEST_DIR/t.IMGFMT.copy': Could not open 'TEST_DIR/t.IMGFMT.copy': No such file or directory + +qemu-img: warning: Skipping inconsistent bitmap 'b0' +qemu-img: warning: Skipping inconsistent bitmap 'b2' +image: TEST_DIR/t.IMGFMT.copy +file format: IMGFMT +virtual size: 10 MiB (10485760 bytes) +cluster_size: 65536 +Format specific information: + bitmaps: + [0]: + flags: + [0]: auto + name: b4 + granularity: 65536 + corrupt: false + +image: TEST_DIR/t.IMGFMT.copy +file format: IMGFMT +virtual size: 10 MiB (10485760 bytes) +cluster_size: 65536 +Format specific information: + bitmaps: + [0]: + flags: + [0]: auto + name: b4 + granularity: 65536 + [1]: + flags: + [0]: auto + name: b2 + granularity: 65536 + corrupt: false *** done From 4699a9277932a0e5b5a22ffed18a753c51a0f3cb Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Tue, 13 Jul 2021 10:51:33 -0500 Subject: [PATCH 286/531] Hexagon (target/hexagon) remove put_user_*/get_user_* Replace put_user_* with cpu_st*_data_ra Replace get_user_* with cpu_ld*_data_ra Suggested-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Taylor Simpson Message-Id: <1626384156-6248-2-git-send-email-tsimpson@quicinc.com> --- target/hexagon/op_helper.c | 39 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 459555966d..a959dba56e 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -17,6 +17,7 @@ #include "qemu/osdep.h" #include "qemu.h" +#include "exec/cpu_ldst.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" #include "cpu.h" @@ -140,22 +141,22 @@ void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check) void HELPER(commit_store)(CPUHexagonState *env, int slot_num) { - switch (env->mem_log_stores[slot_num].width) { + uintptr_t ra = GETPC(); + uint8_t width = env->mem_log_stores[slot_num].width; + target_ulong va = env->mem_log_stores[slot_num].va; + + switch (width) { case 1: - put_user_u8(env->mem_log_stores[slot_num].data32, - env->mem_log_stores[slot_num].va); + cpu_stb_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra); break; case 2: - put_user_u16(env->mem_log_stores[slot_num].data32, - env->mem_log_stores[slot_num].va); + cpu_stw_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra); break; case 4: - put_user_u32(env->mem_log_stores[slot_num].data32, - env->mem_log_stores[slot_num].va); + cpu_stl_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra); break; case 8: - put_user_u64(env->mem_log_stores[slot_num].data64, - env->mem_log_stores[slot_num].va); + cpu_stq_data_ra(env, va, env->mem_log_stores[slot_num].data64, ra); break; default: g_assert_not_reached(); @@ -393,37 +394,33 @@ static void check_noshuf(CPUHexagonState *env, uint32_t slot) static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, target_ulong vaddr) { - uint8_t retval; + uintptr_t ra = GETPC(); check_noshuf(env, slot); - get_user_u8(retval, vaddr); - return retval; + return cpu_ldub_data_ra(env, vaddr, ra); } static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, target_ulong vaddr) { - uint16_t retval; + uintptr_t ra = GETPC(); check_noshuf(env, slot); - get_user_u16(retval, vaddr); - return retval; + return cpu_lduw_data_ra(env, vaddr, ra); } static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, target_ulong vaddr) { - uint32_t retval; + uintptr_t ra = GETPC(); check_noshuf(env, slot); - get_user_u32(retval, vaddr); - return retval; + return cpu_ldl_data_ra(env, vaddr, ra); } static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, target_ulong vaddr) { - uint64_t retval; + uintptr_t ra = GETPC(); check_noshuf(env, slot); - get_user_u64(retval, vaddr); - return retval; + return cpu_ldq_data_ra(env, vaddr, ra); } /* Floating point */ From 25fc9b79cd057e394f35d7afc18493becd515797 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sat, 17 Jul 2021 11:30:17 +0100 Subject: [PATCH 287/531] target/hexagon: Drop include of qemu.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The qemu.h file is a CONFIG_USER_ONLY header; it doesn't appear on the include path for softmmu builds. Currently we include it unconditionally in target/hexagon/op_helper.c. We used to need it for the put_user_*() and get_user_*() functions, but now that we have removed the uses of those from op_helper.c, the only reason it's still there is that we're implicitly relying on it pulling in some other headers. Explicitly include the headers we need for other functions, and drop the include of qemu.h. Signed-off-by: Peter Maydell Message-Id: <20210717103017.20491-1-peter.maydell@linaro.org> Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Reviewed-by: Taylor Simpson Signed-off-by: Taylor Simpson --- target/hexagon/op_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index a959dba56e..61d5cde939 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -16,7 +16,8 @@ */ #include "qemu/osdep.h" -#include "qemu.h" +#include "qemu/log.h" +#include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" From dc2deaba4852e3324a4558a8bd29c58ce3299699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 31 May 2021 12:19:28 +0200 Subject: [PATCH 288/531] hw/display/virtio-gpu: Fix memory leak (CID 1453811) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid leaking memory on the error path, reorder the code as: - check the parameters first - check resource already existing - finally allocate memory Reported-by: Coverity (CID 1453811: RESOURCE_LEAK) Fixes: e0933d91b1c ("virtio-gpu: Add virtio_gpu_resource_create_blob") Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210531101928.1662732-1-philmd@redhat.com> Signed-off-by: Gerd Hoffmann --- hw/display/virtio-gpu.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 6b7f643951..990e71fd40 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -340,8 +340,15 @@ static void virtio_gpu_resource_create_blob(VirtIOGPU *g, return; } - res = virtio_gpu_find_resource(g, cblob.resource_id); - if (res) { + if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_GUEST && + cblob.blob_flags != VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid memory type\n", + __func__); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + + if (virtio_gpu_find_resource(g, cblob.resource_id)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", __func__, cblob.resource_id); cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; @@ -352,25 +359,12 @@ static void virtio_gpu_resource_create_blob(VirtIOGPU *g, res->resource_id = cblob.resource_id; res->blob_size = cblob.size; - if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_GUEST && - cblob.blob_flags != VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid memory type\n", - __func__); - cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; - g_free(res); - return; - } - - if (res->iov) { - cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; - return; - } - ret = virtio_gpu_create_mapping_iov(g, cblob.nr_entries, sizeof(cblob), cmd, &res->addrs, &res->iov, &res->iov_cnt); - if (ret != 0) { + if (ret != 0 || res->iov) { cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + g_free(res); return; } From f288d9932c29e8e24f1cbecd95e3539fbca5b90a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 19 Jul 2021 12:44:35 -0400 Subject: [PATCH 289/531] chardev-spice: add missing module_obj directive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The chardev-spicevmc class was not listed in chardev/spice.c, causing "-chardev spicevmc" to fail when modules are enabled. Reported-by: Frederic Bezies Fixes: 9f4a0f0978 ("modules: use modinfo for qom load", 2021-07-09) Resolves: //gitlab.com/qemu-project/qemu/-/issues/488 Signed-off-by: Paolo Bonzini Reviewed-by: Daniel P. Berrangé Message-Id: <20210719164435.1227794-1-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- chardev/spice.c | 1 + 1 file changed, 1 insertion(+) diff --git a/chardev/spice.c b/chardev/spice.c index 3ffb3fdc0d..bbffef4913 100644 --- a/chardev/spice.c +++ b/chardev/spice.c @@ -382,6 +382,7 @@ static const TypeInfo char_spicevmc_type_info = { .parent = TYPE_CHARDEV_SPICE, .class_init = char_spicevmc_class_init, }; +module_obj(TYPE_CHARDEV_SPICEVMC); static void char_spiceport_class_init(ObjectClass *oc, void *data) { From 670b35919301213e45ef42ed689f6ea67004d714 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 21 Jul 2021 10:17:18 +0200 Subject: [PATCH 290/531] usb: fix usb-host dependency check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: 90540f3289 ("configure, meson: convert libusb detection to meson", 2021-06-25) Reported-by: Programmingkid Signed-off-by: Gerd Hoffmann Message-Id: <20210721081718.301343-1-kraxel@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- hw/usb/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/meson.build b/hw/usb/meson.build index 3ca6127937..de853d780d 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build @@ -72,7 +72,7 @@ if usbredir.found() endif # usb pass-through -if config_host.has_key('CONFIG_USB_LIBUSB') +if libusb.found() usbhost_ss = ss.source_set() usbhost_ss.add(when: ['CONFIG_USB', libusb], if_true: files('host-libusb.c')) From 40e07370f21f12f020c1eb8a8d8c5321774e488a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Jul 2021 16:10:55 +0100 Subject: [PATCH 291/531] qemu-config: restore "machine" in qmp_query_command_line_options() Commit d8fb7d0969d5c32b3d1b9e20b63ec6c0abe80be4 ("vl: switch -M parsing to keyval") stopped adding the "machine" QemuOptsList. This causes "machine" options to not show up in QMP query-command-line-options output. For example, libvirt cannot detect that kernel_irqchip support is available. Adjust the "machine" opts enumeration in qmp_query_command_line_options() so that options are properly reported. Fixes: d8fb7d0969d5 ("vl: switch -M parsing to keyval") Cc: Paolo Bonzini Signed-off-by: Stefan Hajnoczi Message-Id: <20210721151055.424580-1-stefanha@redhat.com> Signed-off-by: Paolo Bonzini --- util/qemu-config.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/util/qemu-config.c b/util/qemu-config.c index fdf6cd69fc..436ab63b16 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -255,8 +255,6 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option, info->option = g_strdup(vm_config_groups[i]->name); if (!strcmp("drive", vm_config_groups[i]->name)) { info->parameters = get_drive_infolist(); - } else if (!strcmp("machine", vm_config_groups[i]->name)) { - info->parameters = query_option_descs(machine_opts.desc); } else { info->parameters = query_option_descs(vm_config_groups[i]->desc); @@ -265,6 +263,13 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option, } } + if (!has_option || !strcmp(option, "machine")) { + info = g_malloc0(sizeof(*info)); + info->option = g_strdup("machine"); + info->parameters = query_option_descs(machine_opts.desc); + QAPI_LIST_PREPEND(conf_list, info); + } + if (conf_list == NULL) { error_setg(errp, "invalid option name: %s", option); } From b128b25a5a2b1a7db6965a6d3fd0e4f6f0affc50 Mon Sep 17 00:00:00 2001 From: Lara Lazier Date: Wed, 21 Jul 2021 17:26:49 +0200 Subject: [PATCH 292/531] target/i386: Added V_INTR_PRIO check to virtual interrupts The APM2 states that The processor takes a virtual INTR interrupt if V_IRQ and V_INTR_PRIO indicate that there is a virtual interrupt pending whose priority is greater than the value in V_TPR. Signed-off-by: Lara Lazier Message-Id: <20210721152651.14683-1-laramglazier@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/tcg/sysemu/svm_helper.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 00618cff23..72b03a345d 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -65,6 +65,16 @@ static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr, sc->base, sc->limit, sc->flags); } +static inline bool ctl_has_irq(uint32_t int_ctl) +{ + uint32_t int_prio; + uint32_t tpr; + + int_prio = (int_ctl & V_INTR_PRIO_MASK) >> V_INTR_MASKING_SHIFT; + tpr = int_ctl & V_TPR_MASK; + return (int_ctl & V_IRQ_MASK) && (int_prio >= tpr); +} + void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) { CPUState *cs = env_cpu(env); @@ -290,7 +300,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) env->hflags2 |= HF2_GIF_MASK; - if (int_ctl & V_IRQ_MASK) { + if (ctl_has_irq(int_ctl)) { CPUState *cs = env_cpu(env); cs->interrupt_request |= CPU_INTERRUPT_VIRQ; From 213ff024a2f92020290296cb9dc29c2af3d4a221 Mon Sep 17 00:00:00 2001 From: Lara Lazier Date: Wed, 21 Jul 2021 17:26:50 +0200 Subject: [PATCH 293/531] target/i386: Added consistency checks for CR4 All MBZ bits in CR4 must be zero. (APM2 15.5) Added reserved bitmask and added checks in both helper_vmrun and helper_write_crN. Signed-off-by: Lara Lazier Message-Id: <20210721152651.14683-2-laramglazier@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 39 ++++++++++++++++++++++++++++ target/i386/tcg/sysemu/misc_helper.c | 3 +++ target/i386/tcg/sysemu/svm_helper.c | 9 ++++--- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 5d98a4e7c0..1f7e8d7f0a 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -240,6 +240,7 @@ typedef enum X86Seg { #define CR4_OSFXSR_SHIFT 9 #define CR4_OSFXSR_MASK (1U << CR4_OSFXSR_SHIFT) #define CR4_OSXMMEXCPT_MASK (1U << 10) +#define CR4_UMIP_MASK (1U << 11) #define CR4_LA57_MASK (1U << 12) #define CR4_VMXE_MASK (1U << 13) #define CR4_SMXE_MASK (1U << 14) @@ -251,6 +252,14 @@ typedef enum X86Seg { #define CR4_PKE_MASK (1U << 22) #define CR4_PKS_MASK (1U << 24) +#define CR4_RESERVED_MASK \ +(~(target_ulong)(CR4_VME_MASK | CR4_PVI_MASK | CR4_TSD_MASK \ + | CR4_DE_MASK | CR4_PSE_MASK | CR4_PAE_MASK \ + | CR4_MCE_MASK | CR4_PGE_MASK | CR4_PCE_MASK \ + | CR4_OSFXSR_MASK | CR4_OSXMMEXCPT_MASK |CR4_UMIP_MASK \ + | CR4_FSGSBASE_MASK | CR4_PCIDE_MASK | CR4_OSXSAVE_MASK \ + | CR4_SMEP_MASK | CR4_SMAP_MASK | CR4_PKE_MASK | CR4_PKS_MASK)) + #define DR6_BD (1 << 13) #define DR6_BS (1 << 14) #define DR6_BT (1 << 15) @@ -2196,6 +2205,36 @@ static inline bool hyperv_feat_enabled(X86CPU *cpu, int feat) return !!(cpu->hyperv_features & BIT(feat)); } +static inline uint64_t cr4_reserved_bits(CPUX86State *env) +{ + uint64_t reserved_bits = CR4_RESERVED_MASK; + if (!env->features[FEAT_XSAVE]) { + reserved_bits |= CR4_OSXSAVE_MASK; + } + if (!(env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_SMEP)) { + reserved_bits |= CR4_SMEP_MASK; + } + if (!(env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_SMAP)) { + reserved_bits |= CR4_SMAP_MASK; + } + if (!(env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_FSGSBASE)) { + reserved_bits |= CR4_FSGSBASE_MASK; + } + if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKU)) { + reserved_bits |= CR4_PKE_MASK; + } + if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_LA57)) { + reserved_bits |= CR4_LA57_MASK; + } + if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_UMIP)) { + reserved_bits |= CR4_UMIP_MASK; + } + if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKS)) { + reserved_bits |= CR4_PKS_MASK; + } + return reserved_bits; +} + #if defined(TARGET_X86_64) && \ defined(CONFIG_USER_ONLY) && \ defined(CONFIG_LINUX) diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c index db0d8a9d79..a2af2c9bba 100644 --- a/target/i386/tcg/sysemu/misc_helper.c +++ b/target/i386/tcg/sysemu/misc_helper.c @@ -99,6 +99,9 @@ void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) cpu_x86_update_cr3(env, t0); break; case 4: + if (t0 & cr4_reserved_bits(env)) { + cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); + } if (((t0 ^ env->cr[4]) & CR4_LA57_MASK) && (env->hflags & HF_CS64_MASK)) { raise_exception_ra(env, EXCP0D_GPF, GETPC()); diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 72b03a345d..d7d7a86aa9 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -85,6 +85,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) uint32_t int_ctl; uint32_t asid; uint64_t new_cr0; + uint64_t new_cr4; cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC()); @@ -225,14 +226,16 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) if ((new_cr0 & CR0_NW_MASK) && !(new_cr0 & CR0_CD_MASK)) { cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); } + new_cr4 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr4)); + if (new_cr4 & cr4_reserved_bits(env)) { + cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); + } /* clear exit_info_2 so we behave like the real hardware */ x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0); cpu_x86_update_cr0(env, new_cr0); - cpu_x86_update_cr4(env, x86_ldq_phys(cs, - env->vm_vmcb + offsetof(struct vmcb, - save.cr4))); + cpu_x86_update_cr4(env, new_cr4); cpu_x86_update_cr3(env, x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr3))); From d499f196fe97a6650ac5bd56811d2985c010e0d7 Mon Sep 17 00:00:00 2001 From: Lara Lazier Date: Wed, 21 Jul 2021 17:26:51 +0200 Subject: [PATCH 294/531] target/i386: Added consistency checks for EFER EFER.SVME has to be set, and EFER reserved bits must be zero. In addition the combinations * EFER.LMA or EFER.LME is non-zero and the processor does not support LM * non-zero EFER.LME and CR0.PG and zero CR4.PAE * non-zero EFER.LME and CR0.PG and zero CR0.PE * non-zero EFER.LME, CR0.PG, CR4.PAE, CS.L and CS.D are all invalid. (AMD64 Architecture Programmer's Manual, V2, 15.5) Signed-off-by: Lara Lazier Message-Id: <20210721152651.14683-3-laramglazier@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 5 ++++ target/i386/tcg/sysemu/svm_helper.c | 39 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 1f7e8d7f0a..6c50d3ab4f 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -475,6 +475,11 @@ typedef enum X86Seg { #define MSR_EFER_SVME (1 << 12) #define MSR_EFER_FFXSR (1 << 14) +#define MSR_EFER_RESERVED\ + (~(target_ulong)(MSR_EFER_SCE | MSR_EFER_LME\ + | MSR_EFER_LMA | MSR_EFER_NXE | MSR_EFER_SVME\ + | MSR_EFER_FFXSR)) + #define MSR_STAR 0xc0000081 #define MSR_LSTAR 0xc0000082 #define MSR_CSTAR 0xc0000083 diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index d7d7a86aa9..4d64ec378e 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -75,6 +75,41 @@ static inline bool ctl_has_irq(uint32_t int_ctl) return (int_ctl & V_IRQ_MASK) && (int_prio >= tpr); } +static inline bool is_efer_invalid_state (CPUX86State *env) +{ + if (!(env->efer & MSR_EFER_SVME)) { + return true; + } + + if (env->efer & MSR_EFER_RESERVED) { + return true; + } + + if ((env->efer & (MSR_EFER_LMA | MSR_EFER_LME)) && + !(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) { + return true; + } + + if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK) + && !(env->cr[4] & CR4_PAE_MASK)) { + return true; + } + + if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK) + && !(env->cr[0] & CR0_PE_MASK)) { + return true; + } + + if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK) + && (env->cr[4] & CR4_PAE_MASK) + && (env->segs[R_CS].flags & DESC_L_MASK) + && (env->segs[R_CS].flags & DESC_B_MASK)) { + return true; + } + + return false; +} + void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) { CPUState *cs = env_cpu(env); @@ -291,6 +326,10 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) } #endif + if (is_efer_invalid_state(env)) { + cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); + } + switch (x86_ldub_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) { case TLB_CONTROL_DO_NOTHING: From c10852afb6a2b84bcc3bffce40c1c0509d6c8e64 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 14 Jul 2021 09:28:55 +0200 Subject: [PATCH 295/531] configure: Drop obsolete check for the alloc_size attribute We recently bumped our requirement for Clang to at least version 6.0. And according to: https://releases.llvm.org/6.0.0/tools/clang/docs/AttributeReference.html Clang v6.0 supports the alloc_size attribute. Thus we can drop this check in the configure script now. Signed-off-by: Thomas Huth Message-Id: <20210714072855.785566-1-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- configure | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/configure b/configure index 63f38fa94c..026704f15a 100755 --- a/configure +++ b/configure @@ -3266,18 +3266,6 @@ if ! compile_prog "$glib_cflags" "$glib_libs" ; then "build target" fi -# Silence clang 3.5.0 warnings about glib attribute __alloc_size__ usage -cat > $TMPC << EOF -#include -int main(void) { return 0; } -EOF -if ! compile_prog "$glib_cflags -Werror" "$glib_libs" ; then - if cc_has_warning_flag "-Wno-unknown-attributes"; then - glib_cflags="-Wno-unknown-attributes $glib_cflags" - CONFIGURE_CFLAGS="-Wno-unknown-attributes $CONFIGURE_CFLAGS" - fi -fi - # Silence clang warnings triggered by glib < 2.57.2 cat > $TMPC << EOF #include From ac34711171f0b350d9125c46691744405b6a54ce Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 21 Jul 2021 18:51:57 +0200 Subject: [PATCH 296/531] meson: fix dependencies for modinfo modinfo runs the preprocessor and therefore needs all generated input files to be there. The "depends" clause does not work in Meson 0.55.3, so for now use "input". Signed-off-by: Paolo Bonzini --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 6e4d2d8034..eb85fe8e44 100644 --- a/meson.build +++ b/meson.build @@ -2335,9 +2335,9 @@ foreach d, list : modules # https://github.com/mesonbuild/meson/pull/8900 modinfo_files += custom_target(d + '-' + m + '.modinfo', output: d + '-' + m + '.modinfo', - input: module_ss.sources(), + input: module_ss.sources() + genh, capture: true, - command: [modinfo_collect, '@INPUT@']) + command: [modinfo_collect, module_ss.sources()]) endif else if d == 'block' From 332008e0b9da33dee2c765db3e4e16b3c3ba3a92 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 13 Jul 2021 11:31:52 +0200 Subject: [PATCH 297/531] configure: Fix --without-default-features propagation to meson A typo prevents that many features get disabled when the user runs "configure" with the --without-default-features switch. Reported-by: Cole Robinson Signed-off-by: Thomas Huth Message-Id: <20210713093155.677589-2-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 026704f15a..19c4bc1192 100755 --- a/configure +++ b/configure @@ -5206,7 +5206,7 @@ if test "$skip_meson" = no; then -Ddocs=$docs -Dsphinx_build=$sphinx_build -Dinstall_blobs=$blobs \ -Dvhost_user_blk_server=$vhost_user_blk_server -Dmultiprocess=$multiprocess \ -Dfuse=$fuse -Dfuse_lseek=$fuse_lseek -Dguest_agent_msi=$guest_agent_msi -Dbpf=$bpf\ - $(if test "$default_features" = no; then echo "-Dauto_features=disabled"; fi) \ + $(if test "$default_feature" = no; then echo "-Dauto_features=disabled"; fi) \ -Dtcg_interpreter=$tcg_interpreter \ $cross_arg \ "$PWD" "$source_path" From 3a6a1256d46daa21210d52b2740121f4ea929e9b Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 13 Jul 2021 11:31:53 +0200 Subject: [PATCH 298/531] configure: Allow vnc to get disabled with --without-default-features There's no reason why we should keep VNC enabled when the user specified --without-default-features. Reported-by: Cole Robinson Signed-off-by: Thomas Huth Message-Id: <20210713093155.677589-3-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- configure | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 19c4bc1192..468aac58e2 100755 --- a/configure +++ b/configure @@ -304,7 +304,7 @@ virtiofsd="auto" virtfs="auto" libudev="auto" mpath="auto" -vnc="enabled" +vnc="auto" sparse="auto" vde="$default_feature" vnc_sasl="auto" diff --git a/meson.build b/meson.build index eb85fe8e44..cb3856fc35 100644 --- a/meson.build +++ b/meson.build @@ -930,7 +930,7 @@ vnc = not_found png = not_found jpeg = not_found sasl = not_found -if get_option('vnc').enabled() +if not get_option('vnc').disabled() vnc = declare_dependency() # dummy dependency png = dependency('libpng', required: get_option('vnc_png'), method: 'pkg-config', kwargs: static_kwargs) From bcf0a7dabd8fe01f948801c49b9a948560fa346d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 13 Jul 2021 11:31:54 +0200 Subject: [PATCH 299/531] configure: Fix the default setting of the "xen" feature The "xen" variable should either contain "enabled", "disabled" or nothing (for auto detection). But when the user currently runs the configure script with --without-default-features, it gets set to "no" instead. This does not work as expected, the feature will still be enabled if the Xen headers are present. Thus set the variable to "disabled" instead if default_feature switch has been set. Reported-by: Cole Robinson Signed-off-by: Thomas Huth Message-Id: <20210713093155.677589-4-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 468aac58e2..40fa8cc26e 100755 --- a/configure +++ b/configure @@ -311,7 +311,7 @@ vnc_sasl="auto" vnc_jpeg="auto" vnc_png="auto" xkbcommon="auto" -xen="$default_feature" +xen=${default_feature:+disabled} xen_ctrl_version="$default_feature" xen_pci_passthrough="auto" linux_aio="$default_feature" From 0848f8aca6f7b13f2a755c2593b0a1cbb39f658e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 13 Jul 2021 11:31:55 +0200 Subject: [PATCH 300/531] configure: Let --without-default-features disable vhost-kernel and vhost-vdpa The vhost_kernel and vhost_vdpa variables should be pre-initialized with the $default_feature setting so that these features get disabled when the user runs the configure scripts with --without-default-features. Reported-by: Cole Robinson Signed-off-by: Thomas Huth Message-Id: <20210713093155.677589-5-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- configure | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure b/configure index 40fa8cc26e..2a6d23a844 100755 --- a/configure +++ b/configure @@ -321,6 +321,7 @@ attr="auto" xfs="$default_feature" tcg="enabled" membarrier="$default_feature" +vhost_kernel="$default_feature" vhost_net="$default_feature" vhost_crypto="$default_feature" vhost_scsi="$default_feature" @@ -328,6 +329,7 @@ vhost_vsock="$default_feature" vhost_user="no" vhost_user_blk_server="auto" vhost_user_fs="$default_feature" +vhost_vdpa="$default_feature" bpf="auto" kvm="auto" hax="auto" From 39b8a183e2f399d19f3ab6a3db44c7c74774dabd Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 21 Jul 2021 11:33:46 +0200 Subject: [PATCH 301/531] qxl: remove assert in qxl_pre_save. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 551dbd0846d2 ("migration: check pre_save return in vmstate_save_state") the pre_save hook can fail. So lets finally use that to drop the guest-triggerable assert in qxl_pre_save(). Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-Id: <20210721093347.338536-2-kraxel@redhat.com> --- hw/display/qxl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 84f99088e0..3867b94fe2 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2283,7 +2283,9 @@ static int qxl_pre_save(void *opaque) } else { d->last_release_offset = (uint8_t *)d->last_release - ram_start; } - assert(d->last_release_offset < d->vga.vram_size); + if (d->last_release_offset < d->vga.vram_size) { + return 1; + } return 0; } From dcc5fc2a3adb9ec4b196f82ebe4079bc88f3c91e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 21 Jul 2021 11:33:47 +0200 Subject: [PATCH 302/531] Revert "qxl: add migration blocker to avoid pre-save assert" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 86dbcdd9c7590d06db89ca256c5eaf0b4aba8858. The pre-save assert is gone now, so the migration blocker is not needed any more. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-Id: <20210721093347.338536-3-kraxel@redhat.com> --- hw/display/qxl.c | 31 ------------------------------- hw/display/qxl.h | 1 - 2 files changed, 32 deletions(-) diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 3867b94fe2..43482d4364 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -30,7 +30,6 @@ #include "qemu/module.h" #include "hw/qdev-properties.h" #include "sysemu/runstate.h" -#include "migration/blocker.h" #include "migration/vmstate.h" #include "trace.h" @@ -666,30 +665,6 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) qxl->guest_primary.commands++; qxl_track_command(qxl, ext); qxl_log_command(qxl, "cmd", ext); - { - /* - * Windows 8 drivers place qxl commands in the vram - * (instead of the ram) bar. We can't live migrate such a - * guest, so add a migration blocker in case we detect - * this, to avoid triggering the assert in pre_save(). - * - * https://cgit.freedesktop.org/spice/win32/qxl-wddm-dod/commit/?id=f6e099db39e7d0787f294d5fd0dce328b5210faa - */ - void *msg = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); - if (msg != NULL && ( - msg < (void *)qxl->vga.vram_ptr || - msg > ((void *)qxl->vga.vram_ptr + qxl->vga.vram_size))) { - if (!qxl->migration_blocker) { - Error *local_err = NULL; - error_setg(&qxl->migration_blocker, - "qxl: guest bug: command not in ram bar"); - migrate_add_blocker(qxl->migration_blocker, &local_err); - if (local_err) { - error_report_err(local_err); - } - } - } - } trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); return true; default: @@ -1283,12 +1258,6 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) qemu_spice_create_host_memslot(&d->ssd); qxl_soft_reset(d); - if (d->migration_blocker) { - migrate_del_blocker(d->migration_blocker); - error_free(d->migration_blocker); - d->migration_blocker = NULL; - } - if (startstop) { qemu_spice_display_start(); } diff --git a/hw/display/qxl.h b/hw/display/qxl.h index 379d3304ab..30d21f4d0b 100644 --- a/hw/display/qxl.h +++ b/hw/display/qxl.h @@ -39,7 +39,6 @@ struct PCIQXLDevice { uint32_t cmdlog; uint32_t guest_bug; - Error *migration_blocker; enum qxl_mode mode; uint32_t cmdflags; From 02f9725f3df8a0e8f0a209d7436fad04e1ac190e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 5 Jul 2021 14:42:18 +0400 Subject: [PATCH 303/531] hw/display: fail early when multiple virgl devices are requested MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids failing to initialize virgl and crashing later on, and clear the user expectations. Signed-off-by: Marc-André Lureau Reviewed-by: Mark Cave-Ayland Message-Id: <20210705104218.1161101-1-marcandre.lureau@redhat.com> Signed-off-by: Gerd Hoffmann --- hw/display/virtio-gpu-gl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 7ab93bf8c8..b1035e119c 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -113,6 +113,11 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) return; #endif + if (!object_resolve_path_type("", TYPE_VIRTIO_GPU_GL, NULL)) { + error_setg(errp, "at most one %s device is permitted", TYPE_VIRTIO_GPU_GL); + return; + } + if (!display_opengl) { error_setg(errp, "opengl is not available"); return; From f29d52611c73347a2fc0fcea62e6197383b18fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 1 Jul 2021 10:24:21 +0400 Subject: [PATCH 304/531] vl: add virtio-vga-gl to the default_list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not instantiate an extra default VGA device if -device virtio-vga-gl is provided. Related to commit b36eb8860f8f4a9c6f131c3fd380116a3017e022 ("virtio-gpu: add virtio-vga-gl") Signed-off-by: Marc-André Lureau Message-Id: <20210701062421.721414-1-marcandre.lureau@redhat.com> Signed-off-by: Gerd Hoffmann --- softmmu/vl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/softmmu/vl.c b/softmmu/vl.c index 4df1496101..a6c17fa39c 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -202,6 +202,7 @@ static struct { { .driver = "virtio-vga", .flag = &default_vga }, { .driver = "ati-vga", .flag = &default_vga }, { .driver = "vhost-user-vga", .flag = &default_vga }, + { .driver = "virtio-vga-gl", .flag = &default_vga }, }; static QemuOptsList qemu_rtc_opts = { From 8a13b9bc0f283caff4333c75bc396a963f47ce5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 2 Jul 2021 16:32:21 +0400 Subject: [PATCH 305/531] hw/display: fix virgl reset regression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before commit 49afbca3b00e8e517d54964229a794b51768deaf ("virtio-gpu: drop use_virgl_renderer"), use_virgl_renderer was preventing calling GL functions from non-GL context threads. The innocuously looking g->parent_obj.use_virgl_renderer = false; was set the first time virtio_gpu_gl_reset() was called, during pc_machine_reset() in the main thread. Further virtio_gpu_gl_reset() calls in IO threads, without associated GL context, were thus skipping GL calls and avoided warnings or crashes (see also https://gitlab.freedesktop.org/virgl/virglrenderer/-/issues/226). Signed-off-by: Marc-André Lureau Message-Id: <20210702123221.942432-1-marcandre.lureau@redhat.com> Signed-off-by: Gerd Hoffmann --- hw/display/virtio-gpu-gl.c | 22 +++++++++++----------- hw/display/virtio-gpu-virgl.c | 8 ++++++-- include/hw/virtio/virtio-gpu.h | 1 + 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index b1035e119c..6cc4313b1a 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -51,12 +51,7 @@ static void virtio_gpu_gl_update_cursor_data(VirtIOGPU *g, static void virtio_gpu_gl_flushed(VirtIOGPUBase *b) { VirtIOGPU *g = VIRTIO_GPU(b); - VirtIOGPUGL *gl = VIRTIO_GPU_GL(b); - if (gl->renderer_reset) { - gl->renderer_reset = false; - virtio_gpu_virgl_reset(g); - } virtio_gpu_process_cmdq(g); } @@ -74,6 +69,10 @@ static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) virtio_gpu_virgl_init(g); gl->renderer_inited = true; } + if (gl->renderer_reset) { + gl->renderer_reset = false; + virtio_gpu_virgl_reset(g); + } cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); while (cmd) { @@ -95,12 +94,13 @@ static void virtio_gpu_gl_reset(VirtIODevice *vdev) virtio_gpu_reset(vdev); - if (gl->renderer_inited) { - if (g->parent_obj.renderer_blocked) { - gl->renderer_reset = true; - } else { - virtio_gpu_virgl_reset(g); - } + /* + * GL functions must be called with the associated GL context in main + * thread, and when the renderer is unblocked. + */ + if (gl->renderer_inited && !gl->renderer_reset) { + virtio_gpu_virgl_reset_scanout(g); + gl->renderer_reset = true; } } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 092c6dc380..18d054922f 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -588,17 +588,21 @@ void virtio_gpu_virgl_fence_poll(VirtIOGPU *g) virtio_gpu_fence_poll(g); } -void virtio_gpu_virgl_reset(VirtIOGPU *g) +void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g) { int i; - virgl_renderer_reset(); for (i = 0; i < g->parent_obj.conf.max_outputs; i++) { dpy_gfx_replace_surface(g->parent_obj.scanout[i].con, NULL); dpy_gl_scanout_disable(g->parent_obj.scanout[i].con); } } +void virtio_gpu_virgl_reset(VirtIOGPU *g) +{ + virgl_renderer_reset(); +} + int virtio_gpu_virgl_init(VirtIOGPU *g) { int ret; diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index bcf54d970f..24c6628944 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -279,6 +279,7 @@ int virtio_gpu_update_dmabuf(VirtIOGPU *g, void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd); void virtio_gpu_virgl_fence_poll(VirtIOGPU *g); +void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); int virtio_gpu_virgl_init(VirtIOGPU *g); int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); From 917ddc27d86ae427d2aa7ff2d19eb7fdb642b68e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 23 Jul 2021 14:01:56 +0200 Subject: [PATCH 306/531] meson: fix dependencies for modinfo #2 modinfo runs the preprocessor and therefore needs all generated input files to be there. The "depends" clause does not work in Meson 0.55.3, so for now use "input". Part #2: Update the rule for target-specific modules too. Signed-off-by: Gerd Hoffmann Message-Id: <20210723120156.1183920-1-kraxel@redhat.com> Signed-off-by: Paolo Bonzini --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index df5094e563..f2e148eaf9 100644 --- a/meson.build +++ b/meson.build @@ -2373,9 +2373,9 @@ foreach d, list : target_modules # FIXME: Should use sl.extract_all_objects(recursive: true) too. modinfo_files += custom_target(module_name + '.modinfo', output: module_name + '.modinfo', - input: target_module_ss.sources(), + input: target_module_ss.sources() + genh, capture: true, - command: [modinfo_collect, '--target', target, '@INPUT@']) + command: [modinfo_collect, '--target', target, target_module_ss.sources()]) endif endif endforeach From 3407259b20ccb5f53183bc50605da6f229dc2de2 Mon Sep 17 00:00:00 2001 From: Lara Lazier Date: Fri, 23 Jul 2021 13:27:40 +0200 Subject: [PATCH 307/531] target/i386: Added consistency checks for CR3 All MBZ in CR3 must be zero (APM2 15.5) Added checks in both helper_vmrun and helper_write_crN. When EFER.LMA is zero the upper 32 bits needs to be zeroed. Signed-off-by: Lara Lazier Message-Id: <20210723112740.45962-1-laramglazier@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/tcg/sysemu/misc_helper.c | 7 +++++++ target/i386/tcg/sysemu/svm_helper.c | 10 +++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c index a2af2c9bba..d347af2a99 100644 --- a/target/i386/tcg/sysemu/misc_helper.c +++ b/target/i386/tcg/sysemu/misc_helper.c @@ -96,6 +96,13 @@ void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) cpu_x86_update_cr0(env, t0); break; case 3: + if ((env->efer & MSR_EFER_LMA) && + (t0 & ((~0UL) << env_archcpu(env)->phys_bits))) { + cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); + } + if (!(env->efer & MSR_EFER_LMA)) { + t0 &= 0xffffffffUL; + } cpu_x86_update_cr3(env, t0); break; case 4: diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 4d64ec378e..145511d635 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -120,6 +120,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) uint32_t int_ctl; uint32_t asid; uint64_t new_cr0; + uint64_t new_cr3; uint64_t new_cr4; cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC()); @@ -261,6 +262,11 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) if ((new_cr0 & CR0_NW_MASK) && !(new_cr0 & CR0_CD_MASK)) { cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); } + new_cr3 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr3)); + if ((env->efer & MSR_EFER_LMA) && + (new_cr3 & ((~0UL) << cpu->phys_bits))) { + cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); + } new_cr4 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr4)); if (new_cr4 & cr4_reserved_bits(env)) { cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); @@ -271,9 +277,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) cpu_x86_update_cr0(env, new_cr0); cpu_x86_update_cr4(env, new_cr4); - cpu_x86_update_cr3(env, x86_ldq_phys(cs, - env->vm_vmcb + offsetof(struct vmcb, - save.cr3))); + cpu_x86_update_cr3(env, new_cr3); env->cr[2] = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr2)); int_ctl = x86_ldl_phys(cs, From 5b8978d8042660de35b2c67c62ffeb6b42ff441e Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Fri, 23 Jul 2021 13:29:21 +0200 Subject: [PATCH 308/531] i386: do not call cpudef-only models functions for max, host, base Some cpu properties have to be set only for cpu models in builtin_x86_defs, registered with x86_register_cpu_model_type, and not for cpu models "base", "max", and the subclass "host". These properties are the ones set by function x86_cpu_apply_props, (also including kvm_default_props, tcg_default_props), and the "vendor" property for the KVM and HVF accelerators. After recent refactoring of cpu, which also affected these properties, they were instead set unconditionally for all x86 cpus. This has been detected as a bug with Nested on AMD with cpu "host", as svm was not turned on by default, due to the wrongful setting of kvm_default_props via x86_cpu_apply_props, which set svm to "off". Rectify the bug introduced in commit "i386: split cpu accelerators" and document the functions that are builtin_x86_defs-only. Signed-off-by: Claudio Fontana Tested-by: Alexander Bulekov Fixes: f5cc5a5c ("i386: split cpu accelerators from cpu.c,"...) Resolves: https://gitlab.com/qemu-project/qemu/-/issues/477 Message-Id: <20210723112921.12637-1-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 19 ++++++- target/i386/host-cpu.c | 13 +++-- target/i386/kvm/kvm-cpu.c | 105 ++++++++++++++++++++------------------ target/i386/tcg/tcg-cpu.c | 11 ++-- 4 files changed, 89 insertions(+), 59 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 48b55ebd0a..edb97ebbbe 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -4919,6 +4919,9 @@ static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, return r; } +/* + * Only for builtin_x86_defs models initialized with x86_register_cpudef_types. + */ void x86_cpu_apply_props(X86CPU *cpu, PropValue *props) { PropValue *pv; @@ -4931,7 +4934,11 @@ void x86_cpu_apply_props(X86CPU *cpu, PropValue *props) } } -/* Apply properties for the CPU model version specified in model */ +/* + * Apply properties for the CPU model version specified in model. + * Only for builtin_x86_defs models initialized with x86_register_cpudef_types. + */ + static void x86_cpu_apply_version_props(X86CPU *cpu, X86CPUModel *model) { const X86CPUVersionDefinition *vdef; @@ -4960,7 +4967,9 @@ static void x86_cpu_apply_version_props(X86CPU *cpu, X86CPUModel *model) assert(vdef->version == version); } -/* Load data from X86CPUDefinition into a X86CPU object +/* + * Load data from X86CPUDefinition into a X86CPU object. + * Only for builtin_x86_defs models initialized with x86_register_cpudef_types. */ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) { @@ -5051,6 +5060,12 @@ static void x86_register_cpu_model_type(const char *name, X86CPUModel *model) type_register(&ti); } + +/* + * register builtin_x86_defs; + * "max", "base" and subclasses ("host") are not registered here. + * See x86_cpu_register_types for all model registrations. + */ static void x86_register_cpudef_types(const X86CPUDefinition *def) { X86CPUModel *m; diff --git a/target/i386/host-cpu.c b/target/i386/host-cpu.c index 4ea9e354ea..10f8aba86e 100644 --- a/target/i386/host-cpu.c +++ b/target/i386/host-cpu.c @@ -150,13 +150,16 @@ void host_cpu_vendor_fms(char *vendor, int *family, int *model, int *stepping) void host_cpu_instance_init(X86CPU *cpu) { - uint32_t ebx = 0, ecx = 0, edx = 0; - char vendor[CPUID_VENDOR_SZ + 1]; + X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu); - host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); - x86_cpu_vendor_words2str(vendor, ebx, edx, ecx); + if (xcc->model) { + uint32_t ebx = 0, ecx = 0, edx = 0; + char vendor[CPUID_VENDOR_SZ + 1]; - object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); + host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); + x86_cpu_vendor_words2str(vendor, ebx, edx, ecx); + object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); + } } void host_cpu_max_instance_init(X86CPU *cpu) diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index bbe817764d..d95028018e 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -52,47 +52,6 @@ static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) return host_cpu_realizefn(cs, errp); } -/* - * KVM-specific features that are automatically added/removed - * from all CPU models when KVM is enabled. - * - * NOTE: features can be enabled by default only if they were - * already available in the oldest kernel version supported - * by the KVM accelerator (see "OS requirements" section at - * docs/system/target-i386.rst) - */ -static PropValue kvm_default_props[] = { - { "kvmclock", "on" }, - { "kvm-nopiodelay", "on" }, - { "kvm-asyncpf", "on" }, - { "kvm-steal-time", "on" }, - { "kvm-pv-eoi", "on" }, - { "kvmclock-stable-bit", "on" }, - { "x2apic", "on" }, - { "kvm-msi-ext-dest-id", "off" }, - { "acpi", "off" }, - { "monitor", "off" }, - { "svm", "off" }, - { NULL, NULL }, -}; - -void x86_cpu_change_kvm_default(const char *prop, const char *value) -{ - PropValue *pv; - for (pv = kvm_default_props; pv->prop; pv++) { - if (!strcmp(pv->prop, prop)) { - pv->value = value; - break; - } - } - - /* - * It is valid to call this function only for properties that - * are already present in the kvm_default_props table. - */ - assert(pv->prop); -} - static bool lmce_supported(void) { uint64_t mce_cap = 0; @@ -150,22 +109,70 @@ static void kvm_cpu_xsave_init(void) } } +/* + * KVM-specific features that are automatically added/removed + * from cpudef models when KVM is enabled. + * Only for builtin_x86_defs models initialized with x86_register_cpudef_types. + * + * NOTE: features can be enabled by default only if they were + * already available in the oldest kernel version supported + * by the KVM accelerator (see "OS requirements" section at + * docs/system/target-i386.rst) + */ +static PropValue kvm_default_props[] = { + { "kvmclock", "on" }, + { "kvm-nopiodelay", "on" }, + { "kvm-asyncpf", "on" }, + { "kvm-steal-time", "on" }, + { "kvm-pv-eoi", "on" }, + { "kvmclock-stable-bit", "on" }, + { "x2apic", "on" }, + { "kvm-msi-ext-dest-id", "off" }, + { "acpi", "off" }, + { "monitor", "off" }, + { "svm", "off" }, + { NULL, NULL }, +}; + +/* + * Only for builtin_x86_defs models initialized with x86_register_cpudef_types. + */ +void x86_cpu_change_kvm_default(const char *prop, const char *value) +{ + PropValue *pv; + for (pv = kvm_default_props; pv->prop; pv++) { + if (!strcmp(pv->prop, prop)) { + pv->value = value; + break; + } + } + + /* + * It is valid to call this function only for properties that + * are already present in the kvm_default_props table. + */ + assert(pv->prop); +} + static void kvm_cpu_instance_init(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); + X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu); host_cpu_instance_init(cpu); - if (!kvm_irqchip_in_kernel()) { - x86_cpu_change_kvm_default("x2apic", "off"); - } else if (kvm_irqchip_is_split() && kvm_enable_x2apic()) { - x86_cpu_change_kvm_default("kvm-msi-ext-dest-id", "on"); + if (xcc->model) { + /* only applies to builtin_x86_defs cpus */ + if (!kvm_irqchip_in_kernel()) { + x86_cpu_change_kvm_default("x2apic", "off"); + } else if (kvm_irqchip_is_split() && kvm_enable_x2apic()) { + x86_cpu_change_kvm_default("kvm-msi-ext-dest-id", "on"); + } + + /* Special cases not set in the X86CPUDefinition structs: */ + x86_cpu_apply_props(cpu, kvm_default_props); } - /* Special cases not set in the X86CPUDefinition structs: */ - - x86_cpu_apply_props(cpu, kvm_default_props); - if (cpu->max_features) { kvm_cpu_max_instance_init(cpu); } diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 238e3a9395..93a79a5741 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -111,7 +111,8 @@ static void tcg_cpu_xsave_init(void) } /* - * TCG-specific defaults that override all CPU models when using TCG + * TCG-specific defaults that override cpudef models when using TCG. + * Only for builtin_x86_defs models initialized with x86_register_cpudef_types. */ static PropValue tcg_default_props[] = { { "vme", "off" }, @@ -121,8 +122,12 @@ static PropValue tcg_default_props[] = { static void tcg_cpu_instance_init(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); - /* Special cases not set in the X86CPUDefinition structs: */ - x86_cpu_apply_props(cpu, tcg_default_props); + X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu); + + if (xcc->model) { + /* Special cases not set in the X86CPUDefinition structs: */ + x86_cpu_apply_props(cpu, tcg_default_props); + } tcg_cpu_xsave_init(); } From 4ade3ea145261fb6ae6c80b284f6912f3f7b87be Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 23 Jul 2021 12:05:30 +0200 Subject: [PATCH 309/531] MAINTAINERS: Replace Eduardo as "Host Memory Backends" maintainer Edurdo asked me to take over co-maintaining "Host Memory Backends" with Igor, as Eduardo has plenty of other things to look after. Thanks a lot Eduardo for your excellent work in the past! Cc: Peter Maydell Cc: Eduardo Habkost Cc: Igor Mammedov Cc: Paolo Bonzini Signed-off-by: David Hildenbrand Acked-by: Igor Mammedov Message-Id: <20210723100532.27353-2-david@redhat.com> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 4256ad1adb..420c8a48a1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2547,7 +2547,7 @@ S: Maintained F: net/netmap.c Host Memory Backends -M: Eduardo Habkost +M: David Hildenbrand M: Igor Mammedov S: Maintained F: backends/hostmem*.c From 07b315ba92f508cd63ca0adeab58fbb13d0b5585 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 23 Jul 2021 12:05:31 +0200 Subject: [PATCH 310/531] MAINTAINERS: Add Peter Xu and myself as co-maintainer of "Memory API" Peter and myself volunteered to help out co-maintaining "Memory API" with Paolo, so let's update the MAINTAINERS file. Cc: Peter Maydell Cc: Paolo Bonzini Cc: Peter Xu Signed-off-by: David Hildenbrand Message-Id: <20210723100532.27353-3-david@redhat.com> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 420c8a48a1..190a90b541 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2452,6 +2452,8 @@ F: tests/tcg/multiarch/gdbstub/ Memory API M: Paolo Bonzini +M: Peter Xu +M: David Hildenbrand S: Supported F: include/exec/ioport.h F: include/exec/memop.h From 9f04dd7f5a3dd6d9a4c34f4882dd1ef0b7936a2f Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 23 Jul 2021 12:05:32 +0200 Subject: [PATCH 311/531] MAINTAINERS: Add memory_mapping.h and memory_mapping.c to "Memory API" Both files logically belong to "Memory API" and are not yet listed anywhere else explicitly. Let's add them to "Memory API". Cc: Peter Maydell Cc: Paolo Bonzini Cc: Peter Xu Signed-off-by: David Hildenbrand Acked-by: Peter Xu Message-Id: <20210723100532.27353-4-david@redhat.com> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 190a90b541..445f7fe2d1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2460,9 +2460,11 @@ F: include/exec/memop.h F: include/exec/memory.h F: include/exec/ram_addr.h F: include/exec/ramblock.h +F: include/sysemu/memory_mapping.h F: softmmu/dma-helpers.c F: softmmu/ioport.c F: softmmu/memory.c +F: softmmu/memory_mapping.c F: softmmu/physmem.c F: include/exec/memory-internal.h F: scripts/coccinelle/memory-region-housekeeping.cocci From eafadbbbac06a8d72baa976f4d3c42b0e5f8cfc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 23 Jul 2021 12:30:51 +0100 Subject: [PATCH 312/531] gitlab: only let pages be published from default branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitLab will happily publish pages generated by the latest CI pipeline from any branch: https://docs.gitlab.com/ee/user/project/pages/introduction.html "Remember that GitLab Pages are by default branch/tag agnostic and their deployment relies solely on what you specify in .gitlab-ci.yml. You can limit the pages job with the only parameter, whenever a new commit is pushed to a branch used specifically for your pages." The current "pages" job is not limited, so it is happily publishing docs content from any branch/tag in qemu.git that gets pushed to. This means we're potentially publishing from the "staging" branch or worse from outdated "stable-NNN" branches This change restricts it to only publish from the default branch in the main repository. For contributor forks, however, we allow it to publish from any branch, since users will have arbitrarily named topic branches in flight at any time. Signed-off-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210723113051.2792799-1-berrange@redhat.com> Signed-off-by: Paolo Bonzini --- .gitlab-ci.d/buildtest.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 89df51517c..80b57b7082 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -663,6 +663,17 @@ build-tools-and-docs-debian: # Prepare for GitLab pages deployment. Anything copied into the # "public" directory will be deployed to $USER.gitlab.io/$PROJECT +# +# GitLab publishes from any branch that triggers a CI pipeline +# +# For the main repo we don't want to publish from 'staging' +# since that content may not be pushed, nor do we wish to +# publish from 'stable-NNN' branches as that content is outdated. +# Thus we restrict to just the default branch +# +# For contributor forks we want to publish from any repo so +# that users can see the results of their commits, regardless +# of what topic branch they're currently using pages: image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:latest stage: test @@ -681,3 +692,10 @@ pages: artifacts: paths: - public + rules: + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' + when: on_success + - if: '$CI_PROJECT_NAMESPACE == "qemu-project"' + when: never + - if: '$CI_PROJECT_NAMESPACE != "qemu-project"' + when: on_success From 18fa3ebc45262cebc7c9f0ba6f717452bdc51db7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 18 Jul 2021 08:49:22 +0200 Subject: [PATCH 313/531] qapi: introduce forwarding visitor This new adaptor visitor takes a single field of the adaptee, and exposes it with a different name. This will be used for QOM alias properties. Alias targets can of course have a different name than the alias property itself (e.g. a machine's pflash0 might be an alias of a property named 'drive'). When the target's getter or setter invokes the visitor, it will use a different name than what the caller expects, and the visitor will not be able to find it (or will consume erroneously). The solution is for alias getters and setters to wrap the incoming visitor, and forward the sole field that the target is expecting while renaming it appropriately. Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini --- include/qapi/forward-visitor.h | 27 +++ qapi/meson.build | 1 + qapi/qapi-forward-visitor.c | 326 ++++++++++++++++++++++++++++++ tests/unit/meson.build | 1 + tests/unit/test-forward-visitor.c | 197 ++++++++++++++++++ 5 files changed, 552 insertions(+) create mode 100644 include/qapi/forward-visitor.h create mode 100644 qapi/qapi-forward-visitor.c create mode 100644 tests/unit/test-forward-visitor.c diff --git a/include/qapi/forward-visitor.h b/include/qapi/forward-visitor.h new file mode 100644 index 0000000000..50fb3e9d50 --- /dev/null +++ b/include/qapi/forward-visitor.h @@ -0,0 +1,27 @@ +/* + * Forwarding visitor + * + * Copyright Red Hat, Inc. 2021 + * + * Author: Paolo Bonzini + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef FORWARD_VISITOR_H +#define FORWARD_VISITOR_H + +#include "qapi/visitor.h" + +typedef struct ForwardFieldVisitor ForwardFieldVisitor; + +/* + * The forwarding visitor only expects a single name, @from, to be passed for + * toplevel fields. It is converted to @to and forwarded to the @target visitor. + * Calls within a struct are forwarded without changing the name. + */ +Visitor *visitor_forward_field(Visitor *target, const char *from, const char *to); + +#endif diff --git a/qapi/meson.build b/qapi/meson.build index 376f4ceafe..c356a385e3 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -2,6 +2,7 @@ util_ss.add(files( 'opts-visitor.c', 'qapi-clone-visitor.c', 'qapi-dealloc-visitor.c', + 'qapi-forward-visitor.c', 'qapi-util.c', 'qapi-visit-core.c', 'qobject-input-visitor.c', diff --git a/qapi/qapi-forward-visitor.c b/qapi/qapi-forward-visitor.c new file mode 100644 index 0000000000..a4b111e22a --- /dev/null +++ b/qapi/qapi-forward-visitor.c @@ -0,0 +1,326 @@ +/* + * Forward Visitor + * + * Copyright (C) 2021 Red Hat, Inc. + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/compat-policy.h" +#include "qapi/error.h" +#include "qapi/forward-visitor.h" +#include "qapi/visitor-impl.h" +#include "qemu/queue.h" +#include "qapi/qmp/qjson.h" +#include "qapi/qmp/qbool.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qerror.h" +#include "qapi/qmp/qlist.h" +#include "qapi/qmp/qnull.h" +#include "qapi/qmp/qnum.h" +#include "qapi/qmp/qstring.h" +#include "qemu/cutils.h" +#include "qemu/option.h" + +struct ForwardFieldVisitor { + Visitor visitor; + + Visitor *target; + char *from; + char *to; + + int depth; +}; + +static ForwardFieldVisitor *to_ffv(Visitor *v) +{ + return container_of(v, ForwardFieldVisitor, visitor); +} + +static bool forward_field_translate_name(ForwardFieldVisitor *v, const char **name, + Error **errp) +{ + if (v->depth) { + return true; + } + if (g_str_equal(*name, v->from)) { + *name = v->to; + return true; + } + error_setg(errp, QERR_MISSING_PARAMETER, *name); + return false; +} + +static bool forward_field_check_struct(Visitor *v, Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + return visit_check_struct(ffv->target, errp); +} + +static bool forward_field_start_struct(Visitor *v, const char *name, void **obj, + size_t size, Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, errp)) { + return false; + } + if (!visit_start_struct(ffv->target, name, obj, size, errp)) { + return false; + } + ffv->depth++; + return true; +} + +static void forward_field_end_struct(Visitor *v, void **obj) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + assert(ffv->depth); + ffv->depth--; + visit_end_struct(ffv->target, obj); +} + +static bool forward_field_start_list(Visitor *v, const char *name, + GenericList **list, size_t size, + Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, errp)) { + return false; + } + ffv->depth++; + return visit_start_list(ffv->target, name, list, size, errp); +} + +static GenericList *forward_field_next_list(Visitor *v, GenericList *tail, + size_t size) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + assert(ffv->depth); + return visit_next_list(ffv->target, tail, size); +} + +static bool forward_field_check_list(Visitor *v, Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + assert(ffv->depth); + return visit_check_list(ffv->target, errp); +} + +static void forward_field_end_list(Visitor *v, void **obj) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + assert(ffv->depth); + ffv->depth--; + visit_end_list(ffv->target, obj); +} + +static bool forward_field_start_alternate(Visitor *v, const char *name, + GenericAlternate **obj, size_t size, + Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, errp)) { + return false; + } + /* + * The name passed to start_alternate is used also in the visit_type_* calls + * that retrieve the alternate's content; so, do not increase depth here. + */ + return visit_start_alternate(ffv->target, name, obj, size, errp); +} + +static void forward_field_end_alternate(Visitor *v, void **obj) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + visit_end_alternate(ffv->target, obj); +} + +static bool forward_field_type_int64(Visitor *v, const char *name, int64_t *obj, + Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, errp)) { + return false; + } + return visit_type_int64(ffv->target, name, obj, errp); +} + +static bool forward_field_type_uint64(Visitor *v, const char *name, + uint64_t *obj, Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, errp)) { + return false; + } + return visit_type_uint64(ffv->target, name, obj, errp); +} + +static bool forward_field_type_bool(Visitor *v, const char *name, bool *obj, + Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, errp)) { + return false; + } + return visit_type_bool(ffv->target, name, obj, errp); +} + +static bool forward_field_type_str(Visitor *v, const char *name, char **obj, + Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, errp)) { + return false; + } + return visit_type_str(ffv->target, name, obj, errp); +} + +static bool forward_field_type_size(Visitor *v, const char *name, uint64_t *obj, + Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, errp)) { + return false; + } + return visit_type_size(ffv->target, name, obj, errp); +} + +static bool forward_field_type_number(Visitor *v, const char *name, double *obj, + Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, errp)) { + return false; + } + return visit_type_number(ffv->target, name, obj, errp); +} + +static bool forward_field_type_any(Visitor *v, const char *name, QObject **obj, + Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, errp)) { + return false; + } + return visit_type_any(ffv->target, name, obj, errp); +} + +static bool forward_field_type_null(Visitor *v, const char *name, + QNull **obj, Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, errp)) { + return false; + } + return visit_type_null(ffv->target, name, obj, errp); +} + +static void forward_field_optional(Visitor *v, const char *name, bool *present) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, NULL)) { + *present = false; + return; + } + visit_optional(ffv->target, name, present); +} + +static bool forward_field_deprecated_accept(Visitor *v, const char *name, + Error **errp) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, errp)) { + return false; + } + return visit_deprecated_accept(ffv->target, name, errp); +} + +static bool forward_field_deprecated(Visitor *v, const char *name) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + if (!forward_field_translate_name(ffv, &name, NULL)) { + return false; + } + return visit_deprecated(ffv->target, name); +} + +static void forward_field_complete(Visitor *v, void *opaque) +{ + /* + * Do nothing, the complete method will be called in due time + * on the target visitor. + */ +} + +static void forward_field_free(Visitor *v) +{ + ForwardFieldVisitor *ffv = to_ffv(v); + + g_free(ffv->from); + g_free(ffv->to); + g_free(ffv); +} + +Visitor *visitor_forward_field(Visitor *target, const char *from, const char *to) +{ + ForwardFieldVisitor *v = g_new0(ForwardFieldVisitor, 1); + + /* + * Clone and dealloc visitors don't use a name for the toplevel + * visit, so they make no sense here. + */ + assert(target->type == VISITOR_OUTPUT || target->type == VISITOR_INPUT); + + v->visitor.type = target->type; + v->visitor.start_struct = forward_field_start_struct; + v->visitor.check_struct = forward_field_check_struct; + v->visitor.end_struct = forward_field_end_struct; + v->visitor.start_list = forward_field_start_list; + v->visitor.next_list = forward_field_next_list; + v->visitor.check_list = forward_field_check_list; + v->visitor.end_list = forward_field_end_list; + v->visitor.start_alternate = forward_field_start_alternate; + v->visitor.end_alternate = forward_field_end_alternate; + v->visitor.type_int64 = forward_field_type_int64; + v->visitor.type_uint64 = forward_field_type_uint64; + v->visitor.type_size = forward_field_type_size; + v->visitor.type_bool = forward_field_type_bool; + v->visitor.type_str = forward_field_type_str; + v->visitor.type_number = forward_field_type_number; + v->visitor.type_any = forward_field_type_any; + v->visitor.type_null = forward_field_type_null; + v->visitor.optional = forward_field_optional; + v->visitor.deprecated_accept = forward_field_deprecated_accept; + v->visitor.deprecated = forward_field_deprecated; + v->visitor.complete = forward_field_complete; + v->visitor.free = forward_field_free; + + v->target = target; + v->from = g_strdup(from); + v->to = g_strdup(to); + + return &v->visitor; +} diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 3e0504dd21..5736d285b2 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -14,6 +14,7 @@ tests = { 'test-qobject-output-visitor': [testqapi], 'test-clone-visitor': [testqapi], 'test-qobject-input-visitor': [testqapi], + 'test-forward-visitor': [testqapi], 'test-string-input-visitor': [testqapi], 'test-string-output-visitor': [testqapi], 'test-opts-visitor': [testqapi], diff --git a/tests/unit/test-forward-visitor.c b/tests/unit/test-forward-visitor.c new file mode 100644 index 0000000000..348f7e4e81 --- /dev/null +++ b/tests/unit/test-forward-visitor.c @@ -0,0 +1,197 @@ +/* + * QAPI Forwarding Visitor unit-tests. + * + * Copyright (C) 2021 Red Hat Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" + +#include "qemu-common.h" +#include "qapi/forward-visitor.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/error.h" +#include "qapi/qmp/qobject.h" +#include "qapi/qmp/qdict.h" +#include "test-qapi-visit.h" +#include "qemu/option.h" + +typedef bool GenericVisitor (Visitor *, const char *, void **, Error **); +#define CAST_VISIT_TYPE(fn) ((GenericVisitor *)(fn)) + +/* + * Parse @srcstr and wrap it with a ForwardFieldVisitor converting "src" to + * "dst". Check that visiting the result with "src" name fails, and return + * the result of visiting "dst". + */ +static void *visit_with_forward(const char *srcstr, GenericVisitor *fn) +{ + bool help = false; + QDict *src = keyval_parse(srcstr, NULL, &help, &error_abort); + Visitor *v, *alias_v; + Error *err = NULL; + void *result = NULL; + + v = qobject_input_visitor_new_keyval(QOBJECT(src)); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + + alias_v = visitor_forward_field(v, "dst", "src"); + fn(alias_v, "src", &result, &err); + error_free_or_abort(&err); + assert(!result); + fn(alias_v, "dst", &result, &err); + assert(err == NULL); + visit_free(alias_v); + + visit_end_struct(v, NULL); + visit_free(v); + qobject_unref(QOBJECT(src)); + return result; +} + +static void test_forward_any(void) +{ + QObject *src = visit_with_forward("src.integer=42,src.string=Hello,src.enum1=value2", + CAST_VISIT_TYPE(visit_type_any)); + Visitor *v = qobject_input_visitor_new_keyval(src); + Error *err = NULL; + UserDefOne *dst; + + visit_type_UserDefOne(v, NULL, &dst, &err); + assert(err == NULL); + visit_free(v); + + g_assert_cmpint(dst->integer, ==, 42); + g_assert_cmpstr(dst->string, ==, "Hello"); + g_assert_cmpint(dst->has_enum1, ==, true); + g_assert_cmpint(dst->enum1, ==, ENUM_ONE_VALUE2); + qapi_free_UserDefOne(dst); + qobject_unref(QOBJECT(src)); +} + +static void test_forward_size(void) +{ + /* + * visit_type_size does not return a pointer, so visit_with_forward + * cannot be used. + */ + bool help = false; + QDict *src = keyval_parse("src=1.5M", NULL, &help, &error_abort); + Visitor *v, *alias_v; + Error *err = NULL; + uint64_t result = 0; + + v = qobject_input_visitor_new_keyval(QOBJECT(src)); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + + alias_v = visitor_forward_field(v, "dst", "src"); + visit_type_size(alias_v, "src", &result, &err); + error_free_or_abort(&err); + visit_type_size(alias_v, "dst", &result, &err); + assert(result == 3 << 19); + assert(err == NULL); + visit_free(alias_v); + + visit_end_struct(v, NULL); + visit_free(v); + qobject_unref(QOBJECT(src)); +} + +static void test_forward_number(void) +{ + /* + * visit_type_number does not return a pointer, so visit_with_forward + * cannot be used. + */ + bool help = false; + QDict *src = keyval_parse("src=1.5", NULL, &help, &error_abort); + Visitor *v, *alias_v; + Error *err = NULL; + double result = 0.0; + + v = qobject_input_visitor_new_keyval(QOBJECT(src)); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + + alias_v = visitor_forward_field(v, "dst", "src"); + visit_type_number(alias_v, "src", &result, &err); + error_free_or_abort(&err); + visit_type_number(alias_v, "dst", &result, &err); + assert(result == 1.5); + assert(err == NULL); + visit_free(alias_v); + + visit_end_struct(v, NULL); + visit_free(v); + qobject_unref(QOBJECT(src)); +} + +static void test_forward_string(void) +{ + char *dst = visit_with_forward("src=Hello", + CAST_VISIT_TYPE(visit_type_str)); + + g_assert_cmpstr(dst, ==, "Hello"); + g_free(dst); +} + +static void test_forward_struct(void) +{ + UserDefOne *dst = visit_with_forward("src.integer=42,src.string=Hello", + CAST_VISIT_TYPE(visit_type_UserDefOne)); + + g_assert_cmpint(dst->integer, ==, 42); + g_assert_cmpstr(dst->string, ==, "Hello"); + g_assert_cmpint(dst->has_enum1, ==, false); + qapi_free_UserDefOne(dst); +} + +static void test_forward_alternate(void) +{ + AltStrObj *s_dst = visit_with_forward("src=hello", + CAST_VISIT_TYPE(visit_type_AltStrObj)); + AltStrObj *o_dst = visit_with_forward("src.integer=42,src.boolean=true,src.string=world", + CAST_VISIT_TYPE(visit_type_AltStrObj)); + + g_assert_cmpint(s_dst->type, ==, QTYPE_QSTRING); + g_assert_cmpstr(s_dst->u.s, ==, "hello"); + g_assert_cmpint(o_dst->type, ==, QTYPE_QDICT); + g_assert_cmpint(o_dst->u.o.integer, ==, 42); + g_assert_cmpint(o_dst->u.o.boolean, ==, true); + g_assert_cmpstr(o_dst->u.o.string, ==, "world"); + + qapi_free_AltStrObj(s_dst); + qapi_free_AltStrObj(o_dst); +} + +static void test_forward_list(void) +{ + uint8List *dst = visit_with_forward("src.0=1,src.1=2,src.2=3,src.3=4", + CAST_VISIT_TYPE(visit_type_uint8List)); + uint8List *tmp; + int i; + + for (tmp = dst, i = 1; i <= 4; i++) { + g_assert(tmp); + g_assert_cmpint(tmp->value, ==, i); + tmp = tmp->next; + } + g_assert(!tmp); + qapi_free_uint8List(dst); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/visitor/forward/struct", test_forward_struct); + g_test_add_func("/visitor/forward/alternate", test_forward_alternate); + g_test_add_func("/visitor/forward/string", test_forward_string); + g_test_add_func("/visitor/forward/size", test_forward_size); + g_test_add_func("/visitor/forward/number", test_forward_number); + g_test_add_func("/visitor/forward/any", test_forward_any); + g_test_add_func("/visitor/forward/list", test_forward_list); + + return g_test_run(); +} From cbc94d9702882128c52b72b252b8eb775b0e73af Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 18 Jul 2021 08:50:44 +0200 Subject: [PATCH 314/531] qom: use correct field name when getting/setting alias properties Alias targets have a different name than the alias property itself (e.g. a machine's pflash0 might be an alias of a property named 'drive'). When the target's getter or setter invokes the visitor, it will use a different name than what the caller expects, and the visitor will not be able to find it (or will consume erroneously). The solution is for alias getters and setters to wrap the incoming visitor, and forward the sole field that the target is expecting while renaming it appropriately. This bug has been there forever, but it was exposed after -M parsing switched from QemuOptions and StringInputVisitor to keyval and QObjectInputVisitor. Before, the visitor ignored the name. Now, it checks "drive" against what was passed on the command line and finds that no such property exists. Fixes: https://gitlab.com/qemu-project/qemu/-/issues/484 Reported-by: Alex Williamson Signed-off-by: Paolo Bonzini --- qom/object.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/qom/object.c b/qom/object.c index 6a01d56546..e86cb05b84 100644 --- a/qom/object.c +++ b/qom/object.c @@ -20,6 +20,7 @@ #include "qapi/string-input-visitor.h" #include "qapi/string-output-visitor.h" #include "qapi/qobject-input-visitor.h" +#include "qapi/forward-visitor.h" #include "qapi/qapi-builtin-visit.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qjson.h" @@ -2683,16 +2684,20 @@ static void property_get_alias(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { AliasProperty *prop = opaque; + Visitor *alias_v = visitor_forward_field(v, prop->target_name, name); - object_property_get(prop->target_obj, prop->target_name, v, errp); + object_property_get(prop->target_obj, prop->target_name, alias_v, errp); + visit_free(alias_v); } static void property_set_alias(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { AliasProperty *prop = opaque; + Visitor *alias_v = visitor_forward_field(v, prop->target_name, name); - object_property_set(prop->target_obj, prop->target_name, v, errp); + object_property_set(prop->target_obj, prop->target_name, alias_v, errp); + visit_free(alias_v); } static Object *property_resolve_alias(Object *obj, void *opaque, From 6e52aafbac1d9f4eaa465ab4ec5d4327f2430832 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 21 Jul 2021 00:26:35 +0100 Subject: [PATCH 315/531] gitignore: Update with some filetypes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update .gitignore to ignore .swp and .patch files. Signed-off-by: Viresh Kumar Signed-off-by: Alex Bennée Reviewed-by: Alex Bennée Message-Id: <79262dbe1f7888eb02e1911501eebafa6f2f6400.1616583806.git.viresh.kumar@linaro.org> Message-Id: <20210720232703.10650-2-alex.bennee@linaro.org> --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 75a4be0724..eb2553026c 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ GTAGS *~ *.ast_raw *.depend_raw +*.swp +*.patch From 189c099f75f39da1c1a0f3e527109af2b169a8fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:36 +0100 Subject: [PATCH 316/531] docs: collect the disparate device emulation docs into one section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While we are at it add a brief preamble that explains some of the common concepts in QEMU's device emulation which will hopefully lead to less confusing about our dizzying command line options. Signed-off-by: Alex Bennée Reviewed-by: Markus Armbruster Cc: Paolo Bonzini Cc: Daniel P. Berrangé Cc: Eduardo Habkost Message-Id: <20210720232703.10650-3-alex.bennee@linaro.org> --- docs/system/device-emulation.rst | 89 +++++++++++++++++++++++ docs/system/{ => devices}/ivshmem.rst | 0 docs/system/{ => devices}/net.rst | 0 docs/system/{ => devices}/nvme.rst | 0 docs/system/{ => devices}/usb.rst | 0 docs/system/{ => devices}/virtio-pmem.rst | 0 docs/system/index.rst | 6 +- 7 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 docs/system/device-emulation.rst rename docs/system/{ => devices}/ivshmem.rst (100%) rename docs/system/{ => devices}/net.rst (100%) rename docs/system/{ => devices}/nvme.rst (100%) rename docs/system/{ => devices}/usb.rst (100%) rename docs/system/{ => devices}/virtio-pmem.rst (100%) diff --git a/docs/system/device-emulation.rst b/docs/system/device-emulation.rst new file mode 100644 index 0000000000..8adf05f606 --- /dev/null +++ b/docs/system/device-emulation.rst @@ -0,0 +1,89 @@ +.. _device-emulation: + +Device Emulation +---------------- + +QEMU supports the emulation of a large number of devices from +peripherals such network cards and USB devices to integrated systems +on a chip (SoCs). Configuration of these is often a source of +confusion so it helps to have an understanding of some of the terms +used to describes devices within QEMU. + +Common Terms +~~~~~~~~~~~~ + +Device Front End +================ + +A device front end is how a device is presented to the guest. The type +of device presented should match the hardware that the guest operating +system is expecting to see. All devices can be specified with the +``--device`` command line option. Running QEMU with the command line +options ``--device help`` will list all devices it is aware of. Using +the command line ``--device foo,help`` will list the additional +configuration options available for that device. + +A front end is often paired with a back end, which describes how the +host's resources are used in the emulation. + +Device Buses +============ + +Most devices will exist on a BUS of some sort. Depending on the +machine model you choose (``-M foo``) a number of buses will have been +automatically created. In most cases the BUS a device is attached to +can be inferred, for example PCI devices are generally automatically +allocated to the next free address of first PCI bus found. However in +complicated configurations you can explicitly specify what bus +(``bus=ID``) a device is attached to along with its address +(``addr=N``). + +Some devices, for example a PCI SCSI host controller, will add an +additional buses to the system that other devices can be attached to. +A hypothetical chain of devices might look like: + + --device foo,bus=pci.0,addr=0,id=foo + --device bar,bus=foo.0,addr=1,id=baz + +which would be a bar device (with the ID of baz) which is attached to +the first foo bus (foo.0) at address 1. The foo device which provides +that bus is itself is attached to the first PCI bus (pci.0). + + +Device Back End +=============== + +The back end describes how the data from the emulated device will be +processed by QEMU. The configuration of the back end is usually +specific to the class of device being emulated. For example serial +devices will be backed by a ``--chardev`` which can redirect the data +to a file or socket or some other system. Storage devices are handled +by ``--blockdev`` which will specify how blocks are handled, for +example being stored in a qcow2 file or accessing a raw host disk +partition. Back ends can sometimes be stacked to implement features +like snapshots. + +While the choice of back end is generally transparent to the guest, +there are cases where features will not be reported to the guest if +the back end is unable to support it. + +Device Pass Through +=================== + +Device pass through is where the device is actually given access to +the underlying hardware. This can be as simple as exposing a single +USB device on the host system to the guest or dedicating a video card +in a PCI slot to the exclusive use of the guest. + + +Emulated Devices +~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + devices/ivshmem.rst + devices/net.rst + devices/nvme.rst + devices/usb.rst + devices/virtio-pmem.rst diff --git a/docs/system/ivshmem.rst b/docs/system/devices/ivshmem.rst similarity index 100% rename from docs/system/ivshmem.rst rename to docs/system/devices/ivshmem.rst diff --git a/docs/system/net.rst b/docs/system/devices/net.rst similarity index 100% rename from docs/system/net.rst rename to docs/system/devices/net.rst diff --git a/docs/system/nvme.rst b/docs/system/devices/nvme.rst similarity index 100% rename from docs/system/nvme.rst rename to docs/system/devices/nvme.rst diff --git a/docs/system/usb.rst b/docs/system/devices/usb.rst similarity index 100% rename from docs/system/usb.rst rename to docs/system/devices/usb.rst diff --git a/docs/system/virtio-pmem.rst b/docs/system/devices/virtio-pmem.rst similarity index 100% rename from docs/system/virtio-pmem.rst rename to docs/system/devices/virtio-pmem.rst diff --git a/docs/system/index.rst b/docs/system/index.rst index fda4b1b705..64a424ae99 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -11,15 +11,12 @@ or Hypervisor.Framework. quickstart invocation + device-emulation keys mux-chardev monitor images - net virtio-net-failover - usb - nvme - ivshmem linuxboot generic-loader guest-loader @@ -30,7 +27,6 @@ or Hypervisor.Framework. gdb managed-startup cpu-hotplug - virtio-pmem pr-manager targets security From 15d9c3cef108f34874200785bf9970bf77dc378b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:37 +0100 Subject: [PATCH 317/531] docs: add a section on the generalities of vhost-user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While we do mention some of this stuff in the various daemons and manuals the subtleties of the socket and memory sharing are sometimes missed. This document attempts to give some background on vhost-user daemons in general terms. Signed-off-by: Alex Bennée Reviewed-by: Stefan Hajnoczi Message-Id: <20210720232703.10650-4-alex.bennee@linaro.org> --- docs/interop/vhost-user.rst | 2 + docs/system/device-emulation.rst | 1 + docs/system/devices/vhost-user.rst | 59 ++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 docs/system/devices/vhost-user.rst diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index d6085f7045..7fc693521e 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -1,3 +1,5 @@ +.. _vhost_user_proto: + =================== Vhost-user Protocol =================== diff --git a/docs/system/device-emulation.rst b/docs/system/device-emulation.rst index 8adf05f606..7afcfd8064 100644 --- a/docs/system/device-emulation.rst +++ b/docs/system/device-emulation.rst @@ -86,4 +86,5 @@ Emulated Devices devices/net.rst devices/nvme.rst devices/usb.rst + devices/vhost-user.rst devices/virtio-pmem.rst diff --git a/docs/system/devices/vhost-user.rst b/docs/system/devices/vhost-user.rst new file mode 100644 index 0000000000..86128114fa --- /dev/null +++ b/docs/system/devices/vhost-user.rst @@ -0,0 +1,59 @@ +.. _vhost_user: + +vhost-user back ends +-------------------- + +vhost-user back ends are way to service the request of VirtIO devices +outside of QEMU itself. To do this there are a number of things +required. + +vhost-user device +=================== + +These are simple stub devices that ensure the VirtIO device is visible +to the guest. The code is mostly boilerplate although each device has +a ``chardev`` option which specifies the ID of the ``--chardev`` +device that connects via a socket to the vhost-user *daemon*. + +vhost-user daemon +================= + +This is a separate process that is connected to by QEMU via a socket +following the :ref:`vhost_user_proto`. There are a number of daemons +that can be built when enabled by the project although any daemon that +meets the specification for a given device can be used. + +Shared memory object +==================== + +In order for the daemon to access the VirtIO queues to process the +requests it needs access to the guest's address space. This is +achieved via the ``memory-backend-file`` or ``memory-backend-memfd`` +objects. A reference to a file-descriptor which can access this object +will be passed via the socket as part of the protocol negotiation. + +Currently the shared memory object needs to match the size of the main +system memory as defined by the ``-m`` argument. + +Example +======= + +First start you daemon. + +.. parsed-literal:: + + $ virtio-foo --socket-path=/var/run/foo.sock $OTHER_ARGS + +The you start your QEMU instance specifying the device, chardev and +memory objects. + +.. parsed-literal:: + + $ |qemu_system| \\ + -m 4096 \\ + -chardev socket,id=ba1,path=/var/run/foo.sock \\ + -device vhost-user-foo,chardev=ba1,$OTHER_ARGS \\ + -object memory-backend-memfd,id=mem,size=4G,share=on \\ + -numa node,memdev=mem \\ + ... + From 11bdcfcdd2ccad91dc3076c7de30803f32f7cdde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:38 +0100 Subject: [PATCH 318/531] configure: remove needless if leg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was pointed out in review of the previous patch that the if leg isn't needed as the for loop will not enter on an empty $device_archs. Fixes: d1d5e9eefd ("configure: allow the selection of alternate config in the build") Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20210720232703.10650-5-alex.bennee@linaro.org> --- configure | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/configure b/configure index 0005cd140d..69cef68861 100755 --- a/configure +++ b/configure @@ -5103,12 +5103,10 @@ if test "$skip_meson" = no; then echo "[properties]" >> $cross # unroll any custom device configs - if test -n "$device_archs"; then - for a in $device_archs; do - eval "c=\$devices_${a}" - echo "${a}-softmmu = '$c'" >> $cross - done - fi + for a in $device_archs; do + eval "c=\$devices_${a}" + echo "${a}-softmmu = '$c'" >> $cross + done test -z "$cxx" && echo "link_language = 'c'" >> $cross echo "[built-in options]" >> $cross From fa3d60953c2d47c9829dd57b3e3900f2f620ce93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:39 +0100 Subject: [PATCH 319/531] contrib/gitdm: add some new aliases to fix up commits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Cc: Yuval Shaia Message-Id: <20210720232703.10650-6-alex.bennee@linaro.org> --- contrib/gitdm/aliases | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/gitdm/aliases b/contrib/gitdm/aliases index c1e744312f..c6ed215e68 100644 --- a/contrib/gitdm/aliases +++ b/contrib/gitdm/aliases @@ -31,6 +31,9 @@ pbrook@c046a42c-6fe2-441c-8c8c-71466251a162 paul@codesourcery.com ths@c046a42c-6fe2-441c-8c8c-71466251a162 ths@networkno.de malc@c046a42c-6fe2-441c-8c8c-71466251a162 av1474@comtv.ru +# some broken tags +yuval.shaia.ml.gmail.com yuval.shaia.ml@gmail.com + # There is also a: # (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162> # for the cvs2svn initialization commit e63c3dc74bf. From 82585a3100286f8fbe08fed763b5229efee9a3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:40 +0100 Subject: [PATCH 320/531] .mailmap: fix up some broken commit authors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: 49a6f3bffb ("target/arm: Correct the encoding of MDCCSR_EL0 and DBGDSCRint") Fixes: 5a07192a04 ("target/i386: Fix handling of k_gs_base register in 32-bit mode in gdbstub") Signed-off-by: Alex Bennée Cc: Nick Hudson Cc: Marek Dolata Message-Id: <20210720232703.10650-7-alex.bennee@linaro.org> --- .mailmap | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.mailmap b/.mailmap index a1bd659817..082ff893ab 100644 --- a/.mailmap +++ b/.mailmap @@ -27,6 +27,10 @@ Paul Brook pbrook ths malc malc +# Corrupted Author fields +Marek Dolata mkdolata@us.ibm.com +Nick Hudson hnick@vmware.com + # There is also a: # (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162> # for the cvs2svn initialization commit e63c3dc74bf. From 0204e6482bcf063c1b5db488b7de8fc1d6bab603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:41 +0100 Subject: [PATCH 321/531] contrib/gitdm: add domain-map for MontaVista MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alex Bennée Acked-by: Corey Minyard Message-Id: <20210720232703.10650-8-alex.bennee@linaro.org> --- contrib/gitdm/domain-map | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/gitdm/domain-map b/contrib/gitdm/domain-map index 0074da618f..efbbb15643 100644 --- a/contrib/gitdm/domain-map +++ b/contrib/gitdm/domain-map @@ -18,6 +18,7 @@ igalia.com Igalia intel.com Intel linaro.org Linaro microsoft.com Microsoft +mvista.com MontaVista nokia.com Nokia nuviainc.com NUVIA oracle.com Oracle From 200a10279e5bace8b918c1fdc02215199e355b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:42 +0100 Subject: [PATCH 322/531] contrib/gitdm: add a group mapping for robot scanners MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This mostly affects Reported-by: tags Signed-off-by: Alex Bennée Message-Id: <20210720232703.10650-9-alex.bennee@linaro.org> --- contrib/gitdm/group-map-robots | 7 +++++++ gitdm.config | 3 +++ 2 files changed, 10 insertions(+) create mode 100644 contrib/gitdm/group-map-robots diff --git a/contrib/gitdm/group-map-robots b/contrib/gitdm/group-map-robots new file mode 100644 index 0000000000..ffd956c2eb --- /dev/null +++ b/contrib/gitdm/group-map-robots @@ -0,0 +1,7 @@ +# +# There are various automatic robots that occasionally scan and report +# bugs. Let's group them together here. +# + +# Euler Robot +euler.robot@huawei.com diff --git a/gitdm.config b/gitdm.config index c01c219078..7378238c20 100644 --- a/gitdm.config +++ b/gitdm.config @@ -43,6 +43,9 @@ GroupMap contrib/gitdm/group-map-janustech Janus Technologies GroupMap contrib/gitdm/group-map-individuals (None) GroupMap contrib/gitdm/group-map-academics Academics (various) +# Group together robots and other auto-reporters +GroupMap contrib/gitdm/group-map-robots Robots (various) + # # # Use FileTypeMap to map a file types to file names using regular From 20ddc8ce9914b1889363ff3e8c8ff6ab72fba6b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:43 +0100 Subject: [PATCH 323/531] gitdm.config: sort the corporate GroupMap entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lets try and keep them that way. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210720232703.10650-10-alex.bennee@linaro.org> --- gitdm.config | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gitdm.config b/gitdm.config index 7378238c20..a3542d2fc7 100644 --- a/gitdm.config +++ b/gitdm.config @@ -28,15 +28,15 @@ EmailMap contrib/gitdm/domain-map # # Use GroupMap to map a file full of addresses to the # same employer. This is used for people that don't post from easily -# identifiable corporate emails. +# identifiable corporate emails. Please keep this list sorted. # -GroupMap contrib/gitdm/group-map-redhat Red Hat -GroupMap contrib/gitdm/group-map-wavecomp Wave Computing GroupMap contrib/gitdm/group-map-cadence Cadence Design Systems GroupMap contrib/gitdm/group-map-codeweavers CodeWeavers GroupMap contrib/gitdm/group-map-ibm IBM GroupMap contrib/gitdm/group-map-janustech Janus Technologies +GroupMap contrib/gitdm/group-map-redhat Red Hat +GroupMap contrib/gitdm/group-map-wavecomp Wave Computing # Also group together our prolific individual contributors # and those working under academic auspices From 44114d3fda3c9b8d43f3af46608b402115dd6030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:44 +0100 Subject: [PATCH 324/531] contrib/gitdm: add domain-map/group-map mappings for Samsung MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minwoo's work from their personal address are treated as personal contributions. Signed-off-by: Alex Bennée Acked-by: Klaus Jensen Cc: Gollu Appalanaidu Cc: Minwoo Im Message-Id: <20210720232703.10650-11-alex.bennee@linaro.org> --- contrib/gitdm/domain-map | 1 + contrib/gitdm/group-map-individuals | 1 + 2 files changed, 2 insertions(+) diff --git a/contrib/gitdm/domain-map b/contrib/gitdm/domain-map index efbbb15643..beeb24341e 100644 --- a/contrib/gitdm/domain-map +++ b/contrib/gitdm/domain-map @@ -26,6 +26,7 @@ proxmox.com Proxmox quicinc.com Qualcomm Innovation Center redhat.com Red Hat rt-rk.com RT-RK +samsung.com Samsung siemens.com Siemens sifive.com SiFive suse.com SUSE diff --git a/contrib/gitdm/group-map-individuals b/contrib/gitdm/group-map-individuals index 36bbb77c39..4ac2f98823 100644 --- a/contrib/gitdm/group-map-individuals +++ b/contrib/gitdm/group-map-individuals @@ -29,3 +29,4 @@ mrolnik@gmail.com huth@tuxfamily.org jhogan@kernel.org atar4qemu@gmail.com +minwoo.im.dev@gmail.com From 061a20d50a330ccd4d865513075deac25979067e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:45 +0100 Subject: [PATCH 325/531] contrib/gitdm: add domain-map for Eldorado MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Luis acked on IRC: #qemu@znc-oftc_2021-07-13.txt:[15:00:02] stsquad: "eldorado.org.br Eldorado" is fine Signed-off-by: Alex Bennée Acked-by: Luis Pires Message-Id: <20210720232703.10650-12-alex.bennee@linaro.org> --- contrib/gitdm/domain-map | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/gitdm/domain-map b/contrib/gitdm/domain-map index beeb24341e..41875c9e75 100644 --- a/contrib/gitdm/domain-map +++ b/contrib/gitdm/domain-map @@ -9,6 +9,7 @@ baidu.com Baidu bytedance.com ByteDance cmss.chinamobile.com China Mobile citrix.com Citrix +eldorado.org.br Instituto de Pesquisas Eldorado fujitsu.com Fujitsu google.com Google greensocs.com GreenSocs From 0e7933e31478519ba5d46a06d4a0f3ba31882f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:46 +0100 Subject: [PATCH 326/531] contrib/gitdm: add domain-map/group-map for Wind River MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As per discussion at: http://patchwork.ozlabs.org/project/qemu-devel/patch/20201004180443.2035359-19-f4bug@amsat.org/ I've added Bin's personal email as an individual contributor. Signed-off-by: Alex Bennée Acked-by: Bin Meng Cc: Ruimei Yan Cc: Xuzhou Cheng Message-Id: <20210720232703.10650-13-alex.bennee@linaro.org> --- contrib/gitdm/domain-map | 1 + contrib/gitdm/group-map-individuals | 1 + 2 files changed, 2 insertions(+) diff --git a/contrib/gitdm/domain-map b/contrib/gitdm/domain-map index 41875c9e75..27b8fbdf8a 100644 --- a/contrib/gitdm/domain-map +++ b/contrib/gitdm/domain-map @@ -34,6 +34,7 @@ suse.com SUSE suse.de SUSE virtuozzo.com Virtuozzo wdc.com Western Digital +windriver.com Wind River xilinx.com Xilinx yadro.com YADRO yandex-team.ru Yandex diff --git a/contrib/gitdm/group-map-individuals b/contrib/gitdm/group-map-individuals index 4ac2f98823..9b6406e624 100644 --- a/contrib/gitdm/group-map-individuals +++ b/contrib/gitdm/group-map-individuals @@ -30,3 +30,4 @@ huth@tuxfamily.org jhogan@kernel.org atar4qemu@gmail.com minwoo.im.dev@gmail.com +bmeng.cn@gmail.com From a8d1095a10114e339665eef601ba615b6b673444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:47 +0100 Subject: [PATCH 327/531] contrib/gitdm: un-ironically add a mapping for LWN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I think this mainly comes from kernel-doc stuff imported into the QEMU tree. Signed-off-by: Alex Bennée Cc: Jonathan Corbet Message-Id: <20210720232703.10650-14-alex.bennee@linaro.org> --- contrib/gitdm/domain-map | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/gitdm/domain-map b/contrib/gitdm/domain-map index 27b8fbdf8a..5ac8288716 100644 --- a/contrib/gitdm/domain-map +++ b/contrib/gitdm/domain-map @@ -18,6 +18,7 @@ ibm.com IBM igalia.com Igalia intel.com Intel linaro.org Linaro +lwn.net LWN microsoft.com Microsoft mvista.com MontaVista nokia.com Nokia From 3d4fcf4200f6b8957e4b3a64082b1f820279a476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:48 +0100 Subject: [PATCH 328/531] contrib/gitdm: add domain-map for Crudebyte MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alex Bennée Reviewed-by: Christian Schoenebeck Message-Id: <20210720232703.10650-15-alex.bennee@linaro.org> --- contrib/gitdm/domain-map | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/gitdm/domain-map b/contrib/gitdm/domain-map index 5ac8288716..e42861cd11 100644 --- a/contrib/gitdm/domain-map +++ b/contrib/gitdm/domain-map @@ -9,6 +9,7 @@ baidu.com Baidu bytedance.com ByteDance cmss.chinamobile.com China Mobile citrix.com Citrix +crudebyte.com Crudebyte eldorado.org.br Instituto de Pesquisas Eldorado fujitsu.com Fujitsu google.com Google From efe2165a0f0a92c1b9fb8d42f41dfccd2cfddd83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:49 +0100 Subject: [PATCH 329/531] contrib/gitdm: add domain-map for NVIDIA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alex Bennée Reviewed-by: Kirti Wankhede Cc: Yishai Hadas Message-Id: <20210720232703.10650-16-alex.bennee@linaro.org> --- contrib/gitdm/domain-map | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/gitdm/domain-map b/contrib/gitdm/domain-map index e42861cd11..2800d9f986 100644 --- a/contrib/gitdm/domain-map +++ b/contrib/gitdm/domain-map @@ -24,6 +24,7 @@ microsoft.com Microsoft mvista.com MontaVista nokia.com Nokia nuviainc.com NUVIA +nvidia.com NVIDIA oracle.com Oracle proxmox.com Proxmox quicinc.com Qualcomm Innovation Center From e061e481a63305365816c63a16ec314fc92ac856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:50 +0100 Subject: [PATCH 330/531] contrib/gitdm: add group-map for Netflix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Warner confirmed he works for Netflix on IRC. Signed-off-by: Alex Bennée Reviewed-by: Warner Losh Message-Id: <20210720232703.10650-17-alex.bennee@linaro.org> --- contrib/gitdm/group-map-netflix | 5 +++++ gitdm.config | 1 + 2 files changed, 6 insertions(+) create mode 100644 contrib/gitdm/group-map-netflix diff --git a/contrib/gitdm/group-map-netflix b/contrib/gitdm/group-map-netflix new file mode 100644 index 0000000000..468f95dcb2 --- /dev/null +++ b/contrib/gitdm/group-map-netflix @@ -0,0 +1,5 @@ +# +# Netflix contributors using their personal emails +# + +imp@bsdimp.com diff --git a/gitdm.config b/gitdm.config index a3542d2fc7..5d5e70fe5f 100644 --- a/gitdm.config +++ b/gitdm.config @@ -35,6 +35,7 @@ GroupMap contrib/gitdm/group-map-cadence Cadence Design Systems GroupMap contrib/gitdm/group-map-codeweavers CodeWeavers GroupMap contrib/gitdm/group-map-ibm IBM GroupMap contrib/gitdm/group-map-janustech Janus Technologies +GroupMap contrib/gitdm/group-map-netflix Netflix GroupMap contrib/gitdm/group-map-redhat Red Hat GroupMap contrib/gitdm/group-map-wavecomp Wave Computing From a7659cd675c4c8fc59818008ad57e0f3dee5f148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:51 +0100 Subject: [PATCH 331/531] contrib/gitdm: add an explicit academic entry for BU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some reason Alexander's contributions were not getting grouped from the plain "edu" mapping. Signed-off-by: Alex Bennée Reviewed-by: Alexander Bulekov Message-Id: <20210720232703.10650-18-alex.bennee@linaro.org> --- contrib/gitdm/group-map-academics | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/gitdm/group-map-academics b/contrib/gitdm/group-map-academics index bf3c894821..44745ca85b 100644 --- a/contrib/gitdm/group-map-academics +++ b/contrib/gitdm/group-map-academics @@ -16,3 +16,6 @@ cota@braap.org uni-paderborn.de edu edu.cn + +# Boston University +bu.edu From a10f373de4e983d7fc91db5733ff08e9ce30b248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:52 +0100 Subject: [PATCH 332/531] contrib/gitdm: add a new interns group-map for GSoC/Outreachy work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It makes sense to put our various interns in a group so we can see the overall impact of GSoC and Outreachy on the project. Signed-off-by: Alex Bennée Reviewed-by: Mahmoud Mandour Cc: Ahmed Karaman Cc: César Belley Message-Id: <20210720232703.10650-19-alex.bennee@linaro.org> --- contrib/gitdm/group-map-interns | 13 +++++++++++++ gitdm.config | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 contrib/gitdm/group-map-interns diff --git a/contrib/gitdm/group-map-interns b/contrib/gitdm/group-map-interns new file mode 100644 index 0000000000..fe33a3231e --- /dev/null +++ b/contrib/gitdm/group-map-interns @@ -0,0 +1,13 @@ +# +# Group together everyone working as an intern via one of the various +# outreach programs. +# + +# GSoC 2020 Virtual FIDO/U2F security key +cesar.belley@lse.epita.fr + +# GSoC 2020 TCG performance +ahmedkhaledkaraman@gmail.com + +# GSoC 2021 TCG plugins +ma.mandourr@gmail.com diff --git a/gitdm.config b/gitdm.config index 5d5e70fe5f..288b100d89 100644 --- a/gitdm.config +++ b/gitdm.config @@ -40,9 +40,10 @@ GroupMap contrib/gitdm/group-map-redhat Red Hat GroupMap contrib/gitdm/group-map-wavecomp Wave Computing # Also group together our prolific individual contributors -# and those working under academic auspices +# and those working under academic or intern auspices GroupMap contrib/gitdm/group-map-individuals (None) GroupMap contrib/gitdm/group-map-academics Academics (various) +GroupMap contrib/gitdm/group-map-interns GSoC/Outreachy Interns # Group together robots and other auto-reporters GroupMap contrib/gitdm/group-map-robots Robots (various) From 094d278547dcb66ad222047ab9c325c452fe31e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:53 +0100 Subject: [PATCH 333/531] contrib/gitdm: add more individual contributor entries. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also ensure Li's canonical gmail address is used. Signed-off-by: Alex Bennée Acked-by: Li Qiang Acked-by: Chetan Pant Acked-by: Akihiko Odaki Message-Id: <20210720232703.10650-20-alex.bennee@linaro.org> --- contrib/gitdm/aliases | 3 +++ contrib/gitdm/group-map-individuals | 3 +++ 2 files changed, 6 insertions(+) diff --git a/contrib/gitdm/aliases b/contrib/gitdm/aliases index c6ed215e68..4792413ce7 100644 --- a/contrib/gitdm/aliases +++ b/contrib/gitdm/aliases @@ -31,6 +31,9 @@ pbrook@c046a42c-6fe2-441c-8c8c-71466251a162 paul@codesourcery.com ths@c046a42c-6fe2-441c-8c8c-71466251a162 ths@networkno.de malc@c046a42c-6fe2-441c-8c8c-71466251a162 av1474@comtv.ru +# canonical emails +liq3ea@163.com liq3ea@gmail.com + # some broken tags yuval.shaia.ml.gmail.com yuval.shaia.ml@gmail.com diff --git a/contrib/gitdm/group-map-individuals b/contrib/gitdm/group-map-individuals index 9b6406e624..f816aa8770 100644 --- a/contrib/gitdm/group-map-individuals +++ b/contrib/gitdm/group-map-individuals @@ -31,3 +31,6 @@ jhogan@kernel.org atar4qemu@gmail.com minwoo.im.dev@gmail.com bmeng.cn@gmail.com +liq3ea@gmail.com +chetan4windows@gmail.com +akihiko.odaki@gmail.com From f7e68c9c99ad94f23d3ba3af1642c805b11c71c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:26:54 +0100 Subject: [PATCH 334/531] tcg/plugins: implement a qemu_plugin_user_exit helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In user-mode emulation there is a small race between preexit_cleanup and exit_group() which means we may end up calling instrumented instructions before the kernel reaps child threads. To solve this we implement a new helper which ensures the callbacks are flushed along with any translations before we let the host do it's a thing. While we are at it make the documentation of qemu_plugin_register_atexit_cb clearer as to what the user can expect. Signed-off-by: Alex Bennée Reviewed-by: Mahmoud Mandour Acked-by: Warner Losh Message-Id: <20210720232703.10650-21-alex.bennee@linaro.org> --- bsd-user/syscall.c | 6 +++--- include/qemu/plugin.h | 12 ++++++++++++ include/qemu/qemu-plugin.h | 13 +++++++++++++ linux-user/exit.c | 2 +- plugins/core.c | 39 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 4 deletions(-) diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index 7d986e9700..3f44311396 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -335,7 +335,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, _mcleanup(); #endif gdb_exit(arg1); - qemu_plugin_atexit_cb(); + qemu_plugin_user_exit(); /* XXX: should free thread stack and CPU env */ _exit(arg1); ret = 0; /* avoid warning */ @@ -437,7 +437,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1, _mcleanup(); #endif gdb_exit(arg1); - qemu_plugin_atexit_cb(); + qemu_plugin_user_exit(); /* XXX: should free thread stack and CPU env */ _exit(arg1); ret = 0; /* avoid warning */ @@ -516,7 +516,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1, _mcleanup(); #endif gdb_exit(arg1); - qemu_plugin_atexit_cb(); + qemu_plugin_user_exit(); /* XXX: should free thread stack and CPU env */ _exit(arg1); ret = 0; /* avoid warning */ diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h index 0fefbc6084..9a8438f683 100644 --- a/include/qemu/plugin.h +++ b/include/qemu/plugin.h @@ -190,6 +190,16 @@ void qemu_plugin_add_dyn_cb_arr(GArray *arr); void qemu_plugin_disable_mem_helpers(CPUState *cpu); +/** + * qemu_plugin_user_exit(): clean-up callbacks before calling exit callbacks + * + * This is a user-mode only helper that ensure we have fully cleared + * callbacks from all threads before calling the exit callbacks. This + * is so the plugins themselves don't have to jump through hoops to + * guard against race conditions. + */ +void qemu_plugin_user_exit(void); + #else /* !CONFIG_PLUGIN */ static inline void qemu_plugin_add_opts(void) @@ -250,6 +260,8 @@ void qemu_plugin_add_dyn_cb_arr(GArray *arr) static inline void qemu_plugin_disable_mem_helpers(CPUState *cpu) { } +static inline void qemu_plugin_user_exit(void) +{ } #endif /* !CONFIG_PLUGIN */ #endif /* QEMU_PLUGIN_H */ diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index dc3496f36c..e6e815abc5 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -549,6 +549,19 @@ void qemu_plugin_vcpu_for_each(qemu_plugin_id_t id, void qemu_plugin_register_flush_cb(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb); +/** + * qemu_plugin_register_atexit_cb() - register exit callback + * @id: plugin ID + * @cb: callback + * @userdata: user data for callback + * + * The @cb function is called once execution has finished. Plugins + * should be able to free all their resources at this point much like + * after a reset/uninstall callback is called. + * + * In user-mode it is possible a few un-instrumented instructions from + * child threads may run before the host kernel reaps the threads. + */ void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id, qemu_plugin_udata_cb_t cb, void *userdata); diff --git a/linux-user/exit.c b/linux-user/exit.c index 70b344048c..527e29cbc1 100644 --- a/linux-user/exit.c +++ b/linux-user/exit.c @@ -35,5 +35,5 @@ void preexit_cleanup(CPUArchState *env, int code) __gcov_dump(); #endif gdb_exit(code); - qemu_plugin_atexit_cb(); + qemu_plugin_user_exit(); } diff --git a/plugins/core.c b/plugins/core.c index 474db287cb..6b2490f973 100644 --- a/plugins/core.c +++ b/plugins/core.c @@ -487,6 +487,45 @@ void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id, plugin_register_cb_udata(id, QEMU_PLUGIN_EV_ATEXIT, cb, udata); } +/* + * Handle exit from linux-user. Unlike the normal atexit() mechanism + * we need to handle the clean-up manually as it's possible threads + * are still running. We need to remove all callbacks from code + * generation, flush the current translations and then we can safely + * trigger the exit callbacks. + */ + +void qemu_plugin_user_exit(void) +{ + enum qemu_plugin_event ev; + CPUState *cpu; + + QEMU_LOCK_GUARD(&plugin.lock); + + start_exclusive(); + + /* un-register all callbacks except the final AT_EXIT one */ + for (ev = 0; ev < QEMU_PLUGIN_EV_MAX; ev++) { + if (ev != QEMU_PLUGIN_EV_ATEXIT) { + struct qemu_plugin_ctx *ctx; + QTAILQ_FOREACH(ctx, &plugin.ctxs, entry) { + plugin_unregister_cb__locked(ctx, ev); + } + } + } + + tb_flush(current_cpu); + + CPU_FOREACH(cpu) { + qemu_plugin_disable_mem_helpers(cpu); + } + + end_exclusive(); + + /* now it's safe to handle the exit case */ + qemu_plugin_atexit_cb(); +} + /* * Call this function after longjmp'ing to the main loop. It's possible that the * last instruction of a TB might have used helpers, and therefore the From de9fc40f36ab8e696d1c69727e80a80c46f20978 Mon Sep 17 00:00:00 2001 From: Mahmoud Mandour Date: Wed, 21 Jul 2021 00:26:55 +0100 Subject: [PATCH 335/531] plugins/cache: Fixed a bug with destroying FIFO metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This manifests itself when associativity degree is greater than the number of sets and FIFO is used, otherwise it's also a memory leak whenever FIFO was used. Signed-off-by: Mahmoud Mandour Signed-off-by: Alex Bennée Reviewed-by: Alex Bennée Message-Id: <20210714172151.8494-2-ma.mandourr@gmail.com> Message-Id: <20210720232703.10650-22-alex.bennee@linaro.org> --- contrib/plugins/cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index bf0d2f6097..4a71602639 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -200,7 +200,7 @@ static void fifo_destroy(Cache *cache) { int i; - for (i = 0; i < cache->assoc; i++) { + for (i = 0; i < cache->num_sets; i++) { g_queue_free(cache->sets[i].fifo_queue); } } From 072c444b0d948451771b0245b74d5310a00e3dd2 Mon Sep 17 00:00:00 2001 From: Mahmoud Mandour Date: Wed, 21 Jul 2021 00:26:56 +0100 Subject: [PATCH 336/531] plugins/cache: limited the scope of a mutex lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's not necessary to lock the address translation portion of the vcpu_mem_access callback. Signed-off-by: Mahmoud Mandour Signed-off-by: Alex Bennée Reviewed-by: Alex Bennée Message-Id: <20210714172151.8494-3-ma.mandourr@gmail.com> Message-Id: <20210720232703.10650-23-alex.bennee@linaro.org> --- contrib/plugins/cache.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index 4a71602639..695fb969dc 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -355,15 +355,14 @@ static void vcpu_mem_access(unsigned int vcpu_index, qemu_plugin_meminfo_t info, struct qemu_plugin_hwaddr *hwaddr; InsnData *insn; - g_mutex_lock(&mtx); hwaddr = qemu_plugin_get_hwaddr(info, vaddr); if (hwaddr && qemu_plugin_hwaddr_is_io(hwaddr)) { - g_mutex_unlock(&mtx); return; } effective_addr = hwaddr ? qemu_plugin_hwaddr_phys_addr(hwaddr) : vaddr; + g_mutex_lock(&mtx); if (!access_cache(dcache, effective_addr)) { insn = (InsnData *) userdata; insn->dmisses++; From c2888a679d376baa2dc36a31e44ddb824f232d9c Mon Sep 17 00:00:00 2001 From: Mahmoud Mandour Date: Wed, 21 Jul 2021 00:26:57 +0100 Subject: [PATCH 337/531] plugins/cache: Fixed "function decl. is not a prototype" warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mahmoud Mandour Signed-off-by: Alex Bennée Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210714172151.8494-7-ma.mandourr@gmail.com> Message-Id: <20210720232703.10650-24-alex.bennee@linaro.org> --- contrib/plugins/cache.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index 695fb969dc..066ea6d8ec 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -469,7 +469,7 @@ static int icmp(gconstpointer a, gconstpointer b) return insn_a->imisses < insn_b->imisses ? 1 : -1; } -static void log_stats() +static void log_stats(void) { g_autoptr(GString) rep = g_string_new(""); g_string_append_printf(rep, @@ -487,7 +487,7 @@ static void log_stats() qemu_plugin_outs(rep->str); } -static void log_top_insns() +static void log_top_insns(void) { int i; GList *curr, *miss_insns; @@ -536,7 +536,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) g_hash_table_destroy(miss_ht); } -static void policy_init() +static void policy_init(void) { switch (policy) { case LRU: From 2da42253ef9af7a9c3a5e9e7fcfb1e7eb84a8bb6 Mon Sep 17 00:00:00 2001 From: Aaron Lindsay Date: Wed, 21 Jul 2021 00:26:58 +0100 Subject: [PATCH 338/531] plugins: Fix physical address calculation for IO regions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The address calculation for IO regions introduced by commit 787148bf928a54b5cc86f5b434f9399e9737679c Author: Aaron Lindsay plugins: Expose physical addresses instead of device offsets is not always accurate. Use the more correct MemoryRegionSection.offset_within_address_space. Signed-off-by: Aaron Lindsay Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210720195735.3934473-1-aaron@os.amperecomputing.com> Message-Id: <20210720232703.10650-25-alex.bennee@linaro.org> --- plugins/api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/api.c b/plugins/api.c index 78b563c5c5..2d521e6ba8 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -319,7 +319,7 @@ uint64_t qemu_plugin_hwaddr_phys_addr(const struct qemu_plugin_hwaddr *haddr) return block->offset + offset + block->mr->addr; } else { MemoryRegionSection *mrs = haddr->v.io.section; - return haddr->v.io.offset + mrs->mr->addr; + return mrs->offset_within_address_space + haddr->v.io.offset; } } #endif From c56f1ee668d504af62f09e041e584e725edfa4b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:27:00 +0100 Subject: [PATCH 339/531] tests/tcg/configure.sh: add handling for assembler only builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Up until this point we only handled local compilers or assumed we had everything in the container. This falls down when we are building QEMU inside the container. This special handling only affects tricore for now but I put it in a case just in case we add any other "special" targets. Setting CROSS_CC_GUEST is a bit of a hack just to ensure the test runs as we gate on a detected compiler even though the Makefile won't actually use it. It also means we display something sane in the configure output. Signed-off-by: Alex Bennée Message-Id: <20210720232703.10650-27-alex.bennee@linaro.org> --- tests/tcg/configure.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh index aa7c24328a..1f985ccfc0 100755 --- a/tests/tcg/configure.sh +++ b/tests/tcg/configure.sh @@ -72,6 +72,10 @@ fi : ${cross_cc_x86_64="x86_64-linux-gnu-gcc"} : ${cross_cc_cflags_x86_64="-m64"} +# tricore is special as it doesn't have a compiler +: ${cross_as_tricore="tricore-as"} +: ${cross_ld_tricore="tricore-ld"} + for target in $target_list; do arch=${target%%-*} @@ -247,6 +251,20 @@ for target in $target_list; do fi fi fi + + # Special handling for assembler only tests + eval "target_as=\"\${cross_as_$arch}\"" + eval "target_ld=\"\${cross_ld_$arch}\"" + if has $target_as && has $target_ld; then + case $target in + tricore-softmmu) + echo "CROSS_CC_GUEST=$target_as" >> $config_target_mak + echo "CROSS_AS_GUEST=$target_as" >> $config_target_mak + echo "CROSS_LD_GUEST=$target_ld" >> $config_target_mak + got_cross_cc=yes + ;; + esac + fi fi if test $got_cross_cc = yes; then From 39ce92373283a3a3ff0aa2d381b87e930a9ab1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 21 Jul 2021 00:27:01 +0100 Subject: [PATCH 340/531] gitlab: enable a very minimal build with the tricore container MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than base of the shared Debian 10 container which would require us to bring in even more dependencies just bring in what is needed for building tricore-softmmu in GitLab. We don't even remove the container from the DOCKER_PARTIAL_IMAGES lest we cause more confusion. Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Reviewed-by: Willian Rampazzo Message-Id: <20210720232703.10650-28-alex.bennee@linaro.org> --- .gitlab-ci.d/buildtest.yml | 11 ++++++ .../dockerfiles/debian-tricore-cross.docker | 34 ++++++++++++++++--- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 89df51517c..48cb45a783 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -354,6 +354,17 @@ build-some-softmmu: TARGETS: xtensa-softmmu arm-softmmu aarch64-softmmu alpha-softmmu MAKE_CHECK_ARGS: check-tcg +# We build tricore in a very minimal tricore only container +build-tricore-softmmu: + extends: .native_build_job_template + needs: + job: tricore-debian-cross-container + variables: + IMAGE: debian-tricore-cross + CONFIGURE_ARGS: --disable-tools --disable-fdt --enable-debug + TARGETS: tricore-softmmu + MAKE_CHECK_ARGS: check-tcg + clang-system: extends: .native_build_job_template needs: diff --git a/tests/docker/dockerfiles/debian-tricore-cross.docker b/tests/docker/dockerfiles/debian-tricore-cross.docker index 985925134c..d8df2c6117 100644 --- a/tests/docker/dockerfiles/debian-tricore-cross.docker +++ b/tests/docker/dockerfiles/debian-tricore-cross.docker @@ -1,23 +1,47 @@ # # Docker TriCore cross-compiler target # -# This docker target builds on the debian Stretch base image. +# This docker target builds on the Debian Buster base image but +# doesn't inherit from the common one to avoid bringing in unneeded +# dependencies. # # Copyright (c) 2018 Philippe Mathieu-Daudé # # SPDX-License-Identifier: GPL-2.0-or-later # -FROM qemu/debian10 +FROM docker.io/library/debian:buster-slim MAINTAINER Philippe Mathieu-Daudé +RUN apt update && \ + DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \ + DEBIAN_FRONTEND=noninteractive eatmydata apt install -yy \ + bzip2 \ + ca-certificates \ + ccache \ + g++ \ + gcc \ + git \ + libglib2.0-dev \ + libpixman-1-dev \ + libtest-harness-perl \ + locales \ + make \ + ninja-build \ + perl-base \ + pkgconf \ + python3-pip \ + python3-setuptools \ + python3-wheel + RUN git clone --single-branch \ https://github.com/bkoppelmann/tricore-binutils.git \ /usr/src/binutils && \ cd /usr/src/binutils && chmod +x missing && \ - CFLAGS=-w ./configure --prefix=/usr --disable-nls --target=tricore && \ + CFLAGS=-w ./configure --prefix=/usr/local --disable-nls --target=tricore && \ make && make install && \ rm -rf /usr/src/binutils -# This image isn't designed for building QEMU but building tests -ENV QEMU_CONFIGURE_OPTS --disable-system --disable-user +# This image can only build a very minimal QEMU as well as the tests +ENV DEF_TARGET_LIST tricore-softmmu +ENV QEMU_CONFIGURE_OPTS --disable-user --disable-tools --disable-fdt From e90c3c3c876454faf96d3f0917501846b9dd146c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 21 Jul 2021 00:27:02 +0100 Subject: [PATCH 341/531] gitlab-ci: Remove the second superfluous macos task MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While there might have been bigger differnces between the -base and the -xcode images in the beginning, they almost vanished in the current builds, e.g. when comparing the output of the "configure" step after cleaning up the differences due to temporary path names, I only get: $ diff -u /tmp/base.txt /tmp/xcode.txt --- /tmp/base.txt 2021-07-16 09:16:24.211427940 +0200 +++ /tmp/xcode.txt 2021-07-16 09:16:43.029684274 +0200 @@ -19,14 +19,14 @@ Build type: native build Project name: qemu Project version: 6.0.50 -C compiler for the host machine: cc (clang 12.0.0 "Apple clang version 12.0.0 (clang-1200.0.32.29)") +C compiler for the host machine: cc (clang 12.0.0 "Apple clang version 12.0.0 (clang-1200.0.32.28)") C linker for the host machine: cc ld64 609.8 Host machine cpu family: x86_64 Host machine cpu: x86_64 Program sh found: YES (/bin/sh) Program python3 found: YES (/usr/local/opt/python@3.9/bin/python3.9) Program bzip2 found: YES (/usr/bin/bzip2) -C++ compiler for the host machine: c++ (clang 12.0.0 "Apple clang version 12.0.0 (clang-1200.0.32.29)") +C++ compiler for the host machine: c++ (clang 12.0.0 "Apple clang version 12.0.0 (clang-1200.0.32.28)") C++ linker for the host machine: c++ ld64 609.8 Objective-C compiler for the host machine: clang (clang 12.0.0) Objective-C linker for the host machine: clang ld64 609.8 Since we're not using Xcode itself at all, it seems like it does not make much sense anymore to waste compute cycles with two images here. Thus let's delete the -xcode job now. [AJB: fix up commit formatting which trips up b4] Signed-off-by: Thomas Huth Signed-off-by: Alex Bennée Reviewed-by: Willian Rampazzo Reviewed-by: Daniel P. Berrangé Message-Id: <20210719073051.1559348-1-thuth@redhat.com> Message-Id: <20210720232703.10650-29-alex.bennee@linaro.org> --- .gitlab-ci.d/cirrus.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.gitlab-ci.d/cirrus.yml b/.gitlab-ci.d/cirrus.yml index 60b13ed83f..675db69622 100644 --- a/.gitlab-ci.d/cirrus.yml +++ b/.gitlab-ci.d/cirrus.yml @@ -85,18 +85,3 @@ x64-macos-11-base-build: PATH_EXTRA: /usr/local/opt/ccache/libexec:/usr/local/opt/gettext/bin PKG_CONFIG_PATH: /usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/ncurses/lib/pkgconfig:/usr/local/opt/readline/lib/pkgconfig TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64 - -x64-macos-11-xcode-build: - extends: .cirrus_build_job - variables: - NAME: macos-11 - CIRRUS_VM_INSTANCE_TYPE: osx_instance - CIRRUS_VM_IMAGE_SELECTOR: image - CIRRUS_VM_IMAGE_NAME: big-sur-xcode - CIRRUS_VM_CPUS: 12 - CIRRUS_VM_RAM: 24G - UPDATE_COMMAND: brew update - INSTALL_COMMAND: brew install - PATH_EXTRA: /usr/local/opt/ccache/libexec:/usr/local/opt/gettext/bin - PKG_CONFIG_PATH: /usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/ncurses/lib/pkgconfig:/usr/local/opt/readline/lib/pkgconfig - TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64 From 0a9487d80af9ed6fa14d2696bc34a920b32e53e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 21 Jul 2021 00:27:03 +0100 Subject: [PATCH 342/531] gitlab-ci: Extract OpenSBI job rules to reusable section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All jobs depending on 'docker-opensbi' job must use at most all the rules that triggers it. The simplest way to ensure that is to always use the same rules. Extract all the rules to a reusable section, and include this section (with the 'extends' keyword) in both 'docker-opensbi' and 'build-opensbi' jobs. The problem was introduced in commit c6fc0fc1a71 ("gitlab-ci.yml: Add jobs to build OpenSBI firmware binaries"), but was revealed in commit 91e9c47e50a ("docker: OpenSBI build job depends on OpenSBI container"). This fix is similar to the one used with the EDK2 firmware job in commit ac0595cf6b3 ("gitlab-ci: Extract EDK2 job rules to reusable section"). Reported-by: Daniel P. Berrangé Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Reviewed-by: Daniel P. Berrangé Reviewed-by: Willian Rampazzo Message-Id: <20210720164829.3949558-1-philmd@redhat.com> Message-Id: <20210720232703.10650-30-alex.bennee@linaro.org> --- .gitlab-ci.d/opensbi.yml | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.d/opensbi.yml b/.gitlab-ci.d/opensbi.yml index f66cd1d908..d8a0456679 100644 --- a/.gitlab-ci.d/opensbi.yml +++ b/.gitlab-ci.d/opensbi.yml @@ -1,10 +1,23 @@ -docker-opensbi: - stage: containers - rules: # Only run this job when the Dockerfile is modified +# All jobs needing docker-opensbi must use the same rules it uses. +.opensbi_job_rules: + rules: # Only run this job when ... - changes: + # this file is modified - .gitlab-ci.d/opensbi.yml + # or the Dockerfile is modified - .gitlab-ci.d/opensbi/Dockerfile when: always + - changes: # or roms/opensbi/ is modified (submodule updated) + - roms/opensbi/* + when: always + - if: '$CI_COMMIT_REF_NAME =~ /^opensbi/' # or the branch/tag starts with 'opensbi' + when: always + - if: '$CI_COMMIT_MESSAGE =~ /opensbi/i' # or last commit description contains 'OpenSBI' + when: always + +docker-opensbi: + extends: .opensbi_job_rules + stage: containers image: docker:19.03.1 services: - docker:19.03.1-dind @@ -24,16 +37,9 @@ docker-opensbi: - docker push $IMAGE_TAG build-opensbi: + extends: .opensbi_job_rules stage: build needs: ['docker-opensbi'] - rules: # Only run this job when ... - - changes: # ... roms/opensbi/ is modified (submodule updated) - - roms/opensbi/* - when: always - - if: '$CI_COMMIT_REF_NAME =~ /^opensbi/' # or the branch/tag starts with 'opensbi' - when: always - - if: '$CI_COMMIT_MESSAGE =~ /opensbi/i' # or last commit description contains 'OpenSBI' - when: always artifacts: paths: # 'artifacts.zip' will contains the following files: - pc-bios/opensbi-riscv32-generic-fw_dynamic.bin From cd6c768f6a4f65a65bd44bdec0638b7fd861ceb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20W=C3=B6lfing?= Date: Tue, 20 Jul 2021 16:39:41 +0200 Subject: [PATCH 343/531] ui/gtk: Fix relative mouse with multiple monitors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To handle relative mouse input the event handler needs to move the mouse away from the screen edges. Failing to do so results in the mouse getting stuck at invisible walls. However the current implementation for this is broken on hosts with multiple monitors. With multiple monitors the mouse can be located outside of the current monitor which is not handled by the current code. Also the monitor itself might be located at coordinates different from (0, 0). Signed-off-by: Dennis Wölfing Reviewed-by: Marc-André Lureau Message-Id: <20210720143940.291413-1-denniswoelfing@gmx.de> Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 376b4d528d..18542c7633 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -865,37 +865,25 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, GdkWindow *win = gtk_widget_get_window(widget); GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win); GdkRectangle geometry; - int screen_width, screen_height; int x = (int)motion->x_root; int y = (int)motion->y_root; gdk_monitor_get_geometry(monitor, &geometry); - screen_width = geometry.width; - screen_height = geometry.height; /* In relative mode check to see if client pointer hit - * one of the screen edges, and if so move it back by - * 200 pixels. This is important because the pointer + * one of the monitor edges, and if so move it back to the + * center of the monitor. This is important because the pointer * in the server doesn't correspond 1-for-1, and so * may still be only half way across the screen. Without * this warp, the server pointer would thus appear to hit * an invisible wall */ - if (x == 0) { - x += 200; - } - if (y == 0) { - y += 200; - } - if (x == (screen_width - 1)) { - x -= 200; - } - if (y == (screen_height - 1)) { - y -= 200; - } - - if (x != (int)motion->x_root || y != (int)motion->y_root) { + if (x <= geometry.x || x - geometry.x >= geometry.width - 1 || + y <= geometry.y || y - geometry.y >= geometry.height - 1) { GdkDevice *dev = gdk_event_get_device((GdkEvent *)motion); + x = geometry.x + geometry.width / 2; + y = geometry.y + geometry.height / 2; + gdk_device_warp(dev, screen, x, y); s->last_set = FALSE; return FALSE; From 9a6c69d389c0492a57c439dc3babbd0f9da2555e Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Wed, 14 Jul 2021 14:57:35 +0900 Subject: [PATCH 344/531] ui/spice: Use HAVE_SPICE_GL for OpenGL checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some code in ui/spice used CONFIG_OPENGL for OpenGL conditionals, but SPICE also depends on CONFIG_GBM and SPICE server whose version is 0.13.1 or later for OpenGL. Always use HAVE_SPICE_GL, which defines the precise condition. Signed-off-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Message-Id: <20210714055735.86050-1-akihiko.odaki@gmail.com> Signed-off-by: Gerd Hoffmann --- ui/spice-app.c | 3 ++- ui/spice-core.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/spice-app.c b/ui/spice-app.c index 641f4a9d53..7e71e18da9 100644 --- a/ui/spice-app.c +++ b/ui/spice-app.c @@ -27,6 +27,7 @@ #include #include "ui/console.h" +#include "ui/spice-display.h" #include "qemu/config-file.h" #include "qemu/option.h" #include "qemu/cutils.h" @@ -175,7 +176,7 @@ static void spice_app_display_early_init(DisplayOptions *opts) qemu_opt_set(qopts, "addr", sock_path, &error_abort); qemu_opt_set(qopts, "image-compression", "off", &error_abort); qemu_opt_set(qopts, "streaming-video", "off", &error_abort); -#ifdef CONFIG_OPENGL +#ifdef HAVE_SPICE_GL qemu_opt_set(qopts, "gl", opts->has_gl ? "on" : "off", &error_abort); display_opengl = opts->has_gl; #endif diff --git a/ui/spice-core.c b/ui/spice-core.c index 86d43783ac..0371055e6c 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -1039,6 +1039,6 @@ static void spice_register_config(void) opts_init(spice_register_config); module_opts("spice"); -#ifdef CONFIG_OPENGL +#ifdef HAVE_SPICE_GL module_dep("ui-opengl"); #endif From 074c0653c25bbd2f3978699099051d2343f34c57 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Wed, 14 Jul 2021 14:56:46 +0900 Subject: [PATCH 345/531] ui/egl-headless: Remove a check for CONFIG_OPENGL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ui/egl-headless is only built when CONFIG_OPENGL is defined because it depends on CONFIG_OPENGL without condition. Remove a redundant conditonal in ui/egl-headless.c Signed-off-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Message-Id: <20210714055646.85952-1-akihiko.odaki@gmail.com> Signed-off-by: Gerd Hoffmann --- ui/egl-headless.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui/egl-headless.c b/ui/egl-headless.c index 75404e0e87..a26a2520c4 100644 --- a/ui/egl-headless.c +++ b/ui/egl-headless.c @@ -214,6 +214,4 @@ static void register_egl(void) type_init(register_egl); -#ifdef CONFIG_OPENGL module_dep("ui-opengl"); -#endif From 40a9aadbc9900f8b50fffe485df7cc0bfb9ec01c Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 9 Jul 2021 01:56:19 +0900 Subject: [PATCH 346/531] ui/cocoa: Fix the type of main's argv Signed-off-by: Akihiko Odaki Reviewed-by: Peter Maydell Message-Id: <20210708165619.29299-1-akihiko.odaki@gmail.com> Signed-off-by: Gerd Hoffmann --- ui/cocoa.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index 9f72844b07..68a6302184 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -1888,12 +1888,12 @@ static void *call_qemu_main(void *opaque) exit(status); } -int main (int argc, const char * argv[]) { +int main (int argc, char **argv) { QemuThread thread; COCOA_DEBUG("Entered main()\n"); gArgc = argc; - gArgv = (char **)argv; + gArgv = argv; qemu_sem_init(&display_init_sem, 0); qemu_sem_init(&app_started_sem, 0); From d4a121048095f276913dca977bb21bcbab02c44c Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 5 Jul 2021 16:59:12 +0900 Subject: [PATCH 347/531] ui: update keycodemapdb submodule commit The change of ui/keycodemapdb effective on QEMU is only commit d21009b1c9f94b740ea66be8e48a1d8ad8124023, which adds mappings for key codes added in commit d7696ff884e35c6dacf83a7cbe3355e3b0a90125. d21009b1c9f94b740ea66be8e48a1d8ad8124023 Add QEMU QKeyCode "lang1" and "lang2" 320f92c36a80bfafc5d57834592a7be5fd79f104 rust: fix cargo clippy e62d42f0fd76f7bb8bf78385a83c060e66ff52b0 tests: add rust test 3e25e1ca1772fc3f2039f739f8f920450dc68e50 gen: add --lang rust 9133a0b8022d1fb063a81cc2ba3b627c14ccdfd1 tests: fix argument order Signed-off-by: Akihiko Odaki Message-Id: <20210705075912.2280-1-akihiko.odaki@gmail.com> Signed-off-by: Gerd Hoffmann --- ui/keycodemapdb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/keycodemapdb b/ui/keycodemapdb index 6119e6e19a..d21009b1c9 160000 --- a/ui/keycodemapdb +++ b/ui/keycodemapdb @@ -1 +1 @@ -Subproject commit 6119e6e19a050df847418de7babe5166779955e4 +Subproject commit d21009b1c9f94b740ea66be8e48a1d8ad8124023 From 584af1f1d955476aacba3350c4efb5865fc91c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sun, 25 Jul 2021 18:50:39 +0200 Subject: [PATCH 348/531] ui/gtk: add a keyboard fifo to the VTE consoles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 8eb13bbbac ("ui/gtk: vte: fix sending multiple characeters") it's very easy to lock up QEMU with the GTK ui. If you configure a guest with a serial device and the guest doesn't listen on this device, QEMU will lock up after entering two characters in the serial console. That's because current code uses a busy loop for the chardev write retries and the busy loop doesn't terminate in this case. To fix this problem add a fifo to the VTE consoles and use the chr_accept_input() callback function to write the remaining characters in the queue to the chardev. The fifo has a size of 4096 bytes, so one can copy and paste a fairly large URL or file path. Fixes: 8eb13bbbac ("ui/gtk: vte: fix sending multiple characeters") Signed-off-by: Volker Rümelin Message-Id: <20210725165039.5242-1-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- include/ui/gtk.h | 4 ++++ ui/gtk.c | 42 +++++++++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/include/ui/gtk.h b/include/ui/gtk.h index 9516670ebc..80d6bbd9b5 100644 --- a/include/ui/gtk.h +++ b/include/ui/gtk.h @@ -25,6 +25,9 @@ #include "ui/egl-helpers.h" #include "ui/egl-context.h" #endif +#ifdef CONFIG_VTE +#include "qemu/fifo8.h" +#endif #define MAX_VCS 10 @@ -62,6 +65,7 @@ typedef struct VirtualVteConsole { GtkWidget *scrollbar; GtkWidget *terminal; Chardev *chr; + Fifo8 out_fifo; bool echo; } VirtualVteConsole; #endif diff --git a/ui/gtk.c b/ui/gtk.c index 18542c7633..974e4dfc0b 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1640,6 +1640,25 @@ static void gd_vc_adjustment_changed(GtkAdjustment *adjustment, void *opaque) } } +static void gd_vc_send_chars(VirtualConsole *vc) +{ + uint32_t len, avail; + + len = qemu_chr_be_can_write(vc->vte.chr); + avail = fifo8_num_used(&vc->vte.out_fifo); + if (len > avail) { + len = avail; + } + while (len > 0) { + const uint8_t *buf; + uint32_t size; + + buf = fifo8_pop_buf(&vc->vte.out_fifo, len, &size); + qemu_chr_be_write(vc->vte.chr, (uint8_t *)buf, size); + len -= size; + } +} + static int gd_vc_chr_write(Chardev *chr, const uint8_t *buf, int len) { VCChardev *vcd = VC_CHARDEV(chr); @@ -1649,6 +1668,14 @@ static int gd_vc_chr_write(Chardev *chr, const uint8_t *buf, int len) return len; } +static void gd_vc_chr_accept_input(Chardev *chr) +{ + VCChardev *vcd = VC_CHARDEV(chr); + VirtualConsole *vc = vcd->console; + + gd_vc_send_chars(vc); +} + static void gd_vc_chr_set_echo(Chardev *chr, bool echo) { VCChardev *vcd = VC_CHARDEV(chr); @@ -1688,6 +1715,7 @@ static void char_gd_vc_class_init(ObjectClass *oc, void *data) cc->parse = qemu_chr_parse_vc; cc->open = gd_vc_open; cc->chr_write = gd_vc_chr_write; + cc->chr_accept_input = gd_vc_chr_accept_input; cc->chr_set_echo = gd_vc_chr_set_echo; } @@ -1702,6 +1730,7 @@ static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size, gpointer user_data) { VirtualConsole *vc = user_data; + uint32_t free; if (vc->vte.echo) { VteTerminal *term = VTE_TERMINAL(vc->vte.terminal); @@ -1721,16 +1750,10 @@ static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size, } } - int remaining = size; - uint8_t* p = (uint8_t *)text; - while (remaining > 0) { - int can_write = qemu_chr_be_can_write(vc->vte.chr); - int written = MIN(remaining, can_write); - qemu_chr_be_write(vc->vte.chr, p, written); + free = fifo8_num_free(&vc->vte.out_fifo); + fifo8_push_all(&vc->vte.out_fifo, (uint8_t *)text, MIN(free, size)); + gd_vc_send_chars(vc); - remaining -= written; - p += written; - } return TRUE; } @@ -1747,6 +1770,7 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc, vc->s = s; vc->vte.echo = vcd->echo; vc->vte.chr = chr; + fifo8_create(&vc->vte.out_fifo, 4096); vcd->console = vc; snprintf(buffer, sizeof(buffer), "vc%d", idx); From 15a730e7a3aaac180df72cd5730e0617bcf44a5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 23 Jul 2021 21:58:43 +0200 Subject: [PATCH 349/531] block/nvme: Fix VFIO_MAP_DMA failed: No space left on device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the NVMe block driver was introduced (see commit bdd6a90a9e5, January 2018), Linux VFIO_IOMMU_MAP_DMA ioctl was only returning -ENOMEM in case of error. The driver was correctly handling the error path to recycle its volatile IOVA mappings. To fix CVE-2019-3882, Linux commit 492855939bdb ("vfio/type1: Limit DMA mappings per container", April 2019) added the -ENOSPC error to signal the user exhausted the DMA mappings available for a container. The block driver started to mis-behave: qemu-system-x86_64: VFIO_MAP_DMA failed: No space left on device (qemu) (qemu) info status VM status: paused (io-error) (qemu) c VFIO_MAP_DMA failed: No space left on device (qemu) c VFIO_MAP_DMA failed: No space left on device (The VM is not resumable from here, hence stuck.) Fix by handling the new -ENOSPC error (when DMA mappings are exhausted) without any distinction to the current -ENOMEM error, so we don't change the behavior on old kernels where the CVE-2019-3882 fix is not present. An easy way to reproduce this bug is to restrict the DMA mapping limit (65535 by default) when loading the VFIO IOMMU module: # modprobe vfio_iommu_type1 dma_entry_limit=666 Cc: qemu-stable@nongnu.org Cc: Fam Zheng Cc: Maxim Levitsky Cc: Alex Williamson Reported-by: Michal Prívozník Signed-off-by: Philippe Mathieu-Daudé Message-id: 20210723195843.1032825-1-philmd@redhat.com Fixes: bdd6a90a9e5 ("block: Add VFIO based NVMe driver") Buglink: https://bugs.launchpad.net/qemu/+bug/1863333 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/65 Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Stefan Hajnoczi --- block/nvme.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/block/nvme.c b/block/nvme.c index 2b5421e7aa..e8dbbc2317 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -1030,7 +1030,29 @@ try_map: r = qemu_vfio_dma_map(s->vfio, qiov->iov[i].iov_base, len, true, &iova); + if (r == -ENOSPC) { + /* + * In addition to the -ENOMEM error, the VFIO_IOMMU_MAP_DMA + * ioctl returns -ENOSPC to signal the user exhausted the DMA + * mappings available for a container since Linux kernel commit + * 492855939bdb ("vfio/type1: Limit DMA mappings per container", + * April 2019, see CVE-2019-3882). + * + * This block driver already handles this error path by checking + * for the -ENOMEM error, so we directly replace -ENOSPC by + * -ENOMEM. Beside, -ENOSPC has a specific meaning for blockdev + * coroutines: it triggers BLOCKDEV_ON_ERROR_ENOSPC and + * BLOCK_ERROR_ACTION_STOP which stops the VM, asking the operator + * to add more storage to the blockdev. Not something we can do + * easily with an IOMMU :) + */ + r = -ENOMEM; + } if (r == -ENOMEM && retry) { + /* + * We exhausted the DMA mappings available for our container: + * recycle the volatile IOVA mappings. + */ retry = false; trace_nvme_dma_flush_queue_wait(s); if (s->dma_map_count) { From 5e32ffd346429b2e92545c425de96d92e88a7498 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 19 Jul 2021 19:52:17 +0100 Subject: [PATCH 350/531] tests/qtest/migration-test.c: use 127.0.0.1 instead of 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OpenBSD doesn't like :0 as an address, switch to using 127.0.0.1 in baddest; it's really testing the :0 port number that isn't allowed on anything. (The test doesn't currently run anyway because of the userfault problem that Peter noticed, but this gets us closer to being able to reenable it) Signed-off-by: Dr. David Alan Gilbert Message-Id: <20210719185217.122105-1-dgilbert@redhat.com> Acked-by: Peter Xu Reviewed-by: Daniel P. Berrangé Reviewed-by: Juan Quintela Reviewed-by: Philippe Mathieu-Daude Signed-off-by: Dr. David Alan Gilbert --- tests/qtest/migration-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 328d6dbe97..1e8b7784ef 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -787,10 +787,10 @@ static void test_baddest(void) args->hide_stderr = true; - if (test_migrate_start(&from, &to, "tcp:0:0", args)) { + if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", args)) { return; } - migrate_qmp(from, "tcp:0:0", "{}"); + migrate_qmp(from, "tcp:127.0.0.1:0", "{}"); wait_for_migration_fail(from, false); test_migrate_end(from, to, false); } From 53021ea1659b8a9074c6f5eb6c65a4e5dddddaec Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 22 Jul 2021 13:58:37 -0400 Subject: [PATCH 351/531] migration: Fix missing join() of rp_thread It's possible that the migration thread skip the join() of the rp_thread in below race and crash on src right at finishing migration: migration_thread rp_thread ---------------- --------- migration_completion() (before rp_thread quits) from_dst_file=NULL [thread got scheduled out] s->rp_state.from_dst_file==NULL (skip join() of rp_thread) migrate_fd_cleanup() qemu_fclose(s->to_dst_file) yank_unregister_instance() assert(yank_find_entry()) <------- crash It could mostly happen with postcopy, but that shouldn't be required, e.g., I think it could also trigger with MIGRATION_CAPABILITY_RETURN_PATH set. It's suspected that above race could be the root cause of a recent (but rare) migration-test break reported by either Dave or PMM: https://lore.kernel.org/qemu-devel/YPamXAHwan%2FPPXLf@work-vm/ The issue is: from_dst_file is reset in the rp_thread, so if the thread reset it to NULL fast enough then the migration thread will assume there's no rp_thread at all. This could potentially cause more severe issue (e.g. crash) after the yank code. Fix it by using a boolean to keep "whether we've created rp_thread". Cc: Dr. David Alan Gilbert Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Peter Xu Message-Id: <20210722175841.938739-2-peterx@redhat.com> Reviewed-by: Lukas Straub Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 4 +++- migration/migration.h | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/migration/migration.c b/migration/migration.c index 2d306582eb..21b94f75a3 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -2867,6 +2867,7 @@ static int open_return_path_on_source(MigrationState *ms, qemu_thread_create(&ms->rp_state.rp_thread, "return path", source_return_path_thread, ms, QEMU_THREAD_JOINABLE); + ms->rp_state.rp_thread_created = true; trace_open_return_path_on_source_continue(); @@ -2891,6 +2892,7 @@ static int await_return_path_close_on_source(MigrationState *ms) } trace_await_return_path_close_on_source_joining(); qemu_thread_join(&ms->rp_state.rp_thread); + ms->rp_state.rp_thread_created = false; trace_await_return_path_close_on_source_close(); return ms->rp_state.error; } @@ -3170,7 +3172,7 @@ static void migration_completion(MigrationState *s) * it will wait for the destination to send it's status in * a SHUT command). */ - if (s->rp_state.from_dst_file) { + if (s->rp_state.rp_thread_created) { int rp_error; trace_migration_return_path_end_before(); rp_error = await_return_path_close_on_source(s); diff --git a/migration/migration.h b/migration/migration.h index 2ebb740dfa..c302879fad 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -195,6 +195,13 @@ struct MigrationState { QEMUFile *from_dst_file; QemuThread rp_thread; bool error; + /* + * We can also check non-zero of rp_thread, but there's no "official" + * way to do this, so this bool makes it slightly more elegant. + * Checking from_dst_file for this is racy because from_dst_file will + * be cleared in the rp_thread! + */ + bool rp_thread_created; QemuSemaphore rp_sem; } rp_state; From 43044ac0ee5758d92b639843c045123c2de578d1 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 22 Jul 2021 13:58:38 -0400 Subject: [PATCH 352/531] migration: Make from_dst_file accesses thread-safe Accessing from_dst_file is potentially racy in current code base like below: if (s->from_dst_file) do_something(s->from_dst_file); Because from_dst_file can be reset right after the check in another thread (rp_thread). One example is migrate_fd_cancel(). Use the same qemu_file_lock to protect it too, just like to_dst_file. When it's safe to access without lock, comment it. There's one special reference in migration_thread() that can be replaced by the newly introduced rp_thread_created flag. Reported-by: Dr. David Alan Gilbert Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Peter Xu Reviewed-by: Lukas Straub Message-Id: <20210722175841.938739-3-peterx@redhat.com> Signed-off-by: Dr. David Alan Gilbert with Peter's fixup --- migration/migration.c | 39 +++++++++++++++++++++++++++++---------- migration/migration.h | 8 +++++--- migration/ram.c | 1 + 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 21b94f75a3..62dbcb7d52 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1879,9 +1879,11 @@ static void migrate_fd_cancel(MigrationState *s) QEMUFile *f = migrate_get_current()->to_dst_file; trace_migrate_fd_cancel(); - if (s->rp_state.from_dst_file) { - /* shutdown the rp socket, so causing the rp thread to shutdown */ - qemu_file_shutdown(s->rp_state.from_dst_file); + WITH_QEMU_LOCK_GUARD(&s->qemu_file_lock) { + if (s->rp_state.from_dst_file) { + /* shutdown the rp socket, so causing the rp thread to shutdown */ + qemu_file_shutdown(s->rp_state.from_dst_file); + } } do { @@ -2686,6 +2688,23 @@ static int migrate_handle_rp_resume_ack(MigrationState *s, uint32_t value) return 0; } +/* Release ms->rp_state.from_dst_file in a safe way */ +static void migration_release_from_dst_file(MigrationState *ms) +{ + QEMUFile *file; + + WITH_QEMU_LOCK_GUARD(&ms->qemu_file_lock) { + /* + * Reset the from_dst_file pointer first before releasing it, as we + * can't block within lock section + */ + file = ms->rp_state.from_dst_file; + ms->rp_state.from_dst_file = NULL; + } + + qemu_fclose(file); +} + /* * Handles messages sent on the return path towards the source VM * @@ -2827,11 +2846,13 @@ out: * Maybe there is something we can do: it looks like a * network down issue, and we pause for a recovery. */ - qemu_fclose(rp); - ms->rp_state.from_dst_file = NULL; + migration_release_from_dst_file(ms); rp = NULL; if (postcopy_pause_return_path_thread(ms)) { - /* Reload rp, reset the rest */ + /* + * Reload rp, reset the rest. Referencing it is safe since + * it's reset only by us above, or when migration completes + */ rp = ms->rp_state.from_dst_file; ms->rp_state.error = false; goto retry; @@ -2843,8 +2864,7 @@ out: } trace_source_return_path_thread_end(); - ms->rp_state.from_dst_file = NULL; - qemu_fclose(rp); + migration_release_from_dst_file(ms); rcu_unregister_thread(); return NULL; } @@ -2852,7 +2872,6 @@ out: static int open_return_path_on_source(MigrationState *ms, bool create_thread) { - ms->rp_state.from_dst_file = qemu_file_get_return_path(ms->to_dst_file); if (!ms->rp_state.from_dst_file) { return -1; @@ -3746,7 +3765,7 @@ static void *migration_thread(void *opaque) * If we opened the return path, we need to make sure dst has it * opened as well. */ - if (s->rp_state.from_dst_file) { + if (s->rp_state.rp_thread_created) { /* Now tell the dest that it should open its end so it can reply */ qemu_savevm_send_open_return_path(s->to_dst_file); diff --git a/migration/migration.h b/migration/migration.h index c302879fad..7a5aa8c2fd 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -154,12 +154,13 @@ struct MigrationState { QemuThread thread; QEMUBH *vm_start_bh; QEMUBH *cleanup_bh; + /* Protected by qemu_file_lock */ QEMUFile *to_dst_file; QIOChannelBuffer *bioc; /* - * Protects to_dst_file pointer. We need to make sure we won't - * yield or hang during the critical section, since this lock will - * be used in OOB command handler. + * Protects to_dst_file/from_dst_file pointers. We need to make sure we + * won't yield or hang during the critical section, since this lock will be + * used in OOB command handler. */ QemuMutex qemu_file_lock; @@ -192,6 +193,7 @@ struct MigrationState { /* State related to return path */ struct { + /* Protected by qemu_file_lock */ QEMUFile *from_dst_file; QemuThread rp_thread; bool error; diff --git a/migration/ram.c b/migration/ram.c index b5fc454b2f..f728f5072f 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4012,6 +4012,7 @@ static void ram_dirty_bitmap_reload_notify(MigrationState *s) int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block) { int ret = -EINVAL; + /* from_dst_file is always valid because we're within rp_thread */ QEMUFile *file = s->rp_state.from_dst_file; unsigned long *le_bitmap, nbits = block->used_length >> TARGET_PAGE_BITS; uint64_t local_size = DIV_ROUND_UP(nbits, 8); From 18711405b506e7ca3822ed19830f1c562e0247f9 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 22 Jul 2021 13:58:39 -0400 Subject: [PATCH 353/531] migration: Introduce migration_ioc_[un]register_yank() There're plenty of places in migration/* that checks against either socket or tls typed ioc for yank operations. Provide two helpers to hide all these information. Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Peter Xu Message-Id: <20210722175841.938739-4-peterx@redhat.com> Reviewed-by: Lukas Straub Signed-off-by: Dr. David Alan Gilbert --- migration/channel.c | 15 ++------------- migration/multifd.c | 8 ++------ migration/qemu-file-channel.c | 8 ++------ migration/yank_functions.c | 28 ++++++++++++++++++++++++++++ migration/yank_functions.h | 2 ++ 5 files changed, 36 insertions(+), 25 deletions(-) diff --git a/migration/channel.c b/migration/channel.c index 01275a9162..c4fc000a1a 100644 --- a/migration/channel.c +++ b/migration/channel.c @@ -44,13 +44,7 @@ void migration_channel_process_incoming(QIOChannel *ioc) TYPE_QIO_CHANNEL_TLS)) { migration_tls_channel_process_incoming(s, ioc, &local_err); } else { - if (object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET) || - object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS)) { - yank_register_function(MIGRATION_YANK_INSTANCE, - migration_yank_iochannel, - QIO_CHANNEL(ioc)); - } - + migration_ioc_register_yank(ioc); migration_ioc_process_incoming(ioc, &local_err); } @@ -94,12 +88,7 @@ void migration_channel_connect(MigrationState *s, } else { QEMUFile *f = qemu_fopen_channel_output(ioc); - if (object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET) || - object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS)) { - yank_register_function(MIGRATION_YANK_INSTANCE, - migration_yank_iochannel, - QIO_CHANNEL(ioc)); - } + migration_ioc_register_yank(ioc); qemu_mutex_lock(&s->qemu_file_lock); s->to_dst_file = f; diff --git a/migration/multifd.c b/migration/multifd.c index ab41590e71..377da78f5b 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -987,12 +987,8 @@ int multifd_load_cleanup(Error **errp) for (i = 0; i < migrate_multifd_channels(); i++) { MultiFDRecvParams *p = &multifd_recv_state->params[i]; - if ((object_dynamic_cast(OBJECT(p->c), TYPE_QIO_CHANNEL_SOCKET) || - object_dynamic_cast(OBJECT(p->c), TYPE_QIO_CHANNEL_TLS)) - && OBJECT(p->c)->ref == 1) { - yank_unregister_function(MIGRATION_YANK_INSTANCE, - migration_yank_iochannel, - QIO_CHANNEL(p->c)); + if (OBJECT(p->c)->ref == 1) { + migration_ioc_unregister_yank(p->c); } object_unref(OBJECT(p->c)); diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c index fad340ea7a..867a5ed0c3 100644 --- a/migration/qemu-file-channel.c +++ b/migration/qemu-file-channel.c @@ -107,12 +107,8 @@ static int channel_close(void *opaque, Error **errp) int ret; QIOChannel *ioc = QIO_CHANNEL(opaque); ret = qio_channel_close(ioc, errp); - if ((object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET) || - object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS)) - && OBJECT(ioc)->ref == 1) { - yank_unregister_function(MIGRATION_YANK_INSTANCE, - migration_yank_iochannel, - QIO_CHANNEL(ioc)); + if (OBJECT(ioc)->ref == 1) { + migration_ioc_unregister_yank(ioc); } object_unref(OBJECT(ioc)); return ret; diff --git a/migration/yank_functions.c b/migration/yank_functions.c index 96c90e17dc..23697173ae 100644 --- a/migration/yank_functions.c +++ b/migration/yank_functions.c @@ -11,6 +11,9 @@ #include "qapi/error.h" #include "io/channel.h" #include "yank_functions.h" +#include "qemu/yank.h" +#include "io/channel-socket.h" +#include "io/channel-tls.h" void migration_yank_iochannel(void *opaque) { @@ -18,3 +21,28 @@ void migration_yank_iochannel(void *opaque) qio_channel_shutdown(ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); } + +/* Return whether yank is supported on this ioc */ +static bool migration_ioc_yank_supported(QIOChannel *ioc) +{ + return object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET) || + object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS); +} + +void migration_ioc_register_yank(QIOChannel *ioc) +{ + if (migration_ioc_yank_supported(ioc)) { + yank_register_function(MIGRATION_YANK_INSTANCE, + migration_yank_iochannel, + QIO_CHANNEL(ioc)); + } +} + +void migration_ioc_unregister_yank(QIOChannel *ioc) +{ + if (migration_ioc_yank_supported(ioc)) { + yank_unregister_function(MIGRATION_YANK_INSTANCE, + migration_yank_iochannel, + QIO_CHANNEL(ioc)); + } +} diff --git a/migration/yank_functions.h b/migration/yank_functions.h index 055ea22523..74c7f18c91 100644 --- a/migration/yank_functions.h +++ b/migration/yank_functions.h @@ -15,3 +15,5 @@ * @opaque: QIOChannel to shutdown */ void migration_yank_iochannel(void *opaque); +void migration_ioc_register_yank(QIOChannel *ioc); +void migration_ioc_unregister_yank(QIOChannel *ioc); From c6ad5be7ae5b8c6bbbd0c592bbf18d4a78540516 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 22 Jul 2021 13:58:40 -0400 Subject: [PATCH 354/531] migration: Teach QEMUFile to be QIOChannel-aware migration uses QIOChannel typed qemufiles. In follow up patches, we'll need the capability to identify this fact, so that we can get the backing QIOChannel from a QEMUFile. We can also define types for QEMUFile but so far since we only need to be able to identify QIOChannel, introduce a boolean which is simpler. Introduce another helper qemu_file_get_ioc() to return the ioc backend of a qemufile if has_ioc is set. No functional change. Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Peter Xu Message-Id: <20210722175841.938739-5-peterx@redhat.com> Reviewed-by: Lukas Straub Signed-off-by: Dr. David Alan Gilbert --- migration/qemu-file-channel.c | 4 ++-- migration/qemu-file.c | 17 ++++++++++++++++- migration/qemu-file.h | 4 +++- migration/ram.c | 2 +- migration/savevm.c | 4 ++-- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c index 867a5ed0c3..2f8b1fcd46 100644 --- a/migration/qemu-file-channel.c +++ b/migration/qemu-file-channel.c @@ -187,11 +187,11 @@ static const QEMUFileOps channel_output_ops = { QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc) { object_ref(OBJECT(ioc)); - return qemu_fopen_ops(ioc, &channel_input_ops); + return qemu_fopen_ops(ioc, &channel_input_ops, true); } QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc) { object_ref(OBJECT(ioc)); - return qemu_fopen_ops(ioc, &channel_output_ops); + return qemu_fopen_ops(ioc, &channel_output_ops, true); } diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 1eacf9e831..6338d8e2ff 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -55,6 +55,8 @@ struct QEMUFile { Error *last_error_obj; /* has the file has been shutdown */ bool shutdown; + /* Whether opaque points to a QIOChannel */ + bool has_ioc; }; /* @@ -101,7 +103,7 @@ bool qemu_file_mode_is_not_valid(const char *mode) return false; } -QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops) +QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops, bool has_ioc) { QEMUFile *f; @@ -109,6 +111,7 @@ QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops) f->opaque = opaque; f->ops = ops; + f->has_ioc = has_ioc; return f; } @@ -851,3 +854,15 @@ void qemu_file_set_blocking(QEMUFile *f, bool block) f->ops->set_blocking(f->opaque, block, NULL); } } + +/* + * Return the ioc object if it's a migration channel. Note: it can return NULL + * for callers passing in a non-migration qemufile. E.g. see qemu_fopen_bdrv() + * and its usage in e.g. load_snapshot(). So we need to check against NULL + * before using it. If without the check, migration_incoming_state_destroy() + * could fail for load_snapshot(). + */ +QIOChannel *qemu_file_get_ioc(QEMUFile *file) +{ + return file->has_ioc ? QIO_CHANNEL(file->opaque) : NULL; +} diff --git a/migration/qemu-file.h b/migration/qemu-file.h index a9b6d6ccb7..3f36d4dc8c 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -27,6 +27,7 @@ #include #include "exec/cpu-common.h" +#include "io/channel.h" /* Read a chunk of data from a file at the given position. The pos argument * can be ignored if the file is only be used for streaming. The number of @@ -119,7 +120,7 @@ typedef struct QEMUFileHooks { QEMURamSaveFunc *save_page; } QEMUFileHooks; -QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops); +QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops, bool has_ioc); void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks); int qemu_get_fd(QEMUFile *f); int qemu_fclose(QEMUFile *f); @@ -179,5 +180,6 @@ void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data); size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, ram_addr_t offset, size_t size, uint64_t *bytes_sent); +QIOChannel *qemu_file_get_ioc(QEMUFile *file); #endif diff --git a/migration/ram.c b/migration/ram.c index f728f5072f..08b3cb7a4a 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -550,7 +550,7 @@ static int compress_threads_save_setup(void) /* comp_param[i].file is just used as a dummy buffer to save data, * set its ops to empty. */ - comp_param[i].file = qemu_fopen_ops(NULL, &empty_ops); + comp_param[i].file = qemu_fopen_ops(NULL, &empty_ops, false); comp_param[i].done = true; comp_param[i].quit = false; qemu_mutex_init(&comp_param[i].mutex); diff --git a/migration/savevm.c b/migration/savevm.c index 72848b946c..96b5e5d639 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -168,9 +168,9 @@ static const QEMUFileOps bdrv_write_ops = { static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable) { if (is_writable) { - return qemu_fopen_ops(bs, &bdrv_write_ops); + return qemu_fopen_ops(bs, &bdrv_write_ops, false); } - return qemu_fopen_ops(bs, &bdrv_read_ops); + return qemu_fopen_ops(bs, &bdrv_read_ops, false); } From 39675ffffb3394d44b880d083a214c5e44786170 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 22 Jul 2021 13:58:41 -0400 Subject: [PATCH 355/531] migration: Move the yank unregister of channel_close out It's efficient, but hackish to call yank unregister calls in channel_close(), especially it'll be hard to debug when qemu crashed with some yank function leaked. Remove that hack, but instead explicitly unregister yank functions at the places where needed, they are: (on src) - migrate_fd_cleanup - postcopy_pause (on dst) - migration_incoming_state_destroy - postcopy_pause_incoming Signed-off-by: Peter Xu Message-Id: <20210722175841.938739-6-peterx@redhat.com> Reviewed-by: Lukas Straub Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 14 +++++++++++++- migration/qemu-file-channel.c | 3 --- migration/savevm.c | 7 +++++++ migration/yank_functions.c | 14 ++++++++++++++ migration/yank_functions.h | 1 + 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 62dbcb7d52..041b8451a6 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -59,6 +59,7 @@ #include "multifd.h" #include "qemu/yank.h" #include "sysemu/cpus.h" +#include "yank_functions.h" #define MAX_THROTTLE (128 << 20) /* Migration transfer speed throttling */ @@ -273,6 +274,7 @@ void migration_incoming_state_destroy(void) } if (mis->from_src_file) { + migration_ioc_unregister_yank_from_file(mis->from_src_file); qemu_fclose(mis->from_src_file); mis->from_src_file = NULL; } @@ -1811,6 +1813,7 @@ static void migrate_fd_cleanup(MigrationState *s) * Close the file handle without the lock to make sure the * critical section won't block for long. */ + migration_ioc_unregister_yank_from_file(tmp); qemu_fclose(tmp); } @@ -3351,8 +3354,17 @@ static MigThrError postcopy_pause(MigrationState *s) while (true) { QEMUFile *file; - /* Current channel is possibly broken. Release it. */ + /* + * Current channel is possibly broken. Release it. Note that this is + * guaranteed even without lock because to_dst_file should only be + * modified by the migration thread. That also guarantees that the + * unregister of yank is safe too without the lock. It should be safe + * even to be within the qemu_file_lock, but we didn't do that to avoid + * taking more mutex (yank_lock) within qemu_file_lock. TL;DR: we make + * the qemu_file_lock critical section as small as possible. + */ assert(s->to_dst_file); + migration_ioc_unregister_yank_from_file(s->to_dst_file); qemu_mutex_lock(&s->qemu_file_lock); file = s->to_dst_file; s->to_dst_file = NULL; diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c index 2f8b1fcd46..bb5a5752df 100644 --- a/migration/qemu-file-channel.c +++ b/migration/qemu-file-channel.c @@ -107,9 +107,6 @@ static int channel_close(void *opaque, Error **errp) int ret; QIOChannel *ioc = QIO_CHANNEL(opaque); ret = qio_channel_close(ioc, errp); - if (OBJECT(ioc)->ref == 1) { - migration_ioc_unregister_yank(ioc); - } object_unref(OBJECT(ioc)); return ret; } diff --git a/migration/savevm.c b/migration/savevm.c index 96b5e5d639..7b7b64bd13 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -65,6 +65,7 @@ #include "qemu/bitmap.h" #include "net/announce.h" #include "qemu/yank.h" +#include "yank_functions.h" const unsigned int postcopy_ram_discard_version; @@ -2568,6 +2569,12 @@ static bool postcopy_pause_incoming(MigrationIncomingState *mis) /* Clear the triggered bit to allow one recovery */ mis->postcopy_recover_triggered = false; + /* + * Unregister yank with either from/to src would work, since ioc behind it + * is the same + */ + migration_ioc_unregister_yank_from_file(mis->from_src_file); + assert(mis->from_src_file); qemu_file_shutdown(mis->from_src_file); qemu_fclose(mis->from_src_file); diff --git a/migration/yank_functions.c b/migration/yank_functions.c index 23697173ae..8c08aef14a 100644 --- a/migration/yank_functions.c +++ b/migration/yank_functions.c @@ -14,6 +14,7 @@ #include "qemu/yank.h" #include "io/channel-socket.h" #include "io/channel-tls.h" +#include "qemu-file.h" void migration_yank_iochannel(void *opaque) { @@ -46,3 +47,16 @@ void migration_ioc_unregister_yank(QIOChannel *ioc) QIO_CHANNEL(ioc)); } } + +void migration_ioc_unregister_yank_from_file(QEMUFile *file) +{ + QIOChannel *ioc = qemu_file_get_ioc(file); + + if (ioc) { + /* + * For migration qemufiles, we'll always reach here. Though we'll skip + * calls from e.g. savevm/loadvm as they don't use yank. + */ + migration_ioc_unregister_yank(ioc); + } +} diff --git a/migration/yank_functions.h b/migration/yank_functions.h index 74c7f18c91..a7577955ed 100644 --- a/migration/yank_functions.h +++ b/migration/yank_functions.h @@ -17,3 +17,4 @@ void migration_yank_iochannel(void *opaque); void migration_ioc_register_yank(QIOChannel *ioc); void migration_ioc_unregister_yank(QIOChannel *ioc); +void migration_ioc_unregister_yank_from_file(QEMUFile *file); From 3143577d6a3f363514219c03d936e653ede44f32 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Thu, 22 Jul 2021 04:30:55 -0400 Subject: [PATCH 356/531] migration: clear the memory region dirty bitmap when skipping free pages When skipping free pages to send, their corresponding dirty bits in the memory region dirty bitmap need to be cleared. Otherwise the skipped pages will be sent in the next round after the migration thread syncs dirty bits from the memory region dirty bitmap. Cc: David Hildenbrand Cc: Peter Xu Cc: Michael S. Tsirkin Reported-by: David Hildenbrand Signed-off-by: Wei Wang Message-Id: <20210722083055.23352-1-wei.w.wang@intel.com> Reviewed-by: David Hildenbrand Signed-off-by: Dr. David Alan Gilbert --- migration/ram.c | 74 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 08b3cb7a4a..7a43bfd7af 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -789,6 +789,53 @@ unsigned long migration_bitmap_find_dirty(RAMState *rs, RAMBlock *rb, return find_next_bit(bitmap, size, start); } +static void migration_clear_memory_region_dirty_bitmap(RAMState *rs, + RAMBlock *rb, + unsigned long page) +{ + uint8_t shift; + hwaddr size, start; + + if (!rb->clear_bmap || !clear_bmap_test_and_clear(rb, page)) { + return; + } + + shift = rb->clear_bmap_shift; + /* + * CLEAR_BITMAP_SHIFT_MIN should always guarantee this... this + * can make things easier sometimes since then start address + * of the small chunk will always be 64 pages aligned so the + * bitmap will always be aligned to unsigned long. We should + * even be able to remove this restriction but I'm simply + * keeping it. + */ + assert(shift >= 6); + + size = 1ULL << (TARGET_PAGE_BITS + shift); + start = (((ram_addr_t)page) << TARGET_PAGE_BITS) & (-size); + trace_migration_bitmap_clear_dirty(rb->idstr, start, size, page); + memory_region_clear_dirty_bitmap(rb->mr, start, size); +} + +static void +migration_clear_memory_region_dirty_bitmap_range(RAMState *rs, + RAMBlock *rb, + unsigned long start, + unsigned long npages) +{ + unsigned long i, chunk_pages = 1UL << rb->clear_bmap_shift; + unsigned long chunk_start = QEMU_ALIGN_DOWN(start, chunk_pages); + unsigned long chunk_end = QEMU_ALIGN_UP(start + npages, chunk_pages); + + /* + * Clear pages from start to start + npages - 1, so the end boundary is + * exclusive. + */ + for (i = chunk_start; i < chunk_end; i += chunk_pages) { + migration_clear_memory_region_dirty_bitmap(rs, rb, i); + } +} + static inline bool migration_bitmap_clear_dirty(RAMState *rs, RAMBlock *rb, unsigned long page) @@ -803,26 +850,9 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs, * the page in the chunk we clear the remote dirty bitmap for all. * Clearing it earlier won't be a problem, but too late will. */ - if (rb->clear_bmap && clear_bmap_test_and_clear(rb, page)) { - uint8_t shift = rb->clear_bmap_shift; - hwaddr size = 1ULL << (TARGET_PAGE_BITS + shift); - hwaddr start = (((ram_addr_t)page) << TARGET_PAGE_BITS) & (-size); - - /* - * CLEAR_BITMAP_SHIFT_MIN should always guarantee this... this - * can make things easier sometimes since then start address - * of the small chunk will always be 64 pages aligned so the - * bitmap will always be aligned to unsigned long. We should - * even be able to remove this restriction but I'm simply - * keeping it. - */ - assert(shift >= 6); - trace_migration_bitmap_clear_dirty(rb->idstr, start, size, page); - memory_region_clear_dirty_bitmap(rb->mr, start, size); - } + migration_clear_memory_region_dirty_bitmap(rs, rb, page); ret = test_and_clear_bit(page, rb->bmap); - if (ret) { rs->migration_dirty_pages--; } @@ -2741,6 +2771,14 @@ void qemu_guest_free_page_hint(void *addr, size_t len) npages = used_len >> TARGET_PAGE_BITS; qemu_mutex_lock(&ram_state->bitmap_mutex); + /* + * The skipped free pages are equavalent to be sent from clear_bmap's + * perspective, so clear the bits from the memory region bitmap which + * are initially set. Otherwise those skipped pages will be sent in + * the next round after syncing from the memory region bitmap. + */ + migration_clear_memory_region_dirty_bitmap_range(ram_state, block, + start, npages); ram_state->migration_dirty_pages -= bitmap_count_one_with_offset(block->bmap, start, npages); bitmap_clear(block->bmap, start, npages); From df3a2de51a07089a4a729fe1f792f658df9dade4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sun, 25 Jul 2021 18:44:04 +0100 Subject: [PATCH 357/531] accel/tcg: Don't use CF_COUNT_MASK as the max value of icount_decr.u16.low MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In cpu_loop_exec_tb() we were bounding the number of insns we might try to execute in a TB using CF_COUNT_MASK. This is incorrect, because we can validly put up to 0xffff into icount_decr.u16.low. In particular, since commit 78ff82bb1b67c0d7 reduced CF_COUNT_MASK to 511 this meant that we would incorrectly only try to execute 511 instructions in a 512-instruction TB, which could result in QEMU hanging when in icount mode. Use the actual maximum value, which is 0xffff. (This brings this code in to line with the similar logic in icount_prepare_for_run() in tcg-accel-ops-icount.c.) Fixes: 78ff82bb1b67c0d7 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Resolves: https://gitlab.com/qemu-project/qemu/-/issues/499 Message-Id: <20210725174405.24568-2-peter.maydell@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index fc895cf51e..6e8dc29119 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -834,7 +834,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, /* Ensure global icount has gone forward */ icount_update(cpu); /* Refill decrementer and continue execution. */ - insns_left = MIN(CF_COUNT_MASK, cpu->icount_budget); + insns_left = MIN(0xffff, cpu->icount_budget); cpu_neg(cpu)->icount_decr.u16.low = insns_left; cpu->icount_extra = cpu->icount_budget - insns_left; From c8cf47a946200239826e58abc203dcaa4fdbb30c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sun, 25 Jul 2021 18:44:05 +0100 Subject: [PATCH 358/531] accel/tcg: Remove unnecessary check on icount_extra in cpu_loop_exec_tb() In cpu_loop_exec_tb(), we decide whether to look for a TB with exactly insns_left instructions in it using the condition (!cpu->icount_extra && insns_left > 0 && insns_left < tb->icount) The check for icount_extra == 0 is unnecessary, because we just set insns_left = MIN(0xffff, cpu->icount_budget); icount_extra = icount_budget - insns_left; and so icount_extra can only be non-zero if icount_budget > 0xffff and insns_left == 0xffff. But in that case insns_left >= tb->icount because 0xffff is much larger than TCG_MAX_INSNS, so the condition will be false anyway. Remove the unnecessary check, and instead assert: * that we are only going to execute a partial TB here if the icount budget has run out (ie icount_extra == 0) * that the number of insns we're going to execute does fit into the CF_COUNT_MASK Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-Id: <20210725174405.24568-3-peter.maydell@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 6e8dc29119..5aa42fbff3 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -843,7 +843,9 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, * execute we need to ensure we find/generate a TB with exactly * insns_left instructions in it. */ - if (!cpu->icount_extra && insns_left > 0 && insns_left < tb->icount) { + if (insns_left > 0 && insns_left < tb->icount) { + assert(insns_left <= CF_COUNT_MASK); + assert(cpu->icount_extra == 0); cpu->cflags_next_tb = (tb->cflags & ~CF_COUNT_MASK) | insns_left; } #endif From 2f0e10a4866c16e0b6f98fcc87add047200e4896 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sun, 25 Jul 2021 12:05:57 +0100 Subject: [PATCH 359/531] bitops.h: revert db1ffc32dd ("qemu/bitops.h: add bitrev8 implementation") MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit db1ffc32dd ("qemu/bitops.h: add bitrev8 implementation") introduced a bitrev8() function to reverse the bit ordering required for storing the MAC address in the q800 PROM. This function is not required since QEMU implements its own revbit8() function which does exactly the same thing. Remove the extraneous bitrev8() function and switch its only caller in hw/m68k/q800.c to use revbit8() instead. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210725110557.3007-1-mark.cave-ayland@ilande.co.uk> Signed-off-by: Richard Henderson --- hw/m68k/q800.c | 2 +- include/qemu/bitops.h | 22 ---------------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 6817c8b5d1..ac0a13060b 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -334,7 +334,7 @@ static void q800_init(MachineState *machine) prom = memory_region_get_ram_ptr(dp8393x_prom); checksum = 0; for (i = 0; i < 6; i++) { - prom[i] = bitrev8(nd_table[0].macaddr.a[i]); + prom[i] = revbit8(nd_table[0].macaddr.a[i]); checksum ^= prom[i]; } prom[7] = 0xff - checksum; diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h index 110c56e099..03213ce952 100644 --- a/include/qemu/bitops.h +++ b/include/qemu/bitops.h @@ -618,26 +618,4 @@ static inline uint64_t half_unshuffle64(uint64_t x) return x; } -/** - * bitrev8: - * @x: 8-bit value to be reversed - * - * Given an input value with bits:: - * - * ABCDEFGH - * - * return the value with its bits reversed from left to right:: - * - * HGFEDCBA - * - * Returns: the bit-reversed value. - */ -static inline uint8_t bitrev8(uint8_t x) -{ - x = ((x >> 1) & 0x55) | ((x << 1) & 0xaa); - x = ((x >> 2) & 0x33) | ((x << 2) & 0xcc); - x = (x >> 4) | (x << 4) ; - return x; -} - #endif From cd1675f8d7fa33b5071a4d3be5dcb69c38300f17 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 13 Jul 2021 13:58:41 +0000 Subject: [PATCH 360/531] nbd/server: Mark variable unused in nbd_negotiate_meta_queries From clang-13: nbd/server.c:976:22: error: variable 'bitmaps' set but not used \ [-Werror,-Wunused-but-set-variable] which is incorrect; see //bugs.llvm.org/show_bug.cgi?id=3888. Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Richard Henderson --- nbd/server.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nbd/server.c b/nbd/server.c index b60ebc3ab6..3927f7789d 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -973,7 +973,8 @@ static int nbd_negotiate_meta_queries(NBDClient *client, { int ret; g_autofree char *export_name = NULL; - g_autofree bool *bitmaps = NULL; + /* Mark unused to work around https://bugs.llvm.org/show_bug.cgi?id=3888 */ + g_autofree G_GNUC_UNUSED bool *bitmaps = NULL; NBDExportMetaContexts local_meta = {0}; uint32_t nb_queries; size_t i; From 2521c775bdfc8150396c4cb173b54d51f44c207e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 12 Jul 2021 18:29:34 +0000 Subject: [PATCH 361/531] accel/tcg: Remove unused variable in cpu_exec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From clang-13: accel/tcg/cpu-exec.c:783:15: error: variable 'cc' set but not used \ [-Werror,-Wunused-but-set-variable] Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 5aa42fbff3..e5c0ccd1a2 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -855,7 +855,6 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, int cpu_exec(CPUState *cpu) { - CPUClass *cc = CPU_GET_CLASS(cpu); int ret; SyncClocks sc = { 0 }; @@ -889,19 +888,14 @@ int cpu_exec(CPUState *cpu) * that we support, but is still unfixed in clang: * https://bugs.llvm.org/show_bug.cgi?id=21183 * - * Reload essential local variables here for those compilers. + * Reload an essential local variable here for those compilers. * Newer versions of gcc would complain about this code (-Wclobbered), * so we only perform the workaround for clang. */ cpu = current_cpu; - cc = CPU_GET_CLASS(cpu); #else - /* - * Non-buggy compilers preserve these locals; assert that - * they have the correct value. - */ + /* Non-buggy compilers preserve this; assert the correct value. */ g_assert(cpu == current_cpu); - g_assert(cc == CPU_GET_CLASS(cpu)); #endif #ifndef CONFIG_SOFTMMU From 53645dc4cb7b74db3507558c01612c3e5ea430ab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 12 Jul 2021 18:39:06 +0000 Subject: [PATCH 362/531] util/selfmap: Discard mapping on error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From clang-13: util/selfmap.c:26:21: error: variable 'errors' set but not used \ [-Werror,-Wunused-but-set-variable] Quite right of course, but there's no reason not to check errors. First, incrementing errors is incorrect, because qemu_strtoul returns an errno not a count -- just or them together so that we have a non-zero value at the end. Second, if we have an error, do not add the struct to the list, but free it instead. Cc: Alex Bennée Reviewed-by: Eric Blake Signed-off-by: Richard Henderson --- util/selfmap.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/util/selfmap.c b/util/selfmap.c index 2ec99dfdda..2c14f019ce 100644 --- a/util/selfmap.c +++ b/util/selfmap.c @@ -23,29 +23,34 @@ GSList *read_self_maps(void) gchar **fields = g_strsplit(lines[i], " ", 6); if (g_strv_length(fields) > 4) { MapInfo *e = g_new0(MapInfo, 1); - int errors; + int errors = 0; const char *end; - errors = qemu_strtoul(fields[0], &end, 16, &e->start); - errors += qemu_strtoul(end + 1, NULL, 16, &e->end); + errors |= qemu_strtoul(fields[0], &end, 16, &e->start); + errors |= qemu_strtoul(end + 1, NULL, 16, &e->end); e->is_read = fields[1][0] == 'r'; e->is_write = fields[1][1] == 'w'; e->is_exec = fields[1][2] == 'x'; e->is_priv = fields[1][3] == 'p'; - errors += qemu_strtoul(fields[2], NULL, 16, &e->offset); + errors |= qemu_strtoul(fields[2], NULL, 16, &e->offset); e->dev = g_strdup(fields[3]); - errors += qemu_strtou64(fields[4], NULL, 10, &e->inode); + errors |= qemu_strtou64(fields[4], NULL, 10, &e->inode); - /* - * The last field may have leading spaces which we - * need to strip. - */ - if (g_strv_length(fields) == 6) { - e->path = g_strdup(g_strchug(fields[5])); + if (!errors) { + /* + * The last field may have leading spaces which we + * need to strip. + */ + if (g_strv_length(fields) == 6) { + e->path = g_strdup(g_strchug(fields[5])); + } + map_info = g_slist_prepend(map_info, e); + } else { + g_free(e->dev); + g_free(e); } - map_info = g_slist_prepend(map_info, e); } g_strfreev(fields); From fe4bd9170c92e5557f9c49ac08acc54c0d752aba Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 12 Jul 2021 18:43:58 +0000 Subject: [PATCH 363/531] net/checksum: Remove unused variable in net_checksum_add_iov From clang-13: ../qemu/net/checksum.c:189:23: error: variable 'buf_off' set but not used \ [-Werror,-Wunused-but-set-variable] Reviewed-by: Eric Blake Signed-off-by: Richard Henderson --- net/checksum.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/checksum.c b/net/checksum.c index 70f4eaeb3a..68245fd748 100644 --- a/net/checksum.c +++ b/net/checksum.c @@ -186,12 +186,11 @@ uint32_t net_checksum_add_iov(const struct iovec *iov, const unsigned int iov_cnt, uint32_t iov_off, uint32_t size, uint32_t csum_offset) { - size_t iovec_off, buf_off; + size_t iovec_off; unsigned int i; uint32_t res = 0; iovec_off = 0; - buf_off = 0; for (i = 0; i < iov_cnt && size; i++) { if (iov_off < (iovec_off + iov[i].iov_len)) { size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off , size); @@ -200,7 +199,6 @@ net_checksum_add_iov(const struct iovec *iov, const unsigned int iov_cnt, res += net_checksum_add_cont(len, chunk_buf, csum_offset); csum_offset += len; - buf_off += len; iov_off += len; size -= len; } From 79fe9e4313f9dbad8ee4619031900ccabd4f8824 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 12 Jul 2021 19:57:41 +0000 Subject: [PATCH 364/531] hw/audio/adlib: Remove unused variable in adlib_callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From clang-13: hw/audio/adlib.c:189:18: error: variable 'net' set but not used \ [-Werror,-Wunused-but-set-variable] Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- hw/audio/adlib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c index 42d50d2fdc..5f979b1487 100644 --- a/hw/audio/adlib.c +++ b/hw/audio/adlib.c @@ -186,7 +186,7 @@ static int write_audio (AdlibState *s, int samples) static void adlib_callback (void *opaque, int free) { AdlibState *s = opaque; - int samples, net = 0, to_play, written; + int samples, to_play, written; samples = free >> SHIFT; if (!(s->active && s->enabled) || !samples) { @@ -219,7 +219,6 @@ static void adlib_callback (void *opaque, int free) written = write_audio (s, samples); if (written) { - net += written; samples -= written; s->pos = (s->pos + written) % s->samples; } From 2d758274ee477a96ba35ba05fe2e393c208e724b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 12 Jul 2021 20:00:18 +0000 Subject: [PATCH 365/531] hw/ppc/spapr_events: Remove unused variable from check_exception From clang-13: hw/ppc/spapr_events.c:937:14: error: variable 'xinfo' set but not used \ [-Werror,-Wunused-but-set-variable] Acked-by: David Gibson Signed-off-by: Richard Henderson --- hw/ppc/spapr_events.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index 0cfc19be19..23e2e2fff1 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -934,7 +934,6 @@ static void check_exception(PowerPCCPU *cpu, SpaprMachineState *spapr, uint32_t nret, target_ulong rets) { uint32_t mask, buf, len, event_len; - uint64_t xinfo; SpaprEventLogEntry *event; struct rtas_error_log header; int i; @@ -944,13 +943,9 @@ static void check_exception(PowerPCCPU *cpu, SpaprMachineState *spapr, return; } - xinfo = rtas_ld(args, 1); mask = rtas_ld(args, 2); buf = rtas_ld(args, 4); len = rtas_ld(args, 5); - if (nargs == 7) { - xinfo |= (uint64_t)rtas_ld(args, 6) << 32; - } event = rtas_event_log_dequeue(spapr, mask); if (!event) { From 984178d86b92be23b0efb6da769f22adb08cb83a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 12 Jul 2021 20:04:37 +0000 Subject: [PATCH 366/531] hw/pci-hist/pnv_phb4: Fix typo in pnv_phb4_ioda_write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From clang-13: hw/pci-host/pnv_phb4.c:375:18: error: variable 'v' set but not used \ [-Werror,-Wunused-but-set-variable] It's pretty clear that we meant to write back 'v' after all that computation and not 'val'. Acked-by: David Gibson Acked-by: Benjamin Herrenschmidt Reviewed-by: Cédric Le Goater Signed-off-by: Richard Henderson --- hw/pci-host/pnv_phb4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index 54f57c660a..5c375a9f28 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -392,7 +392,7 @@ static void pnv_phb4_ioda_write(PnvPHB4 *phb, uint64_t val) v &= 0xffffffffffff0000ull; v |= 0x000000000000cfffull & val; } - *tptr = val; + *tptr = v; break; } case IODA3_TBL_MBT: From 211364c21e7f757ae1acf4e72b5df39c498fb88b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 12 Jul 2021 20:18:46 +0000 Subject: [PATCH 367/531] linux-user/syscall: Remove unused variable from execve From clang-13: linux-user/syscall.c:8503:17: error: variable 'total_size' set but not used \ [-Werror,-Wunused-but-set-variable] Acked-by: Laurent Vivier Signed-off-by: Richard Henderson --- linux-user/syscall.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 376629c689..ccd3892b2d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8364,7 +8364,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, abi_ulong guest_envp; abi_ulong addr; char **q; - int total_size = 0; argc = 0; guest_argp = arg2; @@ -8396,7 +8395,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, break; if (!(*q = lock_user_string(addr))) goto execve_efault; - total_size += strlen(*q) + 1; } *q = NULL; @@ -8408,7 +8406,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, break; if (!(*q = lock_user_string(addr))) goto execve_efault; - total_size += strlen(*q) + 1; } *q = NULL; From 2bf07e788eb69bee843be274386fb20f4ab6b0f6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 12 Jul 2021 20:26:21 +0000 Subject: [PATCH 368/531] tests/unit: Remove unused variable from test_io MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From clang-13: tests/unit/test-iov.c:161:26: error: variable 't' set but not used \ [-Werror,-Wunused-but-set-variable] Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tests/unit/test-iov.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/unit/test-iov.c b/tests/unit/test-iov.c index 9c415e2f1f..5371066fb6 100644 --- a/tests/unit/test-iov.c +++ b/tests/unit/test-iov.c @@ -158,7 +158,7 @@ static void test_io(void) int sv[2]; int r; - unsigned i, j, k, s, t; + unsigned i, j, k, s; fd_set fds; unsigned niov; struct iovec *iov, *siov; @@ -182,7 +182,6 @@ static void test_io(void) FD_ZERO(&fds); - t = 0; if (fork() == 0) { /* writer */ @@ -201,7 +200,6 @@ static void test_io(void) g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0); if (r >= 0) { k += r; - t += r; usleep(g_test_rand_int_range(0, 30)); } else if (errno == EAGAIN) { select(sv[1]+1, NULL, &fds, NULL, NULL); @@ -238,7 +236,6 @@ static void test_io(void) g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0); if (r > 0) { k += r; - t += r; } else if (!r) { if (s) { break; From 5e4f6bcc296ffbd4a66ccdfb975202ba0147d306 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 6 Jul 2021 09:10:56 +0200 Subject: [PATCH 369/531] hw/nvme: remove NvmeCtrl parameter from ns setup/check functions The nvme_ns_setup and nvme_ns_check_constraints should not depend on the controller state. Refactor and remove it. Reviewed-by: Hannes Reinecke Signed-off-by: Klaus Jensen --- hw/nvme/ctrl.c | 2 +- hw/nvme/ns.c | 37 ++++++++++++++++++------------------- hw/nvme/nvme.h | 2 +- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 629b0d38c2..dd18015100 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -6498,7 +6498,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) ns = &n->namespace; ns->params.nsid = 1; - if (nvme_ns_setup(n, ns, errp)) { + if (nvme_ns_setup(ns, errp)) { return; } diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index 4275c3db63..3c4f5b8c71 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -346,8 +346,7 @@ static void nvme_zoned_ns_shutdown(NvmeNamespace *ns) assert(ns->nr_open_zones == 0); } -static int nvme_ns_check_constraints(NvmeCtrl *n, NvmeNamespace *ns, - Error **errp) +static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp) { if (!ns->blkconf.blk) { error_setg(errp, "block backend not configured"); @@ -366,20 +365,6 @@ static int nvme_ns_check_constraints(NvmeCtrl *n, NvmeNamespace *ns, return -1; } - if (!n->subsys) { - if (ns->params.detached) { - error_setg(errp, "detached requires that the nvme device is " - "linked to an nvme-subsys device"); - return -1; - } - - if (ns->params.shared) { - error_setg(errp, "shared requires that the nvme device is " - "linked to an nvme-subsys device"); - return -1; - } - } - if (ns->params.zoned) { if (ns->params.max_active_zones) { if (ns->params.max_open_zones > ns->params.max_active_zones) { @@ -411,9 +396,9 @@ static int nvme_ns_check_constraints(NvmeCtrl *n, NvmeNamespace *ns, return 0; } -int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) +int nvme_ns_setup(NvmeNamespace *ns, Error **errp) { - if (nvme_ns_check_constraints(n, ns, errp)) { + if (nvme_ns_check_constraints(ns, errp)) { return -1; } @@ -465,7 +450,21 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp) uint32_t nsid = ns->params.nsid; int i; - if (nvme_ns_setup(n, ns, errp)) { + if (!n->subsys) { + if (ns->params.detached) { + error_setg(errp, "detached requires that the nvme device is " + "linked to an nvme-subsys device"); + return; + } + + if (ns->params.shared) { + error_setg(errp, "shared requires that the nvme device is " + "linked to an nvme-subsys device"); + return; + } + } + + if (nvme_ns_setup(ns, errp)) { return; } diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h index 56f8eceed2..0868359a1e 100644 --- a/hw/nvme/nvme.h +++ b/hw/nvme/nvme.h @@ -246,7 +246,7 @@ static inline void nvme_aor_dec_active(NvmeNamespace *ns) } void nvme_ns_init_format(NvmeNamespace *ns); -int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp); +int nvme_ns_setup(NvmeNamespace *ns, Error **errp); void nvme_ns_drain(NvmeNamespace *ns); void nvme_ns_shutdown(NvmeNamespace *ns); void nvme_ns_cleanup(NvmeNamespace *ns); From cc6fb6bc506e6c47ed604fcb7b7413dff0b7d845 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 6 Jul 2021 10:48:40 +0200 Subject: [PATCH 370/531] hw/nvme: mark nvme-subsys non-hotpluggable We currently lack the infrastructure to handle subsystem hotplugging, so disable it. Reviewed-by: Hannes Reinecke Signed-off-by: Klaus Jensen --- hw/nvme/subsys.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/nvme/subsys.c b/hw/nvme/subsys.c index 192223d17c..dc7a96862f 100644 --- a/hw/nvme/subsys.c +++ b/hw/nvme/subsys.c @@ -61,6 +61,7 @@ static void nvme_subsys_class_init(ObjectClass *oc, void *data) dc->realize = nvme_subsys_realize; dc->desc = "Virtual NVMe subsystem"; + dc->hotpluggable = false; device_class_set_props(dc, nvme_subsystem_props); } From b0fde9e86133f66c054b31722fa29640f57e975c Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 6 Jul 2021 10:51:36 +0200 Subject: [PATCH 371/531] hw/nvme: unregister controller with subsystem at exit Make sure the controller is unregistered from the subsystem when device is removed. Reviewed-by: Hannes Reinecke Signed-off-by: Klaus Jensen --- hw/nvme/ctrl.c | 4 ++++ hw/nvme/nvme.h | 1 + hw/nvme/subsys.c | 5 +++++ 3 files changed, 10 insertions(+) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index dd18015100..90e3ee2b70 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -6523,6 +6523,10 @@ static void nvme_exit(PCIDevice *pci_dev) nvme_ns_cleanup(ns); } + if (n->subsys) { + nvme_subsys_unregister_ctrl(n->subsys, n); + } + g_free(n->cq); g_free(n->sq); g_free(n->aer_reqs); diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h index 0868359a1e..c4065467d8 100644 --- a/hw/nvme/nvme.h +++ b/hw/nvme/nvme.h @@ -50,6 +50,7 @@ typedef struct NvmeSubsystem { } NvmeSubsystem; int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp); +void nvme_subsys_unregister_ctrl(NvmeSubsystem *subsys, NvmeCtrl *n); static inline NvmeCtrl *nvme_subsys_ctrl(NvmeSubsystem *subsys, uint32_t cntlid) diff --git a/hw/nvme/subsys.c b/hw/nvme/subsys.c index dc7a96862f..92caa604a2 100644 --- a/hw/nvme/subsys.c +++ b/hw/nvme/subsys.c @@ -32,6 +32,11 @@ int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp) return cntlid; } +void nvme_subsys_unregister_ctrl(NvmeSubsystem *subsys, NvmeCtrl *n) +{ + subsys->ctrls[n->cntlid] = NULL; +} + static void nvme_subsys_setup(NvmeSubsystem *subsys) { const char *nqn = subsys->params.nqn ? From 234214734f7347b1bc3ceeb8f4a2ef53195a8242 Mon Sep 17 00:00:00 2001 From: Padmakar Kalghatgi Date: Fri, 9 Jul 2021 07:58:40 +0200 Subject: [PATCH 372/531] hw/nvme: error handling for too many mappings If the number of PRP/SGL mappings exceed 1024, reads and writes will fail because of an internal QEMU limitation of max 1024 vectors. Signed-off-by: Padmakar Kalghatgi Reviewed-by: Klaus Jensen [k.jensen: changed the error message to be more generic] Signed-off-by: Klaus Jensen --- hw/nvme/ctrl.c | 13 +++++++++++++ hw/nvme/trace-events | 1 + 2 files changed, 14 insertions(+) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 90e3ee2b70..ead7531bde 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -623,6 +623,10 @@ static uint16_t nvme_map_addr(NvmeCtrl *n, NvmeSg *sg, hwaddr addr, size_t len) return NVME_INVALID_USE_OF_CMB | NVME_DNR; } + if (sg->iov.niov + 1 > IOV_MAX) { + goto max_mappings_exceeded; + } + if (cmb) { return nvme_map_addr_cmb(n, &sg->iov, addr, len); } else { @@ -634,9 +638,18 @@ static uint16_t nvme_map_addr(NvmeCtrl *n, NvmeSg *sg, hwaddr addr, size_t len) return NVME_INVALID_USE_OF_CMB | NVME_DNR; } + if (sg->qsg.nsg + 1 > IOV_MAX) { + goto max_mappings_exceeded; + } + qemu_sglist_add(&sg->qsg, addr, len); return NVME_SUCCESS; + +max_mappings_exceeded: + NVME_GUEST_ERR(pci_nvme_ub_too_many_mappings, + "number of mappings exceed 1024"); + return NVME_INTERNAL_DEV_ERROR | NVME_DNR; } static inline bool nvme_addr_is_dma(NvmeCtrl *n, hwaddr addr) diff --git a/hw/nvme/trace-events b/hw/nvme/trace-events index f9a1f14e26..430eeb395b 100644 --- a/hw/nvme/trace-events +++ b/hw/nvme/trace-events @@ -199,3 +199,4 @@ pci_nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion qu pci_nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring" pci_nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring" pci_nvme_ub_unknown_css_value(void) "unknown value in cc.css field" +pci_nvme_ub_too_many_mappings(void) "too many prp/sgl mappings" From 51e90178f710d64400f8d01035dc7e4f4f9cb9da Mon Sep 17 00:00:00 2001 From: Gollu Appalanaidu Date: Fri, 18 Jun 2021 16:04:31 +0530 Subject: [PATCH 373/531] tests/qtest/nvme-test: add persistent memory region test This will test the PMR functionality. Signed-off-by: Gollu Appalanaidu Reviewed-by: Klaus Jensen [k.jensen: replaced memory-backend-file with memory-backend-ram] Signed-off-by: Klaus Jensen --- tests/qtest/nvme-test.c | 61 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/tests/qtest/nvme-test.c b/tests/qtest/nvme-test.c index d32c953a38..47e757d7e2 100644 --- a/tests/qtest/nvme-test.c +++ b/tests/qtest/nvme-test.c @@ -13,6 +13,7 @@ #include "libqos/libqtest.h" #include "libqos/qgraph.h" #include "libqos/pci.h" +#include "include/block/nvme.h" typedef struct QNvme QNvme; @@ -66,12 +67,65 @@ static void nvmetest_oob_cmb_test(void *obj, void *data, QGuestAllocator *alloc) g_assert_cmpint(qpci_io_readl(pdev, bar, cmb_bar_size - 1), !=, 0x44332211); } +static void nvmetest_pmr_reg_test(void *obj, void *data, QGuestAllocator *alloc) +{ + QNvme *nvme = obj; + QPCIDevice *pdev = &nvme->dev; + QPCIBar pmr_bar, nvme_bar; + uint32_t pmrcap, pmrsts; + + qpci_device_enable(pdev); + pmr_bar = qpci_iomap(pdev, 4, NULL); + + /* Without Enabling PMRCTL check bar enablemet */ + qpci_io_writel(pdev, pmr_bar, 0, 0xccbbaa99); + g_assert_cmpint(qpci_io_readb(pdev, pmr_bar, 0), !=, 0x99); + g_assert_cmpint(qpci_io_readw(pdev, pmr_bar, 0), !=, 0xaa99); + + /* Map NVMe Bar Register to Enable the Mem Region */ + nvme_bar = qpci_iomap(pdev, 0, NULL); + + pmrcap = qpci_io_readl(pdev, nvme_bar, 0xe00); + g_assert_cmpint(NVME_PMRCAP_RDS(pmrcap), ==, 0x1); + g_assert_cmpint(NVME_PMRCAP_WDS(pmrcap), ==, 0x1); + g_assert_cmpint(NVME_PMRCAP_BIR(pmrcap), ==, 0x4); + g_assert_cmpint(NVME_PMRCAP_PMRWBM(pmrcap), ==, 0x2); + g_assert_cmpint(NVME_PMRCAP_CMSS(pmrcap), ==, 0x1); + + /* Enable PMRCTRL */ + qpci_io_writel(pdev, nvme_bar, 0xe04, 0x1); + + qpci_io_writel(pdev, pmr_bar, 0, 0x44332211); + g_assert_cmpint(qpci_io_readb(pdev, pmr_bar, 0), ==, 0x11); + g_assert_cmpint(qpci_io_readw(pdev, pmr_bar, 0), ==, 0x2211); + g_assert_cmpint(qpci_io_readl(pdev, pmr_bar, 0), ==, 0x44332211); + + pmrsts = qpci_io_readl(pdev, nvme_bar, 0xe08); + g_assert_cmpint(NVME_PMRSTS_NRDY(pmrsts), ==, 0x0); + + /* Disable PMRCTRL */ + qpci_io_writel(pdev, nvme_bar, 0xe04, 0x0); + + qpci_io_writel(pdev, pmr_bar, 0, 0x88776655); + g_assert_cmpint(qpci_io_readb(pdev, pmr_bar, 0), !=, 0x55); + g_assert_cmpint(qpci_io_readw(pdev, pmr_bar, 0), !=, 0x6655); + g_assert_cmpint(qpci_io_readl(pdev, pmr_bar, 0), !=, 0x88776655); + + pmrsts = qpci_io_readl(pdev, nvme_bar, 0xe08); + g_assert_cmpint(NVME_PMRSTS_NRDY(pmrsts), ==, 0x1); + + qpci_iounmap(pdev, nvme_bar); + qpci_iounmap(pdev, pmr_bar); +} + static void nvme_register_nodes(void) { QOSGraphEdgeOptions opts = { .extra_device_opts = "addr=04.0,drive=drv0,serial=foo", .before_cmd_line = "-drive id=drv0,if=none,file=null-co://," - "file.read-zeroes=on,format=raw", + "file.read-zeroes=on,format=raw " + "-object memory-backend-ram,id=pmr0," + "share=on,size=8", }; add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) }); @@ -83,6 +137,11 @@ static void nvme_register_nodes(void) qos_add_test("oob-cmb-access", "nvme", nvmetest_oob_cmb_test, &(QOSGraphTestOptions) { .edge.extra_device_opts = "cmb_size_mb=2" }); + + qos_add_test("pmr-test-access", "nvme", nvmetest_pmr_reg_test, + &(QOSGraphTestOptions) { + .edge.extra_device_opts = "pmrdev=pmr0" + }); } libqos_init(nvme_register_nodes); From 5ffbaeed164da1a87619a3abfadee0c7d63ea1c4 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Fri, 23 Apr 2021 18:55:11 +0200 Subject: [PATCH 374/531] hw/nvme: fix controller hot unplugging Prior to this patch the nvme-ns devices are always children of the NvmeBus owned by the NvmeCtrl. This causes the namespaces to be unrealized when the parent device is removed. However, when subsystems are involved, this is not what we want since the namespaces may be attached to other controllers as well. This patch adds an additional NvmeBus on the subsystem device. When nvme-ns devices are realized, if the parent controller device is linked to a subsystem, the parent bus is set to the subsystem one instead. This makes sure that namespaces are kept alive and not unrealized. Reviewed-by: Hannes Reinecke Signed-off-by: Klaus Jensen --- hw/nvme/ctrl.c | 14 ++++++-------- hw/nvme/ns.c | 18 ++++++++++++++++++ hw/nvme/nvme.h | 15 ++++++++------- hw/nvme/subsys.c | 3 +++ 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index ead7531bde..2f0524e12a 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -6527,16 +6527,14 @@ static void nvme_exit(PCIDevice *pci_dev) nvme_ctrl_reset(n); - for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { - ns = nvme_ns(n, i); - if (!ns) { - continue; + if (n->subsys) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { + ns = nvme_ns(n, i); + if (ns) { + ns->attached--; + } } - nvme_ns_cleanup(ns); - } - - if (n->subsys) { nvme_subsys_unregister_ctrl(n->subsys, n); } diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index 3c4f5b8c71..b7cf1494e7 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -441,6 +441,15 @@ void nvme_ns_cleanup(NvmeNamespace *ns) } } +static void nvme_ns_unrealize(DeviceState *dev) +{ + NvmeNamespace *ns = NVME_NS(dev); + + nvme_ns_drain(ns); + nvme_ns_shutdown(ns); + nvme_ns_cleanup(ns); +} + static void nvme_ns_realize(DeviceState *dev, Error **errp) { NvmeNamespace *ns = NVME_NS(dev); @@ -462,6 +471,14 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp) "linked to an nvme-subsys device"); return; } + } else { + /* + * If this namespace belongs to a subsystem (through a link on the + * controller device), reparent the device. + */ + if (!qdev_set_parent_bus(dev, &subsys->bus.parent_bus, errp)) { + return; + } } if (nvme_ns_setup(ns, errp)) { @@ -552,6 +569,7 @@ static void nvme_ns_class_init(ObjectClass *oc, void *data) dc->bus_type = TYPE_NVME_BUS; dc->realize = nvme_ns_realize; + dc->unrealize = nvme_ns_unrealize; device_class_set_props(dc, nvme_ns_props); dc->desc = "Virtual NVMe namespace"; } diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h index c4065467d8..83ffabade4 100644 --- a/hw/nvme/nvme.h +++ b/hw/nvme/nvme.h @@ -33,12 +33,20 @@ QEMU_BUILD_BUG_ON(NVME_MAX_NAMESPACES > NVME_NSID_BROADCAST - 1); typedef struct NvmeCtrl NvmeCtrl; typedef struct NvmeNamespace NvmeNamespace; +#define TYPE_NVME_BUS "nvme-bus" +OBJECT_DECLARE_SIMPLE_TYPE(NvmeBus, NVME_BUS) + +typedef struct NvmeBus { + BusState parent_bus; +} NvmeBus; + #define TYPE_NVME_SUBSYS "nvme-subsys" #define NVME_SUBSYS(obj) \ OBJECT_CHECK(NvmeSubsystem, (obj), TYPE_NVME_SUBSYS) typedef struct NvmeSubsystem { DeviceState parent_obj; + NvmeBus bus; uint8_t subnqn[256]; NvmeCtrl *ctrls[NVME_MAX_CONTROLLERS]; @@ -365,13 +373,6 @@ typedef struct NvmeCQueue { QTAILQ_HEAD(, NvmeRequest) req_list; } NvmeCQueue; -#define TYPE_NVME_BUS "nvme-bus" -#define NVME_BUS(obj) OBJECT_CHECK(NvmeBus, (obj), TYPE_NVME_BUS) - -typedef struct NvmeBus { - BusState parent_bus; -} NvmeBus; - #define TYPE_NVME "nvme" #define NVME(obj) \ OBJECT_CHECK(NvmeCtrl, (obj), TYPE_NVME) diff --git a/hw/nvme/subsys.c b/hw/nvme/subsys.c index 92caa604a2..93c35950d6 100644 --- a/hw/nvme/subsys.c +++ b/hw/nvme/subsys.c @@ -50,6 +50,9 @@ static void nvme_subsys_realize(DeviceState *dev, Error **errp) { NvmeSubsystem *subsys = NVME_SUBSYS(dev); + qbus_create_inplace(&subsys->bus, sizeof(NvmeBus), TYPE_NVME_BUS, dev, + dev->id); + nvme_subsys_setup(subsys); } From 5d45edbeac143c0a18d82efde92cc5e22c4dc021 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 13 Jul 2021 14:34:52 +0200 Subject: [PATCH 375/531] hw/nvme: split pmrmsc register into upper and lower The specification uses a set of 32 bit PMRMSCL and PMRMSCU registers to make up the 64 bit logical PMRMSC register. Make it so. Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/nvme/ctrl.c | 10 ++++++---- include/block/nvme.h | 31 ++++++++++++++++--------------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 2f0524e12a..070d9f6a96 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -5916,11 +5916,13 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, return; } - n->bar.pmrmsc = (n->bar.pmrmsc & ~0xffffffff) | (data & 0xffffffff); + n->bar.pmrmscl = data; n->pmr.cmse = false; - if (NVME_PMRMSC_CMSE(n->bar.pmrmsc)) { - hwaddr cba = NVME_PMRMSC_CBA(n->bar.pmrmsc) << PMRMSC_CBA_SHIFT; + if (NVME_PMRMSCL_CMSE(n->bar.pmrmscl)) { + uint64_t pmrmscu = n->bar.pmrmscu; + hwaddr cba = (pmrmscu << 32) | + (NVME_PMRMSCL_CBA(n->bar.pmrmscl) << PMRMSCL_CBA_SHIFT); if (cba + int128_get64(n->pmr.dev->mr.size) < cba) { NVME_PMRSTS_SET_CBAI(n->bar.pmrsts, 1); return; @@ -5936,7 +5938,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, return; } - n->bar.pmrmsc = (n->bar.pmrmsc & 0xffffffff) | (data << 32); + n->bar.pmrmscu = data; return; default: NVME_GUEST_ERR(pci_nvme_ub_mmiowr_invalid, diff --git a/include/block/nvme.h b/include/block/nvme.h index 527105fafc..84053b68b9 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -26,7 +26,8 @@ typedef struct QEMU_PACKED NvmeBar { uint32_t pmrsts; uint32_t pmrebs; uint32_t pmrswtp; - uint64_t pmrmsc; + uint32_t pmrmscl; + uint32_t pmrmscu; uint8_t css[484]; } NvmeBar; @@ -475,25 +476,25 @@ enum NvmePmrswtpMask { #define NVME_PMRSWTP_SET_PMRSWTV(pmrswtp, val) \ (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTV_MASK) << PMRSWTP_PMRSWTV_SHIFT) -enum NvmePmrmscShift { - PMRMSC_CMSE_SHIFT = 1, - PMRMSC_CBA_SHIFT = 12, +enum NvmePmrmsclShift { + PMRMSCL_CMSE_SHIFT = 1, + PMRMSCL_CBA_SHIFT = 12, }; -enum NvmePmrmscMask { - PMRMSC_CMSE_MASK = 0x1, - PMRMSC_CBA_MASK = 0xfffffffffffff, +enum NvmePmrmsclMask { + PMRMSCL_CMSE_MASK = 0x1, + PMRMSCL_CBA_MASK = 0xfffff, }; -#define NVME_PMRMSC_CMSE(pmrmsc) \ - ((pmrmsc >> PMRMSC_CMSE_SHIFT) & PMRMSC_CMSE_MASK) -#define NVME_PMRMSC_CBA(pmrmsc) \ - ((pmrmsc >> PMRMSC_CBA_SHIFT) & PMRMSC_CBA_MASK) +#define NVME_PMRMSCL_CMSE(pmrmscl) \ + ((pmrmscl >> PMRMSCL_CMSE_SHIFT) & PMRMSCL_CMSE_MASK) +#define NVME_PMRMSCL_CBA(pmrmscl) \ + ((pmrmscl >> PMRMSCL_CBA_SHIFT) & PMRMSCL_CBA_MASK) -#define NVME_PMRMSC_SET_CMSE(pmrmsc, val) \ - (pmrmsc |= (uint64_t)(val & PMRMSC_CMSE_MASK) << PMRMSC_CMSE_SHIFT) -#define NVME_PMRMSC_SET_CBA(pmrmsc, val) \ - (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT) +#define NVME_PMRMSCL_SET_CMSE(pmrmscl, val) \ + (pmrmscl |= (uint32_t)(val & PMRMSCL_CMSE_MASK) << PMRMSCL_CMSE_SHIFT) +#define NVME_PMRMSCL_SET_CBA(pmrmscl, val) \ + (pmrmscl |= (uint32_t)(val & PMRMSCL_CBA_MASK) << PMRMSCL_CBA_SHIFT) enum NvmeSglDescriptorType { NVME_SGL_DESCR_TYPE_DATA_BLOCK = 0x0, From a316aa50e6c9f25c22a705000271d33620a40595 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 13 Jul 2021 16:29:59 +0200 Subject: [PATCH 376/531] hw/nvme: use symbolic names for registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the NvmeBarRegs enum and use these instead of explicit register offsets. Signed-off-by: Klaus Jensen Reviewed-by: Gollu Appalanaidu Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Keith Busch --- hw/nvme/ctrl.c | 44 ++++++++++++++++++++++---------------------- include/block/nvme.h | 29 ++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 070d9f6a96..23ff71f65c 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -5740,7 +5740,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, } switch (offset) { - case 0xc: /* INTMS */ + case NVME_REG_INTMS: if (unlikely(msix_enabled(&(n->parent_obj)))) { NVME_GUEST_ERR(pci_nvme_ub_mmiowr_intmask_with_msix, "undefined access to interrupt mask set" @@ -5752,7 +5752,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, trace_pci_nvme_mmio_intm_set(data & 0xffffffff, n->bar.intmc); nvme_irq_check(n); break; - case 0x10: /* INTMC */ + case NVME_REG_INTMC: if (unlikely(msix_enabled(&(n->parent_obj)))) { NVME_GUEST_ERR(pci_nvme_ub_mmiowr_intmask_with_msix, "undefined access to interrupt mask clr" @@ -5764,7 +5764,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, trace_pci_nvme_mmio_intm_clr(data & 0xffffffff, n->bar.intmc); nvme_irq_check(n); break; - case 0x14: /* CC */ + case NVME_REG_CC: trace_pci_nvme_mmio_cfg(data & 0xffffffff); /* Windows first sends data, then sends enable bit */ if (!NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc) && @@ -5798,7 +5798,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, n->bar.cc = data; } break; - case 0x1c: /* CSTS */ + case NVME_REG_CSTS: if (data & (1 << 4)) { NVME_GUEST_ERR(pci_nvme_ub_mmiowr_ssreset_w1c_unsupported, "attempted to W1C CSTS.NSSRO" @@ -5809,7 +5809,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, " of controller status"); } break; - case 0x20: /* NSSR */ + case NVME_REG_NSSR: if (data == 0x4e564d65) { trace_pci_nvme_ub_mmiowr_ssreset_unsupported(); } else { @@ -5817,38 +5817,38 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, return; } break; - case 0x24: /* AQA */ + case NVME_REG_AQA: n->bar.aqa = data & 0xffffffff; trace_pci_nvme_mmio_aqattr(data & 0xffffffff); break; - case 0x28: /* ASQ */ + case NVME_REG_ASQ: n->bar.asq = size == 8 ? data : (n->bar.asq & ~0xffffffffULL) | (data & 0xffffffff); trace_pci_nvme_mmio_asqaddr(data); break; - case 0x2c: /* ASQ hi */ + case NVME_REG_ASQ + 4: n->bar.asq = (n->bar.asq & 0xffffffff) | (data << 32); trace_pci_nvme_mmio_asqaddr_hi(data, n->bar.asq); break; - case 0x30: /* ACQ */ + case NVME_REG_ACQ: trace_pci_nvme_mmio_acqaddr(data); n->bar.acq = size == 8 ? data : (n->bar.acq & ~0xffffffffULL) | (data & 0xffffffff); break; - case 0x34: /* ACQ hi */ + case NVME_REG_ACQ + 4: n->bar.acq = (n->bar.acq & 0xffffffff) | (data << 32); trace_pci_nvme_mmio_acqaddr_hi(data, n->bar.acq); break; - case 0x38: /* CMBLOC */ + case NVME_REG_CMBLOC: NVME_GUEST_ERR(pci_nvme_ub_mmiowr_cmbloc_reserved, "invalid write to reserved CMBLOC" " when CMBSZ is zero, ignored"); return; - case 0x3C: /* CMBSZ */ + case NVME_REG_CMBSZ: NVME_GUEST_ERR(pci_nvme_ub_mmiowr_cmbsz_readonly, "invalid write to read only CMBSZ, ignored"); return; - case 0x50: /* CMBMSC */ + case NVME_REG_CMBMSC: if (!NVME_CAP_CMBS(n->bar.cap)) { return; } @@ -5876,15 +5876,15 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, } return; - case 0x54: /* CMBMSC hi */ + case NVME_REG_CMBMSC + 4: n->bar.cmbmsc = (n->bar.cmbmsc & 0xffffffff) | (data << 32); return; - case 0xe00: /* PMRCAP */ + case NVME_REG_PMRCAP: NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrcap_readonly, "invalid write to PMRCAP register, ignored"); return; - case 0xe04: /* PMRCTL */ + case NVME_REG_PMRCTL: if (!NVME_CAP_PMRS(n->bar.cap)) { return; } @@ -5899,19 +5899,19 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, n->pmr.cmse = false; } return; - case 0xe08: /* PMRSTS */ + case NVME_REG_PMRSTS: NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrsts_readonly, "invalid write to PMRSTS register, ignored"); return; - case 0xe0C: /* PMREBS */ + case NVME_REG_PMREBS: NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrebs_readonly, "invalid write to PMREBS register, ignored"); return; - case 0xe10: /* PMRSWTP */ + case NVME_REG_PMRSWTP: NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrswtp_readonly, "invalid write to PMRSWTP register, ignored"); return; - case 0xe14: /* PMRMSCL */ + case NVME_REG_PMRMSCL: if (!NVME_CAP_PMRS(n->bar.cap)) { return; } @@ -5933,7 +5933,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, } return; - case 0xe18: /* PMRMSCU */ + case NVME_REG_PMRMSCU: if (!NVME_CAP_PMRS(n->bar.cap)) { return; } @@ -5975,7 +5975,7 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) * from PMRSTS should ensure prior writes * made it to persistent media */ - if (addr == 0xe08 && + if (addr == NVME_REG_PMRSTS && (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) { memory_region_msync(&n->pmr.dev->mr, 0, n->pmr.dev->size); } diff --git a/include/block/nvme.h b/include/block/nvme.h index 84053b68b9..77aae01174 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -9,7 +9,7 @@ typedef struct QEMU_PACKED NvmeBar { uint32_t cc; uint8_t rsvd24[4]; uint32_t csts; - uint32_t nssrc; + uint32_t nssr; uint32_t aqa; uint64_t asq; uint64_t acq; @@ -31,6 +31,33 @@ typedef struct QEMU_PACKED NvmeBar { uint8_t css[484]; } NvmeBar; +enum NvmeBarRegs { + NVME_REG_CAP = offsetof(NvmeBar, cap), + NVME_REG_VS = offsetof(NvmeBar, vs), + NVME_REG_INTMS = offsetof(NvmeBar, intms), + NVME_REG_INTMC = offsetof(NvmeBar, intmc), + NVME_REG_CC = offsetof(NvmeBar, cc), + NVME_REG_CSTS = offsetof(NvmeBar, csts), + NVME_REG_NSSR = offsetof(NvmeBar, nssr), + NVME_REG_AQA = offsetof(NvmeBar, aqa), + NVME_REG_ASQ = offsetof(NvmeBar, asq), + NVME_REG_ACQ = offsetof(NvmeBar, acq), + NVME_REG_CMBLOC = offsetof(NvmeBar, cmbloc), + NVME_REG_CMBSZ = offsetof(NvmeBar, cmbsz), + NVME_REG_BPINFO = offsetof(NvmeBar, bpinfo), + NVME_REG_BPRSEL = offsetof(NvmeBar, bprsel), + NVME_REG_BPMBL = offsetof(NvmeBar, bpmbl), + NVME_REG_CMBMSC = offsetof(NvmeBar, cmbmsc), + NVME_REG_CMBSTS = offsetof(NvmeBar, cmbsts), + NVME_REG_PMRCAP = offsetof(NvmeBar, pmrcap), + NVME_REG_PMRCTL = offsetof(NvmeBar, pmrctl), + NVME_REG_PMRSTS = offsetof(NvmeBar, pmrsts), + NVME_REG_PMREBS = offsetof(NvmeBar, pmrebs), + NVME_REG_PMRSWTP = offsetof(NvmeBar, pmrswtp), + NVME_REG_PMRMSCL = offsetof(NvmeBar, pmrmscl), + NVME_REG_PMRMSCU = offsetof(NvmeBar, pmrmscu), +}; + enum NvmeCapShift { CAP_MQES_SHIFT = 0, CAP_CQR_SHIFT = 16, From 5029de44b5352d466f1b6e7c0a9f19e1259d33b3 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 13 Jul 2021 19:24:04 +0200 Subject: [PATCH 377/531] hw/nvme: fix out-of-bounds reads Peter noticed that mmio access may read into the NvmeParams member in the NvmeCtrl struct. Fix the bounds check. Reported-by: Peter Maydell Signed-off-by: Klaus Jensen Reviewed-by: Stefan Hajnoczi Reviewed-by: Peter Maydell --- hw/nvme/ctrl.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 23ff71f65c..10c2363c1d 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -5969,23 +5969,26 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) /* should RAZ, fall through for now */ } - if (addr < sizeof(n->bar)) { - /* - * When PMRWBM bit 1 is set then read from - * from PMRSTS should ensure prior writes - * made it to persistent media - */ - if (addr == NVME_REG_PMRSTS && - (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) { - memory_region_msync(&n->pmr.dev->mr, 0, n->pmr.dev->size); - } - memcpy(&val, ptr + addr, size); - } else { + if (addr > sizeof(n->bar) - size) { NVME_GUEST_ERR(pci_nvme_ub_mmiord_invalid_ofs, "MMIO read beyond last register," " offset=0x%"PRIx64", returning 0", addr); + + return 0; } + /* + * When PMRWBM bit 1 is set then read from + * from PMRSTS should ensure prior writes + * made it to persistent media + */ + if (addr == NVME_REG_PMRSTS && + (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) { + memory_region_msync(&n->pmr.dev->mr, 0, n->pmr.dev->size); + } + + memcpy(&val, ptr + addr, size); + return val; } From 49e03457f1d7dfd2a3fd6affc32d8b69f066fb75 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 13 Jul 2021 19:31:27 +0200 Subject: [PATCH 378/531] hw/nvme: fix mmio read The new PMR test unearthed a long-standing issue with MMIO reads on big-endian hosts. Fix this by unconditionally storing all controller registers in little endian. Cc: Gollu Appalanaidu Reported-by: Peter Maydell Signed-off-by: Klaus Jensen Reviewed-by: Peter Maydell --- hw/nvme/ctrl.c | 291 +++++++++++++++++++++++++++---------------------- 1 file changed, 162 insertions(+), 129 deletions(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 10c2363c1d..43dfaeac9f 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -439,10 +439,12 @@ static uint8_t nvme_sq_empty(NvmeSQueue *sq) static void nvme_irq_check(NvmeCtrl *n) { + uint32_t intms = ldl_le_p(&n->bar.intms); + if (msix_enabled(&(n->parent_obj))) { return; } - if (~n->bar.intms & n->irq_status) { + if (~intms & n->irq_status) { pci_irq_assert(&n->parent_obj); } else { pci_irq_deassert(&n->parent_obj); @@ -1289,7 +1291,7 @@ static void nvme_post_cqes(void *opaque) if (ret) { trace_pci_nvme_err_addr_write(addr); trace_pci_nvme_err_cfs(); - n->bar.csts = NVME_CSTS_FAILED; + stl_le_p(&n->bar.csts, NVME_CSTS_FAILED); break; } QTAILQ_REMOVE(&cq->req_list, req, entry); @@ -4022,7 +4024,7 @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeRequest *req) trace_pci_nvme_err_invalid_create_sq_sqid(sqid); return NVME_INVALID_QID | NVME_DNR; } - if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) { + if (unlikely(!qsize || qsize > NVME_CAP_MQES(ldq_le_p(&n->bar.cap)))) { trace_pci_nvme_err_invalid_create_sq_size(qsize); return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR; } @@ -4208,7 +4210,7 @@ static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len, return NVME_INVALID_FIELD | NVME_DNR; } - switch (NVME_CC_CSS(n->bar.cc)) { + switch (NVME_CC_CSS(ldl_le_p(&n->bar.cc))) { case NVME_CC_CSS_NVM: src_iocs = nvme_cse_iocs_nvm; /* fall through */ @@ -4370,7 +4372,7 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeRequest *req) trace_pci_nvme_err_invalid_create_cq_cqid(cqid); return NVME_INVALID_QID | NVME_DNR; } - if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) { + if (unlikely(!qsize || qsize > NVME_CAP_MQES(ldq_le_p(&n->bar.cap)))) { trace_pci_nvme_err_invalid_create_cq_size(qsize); return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR; } @@ -5163,17 +5165,19 @@ static void nvme_update_dmrsl(NvmeCtrl *n) static void nvme_select_iocs_ns(NvmeCtrl *n, NvmeNamespace *ns) { + uint32_t cc = ldl_le_p(&n->bar.cc); + ns->iocs = nvme_cse_iocs_none; switch (ns->csi) { case NVME_CSI_NVM: - if (NVME_CC_CSS(n->bar.cc) != NVME_CC_CSS_ADMIN_ONLY) { + if (NVME_CC_CSS(cc) != NVME_CC_CSS_ADMIN_ONLY) { ns->iocs = nvme_cse_iocs_nvm; } break; case NVME_CSI_ZONED: - if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_CSI) { + if (NVME_CC_CSS(cc) == NVME_CC_CSS_CSI) { ns->iocs = nvme_cse_iocs_zoned; - } else if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_NVM) { + } else if (NVME_CC_CSS(cc) == NVME_CC_CSS_NVM) { ns->iocs = nvme_cse_iocs_nvm; } break; @@ -5510,7 +5514,7 @@ static void nvme_process_sq(void *opaque) if (nvme_addr_read(n, addr, (void *)&cmd, sizeof(cmd))) { trace_pci_nvme_err_addr_read(addr); trace_pci_nvme_err_cfs(); - n->bar.csts = NVME_CSTS_FAILED; + stl_le_p(&n->bar.csts, NVME_CSTS_FAILED); break; } nvme_inc_sq_head(sq); @@ -5565,8 +5569,6 @@ static void nvme_ctrl_reset(NvmeCtrl *n) n->aer_queued = 0; n->outstanding_aers = 0; n->qs_created = false; - - n->bar.cc = 0; } static void nvme_ctrl_shutdown(NvmeCtrl *n) @@ -5605,7 +5607,12 @@ static void nvme_select_iocs(NvmeCtrl *n) static int nvme_start_ctrl(NvmeCtrl *n) { - uint32_t page_bits = NVME_CC_MPS(n->bar.cc) + 12; + uint64_t cap = ldq_le_p(&n->bar.cap); + uint32_t cc = ldl_le_p(&n->bar.cc); + uint32_t aqa = ldl_le_p(&n->bar.aqa); + uint64_t asq = ldq_le_p(&n->bar.asq); + uint64_t acq = ldq_le_p(&n->bar.acq); + uint32_t page_bits = NVME_CC_MPS(cc) + 12; uint32_t page_size = 1 << page_bits; if (unlikely(n->cq[0])) { @@ -5616,73 +5623,72 @@ static int nvme_start_ctrl(NvmeCtrl *n) trace_pci_nvme_err_startfail_sq(); return -1; } - if (unlikely(!n->bar.asq)) { + if (unlikely(!asq)) { trace_pci_nvme_err_startfail_nbarasq(); return -1; } - if (unlikely(!n->bar.acq)) { + if (unlikely(!acq)) { trace_pci_nvme_err_startfail_nbaracq(); return -1; } - if (unlikely(n->bar.asq & (page_size - 1))) { - trace_pci_nvme_err_startfail_asq_misaligned(n->bar.asq); + if (unlikely(asq & (page_size - 1))) { + trace_pci_nvme_err_startfail_asq_misaligned(asq); return -1; } - if (unlikely(n->bar.acq & (page_size - 1))) { - trace_pci_nvme_err_startfail_acq_misaligned(n->bar.acq); + if (unlikely(acq & (page_size - 1))) { + trace_pci_nvme_err_startfail_acq_misaligned(acq); return -1; } - if (unlikely(!(NVME_CAP_CSS(n->bar.cap) & (1 << NVME_CC_CSS(n->bar.cc))))) { - trace_pci_nvme_err_startfail_css(NVME_CC_CSS(n->bar.cc)); + if (unlikely(!(NVME_CAP_CSS(cap) & (1 << NVME_CC_CSS(cc))))) { + trace_pci_nvme_err_startfail_css(NVME_CC_CSS(cc)); return -1; } - if (unlikely(NVME_CC_MPS(n->bar.cc) < - NVME_CAP_MPSMIN(n->bar.cap))) { + if (unlikely(NVME_CC_MPS(cc) < NVME_CAP_MPSMIN(cap))) { trace_pci_nvme_err_startfail_page_too_small( - NVME_CC_MPS(n->bar.cc), - NVME_CAP_MPSMIN(n->bar.cap)); + NVME_CC_MPS(cc), + NVME_CAP_MPSMIN(cap)); return -1; } - if (unlikely(NVME_CC_MPS(n->bar.cc) > - NVME_CAP_MPSMAX(n->bar.cap))) { + if (unlikely(NVME_CC_MPS(cc) > + NVME_CAP_MPSMAX(cap))) { trace_pci_nvme_err_startfail_page_too_large( - NVME_CC_MPS(n->bar.cc), - NVME_CAP_MPSMAX(n->bar.cap)); + NVME_CC_MPS(cc), + NVME_CAP_MPSMAX(cap)); return -1; } - if (unlikely(NVME_CC_IOCQES(n->bar.cc) < + if (unlikely(NVME_CC_IOCQES(cc) < NVME_CTRL_CQES_MIN(n->id_ctrl.cqes))) { trace_pci_nvme_err_startfail_cqent_too_small( - NVME_CC_IOCQES(n->bar.cc), - NVME_CTRL_CQES_MIN(n->bar.cap)); + NVME_CC_IOCQES(cc), + NVME_CTRL_CQES_MIN(cap)); return -1; } - if (unlikely(NVME_CC_IOCQES(n->bar.cc) > + if (unlikely(NVME_CC_IOCQES(cc) > NVME_CTRL_CQES_MAX(n->id_ctrl.cqes))) { trace_pci_nvme_err_startfail_cqent_too_large( - NVME_CC_IOCQES(n->bar.cc), - NVME_CTRL_CQES_MAX(n->bar.cap)); + NVME_CC_IOCQES(cc), + NVME_CTRL_CQES_MAX(cap)); return -1; } - if (unlikely(NVME_CC_IOSQES(n->bar.cc) < + if (unlikely(NVME_CC_IOSQES(cc) < NVME_CTRL_SQES_MIN(n->id_ctrl.sqes))) { trace_pci_nvme_err_startfail_sqent_too_small( - NVME_CC_IOSQES(n->bar.cc), - NVME_CTRL_SQES_MIN(n->bar.cap)); + NVME_CC_IOSQES(cc), + NVME_CTRL_SQES_MIN(cap)); return -1; } - if (unlikely(NVME_CC_IOSQES(n->bar.cc) > + if (unlikely(NVME_CC_IOSQES(cc) > NVME_CTRL_SQES_MAX(n->id_ctrl.sqes))) { trace_pci_nvme_err_startfail_sqent_too_large( - NVME_CC_IOSQES(n->bar.cc), - NVME_CTRL_SQES_MAX(n->bar.cap)); + NVME_CC_IOSQES(cc), + NVME_CTRL_SQES_MAX(cap)); return -1; } - if (unlikely(!NVME_AQA_ASQS(n->bar.aqa))) { + if (unlikely(!NVME_AQA_ASQS(aqa))) { trace_pci_nvme_err_startfail_asqent_sz_zero(); return -1; } - if (unlikely(!NVME_AQA_ACQS(n->bar.aqa))) { + if (unlikely(!NVME_AQA_ACQS(aqa))) { trace_pci_nvme_err_startfail_acqent_sz_zero(); return -1; } @@ -5690,12 +5696,10 @@ static int nvme_start_ctrl(NvmeCtrl *n) n->page_bits = page_bits; n->page_size = page_size; n->max_prp_ents = n->page_size / sizeof(uint64_t); - n->cqe_size = 1 << NVME_CC_IOCQES(n->bar.cc); - n->sqe_size = 1 << NVME_CC_IOSQES(n->bar.cc); - nvme_init_cq(&n->admin_cq, n, n->bar.acq, 0, 0, - NVME_AQA_ACQS(n->bar.aqa) + 1, 1); - nvme_init_sq(&n->admin_sq, n, n->bar.asq, 0, 0, - NVME_AQA_ASQS(n->bar.aqa) + 1); + n->cqe_size = 1 << NVME_CC_IOCQES(cc); + n->sqe_size = 1 << NVME_CC_IOSQES(cc); + nvme_init_cq(&n->admin_cq, n, acq, 0, 0, NVME_AQA_ACQS(aqa) + 1, 1); + nvme_init_sq(&n->admin_sq, n, asq, 0, 0, NVME_AQA_ASQS(aqa) + 1); nvme_set_timestamp(n, 0ULL); @@ -5708,22 +5712,33 @@ static int nvme_start_ctrl(NvmeCtrl *n) static void nvme_cmb_enable_regs(NvmeCtrl *n) { - NVME_CMBLOC_SET_CDPCILS(n->bar.cmbloc, 1); - NVME_CMBLOC_SET_CDPMLS(n->bar.cmbloc, 1); - NVME_CMBLOC_SET_BIR(n->bar.cmbloc, NVME_CMB_BIR); + uint32_t cmbloc = ldl_le_p(&n->bar.cmbloc); + uint32_t cmbsz = ldl_le_p(&n->bar.cmbsz); - NVME_CMBSZ_SET_SQS(n->bar.cmbsz, 1); - NVME_CMBSZ_SET_CQS(n->bar.cmbsz, 0); - NVME_CMBSZ_SET_LISTS(n->bar.cmbsz, 1); - NVME_CMBSZ_SET_RDS(n->bar.cmbsz, 1); - NVME_CMBSZ_SET_WDS(n->bar.cmbsz, 1); - NVME_CMBSZ_SET_SZU(n->bar.cmbsz, 2); /* MBs */ - NVME_CMBSZ_SET_SZ(n->bar.cmbsz, n->params.cmb_size_mb); + NVME_CMBLOC_SET_CDPCILS(cmbloc, 1); + NVME_CMBLOC_SET_CDPMLS(cmbloc, 1); + NVME_CMBLOC_SET_BIR(cmbloc, NVME_CMB_BIR); + stl_le_p(&n->bar.cmbloc, cmbloc); + + NVME_CMBSZ_SET_SQS(cmbsz, 1); + NVME_CMBSZ_SET_CQS(cmbsz, 0); + NVME_CMBSZ_SET_LISTS(cmbsz, 1); + NVME_CMBSZ_SET_RDS(cmbsz, 1); + NVME_CMBSZ_SET_WDS(cmbsz, 1); + NVME_CMBSZ_SET_SZU(cmbsz, 2); /* MBs */ + NVME_CMBSZ_SET_SZ(cmbsz, n->params.cmb_size_mb); + stl_le_p(&n->bar.cmbsz, cmbsz); } static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, unsigned size) { + uint64_t cap = ldq_le_p(&n->bar.cap); + uint32_t cc = ldl_le_p(&n->bar.cc); + uint32_t intms = ldl_le_p(&n->bar.intms); + uint32_t csts = ldl_le_p(&n->bar.csts); + uint32_t pmrsts = ldl_le_p(&n->bar.pmrsts); + if (unlikely(offset & (sizeof(uint32_t) - 1))) { NVME_GUEST_ERR(pci_nvme_ub_mmiowr_misaligned32, "MMIO write not 32-bit aligned," @@ -5747,9 +5762,10 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, " when MSI-X is enabled"); /* should be ignored, fall through for now */ } - n->bar.intms |= data & 0xffffffff; + intms |= data; + stl_le_p(&n->bar.intms, intms); n->bar.intmc = n->bar.intms; - trace_pci_nvme_mmio_intm_set(data & 0xffffffff, n->bar.intmc); + trace_pci_nvme_mmio_intm_set(data & 0xffffffff, intms); nvme_irq_check(n); break; case NVME_REG_INTMC: @@ -5759,44 +5775,55 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, " when MSI-X is enabled"); /* should be ignored, fall through for now */ } - n->bar.intms &= ~(data & 0xffffffff); + intms &= ~data; + stl_le_p(&n->bar.intms, intms); n->bar.intmc = n->bar.intms; - trace_pci_nvme_mmio_intm_clr(data & 0xffffffff, n->bar.intmc); + trace_pci_nvme_mmio_intm_clr(data & 0xffffffff, intms); nvme_irq_check(n); break; case NVME_REG_CC: trace_pci_nvme_mmio_cfg(data & 0xffffffff); + /* Windows first sends data, then sends enable bit */ - if (!NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc) && - !NVME_CC_SHN(data) && !NVME_CC_SHN(n->bar.cc)) + if (!NVME_CC_EN(data) && !NVME_CC_EN(cc) && + !NVME_CC_SHN(data) && !NVME_CC_SHN(cc)) { - n->bar.cc = data; + cc = data; } - if (NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc)) { - n->bar.cc = data; + if (NVME_CC_EN(data) && !NVME_CC_EN(cc)) { + cc = data; + + /* flush CC since nvme_start_ctrl() needs the value */ + stl_le_p(&n->bar.cc, cc); if (unlikely(nvme_start_ctrl(n))) { trace_pci_nvme_err_startfail(); - n->bar.csts = NVME_CSTS_FAILED; + csts = NVME_CSTS_FAILED; } else { trace_pci_nvme_mmio_start_success(); - n->bar.csts = NVME_CSTS_READY; + csts = NVME_CSTS_READY; } - } else if (!NVME_CC_EN(data) && NVME_CC_EN(n->bar.cc)) { + } else if (!NVME_CC_EN(data) && NVME_CC_EN(cc)) { trace_pci_nvme_mmio_stopped(); nvme_ctrl_reset(n); - n->bar.csts &= ~NVME_CSTS_READY; + cc = 0; + csts &= ~NVME_CSTS_READY; } - if (NVME_CC_SHN(data) && !(NVME_CC_SHN(n->bar.cc))) { + + if (NVME_CC_SHN(data) && !(NVME_CC_SHN(cc))) { trace_pci_nvme_mmio_shutdown_set(); nvme_ctrl_shutdown(n); - n->bar.cc = data; - n->bar.csts |= NVME_CSTS_SHST_COMPLETE; - } else if (!NVME_CC_SHN(data) && NVME_CC_SHN(n->bar.cc)) { + cc = data; + csts |= NVME_CSTS_SHST_COMPLETE; + } else if (!NVME_CC_SHN(data) && NVME_CC_SHN(cc)) { trace_pci_nvme_mmio_shutdown_cleared(); - n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE; - n->bar.cc = data; + csts &= ~NVME_CSTS_SHST_COMPLETE; + cc = data; } + + stl_le_p(&n->bar.cc, cc); + stl_le_p(&n->bar.csts, csts); + break; case NVME_REG_CSTS: if (data & (1 << 4)) { @@ -5818,26 +5845,24 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, } break; case NVME_REG_AQA: - n->bar.aqa = data & 0xffffffff; + stl_le_p(&n->bar.aqa, data); trace_pci_nvme_mmio_aqattr(data & 0xffffffff); break; case NVME_REG_ASQ: - n->bar.asq = size == 8 ? data : - (n->bar.asq & ~0xffffffffULL) | (data & 0xffffffff); + stn_le_p(&n->bar.asq, size, data); trace_pci_nvme_mmio_asqaddr(data); break; case NVME_REG_ASQ + 4: - n->bar.asq = (n->bar.asq & 0xffffffff) | (data << 32); - trace_pci_nvme_mmio_asqaddr_hi(data, n->bar.asq); + stl_le_p((uint8_t *)&n->bar.asq + 4, data); + trace_pci_nvme_mmio_asqaddr_hi(data, ldq_le_p(&n->bar.asq)); break; case NVME_REG_ACQ: trace_pci_nvme_mmio_acqaddr(data); - n->bar.acq = size == 8 ? data : - (n->bar.acq & ~0xffffffffULL) | (data & 0xffffffff); + stn_le_p(&n->bar.acq, size, data); break; case NVME_REG_ACQ + 4: - n->bar.acq = (n->bar.acq & 0xffffffff) | (data << 32); - trace_pci_nvme_mmio_acqaddr_hi(data, n->bar.acq); + stl_le_p((uint8_t *)&n->bar.acq + 4, data); + trace_pci_nvme_mmio_acqaddr_hi(data, ldq_le_p(&n->bar.acq)); break; case NVME_REG_CMBLOC: NVME_GUEST_ERR(pci_nvme_ub_mmiowr_cmbloc_reserved, @@ -5849,21 +5874,23 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, "invalid write to read only CMBSZ, ignored"); return; case NVME_REG_CMBMSC: - if (!NVME_CAP_CMBS(n->bar.cap)) { + if (!NVME_CAP_CMBS(cap)) { return; } - n->bar.cmbmsc = size == 8 ? data : - (n->bar.cmbmsc & ~0xffffffff) | (data & 0xffffffff); + stn_le_p(&n->bar.cmbmsc, size, data); n->cmb.cmse = false; if (NVME_CMBMSC_CRE(data)) { nvme_cmb_enable_regs(n); if (NVME_CMBMSC_CMSE(data)) { - hwaddr cba = NVME_CMBMSC_CBA(data) << CMBMSC_CBA_SHIFT; + uint64_t cmbmsc = ldq_le_p(&n->bar.cmbmsc); + hwaddr cba = NVME_CMBMSC_CBA(cmbmsc) << CMBMSC_CBA_SHIFT; if (cba + int128_get64(n->cmb.mem.size) < cba) { - NVME_CMBSTS_SET_CBAI(n->bar.cmbsts, 1); + uint32_t cmbsts = ldl_le_p(&n->bar.cmbsts); + NVME_CMBSTS_SET_CBAI(cmbsts, 1); + stl_le_p(&n->bar.cmbsts, cmbsts); return; } @@ -5877,7 +5904,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, return; case NVME_REG_CMBMSC + 4: - n->bar.cmbmsc = (n->bar.cmbmsc & 0xffffffff) | (data << 32); + stl_le_p((uint8_t *)&n->bar.cmbmsc + 4, data); return; case NVME_REG_PMRCAP: @@ -5885,19 +5912,20 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, "invalid write to PMRCAP register, ignored"); return; case NVME_REG_PMRCTL: - if (!NVME_CAP_PMRS(n->bar.cap)) { + if (!NVME_CAP_PMRS(cap)) { return; } - n->bar.pmrctl = data; + stl_le_p(&n->bar.pmrctl, data); if (NVME_PMRCTL_EN(data)) { memory_region_set_enabled(&n->pmr.dev->mr, true); - n->bar.pmrsts = 0; + pmrsts = 0; } else { memory_region_set_enabled(&n->pmr.dev->mr, false); - NVME_PMRSTS_SET_NRDY(n->bar.pmrsts, 1); + NVME_PMRSTS_SET_NRDY(pmrsts, 1); n->pmr.cmse = false; } + stl_le_p(&n->bar.pmrsts, pmrsts); return; case NVME_REG_PMRSTS: NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrsts_readonly, @@ -5912,19 +5940,20 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, "invalid write to PMRSWTP register, ignored"); return; case NVME_REG_PMRMSCL: - if (!NVME_CAP_PMRS(n->bar.cap)) { + if (!NVME_CAP_PMRS(cap)) { return; } - n->bar.pmrmscl = data; + stl_le_p(&n->bar.pmrmscl, data); n->pmr.cmse = false; - if (NVME_PMRMSCL_CMSE(n->bar.pmrmscl)) { - uint64_t pmrmscu = n->bar.pmrmscu; - hwaddr cba = (pmrmscu << 32) | - (NVME_PMRMSCL_CBA(n->bar.pmrmscl) << PMRMSCL_CBA_SHIFT); + if (NVME_PMRMSCL_CMSE(data)) { + uint64_t pmrmscu = ldl_le_p(&n->bar.pmrmscu); + hwaddr cba = pmrmscu << 32 | + (NVME_PMRMSCL_CBA(data) << PMRMSCL_CBA_SHIFT); if (cba + int128_get64(n->pmr.dev->mr.size) < cba) { - NVME_PMRSTS_SET_CBAI(n->bar.pmrsts, 1); + NVME_PMRSTS_SET_CBAI(pmrsts, 1); + stl_le_p(&n->bar.pmrsts, pmrsts); return; } @@ -5934,11 +5963,11 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, return; case NVME_REG_PMRMSCU: - if (!NVME_CAP_PMRS(n->bar.cap)) { + if (!NVME_CAP_PMRS(cap)) { return; } - n->bar.pmrmscu = data; + stl_le_p(&n->bar.pmrmscu, data); return; default: NVME_GUEST_ERR(pci_nvme_ub_mmiowr_invalid, @@ -5953,7 +5982,6 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) { NvmeCtrl *n = (NvmeCtrl *)opaque; uint8_t *ptr = (uint8_t *)&n->bar; - uint64_t val = 0; trace_pci_nvme_mmio_read(addr, size); @@ -5983,13 +6011,11 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) * made it to persistent media */ if (addr == NVME_REG_PMRSTS && - (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) { + (NVME_PMRCAP_PMRWBM(ldl_le_p(&n->bar.pmrcap)) & 0x02)) { memory_region_msync(&n->pmr.dev->mr, 0, n->pmr.dev->size); } - memcpy(&val, ptr + addr, size); - - return val; + return ldn_le_p(ptr + addr, size); } static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) @@ -6247,6 +6273,7 @@ static void nvme_init_state(NvmeCtrl *n) static void nvme_init_cmb(NvmeCtrl *n, PCIDevice *pci_dev) { uint64_t cmb_size = n->params.cmb_size_mb * MiB; + uint64_t cap = ldq_le_p(&n->bar.cap); n->cmb.buf = g_malloc0(cmb_size); memory_region_init_io(&n->cmb.mem, OBJECT(n), &nvme_cmb_ops, n, @@ -6256,7 +6283,8 @@ static void nvme_init_cmb(NvmeCtrl *n, PCIDevice *pci_dev) PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH, &n->cmb.mem); - NVME_CAP_SET_CMBS(n->bar.cap, 1); + NVME_CAP_SET_CMBS(cap, 1); + stq_le_p(&n->bar.cap, cap); if (n->params.legacy_cmb) { nvme_cmb_enable_regs(n); @@ -6266,14 +6294,17 @@ static void nvme_init_cmb(NvmeCtrl *n, PCIDevice *pci_dev) static void nvme_init_pmr(NvmeCtrl *n, PCIDevice *pci_dev) { - NVME_PMRCAP_SET_RDS(n->bar.pmrcap, 1); - NVME_PMRCAP_SET_WDS(n->bar.pmrcap, 1); - NVME_PMRCAP_SET_BIR(n->bar.pmrcap, NVME_PMR_BIR); - /* Turn on bit 1 support */ - NVME_PMRCAP_SET_PMRWBM(n->bar.pmrcap, 0x02); - NVME_PMRCAP_SET_CMSS(n->bar.pmrcap, 1); + uint32_t pmrcap = ldl_le_p(&n->bar.pmrcap); - pci_register_bar(pci_dev, NVME_PMRCAP_BIR(n->bar.pmrcap), + NVME_PMRCAP_SET_RDS(pmrcap, 1); + NVME_PMRCAP_SET_WDS(pmrcap, 1); + NVME_PMRCAP_SET_BIR(pmrcap, NVME_PMR_BIR); + /* Turn on bit 1 support */ + NVME_PMRCAP_SET_PMRWBM(pmrcap, 0x02); + NVME_PMRCAP_SET_CMSS(pmrcap, 1); + stl_le_p(&n->bar.pmrcap, pmrcap); + + pci_register_bar(pci_dev, NVME_PMR_BIR, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmr.dev->mr); @@ -6363,6 +6394,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) { NvmeIdCtrl *id = &n->id_ctrl; uint8_t *pci_conf = pci_dev->config; + uint64_t cap = ldq_le_p(&n->bar.cap); id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID)); id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID)); @@ -6441,17 +6473,18 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) id->cmic |= NVME_CMIC_MULTI_CTRL; } - NVME_CAP_SET_MQES(n->bar.cap, 0x7ff); - NVME_CAP_SET_CQR(n->bar.cap, 1); - NVME_CAP_SET_TO(n->bar.cap, 0xf); - NVME_CAP_SET_CSS(n->bar.cap, NVME_CAP_CSS_NVM); - NVME_CAP_SET_CSS(n->bar.cap, NVME_CAP_CSS_CSI_SUPP); - NVME_CAP_SET_CSS(n->bar.cap, NVME_CAP_CSS_ADMIN_ONLY); - NVME_CAP_SET_MPSMAX(n->bar.cap, 4); - NVME_CAP_SET_CMBS(n->bar.cap, n->params.cmb_size_mb ? 1 : 0); - NVME_CAP_SET_PMRS(n->bar.cap, n->pmr.dev ? 1 : 0); + NVME_CAP_SET_MQES(cap, 0x7ff); + NVME_CAP_SET_CQR(cap, 1); + NVME_CAP_SET_TO(cap, 0xf); + NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_NVM); + NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_CSI_SUPP); + NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_ADMIN_ONLY); + NVME_CAP_SET_MPSMAX(cap, 4); + NVME_CAP_SET_CMBS(cap, n->params.cmb_size_mb ? 1 : 0); + NVME_CAP_SET_PMRS(cap, n->pmr.dev ? 1 : 0); + stq_le_p(&n->bar.cap, cap); - n->bar.vs = NVME_SPEC_VER; + stl_le_p(&n->bar.vs, NVME_SPEC_VER); n->bar.intmc = n->bar.intms = 0; } @@ -6602,7 +6635,7 @@ static void nvme_set_smart_warning(Object *obj, Visitor *v, const char *name, cap = NVME_SMART_SPARE | NVME_SMART_TEMPERATURE | NVME_SMART_RELIABILITY | NVME_SMART_MEDIA_READ_ONLY | NVME_SMART_FAILED_VOLATILE_MEDIA; - if (NVME_CAP_PMRS(n->bar.cap)) { + if (NVME_CAP_PMRS(ldq_le_p(&n->bar.cap))) { cap |= NVME_SMART_PMR_UNRELIABLE; } From 9631a8ab21679e3d605f7f540dd8c692b9593e02 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 13 Jul 2021 19:33:14 +0200 Subject: [PATCH 379/531] tests/qtest/nvme-test: add mmio read test Add a regression test for mmio read on big-endian hosts. Signed-off-by: Klaus Jensen Reviewed-by: Gollu Appalanaidu --- tests/qtest/nvme-test.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/qtest/nvme-test.c b/tests/qtest/nvme-test.c index 47e757d7e2..f8bafb5d70 100644 --- a/tests/qtest/nvme-test.c +++ b/tests/qtest/nvme-test.c @@ -67,6 +67,30 @@ static void nvmetest_oob_cmb_test(void *obj, void *data, QGuestAllocator *alloc) g_assert_cmpint(qpci_io_readl(pdev, bar, cmb_bar_size - 1), !=, 0x44332211); } +static void nvmetest_reg_read_test(void *obj, void *data, QGuestAllocator *alloc) +{ + QNvme *nvme = obj; + QPCIDevice *pdev = &nvme->dev; + QPCIBar bar; + uint32_t cap_lo, cap_hi; + uint64_t cap; + + qpci_device_enable(pdev); + bar = qpci_iomap(pdev, 0, NULL); + + cap_lo = qpci_io_readl(pdev, bar, 0x0); + g_assert_cmpint(NVME_CAP_MQES(cap_lo), ==, 0x7ff); + + cap_hi = qpci_io_readl(pdev, bar, 0x4); + g_assert_cmpint(NVME_CAP_MPSMAX((uint64_t)cap_hi << 32), ==, 0x4); + + cap = qpci_io_readq(pdev, bar, 0x0); + g_assert_cmpint(NVME_CAP_MQES(cap), ==, 0x7ff); + g_assert_cmpint(NVME_CAP_MPSMAX(cap), ==, 0x4); + + qpci_iounmap(pdev, bar); +} + static void nvmetest_pmr_reg_test(void *obj, void *data, QGuestAllocator *alloc) { QNvme *nvme = obj; @@ -142,6 +166,8 @@ static void nvme_register_nodes(void) &(QOSGraphTestOptions) { .edge.extra_device_opts = "pmrdev=pmr0" }); + + qos_add_test("reg-read", "nvme", nvmetest_reg_read_test, NULL); } libqos_init(nvme_register_nodes); From 1b41847afbe9974356848a61b203445e4ca645f3 Mon Sep 17 00:00:00 2001 From: Joe Komlodi Date: Mon, 26 Jul 2021 11:07:18 +0100 Subject: [PATCH 380/531] hw/arm/smmuv3: Check 31st bit to see if CD is valid The bit to see if a CD is valid is the last bit of the first word of the CD. Signed-off-by: Joe Komlodi Message-id: 1626728232-134665-2-git-send-email-joe.komlodi@xilinx.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/smmuv3-internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index 3dac5766ca..d1885ae3f2 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h @@ -570,7 +570,7 @@ static inline int pa_range(STE *ste) /* CD fields */ -#define CD_VALID(x) extract32((x)->word[0], 30, 1) +#define CD_VALID(x) extract32((x)->word[0], 31, 1) #define CD_ASID(x) extract32((x)->word[1], 16, 16) #define CD_TTB(x, sel) \ ({ \ From 953558291ec319476355900655fa53aa84ab99f0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 19 Jul 2021 11:52:57 +0100 Subject: [PATCH 381/531] qemu-options.hx: Fix formatting of -machine memory-backend option The documentation of the -machine memory-backend has some minor formatting errors: * Misindentation of the initial line meant that the whole option section is incorrectly indented in the HTML output compared to the other -machine options * The examples weren't indented, which meant that they were formatted as plain run-on text including outputting the "::" as text. * The a) b) list has no rst-format markup so it is rendered as a single run-on paragraph Fix the formatting. Signed-off-by: Peter Maydell Reviewed-by: Igor Mammedov Message-id: 20210719105257.3599-1-peter.maydell@linaro.org --- qemu-options.hx | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 99ed5ec5f1..83aa59a920 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -98,28 +98,32 @@ SRST Enables or disables ACPI Heterogeneous Memory Attribute Table (HMAT) support. The default is off. - ``memory-backend='id'`` + ``memory-backend='id'`` An alternative to legacy ``-mem-path`` and ``mem-prealloc`` options. Allows to use a memory backend as main RAM. For example: :: - -object memory-backend-file,id=pc.ram,size=512M,mem-path=/hugetlbfs,prealloc=on,share=on - -machine memory-backend=pc.ram - -m 512M + + -object memory-backend-file,id=pc.ram,size=512M,mem-path=/hugetlbfs,prealloc=on,share=on + -machine memory-backend=pc.ram + -m 512M Migration compatibility note: - a) as backend id one shall use value of 'default-ram-id', advertised by - machine type (available via ``query-machines`` QMP command), if migration - to/from old QEMU (<5.0) is expected. - b) for machine types 4.0 and older, user shall - use ``x-use-canonical-path-for-ramblock-id=off`` backend option - if migration to/from old QEMU (<5.0) is expected. + + * as backend id one shall use value of 'default-ram-id', advertised by + machine type (available via ``query-machines`` QMP command), if migration + to/from old QEMU (<5.0) is expected. + * for machine types 4.0 and older, user shall + use ``x-use-canonical-path-for-ramblock-id=off`` backend option + if migration to/from old QEMU (<5.0) is expected. + For example: :: - -object memory-backend-ram,id=pc.ram,size=512M,x-use-canonical-path-for-ramblock-id=off - -machine memory-backend=pc.ram - -m 512M + + -object memory-backend-ram,id=pc.ram,size=512M,x-use-canonical-path-for-ramblock-id=off + -machine memory-backend=pc.ram + -m 512M ERST HXCOMM Deprecated by -machine From 888f470f123521b4fc9974d2dd1cc48629d73adc Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 23 Jul 2021 17:21:41 +0100 Subject: [PATCH 382/531] target/arm: Enforce that M-profile SP low 2 bits are always zero For M-profile, unlike A-profile, the low 2 bits of SP are defined to be RES0H, which is to say that they must be hardwired to zero so that guest attempts to write non-zero values to them are ignored. Implement this behaviour by masking out the low bits: * for writes to r13 by the gdbstub * for writes to any of the various flavours of SP via MSR * for writes to r13 via store_reg() in generated code Note that all the direct uses of cpu_R[] in translate.c are in places where the register is definitely not r13 (usually because that has been checked for as an UNDEFINED or UNPREDICTABLE case and handled as UNDEF). All the other writes to regs[13] in C code are either: * A-profile only code * writes of values we can guarantee to be aligned, such as - writes of previous-SP-value plus or minus a 4-aligned constant - writes of the value in an SP limit register (which we already enforce to be aligned) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210723162146.5167-2-peter.maydell@linaro.org --- target/arm/gdbstub.c | 4 ++++ target/arm/m_helper.c | 14 ++++++++------ target/arm/translate.c | 3 +++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index a8fff2a3d0..826601b341 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -84,6 +84,10 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) if (n < 16) { /* Core integer register. */ + if (n == 13 && arm_feature(env, ARM_FEATURE_M)) { + /* M profile SP low bits are always 0 */ + tmp &= ~3; + } env->regs[n] = tmp; return 4; } diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index 7a1e35ab5b..f9a9cb466c 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -2563,13 +2563,13 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) if (!env->v7m.secure) { return; } - env->v7m.other_ss_msp = val; + env->v7m.other_ss_msp = val & ~3; return; case 0x89: /* PSP_NS */ if (!env->v7m.secure) { return; } - env->v7m.other_ss_psp = val; + env->v7m.other_ss_psp = val & ~3; return; case 0x8a: /* MSPLIM_NS */ if (!env->v7m.secure) { @@ -2638,6 +2638,8 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) limit = is_psp ? env->v7m.psplim[false] : env->v7m.msplim[false]; + val &= ~0x3; + if (val < limit) { raise_exception_ra(env, EXCP_STKOF, 0, 1, GETPC()); } @@ -2660,16 +2662,16 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) break; case 8: /* MSP */ if (v7m_using_psp(env)) { - env->v7m.other_sp = val; + env->v7m.other_sp = val & ~3; } else { - env->regs[13] = val; + env->regs[13] = val & ~3; } break; case 9: /* PSP */ if (v7m_using_psp(env)) { - env->regs[13] = val; + env->regs[13] = val & ~3; } else { - env->v7m.other_sp = val; + env->v7m.other_sp = val & ~3; } break; case 10: /* MSPLIM */ diff --git a/target/arm/translate.c b/target/arm/translate.c index 351afa43a2..80c282669f 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -291,6 +291,9 @@ void store_reg(DisasContext *s, int reg, TCGv_i32 var) */ tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3); s->base.is_jmp = DISAS_JUMP; + } else if (reg == 13 && arm_dc_feature(s, ARM_FEATURE_M)) { + /* For M-profile SP bits [1:0] are always zero */ + tcg_gen_andi_i32(var, var, ~3); } tcg_gen_mov_i32(cpu_R[reg], var); tcg_temp_free_i32(var); From 0c317eb3dd407f2ec7fcaccec79be6c3987573e2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 23 Jul 2021 17:21:42 +0100 Subject: [PATCH 383/531] target/arm: Add missing 'return's after calling v7m_exception_taken() In do_v7m_exception_exit(), we perform various checks as part of performing the exception return. If one of these checks fails, the architecture requires that we take an appropriate exception on the existing stackframe. We implement this by calling v7m_exception_taken() to set up to take the new exception, and then immediately returning from do_v7m_exception_exit() without proceeding any further with the unstack-and-exception-return process. In a couple of checks that are new in v8.1M, we forgot the "return" statement, with the effect that if bad code in the guest tripped over these checks we would set up to take a UsageFault exception but then blunder on trying to also unstack and return from the original exception, with the probable result that the guest would crash. Add the missing return statements. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210723162146.5167-3-peter.maydell@linaro.org --- target/arm/m_helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index f9a9cb466c..f352346a96 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -1554,6 +1554,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu) qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing " "stackframe: NSACR prevents clearing FPU registers\n"); v7m_exception_taken(cpu, excret, true, false); + return; } else if (!cpacr_pass) { armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, exc_secure); @@ -1561,6 +1562,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu) qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing " "stackframe: CPACR prevents clearing FPU registers\n"); v7m_exception_taken(cpu, excret, true, false); + return; } } /* Clear s0..s15, FPSCR and VPR */ From d4f6883912dba8a710274e2364c440c210e4ec65 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 23 Jul 2021 17:21:43 +0100 Subject: [PATCH 384/531] target/arm: Report M-profile alignment faults correctly to the guest For M-profile, we weren't reporting alignment faults triggered by the generic TCG code correctly to the guest. These get passed into arm_v7m_cpu_do_interrupt() as an EXCP_DATA_ABORT with an A-profile style exception.fsr value of 1. We didn't check for this, and so they fell through into the default of "assume this is an MPU fault" and were reported to the guest as a data access violation MPU fault. Report these alignment faults as UsageFaults which set the UNALIGNED bit in the UFSR. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210723162146.5167-4-peter.maydell@linaro.org --- target/arm/m_helper.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index f352346a96..20761c9487 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -2248,6 +2248,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK; break; case EXCP_UNALIGNED: + /* Unaligned faults reported by M-profile aware code */ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure); env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNALIGNED_MASK; break; @@ -2320,6 +2321,13 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) } armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false); break; + case 0x1: /* Alignment fault reported by generic code */ + qemu_log_mask(CPU_LOG_INT, + "...really UsageFault with UFSR.UNALIGNED\n"); + env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNALIGNED_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, + env->v7m.secure); + break; default: /* * All other FSR values are either MPU faults or "can't happen From 41487794f5af977e992870e18521bed88daa68d5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 23 Jul 2021 17:21:44 +0100 Subject: [PATCH 385/531] hw/intc/armv7m_nvic: ISCR.ISRPENDING is set for non-enabled pending interrupts The ISCR.ISRPENDING bit is set when an external interrupt is pending. This is true whether that external interrupt is enabled or not. This means that we can't use 's->vectpending == 0' as a shortcut to "ISRPENDING is zero", because s->vectpending indicates only the highest priority pending enabled interrupt. Remove the incorrect optimization so that if there is no pending enabled interrupt we fall through to scanning through the whole interrupt array. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210723162146.5167-5-peter.maydell@linaro.org --- hw/intc/armv7m_nvic.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 94fe00235a..2aba213682 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -127,15 +127,14 @@ static bool nvic_isrpending(NVICState *s) { int irq; - /* We can shortcut if the highest priority pending interrupt - * happens to be external or if there is nothing pending. + /* + * We can shortcut if the highest priority pending interrupt + * happens to be external; if not we need to check the whole + * vectors[] array. */ if (s->vectpending > NVIC_FIRST_IRQ) { return true; } - if (s->vectpending == 0) { - return false; - } for (irq = NVIC_FIRST_IRQ; irq < s->num_irq; irq++) { if (s->vectors[irq].pending) { From 7caad65756c0afaf4b238b068ab61481eb68a1dc Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 23 Jul 2021 17:21:45 +0100 Subject: [PATCH 386/531] hw/intc/armv7m_nvic: Correct size of ICSR.VECTPENDING The VECTPENDING field in the ICSR is 9 bits wide, in bits [20:12] of the register. We were incorrectly masking it to 8 bits, so it would report the wrong value if the pending exception was greater than 256. Fix the bug. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210723162146.5167-6-peter.maydell@linaro.org --- hw/intc/armv7m_nvic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 2aba213682..c9149a3b22 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -1039,7 +1039,7 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) /* VECTACTIVE */ val = cpu->env.v7m.exception; /* VECTPENDING */ - val |= (s->vectpending & 0xff) << 12; + val |= (s->vectpending & 0x1ff) << 12; /* ISRPENDING - set if any external IRQ is pending */ if (nvic_isrpending(s)) { val |= (1 << 22); From 845d27a91315bc1e3a0000339c5ee46ef63598a5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 23 Jul 2021 17:21:46 +0100 Subject: [PATCH 387/531] hw/intc/armv7m_nvic: for v8.1M VECTPENDING hides S exceptions from NS In Arm v8.1M the VECTPENDING field in the ICSR has new behaviour: if the register is accessed NonSecure and the highest priority pending enabled exception (that would be returned in the VECTPENDING field) targets Secure, then the VECTPENDING field must read 1 rather than the exception number of the pending exception. Implement this. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210723162146.5167-7-peter.maydell@linaro.org --- hw/intc/armv7m_nvic.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index c9149a3b22..1e7ddcb94c 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -804,6 +804,16 @@ void armv7m_nvic_acknowledge_irq(void *opaque) nvic_irq_update(s); } +static bool vectpending_targets_secure(NVICState *s) +{ + /* Return true if s->vectpending targets Secure state */ + if (s->vectpending_is_s_banked) { + return true; + } + return !exc_is_banked(s->vectpending) && + exc_targets_secure(s, s->vectpending); +} + void armv7m_nvic_get_pending_irq_info(void *opaque, int *pirq, bool *ptargets_secure) { @@ -813,12 +823,7 @@ void armv7m_nvic_get_pending_irq_info(void *opaque, assert(pending > ARMV7M_EXCP_RESET && pending < s->num_irq); - if (s->vectpending_is_s_banked) { - targets_secure = true; - } else { - targets_secure = !exc_is_banked(pending) && - exc_targets_secure(s, pending); - } + targets_secure = vectpending_targets_secure(s); trace_nvic_get_pending_irq_info(pending, targets_secure); @@ -1039,7 +1044,19 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) /* VECTACTIVE */ val = cpu->env.v7m.exception; /* VECTPENDING */ - val |= (s->vectpending & 0x1ff) << 12; + if (s->vectpending) { + /* + * From v8.1M VECTPENDING must read as 1 if accessed as + * NonSecure and the highest priority pending and enabled + * exception targets Secure. + */ + int vp = s->vectpending; + if (!attrs.secure && arm_feature(&cpu->env, ARM_FEATURE_V8_1M) && + vectpending_targets_secure(s)) { + vp = 1; + } + val |= (vp & 0x1ff) << 12; + } /* ISRPENDING - set if any external IRQ is pending */ if (nvic_isrpending(s)) { val |= (1 << 22); From a476b2167296c0f8bfd6a66d1eb54ca39ea0e6f2 Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Fri, 23 Jul 2021 14:58:28 +0800 Subject: [PATCH 388/531] docs: Update path that mentions deprecated.rst Missed in commit f3478392 "docs: Move deprecation, build and license info out of system/" Signed-off-by: Mao Zhongyi Reviewed-by: Peter Maydell Message-id: 20210723065828.1336760-1-maozhongyi@cmss.chinamobile.com Signed-off-by: Peter Maydell --- MAINTAINERS | 2 +- configure | 2 +- target/i386/cpu.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 445f7fe2d1..42ac45c3e5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3439,7 +3439,7 @@ F: contrib/gitdm/* Incompatible changes R: libvir-list@redhat.com -F: docs/system/deprecated.rst +F: docs/about/deprecated.rst Build System ------------ diff --git a/configure b/configure index 69cef68861..79e2ddc74e 100755 --- a/configure +++ b/configure @@ -5230,7 +5230,7 @@ fi if test -n "${deprecated_features}"; then echo "Warning, deprecated features enabled." - echo "Please see docs/system/deprecated.rst" + echo "Please see docs/about/deprecated.rst" echo " features: ${deprecated_features}" fi diff --git a/target/i386/cpu.c b/target/i386/cpu.c index edb97ebbbe..34a7ce865b 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -4110,7 +4110,7 @@ static const X86CPUDefinition builtin_x86_defs[] = { * none", but this is just for compatibility while libvirt isn't * adapted to resolve CPU model versions before creating VMs. * See "Runnability guarantee of CPU models" at - * docs/system/deprecated.rst. + * docs/about/deprecated.rst. */ X86CPUVersion default_cpu_version = 1; From dc0bc8e7855643c4c2aaff74409bada9761b390e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jul 2021 10:33:42 -1000 Subject: [PATCH 389/531] target/arm: Correctly bound length in sve_zcr_get_valid_len Currently, our only caller is sve_zcr_len_for_el, which has already masked the length extracted from ZCR_ELx, so the masking done here is a nop. But we will shortly have uses from other locations, where the length will be unmasked. Saturate the length to ARM_MAX_VQ instead of truncating to the low 4 bits. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20210723203344.968563-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 0c07ca9837..8c1d8dbce3 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6461,7 +6461,9 @@ static uint32_t sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len) { uint32_t end_len; - end_len = start_len &= 0xf; + start_len = MIN(start_len, ARM_MAX_VQ - 1); + end_len = start_len; + if (!test_bit(start_len, cpu->sve_vq_map)) { end_len = find_last_bit(cpu->sve_vq_map, start_len); assert(end_len < start_len); From ce440581c1446e56d911d83c9c3b760ae4f98b3e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jul 2021 10:33:43 -1000 Subject: [PATCH 390/531] target/arm: Export aarch64_sve_zcr_get_valid_len Rename from sve_zcr_get_valid_len and make accessible from outside of helper.c. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20210723203344.968563-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 4 ++-- target/arm/internals.h | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 8c1d8dbce3..155d8bf239 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6457,7 +6457,7 @@ int sve_exception_el(CPUARMState *env, int el) return 0; } -static uint32_t sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len) +uint32_t aarch64_sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len) { uint32_t end_len; @@ -6489,7 +6489,7 @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el) zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[3]); } - return sve_zcr_get_valid_len(cpu, zcr_len); + return aarch64_sve_zcr_get_valid_len(cpu, zcr_len); } static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, diff --git a/target/arm/internals.h b/target/arm/internals.h index 11a72013f5..cd2ea8a388 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -177,6 +177,16 @@ void arm_translate_init(void); void arm_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb); #endif /* CONFIG_TCG */ +/** + * aarch64_sve_zcr_get_valid_len: + * @cpu: cpu context + * @start_len: maximum len to consider + * + * Return the maximum supported sve vector length <= @start_len. + * Note that both @start_len and the return value are in units + * of ZCR_ELx.LEN, so the vector bit length is (x + 1) * 128. + */ +uint32_t aarch64_sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len); enum arm_fprounding { FPROUNDING_TIEEVEN, From b3d52804c591b478ec0620253c2bd71e4ff87bb9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jul 2021 10:33:44 -1000 Subject: [PATCH 391/531] target/arm: Add sve-default-vector-length cpu property Mirror the behavour of /proc/sys/abi/sve_default_vector_length under the real linux kernel. We have no way of passing along a real default across exec like the kernel can, but this is a decent way of adjusting the startup vector length of a process. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/482 Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20210723203344.968563-4-richard.henderson@linaro.org [PMM: tweaked docs formatting, document -1 special-case, added fixup patch from RTH mentioning QEMU's maximum veclen.] Signed-off-by: Peter Maydell --- docs/system/arm/cpu-features.rst | 15 ++++++++ target/arm/cpu.c | 14 ++++++-- target/arm/cpu.h | 5 +++ target/arm/cpu64.c | 60 ++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 2 deletions(-) diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst index c455442eaf..11dce5c603 100644 --- a/docs/system/arm/cpu-features.rst +++ b/docs/system/arm/cpu-features.rst @@ -376,3 +376,18 @@ verbose command lines. However, the recommended way to select vector lengths is to explicitly enable each desired length. Therefore only example's (1), (4), and (6) exhibit recommended uses of the properties. +SVE User-mode Default Vector Length Property +-------------------------------------------- + +For qemu-aarch64, the cpu property ``sve-default-vector-length=N`` is +defined to mirror the Linux kernel parameter file +``/proc/sys/abi/sve_default_vector_length``. The default length, ``N``, +is in units of bytes and must be between 16 and 8192. +If not specified, the default vector length is 64. + +If the default length is larger than the maximum vector length enabled, +the actual vector length will be reduced. Note that the maximum vector +length supported by QEMU is 256. + +If this property is set to ``-1`` then the default vector length +is set to the maximum possible length. diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 752b15bb79..2866dd7658 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -201,7 +201,8 @@ static void arm_cpu_reset(DeviceState *dev) env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 16, 2, 3); /* with reasonable vector length */ if (cpu_isar_feature(aa64_sve, cpu)) { - env->vfp.zcr_el[1] = MIN(cpu->sve_max_vq - 1, 3); + env->vfp.zcr_el[1] = + aarch64_sve_zcr_get_valid_len(cpu, cpu->sve_default_vq - 1); } /* * Enable TBI0 but not TBI1. @@ -1051,7 +1052,16 @@ static void arm_cpu_initfn(Object *obj) QLIST_INIT(&cpu->pre_el_change_hooks); QLIST_INIT(&cpu->el_change_hooks); -#ifndef CONFIG_USER_ONLY +#ifdef CONFIG_USER_ONLY +# ifdef TARGET_AARCH64 + /* + * The linux kernel defaults to 512-bit vectors, when sve is supported. + * See documentation for /proc/sys/abi/sve_default_vector_length, and + * our corresponding sve-default-vector-length cpu property. + */ + cpu->sve_default_vq = 4; +# endif +#else /* Our inbound IRQ and FIQ lines */ if (kvm_enabled()) { /* VIRQ and VFIQ are unused with KVM but we add them to maintain diff --git a/target/arm/cpu.h b/target/arm/cpu.h index be9a4dceae..9f0a5f84d5 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1006,6 +1006,11 @@ struct ARMCPU { /* Used to set the maximum vector length the cpu will support. */ uint32_t sve_max_vq; +#ifdef CONFIG_USER_ONLY + /* Used to set the default vector length at process start. */ + uint32_t sve_default_vq; +#endif + /* * In sve_vq_map each set bit is a supported vector length of * (bit-number + 1) * 16 bytes, i.e. each bit number + 1 is the vector diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index c7a1626bec..c690318a9b 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -559,6 +559,59 @@ static void cpu_arm_set_sve(Object *obj, bool value, Error **errp) cpu->isar.id_aa64pfr0 = t; } +#ifdef CONFIG_USER_ONLY +/* Mirror linux /proc/sys/abi/sve_default_vector_length. */ +static void cpu_arm_set_sve_default_vec_len(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + int32_t default_len, default_vq, remainder; + + if (!visit_type_int32(v, name, &default_len, errp)) { + return; + } + + /* Undocumented, but the kernel allows -1 to indicate "maximum". */ + if (default_len == -1) { + cpu->sve_default_vq = ARM_MAX_VQ; + return; + } + + default_vq = default_len / 16; + remainder = default_len % 16; + + /* + * Note that the 512 max comes from include/uapi/asm/sve_context.h + * and is the maximum architectural width of ZCR_ELx.LEN. + */ + if (remainder || default_vq < 1 || default_vq > 512) { + error_setg(errp, "cannot set sve-default-vector-length"); + if (remainder) { + error_append_hint(errp, "Vector length not a multiple of 16\n"); + } else if (default_vq < 1) { + error_append_hint(errp, "Vector length smaller than 16\n"); + } else { + error_append_hint(errp, "Vector length larger than %d\n", + 512 * 16); + } + return; + } + + cpu->sve_default_vq = default_vq; +} + +static void cpu_arm_get_sve_default_vec_len(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + int32_t value = cpu->sve_default_vq * 16; + + visit_type_int32(v, name, &value, errp); +} +#endif + void aarch64_add_sve_properties(Object *obj) { uint32_t vq; @@ -571,6 +624,13 @@ void aarch64_add_sve_properties(Object *obj) object_property_add(obj, name, "bool", cpu_arm_get_sve_vq, cpu_arm_set_sve_vq, NULL, NULL); } + +#ifdef CONFIG_USER_ONLY + /* Mirror linux /proc/sys/abi/sve_default_vector_length. */ + object_property_add(obj, "sve-default-vector-length", "int32", + cpu_arm_get_sve_default_vec_len, + cpu_arm_set_sve_default_vec_len, NULL, NULL); +#endif } void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp) From b1c2a6bd3d035a60bc7c6cbc109996af8cfe2b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 26 Jul 2021 17:09:53 +0200 Subject: [PATCH 392/531] hw/arm/nseries: Display hexadecimal value with '0x' prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20210726150953.1218690-1-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/nseries.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index 906c915df7..af3164c551 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -692,7 +692,7 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len) default: bad_cmd: qemu_log_mask(LOG_GUEST_ERROR, - "%s: unknown command %02x\n", __func__, s->cmd); + "%s: unknown command 0x%02x\n", __func__, s->cmd); break; } From e229a179a503f2aee43a76888cf12fbdfe8a3749 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 13 Jul 2021 16:28:52 +0930 Subject: [PATCH 393/531] hw: aspeed_gpio: Fix memory size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The macro used to calculate the maximum memory size of the MMIO region had a mistake, causing all GPIO models to create a mapping of 0x9D8. The intent was to have it be 0x9D8 - 0x800. This extra size doesn't matter on ast2400 and ast2500, which have a 4KB region set aside for the GPIO controller. On the ast2600 the 3.3V and 1.8V GPIO controllers are 2KB apart, so the regions would overlap. Worse was the 1.8V controller would map over the top of the following peripheral, which happens to be the RTC. The mmio region used by each device is a maximum of 2KB, so avoid the calculations and hard code this as the maximum. Fixes: 36d737ee82b2 ("hw/gpio: Add in AST2600 specific implementation") Signed-off-by: Joel Stanley Reviewed-by: Rashmica Gupta Reviewed-by: Cédric Le Goater Message-id: 20210713065854.134634-2-joel@jms.id.au [PMM: fix autocorrect error in commit message] Signed-off-by: Peter Maydell --- hw/gpio/aspeed_gpio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index 6ae0116be7..b3dec44480 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -207,7 +207,6 @@ #define GPIO_1_8V_MEM_SIZE 0x9D8 #define GPIO_1_8V_REG_ARRAY_SIZE ((GPIO_1_8V_MEM_SIZE - \ GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_MAX_MEM_SIZE MAX(GPIO_3_6V_MEM_SIZE, GPIO_1_8V_MEM_SIZE) static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio) { @@ -849,7 +848,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error **errp) } memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s, - TYPE_ASPEED_GPIO, GPIO_MAX_MEM_SIZE); + TYPE_ASPEED_GPIO, 0x800); sysbus_init_mmio(sbd, &s->iomem); } From 3e61a13af3d3a1942a1ec2f6dfd7b407a43e4273 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 20 Jul 2021 14:54:08 +0200 Subject: [PATCH 394/531] vl: Don't continue after -smp help. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We continue after -smp help: $ qemu-system-x86_64 -smp help -display none -monitor stdio smp-opts options: cores= cpus= dies= maxcpus= sockets= threads= QEMU 6.0.50 monitor - type 'help' for more information (qemu) Other options, such as -object help and -device help, don't. Adjust -smp not to continue either. Cc: Paolo Bonzini Signed-off-by: Markus Armbruster Message-Id: <20210720125408.387910-17-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pankaj Gupta Acked-by: Michael S. Tsirkin --- softmmu/vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index f815acccaa..4dee472c79 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1545,7 +1545,7 @@ machine_parse_property_opt(QemuOptsList *opts_list, const char *propname, prop = keyval_parse(arg, opts_list->implied_opt_name, &help, errp); if (help) { qemu_opts_print_help(opts_list, true); - return; + exit(0); } opts = qdict_new(); qdict_put(opts, propname, prop); From f2da205cb4142259d9bc6b9d4596ebbe2426fe49 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 27 Jul 2021 18:07:52 +0100 Subject: [PATCH 395/531] Update version for v6.1.0-rc1 release Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7d5e1d8670..f51337edb0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.90 +6.0.91 From 6ebc0048dd8ff93c2847739599afa630f3d9dabd Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 15 Jul 2021 18:50:44 +0200 Subject: [PATCH 396/531] ppc/pegasos2: Fix spurious warning with -bios The -append option is currently not compatible with -bios (as we don't yet emulate nvram so we can only put it in the environment with VOF). Therefore a warning is printed if -append is used with -bios but because the default value of kernel_cmdline seems to be an empty string instead of NULL this warning was printed even without -append when -bios is used. Only print warning if -append is given. Signed-off-by: BALATON Zoltan Message-Id: <483ac599a1407b766179aaea2794aed60cc09f53.1626367844.git.balaton@eik.bme.hu> Signed-off-by: David Gibson --- hw/ppc/pegasos2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index 9fad1854b1..b8ce859f1a 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -191,7 +191,7 @@ static void pegasos2_init(MachineState *machine) warn_report("Option -kernel may be ineffective with -bios."); } } - if (machine->kernel_cmdline && !pm->vof) { + if (!pm->vof && machine->kernel_cmdline && machine->kernel_cmdline[0]) { warn_report("Option -append may be ineffective with -bios."); } } From 793abe24aa9c6ad1a06dee091fa4dd4479fef482 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 15 Jul 2021 18:50:44 +0200 Subject: [PATCH 397/531] i2c/smbus_eeprom: Add feature bit to SPD data Add the differential clock input feature bit to the generated SPD data. Most guests don't seem to care but pegasos2 firmware version 1.2 checks for this bit and stops with unsupported module type error if it's not present. Since this feature is likely present on real memory modules add it in the general code rather than patching the generated SPD data in pegasos2 board only. Signed-off-by: BALATON Zoltan Message-Id: <19d42ade295d5297aa624a9eb757b8df18cf64d6.1626367844.git.balaton@eik.bme.hu> Acked-by: Corey Minyard Signed-off-by: David Gibson --- hw/i2c/smbus_eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c index 4d2bf99207..12c5741f38 100644 --- a/hw/i2c/smbus_eeprom.c +++ b/hw/i2c/smbus_eeprom.c @@ -276,7 +276,7 @@ uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t ram_size) spd[18] = 12; /* ~CAS latencies supported */ spd[19] = (type == DDR2 ? 0 : 1); /* reserved / ~CS latencies supported */ spd[20] = 2; /* DIMM type / ~WE latencies */ - /* module features */ + spd[21] = (type < DDR2 ? 0x20 : 0); /* module features */ /* memory chip features */ spd[23] = 0x12; /* clock cycle time @ medium CAS latency */ /* data access time */ From 2d1154bd95a8bfea30cc59de8e080e5a016a9bee Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 20 Jul 2021 10:55:07 -0300 Subject: [PATCH 398/531] target/ppc: Ease L=0 requirement on cmp/cmpi/cmpl/cmpli for ppc32 In commit 8f0a4b6a9b, we started to require L=0 for ppc32 to match what The Programming Environments Manual say: "For 32-bit implementations, the L field must be cleared, otherwise the instruction form is invalid." The stricter behavior, however, broke AROS boot on sam460ex, which is a regression from 6.0. This patch partially reverts the change, raising the exception only for CPUs known to require L=0 (e500 and e500mc) and logging a guest error for other cases. Both behaviors are acceptable by the PowerISA, which allows "the system illegal instruction error handler to be invoked or yield boundedly undefined results." Reported-by: BALATON Zoltan Fixes: 8f0a4b6a9b ("target/ppc: Move cmp/cmpi/cmpl/cmpli to decodetree") Tested-by: BALATON Zoltan Signed-off-by: Matheus Ferst Message-Id: <20210720135507.2444635-1-matheus.ferst@eldorado.org.br> Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target/ppc/translate/fixedpoint-impl.c.inc | 58 +++++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/target/ppc/translate/fixedpoint-impl.c.inc b/target/ppc/translate/fixedpoint-impl.c.inc index 8864ac4516..2e2518ee15 100644 --- a/target/ppc/translate/fixedpoint-impl.c.inc +++ b/target/ppc/translate/fixedpoint-impl.c.inc @@ -171,8 +171,35 @@ TRANS64(PSTD, do_ldst_PLS_D, false, true, MO_Q) static bool do_cmp_X(DisasContext *ctx, arg_X_bfl *a, bool s) { + if ((ctx->insns_flags & PPC_64B) == 0) { + /* + * For 32-bit implementations, The Programming Environments Manual says + * that "the L field must be cleared, otherwise the instruction form is + * invalid." It seems, however, that most 32-bit CPUs ignore invalid + * forms (e.g., section "Instruction Formats" of the 405 and 440 + * manuals, "Integer Compare Instructions" of the 601 manual), with the + * notable exception of the e500 and e500mc, where L=1 was reported to + * cause an exception. + */ + if (a->l) { + if ((ctx->insns_flags2 & PPC2_BOOKE206)) { + /* + * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc), + * generate an illegal instruction exception. + */ + return false; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n", + s ? "" : "L", ctx->cia); + } + } + gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf); + return true; + } + + /* For 64-bit implementations, deal with bit L accordingly. */ if (a->l) { - REQUIRE_64BIT(ctx); gen_op_cmp(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf); } else { gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf); @@ -182,8 +209,35 @@ static bool do_cmp_X(DisasContext *ctx, arg_X_bfl *a, bool s) static bool do_cmp_D(DisasContext *ctx, arg_D_bf *a, bool s) { + if ((ctx->insns_flags & PPC_64B) == 0) { + /* + * For 32-bit implementations, The Programming Environments Manual says + * that "the L field must be cleared, otherwise the instruction form is + * invalid." It seems, however, that most 32-bit CPUs ignore invalid + * forms (e.g., section "Instruction Formats" of the 405 and 440 + * manuals, "Integer Compare Instructions" of the 601 manual), with the + * notable exception of the e500 and e500mc, where L=1 was reported to + * cause an exception. + */ + if (a->l) { + if ((ctx->insns_flags2 & PPC2_BOOKE206)) { + /* + * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc), + * generate an illegal instruction exception. + */ + return false; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n", + s ? "I" : "LI", ctx->cia); + } + } + gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf); + return true; + } + + /* For 64-bit implementations, deal with bit L accordingly. */ if (a->l) { - REQUIRE_64BIT(ctx); gen_op_cmp(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf); } else { gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf); From 14c7e06e722af6f5459ab92bae3023bb336fa497 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Tue, 20 Jul 2021 15:07:26 +1000 Subject: [PATCH 399/531] ppc/vof: Fix Coverity issues Coverity reported issues which are caused by mixing of signed return codes from DTC and unsigned return codes of the client interface. This introduces PROM_ERROR and makes distinction between the error types. This fixes NEGATIVE_RETURNS, OVERRUN issues reported by Coverity. This adds a comment about the return parameters number in the VOF hcall. The reason for such counting is to keep the numbers look the same in vof_client_handle() and the Linux (an OF client). vmc->client_architecture_support() returns target_ulong and we want to propagate this to the client (for example H_MULTI_THREADS_ACTIVE). The VOF path to do_client_architecture_support() needs chopping off the top 32bit but SLOF's H_CAS does not; and either way the return values are either 0 or 32bit negative error code. For now this chops the top 32bits. This makes "claim" fail if the allocated address is above 4GB as the client interface is 32bit. This still allows claiming memory above 4GB as potentially initrd can be put there and the client can read the address from the FDT's "available" property. Fixes: CID 1458139, 1458138, 1458137, 1458133, 1458132 Signed-off-by: Alexey Kardashevskiy Message-Id: <20210720050726.2737405-1-aik@ozlabs.ru> Signed-off-by: David Gibson --- hw/ppc/trace-events | 4 +- hw/ppc/vof.c | 139 +++++++++++++++++++++++-------------------- include/hw/ppc/vof.h | 2 + 3 files changed, 78 insertions(+), 67 deletions(-) diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 6e90a01072..da6e74b80d 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -88,8 +88,8 @@ vof_getproplen(uint32_t ph, const char *prop, uint32_t ret) "ph=0x%x \"%s\" => l vof_setprop(uint32_t ph, const char *prop, const char *val, uint32_t vallen, uint32_t ret) "ph=0x%x \"%s\" [%s] len=%d => ret=%d" vof_open(const char *path, uint32_t ph, uint32_t ih) "%s ph=0x%x => ih=0x%x" vof_interpret(const char *cmd, uint32_t param1, uint32_t param2, uint32_t ret, uint32_t ret2) "[%s] 0x%x 0x%x => 0x%x 0x%x" -vof_package_to_path(uint32_t ph, const char *tmp, uint32_t ret) "ph=0x%x => %s len=%d" -vof_instance_to_path(uint32_t ih, uint32_t ph, const char *tmp, uint32_t ret) "ih=0x%x ph=0x%x => %s len=%d" +vof_package_to_path(uint32_t ph, const char *tmp, int ret) "ph=0x%x => %s len=%d" +vof_instance_to_path(uint32_t ih, uint32_t ph, const char *tmp, int ret) "ih=0x%x ph=0x%x => %s len=%d" vof_instance_to_package(uint32_t ih, uint32_t ph) "ih=0x%x => ph=0x%x" vof_write(uint32_t ih, unsigned cb, const char *msg) "ih=0x%x [%u] \"%s\"" vof_avail(uint64_t start, uint64_t end, uint64_t size) "0x%"PRIx64"..0x%"PRIx64" size=0x%"PRIx64 diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c index 81f6596215..73adc44ec2 100644 --- a/hw/ppc/vof.c +++ b/hw/ppc/vof.c @@ -160,7 +160,7 @@ static int path_offset(const void *fdt, const char *path) static uint32_t vof_finddevice(const void *fdt, uint32_t nodeaddr) { char fullnode[VOF_MAX_PATH]; - uint32_t ret = -1; + uint32_t ret = PROM_ERROR; int offset; if (readstr(nodeaddr, fullnode, sizeof(fullnode))) { @@ -172,7 +172,7 @@ static uint32_t vof_finddevice(const void *fdt, uint32_t nodeaddr) ret = fdt_get_phandle(fdt, offset); } trace_vof_finddevice(fullnode, ret); - return (uint32_t) ret; + return ret; } static const void *getprop(const void *fdt, int nodeoff, const char *propname, @@ -229,10 +229,10 @@ static uint32_t vof_getprop(const void *fdt, uint32_t nodeph, uint32_t pname, bool write0; if (nodeoff < 0) { - return -1; + return PROM_ERROR; } if (readstr(pname, propname, sizeof(propname))) { - return -1; + return PROM_ERROR; } prop = getprop(fdt, nodeoff, propname, &proplen, &write0); if (prop) { @@ -244,7 +244,7 @@ static uint32_t vof_getprop(const void *fdt, uint32_t nodeph, uint32_t pname, (write0 && cb == proplen && VOF_MEM_WRITE(valaddr + cb - 1, &zero, 1) != MEMTX_OK)) { - ret = -1; + ret = PROM_ERROR; } else { /* * OF1275 says: @@ -259,7 +259,7 @@ static uint32_t vof_getprop(const void *fdt, uint32_t nodeph, uint32_t pname, } } } else { - ret = -1; + ret = PROM_ERROR; } trace_vof_getprop(nodeph, propname, ret, trval); @@ -275,16 +275,16 @@ static uint32_t vof_getproplen(const void *fdt, uint32_t nodeph, uint32_t pname) int nodeoff = fdt_node_offset_by_phandle(fdt, nodeph); if (nodeoff < 0) { - return -1; + return PROM_ERROR; } if (readstr(pname, propname, sizeof(propname))) { - return -1; + return PROM_ERROR; } prop = getprop(fdt, nodeoff, propname, &proplen, NULL); if (prop) { ret = proplen; } else { - ret = -1; + ret = PROM_ERROR; } trace_vof_getproplen(nodeph, propname, ret); @@ -296,8 +296,8 @@ static uint32_t vof_setprop(MachineState *ms, void *fdt, Vof *vof, uint32_t valaddr, uint32_t vallen) { char propname[OF_PROPNAME_LEN_MAX + 1]; - uint32_t ret = -1; - int offset; + uint32_t ret = PROM_ERROR; + int offset, rc; char trval[64] = ""; char nodepath[VOF_MAX_PATH] = ""; Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF); @@ -314,8 +314,8 @@ static uint32_t vof_setprop(MachineState *ms, void *fdt, Vof *vof, if (offset < 0) { goto trace_exit; } - ret = get_path(fdt, offset, nodepath, sizeof(nodepath)); - if (ret <= 0) { + rc = get_path(fdt, offset, nodepath, sizeof(nodepath)); + if (rc <= 0) { goto trace_exit; } @@ -333,8 +333,8 @@ static uint32_t vof_setprop(MachineState *ms, void *fdt, Vof *vof, goto trace_exit; } - ret = fdt_setprop(fdt, offset, propname, val, vallen); - if (ret) { + rc = fdt_setprop(fdt, offset, propname, val, vallen); + if (rc) { goto trace_exit; } @@ -358,7 +358,7 @@ static uint32_t vof_nextprop(const void *fdt, uint32_t phandle, const char *tmp; if (readstr(prevaddr, prev, sizeof(prev))) { - return -1; + return PROM_ERROR; } fdt_for_each_property_offset(offset, fdt, nodeoff) { @@ -377,7 +377,7 @@ static uint32_t vof_nextprop(const void *fdt, uint32_t phandle, } if (VOF_MEM_WRITE(nameaddr, tmp, strlen(tmp) + 1) != MEMTX_OK) { - return -1; + return PROM_ERROR; } return 1; } @@ -388,18 +388,17 @@ static uint32_t vof_nextprop(const void *fdt, uint32_t phandle, static uint32_t vof_peer(const void *fdt, uint32_t phandle) { - int ret; + uint32_t ret = 0; + int rc; if (phandle == 0) { - ret = fdt_path_offset(fdt, "/"); + rc = fdt_path_offset(fdt, "/"); } else { - ret = fdt_next_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle)); + rc = fdt_next_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle)); } - if (ret < 0) { - ret = 0; - } else { - ret = fdt_get_phandle(fdt, ret); + if (rc >= 0) { + ret = fdt_get_phandle(fdt, rc); } return ret; @@ -407,12 +406,11 @@ static uint32_t vof_peer(const void *fdt, uint32_t phandle) static uint32_t vof_child(const void *fdt, uint32_t phandle) { - int ret = fdt_first_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle)); + uint32_t ret = 0; + int rc = fdt_first_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle)); - if (ret < 0) { - ret = 0; - } else { - ret = fdt_get_phandle(fdt, ret); + if (rc >= 0) { + ret = fdt_get_phandle(fdt, rc); } return ret; @@ -420,12 +418,11 @@ static uint32_t vof_child(const void *fdt, uint32_t phandle) static uint32_t vof_parent(const void *fdt, uint32_t phandle) { - int ret = fdt_parent_offset(fdt, fdt_node_offset_by_phandle(fdt, phandle)); + uint32_t ret = 0; + int rc = fdt_parent_offset(fdt, fdt_node_offset_by_phandle(fdt, phandle)); - if (ret < 0) { - ret = 0; - } else { - ret = fdt_get_phandle(fdt, ret); + if (rc >= 0) { + ret = fdt_get_phandle(fdt, rc); } return ret; @@ -433,7 +430,7 @@ static uint32_t vof_parent(const void *fdt, uint32_t phandle) static uint32_t vof_do_open(void *fdt, Vof *vof, int offset, const char *path) { - uint32_t ret = -1; + uint32_t ret = PROM_ERROR; OfInstance *inst = NULL; if (vof->of_instance_last == 0xFFFFFFFF) { @@ -461,18 +458,18 @@ trace_exit: uint32_t vof_client_open_store(void *fdt, Vof *vof, const char *nodename, const char *prop, const char *path) { - int node = fdt_path_offset(fdt, nodename); - int inst, offset; + int offset, node = fdt_path_offset(fdt, nodename); + uint32_t inst; offset = fdt_path_offset(fdt, path); if (offset < 0) { trace_vof_error_unknown_path(path); - return offset; + return PROM_ERROR; } inst = vof_do_open(fdt, vof, offset, path); - return fdt_setprop_cell(fdt, node, prop, inst); + return fdt_setprop_cell(fdt, node, prop, inst) >= 0 ? 0 : PROM_ERROR; } static uint32_t vof_open(void *fdt, Vof *vof, uint32_t pathaddr) @@ -481,13 +478,13 @@ static uint32_t vof_open(void *fdt, Vof *vof, uint32_t pathaddr) int offset; if (readstr(pathaddr, path, sizeof(path))) { - return -1; + return PROM_ERROR; } offset = path_offset(fdt, path); if (offset < 0) { trace_vof_error_unknown_path(path); - return offset; + return PROM_ERROR; } return vof_do_open(fdt, vof, offset, path); @@ -504,7 +501,7 @@ static uint32_t vof_instance_to_package(Vof *vof, uint32_t ihandle) { gpointer instp = g_hash_table_lookup(vof->of_instances, GINT_TO_POINTER(ihandle)); - uint32_t ret = -1; + uint32_t ret = PROM_ERROR; if (instp) { ret = ((OfInstance *)instp)->phandle; @@ -517,39 +514,39 @@ static uint32_t vof_instance_to_package(Vof *vof, uint32_t ihandle) static uint32_t vof_package_to_path(const void *fdt, uint32_t phandle, uint32_t buf, uint32_t len) { - uint32_t ret = -1; + int rc; char tmp[VOF_MAX_PATH] = ""; - ret = phandle_to_path(fdt, phandle, tmp, sizeof(tmp)); - if (ret > 0) { - if (VOF_MEM_WRITE(buf, tmp, ret) != MEMTX_OK) { - ret = -1; + rc = phandle_to_path(fdt, phandle, tmp, sizeof(tmp)); + if (rc > 0) { + if (VOF_MEM_WRITE(buf, tmp, rc) != MEMTX_OK) { + rc = -1; } } - trace_vof_package_to_path(phandle, tmp, ret); + trace_vof_package_to_path(phandle, tmp, rc); - return ret; + return rc > 0 ? (uint32_t)rc : PROM_ERROR; } static uint32_t vof_instance_to_path(void *fdt, Vof *vof, uint32_t ihandle, uint32_t buf, uint32_t len) { - uint32_t ret = -1; + int rc = -1; uint32_t phandle = vof_instance_to_package(vof, ihandle); char tmp[VOF_MAX_PATH] = ""; if (phandle != -1) { - ret = phandle_to_path(fdt, phandle, tmp, sizeof(tmp)); - if (ret > 0) { - if (VOF_MEM_WRITE(buf, tmp, ret) != MEMTX_OK) { - ret = -1; + rc = phandle_to_path(fdt, phandle, tmp, sizeof(tmp)); + if (rc > 0) { + if (VOF_MEM_WRITE(buf, tmp, rc) != MEMTX_OK) { + rc = -1; } } } - trace_vof_instance_to_path(ihandle, phandle, tmp, ret); + trace_vof_instance_to_path(ihandle, phandle, tmp, rc); - return ret; + return rc > 0 ? (uint32_t)rc : PROM_ERROR; } static uint32_t vof_write(Vof *vof, uint32_t ihandle, uint32_t buf, @@ -562,13 +559,13 @@ static uint32_t vof_write(Vof *vof, uint32_t ihandle, uint32_t buf, if (!inst) { trace_vof_error_write(ihandle); - return -1; + return PROM_ERROR; } for ( ; len > 0; len -= cb) { cb = MIN(len, sizeof(tmp) - 1); if (VOF_MEM_READ(buf, tmp, cb) != MEMTX_OK) { - return -1; + return PROM_ERROR; } /* FIXME: there is no backend(s) yet so just call a trace */ @@ -747,7 +744,7 @@ uint64_t vof_claim(Vof *vof, uint64_t virt, uint64_t size, static uint32_t vof_release(Vof *vof, uint64_t virt, uint64_t size) { - uint32_t ret = -1; + uint32_t ret = PROM_ERROR; int i; GArray *claimed = vof->claimed; OfClaimed c; @@ -776,7 +773,7 @@ static uint32_t vof_call_method(MachineState *ms, Vof *vof, uint32_t methodaddr, uint32_t param2, uint32_t param3, uint32_t param4, uint32_t *ret2) { - uint32_t ret = -1; + uint32_t ret = PROM_ERROR; char method[VOF_MAX_METHODLEN] = ""; OfInstance *inst; @@ -802,7 +799,8 @@ static uint32_t vof_call_method(MachineState *ms, Vof *vof, uint32_t methodaddr, VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo); g_assert(vmc->client_architecture_support); - ret = vmc->client_architecture_support(ms, first_cpu, param1); + ret = (uint32_t)vmc->client_architecture_support(ms, first_cpu, + param1); } *ret2 = 0; @@ -826,7 +824,7 @@ trace_exit: static uint32_t vof_call_interpret(uint32_t cmdaddr, uint32_t param1, uint32_t param2, uint32_t *ret2) { - uint32_t ret = -1; + uint32_t ret = PROM_ERROR; char cmd[VOF_MAX_FORTHCODE] = ""; /* No interpret implemented so just call a trace */ @@ -895,13 +893,20 @@ static uint32_t vof_client_handle(MachineState *ms, void *fdt, Vof *vof, } else if (cmpserv("write", 3, 1)) { ret = vof_write(vof, args[0], args[1], args[2]); } else if (cmpserv("claim", 3, 1)) { - ret = vof_claim(vof, args[0], args[1], args[2]); - if (ret != -1) { + uint64_t ret64 = vof_claim(vof, args[0], args[1], args[2]); + + if (ret64 < 0x100000000UL) { vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base); + ret = (uint32_t)ret64; + } else { + if (ret64 != -1) { + vof_release(vof, ret, args[1]); + } + ret = PROM_ERROR; } } else if (cmpserv("release", 2, 0)) { ret = vof_release(vof, args[0], args[1]); - if (ret != -1) { + if (ret != PROM_ERROR) { vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base); } } else if (cmpserv("call-method", 0, 0)) { @@ -965,11 +970,15 @@ int vof_client_call(MachineState *ms, Vof *vof, void *fdt, } nret = be32_to_cpu(args_be.nret); + if (nret > ARRAY_SIZE(args_be.args) - nargs) { + return -EINVAL; + } ret = vof_client_handle(ms, fdt, vof, service, args, nargs, rets, nret); if (!nret) { return 0; } + /* @nrets includes the value which this function returns */ args_be.args[nargs] = cpu_to_be32(ret); for (i = 1; i < nret; ++i) { args_be.args[nargs + i] = cpu_to_be32(rets[i - 1]); diff --git a/include/hw/ppc/vof.h b/include/hw/ppc/vof.h index 640be46163..97fdef758b 100644 --- a/include/hw/ppc/vof.h +++ b/include/hw/ppc/vof.h @@ -55,4 +55,6 @@ struct VofMachineIfClass { address_space_write(&address_space_memory, \ (pa), MEMTXATTRS_UNSPECIFIED, (buf), (size)) +#define PROM_ERROR (~0U) + #endif /* HW_VOF_H */ From 380e49297c302fdcf8e5d56abdbe07868d3af8d8 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Thu, 22 Jul 2021 11:13:40 -0300 Subject: [PATCH 400/531] kvm: ppc: Print meaningful message on KVM_CREATE_VM failure PowerPC has two KVM types (HV, PR) that translate into three kernel modules: kvm.ko - common kvm code kvm_hv.ko - kvm running with MSR_HV=1 or MSR_HV|PR=0 in a nested guest. kvm_pr.ko - kvm running in usermode MSR_PR=1. Since the two KVM types can both be running at the same time, this creates a situation in which it is possible for one or both of the modules to fail to initialize, leaving the generic one behind. This leads QEMU to think it can create a guest, but KVM will fail when calling the type-specific code: ioctl(KVM_CREATE_VM) failed: 22 Invalid argument qemu-kvm: failed to initialize KVM: Invalid argument Ideally this would be solved kernel-side, but it might be a while until we can get rid of one of the modules. So in the meantime this patch tries to make this less confusing for the end user by adding a more elucidative message: ioctl(KVM_CREATE_VM) failed: 22 Invalid argument PPC KVM module is not loaded. Try 'modprobe kvm_hv'. [dwg: Fixed error in #elif which failed compile on !ppc hosts] Signed-off-by: Fabiano Rosas Message-Id: <20210722141340.2367905-1-farosas@linux.ibm.com> Signed-off-by: David Gibson --- accel/kvm/kvm-all.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index e5b10dd129..0125c17edb 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -2397,6 +2397,12 @@ static int kvm_init(MachineState *ms) "- for kernels supporting the vm.allocate_pgste sysctl, " "whether it is enabled\n"); } +#elif defined(TARGET_PPC) + if (ret == -EINVAL) { + fprintf(stderr, + "PPC KVM module is not loaded. Try modprobe kvm_%s.\n", + (type == 2) ? "pr" : "hv"); + } #endif goto err; } From 9ada9fd2593716cc1c61f2d56bb84bef12056cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 27 Jul 2021 16:24:28 +0200 Subject: [PATCH 401/531] docs: Document GitLab custom CI/CD variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We introduced the QEMU_CI_AVOCADO_TESTING variable in commit f56bf4caf ("gitlab: Run Avocado tests manually (except mainstream CI)"), but forgot to document it properly. Do it now. Suggested-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Willian Rampazzo Reviewed-by: Thomas Huth Message-Id: <20210727142431.1672530-2-philmd@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.yml | 19 ++----------------- docs/devel/ci.rst | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6dc5385e69..9762dda2ee 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,24 +16,9 @@ # QEMU CI jobs are based on templates. Some templates provide # user-configurable options, modifiable via configuration variables. # -# These variables can be set globally in the user's CI namespace -# setting: -# https://docs.gitlab.com/ee/ci/variables/#create-a-custom-variable-in-the-ui -# or set manually each time a branch/tag is pushed, as a git-push -# command line argument: -# https://docs.gitlab.com/ee/user/project/push_options.html#push-options-for-gitlab-cicd +# See https://qemu-project.gitlab.io/qemu/devel/ci.html#custom-ci-cd-variables +# for more information. # -# Example setting the QEMU_CI_EXAMPLE_VAR variable: -# -# git push -o ci.variable="QEMU_CI_EXAMPLE_VAR=value" myrepo mybranch -# -# ---------------------------------------------------------------------- -# -# List of environment variables that can be use to modify the set -# of jobs selected: -# -# - QEMU_CI_AVOCADO_TESTING -# If set, tests using the Avocado framework will be run include: - local: '/.gitlab-ci.d/qemu-project.yml' diff --git a/docs/devel/ci.rst b/docs/devel/ci.rst index b3bf3ef615..205572510c 100644 --- a/docs/devel/ci.rst +++ b/docs/devel/ci.rst @@ -8,6 +8,46 @@ found at:: https://wiki.qemu.org/Testing/CI +Custom CI/CD variables +====================== + +QEMU CI pipelines can be tuned by setting some CI environment variables. + +Set variable globally in the user's CI namespace +------------------------------------------------ + +Variables can be set globally in the user's CI namespace setting. + +For further information about how to set these variables, please refer to:: + + https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-a-project + +Set variable manually when pushing a branch or tag to the user's repository +--------------------------------------------------------------------------- + +Variables can be set manually when pushing a branch or tag, using +git-push command line arguments. + +Example setting the QEMU_CI_EXAMPLE_VAR variable: + +.. code:: + + git push -o ci.variable="QEMU_CI_EXAMPLE_VAR=value" myrepo mybranch + +For further information about how to set these variables, please refer to:: + + https://docs.gitlab.com/ee/user/project/push_options.html#push-options-for-gitlab-cicd + +Here is a list of the most used variables: + +QEMU_CI_AVOCADO_TESTING +~~~~~~~~~~~~~~~~~~~~~~~ +By default, tests using the Avocado framework are not run automatically in +the pipelines (because multiple artifacts have to be downloaded, and if +these artifacts are not already cached, downloading them make the jobs +reach the timeout limit). Set this variable to have the tests using the +Avocado framework run automatically. + Jobs on Custom Runners ====================== From d3a4e41da25e55b327cc8092f97a6cf02d0b5227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 27 Jul 2021 16:24:29 +0200 Subject: [PATCH 402/531] gitlab-ci: Fix 'when:' condition in acceptance_test_job_template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Jobs depending on another should not use the 'when: always' condition, because if a dependency failed we should not keep running jobs depending on it. The correct condition is 'when: on_success'. Fixes: f56bf4caf71 ("gitlab: Run Avocado tests manually (except mainstream CI)") Reported-by: Daniel P. Berrangé Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Willian Rampazzo Reviewed-by: Thomas Huth Message-Id: <20210727142431.1672530-3-philmd@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/buildtest-template.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.d/buildtest-template.yml b/.gitlab-ci.d/buildtest-template.yml index 3e3e19d96b..fcbcc4e627 100644 --- a/.gitlab-ci.d/buildtest-template.yml +++ b/.gitlab-ci.d/buildtest-template.yml @@ -73,9 +73,9 @@ # in its namespace setting or via git-push option, see documentation # in /.gitlab-ci.yml of this repository). - if: '$CI_PROJECT_NAMESPACE == "qemu-project"' - when: always + when: on_success - if: '$QEMU_CI_AVOCADO_TESTING' - when: always + when: on_success # Otherwise, set to manual (the jobs are created but not run). - when: manual allow_failure: true From 59e8b62b22062e8849429bf1e9cfde6f0affb83c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 27 Jul 2021 16:24:30 +0200 Subject: [PATCH 403/531] gitlab-ci: Fix 'when:' condition in EDK2 jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Jobs depending on another should not use the 'when: always' condition, because if a dependency failed we should not keep running jobs depending on it. The correct condition is 'when: on_success'. Fixes: 71920809cea ("gitlab-ci.yml: Add jobs to build EDK2 firmware binaries") Reported-by: Daniel P. Berrangé Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Willian Rampazzo Reviewed-by: Thomas Huth Message-Id: <20210727142431.1672530-4-philmd@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/edk2.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.d/edk2.yml b/.gitlab-ci.d/edk2.yml index aae2f7ad88..62497ba47f 100644 --- a/.gitlab-ci.d/edk2.yml +++ b/.gitlab-ci.d/edk2.yml @@ -8,11 +8,11 @@ - .gitlab-ci.d/edk2/Dockerfile # or roms/edk2/ is modified (submodule updated) - roms/edk2/* - when: always + when: on_success - if: '$CI_COMMIT_REF_NAME =~ /^edk2/' # or the branch/tag starts with 'edk2' - when: always + when: on_success - if: '$CI_COMMIT_MESSAGE =~ /edk2/i' # or last commit description contains 'EDK2' - when: always + when: on_success docker-edk2: extends: .edk2_job_rules From c217fd8e36a1d619956f550e8a39528a855de2f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 27 Jul 2021 16:24:31 +0200 Subject: [PATCH 404/531] gitlab-ci: Fix 'when:' condition in OpenSBI jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Jobs depending on another should not use the 'when: always' condition, because if a dependency failed we should not keep running jobs depending on it. The correct condition is 'when: on_success'. Fixes: c6fc0fc1a71 ("gitlab-ci.yml: Add jobs to build OpenSBI firmware binaries") Reported-by: Daniel P. Berrangé Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Willian Rampazzo Message-Id: <20210727142431.1672530-5-philmd@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/opensbi.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.d/opensbi.yml b/.gitlab-ci.d/opensbi.yml index d8a0456679..5e0a2477c5 100644 --- a/.gitlab-ci.d/opensbi.yml +++ b/.gitlab-ci.d/opensbi.yml @@ -6,14 +6,14 @@ - .gitlab-ci.d/opensbi.yml # or the Dockerfile is modified - .gitlab-ci.d/opensbi/Dockerfile - when: always + when: on_success - changes: # or roms/opensbi/ is modified (submodule updated) - roms/opensbi/* - when: always + when: on_success - if: '$CI_COMMIT_REF_NAME =~ /^opensbi/' # or the branch/tag starts with 'opensbi' - when: always + when: on_success - if: '$CI_COMMIT_MESSAGE =~ /opensbi/i' # or last commit description contains 'OpenSBI' - when: always + when: on_success docker-opensbi: extends: .opensbi_job_rules From db1e119238f94d68727279d7606c5fc096de1de1 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 27 Jul 2021 18:25:42 +0200 Subject: [PATCH 405/531] gitlab-ci.d/buildtest: Disable iotests 197 and 215 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The iotests 197 and 215 are occasionally failing in the gitlab-CI now. According to the log, the failure is "./common.rc: Killed" which might be an indication that the process has been killed due to out-of-memory reasons. Both tests are doing a big read with 2G that likely causes this issue. It used to work fine in the gitlab-CI in the past, but either the program is now requiring more free memory, or the the CI containers have changed, so that the OOM condition now sometimes occurs. Anyway, these two tests are not really suitable for CI containers if they are doing things like huge reads (which is likely also the reason why they haven't been added to the "auto" group in the past), so let's simply disable them in the gitlab-CI now, too. Message-Id: <20210727162542.318882-1-thuth@redhat.com> Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Willian Rampazzo Signed-off-by: Thomas Huth --- .gitlab-ci.d/buildtest.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index ee0c83b600..63f1903f07 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -305,10 +305,10 @@ build-tcg-disabled: - cd tests/qemu-iotests/ - ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048 052 063 077 086 101 104 106 113 148 150 151 152 157 159 160 163 - 170 171 183 184 192 194 197 208 215 221 222 226 227 236 253 277 + 170 171 183 184 192 194 208 221 222 226 227 236 253 277 - ./check -qcow2 028 051 056 057 058 065 068 082 085 091 095 096 102 122 - 124 132 139 142 144 145 151 152 155 157 165 194 196 197 200 202 - 208 209 215 216 218 222 227 234 246 247 248 250 254 255 257 258 + 124 132 139 142 144 145 151 152 155 157 165 194 196 200 202 + 208 209 216 218 222 227 234 246 247 248 250 254 255 257 258 260 261 262 263 264 270 272 273 277 279 build-user: From e37264ebe34fe80f7ef3ac649408fd7845c82c65 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 28 Jul 2021 09:09:14 +0200 Subject: [PATCH 406/531] gitlab-ci.d/buildtest: Mark the aarch64 and ppc64-s390x CFI jobs as manual MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These two jobs are currently failing very often - the linker seems to get killed due to out-of-memory problems. Since apparently nobody has currently an idea how to fix that nicely, let's mark the jobs as manual for the time being until someone comes up with a proper fix. Message-Id: <20210728075141.400816-1-thuth@redhat.com> Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Willian Rampazzo Signed-off-by: Thomas Huth --- .gitlab-ci.d/buildtest.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 63f1903f07..903ee65f32 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -416,6 +416,12 @@ build-cfi-aarch64: expire_in: 2 days paths: - build + rules: + # FIXME: This job is often failing, likely due to out-of-memory problems in + # the constrained containers of the shared runners. Thus this is marked as + # manual until the situation has been solved. + - when: manual + allow_failure: true check-cfi-aarch64: extends: .native_test_job_template @@ -452,6 +458,12 @@ build-cfi-ppc64-s390x: expire_in: 2 days paths: - build + rules: + # FIXME: This job is often failing, likely due to out-of-memory problems in + # the constrained containers of the shared runners. Thus this is marked as + # manual until the situation has been solved. + - when: manual + allow_failure: true check-cfi-ppc64-s390x: extends: .native_test_job_template From c5dd0f03423c8b614147778547a3a58525d9eb94 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 28 Jul 2021 19:38:57 +0200 Subject: [PATCH 407/531] gitlab-ci.d/custom-runners: Improve rules for the staging branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If maintainers are currently pushing to a branch called "staging" in their repository, they are ending up with some stuck jobs - unless they have a s390x CI runner machine available. That's ugly, we should make sure that the related jobs are really only started if such a runner is available. So let's only run these jobs if it's the "staging" branch of the main repository of the QEMU project (where we can be sure that the s390x runner is available), or if the user explicitly set a S390X_RUNNER_AVAILABLE variable in their CI configs to declare that they have such a runner available, too. Fixes: 4799c21023 ("Jobs based on custom runners: add job definitions ...") Message-Id: <20210728173857.497523-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Willian Rampazzo Signed-off-by: Thomas Huth --- .gitlab-ci.d/custom-runners.yml | 40 +++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/.gitlab-ci.d/custom-runners.yml b/.gitlab-ci.d/custom-runners.yml index 061d3cdfed..564b94565d 100644 --- a/.gitlab-ci.d/custom-runners.yml +++ b/.gitlab-ci.d/custom-runners.yml @@ -24,7 +24,8 @@ ubuntu-18.04-s390x-all-linux-static: - ubuntu_18.04 - s390x rules: - - if: '$CI_COMMIT_BRANCH =~ /^staging/' + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + - if: "$S390X_RUNNER_AVAILABLE" script: # --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763 # --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages @@ -43,7 +44,8 @@ ubuntu-18.04-s390x-all: - ubuntu_18.04 - s390x rules: - - if: '$CI_COMMIT_BRANCH =~ /^staging/' + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + - if: "$S390X_RUNNER_AVAILABLE" script: - mkdir build - cd build @@ -59,7 +61,8 @@ ubuntu-18.04-s390x-alldbg: - ubuntu_18.04 - s390x rules: - - if: '$CI_COMMIT_BRANCH =~ /^staging/' + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + - if: "$S390X_RUNNER_AVAILABLE" script: - mkdir build - cd build @@ -76,7 +79,9 @@ ubuntu-18.04-s390x-clang: - ubuntu_18.04 - s390x rules: - - if: '$CI_COMMIT_BRANCH =~ /^staging/' + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + when: manual + - if: "$S390X_RUNNER_AVAILABLE" when: manual script: - mkdir build @@ -93,7 +98,8 @@ ubuntu-18.04-s390x-tci: - ubuntu_18.04 - s390x rules: - - if: '$CI_COMMIT_BRANCH =~ /^staging/' + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + - if: "$S390X_RUNNER_AVAILABLE" script: - mkdir build - cd build @@ -108,7 +114,9 @@ ubuntu-18.04-s390x-notcg: - ubuntu_18.04 - s390x rules: - - if: '$CI_COMMIT_BRANCH =~ /^staging/' + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + when: manual + - if: "$S390X_RUNNER_AVAILABLE" when: manual script: - mkdir build @@ -128,7 +136,8 @@ ubuntu-20.04-aarch64-all-linux-static: - ubuntu_20.04 - aarch64 rules: - - if: '$CI_COMMIT_BRANCH =~ /^staging/' + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + - if: "$S390X_RUNNER_AVAILABLE" script: # --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763 # --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages @@ -147,7 +156,8 @@ ubuntu-20.04-aarch64-all: - ubuntu_20.04 - aarch64 rules: - - if: '$CI_COMMIT_BRANCH =~ /^staging/' + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + - if: "$S390X_RUNNER_AVAILABLE" script: - mkdir build - cd build @@ -163,7 +173,8 @@ ubuntu-20.04-aarch64-alldbg: - ubuntu_20.04 - aarch64 rules: - - if: '$CI_COMMIT_BRANCH =~ /^staging/' + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + - if: "$S390X_RUNNER_AVAILABLE" script: - mkdir build - cd build @@ -180,7 +191,9 @@ ubuntu-20.04-aarch64-clang: - ubuntu_20.04 - aarch64 rules: - - if: '$CI_COMMIT_BRANCH =~ /^staging/' + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + when: manual + - if: "$S390X_RUNNER_AVAILABLE" when: manual script: - mkdir build @@ -197,7 +210,8 @@ ubuntu-20.04-aarch64-tci: - ubuntu_20.04 - aarch64 rules: - - if: '$CI_COMMIT_BRANCH =~ /^staging/' + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + - if: "$S390X_RUNNER_AVAILABLE" script: - mkdir build - cd build @@ -212,7 +226,9 @@ ubuntu-20.04-aarch64-notcg: - ubuntu_20.04 - aarch64 rules: - - if: '$CI_COMMIT_BRANCH =~ /^staging/' + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + when: manual + - if: "$S390X_RUNNER_AVAILABLE" when: manual script: - mkdir build From 61c32485b7920ecb25875561528778fbd3a7ad16 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 28 Jul 2021 17:41:28 -0400 Subject: [PATCH 408/531] tests: Fix migration-test build failure for sparc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even if seems to exist for all archs on linux, however including it with __linux__ defined seems to be not working yet as it'll try to include asm/kvm.h and that can be missing for archs that do not support kvm. To fix this (instead of any attempt to fix linux headers..), we can mark the header to be x86_64 only, because it's so far only service for adding the kvm dirty ring test. Fixes: 1f546b709d6 ("tests: migration-test: Add dirty ring test") Reported-by: Richard Henderson Signed-off-by: Peter Xu Message-Id: <20210728214128.206198-1-peterx@redhat.com> Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- tests/qtest/migration-test.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 1e8b7784ef..cc5e83d98a 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -27,7 +27,8 @@ #include "migration-helpers.h" #include "tests/migration/migration-test.h" -#if defined(__linux__) +/* For dirty ring test; so far only x86_64 is supported */ +#if defined(__linux__) && defined(HOST_X86_64) #include "linux/kvm.h" #endif @@ -1395,7 +1396,7 @@ static void test_multifd_tcp_cancel(void) static bool kvm_dirty_ring_supported(void) { -#if defined(__linux__) +#if defined(__linux__) && defined(HOST_X86_64) int ret, kvm_fd = open("/dev/kvm", O_RDONLY); if (kvm_fd < 0) { From b8ee198d21c4bab41b8cb8d1729a956d9f648997 Mon Sep 17 00:00:00 2001 From: Richard Zak Date: Tue, 20 Jul 2021 21:40:04 -0400 Subject: [PATCH 409/531] configure script fix for Haiku Haiku does not support compiling with -fpie. See the discussion here for details: https://discuss.haiku-os.org/t/qemu-on-haiku-sdl-issue/10961/6?u=rjzak Signed-off-by: Richard Zak Message-Id: [thuth: Tweaked title and patch description] Signed-off-by: Thomas Huth --- configure | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 79e2ddc74e..cd5e6892f4 100755 --- a/configure +++ b/configure @@ -770,7 +770,8 @@ SunOS) ;; Haiku) haiku="yes" - QEMU_CFLAGS="-DB_USE_POSITIVE_POSIX_ERRORS -D_BSD_SOURCE $QEMU_CFLAGS" + pie="no" + QEMU_CFLAGS="-DB_USE_POSITIVE_POSIX_ERRORS -D_BSD_SOURCE -fPIC $QEMU_CFLAGS" ;; Linux) audio_drv_list="try-pa oss" From e4adb09f7952fd37b7f1ba3df377d54d0823e682 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Fri, 16 Jul 2021 13:58:51 +0200 Subject: [PATCH 410/531] i386: assert 'cs->kvm_state' is not null Coverity reports potential NULL pointer dereference in get_supported_hv_cpuid_legacy() when 'cs->kvm_state' is NULL. While 'cs->kvm_state' can indeed be NULL in hv_cpuid_get_host(), kvm_hyperv_expand_features() makes sure that it only happens when KVM_CAP_SYS_HYPERV_CPUID is supported and KVM_CAP_SYS_HYPERV_CPUID implies KVM_CAP_HYPERV_CPUID so get_supported_hv_cpuid_legacy() is never really called. Add asserts to strengthen the protection against broken KVM behavior. Coverity: CID 1458243 Signed-off-by: Vitaly Kuznetsov Message-Id: <20210716115852.418293-1-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 59ed8327ac..e69abe48e3 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -974,6 +974,12 @@ static struct kvm_cpuid2 *get_supported_hv_cpuid(CPUState *cs) do_sys_ioctl = kvm_check_extension(kvm_state, KVM_CAP_SYS_HYPERV_CPUID) > 0; + /* + * Non-empty KVM context is needed when KVM_CAP_SYS_HYPERV_CPUID is + * unsupported, kvm_hyperv_expand_features() checks for that. + */ + assert(do_sys_ioctl || cs->kvm_state); + /* * When the buffer is too small, KVM_GET_SUPPORTED_HV_CPUID fails with * -E2BIG, however, it doesn't report back the right size. Keep increasing @@ -1105,6 +1111,14 @@ static uint32_t hv_cpuid_get_host(CPUState *cs, uint32_t func, int reg) if (kvm_check_extension(kvm_state, KVM_CAP_HYPERV_CPUID) > 0) { cpuid = get_supported_hv_cpuid(cs); } else { + /* + * 'cs->kvm_state' may be NULL when Hyper-V features are expanded + * before KVM context is created but this is only done when + * KVM_CAP_SYS_HYPERV_CPUID is supported and it implies + * KVM_CAP_HYPERV_CPUID. + */ + assert(cs->kvm_state); + cpuid = get_supported_hv_cpuid_legacy(cs); } hv_cpuid_cache = cpuid; From 14833e24dea49303ebc2464813601054b6cdfcac Mon Sep 17 00:00:00 2001 From: Alexey Neyman Date: Wed, 21 Jul 2021 19:08:46 -0700 Subject: [PATCH 411/531] Makefile: ignore long options When searching for options like -n in MAKEFLAGS, current code may result in a false positive match when make is invoked with long options like --no-print-directory. This has been observed with certain versions of host make (e.g. 3.82) while building the Qemu package in buildroot. Filter out such long options before searching for one-character options. Signed-off-by: Alexey Neyman Message-Id: <20210722020846.3678817-1-stilor@att.net> Signed-off-by: Paolo Bonzini --- Makefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 6c36330eef..401c623a65 100644 --- a/Makefile +++ b/Makefile @@ -129,9 +129,11 @@ endif # 4. Rules to bridge to other makefiles ifneq ($(NINJA),) -MAKE.n = $(findstring n,$(firstword $(MAKEFLAGS))) -MAKE.k = $(findstring k,$(firstword $(MAKEFLAGS))) -MAKE.q = $(findstring q,$(firstword $(MAKEFLAGS))) +# Filter out long options to avoid flags like --no-print-directory which +# may result in false positive match for MAKE.n +MAKE.n = $(findstring n,$(firstword $(filter-out --%,$(MAKEFLAGS)))) +MAKE.k = $(findstring k,$(firstword $(filter-out --%,$(MAKEFLAGS)))) +MAKE.q = $(findstring q,$(firstword $(filter-out --%,$(MAKEFLAGS)))) MAKE.nq = $(if $(word 2, $(MAKE.n) $(MAKE.q)),nq) NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \ $(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \ From 5b945f23d651a71aa722cc6af84a480d41bc549a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Jul 2021 10:01:12 -1000 Subject: [PATCH 412/531] configure: Add -Werror to avx2, avx512 tests When using clang, we get ERROR: configure test passed without -Werror but failed with -Werror. This is probably a bug in the configure script. The failing command will be at the bottom of config.log. You can run configure with --disable-werror to bypass this check. What we really want from these two tests is whether the entire code sequence is supported, including pragmas. Adding -Werror makes the test properly fail for clang. Signed-off-by: Richard Henderson Message-Id: <20210719200112.295316-1-richard.henderson@linaro.org> Signed-off-by: Paolo Bonzini --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 79e2ddc74e..422a456f0b 100755 --- a/configure +++ b/configure @@ -3881,7 +3881,7 @@ static int bar(void *a) { } int main(int argc, char *argv[]) { return bar(argv[0]); } EOF - if compile_object "" ; then + if compile_object "-Werror" ; then avx2_opt="yes" else avx2_opt="no" @@ -3911,7 +3911,7 @@ int main(int argc, char *argv[]) return bar(argv[0]); } EOF - if ! compile_object "" ; then + if ! compile_object "-Werror" ; then avx512f_opt="no" fi else From eceb4f01123355a7045ec4ba9cd547511682a4d9 Mon Sep 17 00:00:00 2001 From: Lara Lazier Date: Sun, 25 Jul 2021 11:08:55 +0200 Subject: [PATCH 413/531] target/i386: Added consistency checks for event injection VMRUN exits with SVM_EXIT_ERR if either: * The event injected has a reserved type. * When the event injected is of type 3 (exception), and the vector that has been specified does not correspond to an exception. This does not fix the entire exc_inj test in kvm-unit-tests. Signed-off-by: Lara Lazier Message-Id: <20210725090855.19713-1-laramglazier@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/tcg/sysemu/svm_helper.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 145511d635..90a9de30f8 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -383,6 +383,9 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) cpu_loop_exit(cs); break; case SVM_EVTINJ_TYPE_EXEPT: + if (vector == EXCP02_NMI || vector >= 31) { + cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); + } cs->exception_index = vector; env->error_code = event_inj_err; env->exception_is_int = 0; @@ -398,6 +401,9 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT"); cpu_loop_exit(cs); break; + default: + cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); + break; } qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", cs->exception_index, env->error_code); From f594bfb79f572b27404d251f9758a36b83271580 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 29 Jul 2021 09:56:38 +0200 Subject: [PATCH 414/531] target/i386: fix typo in ctl_has_irq The shift constant was incorrect, causing int_prio to always be zero. Signed-off-by: Lara Lazier [Rewritten commit message since v1 had already been included. - Paolo] Signed-off-by: Paolo Bonzini --- target/i386/tcg/sysemu/svm_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 90a9de30f8..e151104b4e 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -70,7 +70,7 @@ static inline bool ctl_has_irq(uint32_t int_ctl) uint32_t int_prio; uint32_t tpr; - int_prio = (int_ctl & V_INTR_PRIO_MASK) >> V_INTR_MASKING_SHIFT; + int_prio = (int_ctl & V_INTR_PRIO_MASK) >> V_INTR_PRIO_SHIFT; tpr = int_ctl & V_TPR_MASK; return (int_ctl & V_IRQ_MASK) && (int_prio >= tpr); } From 3f55f97b14086b0f9f638e5bb784b3485b36d583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 5 May 2021 19:13:12 +0400 Subject: [PATCH 415/531] meson: fix meson 0.58 warning with libvhost-user subproject MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Meson now checks that subprojects do not access files from parent project. While we all agree this is best practice, libvhost-user also want to share a few headers with QEMU, and libvhost-user isn't really a standalone project at this point (although this is making the dependency a bit more explicit). Signed-off-by: Marc-André Lureau Message-Id: <20210505151313.203258-1-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini --- subprojects/libvhost-user/include/atomic.h | 1 + subprojects/libvhost-user/libvhost-user.c | 2 +- subprojects/libvhost-user/meson.build | 6 +----- subprojects/libvhost-user/standard-headers/linux | 1 + 4 files changed, 4 insertions(+), 6 deletions(-) create mode 120000 subprojects/libvhost-user/include/atomic.h create mode 120000 subprojects/libvhost-user/standard-headers/linux diff --git a/subprojects/libvhost-user/include/atomic.h b/subprojects/libvhost-user/include/atomic.h new file mode 120000 index 0000000000..8c2be64f7b --- /dev/null +++ b/subprojects/libvhost-user/include/atomic.h @@ -0,0 +1 @@ +../../../include/qemu/atomic.h \ No newline at end of file diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c index fab7ca17ee..2971ba0112 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -40,7 +40,7 @@ #endif -#include "qemu/atomic.h" +#include "include/atomic.h" #include "libvhost-user.h" diff --git a/subprojects/libvhost-user/meson.build b/subprojects/libvhost-user/meson.build index b03446e7cd..39825d9404 100644 --- a/subprojects/libvhost-user/meson.build +++ b/subprojects/libvhost-user/meson.build @@ -4,21 +4,17 @@ project('libvhost-user', 'c', threads = dependency('threads') glib = dependency('glib-2.0') -inc = include_directories('../../include', '../../linux-headers') vhost_user = static_library('vhost-user', files('libvhost-user.c'), - include_directories: inc, dependencies: threads, c_args: '-D_GNU_SOURCE') executable('link-test', files('link-test.c'), - link_whole: vhost_user, - include_directories: inc) + link_whole: vhost_user) vhost_user_glib = static_library('vhost-user-glib', files('libvhost-user-glib.c'), - include_directories: inc, link_with: vhost_user, dependencies: glib) diff --git a/subprojects/libvhost-user/standard-headers/linux b/subprojects/libvhost-user/standard-headers/linux new file mode 120000 index 0000000000..15a2378139 --- /dev/null +++ b/subprojects/libvhost-user/standard-headers/linux @@ -0,0 +1 @@ +../../../include/standard-headers/linux \ No newline at end of file From 4fe29344bef6c54a6eff7aa0343754f8a9df5715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 5 May 2021 19:13:13 +0400 Subject: [PATCH 416/531] libvhost-user: fix -Werror=format= warnings with __u64 fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ../subprojects/libvhost-user/libvhost-user.c:1070:12: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 3 has type ‘__u64’ {aka ‘long long unsigned int’} [-Werror=format=] 1070 | DPRINT(" desc_user_addr: 0x%016" PRIx64 "\n", vra->desc_user_addr); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~ | | | __u64 {aka long long unsigned int} Rather than using %llx, which may fail if __u64 is declared differently elsewhere, let's just cast the values. Feel free to propose a better solution! Signed-off-by: Marc-André Lureau Message-Id: <20210505151313.203258-2-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini --- subprojects/libvhost-user/libvhost-user.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c index 2971ba0112..bf09693255 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -1067,10 +1067,10 @@ vu_set_vring_addr_exec(VuDev *dev, VhostUserMsg *vmsg) DPRINT("vhost_vring_addr:\n"); DPRINT(" index: %d\n", vra->index); DPRINT(" flags: %d\n", vra->flags); - DPRINT(" desc_user_addr: 0x%016" PRIx64 "\n", vra->desc_user_addr); - DPRINT(" used_user_addr: 0x%016" PRIx64 "\n", vra->used_user_addr); - DPRINT(" avail_user_addr: 0x%016" PRIx64 "\n", vra->avail_user_addr); - DPRINT(" log_guest_addr: 0x%016" PRIx64 "\n", vra->log_guest_addr); + DPRINT(" desc_user_addr: 0x%016" PRIx64 "\n", (uint64_t)vra->desc_user_addr); + DPRINT(" used_user_addr: 0x%016" PRIx64 "\n", (uint64_t)vra->used_user_addr); + DPRINT(" avail_user_addr: 0x%016" PRIx64 "\n", (uint64_t)vra->avail_user_addr); + DPRINT(" log_guest_addr: 0x%016" PRIx64 "\n", (uint64_t)vra->log_guest_addr); vq->vra = *vra; vq->vring.flags = vra->flags; From 663fdc815ed427219f540d3c96ba8e2399cfba96 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 23 Jun 2021 10:52:48 +0200 Subject: [PATCH 417/531] usb-host: wire up timer for windows On windows we can't wait on file descriptors. Poll libusb using a timer instead. Fixes long-standing FIXME. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/431 Signed-off-by: Gerd Hoffmann Message-Id: <20210623085249.1151901-2-kraxel@redhat.com> Signed-off-by: Gerd Hoffmann --- hw/usb/host-libusb.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index c0f314462a..00f6fbb29b 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -254,6 +254,29 @@ static void usb_host_del_fd(int fd, void *user_data) qemu_set_fd_handler(fd, NULL, NULL, NULL); } +#else + +static QEMUTimer *poll_timer; +static uint32_t request_count; + +static void usb_host_timer_kick(void) +{ + int64_t delay_ns; + + delay_ns = request_count + ? (NANOSECONDS_PER_SECOND / 100) /* 10 ms interval with active req */ + : (NANOSECONDS_PER_SECOND); /* 1 sec interval otherwise */ + timer_mod(poll_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + delay_ns); +} + +static void usb_host_timer(void *opaque) +{ + struct timeval tv = { 0, 0 }; + + libusb_handle_events_timeout(ctx, &tv); + usb_host_timer_kick(); +} + #endif /* !CONFIG_WIN32 */ static int usb_host_init(void) @@ -276,7 +299,8 @@ static int usb_host_init(void) libusb_set_debug(ctx, loglevel); #endif #ifdef CONFIG_WIN32 - /* FIXME: add support for Windows. */ + poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, usb_host_timer, NULL); + usb_host_timer_kick(); #else libusb_set_pollfd_notifiers(ctx, usb_host_add_fd, usb_host_del_fd, @@ -364,11 +388,18 @@ static USBHostRequest *usb_host_req_alloc(USBHostDevice *s, USBPacket *p, r->buffer = g_malloc(bufsize); } QTAILQ_INSERT_TAIL(&s->requests, r, next); +#ifdef CONFIG_WIN32 + request_count++; + usb_host_timer_kick(); +#endif return r; } static void usb_host_req_free(USBHostRequest *r) { +#ifdef CONFIG_WIN32 + request_count--; +#endif QTAILQ_REMOVE(&r->host->requests, r, next); libusb_free_transfer(r->xfer); g_free(r->buffer); From 8a2d766f05f0b6904e1496c699b2394e278c1926 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 23 Jun 2021 10:52:49 +0200 Subject: [PATCH 418/531] ci: add libusb for windows builds Add CI coverage for usb passthrough on windows. Signed-off-by: Gerd Hoffmann Reviewed-by: Willian Rampazzo Message-Id: <20210623085249.1151901-3-kraxel@redhat.com> Signed-off-by: Gerd Hoffmann --- tests/docker/dockerfiles/fedora-win32-cross.docker | 1 + tests/docker/dockerfiles/fedora-win64-cross.docker | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index 5a03e1af43..aad39dd97f 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -23,6 +23,7 @@ ENV PACKAGES \ mingw32-libjpeg-turbo \ mingw32-libpng \ mingw32-libtasn1 \ + mingw32-libusbx \ mingw32-nettle \ mingw32-nsis \ mingw32-pixman \ diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index d3f13666e8..9a224a619b 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -23,6 +23,7 @@ ENV PACKAGES \ mingw64-libjpeg-turbo \ mingw64-libpng \ mingw64-libtasn1 \ + mingw64-libusbx \ mingw64-pixman \ mingw64-pkg-config \ perl \ From 5e796671e6b8d5de4b0b423dce1b3eba144a92c9 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 22 Jul 2021 09:27:56 +0200 Subject: [PATCH 419/531] usbredir: fix free call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit data might point into the middle of a larger buffer, there is a separate free_on_destroy pointer passed into bufp_alloc() to handle that. It is only used in the normal workflow though, not when dropping packets due to the queue being full. Fix that. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/491 Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-Id: <20210722072756.647673-1-kraxel@redhat.com> --- hw/usb/redirect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 4ec9326e05..1ec909a63a 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -476,7 +476,7 @@ static int bufp_alloc(USBRedirDevice *dev, uint8_t *data, uint16_t len, if (dev->endpoint[EP2I(ep)].bufpq_dropping_packets) { if (dev->endpoint[EP2I(ep)].bufpq_size > dev->endpoint[EP2I(ep)].bufpq_target_size) { - free(data); + free(free_on_destroy); return -1; } dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; From 2a49e4e9277085fb0f30037529666fc2d76c730e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 28 Jul 2021 15:14:54 +0100 Subject: [PATCH 420/531] docs: Incorporate information in usb-storage.txt into rST manual We already have a section on USB in the rST manual; fold the information in docs/usb-storage.txt into it. We add 'format=raw' to the various -drive options in the code examples, because QEMU will print warnings these days if you omit it. Signed-off-by: Peter Maydell Message-Id: <20210728141457.14825-2-peter.maydell@linaro.org> Signed-off-by: Gerd Hoffmann --- MAINTAINERS | 2 +- docs/system/devices/usb.rst | 57 ++++++++++++++++++++++++++++++----- docs/usb-storage.txt | 59 ------------------------------------- 3 files changed, 51 insertions(+), 67 deletions(-) delete mode 100644 docs/usb-storage.txt diff --git a/MAINTAINERS b/MAINTAINERS index 42ac45c3e5..b1f8e82bef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1836,7 +1836,7 @@ S: Maintained F: hw/usb/* F: stubs/usb-dev-stub.c F: tests/qtest/usb-*-test.c -F: docs/usb2.txt +F: docs/system/devices/usb.rst F: docs/usb-storage.txt F: include/hw/usb.h F: include/hw/usb/ diff --git a/docs/system/devices/usb.rst b/docs/system/devices/usb.rst index eeab78dcfb..7da142ecbb 100644 --- a/docs/system/devices/usb.rst +++ b/docs/system/devices/usb.rst @@ -28,17 +28,46 @@ option or the ``device_add`` monitor command. Available devices are: ``usb-storage,drive=drive_id`` Mass storage device backed by drive_id (see the :ref:`disk images` - chapter in the System Emulation Users Guide) + chapter in the System Emulation Users Guide). This is the classic + bulk-only transport protocol used by 99% of USB sticks. This + example shows it connected to an XHCI USB controller and with + a drive backed by a raw format disk image: + + .. parsed-literal:: + + |qemu_system| [...] \\ + -drive if=none,id=stick,format=raw,file=/path/to/file.img \\ + -device nec-usb-xhci,id=xhci \\ + -device usb-storage,bus=xhci.0,drive=stick ``usb-uas`` - USB attached SCSI device, see - `usb-storage.txt `__ - for details + USB attached SCSI device. This does not create a SCSI disk, so + you need to explicitly create a ``scsi-hd`` or ``scsi-cd`` device + on the command line, as well as using the ``-drive`` option to + specify what those disks are backed by. One ``usb-uas`` device can + handle multiple logical units (disks). This example creates three + logical units: two disks and one cdrom drive: + + .. parsed-literal:: + + |qemu_system| [...] \\ + -drive if=none,id=uas-disk1,format=raw,file=/path/to/file1.img \\ + -drive if=none,id=uas-disk2,format=raw,file=/path/to/file2.img \\ + -drive if=none,id=uas-cdrom,media=cdrom,format=raw,file=/path/to/image.iso \\ + -device nec-usb-xhci,id=xhci \\ + -device usb-uas,id=uas,bus=xhci.0 \\ + -device scsi-hd,bus=uas.0,scsi-id=0,lun=0,drive=uas-disk1 \\ + -device scsi-hd,bus=uas.0,scsi-id=0,lun=1,drive=uas-disk2 \\ + -device scsi-cd,bus=uas.0,scsi-id=0,lun=5,drive=uas-cdrom ``usb-bot`` - Bulk-only transport storage device, see - `usb-storage.txt `__ - for details here, too + Bulk-only transport storage device. This presents the guest with the + same USB bulk-only transport protocol interface as ``usb-storage``, but + the QEMU command line option works like ``usb-uas`` and does not + automatically create SCSI disks for you. ``usb-bot`` supports up to + 16 LUNs. Unlike ``usb-uas``, the LUN numbers must be continuous, + i.e. for three devices you must use 0+1+2. The 0+1+5 numbering from the + ``usb-uas`` example above won't work with ``usb-bot``. ``usb-mtp,rootdir=dir`` Media transfer protocol device, using dir as root of the file tree @@ -84,6 +113,20 @@ option or the ``device_add`` monitor command. Available devices are: ``u2f-{emulated,passthru}`` Universal Second Factor device +Hotplugging USB storage +~~~~~~~~~~~~~~~~~~~~~~~ + +The ``usb-bot`` and ``usb-uas`` devices can be hotplugged. In the hotplug +case they are added with ``attached = false`` so the guest will not see +the device until the ``attached`` property is explicitly set to true. +That allows you to attach one or more scsi devices before making the +device visible to the guest. The workflow looks like this: + +#. ``device-add usb-bot,id=foo`` +#. ``device-add scsi-{hd,cd},bus=foo.0,lun=0`` +#. optionally add more devices (luns 1 ... 15) +#. ``scripts/qmp/qom-set foo.attached = true`` + .. _host_005fusb_005fdevices: Using host USB devices on a Linux host diff --git a/docs/usb-storage.txt b/docs/usb-storage.txt deleted file mode 100644 index 551af6f88b..0000000000 --- a/docs/usb-storage.txt +++ /dev/null @@ -1,59 +0,0 @@ - -qemu usb storage emulation --------------------------- - -QEMU has three devices for usb storage emulation. - -Number one emulates the classic bulk-only transport protocol which is -used by 99% of the usb sticks on the market today and is called -"usb-storage". Usage (hooking up to xhci, other host controllers work -too): - - qemu ${other_vm_args} \ - -drive if=none,id=stick,file=/path/to/file.img \ - -device nec-usb-xhci,id=xhci \ - -device usb-storage,bus=xhci.0,drive=stick - - -Number two is the newer usb attached scsi transport. This one doesn't -automagically create a scsi disk, so you have to explicitly attach one -manually. Multiple logical units are supported. Here is an example -with tree logical units: - - qemu ${other_vm_args} \ - -drive if=none,id=uas-disk1,file=/path/to/file1.img \ - -drive if=none,id=uas-disk2,file=/path/to/file2.img \ - -drive if=none,id=uas-cdrom,media=cdrom,file=/path/to/image.iso \ - -device nec-usb-xhci,id=xhci \ - -device usb-uas,id=uas,bus=xhci.0 \ - -device scsi-hd,bus=uas.0,scsi-id=0,lun=0,drive=uas-disk1 \ - -device scsi-hd,bus=uas.0,scsi-id=0,lun=1,drive=uas-disk2 \ - -device scsi-cd,bus=uas.0,scsi-id=0,lun=5,drive=uas-cdrom - - -Number three emulates the classic bulk-only transport protocol too. -It's called "usb-bot". It shares most code with "usb-storage", and -the guest will not be able to see the difference. The qemu command -line interface is similar to usb-uas though, i.e. no automatic scsi -disk creation. It also features support for up to 16 LUNs. The LUN -numbers must be continuous, i.e. for three devices you must use 0+1+2. -The 0+1+5 numbering from the "usb-uas" example isn't going to work -with "usb-bot". - -Starting with qemu version 2.7 usb-bot and usb-uas devices can be -hotplugged. In the hotplug case they are added with "attached = -false" so the guest will not see the device until the "attached" -property is explicitly set to true. That allows to attach one or more -scsi devices before making the device visible to the guest, i.e. the -workflow looks like this: - - (1) device-add usb-bot,id=foo - (2) device-add scsi-{hd,cd},bus=foo.0,lun=0 - (2b) optionally add more devices (luns 1 ... 15). - (3) scripts/qmp/qom-set foo.attached = true - -enjoy, - Gerd - --- -Gerd Hoffmann From 78da86dce1780c7023624aa1dec8dd083e75db9c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 28 Jul 2021 15:14:55 +0100 Subject: [PATCH 421/531] docs: Fold usb2.txt USB controller information into usb.rst Fold the information in docs/usb2.txt about the different kinds of supported USB controller into the main rST manual. Signed-off-by: Peter Maydell Message-Id: <20210728141457.14825-3-peter.maydell@linaro.org> Signed-off-by: Gerd Hoffmann --- docs/system/devices/usb.rst | 86 +++++++++++++++++++++++++++++++++++++ docs/usb2.txt | 82 ----------------------------------- 2 files changed, 86 insertions(+), 82 deletions(-) diff --git a/docs/system/devices/usb.rst b/docs/system/devices/usb.rst index 7da142ecbb..9f0e613dcc 100644 --- a/docs/system/devices/usb.rst +++ b/docs/system/devices/usb.rst @@ -8,6 +8,92 @@ plug virtual USB devices or real host USB devices (only works with certain host operating systems). QEMU will automatically create and connect virtual USB hubs as necessary to connect multiple USB devices. +USB controllers +~~~~~~~~~~~~~~~ + +XHCI controller support +^^^^^^^^^^^^^^^^^^^^^^^ + +QEMU has XHCI host adapter support. The XHCI hardware design is much +more virtualization-friendly when compared to EHCI and UHCI, thus XHCI +emulation uses less resources (especially CPU). So if your guest +supports XHCI (which should be the case for any operating system +released around 2010 or later) we recommend using it: + + qemu -device qemu-xhci + +XHCI supports USB 1.1, USB 2.0 and USB 3.0 devices, so this is the +only controller you need. With only a single USB controller (and +therefore only a single USB bus) present in the system there is no +need to use the bus= parameter when adding USB devices. + + +EHCI controller support +^^^^^^^^^^^^^^^^^^^^^^^ + +The QEMU EHCI Adapter supports USB 2.0 devices. It can be used either +standalone or with companion controllers (UHCI, OHCI) for USB 1.1 +devices. The companion controller setup is more convenient to use +because it provides a single USB bus supporting both USB 2.0 and USB +1.1 devices. See next section for details. + +When running EHCI in standalone mode you can add UHCI or OHCI +controllers for USB 1.1 devices too. Each controller creates its own +bus though, so there are two completely separate USB buses: One USB +1.1 bus driven by the UHCI controller and one USB 2.0 bus driven by +the EHCI controller. Devices must be attached to the correct +controller manually. + +The easiest way to add a UHCI controller to a ``pc`` machine is the +``-usb`` switch. QEMU will create the UHCI controller as function of +the PIIX3 chipset. The USB 1.1 bus will carry the name ``usb-bus.0``. + +You can use the standard ``-device`` switch to add a EHCI controller to +your virtual machine. It is strongly recommended to specify an ID for +the controller so the USB 2.0 bus gets an individual name, for example +``-device usb-ehci,id=ehci``. This will give you a USB 2.0 bus named +``ehci.0``. + +When adding USB devices using the ``-device`` switch you can specify the +bus they should be attached to. Here is a complete example: + +.. parsed-literal:: + + |qemu_system| -M pc ${otheroptions} \\ + -drive if=none,id=usbstick,format=raw,file=/path/to/image \\ + -usb \\ + -device usb-ehci,id=ehci \\ + -device usb-tablet,bus=usb-bus.0 \\ + -device usb-storage,bus=ehci.0,drive=usbstick + +This attaches a USB tablet to the UHCI adapter and a USB mass storage +device to the EHCI adapter. + + +Companion controller support +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The UHCI and OHCI controllers can attach to a USB bus created by EHCI +as companion controllers. This is done by specifying the ``masterbus`` +and ``firstport`` properties. ``masterbus`` specifies the bus name the +controller should attach to. ``firstport`` specifies the first port the +controller should attach to, which is needed as usually one EHCI +controller with six ports has three UHCI companion controllers with +two ports each. + +There is a config file in docs which will do all this for +you, which you can use like this: + +.. parsed-literal:: + + |qemu_system| -readconfig docs/config/ich9-ehci-uhci.cfg + +Then use ``bus=ehci.0`` to assign your USB devices to that bus. + +Using the ``-usb`` switch for ``q35`` machines will create a similar +USB controller configuration. + + .. _Connecting USB devices: Connecting USB devices diff --git a/docs/usb2.txt b/docs/usb2.txt index 172614d3a7..adf4ba3f2a 100644 --- a/docs/usb2.txt +++ b/docs/usb2.txt @@ -1,86 +1,4 @@ -USB Quick Start -=============== - -XHCI controller support ------------------------ - -QEMU has XHCI host adapter support. The XHCI hardware design is much -more virtualization-friendly when compared to EHCI and UHCI, thus XHCI -emulation uses less resources (especially cpu). So if your guest -supports XHCI (which should be the case for any operating system -released around 2010 or later) we recommend using it: - - qemu -device qemu-xhci - -XHCI supports USB 1.1, USB 2.0 and USB 3.0 devices, so this is the -only controller you need. With only a single USB controller (and -therefore only a single USB bus) present in the system there is no -need to use the bus= parameter when adding USB devices. - - -EHCI controller support ------------------------ - -The QEMU EHCI Adapter supports USB 2.0 devices. It can be used either -standalone or with companion controllers (UHCI, OHCI) for USB 1.1 -devices. The companion controller setup is more convenient to use -because it provides a single USB bus supporting both USB 2.0 and USB -1.1 devices. See next section for details. - -When running EHCI in standalone mode you can add UHCI or OHCI -controllers for USB 1.1 devices too. Each controller creates its own -bus though, so there are two completely separate USB buses: One USB -1.1 bus driven by the UHCI controller and one USB 2.0 bus driven by -the EHCI controller. Devices must be attached to the correct -controller manually. - -The easiest way to add a UHCI controller to a 'pc' machine is the -'-usb' switch. QEMU will create the UHCI controller as function of -the PIIX3 chipset. The USB 1.1 bus will carry the name "usb-bus.0". - -You can use the standard -device switch to add a EHCI controller to -your virtual machine. It is strongly recommended to specify an ID for -the controller so the USB 2.0 bus gets an individual name, for example -'-device usb-ehci,id=ehci". This will give you a USB 2.0 bus named -"ehci.0". - -When adding USB devices using the -device switch you can specify the -bus they should be attached to. Here is a complete example: - - qemu -M pc ${otheroptions} \ - -drive if=none,id=usbstick,file=/path/to/image \ - -usb \ - -device usb-ehci,id=ehci \ - -device usb-tablet,bus=usb-bus.0 \ - -device usb-storage,bus=ehci.0,drive=usbstick - -This attaches a USB tablet to the UHCI adapter and a USB mass storage -device to the EHCI adapter. - - -Companion controller support ----------------------------- - -The UHCI and OHCI controllers can attach to a USB bus created by EHCI -as companion controllers. This is done by specifying the masterbus -and firstport properties. masterbus specifies the bus name the -controller should attach to. firstport specifies the first port the -controller should attach to, which is needed as usually one EHCI -controller with six ports has three UHCI companion controllers with -two ports each. - -There is a config file in docs which will do all this for -you, just try ... - - qemu -readconfig docs/config/ich9-ehci-uhci.cfg - -... then use "bus=ehci.0" to assign your USB devices to that bus. - -Using the '-usb' switch for 'q35' machines will create a similar -USB controller configuration. - - More USB tips & tricks ====================== From 557ae9763ad3669165c0db189118fac85bea706e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 28 Jul 2021 15:14:56 +0100 Subject: [PATCH 422/531] docs: Fold usb2.txt physical port addressing info into usb.rst Fold the usb2.txt documentation about specifying which physical port a USB device should use into usb.rst. Signed-off-by: Peter Maydell Message-Id: <20210728141457.14825-4-peter.maydell@linaro.org> Signed-off-by: Gerd Hoffmann --- docs/system/devices/usb.rst | 33 +++++++++++++++++++++++++++++++++ docs/usb2.txt | 32 -------------------------------- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/docs/system/devices/usb.rst b/docs/system/devices/usb.rst index 9f0e613dcc..bab0cd3fdf 100644 --- a/docs/system/devices/usb.rst +++ b/docs/system/devices/usb.rst @@ -199,6 +199,39 @@ option or the ``device_add`` monitor command. Available devices are: ``u2f-{emulated,passthru}`` Universal Second Factor device +Physical port addressing +^^^^^^^^^^^^^^^^^^^^^^^^ + +For all the above USB devices, by default QEMU will plug the device +into the next available port on the specified USB bus, or onto +some available USB bus if you didn't specify one explicitly. +If you need to, you can also specify the physical port where +the device will show up in the guest. This can be done using the +``port`` property. UHCI has two root ports (1,2). EHCI has six root +ports (1-6), and the emulated (1.1) USB hub has eight ports. + +Plugging a tablet into UHCI port 1 works like this:: + + -device usb-tablet,bus=usb-bus.0,port=1 + +Plugging a hub into UHCI port 2 works like this:: + + -device usb-hub,bus=usb-bus.0,port=2 + +Plugging a virtual USB stick into port 4 of the hub just plugged works +this way:: + + -device usb-storage,bus=usb-bus.0,port=2.4,drive=... + +In the monitor, the ``device_add` command also accepts a ``port`` +property specification. If you want to unplug devices too you should +specify some unique id which you can use to refer to the device. +You can then use ``device_del`` to unplug the device later. +For example:: + + (qemu) device_add usb-tablet,bus=usb-bus.0,port=1,id=my-tablet + (qemu) device_del my-tablet + Hotplugging USB storage ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/usb2.txt b/docs/usb2.txt index adf4ba3f2a..6a88d5314f 100644 --- a/docs/usb2.txt +++ b/docs/usb2.txt @@ -6,38 +6,6 @@ Recently the USB pass through driver (also known as usb-host) and the QEMU USB subsystem gained a few capabilities which are available only via qdev properties, i,e. when using '-device'. - -physical port addressing ------------------------- - -First you can (for all USB devices) specify the physical port where -the device will show up in the guest. This can be done using the -"port" property. UHCI has two root ports (1,2). EHCI has six root -ports (1-6), the emulated (1.1) USB hub has eight ports. - -Plugging a tablet into UHCI port 1 works like this: - - -device usb-tablet,bus=usb-bus.0,port=1 - -Plugging a hub into UHCI port 2 works like this: - - -device usb-hub,bus=usb-bus.0,port=2 - -Plugging a virtual USB stick into port 4 of the hub just plugged works -this way: - - -device usb-storage,bus=usb-bus.0,port=2.4,drive=... - -You can do basically the same in the monitor using the device_add -command. If you want to unplug devices too you should specify some -unique id which you can use to refer to the device ... - - (qemu) device_add usb-tablet,bus=usb-bus.0,port=1,id=my-tablet - (qemu) device_del my-tablet - -... when unplugging it with device_del. - - USB pass through hints ---------------------- From 30a20f2c5a9cf8f01ffcc918a7a5751dfe956524 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 28 Jul 2021 15:14:57 +0100 Subject: [PATCH 423/531] docs: Fold usb2.txt passthrough information into usb.rst Fold the usb2.txt information on device passthrough into usb.rst; since this is the last part of the .txt file we can delete it now. Signed-off-by: Peter Maydell Message-Id: <20210728141457.14825-5-peter.maydell@linaro.org> Signed-off-by: Gerd Hoffmann --- MAINTAINERS | 1 - docs/system/devices/usb.rst | 49 +++++++++++++++++++++++++++++++ docs/usb2.txt | 58 ------------------------------------- 3 files changed, 49 insertions(+), 59 deletions(-) delete mode 100644 docs/usb2.txt diff --git a/MAINTAINERS b/MAINTAINERS index b1f8e82bef..2089e71007 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1837,7 +1837,6 @@ F: hw/usb/* F: stubs/usb-dev-stub.c F: tests/qtest/usb-*-test.c F: docs/system/devices/usb.rst -F: docs/usb-storage.txt F: include/hw/usb.h F: include/hw/usb/ diff --git a/docs/system/devices/usb.rst b/docs/system/devices/usb.rst index bab0cd3fdf..afb7d6c226 100644 --- a/docs/system/devices/usb.rst +++ b/docs/system/devices/usb.rst @@ -300,3 +300,52 @@ are not supported yet. When relaunching QEMU, you may have to unplug and plug again the USB device to make it work again (this is a bug). + +``usb-host`` properties for specifying the host device +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The example above uses the ``vendorid`` and ``productid`` to +specify which host device to pass through, but this is not +the only way to specify the host device. ``usb-host`` supports +the following properties: + +``hostbus=`` + Specifies the bus number the device must be attached to +``hostaddr=`` + Specifies the device address the device got assigned by the guest os +``hostport=`` + Specifies the physical port the device is attached to +``vendorid=`` + Specifies the vendor ID of the device +``productid=`` + Specifies the product ID of the device. + +In theory you can combine all these properties as you like. In +practice only a few combinations are useful: + +- ``vendorid`` and ``productid`` -- match for a specific device, pass it to + the guest when it shows up somewhere in the host. + +- ``hostbus`` and ``hostport`` -- match for a specific physical port in the + host, any device which is plugged in there gets passed to the + guest. + +- ``hostbus`` and ``hostaddr`` -- most useful for ad-hoc pass through as the + hostaddr isn't stable. The next time you plug the device into the host it + will get a new hostaddr. + +Note that on the host USB 1.1 devices are handled by UHCI/OHCI and USB +2.0 by EHCI. That means different USB devices plugged into the very +same physical port on the host may show up on different host buses +depending on the speed. Supposing that devices plugged into a given +physical port appear as bus 1 + port 1 for 2.0 devices and bus 3 + port 1 +for 1.1 devices, you can pass through any device plugged into that port +and also assign it to the correct USB bus in QEMU like this: + +.. parsed-literal:: + + |qemu_system| -M pc [...] \\ + -usb \\ + -device usb-ehci,id=ehci \\ + -device usb-host,bus=usb-bus.0,hostbus=3,hostport=1 \\ + -device usb-host,bus=ehci.0,hostbus=1,hostport=1 diff --git a/docs/usb2.txt b/docs/usb2.txt deleted file mode 100644 index 6a88d5314f..0000000000 --- a/docs/usb2.txt +++ /dev/null @@ -1,58 +0,0 @@ - -More USB tips & tricks -====================== - -Recently the USB pass through driver (also known as usb-host) and the -QEMU USB subsystem gained a few capabilities which are available only -via qdev properties, i,e. when using '-device'. - -USB pass through hints ----------------------- - -The usb-host driver has a bunch of properties to specify the device -which should be passed to the guest: - - hostbus= -- Specifies the bus number the device must be attached - to. - - hostaddr= -- Specifies the device address the device got - assigned by the guest os. - - hostport= -- Specifies the physical port the device is attached - to. - - vendorid= -- Specifies the vendor ID of the device. - productid= -- Specifies the product ID of the device. - -In theory you can combine all these properties as you like. In -practice only a few combinations are useful: - - (1) vendorid+productid -- match for a specific device, pass it to - the guest when it shows up somewhere in the host. - - (2) hostbus+hostport -- match for a specific physical port in the - host, any device which is plugged in there gets passed to the - guest. - - (3) hostbus+hostaddr -- most useful for ad-hoc pass through as the - hostaddr isn't stable, the next time you plug in the device it - gets a new one ... - -Note that USB 1.1 devices are handled by UHCI/OHCI and USB 2.0 by -EHCI. That means a device plugged into the very same physical port -may show up on different buses depending on the speed. The port I'm -using for testing is bus 1 + port 1 for 2.0 devices and bus 3 + port 1 -for 1.1 devices. Passing through any device plugged into that port -and also assign them to the correct bus can be done this way: - - qemu -M pc ${otheroptions} \ - -usb \ - -device usb-ehci,id=ehci \ - -device usb-host,bus=usb-bus.0,hostbus=3,hostport=1 \ - -device usb-host,bus=ehci.0,hostbus=1,hostport=1 - -enjoy, - Gerd - --- -Gerd Hoffmann From 0ef2801423be33d80b52b14b6b55b3713a325dba Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Wed, 28 Jul 2021 15:15:15 +0200 Subject: [PATCH 424/531] MAINTAINERS: add Stefano Garzarella as io_uring reviewer I've been working with io_uring for a while so I'd like to help with reviews. Signed-off-by: Stefano Garzarella Message-Id: <20210728131515.131045-1-sgarzare@redhat.com> Signed-off-by: Stefan Hajnoczi --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 42ac45c3e5..1776d0950b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3257,6 +3257,7 @@ Linux io_uring M: Aarushi Mehta M: Julia Suvorova M: Stefan Hajnoczi +R: Stefano Garzarella L: qemu-block@nongnu.org S: Maintained F: block/io_uring.c From 54caccb3657e3960d8f5d57ab8e867028325d131 Mon Sep 17 00:00:00 2001 From: Fabian Ebner Date: Thu, 29 Jul 2021 11:10:29 +0200 Subject: [PATCH 425/531] block/io_uring: resubmit when result is -EAGAIN Linux SCSI can throw spurious -EAGAIN in some corner cases in its completion path, which will end up being the result in the completed io_uring request. Resubmitting such requests should allow block jobs to complete, even if such spurious errors are encountered. Co-authored-by: Stefan Hajnoczi Reviewed-by: Stefano Garzarella Signed-off-by: Fabian Ebner Message-id: 20210729091029.65369-1-f.ebner@proxmox.com Signed-off-by: Stefan Hajnoczi --- block/io_uring.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/block/io_uring.c b/block/io_uring.c index 00a3ee9fb8..dfa475cc87 100644 --- a/block/io_uring.c +++ b/block/io_uring.c @@ -165,7 +165,21 @@ static void luring_process_completions(LuringState *s) total_bytes = ret + luringcb->total_read; if (ret < 0) { - if (ret == -EINTR) { + /* + * Only writev/readv/fsync requests on regular files or host block + * devices are submitted. Therefore -EAGAIN is not expected but it's + * known to happen sometimes with Linux SCSI. Submit again and hope + * the request completes successfully. + * + * For more information, see: + * https://lore.kernel.org/io-uring/20210727165811.284510-3-axboe@kernel.dk/T/#u + * + * If the code is changed to submit other types of requests in the + * future, then this workaround may need to be extended to deal with + * genuine -EAGAIN results that should not be resubmitted + * immediately. + */ + if (ret == -EINTR || ret == -EAGAIN) { luring_resubmit(s, luringcb); continue; } From cc8eecd7f105a1dff5876adeb238a14696061a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 28 Jul 2021 20:33:40 +0200 Subject: [PATCH 426/531] MAINTAINERS: Added myself as a reviewer for the NVMe Block Driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm interested in following the activity around the NVMe bdrv. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20210728183340.2018313-1-philmd@redhat.com Signed-off-by: Stefan Hajnoczi --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1776d0950b..a3d598459a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3178,6 +3178,7 @@ F: block/null.c NVMe Block Driver M: Stefan Hajnoczi R: Fam Zheng +R: Philippe Mathieu-Daudé L: qemu-block@nongnu.org S: Supported F: block/nvme* From a3c2f12830683e285e1ef32d459717dcdf9b70c6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 29 Jul 2021 15:53:27 +0200 Subject: [PATCH 427/531] vl: introduce machine_merge_property It will be used to parse smp-opts config groups from configuration files. The point to note is that it does not steal a reference from the caller. This is better because this function will be called from qemu_config_foreach's callback; qemu_config_foreach does not cede its reference to the qdict to the callback, and wants to free it. To balance that extra reference, machine_parse_property_opt now needs a qobject_unref. Signed-off-by: Paolo Bonzini --- softmmu/vl.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index 4dee472c79..93aef8e747 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1534,23 +1534,36 @@ static void machine_help_func(const QDict *qdict) } } +static void +machine_merge_property(const char *propname, QDict *prop, Error **errp) +{ + QDict *opts; + + opts = qdict_new(); + /* Preserve the caller's reference to prop. */ + qobject_ref(prop); + qdict_put(opts, propname, prop); + keyval_merge(machine_opts_dict, opts, errp); + qobject_unref(opts); +} + static void machine_parse_property_opt(QemuOptsList *opts_list, const char *propname, const char *arg, Error **errp) { - QDict *opts, *prop; + QDict *prop = NULL; bool help = false; - ERRP_GUARD(); prop = keyval_parse(arg, opts_list->implied_opt_name, &help, errp); if (help) { qemu_opts_print_help(opts_list, true); exit(0); } - opts = qdict_new(); - qdict_put(opts, propname, prop); - keyval_merge(machine_opts_dict, opts, errp); - qobject_unref(opts); + if (!prop) { + return; + } + machine_merge_property(propname, prop, errp); + qobject_unref(prop); } static const char *pid_file; From e4383ca240d804bf1c472ed004d6c7b8a505fc63 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 29 Jul 2021 16:03:43 +0200 Subject: [PATCH 428/531] vl: stop recording -smp in QemuOpts -readconfig is still recording SMP options in QemuOpts instead of using machine_opts_dict. This means that SMP options from -readconfig are ignored. Just stop using QemuOpts for -smp, making it return false for is_qemuopts_group. Configuration files will merge the values in machine_opts_dict using the new function machine_merge_property. At the same time, fix -mem-prealloc which looked at QemuOpts to find the number of guest CPUs, which it used as the default number of preallocation threads. Signed-off-by: Paolo Bonzini --- softmmu/vl.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index 93aef8e747..5ca11e7469 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -31,6 +31,7 @@ #include "qapi/compat-policy.h" #include "qapi/error.h" #include "qapi/qmp/qdict.h" +#include "qapi/qmp/qstring.h" #include "qapi/qmp/qjson.h" #include "qemu-version.h" #include "qemu/cutils.h" @@ -2166,7 +2167,8 @@ static int global_init_func(void *opaque, QemuOpts *opts, Error **errp) static bool is_qemuopts_group(const char *group) { if (g_str_equal(group, "object") || - g_str_equal(group, "machine")) { + g_str_equal(group, "machine") || + g_str_equal(group, "smp-opts")) { return false; } return true; @@ -2186,6 +2188,8 @@ static void qemu_record_config_group(const char *group, QDict *dict, */ assert(!from_json); keyval_merge(machine_opts_dict, dict, errp); + } else if (g_str_equal(group, "smp-opts")) { + machine_merge_property("smp", dict, &error_fatal); } else { abort(); } @@ -2452,13 +2456,15 @@ static void qemu_validate_options(const QDict *machine_opts) static void qemu_process_sugar_options(void) { if (mem_prealloc) { - char *val; - - val = g_strdup_printf("%d", - (uint32_t) qemu_opt_get_number(qemu_find_opts_singleton("smp-opts"), "cpus", 1)); - object_register_sugar_prop("memory-backend", "prealloc-threads", val, - false); - g_free(val); + QObject *smp = qdict_get(machine_opts_dict, "smp"); + if (smp && qobject_type(smp) == QTYPE_QDICT) { + QObject *cpus = qdict_get(qobject_to(QDict, smp), "cpus"); + if (cpus && qobject_type(cpus) == QTYPE_QSTRING) { + const char *val = qstring_get_str(qobject_to(QString, cpus)); + object_register_sugar_prop("memory-backend", "prealloc-threads", + val, false); + } + } object_register_sugar_prop("memory-backend", "prealloc", "on", false); } From d4b3d152ee005825520dc171e1e650174ae5ebe6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 27 Jul 2021 17:50:09 +0200 Subject: [PATCH 429/531] coverity-model: update address_space_read/write models Use void * for consistency with the actual function; provide a model for MemoryRegionCache functions and for address_space_rw. These let Coverity understand the bounds of the data that various functions read and write even at very high levels of inlining (e.g. pci_dma_read). Signed-off-by: Paolo Bonzini --- scripts/coverity-scan/model.c | 48 ++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/scripts/coverity-scan/model.c b/scripts/coverity-scan/model.c index 2c0346ff25..e1bdf0ad84 100644 --- a/scripts/coverity-scan/model.c +++ b/scripts/coverity-scan/model.c @@ -45,9 +45,10 @@ typedef struct va_list_str *va_list; /* exec.c */ typedef struct AddressSpace AddressSpace; +typedef struct MemoryRegionCache MemoryRegionCache; typedef uint64_t hwaddr; typedef uint32_t MemTxResult; -typedef uint64_t MemTxAttrs; +typedef struct MemTxAttrs {} MemTxAttrs; static void __bufwrite(uint8_t *buf, ssize_t len) { @@ -67,9 +68,40 @@ static void __bufread(uint8_t *buf, ssize_t len) int last = buf[len-1]; } +MemTxResult address_space_read_cached(MemoryRegionCache *cache, hwaddr addr, + MemTxAttrs attrs, + void *buf, int len) +{ + MemTxResult result; + // TODO: investigate impact of treating reads as producing + // tainted data, with __coverity_tainted_data_argument__(buf). + __bufwrite(buf, len); + return result; +} + +MemTxResult address_space_write_cached(MemoryRegionCache *cache, hwaddr addr, + MemTxAttrs attrs, + const void *buf, int len) +{ + MemTxResult result; + __bufread(buf, len); + return result; +} + +MemTxResult address_space_rw_cached(MemoryRegionCache *cache, hwaddr addr, + MemTxAttrs attrs, + void *buf, int len, bool is_write) +{ + if (is_write) { + return address_space_write_cached(cache, addr, attrs, buf, len); + } else { + return address_space_read_cached(cache, addr, attrs, buf, len); + } +} + MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, - uint8_t *buf, int len) + void *buf, int len) { MemTxResult result; // TODO: investigate impact of treating reads as producing @@ -80,13 +112,23 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxResult address_space_write(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, - const uint8_t *buf, int len) + const void *buf, int len) { MemTxResult result; __bufread(buf, len); return result; } +MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, + MemTxAttrs attrs, + void *buf, int len, bool is_write) +{ + if (is_write) { + return address_space_write(as, addr, attrs, buf, len); + } else { + return address_space_read(as, addr, attrs, buf, len); + } +} /* Tainting */ From 243a545bffc7e86c0f5ae97c0f7d32c079ab78a3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 27 Jul 2021 17:54:15 +0200 Subject: [PATCH 430/531] coverity-model: make g_free a synonym of free Recently, Coverity has started complaining about using g_free() to free memory areas allocated by GLib functions not included in model.c, such as g_strfreev. This unfortunately goes against the GLib documentation, which suggests that g_malloc() should be matched with g_free() and plain malloc() with free(); since GLib 2.46 however g_malloc() is hardcoded to always use the system malloc implementation, and g_free is just "free" plus a tracepoint. Therefore, this should not cause any problem in practice. Signed-off-by: Paolo Bonzini --- scripts/coverity-scan/model.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/scripts/coverity-scan/model.c b/scripts/coverity-scan/model.c index e1bdf0ad84..8e64a84c5a 100644 --- a/scripts/coverity-scan/model.c +++ b/scripts/coverity-scan/model.c @@ -186,7 +186,7 @@ void *g_malloc_n(size_t nmemb, size_t size) sz = nmemb * size; ptr = __coverity_alloc__(sz); __coverity_mark_as_uninitialized_buffer__(ptr); - __coverity_mark_as_afm_allocated__(ptr, "g_free"); + __coverity_mark_as_afm_allocated__(ptr, AFM_free); return ptr; } @@ -200,7 +200,7 @@ void *g_malloc0_n(size_t nmemb, size_t size) sz = nmemb * size; ptr = __coverity_alloc__(sz); __coverity_writeall0__(ptr); - __coverity_mark_as_afm_allocated__(ptr, "g_free"); + __coverity_mark_as_afm_allocated__(ptr, AFM_free); return ptr; } @@ -218,14 +218,14 @@ void *g_realloc_n(void *ptr, size_t nmemb, size_t size) * model that. See Coverity's realloc() model */ __coverity_writeall__(ptr); - __coverity_mark_as_afm_allocated__(ptr, "g_free"); + __coverity_mark_as_afm_allocated__(ptr, AFM_free); return ptr; } void g_free(void *ptr) { __coverity_free__(ptr); - __coverity_mark_as_afm_freed__(ptr, "g_free"); + __coverity_mark_as_afm_freed__(ptr, AFM_free); } /* @@ -328,7 +328,7 @@ char *g_strdup(const char *s) __coverity_string_null_sink__(s); __coverity_string_size_sink__(s); dup = __coverity_alloc_nosize__(); - __coverity_mark_as_afm_allocated__(dup, "g_free"); + __coverity_mark_as_afm_allocated__(dup, AFM_free); for (i = 0; (dup[i] = s[i]); i++) ; return dup; } @@ -362,7 +362,7 @@ char *g_strdup_printf(const char *format, ...) s = __coverity_alloc_nosize__(); __coverity_writeall__(s); - __coverity_mark_as_afm_allocated__(s, "g_free"); + __coverity_mark_as_afm_allocated__(s, AFM_free); return s; } @@ -375,11 +375,10 @@ char *g_strdup_vprintf(const char *format, va_list ap) __coverity_string_size_sink__(format); ch = *format; - ch = *(char *)ap; s = __coverity_alloc_nosize__(); __coverity_writeall__(s); - __coverity_mark_as_afm_allocated__(s, "g_free"); + __coverity_mark_as_afm_allocated__(s, AFM_free); return len; } @@ -395,7 +394,7 @@ char *g_strconcat(const char *s, ...) s = __coverity_alloc_nosize__(); __coverity_writeall__(s); - __coverity_mark_as_afm_allocated__(s, "g_free"); + __coverity_mark_as_afm_allocated__(s, AFM_free); return s; } From 96915d638cb83aa139e39096815b8dd9832f264b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 27 Jul 2021 17:56:04 +0200 Subject: [PATCH 431/531] coverity-model: remove model for more allocation functions These models are not needed anymore now that Coverity does not check anymore that the result is used with "g_free". Coverity understands GCC attributes and uses them to detect leaks. Signed-off-by: Paolo Bonzini --- scripts/coverity-scan/model.c | 105 +--------------------------------- 1 file changed, 1 insertion(+), 104 deletions(-) diff --git a/scripts/coverity-scan/model.c b/scripts/coverity-scan/model.c index 8e64a84c5a..1a5f39d2ae 100644 --- a/scripts/coverity-scan/model.c +++ b/scripts/coverity-scan/model.c @@ -263,7 +263,7 @@ void *g_try_realloc_n(void *ptr, size_t nmemb, size_t size) return g_realloc_n(ptr, nmemb, size); } -/* Trivially derive the g_FOO() from the g_FOO_n() */ +/* Derive the g_FOO() from the g_FOO_n() */ void *g_malloc(size_t size) { @@ -295,109 +295,6 @@ void *g_try_realloc(void *ptr, size_t size) return g_try_realloc_n(ptr, 1, size); } -/* Other memory allocation functions */ - -void *g_memdup(const void *ptr, unsigned size) -{ - unsigned char *dup; - unsigned i; - - if (!ptr) { - return NULL; - } - - dup = g_malloc(size); - for (i = 0; i < size; i++) - dup[i] = ((unsigned char *)ptr)[i]; - return dup; -} - -/* - * GLib string allocation functions - */ - -char *g_strdup(const char *s) -{ - char *dup; - size_t i; - - if (!s) { - return NULL; - } - - __coverity_string_null_sink__(s); - __coverity_string_size_sink__(s); - dup = __coverity_alloc_nosize__(); - __coverity_mark_as_afm_allocated__(dup, AFM_free); - for (i = 0; (dup[i] = s[i]); i++) ; - return dup; -} - -char *g_strndup(const char *s, size_t n) -{ - char *dup; - size_t i; - - __coverity_negative_sink__(n); - - if (!s) { - return NULL; - } - - dup = g_malloc(n + 1); - for (i = 0; i < n && (dup[i] = s[i]); i++) ; - dup[i] = 0; - return dup; -} - -char *g_strdup_printf(const char *format, ...) -{ - char ch, *s; - size_t len; - - __coverity_string_null_sink__(format); - __coverity_string_size_sink__(format); - - ch = *format; - - s = __coverity_alloc_nosize__(); - __coverity_writeall__(s); - __coverity_mark_as_afm_allocated__(s, AFM_free); - return s; -} - -char *g_strdup_vprintf(const char *format, va_list ap) -{ - char ch, *s; - size_t len; - - __coverity_string_null_sink__(format); - __coverity_string_size_sink__(format); - - ch = *format; - - s = __coverity_alloc_nosize__(); - __coverity_writeall__(s); - __coverity_mark_as_afm_allocated__(s, AFM_free); - - return len; -} - -char *g_strconcat(const char *s, ...) -{ - char *s; - - /* - * Can't model: last argument must be null, the others - * null-terminated strings - */ - - s = __coverity_alloc_nosize__(); - __coverity_writeall__(s); - __coverity_mark_as_afm_allocated__(s, AFM_free); - return s; -} - /* Other glib functions */ typedef struct pollfd GPollFD; From 05ad6857a57238c27df84f6c0c1943dd162a82ad Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 27 Jul 2021 17:55:41 +0200 Subject: [PATCH 432/531] coverity-model: clean up the models for array allocation functions sz is only used in one place, so replace it with nmemb * size in that one place. Signed-off-by: Paolo Bonzini --- scripts/coverity-scan/model.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/scripts/coverity-scan/model.c b/scripts/coverity-scan/model.c index 1a5f39d2ae..2d384bdd79 100644 --- a/scripts/coverity-scan/model.c +++ b/scripts/coverity-scan/model.c @@ -178,13 +178,11 @@ uint8_t replay_get_byte(void) void *g_malloc_n(size_t nmemb, size_t size) { - size_t sz; void *ptr; __coverity_negative_sink__(nmemb); __coverity_negative_sink__(size); - sz = nmemb * size; - ptr = __coverity_alloc__(sz); + ptr = __coverity_alloc__(nmemb * size); __coverity_mark_as_uninitialized_buffer__(ptr); __coverity_mark_as_afm_allocated__(ptr, AFM_free); return ptr; @@ -192,13 +190,11 @@ void *g_malloc_n(size_t nmemb, size_t size) void *g_malloc0_n(size_t nmemb, size_t size) { - size_t sz; void *ptr; __coverity_negative_sink__(nmemb); __coverity_negative_sink__(size); - sz = nmemb * size; - ptr = __coverity_alloc__(sz); + ptr = __coverity_alloc__(nmemb * size); __coverity_writeall0__(ptr); __coverity_mark_as_afm_allocated__(ptr, AFM_free); return ptr; @@ -206,13 +202,10 @@ void *g_malloc0_n(size_t nmemb, size_t size) void *g_realloc_n(void *ptr, size_t nmemb, size_t size) { - size_t sz; - __coverity_negative_sink__(nmemb); __coverity_negative_sink__(size); - sz = nmemb * size; __coverity_escape__(ptr); - ptr = __coverity_alloc__(sz); + ptr = __coverity_alloc__(nmemb * size); /* * Memory beyond the old size isn't actually initialized. Can't * model that. See Coverity's realloc() model From 0da41187dfda6abecbcbc237471254ab614e063d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 28 Jul 2021 19:12:22 +0200 Subject: [PATCH 433/531] coverity-model: constrain g_malloc/g_malloc0/g_realloc as never returning NULL g_malloc/g_malloc0/g_realloc only return NULL if the size is 0; we do not need to cover that in the model, and so far have expected __coverity_alloc__ to model a non-NULL return value. But that apparently does not work anymore, so add some extra conditionals that invoke __coverity_panic__ for NULL pointers. Signed-off-by: Paolo Bonzini --- scripts/coverity-scan/model.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/coverity-scan/model.c b/scripts/coverity-scan/model.c index 2d384bdd79..028f13e9e3 100644 --- a/scripts/coverity-scan/model.c +++ b/scripts/coverity-scan/model.c @@ -183,6 +183,9 @@ void *g_malloc_n(size_t nmemb, size_t size) __coverity_negative_sink__(nmemb); __coverity_negative_sink__(size); ptr = __coverity_alloc__(nmemb * size); + if (!ptr) { + __coverity_panic__(); + } __coverity_mark_as_uninitialized_buffer__(ptr); __coverity_mark_as_afm_allocated__(ptr, AFM_free); return ptr; @@ -195,6 +198,9 @@ void *g_malloc0_n(size_t nmemb, size_t size) __coverity_negative_sink__(nmemb); __coverity_negative_sink__(size); ptr = __coverity_alloc__(nmemb * size); + if (!ptr) { + __coverity_panic__(); + } __coverity_writeall0__(ptr); __coverity_mark_as_afm_allocated__(ptr, AFM_free); return ptr; @@ -206,6 +212,9 @@ void *g_realloc_n(void *ptr, size_t nmemb, size_t size) __coverity_negative_sink__(size); __coverity_escape__(ptr); ptr = __coverity_alloc__(nmemb * size); + if (!ptr) { + __coverity_panic__(); + } /* * Memory beyond the old size isn't actually initialized. Can't * model that. See Coverity's realloc() model From e17bdaab2b36db54f0214a14f394fa773cee58df Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 27 Jul 2021 18:03:16 +0200 Subject: [PATCH 434/531] coverity-model: write models fully for non-array allocation functions Coverity seems to have issues figuring out the properties of g_malloc0 and other non *_n functions. While this was "fixed" by removing the custom second argument to __coverity_mark_as_afm_allocated__, inline the code from the array-based allocation functions to avoid future issues. Signed-off-by: Paolo Bonzini --- scripts/coverity-scan/model.c | 57 +++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/scripts/coverity-scan/model.c b/scripts/coverity-scan/model.c index 028f13e9e3..9d4fba53d9 100644 --- a/scripts/coverity-scan/model.c +++ b/scripts/coverity-scan/model.c @@ -269,32 +269,77 @@ void *g_try_realloc_n(void *ptr, size_t nmemb, size_t size) void *g_malloc(size_t size) { - return g_malloc_n(1, size); + void *ptr; + + __coverity_negative_sink__(size); + ptr = __coverity_alloc__(size); + if (!ptr) { + __coverity_panic__(); + } + __coverity_mark_as_uninitialized_buffer__(ptr); + __coverity_mark_as_afm_allocated__(ptr, AFM_free); + return ptr; } void *g_malloc0(size_t size) { - return g_malloc0_n(1, size); + void *ptr; + + __coverity_negative_sink__(size); + ptr = __coverity_alloc__(size); + if (!ptr) { + __coverity_panic__(); + } + __coverity_writeall0__(ptr); + __coverity_mark_as_afm_allocated__(ptr, AFM_free); + return ptr; } void *g_realloc(void *ptr, size_t size) { - return g_realloc_n(ptr, 1, size); + __coverity_negative_sink__(size); + __coverity_escape__(ptr); + ptr = __coverity_alloc__(size); + if (!ptr) { + __coverity_panic__(); + } + /* + * Memory beyond the old size isn't actually initialized. Can't + * model that. See Coverity's realloc() model + */ + __coverity_writeall__(ptr); + __coverity_mark_as_afm_allocated__(ptr, AFM_free); + return ptr; } void *g_try_malloc(size_t size) { - return g_try_malloc_n(1, size); + int nomem; + + if (nomem) { + return NULL; + } + return g_malloc(size); } void *g_try_malloc0(size_t size) { - return g_try_malloc0_n(1, size); + int nomem; + + if (nomem) { + return NULL; + } + return g_malloc0(size); } void *g_try_realloc(void *ptr, size_t size) { - return g_try_realloc_n(ptr, 1, size); + int nomem; + + if (nomem) { + return NULL; + } + return g_realloc(ptr, size); } /* Other glib functions */ From 7039e1f60486662d238ea1a16992a3efe80d7840 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 26 Jul 2021 08:10:23 -1000 Subject: [PATCH 435/531] accel/tcg: Remove double bswap for helper_atomic_sto_*_mmu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This crept in as either a cut-and-paste error, or rebase error. Fixes: cfec388518d ("atomic_template: add inline trace/plugin helpers") Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210729004647.282017-24-richard.henderson@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/atomic_template.h | 1 - 1 file changed, 1 deletion(-) diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h index d89af4cc1e..8098a1be31 100644 --- a/accel/tcg/atomic_template.h +++ b/accel/tcg/atomic_template.h @@ -251,7 +251,6 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, PAGE_WRITE, retaddr); uint16_t info = atomic_trace_st_pre(env, addr, oi); - val = BSWAP(val); val = BSWAP(val); atomic16_set(haddr, val); ATOMIC_MMU_CLEANUP; From 236f6709ae0da224314c3344c339ed0dc07c15cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 29 Jul 2021 12:13:15 +0200 Subject: [PATCH 436/531] target/nios2: Mark raise_exception() as noreturn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Raised exceptions don't return, so mark the helper with noreturn. Fixes: 032c76bc6f9 ("nios2: Add architecture emulation support") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210729101315.2318714-1-f4bug@amsat.org> Signed-off-by: Richard Henderson --- target/nios2/helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/nios2/helper.h b/target/nios2/helper.h index b0cb9146a5..6c8f0b5b35 100644 --- a/target/nios2/helper.h +++ b/target/nios2/helper.h @@ -18,7 +18,7 @@ * */ -DEF_HELPER_2(raise_exception, void, env, i32) +DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32) #if !defined(CONFIG_USER_ONLY) DEF_HELPER_2(mmu_read_debug, void, env, i32) From 9010b0c7a9a097590e183f63716091f6c42a223f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 21 Jul 2021 16:15:59 +0200 Subject: [PATCH 437/531] hw/net/vmxnet3: Do not abort QEMU if guest specified bad queue numbers QEMU should never terminate unexpectedly just because the guest is doing something wrong like specifying wrong queue numbers. Let's simply refuse to set the device active in this case. Buglink: https://bugs.launchpad.net/qemu/+bug/1890160 Signed-off-by: Thomas Huth Signed-off-by: Jason Wang --- hw/net/vmxnet3.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index f6bd8c53b1..41f796a247 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -1381,7 +1381,7 @@ static void vmxnet3_validate_interrupts(VMXNET3State *s) } } -static void vmxnet3_validate_queues(VMXNET3State *s) +static bool vmxnet3_validate_queues(VMXNET3State *s) { /* * txq_num and rxq_num are total number of queues @@ -1390,12 +1390,18 @@ static void vmxnet3_validate_queues(VMXNET3State *s) */ if (s->txq_num > VMXNET3_DEVICE_MAX_TX_QUEUES) { - hw_error("Bad TX queues number: %d\n", s->txq_num); + qemu_log_mask(LOG_GUEST_ERROR, "vmxnet3: Bad TX queues number: %d\n", + s->txq_num); + return false; } if (s->rxq_num > VMXNET3_DEVICE_MAX_RX_QUEUES) { - hw_error("Bad RX queues number: %d\n", s->rxq_num); + qemu_log_mask(LOG_GUEST_ERROR, "vmxnet3: Bad RX queues number: %d\n", + s->rxq_num); + return false; } + + return true; } static void vmxnet3_activate_device(VMXNET3State *s) @@ -1419,6 +1425,16 @@ static void vmxnet3_activate_device(VMXNET3State *s) return; } + s->txq_num = + VMXNET3_READ_DRV_SHARED8(d, s->drv_shmem, devRead.misc.numTxQueues); + s->rxq_num = + VMXNET3_READ_DRV_SHARED8(d, s->drv_shmem, devRead.misc.numRxQueues); + + VMW_CFPRN("Number of TX/RX queues %u/%u", s->txq_num, s->rxq_num); + if (!vmxnet3_validate_queues(s)) { + return; + } + vmxnet3_adjust_by_guest_type(s); vmxnet3_update_features(s); vmxnet3_update_pm_state(s); @@ -1445,14 +1461,6 @@ static void vmxnet3_activate_device(VMXNET3State *s) VMXNET3_READ_DRV_SHARED8(d, s->drv_shmem, devRead.intrConf.autoMask); VMW_CFPRN("Automatic interrupt masking is %d", (int)s->auto_int_masking); - s->txq_num = - VMXNET3_READ_DRV_SHARED8(d, s->drv_shmem, devRead.misc.numTxQueues); - s->rxq_num = - VMXNET3_READ_DRV_SHARED8(d, s->drv_shmem, devRead.misc.numRxQueues); - - VMW_CFPRN("Number of TX/RX queues %u/%u", s->txq_num, s->rxq_num); - vmxnet3_validate_queues(s); - qdescr_table_pa = VMXNET3_READ_DRV_SHARED64(d, s->drv_shmem, devRead.misc.queueDescPA); VMW_CFPRN("TX queues descriptors table is at 0x%" PRIx64, qdescr_table_pa); @@ -2404,7 +2412,9 @@ static int vmxnet3_post_load(void *opaque, int version_id) } } - vmxnet3_validate_queues(s); + if (!vmxnet3_validate_queues(s)) { + return -1; + } vmxnet3_validate_interrupts(s); return 0; From 11744862f27b9ba6488a247d2fd6bb83d9bc3c8d Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Thu, 29 Jul 2021 14:33:27 +0200 Subject: [PATCH 438/531] hw/net/can: sja1000 fix buff2frame_bas and buff2frame_pel when dlc is out of std CAN 8 bytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem reported by openEuler fuzz-sig group. The buff2frame_bas function (hw\net\can\can_sja1000.c) infoleak(qemu5.x~qemu6.x) or stack-overflow(qemu 4.x). Reported-by: Qiang Ning Cc: qemu-stable@nongnu.org Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Pavel Pisa Signed-off-by: Jason Wang --- hw/net/can/can_sja1000.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/net/can/can_sja1000.c b/hw/net/can/can_sja1000.c index 42d2f99dfb..34eea684ce 100644 --- a/hw/net/can/can_sja1000.c +++ b/hw/net/can/can_sja1000.c @@ -275,6 +275,10 @@ static void buff2frame_pel(const uint8_t *buff, qemu_can_frame *frame) } frame->can_dlc = buff[0] & 0x0f; + if (frame->can_dlc > 8) { + frame->can_dlc = 8; + } + if (buff[0] & 0x80) { /* Extended */ frame->can_id |= QEMU_CAN_EFF_FLAG; frame->can_id |= buff[1] << 21; /* ID.28~ID.21 */ @@ -311,6 +315,10 @@ static void buff2frame_bas(const uint8_t *buff, qemu_can_frame *frame) } frame->can_dlc = buff[1] & 0x0f; + if (frame->can_dlc > 8) { + frame->can_dlc = 8; + } + for (i = 0; i < frame->can_dlc; i++) { frame->data[i] = buff[2 + i]; } From a1d7e475beb5c9e7a8e1213f29b0d20a208a9ade Mon Sep 17 00:00:00 2001 From: Christina Wang Date: Fri, 23 Jul 2021 15:55:10 +0800 Subject: [PATCH 439/531] hw/net: e1000: Correct the initial value of VET register The initial value of VLAN Ether Type (VET) register is 0x8100, as per the manual and real hardware. While Linux e1000 driver always writes VET register to 0x8100, it is not always the case for everyone. Drivers relying on the reset value of VET won't be able to transmit and receive VLAN frames in QEMU. Reported-by: Markus Carlstedt Signed-off-by: Christina Wang Signed-off-by: Bin Meng Signed-off-by: Jason Wang --- hw/core/machine.c | 1 + hw/net/e1000.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index 775add0795..f98a797e43 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -41,6 +41,7 @@ GlobalProperty hw_compat_6_0[] = { { "gpex-pcihost", "allow-unmapped-accesses", "false" }, { "i8042", "extended-state", "false"}, { "nvme-ns", "eui64-default", "off"}, + { "e1000", "init-vet", "off" }, }; const size_t hw_compat_6_0_len = G_N_ELEMENTS(hw_compat_6_0); diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 4f75b44cfc..a30546c5d5 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -29,6 +29,7 @@ #include "hw/pci/pci.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" +#include "net/eth.h" #include "net/net.h" #include "net/checksum.h" #include "sysemu/sysemu.h" @@ -130,10 +131,13 @@ struct E1000State_st { #define E1000_FLAG_MIT_BIT 1 #define E1000_FLAG_MAC_BIT 2 #define E1000_FLAG_TSO_BIT 3 +#define E1000_FLAG_VET_BIT 4 #define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT) #define E1000_FLAG_MIT (1 << E1000_FLAG_MIT_BIT) #define E1000_FLAG_MAC (1 << E1000_FLAG_MAC_BIT) #define E1000_FLAG_TSO (1 << E1000_FLAG_TSO_BIT) +#define E1000_FLAG_VET (1 << E1000_FLAG_VET_BIT) + uint32_t compat_flags; bool received_tx_tso; bool use_tso_for_migration; @@ -361,6 +365,13 @@ e1000_autoneg_timer(void *opaque) } } +static bool e1000_vet_init_need(void *opaque) +{ + E1000State *s = opaque; + + return chkflag(VET); +} + static void e1000_reset(void *opaque) { E1000State *d = opaque; @@ -386,6 +397,10 @@ static void e1000_reset(void *opaque) } e1000x_reset_mac_addr(d->nic, d->mac_reg, macaddr); + + if (e1000_vet_init_need(d)) { + d->mac_reg[VET] = ETH_P_VLAN; + } } static void @@ -1737,6 +1752,8 @@ static Property e1000_properties[] = { compat_flags, E1000_FLAG_MAC_BIT, true), DEFINE_PROP_BIT("migrate_tso_props", E1000State, compat_flags, E1000_FLAG_TSO_BIT, true), + DEFINE_PROP_BIT("init-vet", E1000State, + compat_flags, E1000_FLAG_VET_BIT, true), DEFINE_PROP_END_OF_LIST(), }; From d897056960fb379302cc9b656b899829f571eb6e Mon Sep 17 00:00:00 2001 From: Christina Wang Date: Fri, 23 Jul 2021 15:55:11 +0800 Subject: [PATCH 440/531] hw/net: e1000e: Correct the initial value of VET register The initial value of VLAN Ether Type (VET) register is 0x8100, as per the manual and real hardware. While Linux e1000e driver always writes VET register to 0x8100, it is not always the case for everyone. Drivers relying on the reset value of VET won't be able to transmit and receive VLAN frames in QEMU. Unlike e1000 in QEMU, e1000e uses a field 'vet' in "struct E1000Core" to cache the value of VET register, but the cache only gets updated when VET register is written. To always get a consistent VET value no matter VET is written or remains its reset value, drop the 'vet' field and use 'core->mac[VET]' directly. Reported-by: Markus Carlstedt Signed-off-by: Christina Wang Signed-off-by: Bin Meng Signed-off-by: Jason Wang --- hw/core/machine.c | 1 + hw/net/e1000e.c | 8 +++++++- hw/net/e1000e_core.c | 9 ++++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index f98a797e43..943974d411 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -42,6 +42,7 @@ GlobalProperty hw_compat_6_0[] = { { "i8042", "extended-state", "false"}, { "nvme-ns", "eui64-default", "off"}, { "e1000", "init-vet", "off" }, + { "e1000e", "init-vet", "off" }, }; const size_t hw_compat_6_0_len = G_N_ELEMENTS(hw_compat_6_0); diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index a8a77eca95..ac96f7665a 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -35,6 +35,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" +#include "net/eth.h" #include "net/net.h" #include "net/tap.h" #include "qemu/module.h" @@ -79,7 +80,7 @@ struct E1000EState { bool disable_vnet; E1000ECore core; - + bool init_vet; }; #define E1000E_MMIO_IDX 0 @@ -527,6 +528,10 @@ static void e1000e_qdev_reset(DeviceState *dev) trace_e1000e_cb_qdev_reset(); e1000e_core_reset(&s->core); + + if (s->init_vet) { + s->core.mac[VET] = ETH_P_VLAN; + } } static int e1000e_pre_save(void *opaque) @@ -666,6 +671,7 @@ static Property e1000e_properties[] = { e1000e_prop_subsys_ven, uint16_t), DEFINE_PROP_SIGNED("subsys", E1000EState, subsys, 0, e1000e_prop_subsys, uint16_t), + DEFINE_PROP_BOOL("init-vet", E1000EState, init_vet, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index b75f2ab8fc..b4bf4ca2f1 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -731,7 +731,7 @@ e1000e_process_tx_desc(E1000ECore *core, if (e1000x_vlan_enabled(core->mac) && e1000x_is_vlan_txd(txd_lower)) { net_tx_pkt_setup_vlan_header_ex(tx->tx_pkt, - le16_to_cpu(dp->upper.fields.special), core->vet); + le16_to_cpu(dp->upper.fields.special), core->mac[VET]); } if (e1000e_tx_pkt_send(core, tx, queue_index)) { e1000e_on_tx_done_update_stats(core, tx->tx_pkt); @@ -1012,7 +1012,7 @@ e1000e_receive_filter(E1000ECore *core, const uint8_t *buf, int size) { uint32_t rctl = core->mac[RCTL]; - if (e1000x_is_vlan_packet(buf, core->vet) && + if (e1000x_is_vlan_packet(buf, core->mac[VET]) && e1000x_vlan_rx_filter_enabled(core->mac)) { uint16_t vid = lduw_be_p(buf + 14); uint32_t vfta = ldl_le_p((uint32_t *)(core->mac + VFTA) + @@ -1686,7 +1686,7 @@ e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt) } net_rx_pkt_attach_iovec_ex(core->rx_pkt, iov, iovcnt, iov_ofs, - e1000x_vlan_enabled(core->mac), core->vet); + e1000x_vlan_enabled(core->mac), core->mac[VET]); e1000e_rss_parse_packet(core, core->rx_pkt, &rss_info); e1000e_rx_ring_init(core, &rxr, rss_info.queue); @@ -2397,8 +2397,7 @@ static void e1000e_set_vet(E1000ECore *core, int index, uint32_t val) { core->mac[VET] = val & 0xffff; - core->vet = le16_to_cpu(core->mac[VET]); - trace_e1000e_vlan_vet(core->vet); + trace_e1000e_vlan_vet(core->mac[VET]); } static void From cfe6d6841ff46b43ec38792422f690813f4ce3bf Mon Sep 17 00:00:00 2001 From: Christina Wang Date: Fri, 23 Jul 2021 15:55:12 +0800 Subject: [PATCH 441/531] hw/net: e1000e: Don't zero out the VLAN tag in the legacy RX descriptor In the legacy RX descriptor mode, VLAN tag was saved to d->special by e1000e_build_rx_metadata() in e1000e_write_lgcy_rx_descr(), but it was then zeroed out again at the end of the call, which is wrong. Fixes: c89d416a2b0f ("e1000e: Don't zero out buffer address in rx descriptor") Reported-by: Markus Carlstedt Signed-off-by: Christina Wang Signed-off-by: Bin Meng Signed-off-by: Jason Wang --- hw/net/e1000e_core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index b4bf4ca2f1..8ae6fb7e14 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -1285,7 +1285,6 @@ e1000e_write_lgcy_rx_descr(E1000ECore *core, uint8_t *desc, &d->special); d->errors = (uint8_t) (le32_to_cpu(status_flags) >> 24); d->status = (uint8_t) le32_to_cpu(status_flags); - d->special = 0; } static inline void From c9543db4cc8c5a858a2cba424c603ffbd8bf613e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 22 Jul 2021 18:52:27 +0100 Subject: [PATCH 442/531] docs: Add documentation of Arm 'mainstone' board Add brief documentation of the Arm 'mainstone' board. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210722175229.29065-2-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/system/arm/mainstone.rst | 25 +++++++++++++++++++++++++ docs/system/target-arm.rst | 1 + 3 files changed, 27 insertions(+) create mode 100644 docs/system/arm/mainstone.rst diff --git a/MAINTAINERS b/MAINTAINERS index 6831978d2c..24e0819bf8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -856,6 +856,7 @@ F: include/hw/arm/pxa.h F: include/hw/arm/sharpsl.h F: include/hw/display/tc6393xb.h F: docs/system/arm/xscale.rst +F: docs/system/arm/mainstone.rst SABRELITE / i.MX6 M: Peter Maydell diff --git a/docs/system/arm/mainstone.rst b/docs/system/arm/mainstone.rst new file mode 100644 index 0000000000..05310f42c7 --- /dev/null +++ b/docs/system/arm/mainstone.rst @@ -0,0 +1,25 @@ +Intel Mainstone II board (``mainstone``) +======================================== + +The ``mainstone`` board emulates the Intel Mainstone II development +board, which uses a PXA270 CPU. + +Emulated devices: + +- Flash memory +- Keypad +- MMC controller +- 91C111 ethernet +- PIC +- Timer +- DMA +- GPIO +- FIR +- Serial +- LCD controller +- SSP +- USB controller +- RTC +- PCMCIA +- I2C +- I2S diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index c0c2585c0a..ad3f5f435d 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -90,6 +90,7 @@ undocumented; you can get a complete list by running arm/highbank arm/musicpal arm/gumstix + arm/mainstone arm/nrf arm/nseries arm/nuvoton From fa6c93944a049dac4d313b5b66d67344266c1d2a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 22 Jul 2021 18:52:28 +0100 Subject: [PATCH 443/531] docs: Add documentation of Arm 'kzm' board Add brief documentation of the Arm 'kzm' board. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210722175229.29065-3-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/system/arm/kzm.rst | 18 ++++++++++++++++++ docs/system/target-arm.rst | 1 + 3 files changed, 20 insertions(+) create mode 100644 docs/system/arm/kzm.rst diff --git a/MAINTAINERS b/MAINTAINERS index 24e0819bf8..6c558303f9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -694,6 +694,7 @@ F: hw/*/imx_* F: hw/*/*imx31* F: include/hw/*/imx_* F: include/hw/*/*imx31* +F: docs/system/arm/kzm.rst Integrator CP M: Peter Maydell diff --git a/docs/system/arm/kzm.rst b/docs/system/arm/kzm.rst new file mode 100644 index 0000000000..bb018fbdf7 --- /dev/null +++ b/docs/system/arm/kzm.rst @@ -0,0 +1,18 @@ +Kyoto Microcomputer KZM-ARM11-01 (``kzm``) +========================================== + +The ``kzm`` board emulates the Kyoto Microcomputer KZM-ARM11-01 +evaluation board, which is based on an NXP i.MX32 SoC +which uses an ARM1136 CPU. + +Emulated devices: + +- UARTs +- LAN9118 ethernet +- AVIC +- CCM +- GPT +- EPIT timers +- I2C +- GPIO controllers +- Watchdog timer diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index ad3f5f435d..d423782d66 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -91,6 +91,7 @@ undocumented; you can get a complete list by running arm/musicpal arm/gumstix arm/mainstone + arm/kzm arm/nrf arm/nseries arm/nuvoton From b1b3e3e3bff2aec62b6d5df8491dca94e380978b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 22 Jul 2021 18:52:29 +0100 Subject: [PATCH 444/531] docs: Add documentation of Arm 'imx25-pdk' board Add brief documentation of the Arm 'imx25-pdk' board. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210722175229.29065-4-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/system/arm/imx25-pdk.rst | 19 +++++++++++++++++++ docs/system/target-arm.rst | 1 + 3 files changed, 21 insertions(+) create mode 100644 docs/system/arm/imx25-pdk.rst diff --git a/MAINTAINERS b/MAINTAINERS index 6c558303f9..bda08356d4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -684,6 +684,7 @@ F: hw/watchdog/wdt_imx2.c F: include/hw/arm/fsl-imx25.h F: include/hw/misc/imx25_ccm.h F: include/hw/watchdog/wdt_imx2.h +F: docs/system/arm/imx25-pdk.rst i.MX31 (kzm) M: Peter Maydell diff --git a/docs/system/arm/imx25-pdk.rst b/docs/system/arm/imx25-pdk.rst new file mode 100644 index 0000000000..2a9711e8a7 --- /dev/null +++ b/docs/system/arm/imx25-pdk.rst @@ -0,0 +1,19 @@ +NXP i.MX25 PDK board (``imx25-pdk``) +==================================== + +The ``imx25-pdk`` board emulates the NXP i.MX25 Product Development Kit +board, which is based on an i.MX25 SoC which uses an ARM926 CPU. + +Emulated devices: + +- SD controller +- AVIC +- CCM +- GPT +- EPIT timers +- FEC +- RNGC +- I2C +- GPIO controllers +- Watchdog timer +- USB controllers diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index d423782d66..91ebc26c6d 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -95,6 +95,7 @@ undocumented; you can get a complete list by running arm/nrf arm/nseries arm/nuvoton + arm/imx25-pdk arm/orangepi arm/palm arm/raspi From 7c6ef61a5c69e1a4f2c43b6f207d215bea714b19 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 22 Jul 2021 19:09:51 +0100 Subject: [PATCH 445/531] MAINTAINERS: Don't list Andrzej Zaborowski for various components Andrzej Zaborowski is listed as an "Odd Fixes" maintainer for the nSeries, Palm and PXA2XX boards, as well as the "Maintained" status Arm 32-bit TCG backend. Andrzej's last email to qemu-devel was back in 2017, and the email before that was all the way back in 2013. We don't really need to fill his email up with CCs on QEMU patches any more... Remove Andrzej from the various boards sections (leaving them still Odd Fixes with me as the backup patch reviewer). Add Richard Henderson as the maintainer for the Arm TCG backend, since removing Andrzej would otherwise leave that section with no M: line at all. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210722180951.29802-1-peter.maydell@linaro.org --- MAINTAINERS | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index bda08356d4..37b1a8e442 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -788,7 +788,6 @@ F: roms/vbootrom F: docs/system/arm/nuvoton.rst nSeries -M: Andrzej Zaborowski M: Peter Maydell L: qemu-arm@nongnu.org S: Odd Fixes @@ -806,7 +805,6 @@ F: tests/acceptance/machine_arm_n8x0.py F: docs/system/arm/nseries.rst Palm -M: Andrzej Zaborowski M: Peter Maydell L: qemu-arm@nongnu.org S: Odd Fixes @@ -839,7 +837,6 @@ F: include/hw/intc/realview_gic.h F: docs/system/arm/realview.rst PXA2XX -M: Andrzej Zaborowski M: Peter Maydell L: qemu-arm@nongnu.org S: Odd Fixes @@ -3043,7 +3040,7 @@ F: disas/arm-a64.cc F: disas/libvixl/ ARM TCG target -M: Andrzej Zaborowski +M: Richard Henderson S: Maintained L: qemu-arm@nongnu.org F: tcg/arm/ From 199a4363056a205c5a770802323aa22c1555c2b8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 22 Jul 2021 20:20:15 +0100 Subject: [PATCH 446/531] docs: Remove stale TODO comments about license and version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commits 13f934e79fa and 3a50c8f3067aaf, our HTML docs include a footer to all pages stating the license and version. We can therefore delete the TODO comments suggesting we should do that from our .rst files. Signed-off-by: Peter Maydell Reviewed-by: Marc-André Lureau Reviewed-by: Cleber Rosa Reviewed-by: Markus Armbruster Message-id: 20210722192016.24915-2-peter.maydell@linaro.org --- docs/interop/qemu-ga-ref.rst | 9 --------- docs/interop/qemu-qmp-ref.rst | 9 --------- docs/interop/qemu-storage-daemon-qmp-ref.rst | 9 --------- 3 files changed, 27 deletions(-) diff --git a/docs/interop/qemu-ga-ref.rst b/docs/interop/qemu-ga-ref.rst index db1e946124..032d492455 100644 --- a/docs/interop/qemu-ga-ref.rst +++ b/docs/interop/qemu-ga-ref.rst @@ -1,15 +1,6 @@ QEMU Guest Agent Protocol Reference =================================== -.. - TODO: the old Texinfo manual used to note that this manual - is GPL-v2-or-later. We should make that reader-visible - both here and in our Sphinx manuals more generally. - -.. - TODO: display the QEMU version, both here and in our Sphinx manuals - more generally. - .. contents:: :depth: 3 diff --git a/docs/interop/qemu-qmp-ref.rst b/docs/interop/qemu-qmp-ref.rst index b5bebf6b9a..357effd64f 100644 --- a/docs/interop/qemu-qmp-ref.rst +++ b/docs/interop/qemu-qmp-ref.rst @@ -1,15 +1,6 @@ QEMU QMP Reference Manual ========================= -.. - TODO: the old Texinfo manual used to note that this manual - is GPL-v2-or-later. We should make that reader-visible - both here and in our Sphinx manuals more generally. - -.. - TODO: display the QEMU version, both here and in our Sphinx manuals - more generally. - .. contents:: :depth: 3 diff --git a/docs/interop/qemu-storage-daemon-qmp-ref.rst b/docs/interop/qemu-storage-daemon-qmp-ref.rst index d0ebb42ebd..9fed68152f 100644 --- a/docs/interop/qemu-storage-daemon-qmp-ref.rst +++ b/docs/interop/qemu-storage-daemon-qmp-ref.rst @@ -1,15 +1,6 @@ QEMU Storage Daemon QMP Reference Manual ======================================== -.. - TODO: the old Texinfo manual used to note that this manual - is GPL-v2-or-later. We should make that reader-visible - both here and in our Sphinx manuals more generally. - -.. - TODO: display the QEMU version, both here and in our Sphinx manuals - more generally. - .. contents:: :depth: 3 From 4e0b15c25228d14c55bdd482e11a1b351d00191b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 22 Jul 2021 20:20:16 +0100 Subject: [PATCH 447/531] docs: Move licence/copyright from HTML output to rST comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our built HTML documentation now has a standard footer which gives the license for QEMU (and its documentation as a whole). In almost all pages, we either don't bother to state the copyright/license for the individual rST sources, or we put it in an rST comment. There are just three pages which render copyright or license information into the user-visible HTML. Quoting a specific (different) license for an individual HTML page within the manual is confusing. Downgrade the license and copyright info to a comment within the rST source, bringing these pages in line with the rest of our documents. Suggested-by: Markus Armbruster Signed-off-by: Peter Maydell Reviewed-by: Marc-André Lureau Reviewed-by: Cleber Rosa Reviewed-by: Markus Armbruster Acked-by: Michael S. Tsirkin Message-id: 20210722192016.24915-3-peter.maydell@linaro.org --- docs/interop/vhost-user-gpu.rst | 7 ++++--- docs/interop/vhost-user.rst | 12 +++++++----- docs/system/generic-loader.rst | 4 ++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/interop/vhost-user-gpu.rst b/docs/interop/vhost-user-gpu.rst index 3268bf405c..71a2c52b31 100644 --- a/docs/interop/vhost-user-gpu.rst +++ b/docs/interop/vhost-user-gpu.rst @@ -2,9 +2,10 @@ Vhost-user-gpu Protocol ======================= -:Licence: This work is licensed under the terms of the GNU GPL, - version 2 or later. See the COPYING file in the top-level - directory. +.. + Licence: This work is licensed under the terms of the GNU GPL, + version 2 or later. See the COPYING file in the top-level + directory. .. contents:: Table of Contents diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index 7fc693521e..edc3ad84a3 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -3,11 +3,13 @@ =================== Vhost-user Protocol =================== -:Copyright: 2014 Virtual Open Systems Sarl. -:Copyright: 2019 Intel Corporation -:Licence: This work is licensed under the terms of the GNU GPL, - version 2 or later. See the COPYING file in the top-level - directory. + +.. + Copyright 2014 Virtual Open Systems Sarl. + Copyright 2019 Intel Corporation + Licence: This work is licensed under the terms of the GNU GPL, + version 2 or later. See the COPYING file in the top-level + directory. .. contents:: Table of Contents diff --git a/docs/system/generic-loader.rst b/docs/system/generic-loader.rst index 531ddbc8e3..4f9fb005f1 100644 --- a/docs/system/generic-loader.rst +++ b/docs/system/generic-loader.rst @@ -1,8 +1,8 @@ .. Copyright (c) 2016, Xilinx Inc. -This work is licensed under the terms of the GNU GPL, version 2 or later. See -the COPYING file in the top-level directory. + This work is licensed under the terms of the GNU GPL, version 2 or later. See + the COPYING file in the top-level directory. Generic Loader -------------- From 35a4ca403145c9412c5fc042fd2baa20bc21b858 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Jul 2021 15:23:29 +0100 Subject: [PATCH 448/531] docs/devel/build-system.rst: Format literals correctly In rST markup, single backticks `like this` represent "interpreted text", which can be handled as a bunch of different things if tagged with a specific "role": https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#interpreted-text (the most common one for us is "reference to a URL, which gets hyperlinked"). The default "role" if none is specified is "title_reference", intended for references to book or article titles, and it renders into the HTML as ... (usually comes out as italics). build-system.rst seems to have been written under the mistaken assumption that single-backticks mark up literal text (function names, etc) which should be rendered in a fixed-width font. The rST markup for this is ``double backticks``. Update all the markup. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210726142338.31872-2-peter.maydell@linaro.org --- docs/devel/build-system.rst | 156 ++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/docs/devel/build-system.rst b/docs/devel/build-system.rst index fd1650442e..ee660a998d 100644 --- a/docs/devel/build-system.rst +++ b/docs/devel/build-system.rst @@ -53,14 +53,14 @@ following tasks: - Add a Meson build option to meson_options.txt. - Add support to the command line arg parser to handle any new - `--enable-XXX`/`--disable-XXX` flags required by the feature. + ``--enable-XXX``/``--disable-XXX`` flags required by the feature. - Add information to the help output message to report on the new feature flag. - Add code to perform the actual feature check. - - Add code to include the feature status in `config-host.h` + - Add code to include the feature status in ``config-host.h`` - Add code to print out the feature status in the configure summary upon completion. @@ -116,51 +116,51 @@ Helper functions The configure script provides a variety of helper functions to assist developers in checking for system features: -`do_cc $ARGS...` +``do_cc $ARGS...`` Attempt to run the system C compiler passing it $ARGS... -`do_cxx $ARGS...` +``do_cxx $ARGS...`` Attempt to run the system C++ compiler passing it $ARGS... -`compile_object $CFLAGS` +``compile_object $CFLAGS`` Attempt to compile a test program with the system C compiler using $CFLAGS. The test program must have been previously written to a file - called $TMPC. The replacement in Meson is the compiler object `cc`, - which has methods such as `cc.compiles()`, - `cc.check_header()`, `cc.has_function()`. + called $TMPC. The replacement in Meson is the compiler object ``cc``, + which has methods such as ``cc.compiles()``, + ``cc.check_header()``, ``cc.has_function()``. -`compile_prog $CFLAGS $LDFLAGS` +``compile_prog $CFLAGS $LDFLAGS`` Attempt to compile a test program with the system C compiler using $CFLAGS and link it with the system linker using $LDFLAGS. The test program must have been previously written to a file called $TMPC. - The replacement in Meson is `cc.find_library()` and `cc.links()`. + The replacement in Meson is ``cc.find_library()`` and ``cc.links()``. -`has $COMMAND` +``has $COMMAND`` Determine if $COMMAND exists in the current environment, either as a shell builtin, or executable binary, returning 0 on success. The - replacement in Meson is `find_program()`. + replacement in Meson is ``find_program()``. -`check_define $NAME` +``check_define $NAME`` Determine if the macro $NAME is defined by the system C compiler -`check_include $NAME` +``check_include $NAME`` Determine if the include $NAME file is available to the system C - compiler. The replacement in Meson is `cc.has_header()`. + compiler. The replacement in Meson is ``cc.has_header()``. -`write_c_skeleton` +``write_c_skeleton`` Write a minimal C program main() function to the temporary file indicated by $TMPC -`feature_not_found $NAME $REMEDY` +``feature_not_found $NAME $REMEDY`` Print a message to stderr that the feature $NAME was not available on the system, suggesting the user try $REMEDY to address the problem. -`error_exit $MESSAGE $MORE...` +``error_exit $MESSAGE $MORE...`` Print $MESSAGE to stderr, followed by $MORE... and then exit from the configure script with non-zero status -`query_pkg_config $ARGS...` +``query_pkg_config $ARGS...`` Run pkg-config passing it $ARGS. If QEMU is doing a static build, then --static will be automatically added to $ARGS @@ -187,7 +187,7 @@ process for: 4) other data files, such as icons or desktop files -All executables are built by default, except for some `contrib/` +All executables are built by default, except for some ``contrib/`` binaries that are known to fail to build on some platforms (for example 32-bit or big-endian platforms). Tests are also built by default, though that might change in the future. @@ -195,14 +195,14 @@ though that might change in the future. The source code is highly modularized, split across many files to facilitate building of all of these components with as little duplicated compilation as possible. Using the Meson "sourceset" functionality, -`meson.build` files group the source files in rules that are +``meson.build`` files group the source files in rules that are enabled according to the available system libraries and to various configuration symbols. Sourcesets belong to one of four groups: Subsystem sourcesets: Various subsystems that are common to both tools and emulators have - their own sourceset, for example `block_ss` for the block device subsystem, - `chardev_ss` for the character device subsystem, etc. These sourcesets + their own sourceset, for example ``block_ss`` for the block device subsystem, + ``chardev_ss`` for the character device subsystem, etc. These sourcesets are then turned into static libraries as follows:: libchardev = static_library('chardev', chardev_ss.sources(), @@ -211,8 +211,8 @@ Subsystem sourcesets: chardev = declare_dependency(link_whole: libchardev) - As of Meson 0.55.1, the special `.fa` suffix should be used for everything - that is used with `link_whole`, to ensure that the link flags are placed + As of Meson 0.55.1, the special ``.fa`` suffix should be used for everything + that is used with ``link_whole``, to ensure that the link flags are placed correctly in the command line. Target-independent emulator sourcesets: @@ -221,16 +221,16 @@ Target-independent emulator sourcesets: This includes error handling infrastructure, standard data structures, platform portability wrapper functions, etc. - Target-independent code lives in the `common_ss`, `softmmu_ss` and - `user_ss` sourcesets. `common_ss` is linked into all emulators, - `softmmu_ss` only in system emulators, `user_ss` only in user-mode + Target-independent code lives in the ``common_ss``, ``softmmu_ss`` and + ``user_ss`` sourcesets. ``common_ss`` is linked into all emulators, + ``softmmu_ss`` only in system emulators, ``user_ss`` only in user-mode emulators. Target-independent sourcesets must exercise particular care when using - `if_false` rules. The `if_false` rule will be used correctly when linking + ``if_false`` rules. The ``if_false`` rule will be used correctly when linking emulator binaries; however, when *compiling* target-independent files - into .o files, Meson may need to pick *both* the `if_true` and - `if_false` sides to cater for targets that want either side. To + into .o files, Meson may need to pick *both* the ``if_true`` and + ``if_false`` sides to cater for targets that want either side. To achieve that, you can add a special rule using the ``CONFIG_ALL`` symbol:: @@ -245,14 +245,14 @@ Target-dependent emulator sourcesets: In the target-dependent set lives CPU emulation, some device emulation and much glue code. This sometimes also has to be compiled multiple times, once for each target being built. Target-dependent files are included - in the `specific_ss` sourceset. + in the ``specific_ss`` sourceset. - Each emulator also includes sources for files in the `hw/` and `target/` + Each emulator also includes sources for files in the ``hw/`` and ``target/`` subdirectories. The subdirectory used for each emulator comes from the target's definition of ``TARGET_BASE_ARCH`` or (if missing) - ``TARGET_ARCH``, as found in `default-configs/targets/*.mak`. + ``TARGET_ARCH``, as found in ``default-configs/targets/*.mak``. - Each subdirectory in `hw/` adds one sourceset to the `hw_arch` dictionary, + Each subdirectory in ``hw/`` adds one sourceset to the ``hw_arch`` dictionary, for example:: arm_ss = ss.source_set() @@ -262,8 +262,8 @@ Target-dependent emulator sourcesets: The sourceset is only used for system emulators. - Each subdirectory in `target/` instead should add one sourceset to each - of the `target_arch` and `target_softmmu_arch`, which are used respectively + Each subdirectory in ``target/`` instead should add one sourceset to each + of the ``target_arch`` and ``target_softmmu_arch``, which are used respectively for all emulators and for system emulators only. For example:: arm_ss = ss.source_set() @@ -273,11 +273,11 @@ Target-dependent emulator sourcesets: target_softmmu_arch += {'arm': arm_softmmu_ss} Module sourcesets: - There are two dictionaries for modules: `modules` is used for - target-independent modules and `target_modules` is used for - target-dependent modules. When modules are disabled the `module` - source sets are added to `softmmu_ss` and the `target_modules` - source sets are added to `specific_ss`. + There are two dictionaries for modules: ``modules`` is used for + target-independent modules and ``target_modules`` is used for + target-dependent modules. When modules are disabled the ``module`` + source sets are added to ``softmmu_ss`` and the ``target_modules`` + source sets are added to ``specific_ss``. Both dictionaries are nested. One dictionary is created per subdirectory, and these per-subdirectory dictionaries are added to @@ -290,15 +290,15 @@ Module sourcesets: modules += { 'hw-display': hw_display_modules } Utility sourcesets: - All binaries link with a static library `libqemuutil.a`. This library + All binaries link with a static library ``libqemuutil.a``. This library is built from several sourcesets; most of them however host generated - code, and the only two of general interest are `util_ss` and `stub_ss`. + code, and the only two of general interest are ``util_ss`` and ``stub_ss``. The separation between these two is purely for documentation purposes. - `util_ss` contains generic utility files. Even though this code is only + ``util_ss`` contains generic utility files. Even though this code is only linked in some binaries, sometimes it requires hooks only in some of these and depend on other functions that are not fully implemented by - all QEMU binaries. `stub_ss` links dummy stubs that will only be linked + all QEMU binaries. ``stub_ss`` links dummy stubs that will only be linked into the binary if the real implementation is not present. In a way, the stubs can be thought of as a portable implementation of the weak symbols concept. @@ -307,8 +307,8 @@ Utility sourcesets: The following files concur in the definition of which files are linked into each emulator: -`default-configs/devices/*.mak` - The files under `default-configs/devices/` control the boards and devices +``default-configs/devices/*.mak`` + The files under ``default-configs/devices/`` control the boards and devices that are built into each QEMU system emulation targets. They merely contain a list of config variable definitions such as:: @@ -316,18 +316,18 @@ into each emulator: CONFIG_XLNX_ZYNQMP_ARM=y CONFIG_XLNX_VERSAL=y -`*/Kconfig` - These files are processed together with `default-configs/devices/*.mak` and +``*/Kconfig`` + These files are processed together with ``default-configs/devices/*.mak`` and describe the dependencies between various features, subsystems and device models. They are described in :ref:`kconfig` -`default-configs/targets/*.mak` - These files mostly define symbols that appear in the `*-config-target.h` +``default-configs/targets/*.mak`` + These files mostly define symbols that appear in the ``*-config-target.h`` file for each emulator [#cfgtarget]_. However, the ``TARGET_ARCH`` - and ``TARGET_BASE_ARCH`` will also be used to select the `hw/` and - `target/` subdirectories that are compiled into each target. + and ``TARGET_BASE_ARCH`` will also be used to select the ``hw/`` and + ``target/`` subdirectories that are compiled into each target. -.. [#cfgtarget] This header is included by `qemu/osdep.h` when +.. [#cfgtarget] This header is included by ``qemu/osdep.h`` when compiling files from the target-specific sourcesets. These files rarely need changing unless you are adding a completely @@ -339,19 +339,19 @@ Support scripts --------------- Meson has a special convention for invoking Python scripts: if their -first line is `#! /usr/bin/env python3` and the file is *not* executable, +first line is ``#! /usr/bin/env python3`` and the file is *not* executable, find_program() arranges to invoke the script under the same Python interpreter that was used to invoke Meson. This is the most common and preferred way to invoke support scripts from Meson build files, because it automatically uses the value of configure's --python= option. -In case the script is not written in Python, use a `#! /usr/bin/env ...` +In case the script is not written in Python, use a ``#! /usr/bin/env ...`` line and make the script executable. Scripts written in Python, where it is desirable to make the script executable (for example for test scripts that developers may want to invoke from the command line, such as tests/qapi-schema/test-qapi.py), -should be invoked through the `python` variable in meson.build. For +should be invoked through the ``python`` variable in meson.build. For example:: test('QAPI schema regression tests', python, @@ -375,10 +375,10 @@ rules and wraps them so that e.g. submodules are built before QEMU. The resulting build system is largely non-recursive in nature, in contrast to common practices seen with automake. -Tests are also ran by the Makefile with the traditional `make check` -phony target, while benchmarks are run with `make bench`. Meson test -suites such as `unit` can be ran with `make check-unit` too. It is also -possible to run tests defined in meson.build with `meson test`. +Tests are also ran by the Makefile with the traditional ``make check`` +phony target, while benchmarks are run with ``make bench``. Meson test +suites such as ``unit`` can be ran with ``make check-unit`` too. It is also +possible to run tests defined in meson.build with ``meson test``. Important files for the build system ==================================== @@ -390,28 +390,28 @@ The following key files are statically defined in the source tree, with the rules needed to build QEMU. Their behaviour is influenced by a number of dynamically created files listed later. -`Makefile` +``Makefile`` The main entry point used when invoking make to build all the components of QEMU. The default 'all' target will naturally result in the build of every component. Makefile takes care of recursively building submodules directly via a non-recursive set of rules. -`*/meson.build` +``*/meson.build`` The meson.build file in the root directory is the main entry point for the Meson build system, and it coordinates the configuration and build of all executables. Build rules for various subdirectories are included in other meson.build files spread throughout the QEMU source tree. -`tests/Makefile.include` +``tests/Makefile.include`` Rules for external test harnesses. These include the TCG tests, - `qemu-iotests` and the Avocado-based acceptance tests. + ``qemu-iotests`` and the Avocado-based acceptance tests. -`tests/docker/Makefile.include` +``tests/docker/Makefile.include`` Rules for Docker tests. Like tests/Makefile, this file is included directly by the top level Makefile, anything defined in this file will influence the entire build system. -`tests/vm/Makefile.include` +``tests/vm/Makefile.include`` Rules for VM-based tests. Like tests/Makefile, this file is included directly by the top level Makefile, anything defined in this file will influence the entire build system. @@ -427,11 +427,11 @@ Makefile. Built by configure: -`config-host.mak` +``config-host.mak`` When configure has determined the characteristics of the build host it will write a long list of variables to config-host.mak file. This provides the various install directories, compiler / linker flags and a - variety of `CONFIG_*` variables related to optionally enabled features. + variety of ``CONFIG_*`` variables related to optionally enabled features. This is imported by the top level Makefile and meson.build in order to tailor the build output. @@ -446,29 +446,29 @@ Built by configure: Built by Meson: -`${TARGET-NAME}-config-devices.mak` +``${TARGET-NAME}-config-devices.mak`` TARGET-NAME is again the name of a system or userspace emulator. The config-devices.mak file is automatically generated by make using the scripts/make_device_config.sh program, feeding it the default-configs/$TARGET-NAME file as input. -`config-host.h`, `$TARGET-NAME/config-target.h`, `$TARGET-NAME/config-devices.h` +``config-host.h``, ``$TARGET-NAME/config-target.h``, ``$TARGET-NAME/config-devices.h`` These files are used by source code to determine what features are enabled. They are generated from the contents of the corresponding - `*.h` files using the scripts/create_config program. This extracts + ``*.h`` files using the scripts/create_config program. This extracts relevant variables and formats them as C preprocessor macros. -`build.ninja` +``build.ninja`` The build rules. Built by Makefile: -`Makefile.ninja` +``Makefile.ninja`` A Makefile include that bridges to ninja for the actual build. The Makefile is mostly a list of targets that Meson included in build.ninja. -`Makefile.mtest` +``Makefile.mtest`` The Makefile definitions that let "make check" run tests defined in meson.build. The rules are produced from Meson's JSON description of tests (obtained with "meson introspect --tests") through the script @@ -478,9 +478,9 @@ Built by Makefile: Useful make targets ------------------- -`help` +``help`` Print a help message for the most common build targets. -`print-VAR` +``print-VAR`` Print the value of the variable VAR. Useful for debugging the build system. From d463f3c79ade6f678bded5f150341206750a37b7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Jul 2021 15:23:30 +0100 Subject: [PATCH 449/531] docs/devel/build-system.rst: Correct typo in example code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One of the example meson.build fragments incorrectly quotes some symbols as 'CONFIG_FOO`; the correct syntax here is 'CONFIG_FOO'. (This isn't a rST formatting mistake because the example is displayed literally; it's just the wrong kind of quote.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210726142338.31872-3-peter.maydell@linaro.org --- docs/devel/build-system.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/devel/build-system.rst b/docs/devel/build-system.rst index ee660a998d..3baec158f2 100644 --- a/docs/devel/build-system.rst +++ b/docs/devel/build-system.rst @@ -235,11 +235,11 @@ Target-independent emulator sourcesets: symbol:: # Some targets have CONFIG_ACPI, some don't, so this is not enough - softmmu_ss.add(when: 'CONFIG_ACPI`, if_true: files('acpi.c'), + softmmu_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi.c'), if_false: files('acpi-stub.c')) # This is required as well: - softmmu_ss.add(when: 'CONFIG_ALL`, if_true: files('acpi-stub.c')) + softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c')) Target-dependent emulator sourcesets: In the target-dependent set lives CPU emulation, some device emulation and From f0d7b970ac69bdf72fcf40a729c9e8605f4d1bc0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Jul 2021 15:23:31 +0100 Subject: [PATCH 450/531] docs/devel/ebpf_rss.rst: Format literals correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In rST markup, single backticks `like this` represent "interpreted text", which can be handled as a bunch of different things if tagged with a specific "role": https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#interpreted-text (the most common one for us is "reference to a URL, which gets hyperlinked"). The default "role" if none is specified is "title_reference", intended for references to book or article titles, and it renders into the HTML as ... (usually comes out as italics). To format a literal (generally rendered as fixed-width font), double-backticks are required. ebpf_rss.rst gets this wrong in a few places; correct them. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210726142338.31872-4-peter.maydell@linaro.org --- docs/devel/ebpf_rss.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/devel/ebpf_rss.rst b/docs/devel/ebpf_rss.rst index e00962577a..4a68682b31 100644 --- a/docs/devel/ebpf_rss.rst +++ b/docs/devel/ebpf_rss.rst @@ -72,7 +72,7 @@ eBPF RSS implementation eBPF RSS loading functionality located in ebpf/ebpf_rss.c and ebpf/ebpf_rss.h. -The `struct EBPFRSSContext` structure that holds 4 file descriptors: +The ``struct EBPFRSSContext`` structure that holds 4 file descriptors: - ctx - pointer of the libbpf context. - program_fd - file descriptor of the eBPF RSS program. @@ -80,20 +80,20 @@ The `struct EBPFRSSContext` structure that holds 4 file descriptors: - map_toeplitz_key - file descriptor of the 'Toeplitz key' map. One element of the 40byte key prepared for the hashing algorithm. - map_indirections_table - 128 elements of queue indexes. -`struct EBPFRSSConfig` fields: +``struct EBPFRSSConfig`` fields: -- redirect - "boolean" value, should the hash be calculated, on false - `default_queue` would be used as the final decision. +- redirect - "boolean" value, should the hash be calculated, on false - ``default_queue`` would be used as the final decision. - populate_hash - for now, not used. eBPF RSS doesn't support hash reporting. -- hash_types - binary mask of different hash types. See `VIRTIO_NET_RSS_HASH_TYPE_*` defines. If for packet hash should not be calculated - `default_queue` would be used. +- hash_types - binary mask of different hash types. See ``VIRTIO_NET_RSS_HASH_TYPE_*`` defines. If for packet hash should not be calculated - ``default_queue`` would be used. - indirections_len - length of the indirections table, maximum 128. - default_queue - the queue index that used for packet that shouldn't be hashed. For some packets, the hash can't be calculated(g.e ARP). Functions: -- `ebpf_rss_init()` - sets ctx to NULL, which indicates that EBPFRSSContext is not loaded. -- `ebpf_rss_load()` - creates 3 maps and loads eBPF program from the rss.bpf.skeleton.h. Returns 'true' on success. After that, program_fd can be used to set steering for TAP. -- `ebpf_rss_set_all()` - sets values for eBPF maps. `indirections_table` length is in EBPFRSSConfig. `toeplitz_key` is VIRTIO_NET_RSS_MAX_KEY_SIZE aka 40 bytes array. -- `ebpf_rss_unload()` - close all file descriptors and set ctx to NULL. +- ``ebpf_rss_init()`` - sets ctx to NULL, which indicates that EBPFRSSContext is not loaded. +- ``ebpf_rss_load()`` - creates 3 maps and loads eBPF program from the rss.bpf.skeleton.h. Returns 'true' on success. After that, program_fd can be used to set steering for TAP. +- ``ebpf_rss_set_all()`` - sets values for eBPF maps. ``indirections_table`` length is in EBPFRSSConfig. ``toeplitz_key`` is VIRTIO_NET_RSS_MAX_KEY_SIZE aka 40 bytes array. +- ``ebpf_rss_unload()`` - close all file descriptors and set ctx to NULL. Simplified eBPF RSS workflow: @@ -122,4 +122,4 @@ Simplified eBPF RSS workflow: NetClientState SetSteeringEBPF() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -For now, `set_steering_ebpf()` method supported by Linux TAP NetClientState. The method requires an eBPF program file descriptor as an argument. +For now, ``set_steering_ebpf()`` method supported by Linux TAP NetClientState. The method requires an eBPF program file descriptor as an argument. From 4df3a7bf8f895e356a3b1f4891489c1ffa5e1e46 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Jul 2021 15:23:32 +0100 Subject: [PATCH 451/531] docs/devel/migration.rst: Format literals correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In rST markup, single backticks `like this` represent "interpreted text", which can be handled as a bunch of different things if tagged with a specific "role": https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#interpreted-text (the most common one for us is "reference to a URL, which gets hyperlinked"). The default "role" if none is specified is "title_reference", intended for references to book or article titles, and it renders into the HTML as ... (usually comes out as italics). To format a literal (generally rendered as fixed-width font), double-backticks are required. Mostly migration.rst gets this right, but some places incorrectly use single backticks where double backticks were intended; correct them. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Acked-by: Dr. David Alan Gilbert Message-id: 20210726142338.31872-5-peter.maydell@linaro.org --- docs/devel/migration.rst | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst index 19c3d4f3ea..2401253482 100644 --- a/docs/devel/migration.rst +++ b/docs/devel/migration.rst @@ -53,7 +53,7 @@ savevm/loadvm functionality. Debugging ========= -The migration stream can be analyzed thanks to `scripts/analyze-migration.py`. +The migration stream can be analyzed thanks to ``scripts/analyze-migration.py``. Example usage: @@ -75,8 +75,8 @@ Common infrastructure ===================== The files, sockets or fd's that carry the migration stream are abstracted by -the ``QEMUFile`` type (see `migration/qemu-file.h`). In most cases this -is connected to a subtype of ``QIOChannel`` (see `io/`). +the ``QEMUFile`` type (see ``migration/qemu-file.h``). In most cases this +is connected to a subtype of ``QIOChannel`` (see ``io/``). Saving the state of one device @@ -166,14 +166,14 @@ An example (from hw/input/pckbd.c) }; We are declaring the state with name "pckbd". -The `version_id` is 3, and the fields are 4 uint8_t in a KBDState structure. +The ``version_id`` is 3, and the fields are 4 uint8_t in a KBDState structure. We registered this with: .. code:: c vmstate_register(NULL, 0, &vmstate_kbd, s); -For devices that are `qdev` based, we can register the device in the class +For devices that are ``qdev`` based, we can register the device in the class init function: .. code:: c @@ -210,9 +210,9 @@ another to load the state back. SaveVMHandlers *ops, void *opaque); -Two functions in the ``ops`` structure are the `save_state` -and `load_state` functions. Notice that `load_state` receives a version_id -parameter to know what state format is receiving. `save_state` doesn't +Two functions in the ``ops`` structure are the ``save_state`` +and ``load_state`` functions. Notice that ``load_state`` receives a version_id +parameter to know what state format is receiving. ``save_state`` doesn't have a version_id parameter because it always uses the latest version. Note that because the VMState macros still save the data in a raw @@ -385,18 +385,18 @@ migration of a device, and using them breaks backward-migration compatibility; in general most changes can be made by adding Subsections (see above) or _TEST macros (see above) which won't break compatibility. -Each version is associated with a series of fields saved. The `save_state` always saves -the state as the newer version. But `load_state` sometimes is able to +Each version is associated with a series of fields saved. The ``save_state`` always saves +the state as the newer version. But ``load_state`` sometimes is able to load state from an older version. You can see that there are several version fields: -- `version_id`: the maximum version_id supported by VMState for that device. -- `minimum_version_id`: the minimum version_id that VMState is able to understand +- ``version_id``: the maximum version_id supported by VMState for that device. +- ``minimum_version_id``: the minimum version_id that VMState is able to understand for that device. -- `minimum_version_id_old`: For devices that were not able to port to vmstate, we can +- ``minimum_version_id_old``: For devices that were not able to port to vmstate, we can assign a function that knows how to read this old state. This field is - ignored if there is no `load_state_old` handler. + ignored if there is no ``load_state_old`` handler. VMState is able to read versions from minimum_version_id to version_id. And the function ``load_state_old()`` (if present) is able to @@ -454,7 +454,7 @@ data and then transferred to the main structure. If you use memory API functions that update memory layout outside initialization (i.e., in response to a guest action), this is a strong -indication that you need to call these functions in a `post_load` callback. +indication that you need to call these functions in a ``post_load`` callback. Examples of such memory API functions are: - memory_region_add_subregion() @@ -823,12 +823,12 @@ Postcopy migration with shared memory needs explicit support from the other processes that share memory and from QEMU. There are restrictions on the type of memory that userfault can support shared. -The Linux kernel userfault support works on `/dev/shm` memory and on `hugetlbfs` -(although the kernel doesn't provide an equivalent to `madvise(MADV_DONTNEED)` +The Linux kernel userfault support works on ``/dev/shm`` memory and on ``hugetlbfs`` +(although the kernel doesn't provide an equivalent to ``madvise(MADV_DONTNEED)`` for hugetlbfs which may be a problem in some configurations). The vhost-user code in QEMU supports clients that have Postcopy support, -and the `vhost-user-bridge` (in `tests/`) and the DPDK package have changes +and the ``vhost-user-bridge`` (in ``tests/``) and the DPDK package have changes to support postcopy. The client needs to open a userfaultfd and register the areas From 1e235edab8df6d1cb6da5c726c2b8e2a2782e37b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Jul 2021 15:23:33 +0100 Subject: [PATCH 452/531] docs/devel: Format literals correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In rST markup, single backticks `like this` represent "interpreted text", which can be handled as a bunch of different things if tagged with a specific "role": https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#interpreted-text (the most common one for us is "reference to a URL, which gets hyperlinked"). The default "role" if none is specified is "title_reference", intended for references to book or article titles, and it renders into the HTML as ... (usually comes out as italics). Fix various places in the devel section of the manual which were using single backticks when double backticks (for literal text) were intended. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210726142338.31872-6-peter.maydell@linaro.org --- docs/devel/qgraph.rst | 8 ++++---- docs/devel/tcg-plugins.rst | 14 +++++++------- docs/devel/testing.rst | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/devel/qgraph.rst b/docs/devel/qgraph.rst index 318534d4b0..39e293687e 100644 --- a/docs/devel/qgraph.rst +++ b/docs/devel/qgraph.rst @@ -66,11 +66,11 @@ Notes for the nodes: Edges ^^^^^^ -An edge relation between two nodes (drivers or machines) `X` and `Y` can be: +An edge relation between two nodes (drivers or machines) ``X`` and ``Y`` can be: -- ``X CONSUMES Y``: `Y` can be plugged into `X` -- ``X PRODUCES Y``: `X` provides the interface `Y` -- ``X CONTAINS Y``: `Y` is part of `X` component +- ``X CONSUMES Y``: ``Y`` can be plugged into ``X`` +- ``X PRODUCES Y``: ``X`` provides the interface ``Y`` +- ``X CONTAINS Y``: ``Y`` is part of ``X`` component Execution steps ^^^^^^^^^^^^^^^ diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst index 7e54f12837..047bf4ada7 100644 --- a/docs/devel/tcg-plugins.rst +++ b/docs/devel/tcg-plugins.rst @@ -34,11 +34,11 @@ version they were built against. This can be done simply by:: QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; The core code will refuse to load a plugin that doesn't export a -`qemu_plugin_version` symbol or if plugin version is outside of QEMU's +``qemu_plugin_version`` symbol or if plugin version is outside of QEMU's supported range of API versions. -Additionally the `qemu_info_t` structure which is passed to the -`qemu_plugin_install` method of a plugin will detail the minimum and +Additionally the ``qemu_info_t`` structure which is passed to the +``qemu_plugin_install`` method of a plugin will detail the minimum and current API versions supported by QEMU. The API version will be incremented if new APIs are added. The minimum API version will be incremented if existing APIs are changed or removed. @@ -146,12 +146,12 @@ Example Plugins There are a number of plugins included with QEMU and you are encouraged to contribute your own plugins plugins upstream. There is a -`contrib/plugins` directory where they can go. +``contrib/plugins`` directory where they can go. - tests/plugins These are some basic plugins that are used to test and exercise the -API during the `make check-tcg` target. +API during the ``make check-tcg`` target. - contrib/plugins/hotblocks.c @@ -163,7 +163,7 @@ with linux-user execution as system emulation tends to generate re-translations as blocks from different programs get swapped in and out of system memory. -If your program is single-threaded you can use the `inline` option for +If your program is single-threaded you can use the ``inline`` option for slightly faster (but not thread safe) counters. Example:: @@ -251,7 +251,7 @@ which will lead to a sorted list after the class breakdown:: ... To find the argument shorthand for the class you need to examine the -source code of the plugin at the moment, specifically the `*opt` +source code of the plugin at the moment, specifically the ``*opt`` argument in the InsnClassExecCount tables. - contrib/plugins/lockstep.c diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst index 8f572255d3..8a9cda33a5 100644 --- a/docs/devel/testing.rst +++ b/docs/devel/testing.rst @@ -775,7 +775,7 @@ The base test class has also support for tests with more than one QEMUMachine. The way to get machines is through the ``self.get_vm()`` method which will return a QEMUMachine instance. The ``self.get_vm()`` method accepts arguments that will be passed to the QEMUMachine creation -and also an optional `name` attribute so you can identify a specific +and also an optional ``name`` attribute so you can identify a specific machine and get it more than once through the tests methods. A simple and hypothetical example follows: @@ -1062,7 +1062,7 @@ Here is a list of the most used variables: AVOCADO_ALLOW_LARGE_STORAGE ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tests which are going to fetch or produce assets considered *large* are not -going to run unless that `AVOCADO_ALLOW_LARGE_STORAGE=1` is exported on +going to run unless that ``AVOCADO_ALLOW_LARGE_STORAGE=1`` is exported on the environment. The definition of *large* is a bit arbitrary here, but it usually means an @@ -1076,7 +1076,7 @@ skipped by default. The definition of *not safe* is also arbitrary but usually it means a blob which either its source or build process aren't public available. -You should export `AVOCADO_ALLOW_UNTRUSTED_CODE=1` on the environment in +You should export ``AVOCADO_ALLOW_UNTRUSTED_CODE=1`` on the environment in order to allow tests which make use of those kind of assets. AVOCADO_TIMEOUT_EXPECTED @@ -1090,7 +1090,7 @@ property defined in the test class, for further details:: Even though the timeout can be set by the test developer, there are some tests that may not have a well-defined limit of time to finish under certain conditions. For example, tests that take longer to execute when QEMU is -compiled with debug flags. Therefore, the `AVOCADO_TIMEOUT_EXPECTED` variable +compiled with debug flags. Therefore, the ``AVOCADO_TIMEOUT_EXPECTED`` variable has been used to determine whether those tests should run or not. GITLAB_CI From 9c372ecfec5bd00f7ef5b6b2e9db9c2c859b408b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Jul 2021 15:23:34 +0100 Subject: [PATCH 453/531] docs/system/s390x/protvirt.rst: Format literals correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In rST markup, single backticks `like this` represent "interpreted text", which can be handled as a bunch of different things if tagged with a specific "role": https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#interpreted-text (the most common one for us is "reference to a URL, which gets hyperlinked"). The default "role" if none is specified is "title_reference", intended for references to book or article titles, and it renders into the HTML as ... (usually comes out as italics). To format a literal (generally rendered as fixed-width font), double-backticks are required. protvirt.rst consistently uses single backticks when double backticks are required; correct it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Acked-by: Cornelia Huck Message-id: 20210726142338.31872-7-peter.maydell@linaro.org --- docs/system/s390x/protvirt.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/system/s390x/protvirt.rst b/docs/system/s390x/protvirt.rst index 0f481043d9..aee63ed7ec 100644 --- a/docs/system/s390x/protvirt.rst +++ b/docs/system/s390x/protvirt.rst @@ -14,11 +14,11 @@ Prerequisites To run PVMs, a machine with the Protected Virtualization feature, as indicated by the Ultravisor Call facility (stfle bit 158), is required. The Ultravisor needs to be initialized at boot by setting -`prot_virt=1` on the host's kernel command line. +``prot_virt=1`` on the host's kernel command line. Running PVMs requires using the KVM hypervisor. -If those requirements are met, the capability `KVM_CAP_S390_PROTECTED` +If those requirements are met, the capability ``KVM_CAP_S390_PROTECTED`` will indicate that KVM can support PVMs on that LPAR. @@ -26,15 +26,15 @@ Running a Protected Virtual Machine ----------------------------------- To run a PVM you will need to select a CPU model which includes the -`Unpack facility` (stfle bit 161 represented by the feature -`unpack`/`S390_FEAT_UNPACK`), and add these options to the command line:: +``Unpack facility`` (stfle bit 161 represented by the feature +``unpack``/``S390_FEAT_UNPACK``), and add these options to the command line:: -object s390-pv-guest,id=pv0 \ -machine confidential-guest-support=pv0 Adding these options will: -* Ensure the `unpack` facility is available +* Ensure the ``unpack`` facility is available * Enable the IOMMU by default for all I/O devices * Initialize the PV mechanism @@ -63,5 +63,5 @@ from the disk boot. This memory layout includes the encrypted components (kernel, initrd, cmdline), the stage3a loader and metadata. In case this boot method is used, the command line options -initrd and -cmdline are ineffective. The preparation of a PVM -image is done via the `genprotimg` tool from the s390-tools +image is done via the ``genprotimg`` tool from the s390-tools collection. From 8a48a7c2e004ac55c9397b3dd6cd3475a00b0f58 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Jul 2021 15:23:35 +0100 Subject: [PATCH 454/531] docs/system/arm/cpu-features.rst: Format literals correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In rST markup, single backticks `like this` represent "interpreted text", which can be handled as a bunch of different things if tagged with a specific "role": https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#interpreted-text (the most common one for us is "reference to a URL, which gets hyperlinked"). The default "role" if none is specified is "title_reference", intended for references to book or article titles, and it renders into the HTML as ... (usually comes out as italics). To format a literal (generally rendered as fixed-width font), double-backticks are required. cpu-features.rst consistently uses single backticks when double backticks are required; correct it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210726142338.31872-8-peter.maydell@linaro.org --- docs/system/arm/cpu-features.rst | 116 +++++++++++++++---------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst index 11dce5c603..584eb17097 100644 --- a/docs/system/arm/cpu-features.rst +++ b/docs/system/arm/cpu-features.rst @@ -10,22 +10,22 @@ is the Performance Monitoring Unit (PMU). CPU types such as the Cortex-A15 and the Cortex-A57, which respectively implement Arm architecture reference manuals ARMv7-A and ARMv8-A, may both optionally implement PMUs. For example, if a user wants to use a Cortex-A15 without -a PMU, then the `-cpu` parameter should contain `pmu=off` on the QEMU -command line, i.e. `-cpu cortex-a15,pmu=off`. +a PMU, then the ``-cpu`` parameter should contain ``pmu=off`` on the QEMU +command line, i.e. ``-cpu cortex-a15,pmu=off``. As not all CPU types support all optional CPU features, then whether or not a CPU property exists depends on the CPU type. For example, CPUs that implement the ARMv8-A architecture reference manual may optionally support the AArch32 CPU feature, which may be enabled by disabling the -`aarch64` CPU property. A CPU type such as the Cortex-A15, which does -not implement ARMv8-A, will not have the `aarch64` CPU property. +``aarch64`` CPU property. A CPU type such as the Cortex-A15, which does +not implement ARMv8-A, will not have the ``aarch64`` CPU property. QEMU's support may be limited for some CPU features, only partially supporting the feature or only supporting the feature under certain -configurations. For example, the `aarch64` CPU feature, which, when +configurations. For example, the ``aarch64`` CPU feature, which, when disabled, enables the optional AArch32 CPU feature, is only supported when using the KVM accelerator and when running on a host CPU type that -supports the feature. While `aarch64` currently only works with KVM, +supports the feature. While ``aarch64`` currently only works with KVM, it could work with TCG. CPU features that are specific to KVM are prefixed with "kvm-" and are described in "KVM VCPU Features". @@ -33,12 +33,12 @@ CPU Feature Probing =================== Determining which CPU features are available and functional for a given -CPU type is possible with the `query-cpu-model-expansion` QMP command. -Below are some examples where `scripts/qmp/qmp-shell` (see the top comment +CPU type is possible with the ``query-cpu-model-expansion`` QMP command. +Below are some examples where ``scripts/qmp/qmp-shell`` (see the top comment block in the script for usage) is used to issue the QMP commands. -1. Determine which CPU features are available for the `max` CPU type - (Note, we started QEMU with qemu-system-aarch64, so `max` is +1. Determine which CPU features are available for the ``max`` CPU type + (Note, we started QEMU with qemu-system-aarch64, so ``max`` is implementing the ARMv8-A reference manual in this case):: (QEMU) query-cpu-model-expansion type=full model={"name":"max"} @@ -51,9 +51,9 @@ block in the script for usage) is used to issue the QMP commands. "sve896": true, "sve1280": true, "sve2048": true }}}} -We see that the `max` CPU type has the `pmu`, `aarch64`, `sve`, and many -`sve` CPU features. We also see that all the CPU features are -enabled, as they are all `true`. (The `sve` CPU features are all +We see that the ``max`` CPU type has the ``pmu``, ``aarch64``, ``sve``, and many +``sve`` CPU features. We also see that all the CPU features are +enabled, as they are all ``true``. (The ``sve`` CPU features are all optional SVE vector lengths (see "SVE CPU Properties"). While with TCG all SVE vector lengths can be supported, when KVM is in use it's more likely that only a few lengths will be supported, if SVE is supported at @@ -71,9 +71,9 @@ all.) "sve896": true, "sve1280": true, "sve2048": true }}}} -We see it worked, as `pmu` is now `false`. +We see it worked, as ``pmu`` is now ``false``. -(3) Let's try to disable `aarch64`, which enables the AArch32 CPU feature:: +(3) Let's try to disable ``aarch64``, which enables the AArch32 CPU feature:: (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"aarch64":false}} {"error": { @@ -84,7 +84,7 @@ We see it worked, as `pmu` is now `false`. It looks like this feature is limited to a configuration we do not currently have. -(4) Let's disable `sve` and see what happens to all the optional SVE +(4) Let's disable ``sve`` and see what happens to all the optional SVE vector lengths:: (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"sve":false}} @@ -97,14 +97,14 @@ currently have. "sve896": false, "sve1280": false, "sve2048": false }}}} -As expected they are now all `false`. +As expected they are now all ``false``. (5) Let's try probing CPU features for the Cortex-A15 CPU type:: (QEMU) query-cpu-model-expansion type=full model={"name":"cortex-a15"} {"return": {"model": {"name": "cortex-a15", "props": {"pmu": true}}}} -Only the `pmu` CPU feature is available. +Only the ``pmu`` CPU feature is available. A note about CPU feature dependencies ------------------------------------- @@ -123,29 +123,29 @@ A note about CPU models and KVM ------------------------------- Named CPU models generally do not work with KVM. There are a few cases -that do work, e.g. using the named CPU model `cortex-a57` with KVM on a -seattle host, but mostly if KVM is enabled the `host` CPU type must be +that do work, e.g. using the named CPU model ``cortex-a57`` with KVM on a +seattle host, but mostly if KVM is enabled the ``host`` CPU type must be used. This means the guest is provided all the same CPU features as the -host CPU type has. And, for this reason, the `host` CPU type should +host CPU type has. And, for this reason, the ``host`` CPU type should enable all CPU features that the host has by default. Indeed it's even a bit strange to allow disabling CPU features that the host has when using -the `host` CPU type, but in the absence of CPU models it's the best we can +the ``host`` CPU type, but in the absence of CPU models it's the best we can do if we want to launch guests without all the host's CPU features enabled. -Enabling KVM also affects the `query-cpu-model-expansion` QMP command. The +Enabling KVM also affects the ``query-cpu-model-expansion`` QMP command. The affect is not only limited to specific features, as pointed out in example (3) of "CPU Feature Probing", but also to which CPU types may be expanded. -When KVM is enabled, only the `max`, `host`, and current CPU type may be +When KVM is enabled, only the ``max``, ``host``, and current CPU type may be expanded. This restriction is necessary as it's not possible to know all CPU types that may work with KVM, but it does impose a small risk of users experiencing unexpected errors. For example on a seattle, as mentioned -above, the `cortex-a57` CPU type is also valid when KVM is enabled. -Therefore a user could use the `host` CPU type for the current type, but -then attempt to query `cortex-a57`, however that query will fail with our +above, the ``cortex-a57`` CPU type is also valid when KVM is enabled. +Therefore a user could use the ``host`` CPU type for the current type, but +then attempt to query ``cortex-a57``, however that query will fail with our restrictions. This shouldn't be an issue though as management layers and -users have been preferring the `host` CPU type for use with KVM for quite +users have been preferring the ``host`` CPU type for use with KVM for quite some time. Additionally, if the KVM-enabled QEMU instance running on a -seattle host is using the `cortex-a57` CPU type, then querying `cortex-a57` +seattle host is using the ``cortex-a57`` CPU type, then querying ``cortex-a57`` will work. Using CPU Features @@ -158,12 +158,12 @@ QEMU command line with that CPU type:: $ qemu-system-aarch64 -M virt -cpu max,pmu=off,sve=on,sve128=on,sve256=on The example above disables the PMU and enables the first two SVE vector -lengths for the `max` CPU type. Note, the `sve=on` isn't actually -necessary, because, as we observed above with our probe of the `max` CPU -type, `sve` is already on by default. Also, based on our probe of +lengths for the ``max`` CPU type. Note, the ``sve=on`` isn't actually +necessary, because, as we observed above with our probe of the ``max`` CPU +type, ``sve`` is already on by default. Also, based on our probe of defaults, it would seem we need to disable many SVE vector lengths, rather than only enabling the two we want. This isn't the case, because, as -disabling many SVE vector lengths would be quite verbose, the `sve` CPU +disabling many SVE vector lengths would be quite verbose, the ``sve`` CPU properties have special semantics (see "SVE CPU Property Parsing Semantics"). @@ -217,11 +217,11 @@ TCG VCPU Features TCG VCPU features are CPU features that are specific to TCG. Below is the list of TCG VCPU features and their descriptions. - pauth Enable or disable `FEAT_Pauth`, pointer + pauth Enable or disable ``FEAT_Pauth``, pointer authentication. By default, the feature is - enabled with `-cpu max`. + enabled with ``-cpu max``. - pauth-impdef When `FEAT_Pauth` is enabled, either the + pauth-impdef When ``FEAT_Pauth`` is enabled, either the *impdef* (Implementation Defined) algorithm is enabled or the *architected* QARMA algorithm is enabled. By default the impdef algorithm @@ -235,49 +235,49 @@ Below is the list of TCG VCPU features and their descriptions. SVE CPU Properties ================== -There are two types of SVE CPU properties: `sve` and `sve`. The first -is used to enable or disable the entire SVE feature, just as the `pmu` +There are two types of SVE CPU properties: ``sve`` and ``sve``. The first +is used to enable or disable the entire SVE feature, just as the ``pmu`` CPU property completely enables or disables the PMU. The second type -is used to enable or disable specific vector lengths, where `N` is the -number of bits of the length. The `sve` CPU properties have special +is used to enable or disable specific vector lengths, where ``N`` is the +number of bits of the length. The ``sve`` CPU properties have special dependencies and constraints, see "SVE CPU Property Dependencies and Constraints" below. Additionally, as we want all supported vector lengths to be enabled by default, then, in order to avoid overly verbose command -lines (command lines full of `sve=off`, for all `N` not wanted), we +lines (command lines full of ``sve=off``, for all ``N`` not wanted), we provide the parsing semantics listed in "SVE CPU Property Parsing Semantics". SVE CPU Property Dependencies and Constraints --------------------------------------------- - 1) At least one vector length must be enabled when `sve` is enabled. + 1) At least one vector length must be enabled when ``sve`` is enabled. - 2) If a vector length `N` is enabled, then, when KVM is enabled, all + 2) If a vector length ``N`` is enabled, then, when KVM is enabled, all smaller, host supported vector lengths must also be enabled. If KVM is not enabled, then only all the smaller, power-of-two vector lengths must be enabled. E.g. with KVM if the host supports all - vector lengths up to 512-bits (128, 256, 384, 512), then if `sve512` + vector lengths up to 512-bits (128, 256, 384, 512), then if ``sve512`` is enabled, the 128-bit vector length, 256-bit vector length, and 384-bit vector length must also be enabled. Without KVM, the 384-bit vector length would not be required. 3) If KVM is enabled then only vector lengths that the host CPU type support may be enabled. If SVE is not supported by the host, then - no `sve*` properties may be enabled. + no ``sve*`` properties may be enabled. SVE CPU Property Parsing Semantics ---------------------------------- - 1) If SVE is disabled (`sve=off`), then which SVE vector lengths + 1) If SVE is disabled (``sve=off``), then which SVE vector lengths are enabled or disabled is irrelevant to the guest, as the entire SVE feature is disabled and that disables all vector lengths for - the guest. However QEMU will still track any `sve` CPU - properties provided by the user. If later an `sve=on` is provided, - then the guest will get only the enabled lengths. If no `sve=on` + the guest. However QEMU will still track any ``sve`` CPU + properties provided by the user. If later an ``sve=on`` is provided, + then the guest will get only the enabled lengths. If no ``sve=on`` is provided and there are explicitly enabled vector lengths, then an error is generated. - 2) If SVE is enabled (`sve=on`), but no `sve` CPU properties are + 2) If SVE is enabled (``sve=on``), but no ``sve`` CPU properties are provided, then all supported vector lengths are enabled, which when KVM is not in use means including the non-power-of-two lengths, and, when KVM is in use, it means all vector lengths supported by the host @@ -293,7 +293,7 @@ SVE CPU Property Parsing Semantics constraint (2) of "SVE CPU Property Dependencies and Constraints"). 5) When KVM is enabled, if the host does not support SVE, then an error - is generated when attempting to enable any `sve*` properties (see + is generated when attempting to enable any ``sve*`` properties (see constraint (3) of "SVE CPU Property Dependencies and Constraints"). 6) When KVM is enabled, if the host does support SVE, then an error is @@ -301,8 +301,8 @@ SVE CPU Property Parsing Semantics by the host (see constraint (3) of "SVE CPU Property Dependencies and Constraints"). - 7) If one or more `sve` CPU properties are set `off`, but no `sve`, - CPU properties are set `on`, then the specified vector lengths are + 7) If one or more ``sve`` CPU properties are set ``off``, but no ``sve``, + CPU properties are set ``on``, then the specified vector lengths are disabled but the default for any unspecified lengths remains enabled. When KVM is not enabled, disabling a power-of-two vector length also disables all vector lengths larger than the power-of-two length. @@ -310,15 +310,15 @@ SVE CPU Property Parsing Semantics disables all larger vector lengths (see constraint (2) of "SVE CPU Property Dependencies and Constraints"). - 8) If one or more `sve` CPU properties are set to `on`, then they + 8) If one or more ``sve`` CPU properties are set to ``on``, then they are enabled and all unspecified lengths default to disabled, except for the required lengths per constraint (2) of "SVE CPU Property Dependencies and Constraints", which will even be auto-enabled if they were not explicitly enabled. - 9) If SVE was disabled (`sve=off`), allowing all vector lengths to be + 9) If SVE was disabled (``sve=off``), allowing all vector lengths to be explicitly disabled (i.e. avoiding the error specified in (3) of - "SVE CPU Property Parsing Semantics"), then if later an `sve=on` is + "SVE CPU Property Parsing Semantics"), then if later an ``sve=on`` is provided an error will be generated. To avoid this error, one must enable at least one vector length prior to enabling SVE. @@ -329,12 +329,12 @@ SVE CPU Property Examples $ qemu-system-aarch64 -M virt -cpu max,sve=off - 2) Implicitly enable all vector lengths for the `max` CPU type:: + 2) Implicitly enable all vector lengths for the ``max`` CPU type:: $ qemu-system-aarch64 -M virt -cpu max 3) When KVM is enabled, implicitly enable all host CPU supported vector - lengths with the `host` CPU type:: + lengths with the ``host`` CPU type:: $ qemu-system-aarch64 -M virt,accel=kvm -cpu host From 6df743dc31a6a0b618042da2b550993c6e9767d1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Jul 2021 15:23:36 +0100 Subject: [PATCH 455/531] docs: Format literals correctly In rST markup, single backticks `like this` represent "interpreted text", which can be handled as a bunch of different things if tagged with a specific "role": https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#interpreted-text (the most common one for us is "reference to a URL, which gets hyperlinked"). The default "role" if none is specified is "title_reference", intended for references to book or article titles, and it renders into the HTML as ... (usually comes out as italics). This commit fixes various places in the manual which were using single backticks when double backticks (for literal text) were intended, and covers those files where only one or two instances of these errors were made. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- docs/about/index.rst | 2 +- docs/interop/live-block-operations.rst | 2 +- docs/system/arm/nuvoton.rst | 2 +- docs/system/arm/sbsa.rst | 4 ++-- docs/system/arm/virt.rst | 2 +- docs/system/cpu-hotplug.rst | 2 +- docs/system/guest-loader.rst | 6 +++--- docs/system/ppc/powernv.rst | 8 ++++---- docs/system/riscv/microchip-icicle-kit.rst | 2 +- docs/system/riscv/virt.rst | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/about/index.rst b/docs/about/index.rst index 689a9861dc..beb762aa0a 100644 --- a/docs/about/index.rst +++ b/docs/about/index.rst @@ -15,7 +15,7 @@ where QEMU can launch processes compiled for one CPU on another CPU. In this mode the CPU is always emulated. QEMU also provides a number of standalone commandline utilities, -such as the `qemu-img` disk image utility that allows you to create, +such as the ``qemu-img`` disk image utility that allows you to create, convert and modify disk images. .. toctree:: diff --git a/docs/interop/live-block-operations.rst b/docs/interop/live-block-operations.rst index 477d085f54..9e3635b233 100644 --- a/docs/interop/live-block-operations.rst +++ b/docs/interop/live-block-operations.rst @@ -781,7 +781,7 @@ the content of image [D]. } (6) [On *destination* QEMU] Finally, resume the guest vCPUs by issuing the - QMP command `cont`:: + QMP command ``cont``:: (QEMU) cont { diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst index 3cd2b2b18d..69f57c2886 100644 --- a/docs/system/arm/nuvoton.rst +++ b/docs/system/arm/nuvoton.rst @@ -79,7 +79,7 @@ Boot options ------------ The Nuvoton machines can boot from an OpenBMC firmware image, or directly into -a kernel using the ``-kernel`` option. OpenBMC images for `quanta-gsj` and +a kernel using the ``-kernel`` option. OpenBMC images for ``quanta-gsj`` and possibly others can be downloaded from the OpenPOWER jenkins : https://openpower.xyz/ diff --git a/docs/system/arm/sbsa.rst b/docs/system/arm/sbsa.rst index 27b0999aac..b499d7e927 100644 --- a/docs/system/arm/sbsa.rst +++ b/docs/system/arm/sbsa.rst @@ -1,8 +1,8 @@ Arm Server Base System Architecture Reference board (``sbsa-ref``) ================================================================== -While the `virt` board is a generic board platform that doesn't match -any real hardware the `sbsa-ref` board intends to look like real +While the ``virt`` board is a generic board platform that doesn't match +any real hardware the ``sbsa-ref`` board intends to look like real hardware. The `Server Base System Architecture `_ defines a minimum base line of hardware support and importantly how the firmware diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst index 27652adfae..59acf0eeaf 100644 --- a/docs/system/arm/virt.rst +++ b/docs/system/arm/virt.rst @@ -1,7 +1,7 @@ 'virt' generic virtual platform (``virt``) ========================================== -The `virt` board is a platform which does not correspond to any +The ``virt`` board is a platform which does not correspond to any real hardware; it is designed for use in virtual machines. It is the recommended board type if you simply want to run a guest such as Linux and do not care about reproducing the diff --git a/docs/system/cpu-hotplug.rst b/docs/system/cpu-hotplug.rst index bd0663616e..015ce2b6ec 100644 --- a/docs/system/cpu-hotplug.rst +++ b/docs/system/cpu-hotplug.rst @@ -78,7 +78,7 @@ vCPU hotplug } (QEMU) -(5) Optionally, run QMP `query-cpus-fast` for some details about the +(5) Optionally, run QMP ``query-cpus-fast`` for some details about the vCPUs:: (QEMU) query-cpus-fast diff --git a/docs/system/guest-loader.rst b/docs/system/guest-loader.rst index 37d03cbd89..4320d1183f 100644 --- a/docs/system/guest-loader.rst +++ b/docs/system/guest-loader.rst @@ -4,7 +4,7 @@ Guest Loader ------------ -The guest loader is similar to the `generic-loader` although it is +The guest loader is similar to the ``generic-loader`` although it is aimed at a particular use case of loading hypervisor guests. This is useful for debugging hypervisors without having to jump through the hoops of firmware and boot-loaders. @@ -27,12 +27,12 @@ multi-boot capability. A typical example would look like: In the above example the Xen hypervisor is loaded by the -kernel parameter and passed it's boot arguments via -append. The Dom0 guest is loaded into the areas of memory. Each blob will get -`/chosen/module@` entry in the FDT to indicate it's location and +``/chosen/module@`` entry in the FDT to indicate it's location and size. Additional information can be passed with by using additional arguments. Currently the only supported machines which use FDT data to boot are -the ARM and RiscV `virt` machines. +the ARM and RiscV ``virt`` machines. Arguments ^^^^^^^^^ diff --git a/docs/system/ppc/powernv.rst b/docs/system/ppc/powernv.rst index 43c58bc32e..4c4cdea527 100644 --- a/docs/system/ppc/powernv.rst +++ b/docs/system/ppc/powernv.rst @@ -48,15 +48,15 @@ Firmware -------- The OPAL firmware (OpenPower Abstraction Layer) for OpenPower systems -includes the runtime services `skiboot` and the bootloader kernel and -initramfs `skiroot`. Source code can be found on GitHub: +includes the runtime services ``skiboot`` and the bootloader kernel and +initramfs ``skiroot``. Source code can be found on GitHub: https://github.com/open-power. -Prebuilt images of `skiboot` and `skiboot` are made available on the `OpenPOWER `__ site. To boot a POWER9 machine, use the `witherspoon `__ images. For POWER8, use +Prebuilt images of ``skiboot`` and ``skiboot`` are made available on the `OpenPOWER `__ site. To boot a POWER9 machine, use the `witherspoon `__ images. For POWER8, use the `palmetto `__ images. -QEMU includes a prebuilt image of `skiboot` which is updated when a +QEMU includes a prebuilt image of ``skiboot`` which is updated when a more recent version is required by the models. Boot options diff --git a/docs/system/riscv/microchip-icicle-kit.rst b/docs/system/riscv/microchip-icicle-kit.rst index 817d2aec9c..40798b1aae 100644 --- a/docs/system/riscv/microchip-icicle-kit.rst +++ b/docs/system/riscv/microchip-icicle-kit.rst @@ -95,7 +95,7 @@ Then we can boot the machine by: -serial chardev:serial1 With above command line, current terminal session will be used for the first -serial port. Open another terminal window, and use `minicom` to connect the +serial port. Open another terminal window, and use ``minicom`` to connect the second serial port. .. code-block:: bash diff --git a/docs/system/riscv/virt.rst b/docs/system/riscv/virt.rst index 3709f05797..321d77e07d 100644 --- a/docs/system/riscv/virt.rst +++ b/docs/system/riscv/virt.rst @@ -1,7 +1,7 @@ 'virt' Generic Virtual Platform (``virt``) ========================================== -The `virt` board is a platform which does not correspond to any real hardware; +The ``virt`` board is a platform which does not correspond to any real hardware; it is designed for use in virtual machines. It is the recommended board type if you simply want to run a guest such as Linux and do not care about reproducing the idiosyncrasies and limitations of a particular bit of From 1662ea9f4b8d13e53f3384083fc28e7c8ce93055 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Jul 2021 15:23:37 +0100 Subject: [PATCH 456/531] docs/about/removed-features: Fix markup error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The section describing the removed feature "-usbdevice ccid" had a typo so the markup started with single backtick and ended with double backtick; fix it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210726142338.31872-10-peter.maydell@linaro.org --- docs/about/removed-features.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 28bb035043..07d597847c 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -124,7 +124,7 @@ devices. Drives the board doesn't pick up can no longer be used with ''''''''''''''''''''''''''''''''''''' This option was undocumented and not used in the field. -Use `-device usb-ccid`` instead. +Use ``-device usb-ccid`` instead. RISC-V firmware not booted by default (removed in 5.1) '''''''''''''''''''''''''''''''''''''''''''''''''''''' From 4d6646c7de6164b005d04745faa90b430d4e7c61 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Jul 2021 15:23:38 +0100 Subject: [PATCH 457/531] docs/tools/virtiofsd.rst: Delete stray backtick MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The documentation of the posix_acl option has a stray backtick at the end of the text (which is rendered literally into the HTML). Delete it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Acked-by: Dr. David Alan Gilbert Message-id: 20210726142338.31872-11-peter.maydell@linaro.org --- docs/tools/virtiofsd.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst index c4ac7fdf38..b208f2a6f0 100644 --- a/docs/tools/virtiofsd.rst +++ b/docs/tools/virtiofsd.rst @@ -102,7 +102,7 @@ Options default is ``no_xattr``. * posix_acl|no_posix_acl - - Enable/disable posix acl support. Posix ACLs are disabled by default`. + Enable/disable posix acl support. Posix ACLs are disabled by default. .. option:: --socket-path=PATH From dae257394ae523aff0a9c4049c2e9934e3972ddc Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Jul 2021 17:33:51 +0100 Subject: [PATCH 458/531] hw/arm/boot: Report error if there is no fw_cfg device in the machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the user provides both a BIOS/firmware image and also a guest kernel filename, arm_setup_firmware_boot() will pass the kernel image to the firmware via the fw_cfg device. However we weren't checking whether there really was a fw_cfg device present, and if there wasn't we would crash. This crash can be provoked with a command line such as qemu-system-aarch64 -M raspi3 -kernel /dev/null -bios /dev/null -display none It is currently only possible on the raspi3 machine, because unless the machine sets info->firmware_loaded we won't call arm_setup_firmware_boot(), and the only machines which set that are: * virt (has a fw-cfg device) * sbsa-ref (checks itself for kernel_filename && firmware_loaded) * raspi3 (crashes) But this is an unfortunate beartrap to leave for future machine model implementors, so we should handle this situation in boot.c. Check in arm_setup_firmware_boot() whether the fw-cfg device exists before trying to load files into it, and if it doesn't exist then exit with a hopefully helpful error message. Because we now handle this check in a machine-agnostic way, we can remove the check from sbsa-ref. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/503 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210726163351.32086-1-peter.maydell@linaro.org --- hw/arm/boot.c | 9 +++++++++ hw/arm/sbsa-ref.c | 7 ------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index d7b059225e..57efb61ee4 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -1243,6 +1243,15 @@ static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info) bool try_decompressing_kernel; fw_cfg = fw_cfg_find(); + + if (!fw_cfg) { + error_report("This machine type does not support loading both " + "a guest firmware/BIOS image and a guest kernel at " + "the same time. You should change your QEMU command " + "line to specify one or the other, but not both."); + exit(1); + } + try_decompressing_kernel = arm_feature(&cpu->env, ARM_FEATURE_AARCH64); diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 43c19b4923..c1629df603 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -691,13 +691,6 @@ static void sbsa_ref_init(MachineState *machine) firmware_loaded = sbsa_firmware_init(sms, sysmem, secure_sysmem); - if (machine->kernel_filename && firmware_loaded) { - error_report("sbsa-ref: No fw_cfg device on this machine, " - "so -kernel option is not supported when firmware loaded, " - "please load OS from hard disk instead"); - exit(1); - } - /* * This machine has EL3 enabled, external firmware should supply PSCI * implementation, so the QEMU's internal PSCI is disabled. From bd77bc8b8900654d12194ac38d375d3d0f882cc4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 27 Jul 2021 20:49:55 +0100 Subject: [PATCH 459/531] docs: Move bootindex.txt into system section and rstify Move bootindex.txt into the system section of the manual and turn it into rST format. To make the document make more sense in the context of the system manual, expand the title and introductory paragraphs to give more context. Signed-off-by: Peter Maydell Reviewed-by: Markus Armbruster Message-id: 20210727194955.7764-1-peter.maydell@linaro.org --- docs/bootindex.txt | 52 --------------------------- docs/system/bootindex.rst | 76 +++++++++++++++++++++++++++++++++++++++ docs/system/index.rst | 1 + 3 files changed, 77 insertions(+), 52 deletions(-) delete mode 100644 docs/bootindex.txt create mode 100644 docs/system/bootindex.rst diff --git a/docs/bootindex.txt b/docs/bootindex.txt deleted file mode 100644 index 6937862ba0..0000000000 --- a/docs/bootindex.txt +++ /dev/null @@ -1,52 +0,0 @@ -= Bootindex property = - -Block and net devices have bootindex property. This property is used to -determine the order in which firmware will consider devices for booting -the guest OS. If the bootindex property is not set for a device, it gets -lowest boot priority. There is no particular order in which devices with -unset bootindex property will be considered for booting, but they will -still be bootable. - -== Example == - -Let's assume we have a QEMU machine with two NICs (virtio, e1000) and two -disks (IDE, virtio): - -qemu -drive file=disk1.img,if=none,id=disk1 - -device ide-hd,drive=disk1,bootindex=4 - -drive file=disk2.img,if=none,id=disk2 - -device virtio-blk-pci,drive=disk2,bootindex=3 - -netdev type=user,id=net0 -device virtio-net-pci,netdev=net0,bootindex=2 - -netdev type=user,id=net1 -device e1000,netdev=net1,bootindex=1 - -Given the command above, firmware should try to boot from the e1000 NIC -first. If this fails, it should try the virtio NIC next; if this fails -too, it should try the virtio disk, and then the IDE disk. - -== Limitations == - -1. Some firmware has limitations on which devices can be considered for -booting. For instance, the PC BIOS boot specification allows only one -disk to be bootable. If boot from disk fails for some reason, the BIOS -won't retry booting from other disk. It can still try to boot from -floppy or net, though. - -2. Sometimes, firmware cannot map the device path QEMU wants firmware to -boot from to a boot method. It doesn't happen for devices the firmware -can natively boot from, but if firmware relies on an option ROM for -booting, and the same option ROM is used for booting from more then one -device, the firmware may not be able to ask the option ROM to boot from -a particular device reliably. For instance with the PC BIOS, if a SCSI HBA -has three bootable devices target1, target3, target5 connected to it, -the option ROM will have a boot method for each of them, but it is not -possible to map from boot method back to a specific target. This is a -shortcoming of the PC BIOS boot specification. - -== Mixing bootindex and boot order parameters == - -Note that it does not make sense to use the bootindex property together -with the "-boot order=..." (or "-boot once=...") parameter. The guest -firmware implementations normally either support the one or the other, -but not both parameters at the same time. Mixing them will result in -undefined behavior, and thus the guest firmware will likely not boot -from the expected devices. diff --git a/docs/system/bootindex.rst b/docs/system/bootindex.rst new file mode 100644 index 0000000000..8b057f812f --- /dev/null +++ b/docs/system/bootindex.rst @@ -0,0 +1,76 @@ +Managing device boot order with bootindex properties +==================================================== + +QEMU can tell QEMU-aware guest firmware (like the x86 PC BIOS) +which order it should look for a bootable OS on which devices. +A simple way to set this order is to use the ``-boot order=`` option, +but you can also do this more flexibly, by setting a ``bootindex`` +property on the individual block or net devices you specify +on the QEMU command line. + +The ``bootindex`` properties are used to determine the order in which +firmware will consider devices for booting the guest OS. If the +``bootindex`` property is not set for a device, it gets the lowest +boot priority. There is no particular order in which devices with no +``bootindex`` property set will be considered for booting, but they +will still be bootable. + +Some guest machine types (for instance the s390x machines) do +not support ``-boot order=``; on those machines you must always +use ``bootindex`` properties. + +There is no way to set a ``bootindex`` property if you are using +a short-form option like ``-hda`` or ``-cdrom``, so to use +``bootindex`` properties you will need to expand out those options +into long-form ``-drive`` and ``-device`` option pairs. + +Example +------- + +Let's assume we have a QEMU machine with two NICs (virtio, e1000) and two +disks (IDE, virtio): + +.. parsed-literal:: + + |qemu_system| -drive file=disk1.img,if=none,id=disk1 \\ + -device ide-hd,drive=disk1,bootindex=4 \\ + -drive file=disk2.img,if=none,id=disk2 \\ + -device virtio-blk-pci,drive=disk2,bootindex=3 \\ + -netdev type=user,id=net0 \\ + -device virtio-net-pci,netdev=net0,bootindex=2 \\ + -netdev type=user,id=net1 \\ + -device e1000,netdev=net1,bootindex=1 + +Given the command above, firmware should try to boot from the e1000 NIC +first. If this fails, it should try the virtio NIC next; if this fails +too, it should try the virtio disk, and then the IDE disk. + +Limitations +----------- + +Some firmware has limitations on which devices can be considered for +booting. For instance, the PC BIOS boot specification allows only one +disk to be bootable. If boot from disk fails for some reason, the BIOS +won't retry booting from other disk. It can still try to boot from +floppy or net, though. + +Sometimes, firmware cannot map the device path QEMU wants firmware to +boot from to a boot method. It doesn't happen for devices the firmware +can natively boot from, but if firmware relies on an option ROM for +booting, and the same option ROM is used for booting from more then one +device, the firmware may not be able to ask the option ROM to boot from +a particular device reliably. For instance with the PC BIOS, if a SCSI HBA +has three bootable devices target1, target3, target5 connected to it, +the option ROM will have a boot method for each of them, but it is not +possible to map from boot method back to a specific target. This is a +shortcoming of the PC BIOS boot specification. + +Mixing bootindex and boot order parameters +------------------------------------------ + +Note that it does not make sense to use the bootindex property together +with the ``-boot order=...`` (or ``-boot once=...``) parameter. The guest +firmware implementations normally either support the one or the other, +but not both parameters at the same time. Mixing them will result in +undefined behavior, and thus the guest firmware will likely not boot +from the expected devices. diff --git a/docs/system/index.rst b/docs/system/index.rst index 64a424ae99..650409d156 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -26,6 +26,7 @@ or Hypervisor.Framework. authz gdb managed-startup + bootindex cpu-hotplug pr-manager targets From 6cb02f15223810e1d528e3559194a47b0bbe5020 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 27 Jul 2021 21:41:10 +0100 Subject: [PATCH 460/531] docs: Move the protocol part of barrier.txt into interop Most of docs/barrier.txt is describing the protocol implemented by the input-barrier device. Move this into the interop section of the manual, and rstify it. Signed-off-by: Peter Maydell Reviewed-by: Paolo Bonzini Reviewed-by: Laurent Vivier Message-id: 20210727204112.12579-2-peter.maydell@linaro.org --- docs/barrier.txt | 318 ----------------------------- docs/interop/barrier.rst | 426 +++++++++++++++++++++++++++++++++++++++ docs/interop/index.rst | 1 + 3 files changed, 427 insertions(+), 318 deletions(-) create mode 100644 docs/interop/barrier.rst diff --git a/docs/barrier.txt b/docs/barrier.txt index b21d15015d..376d0b2d70 100644 --- a/docs/barrier.txt +++ b/docs/barrier.txt @@ -45,324 +45,6 @@ (qemu) object_del barrier0 (qemu) object_add input-barrier,id=barrier0,name=VM-1 - -* Message format - - Message format between the server and client is in two parts: - - 1- the payload length is a 32bit integer in network endianness, - 2- the payload - - The payload starts with a 4byte string (without NUL) which is the - command. The first command between the server and the client - is the only command not encoded on 4 bytes ("Barrier"). - The remaining part of the payload is decoded according to the command. - -* Protocol Description (from barrier/src/lib/barrier/protocol_types.h) - - - barrierCmdHello "Barrier" - - Direction: server -> client - Parameters: { int16_t minor, int16_t major } - Description: - - Say hello to client - minor = protocol major version number supported by server - major = protocol minor version number supported by server - - - barrierCmdHelloBack "Barrier" - - Direction: client ->server - Parameters: { int16_t minor, int16_t major, char *name} - Description: - - Respond to hello from server - minor = protocol major version number supported by client - major = protocol minor version number supported by client - name = client name - - - barrierCmdDInfo "DINF" - - Direction: client ->server - Parameters: { int16_t x_origin, int16_t y_origin, int16_t width, int16_t height, int16_t x, int16_t y} - Description: - - The client screen must send this message in response to the - barrierCmdQInfo message. It must also send this message when the - screen's resolution changes. In this case, the client screen should - ignore any barrierCmdDMouseMove messages until it receives a - barrierCmdCInfoAck in order to prevent attempts to move the mouse off - the new screen area. - - - barrierCmdCNoop "CNOP" - - Direction: client -> server - Parameters: None - Description: - - No operation - - - barrierCmdCClose "CBYE" - - Direction: server -> client - Parameters: None - Description: - - Close connection - - - barrierCmdCEnter "CINN" - - Direction: server -> client - Parameters: { int16_t x, int16_t y, int32_t seq, int16_t modifier } - Description: - - Enter screen. - x,y = entering screen absolute coordinates - seq = sequence number, which is used to order messages between - screens. the secondary screen must return this number - with some messages - modifier = modifier key mask. this will have bits set for each - toggle modifier key that is activated on entry to the - screen. the secondary screen should adjust its toggle - modifiers to reflect that state. - - - barrierCmdCLeave "COUT" - - Direction: server -> client - Parameters: None - Description: - - Leaving screen. the secondary screen should send clipboard data in - response to this message for those clipboards that it has grabbed - (i.e. has sent a barrierCmdCClipboard for and has not received a - barrierCmdCClipboard for with a greater sequence number) and that - were grabbed or have changed since the last leave. - - - barrierCmdCClipboard "CCLP" - - Direction: server -> client - Parameters: { int8_t id, int32_t seq } - Description: - - Grab clipboard. Sent by screen when some other app on that screen - grabs a clipboard. - id = the clipboard identifier - seq = sequence number. Client must use the sequence number passed in - the most recent barrierCmdCEnter. the server always sends 0. - - - barrierCmdCScreenSaver "CSEC" - - Direction: server -> client - Parameters: { int8_t started } - Description: - - Screensaver change. - started = Screensaver on primary has started (1) or closed (0) - - - barrierCmdCResetOptions "CROP" - - Direction: server -> client - Parameters: None - Description: - - Reset options. Client should reset all of its options to their - defaults. - - - barrierCmdCInfoAck "CIAK" - - Direction: server -> client - Parameters: None - Description: - - Resolution change acknowledgment. Sent by server in response to a - client screen's barrierCmdDInfo. This is sent for every - barrierCmdDInfo, whether or not the server had sent a barrierCmdQInfo. - - - barrierCmdCKeepAlive "CALV" - - Direction: server -> client - Parameters: None - Description: - - Keep connection alive. Sent by the server periodically to verify - that connections are still up and running. clients must reply in - kind on receipt. if the server gets an error sending the message or - does not receive a reply within a reasonable time then the server - disconnects the client. if the client doesn't receive these (or any - message) periodically then it should disconnect from the server. the - appropriate interval is defined by an option. - - - barrierCmdDKeyDown "DKDN" - - Direction: server -> client - Parameters: { int16_t keyid, int16_t modifier [,int16_t button] } - Description: - - Key pressed. - keyid = X11 key id - modified = modified mask - button = X11 Xkb keycode (optional) - - - barrierCmdDKeyRepeat "DKRP" - - Direction: server -> client - Parameters: { int16_t keyid, int16_t modifier, int16_t repeat [,int16_t button] } - Description: - - Key auto-repeat. - keyid = X11 key id - modified = modified mask - repeat = number of repeats - button = X11 Xkb keycode (optional) - - - barrierCmdDKeyUp "DKUP" - - Direction: server -> client - Parameters: { int16_t keyid, int16_t modifier [,int16_t button] } - Description: - - Key released. - keyid = X11 key id - modified = modified mask - button = X11 Xkb keycode (optional) - - - barrierCmdDMouseDown "DMDN" - - Direction: server -> client - Parameters: { int8_t button } - Description: - - Mouse button pressed. - button = button id - - - barrierCmdDMouseUp "DMUP" - - Direction: server -> client - Parameters: { int8_t button } - Description: - - Mouse button release. - button = button id - - - barrierCmdDMouseMove "DMMV" - - Direction: server -> client - Parameters: { int16_t x, int16_t y } - Description: - - Absolute mouse moved. - x,y = absolute screen coordinates - - - barrierCmdDMouseRelMove "DMRM" - - Direction: server -> client - Parameters: { int16_t x, int16_t y } - Description: - - Relative mouse moved. - x,y = r relative screen coordinates - - - barrierCmdDMouseWheel "DMWM" - - Direction: server -> client - Parameters: { int16_t x , int16_t y } or { int16_t y } - Description: - - Mouse scroll. The delta should be +120 for one tick forward (away - from the user) or right and -120 for one tick backward (toward the - user) or left. - x = x delta - y = y delta - - - barrierCmdDClipboard "DCLP" - - Direction: server -> client - Parameters: { int8_t id, int32_t seq, int8_t mark, char *data } - Description: - - Clipboard data. - id = clipboard id - seq = sequence number. The sequence number is 0 when sent by the - server. Client screens should use the/ sequence number from - the most recent barrierCmdCEnter. - - - barrierCmdDSetOptions "DSOP" - - Direction: server -> client - Parameters: { int32 t nb, { int32_t id, int32_t val }[] } - Description: - - Set options. Client should set the given option/value pairs. - nb = numbers of { id, val } entries - id = option id - val = option new value - - - barrierCmdDFileTransfer "DFTR" - - Direction: server -> client - Parameters: { int8_t mark, char *content } - Description: - - Transfer file data. - mark = 0 means the content followed is the file size - 1 means the content followed is the chunk data - 2 means the file transfer is finished - - - barrierCmdDDragInfo "DDRG" int16_t char * - - Direction: server -> client - Parameters: { int16_t nb, char *content } - Description: - - Drag information. - nb = number of dragging objects - content = object's directory - - - barrierCmdQInfo "QINF" - - Direction: server -> client - Parameters: None - Description: - - Query screen info - Client should reply with a barrierCmdDInfo - - - barrierCmdEIncompatible "EICV" - - Direction: server -> client - Parameters: { int16_t nb, major *minor } - Description: - - Incompatible version. - major = major version - minor = minor version - - - barrierCmdEBusy "EBSY" - - Direction: server -> client - Parameters: None - Description: - - Name provided when connecting is already in use. - - - barrierCmdEUnknown "EUNK" - - Direction: server -> client - Parameters: None - Description: - - Unknown client. Name provided when connecting is not in primary's - screen configuration map. - - - barrierCmdEBad "EBAD" - - Direction: server -> client - Parameters: None - Description: - - Protocol violation. Server should disconnect after sending this - message. - * TO DO - Enable SSL diff --git a/docs/interop/barrier.rst b/docs/interop/barrier.rst new file mode 100644 index 0000000000..055f2c1aef --- /dev/null +++ b/docs/interop/barrier.rst @@ -0,0 +1,426 @@ +Barrier client protocol +======================= + +QEMU's ``input-barrier`` device implements the client end of +the KVM (Keyboard-Video-Mouse) software +`Barrier `__. + +This document briefly describes the protocol as we implement it. + +Message format +-------------- + +Message format between the server and client is in two parts: + +#. the payload length, a 32bit integer in network endianness +#. the payload + +The payload starts with a 4byte string (without NUL) which is the +command. The first command between the server and the client +is the only command not encoded on 4 bytes ("Barrier"). +The remaining part of the payload is decoded according to the command. + +Protocol Description +-------------------- + +This comes from ``barrier/src/lib/barrier/protocol_types.h``. + +barrierCmdHello "Barrier" +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int16_t minor, int16_t major }`` +Description: + Say hello to client + + ``minor`` = protocol major version number supported by server + + ``major`` = protocol minor version number supported by server + +barrierCmdHelloBack "Barrier" +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + client ->server +Parameters: + ``{ int16_t minor, int16_t major, char *name}`` +Description: + Respond to hello from server + + ``minor`` = protocol major version number supported by client + + ``major`` = protocol minor version number supported by client + + ``name`` = client name + +barrierCmdDInfo "DINF" +^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + client ->server +Parameters: + ``{ int16_t x_origin, int16_t y_origin, int16_t width, int16_t height, int16_t x, int16_t y}`` +Description: + The client screen must send this message in response to the + barrierCmdQInfo message. It must also send this message when the + screen's resolution changes. In this case, the client screen should + ignore any barrierCmdDMouseMove messages until it receives a + barrierCmdCInfoAck in order to prevent attempts to move the mouse off + the new screen area. + +barrierCmdCNoop "CNOP" +^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + client -> server +Parameters: + None +Description: + No operation + +barrierCmdCClose "CBYE" +^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + None +Description: + Close connection + +barrierCmdCEnter "CINN" +^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int16_t x, int16_t y, int32_t seq, int16_t modifier }`` +Description: + Enter screen. + + ``x``, ``y`` = entering screen absolute coordinates + + ``seq`` = sequence number, which is used to order messages between + screens. the secondary screen must return this number + with some messages + + ``modifier`` = modifier key mask. this will have bits set for each + toggle modifier key that is activated on entry to the + screen. the secondary screen should adjust its toggle + modifiers to reflect that state. + +barrierCmdCLeave "COUT" +^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + None +Description: + Leaving screen. the secondary screen should send clipboard data in + response to this message for those clipboards that it has grabbed + (i.e. has sent a barrierCmdCClipboard for and has not received a + barrierCmdCClipboard for with a greater sequence number) and that + were grabbed or have changed since the last leave. + +barrierCmdCClipboard "CCLP" +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int8_t id, int32_t seq }`` +Description: + Grab clipboard. Sent by screen when some other app on that screen + grabs a clipboard. + + ``id`` = the clipboard identifier + + ``seq`` = sequence number. Client must use the sequence number passed in + the most recent barrierCmdCEnter. the server always sends 0. + +barrierCmdCScreenSaver "CSEC" +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int8_t started }`` +Description: + Screensaver change. + + ``started`` = Screensaver on primary has started (1) or closed (0) + +barrierCmdCResetOptions "CROP" +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + None +Description: + Reset options. Client should reset all of its options to their + defaults. + +barrierCmdCInfoAck "CIAK" +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + None +Description: + Resolution change acknowledgment. Sent by server in response to a + client screen's barrierCmdDInfo. This is sent for every + barrierCmdDInfo, whether or not the server had sent a barrierCmdQInfo. + +barrierCmdCKeepAlive "CALV" +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + None +Description: + Keep connection alive. Sent by the server periodically to verify + that connections are still up and running. clients must reply in + kind on receipt. if the server gets an error sending the message or + does not receive a reply within a reasonable time then the server + disconnects the client. if the client doesn't receive these (or any + message) periodically then it should disconnect from the server. the + appropriate interval is defined by an option. + +barrierCmdDKeyDown "DKDN" +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int16_t keyid, int16_t modifier [,int16_t button] }`` +Description: + Key pressed. + + ``keyid`` = X11 key id + + ``modified`` = modified mask + + ``button`` = X11 Xkb keycode (optional) + +barrierCmdDKeyRepeat "DKRP" +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int16_t keyid, int16_t modifier, int16_t repeat [,int16_t button] }`` +Description: + Key auto-repeat. + + ``keyid`` = X11 key id + + ``modified`` = modified mask + + ``repeat`` = number of repeats + + ``button`` = X11 Xkb keycode (optional) + +barrierCmdDKeyUp "DKUP" +^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int16_t keyid, int16_t modifier [,int16_t button] }`` +Description: + Key released. + + ``keyid`` = X11 key id + + ``modified`` = modified mask + + ``button`` = X11 Xkb keycode (optional) + +barrierCmdDMouseDown "DMDN" +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int8_t button }`` +Description: + Mouse button pressed. + + ``button`` = button id + +barrierCmdDMouseUp "DMUP" +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int8_t button }`` +Description: + Mouse button release. + + ``button`` = button id + +barrierCmdDMouseMove "DMMV" +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int16_t x, int16_t y }`` +Description: + Absolute mouse moved. + + ``x``, ``y`` = absolute screen coordinates + +barrierCmdDMouseRelMove "DMRM" +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int16_t x, int16_t y }`` +Description: + Relative mouse moved. + + ``x``, ``y`` = r relative screen coordinates + +barrierCmdDMouseWheel "DMWM" +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int16_t x , int16_t y }`` or ``{ int16_t y }`` +Description: + Mouse scroll. The delta should be +120 for one tick forward (away + from the user) or right and -120 for one tick backward (toward the + user) or left. + + ``x`` = x delta + + ``y`` = y delta + +barrierCmdDClipboard "DCLP" +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int8_t id, int32_t seq, int8_t mark, char *data }`` +Description: + Clipboard data. + + ``id`` = clipboard id + + ``seq`` = sequence number. The sequence number is 0 when sent by the + server. Client screens should use the/ sequence number from + the most recent barrierCmdCEnter. + +barrierCmdDSetOptions "DSOP" +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int32 t nb, { int32_t id, int32_t val }[] }`` +Description: + Set options. Client should set the given option/value pairs. + + ``nb`` = numbers of ``{ id, val }`` entries + + ``id`` = option id + + ``val`` = option new value + +barrierCmdDFileTransfer "DFTR" +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int8_t mark, char *content }`` +Description: + Transfer file data. + + * ``mark`` = 0 means the content followed is the file size + * 1 means the content followed is the chunk data + * 2 means the file transfer is finished + +barrierCmdDDragInfo "DDRG" +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int16_t nb, char *content }`` +Description: + Drag information. + + ``nb`` = number of dragging objects + + ``content`` = object's directory + +barrierCmdQInfo "QINF" +^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + None +Description: + Query screen info + + Client should reply with a barrierCmdDInfo + +barrierCmdEIncompatible "EICV" +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + ``{ int16_t nb, major *minor }`` +Description: + Incompatible version. + + ``major`` = major version + + ``minor`` = minor version + +barrierCmdEBusy "EBSY" +^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + None +Description: + Name provided when connecting is already in use. + +barrierCmdEUnknown "EUNK" +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + None +Description: + Unknown client. Name provided when connecting is not in primary's + screen configuration map. + +barrierCmdEBad "EBAD" +^^^^^^^^^^^^^^^^^^^^^^^ + +Direction: + server -> client +Parameters: + None +Description: + Protocol violation. Server should disconnect after sending this + message. + diff --git a/docs/interop/index.rst b/docs/interop/index.rst index b1bab81e2e..f9801a9c20 100644 --- a/docs/interop/index.rst +++ b/docs/interop/index.rst @@ -7,6 +7,7 @@ are useful for making QEMU interoperate with other software. .. toctree:: :maxdepth: 2 + barrier bitmaps dbus dbus-vmstate From 399a04775e7ac748834bf0431d31fdb0ae30b912 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 27 Jul 2021 21:41:11 +0100 Subject: [PATCH 461/531] ui/input-barrier: Move TODOs from barrier.txt to a comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docs/barrier.txt has a couple of TODO notes about things to be implemented in this device; move them into a comment in the source code. Signed-off-by: Peter Maydell Reviewed-by: Paolo Bonzini Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210727204112.12579-3-peter.maydell@linaro.org --- docs/barrier.txt | 4 ---- ui/input-barrier.c | 5 +++++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/barrier.txt b/docs/barrier.txt index 376d0b2d70..54cb5fd8ef 100644 --- a/docs/barrier.txt +++ b/docs/barrier.txt @@ -45,8 +45,4 @@ (qemu) object_del barrier0 (qemu) object_add input-barrier,id=barrier0,name=VM-1 -* TO DO - - - Enable SSL - - Manage SetOptions/ResetOptions commands diff --git a/ui/input-barrier.c b/ui/input-barrier.c index 81b8d04ec8..2d57ca7079 100644 --- a/ui/input-barrier.c +++ b/ui/input-barrier.c @@ -3,6 +3,11 @@ * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. + * + * TODO: + * + * - Enable SSL + * - Manage SetOptions/ResetOptions commands */ #include "qemu/osdep.h" From 4a64939db76b10d8d41d2af3c6aad8142da55450 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 27 Jul 2021 21:41:12 +0100 Subject: [PATCH 462/531] docs: Move user-facing barrier docs into system manual MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The remaining text in docs/barrier.txt is user-facing description of what the device is and how to use it. Move this into the system manual and rstify it. Signed-off-by: Peter Maydell Reviewed-by: Paolo Bonzini Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210727204112.12579-4-peter.maydell@linaro.org --- docs/barrier.txt | 48 ----------------------------------------- docs/system/barrier.rst | 44 +++++++++++++++++++++++++++++++++++++ docs/system/index.rst | 1 + 3 files changed, 45 insertions(+), 48 deletions(-) delete mode 100644 docs/barrier.txt create mode 100644 docs/system/barrier.rst diff --git a/docs/barrier.txt b/docs/barrier.txt deleted file mode 100644 index 54cb5fd8ef..0000000000 --- a/docs/barrier.txt +++ /dev/null @@ -1,48 +0,0 @@ - QEMU Barrier Client - - -* About - - Barrier is a KVM (Keyboard-Video-Mouse) software forked from Symless's - synergy 1.9 codebase. - - See https://github.com/debauchee/barrier - -* QEMU usage - - Generally, mouse and keyboard are grabbed through the QEMU video - interface emulation. - - But when we want to use a video graphic adapter via a PCI passthrough - there is no way to provide the keyboard and mouse inputs to the VM - except by plugging a second set of mouse and keyboard to the host - or by installing a KVM software in the guest OS. - - The QEMU Barrier client avoids this by implementing directly the Barrier - protocol into QEMU. - - This protocol is enabled by adding an input-barrier object to QEMU. - - Syntax: input-barrier,id=,name= - [,server=][,port=] - [,x-origin=][,y-origin=] - [,width=][,height=] - - The object can be added on the QEMU command line, for instance with: - - ... -object input-barrier,id=barrier0,name=VM-1 ... - - where VM-1 is the name the display configured int the Barrier server - on the host providing the mouse and the keyboard events. - - by default is "localhost", port is 24800, - and are set to 0, and to - 1920 and 1080. - - If Barrier server is stopped QEMU needs to be reconnected manually, - by removing and re-adding the input-barrier object, for instance - with the help of the HMP monitor: - - (qemu) object_del barrier0 - (qemu) object_add input-barrier,id=barrier0,name=VM-1 - diff --git a/docs/system/barrier.rst b/docs/system/barrier.rst new file mode 100644 index 0000000000..155d7d2901 --- /dev/null +++ b/docs/system/barrier.rst @@ -0,0 +1,44 @@ +QEMU Barrier Client +=================== + +Generally, mouse and keyboard are grabbed through the QEMU video +interface emulation. + +But when we want to use a video graphic adapter via a PCI passthrough +there is no way to provide the keyboard and mouse inputs to the VM +except by plugging a second set of mouse and keyboard to the host +or by installing a KVM software in the guest OS. + +The QEMU Barrier client avoids this by implementing directly the Barrier +protocol into QEMU. + +`Barrier `__ +is a KVM (Keyboard-Video-Mouse) software forked from Symless's +synergy 1.9 codebase. + +This protocol is enabled by adding an input-barrier object to QEMU. + +Syntax:: + + input-barrier,id=,name= + [,server=][,port=] + [,x-origin=][,y-origin=] + [,width=][,height=] + +The object can be added on the QEMU command line, for instance with:: + + -object input-barrier,id=barrier0,name=VM-1 + +where VM-1 is the name the display configured in the Barrier server +on the host providing the mouse and the keyboard events. + +by default ```` is ``localhost``, +```` is ``24800``, ```` and ```` are set to ``0``, +```` and ```` to ``1920`` and ``1080``. + +If the Barrier server is stopped QEMU needs to be reconnected manually, +by removing and re-adding the input-barrier object, for instance +with the help of the HMP monitor:: + + (qemu) object_del barrier0 + (qemu) object_add input-barrier,id=barrier0,name=VM-1 diff --git a/docs/system/index.rst b/docs/system/index.rst index 650409d156..7b9276c05f 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -20,6 +20,7 @@ or Hypervisor.Framework. linuxboot generic-loader guest-loader + barrier vnc-security tls secrets From 3d98f9b68d2a8c10960d788027b8500ee947933f Mon Sep 17 00:00:00 2001 From: Basil Salman Date: Mon, 5 Apr 2021 16:14:18 +0300 Subject: [PATCH 463/531] qga-win: Increase VSS freeze timeout to 60 secs instead of 10 Currently Requester freeze times out after 10 seconds, while the default timeout for Writer Freeze is 60 seconds. according to VSS Documentation [1]. [1]: https://docs.microsoft.com/en-us/windows/win32/vss/overview-of-processing-a-backup-under-vss Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1909073 Signed-off-by: Basil Salman Signed-off-by: Basil Salman Signed-off-by: Michael Roth --- qga/vss-win32/requester.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qga/vss-win32/requester.cpp b/qga/vss-win32/requester.cpp index 5378c55d23..940a2c8f55 100644 --- a/qga/vss-win32/requester.cpp +++ b/qga/vss-win32/requester.cpp @@ -18,7 +18,7 @@ #include /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */ -#define VSS_TIMEOUT_FREEZE_MSEC 10000 +#define VSS_TIMEOUT_FREEZE_MSEC 60000 /* Call QueryStatus every 10 ms while waiting for frozen event */ #define VSS_TIMEOUT_EVENT_MSEC 10 From 02ac3f4b959546ad69287aae84e2d52e21aeb479 Mon Sep 17 00:00:00 2001 From: Basil Salman Date: Mon, 12 Jul 2021 11:15:08 -0500 Subject: [PATCH 464/531] qga-win: Fix build_guest_fsinfo() close of nonexistent On the current error path of build_guest_fsinfo(), a non existent handle is passed to CloseHandle(). This patch adds initialization of hLocalDiskHandle to INVALID_HANDLE_VALUE, and checks for handle validity before the handle is closed. Signed-off-by: Basil Salman Signed-off-by: Basil Salman Signed-off-by: Michael Roth --- qga/commands-win32.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index a099acb34d..763186efd4 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -1091,7 +1091,7 @@ static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp) size_t len; uint64_t i64FreeBytesToCaller, i64TotalBytes, i64FreeBytes; GuestFilesystemInfo *fs = NULL; - HANDLE hLocalDiskHandle = NULL; + HANDLE hLocalDiskHandle = INVALID_HANDLE_VALUE; GetVolumePathNamesForVolumeName(guid, (LPCH)&mnt, 0, &info_size); if (GetLastError() != ERROR_MORE_DATA) { @@ -1149,7 +1149,9 @@ static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp) fs->type = g_strdup(fs_name); fs->disk = build_guest_disk_info(guid, errp); free: - CloseHandle(hLocalDiskHandle); + if (hLocalDiskHandle != INVALID_HANDLE_VALUE) { + CloseHandle(hLocalDiskHandle); + } g_free(mnt_point); return fs; } From ce72f11274f6499b44aa7f2f214f6e7fc09bd9d2 Mon Sep 17 00:00:00 2001 From: Basil Salman Date: Mon, 12 Jul 2021 11:24:44 -0500 Subject: [PATCH 465/531] qga-win: Fix handle leak in ga_get_win_product_name() In ga_get_win_product_name() a handle to Registry key was open but not closed. In this patch the handle is closed as part of the free routine. Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1929144 Signed-off-by: Basil Salman Signed-off-by: Basil Salman Signed-off-by: Michael Roth --- qga/commands-win32.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 763186efd4..098211e724 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -2231,7 +2231,7 @@ static char *ga_get_win_name(OSVERSIONINFOEXW const *os_version, bool id) static char *ga_get_win_product_name(Error **errp) { - HKEY key = NULL; + HKEY key = INVALID_HANDLE_VALUE; DWORD size = 128; char *result = g_malloc0(size); LONG err = ERROR_SUCCESS; @@ -2241,7 +2241,8 @@ static char *ga_get_win_product_name(Error **errp) &key); if (err != ERROR_SUCCESS) { error_setg_win32(errp, err, "failed to open registry key"); - goto fail; + g_free(result); + return NULL; } err = RegQueryValueExA(key, "ProductName", NULL, NULL, @@ -2262,9 +2263,13 @@ static char *ga_get_win_product_name(Error **errp) goto fail; } + RegCloseKey(key); return result; fail: + if (key != INVALID_HANDLE_VALUE) { + RegCloseKey(key); + } g_free(result); return NULL; } From 24328b7a83a43d65389eda0cbabbd67595f43b5b Mon Sep 17 00:00:00 2001 From: Kostiantyn Kostiuk Date: Thu, 10 Jun 2021 18:58:11 +0300 Subject: [PATCH 466/531] qga-win: Free GMatchInfo properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The g_regex_match function creates match_info even if it returns FALSE. So we should always call g_match_info_free. A better solution is using g_autoptr for match_info variable. Signed-off-by: Kostiantyn Kostiuk Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Michael Roth --- qga/commands-win32.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 098211e724..7bac0c5d42 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -2459,7 +2459,7 @@ GuestDeviceInfoList *qmp_guest_get_devices(Error **errp) continue; } for (j = 0; hw_ids[j] != NULL; j++) { - GMatchInfo *match_info; + g_autoptr(GMatchInfo) match_info; GuestDeviceIdPCI *id; if (!g_regex_match(device_pci_re, hw_ids[j], 0, &match_info)) { continue; @@ -2476,7 +2476,6 @@ GuestDeviceInfoList *qmp_guest_get_devices(Error **errp) id->vendor_id = g_ascii_strtoull(vendor_id, NULL, 16); id->device_id = g_ascii_strtoull(device_id, NULL, 16); - g_match_info_free(match_info); break; } if (skip) { From 5f2a8b1fc1422a769e8b36f7b5e9b368f475f9c1 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 26 Jul 2021 17:52:35 +0200 Subject: [PATCH 467/531] qemu-ga/msi: fix w32 libgcc name This is what I find on my Fedora 34 mingw install. Signed-off-by: Gerd Hoffmann Signed-off-by: Michael Roth --- qga/installer/qemu-ga.wxs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qga/installer/qemu-ga.wxs b/qga/installer/qemu-ga.wxs index 9cb4c3d733..ce7b25b5e1 100644 --- a/qga/installer/qemu-ga.wxs +++ b/qga/installer/qemu-ga.wxs @@ -31,7 +31,7 @@ - + From e300858ed4a6d0cbd52b7fb5082d3c69cc371965 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Mon, 2 Aug 2021 22:28:58 -0500 Subject: [PATCH 468/531] qga-win/msi: fix missing libstdc++-6 DLL in MSI installer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit libstdc++ is required for the qga-vss.dll that provides fsfreeze functionality. Currently it is not provided by the MSI installer, resulting in fsfreeze being disabled in guest environments where it has not been installed by other means. In the future this would be better handled via gcc-cpp ComponentGroup provided by msitools, but that would be better handled with a general rework of DLL dependency handling in the installer build. Keep it simple for now to fix this regression. Tested with Fedora 34 mingw build environment. Cc: Gerd Hoffmann Cc: Kostiantyn Kostiuk Cc: Marc-André Lureau Cc: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Signed-off-by: Michael Roth --- qga/installer/qemu-ga.wxs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qga/installer/qemu-ga.wxs b/qga/installer/qemu-ga.wxs index ce7b25b5e1..0950e8c6be 100644 --- a/qga/installer/qemu-ga.wxs +++ b/qga/installer/qemu-ga.wxs @@ -84,6 +84,9 @@ + + + @@ -164,6 +167,7 @@ + From 43f547b73dfaf108c9aaacb0b36200e2e7a200f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 18 May 2021 19:51:11 +0400 Subject: [PATCH 469/531] Update libslirp to v4.6.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch from stable-4.2 branch to upstream v4.6.1 release + fixes. ## [Unreleased] ### Fixed - Haiku fixes. !98 !99 - Fix a minor DHCP regression introduced in 4.6.0. !97 ## [4.6.1] - 2021-06-18 ### Fixed - Fix DHCP regression introduced in 4.6.0. !95 ## [4.6.0] - 2021-06-14 ### Added - mbuf: Add debugging helpers for allocation. !90 ### Changed - Revert "Set macOS deployment target to macOS 10.4". !93 ### Fixed - mtod()-related buffer overflows (CVE-2021-3592 #44, CVE-2021-3593 #45, CVE-2021-3594 #47, CVE-2021-3595 #46). - poll_fd: add missing fd registration for UDP and ICMP - ncsi: make ncsi_calculate_checksum work with unaligned data. !89 - Various typos and doc fixes. !88 ## [4.5.0] - 2021-05-18 ### Added - IPv6 forwarding. !62 !75 !77 - slirp_neighbor_info() to dump the ARP/NDP tables. !71 ### Changed - Lazy guest address resolution for IPv6. !81 - Improve signal handling when spawning a child. !61 - Set macOS deployment target to macOS 10.4. !72 - slirp_add_hostfwd: Ensure all error paths set errno. !80 - More API documentation. ### Fixed - Assertion failure on unspecified IPv6 address. !86 - Disable polling for PRI on MacOS, fixing some closing streams issues. !73 - Various memory leak fixes on fastq/batchq. !68 - Memory leak on IPv6 fast-send. !67 - Slow socket response on Windows. !64 - Misc build and code cleanups. !60 !63 !76 !79 !84 ## [4.4.0] - 2020-12-02 ### Added - udp, udp6, icmp: handle TTL value. !48 - Enable forwarding ICMP errors. !49 - Add DNS resolving for iOS. !54 ### Changed - Improve meson subproject() support. !53 - Removed Makefile-based build system. !56 ### Fixed - socket: consume empty packets. !55 - check pkt_len before reading protocol header (CVE-2020-29129). !57 - ip_stripoptions use memmove (fixes undefined behaviour). !47 - various Coverity-related changes/fixes. ## [4.3.1] - 2020-07-08 ### Changed - A silent truncation could occur in `slirp_fmt()`, which will now print a critical message. See also #22. ### Fixed - CVE-2020-10756 - Drop bogus IPv6 messages that could lead to data leakage. See !44 and !42. - Fix win32 builds by using the SLIRP_PACKED definition. - Various coverity scan errors fixed. !41 - Fix new GCC warnings. !43 ## [4.3.0] - 2020-04-22 ### Added - `SLIRP_VERSION_STRING` macro, with the git sha suffix when building from git - `SlirpConfig.disable_dns`, to disable DNS redirection #16 ### Changed - `slirp_version_string()` now has the git sha suffix when building form git - Limit DNS redirection to port 53 #16 ### Fixed - Fix build regression with mingw & NetBSD - Fix use-afte-free in `ip_reass()` (CVE-2020-1983) Signed-off-by: Marc-André Lureau Reviewed-by: Doug Evans --- meson.build | 2 ++ slirp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index f2e148eaf9..af9bbb83db 100644 --- a/meson.build +++ b/meson.build @@ -1824,6 +1824,8 @@ if have_system slirp_deps = [] if targetos == 'windows' slirp_deps = cc.find_library('iphlpapi') + elif targetos == 'darwin' + slirp_deps = cc.find_library('resolv') endif slirp_conf = configuration_data() slirp_conf.set('SLIRP_MAJOR_VERSION', meson.project_version().split('.')[0]) diff --git a/slirp b/slirp index 8f43a99191..a88d9ace23 160000 --- a/slirp +++ b/slirp @@ -1 +1 @@ -Subproject commit 8f43a99191afb47ca3f3c6972f6306209f367ece +Subproject commit a88d9ace234a24ce1c17189642ef9104799425e0 From 54ba2161d8c40235d7b486d68ac3803ae0818f43 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Mon, 5 Jul 2021 23:04:33 +0200 Subject: [PATCH 470/531] target/s390x: Fix SIGILL and SIGFPE psw.addr reporting For SIGILL, SIGFPE and SIGTRAP the PSW must point after the instruction, and at the instruction for other signals. Currently under qemu-user for SIGFILL and SIGFPE it points at the instruction. Fix by advancing psw.addr for these signals. Co-developed-by: Ulrich Weigand Signed-off-by: Ilya Leoshkevich Reviewed-by: David Hildenbrand Buglink: https://gitlab.com/qemu-project/qemu/-/issues/319 Message-Id: <20210705210434.45824-2-iii@linux.ibm.com> Signed-off-by: Thomas Huth --- linux-user/s390x/cpu_loop.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c index f2d1215fb1..22f2e89c62 100644 --- a/linux-user/s390x/cpu_loop.c +++ b/linux-user/s390x/cpu_loop.c @@ -64,7 +64,13 @@ void cpu_loop(CPUS390XState *env) case EXCP_DEBUG: sig = TARGET_SIGTRAP; n = TARGET_TRAP_BRKPT; - goto do_signal_pc; + /* + * For SIGTRAP the PSW must point after the instruction, which it + * already does thanks to s390x_tr_tb_stop(). si_addr doesn't need + * to be filled. + */ + addr = 0; + goto do_signal; case EXCP_PGM: n = env->int_pgm_code; switch (n) { @@ -132,6 +138,10 @@ void cpu_loop(CPUS390XState *env) do_signal_pc: addr = env->psw.addr; + /* + * For SIGILL and SIGFPE the PSW must point after the instruction. + */ + env->psw.addr += env->int_pgm_ilen; do_signal: info.si_signo = sig; info.si_errno = 0; From ccb5f2708fa02a601833987dacbbc3b47d5b720c Mon Sep 17 00:00:00 2001 From: Jonathan Albrecht Date: Fri, 9 Jul 2021 12:04:58 -0400 Subject: [PATCH 471/531] linux-user/s390x: signal with SIGFPE on compare-and-trap Currently when a compare-and-trap instruction is executed, qemu will always raise a SIGILL signal. On real hardware, a SIGFPE is raised. Change the PGM_DATA case in cpu_loop to follow the behavior in linux kernel /arch/s390/kernel/traps.c. * Only raise SIGILL if DXC == 0 * If DXC matches a non-simulated IEEE exception, raise SIGFPE with correct si_code * Raise SIGFPE with si_code == 0 for everything else When applied on 20210705210434.45824-2-iii@linux.ibm.com, this fixes crashes in the java jdk such as the linked bug. Signed-off-by: Jonathan Albrecht Reviewed-by: Richard Henderson Buglink: https://bugs.launchpad.net/qemu/+bug/1920913 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/319 Message-Id: <20210709160459.4962-2-jonathan.albrecht@linux.vnet.ibm.com> Signed-off-by: Thomas Huth --- linux-user/s390x/cpu_loop.c | 54 +++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c index 22f2e89c62..6a69a6dd26 100644 --- a/linux-user/s390x/cpu_loop.c +++ b/linux-user/s390x/cpu_loop.c @@ -25,6 +25,35 @@ /* s390x masks the fault address it reports in si_addr for SIGSEGV and SIGBUS */ #define S390X_FAIL_ADDR_MASK -4096LL +static int get_pgm_data_si_code(int dxc_code) +{ + switch (dxc_code) { + /* Non-simulated IEEE exceptions */ + case 0x80: + return TARGET_FPE_FLTINV; + case 0x40: + return TARGET_FPE_FLTDIV; + case 0x20: + case 0x28: + case 0x2c: + return TARGET_FPE_FLTOVF; + case 0x10: + case 0x18: + case 0x1c: + return TARGET_FPE_FLTUND; + case 0x08: + case 0x0c: + return TARGET_FPE_FLTRES; + } + /* + * Non-IEEE and simulated IEEE: + * Includes compare-and-trap, quantum exception, etc. + * Simulated IEEE are included here to match current + * s390x linux kernel. + */ + return 0; +} + void cpu_loop(CPUS390XState *env) { CPUState *cs = env_cpu(env); @@ -106,29 +135,14 @@ void cpu_loop(CPUS390XState *env) case PGM_DATA: n = (env->fpc >> 8) & 0xff; - if (n == 0xff) { - /* compare-and-trap */ + if (n == 0) { goto do_sigill_opn; - } else { - /* An IEEE exception, simulated or otherwise. */ - if (n & 0x80) { - n = TARGET_FPE_FLTINV; - } else if (n & 0x40) { - n = TARGET_FPE_FLTDIV; - } else if (n & 0x20) { - n = TARGET_FPE_FLTOVF; - } else if (n & 0x10) { - n = TARGET_FPE_FLTUND; - } else if (n & 0x08) { - n = TARGET_FPE_FLTRES; - } else { - /* ??? Quantum exception; BFP, DFP error. */ - goto do_sigill_opn; - } - sig = TARGET_SIGFPE; - goto do_signal_pc; } + sig = TARGET_SIGFPE; + n = get_pgm_data_si_code(n); + goto do_signal_pc; + default: fprintf(stderr, "Unhandled program exception: %#x\n", n); cpu_dump_state(cs, stderr, 0); From 50e36dd61652a4a4f2af245655ed3ca08ef0a3ed Mon Sep 17 00:00:00 2001 From: Jonathan Albrecht Date: Fri, 9 Jul 2021 12:04:59 -0400 Subject: [PATCH 472/531] tests/tcg: Test that compare-and-trap raises SIGFPE Signed-off-by: Jonathan Albrecht Message-Id: <20210709160459.4962-3-jonathan.albrecht@linux.vnet.ibm.com> Signed-off-by: Thomas Huth --- tests/tcg/s390x/Makefile.target | 2 +- tests/tcg/s390x/trap.c | 102 ++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 tests/tcg/s390x/trap.c diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target index 5d3de1b27a..bd084c7840 100644 --- a/tests/tcg/s390x/Makefile.target +++ b/tests/tcg/s390x/Makefile.target @@ -8,4 +8,4 @@ TESTS+=exrl-trtr TESTS+=pack TESTS+=mvo TESTS+=mvc - +TESTS+=trap diff --git a/tests/tcg/s390x/trap.c b/tests/tcg/s390x/trap.c new file mode 100644 index 0000000000..d4c61c7f52 --- /dev/null +++ b/tests/tcg/s390x/trap.c @@ -0,0 +1,102 @@ +/* + * Copyright 2021 IBM Corp. + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static void error1(const char *filename, int line, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d: ", filename, line); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} + +static int __chk_error(const char *filename, int line, int ret) +{ + if (ret < 0) { + error1(filename, line, "%m (ret=%d, errno=%d/%s)", + ret, errno, strerror(errno)); + } + return ret; +} + +#define error(fmt, ...) error1(__FILE__, __LINE__, fmt, ## __VA_ARGS__) + +#define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret)) + +int sigfpe_count; +int sigill_count; + +static void sig_handler(int sig, siginfo_t *si, void *puc) +{ + if (sig == SIGFPE) { + if (si->si_code != 0) { + error("unexpected si_code: 0x%x != 0", si->si_code); + } + ++sigfpe_count; + return; + } + + if (sig == SIGILL) { + ++sigill_count; + return; + } + + error("unexpected signal 0x%x\n", sig); +} + +int main(int argc, char **argv) +{ + sigfpe_count = sigill_count = 0; + + struct sigaction act; + + /* Set up SIG handler */ + act.sa_sigaction = sig_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + chk_error(sigaction(SIGFPE, &act, NULL)); + chk_error(sigaction(SIGILL, &act, NULL)); + + uint64_t z = 0x0ull; + uint64_t lz = 0xffffffffffffffffull; + asm volatile ( + "lg %%r13,%[lz]\n" + "cgitne %%r13,0\n" /* SIGFPE */ + "lg %%r13,%[z]\n" + "cgitne %%r13,0\n" /* no trap */ + "nopr\n" + "lg %%r13,%[lz]\n" + "citne %%r13,0\n" /* SIGFPE */ + "lg %%r13,%[z]\n" + "citne %%r13,0\n" /* no trap */ + "nopr\n" + : + : [z] "m" (z), [lz] "m" (lz) + : "memory", "r13"); + + if (sigfpe_count != 2) { + error("unexpected SIGFPE count: %d != 2", sigfpe_count); + } + if (sigill_count != 0) { + error("unexpected SIGILL count: %d != 0", sigill_count); + } + + printf("PASS\n"); + return 0; +} From 87ab88025247b893aad5071fd38301b67be76d1a Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 27 Jul 2021 17:49:23 +0200 Subject: [PATCH 473/531] block: Fix in_flight leak in request padding error path When bdrv_pad_request() fails in bdrv_co_preadv_part(), bs->in_flight has been increased, but is never decreased again. This leads to a hang when trying to drain the block node. This bug was observed with Windows guests which issue a request that fully uses IOV_MAX during installation, so that when padding is necessary (O_DIRECT with a 4k sector size block device on the host), adding another entry causes failure. Call bdrv_dec_in_flight() to fix this. There is a larger problem to solve here because this request shouldn't even fail, but Windows doesn't seem to care and with this minimal fix the installation succeeds. So given that we're already in freeze, let's take this minimal fix for 6.1. Fixes: 98ca45494fcd6bf0336ecd559e440b6de6ea4cd3 Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1972079 Reported-by: Qing Wang Signed-off-by: Kevin Wolf Message-Id: <20210727154923.91067-1-kwolf@redhat.com> Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- block/io.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/block/io.c b/block/io.c index e0a689c584..a19942718b 100644 --- a/block/io.c +++ b/block/io.c @@ -1841,7 +1841,7 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, ret = bdrv_pad_request(bs, &qiov, &qiov_offset, &offset, &bytes, &pad, NULL); if (ret < 0) { - return ret; + goto fail; } tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_READ); @@ -1849,10 +1849,11 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, bs->bl.request_alignment, qiov, qiov_offset, flags); tracked_request_end(&req); - bdrv_dec_in_flight(bs); - bdrv_padding_destroy(&pad); +fail: + bdrv_dec_in_flight(bs); + return ret; } From 2a0396285daa9483459ec1d3791951300b595e85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 28 Jul 2021 19:38:05 +0200 Subject: [PATCH 474/531] hw/sd/sdcard: Document out-of-range addresses for SEND_WRITE_PROT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per the 'Physical Layer Simplified Specification Version 3.01', Table 4-22: 'Block Oriented Write Protection Commands' SEND_WRITE_PROT (CMD30) If the card provides write protection features, this command asks the card to send the status of the write protection bits [1]. [1] 32 write protection bits (representing 32 write protect groups starting at the specified address) [...] The last (least significant) bit of the protection bits corresponds to the first addressed group. If the addresses of the last groups are outside the valid range, then the corresponding write protection bits shall be set to 0. Split the if() statement (without changing the behaviour of the code) to better position the description comment. Reviewed-by: Alexander Bulekov Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210802235524.3417739-2-f4bug@amsat.org> Reviewed-by: Peter Maydell Tested-by: Alexander Bulekov --- hw/sd/sd.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 1f964e022b..707dcc12a1 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -822,7 +822,14 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr) for (i = 0; i < 32; i++, wpnum++, addr += WPGROUP_SIZE) { assert(wpnum < sd->wpgrps_size); - if (addr < sd->size && test_bit(wpnum, sd->wp_groups)) { + if (addr >= sd->size) { + /* + * If the addresses of the last groups are outside the valid range, + * then the corresponding write protection bits shall be set to 0. + */ + continue; + } + if (test_bit(wpnum, sd->wp_groups)) { ret |= (1 << i); } } From 4ac0b72bae85cf94ae0e5153b9c2c288c71667d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 3 Aug 2021 01:55:24 +0200 Subject: [PATCH 475/531] hw/sd/sdcard: Fix assertion accessing out-of-range addresses with CMD30 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OSS-Fuzz found sending illegal addresses when querying the write protection bits triggers the assertion added in commit 84816fb63e5 ("hw/sd/sdcard: Assert if accessing an illegal group"): qemu-fuzz-i386-target-generic-fuzz-sdhci-v3: ../hw/sd/sd.c:824: uint32_t sd_wpbits(SDState *, uint64_t): Assertion `wpnum < sd->wpgrps_size' failed. #3 0x7f62a8b22c91 in __assert_fail #4 0x5569adcec405 in sd_wpbits hw/sd/sd.c:824:9 #5 0x5569adce5f6d in sd_normal_command hw/sd/sd.c:1389:38 #6 0x5569adce3870 in sd_do_command hw/sd/sd.c:1737:17 #7 0x5569adcf1566 in sdbus_do_command hw/sd/core.c:100:16 #8 0x5569adcfc192 in sdhci_send_command hw/sd/sdhci.c:337:12 #9 0x5569adcfa3a3 in sdhci_write hw/sd/sdhci.c:1186:9 #10 0x5569adfb3447 in memory_region_write_accessor softmmu/memory.c:492:5 It is legal for the CMD30 to query for out-of-range addresses. Such invalid addresses are simply ignored in the response (write protection bits set to 0). In commit 84816fb63e5 ("hw/sd/sdcard: Assert if accessing an illegal group") we misplaced the assertion *before* we test the address is in range. Move it *after*. Include the qtest reproducer provided by Alexander Bulekov: $ make check-qtest-i386 ... Running test qtest-i386/fuzz-sdcard-test qemu-system-i386: ../hw/sd/sd.c:824: sd_wpbits: Assertion `wpnum < sd->wpgrps_size' failed. Cc: qemu-stable@nongnu.org Reported-by: OSS-Fuzz (Issue 29225) Suggested-by: Peter Maydell Fixes: 84816fb63e5 ("hw/sd/sdcard: Assert if accessing an illegal group") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/495 Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210802235524.3417739-3-f4bug@amsat.org> Reviewed-by: Peter Maydell Tested-by: Alexander Bulekov --- hw/sd/sd.c | 2 +- tests/qtest/fuzz-sdcard-test.c | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 707dcc12a1..bb5dbff68c 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -821,7 +821,6 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr) wpnum = sd_addr_to_wpnum(addr); for (i = 0; i < 32; i++, wpnum++, addr += WPGROUP_SIZE) { - assert(wpnum < sd->wpgrps_size); if (addr >= sd->size) { /* * If the addresses of the last groups are outside the valid range, @@ -829,6 +828,7 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr) */ continue; } + assert(wpnum < sd->wpgrps_size); if (test_bit(wpnum, sd->wp_groups)) { ret |= (1 << i); } diff --git a/tests/qtest/fuzz-sdcard-test.c b/tests/qtest/fuzz-sdcard-test.c index 96602eac7e..ae14305344 100644 --- a/tests/qtest/fuzz-sdcard-test.c +++ b/tests/qtest/fuzz-sdcard-test.c @@ -52,6 +52,41 @@ static void oss_fuzz_29225(void) qtest_quit(s); } +/* + * https://gitlab.com/qemu-project/qemu/-/issues/495 + * Used to trigger: + * Assertion `wpnum < sd->wpgrps_size' failed. + */ +static void oss_fuzz_36217(void) +{ + QTestState *s; + + s = qtest_init(" -display none -m 32 -nodefaults -nographic" + " -device sdhci-pci,sd-spec-version=3 " + "-device sd-card,drive=d0 " + "-drive if=none,index=0,file=null-co://,format=raw,id=d0"); + + qtest_outl(s, 0xcf8, 0x80001010); + qtest_outl(s, 0xcfc, 0xe0000000); + qtest_outl(s, 0xcf8, 0x80001004); + qtest_outw(s, 0xcfc, 0x02); + qtest_bufwrite(s, 0xe000002c, "\x05", 0x1); + qtest_bufwrite(s, 0xe000000f, "\x37", 0x1); + qtest_bufwrite(s, 0xe000000a, "\x01", 0x1); + qtest_bufwrite(s, 0xe000000f, "\x29", 0x1); + qtest_bufwrite(s, 0xe000000f, "\x02", 0x1); + qtest_bufwrite(s, 0xe000000f, "\x03", 0x1); + qtest_bufwrite(s, 0xe0000005, "\x01", 0x1); + qtest_bufwrite(s, 0xe000000f, "\x06", 0x1); + qtest_bufwrite(s, 0xe000000c, "\x05", 0x1); + qtest_bufwrite(s, 0xe000000e, "\x20", 0x1); + qtest_bufwrite(s, 0xe000000f, "\x08", 0x1); + qtest_bufwrite(s, 0xe000000b, "\x3d", 0x1); + qtest_bufwrite(s, 0xe000000f, "\x1e", 0x1); + + qtest_quit(s); +} + int main(int argc, char **argv) { const char *arch = qtest_get_arch(); @@ -60,6 +95,7 @@ int main(int argc, char **argv) if (strcmp(arch, "i386") == 0) { qtest_add_func("fuzz/sdcard/oss_fuzz_29225", oss_fuzz_29225); + qtest_add_func("fuzz/sdcard/oss_fuzz_36217", oss_fuzz_36217); } return g_test_run(); From e2a6290aab578b2170c1f5909fa556385dc0d820 Mon Sep 17 00:00:00 2001 From: Marcel Apfelbaum Date: Mon, 2 Aug 2021 12:00:57 +0300 Subject: [PATCH 476/531] hw/pcie-root-port: Fix hotplug for PCI devices requiring IO Q35 has now ACPI hotplug enabled by default for PCI(e) devices. As opposed to native PCIe hotplug, guests like Fedora 34 will not assign IO range to pcie-root-ports not supporting native hotplug, resulting into a regression. Reproduce by: qemu-bin -M q35 -device pcie-root-port,id=p1 -monitor stdio device_add e1000,bus=p1 In the Guest OS the respective pcie-root-port will have the IO range disabled. Fix it by setting the "reserve-io" hint capability of the pcie-root-ports so the firmware will allocate the IO range instead. Acked-by: Igor Mammedov Signed-off-by: Marcel Apfelbaum Message-Id: <20210802090057.1709775-1-marcel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-bridge/gen_pcie_root_port.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c index ec9907917e..20099a8ae3 100644 --- a/hw/pci-bridge/gen_pcie_root_port.c +++ b/hw/pci-bridge/gen_pcie_root_port.c @@ -28,6 +28,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(GenPCIERootPort, GEN_PCIE_ROOT_PORT) (GEN_PCIE_ROOT_PORT_AER_OFFSET + PCI_ERR_SIZEOF) #define GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR 1 +#define GEN_PCIE_ROOT_DEFAULT_IO_RANGE 4096 struct GenPCIERootPort { /*< private >*/ @@ -75,6 +76,7 @@ static bool gen_rp_test_migrate_msix(void *opaque, int version_id) static void gen_rp_realize(DeviceState *dev, Error **errp) { PCIDevice *d = PCI_DEVICE(dev); + PCIESlot *s = PCIE_SLOT(d); GenPCIERootPort *grp = GEN_PCIE_ROOT_PORT(d); PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d); Error *local_err = NULL; @@ -85,6 +87,9 @@ static void gen_rp_realize(DeviceState *dev, Error **errp) return; } + if (grp->res_reserve.io == -1 && s->hotplug && !s->native_hotplug) { + grp->res_reserve.io = GEN_PCIE_ROOT_DEFAULT_IO_RANGE; + } int rc = pci_bridge_qemu_reserve_cap_init(d, 0, grp->res_reserve, errp); From d7346e614f4ec353f9b24bb69bfeaf1ade287e07 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 23 Jul 2021 05:04:24 -0400 Subject: [PATCH 477/531] acpi: x86: pcihp: add support hotplug on multifunction bridges Commit [1] switched PCI hotplug from native to ACPI one by default. That however breaks hotplug on following CLI that used to work: -nodefaults -machine q35 \ -device pcie-root-port,id=pcie-root-port-0,multifunction=on,bus=pcie.0,addr=0x1,chassis=1 \ -device pcie-root-port,id=pcie-root-port-1,port=0x1,addr=0x1.0x1,bus=pcie.0,chassis=2 where PCI device is hotplugged to pcie-root-port-1 with error on guest side: ACPI BIOS Error (bug): Could not resolve symbol [^S0B.PCNT], AE_NOT_FOUND (20201113/psargs-330) ACPI Error: Aborting method \_SB.PCI0.PCNT due to previous error (AE_NOT_FOUND) (20201113/psparse-531) ACPI Error: Aborting method \_GPE._E01 due to previous error (AE_NOT_FOUND) (20201113/psparse-531) ACPI Error: AE_NOT_FOUND, while evaluating GPE method [_E01] (20201113/evgpe-515) cause is that QEMU's ACPI hotplug never supported functions other then 0 and due to bug it was generating notification entries for not described functions. Technically there is no reason not to describe cold-plugged bridges (root ports) on functions other then 0, as they similarly to bridge on function 0 are unpluggable. So since we need to describe multifunction devices iterate over fuctions as well. But describe only cold-plugged bridges[root ports] on functions other than 0 as well. 1) Fixes: 17858a169508609ca9063c544833e5a1adeb7b52 (hw/acpi/ich9: Set ACPI PCI hot-plug as default on Q35) Signed-off-by: Igor Mammedov Reported-by: Laurent Vivier Message-Id: <20210723090424.2092226-1-imammedo@redhat.com> Fixes: 17858a169508609ca9063c544833e5a1adeb7b52 (hw/acpi/ich9: Set ACPI PCI hot-plug as default on Q35)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reported-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 17836149fe..a33ac8b91e 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -374,7 +374,7 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, Aml *dev, *notify_method = NULL, *method; QObject *bsel; PCIBus *sec; - int i; + int devfn; bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); if (bsel) { @@ -384,23 +384,31 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED); } - for (i = 0; i < ARRAY_SIZE(bus->devices); i += PCI_FUNC_MAX) { + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { DeviceClass *dc; PCIDeviceClass *pc; - PCIDevice *pdev = bus->devices[i]; - int slot = PCI_SLOT(i); + PCIDevice *pdev = bus->devices[devfn]; + int slot = PCI_SLOT(devfn); + int func = PCI_FUNC(devfn); + /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */ + int adr = slot << 16 | func; bool hotplug_enabled_dev; bool bridge_in_acpi; bool cold_plugged_bridge; if (!pdev) { - if (bsel) { /* add hotplug slots for non present devices */ + /* + * add hotplug slots for non present devices. + * hotplug is supported only for non-multifunction device + * so generate device description only for function 0 + */ + if (bsel && !func) { if (pci_bus_is_express(bus) && slot > 0) { break; } - dev = aml_device("S%.02X", PCI_DEVFN(slot, 0)); + dev = aml_device("S%.02X", devfn); aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); - aml_append(dev, aml_name_decl("_ADR", aml_int(slot << 16))); + aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); aml_append(method, aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) @@ -436,9 +444,18 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, continue; } - /* start to compose PCI slot descriptor */ - dev = aml_device("S%.02X", PCI_DEVFN(slot, 0)); - aml_append(dev, aml_name_decl("_ADR", aml_int(slot << 16))); + /* + * allow describing coldplugged bridges in ACPI even if they are not + * on function 0, as they are not unpluggable, for all other devices + * generate description only for function 0 per slot + */ + if (func && !bridge_in_acpi) { + continue; + } + + /* start to compose PCI device descriptor */ + dev = aml_device("S%.02X", devfn); + aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); if (bsel) { /* @@ -496,7 +513,7 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en); } - /* slot descriptor has been composed, add it into parent context */ + /* device descriptor has been composed, add it into parent context */ aml_append(parent_scope, dev); } @@ -525,13 +542,12 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, /* Notify about child bus events in any case */ if (pcihp_bridge_en) { QLIST_FOREACH(sec, &bus->child, sibling) { - int32_t devfn = sec->parent_dev->devfn; - if (pci_bus_is_root(sec)) { continue; } - aml_append(method, aml_name("^S%.02X.PCNT", devfn)); + aml_append(method, aml_name("^S%.02X.PCNT", + sec->parent_dev->devfn)); } } From 5cd4a8d4e567a6d52553c2133bf1c9b008d80481 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 3 Aug 2021 16:13:10 -0400 Subject: [PATCH 478/531] arm/acpi: allow DSDT changes We are going to commit ccee1a8140 ("acpi: Update _DSM method in expected files"). Allow changes to DSDT on ARM. Only configs with pci are affected thus all virt variants but for microvm only the pcie variant. Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..8a7fe463c5 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,6 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/virt/DSDT", +"tests/data/acpi/virt/DSDT.memhp", +"tests/data/acpi/virt/DSDT.numamem", +"tests/data/acpi/virt/DSDT.pxb", +"tests/data/acpi/microvm/DSDT.pcie", From 40c3472a29c9a1fd65255fc196aa6feb99aaec9e Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 27 Jul 2021 05:18:47 -0400 Subject: [PATCH 479/531] Revert "acpi/gpex: Inform os to keep firmware resource map" This reverts commit 0cf8882fd06ba0aeb1e90fa6f23fce85504d7e14. Which this commit, with aarch64 when using efi PCI devices with IO ports do not work. The reason is that EFI creates I/O port mappings below 0x1000 (in fact, at 0). However Linux, for legacy reasons, does not support I/O ports <= 0x1000 on PCI, so the I/O assignment created by EFI is rejected. EFI creates the mappings primarily for itself, and up until DSM #5 started to be enforced, all PCI resource allocations that existed at boot were ignored by Linux and recreated from scratch. Also, the commit in question looks dubious - it seems unlikely that Linux would fail to create a resource tree. What does happen is that BARs get moved around, which may cause trouble in some cases: for instance, Linux had to add special code to the EFI framebuffer driver to copy with framebuffer BARs being relocated. DSM #5 has a long history of debate and misinterpretation. Link: https://lore.kernel.org/r/20210724185234.GA2265457@roeck-us.net/ Fixes: 0cf8882fd06 ("acpi/gpex: Inform os to keep firmware resource map") Reported-by: Guenter Roeck Suggested-by: Ard Biesheuvel Acked-by: Ard Biesheuvel Tested-by: Guenter Roeck Signed-off-by: Michael S. Tsirkin --- hw/pci-host/gpex-acpi.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c index 0f01f13a6e..e7e162a00a 100644 --- a/hw/pci-host/gpex-acpi.c +++ b/hw/pci-host/gpex-acpi.c @@ -112,26 +112,10 @@ static void acpi_dsdt_add_pci_osc(Aml *dev) UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D"); ifctx = aml_if(aml_equal(aml_arg(0), UUID)); ifctx1 = aml_if(aml_equal(aml_arg(2), aml_int(0))); - uint8_t byte_list[] = { - 0x1 << 0 /* support for functions other than function 0 */ | - 0x1 << 5 /* support for function 5 */ - }; - buf = aml_buffer(ARRAY_SIZE(byte_list), byte_list); + uint8_t byte_list[1] = {1}; + buf = aml_buffer(1, byte_list); aml_append(ifctx1, aml_return(buf)); aml_append(ifctx, ifctx1); - - /* - * PCI Firmware Specification 3.1 - * 4.6.5. _DSM for Ignoring PCI Boot Configurations - */ - /* Arg2: Function Index: 5 */ - ifctx1 = aml_if(aml_equal(aml_arg(2), aml_int(5))); - /* - * 0 - The operating system must not ignore the PCI configuration that - * firmware has done at boot time. - */ - aml_append(ifctx1, aml_return(aml_int(0))); - aml_append(ifctx, ifctx1); aml_append(method, ifctx); byte_list[0] = 0; From 62a4db5522cbbd8b5309a2949c22f00e5b0138e3 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 3 Aug 2021 16:20:22 -0400 Subject: [PATCH 480/531] Drop _DSM 5 from expected DSDTs on ARM diff -rup /tmp/old/tests/data/acpi/microvm/DSDT.pcie.dsl /tmp/new/tests/data/acpi/microvm/DSDT.pcie.dsl --- /tmp/old/tests/data/acpi/microvm/DSDT.pcie.dsl 2021-08-03 16:22:52.289295442 -0400 +++ /tmp/new/tests/data/acpi/microvm/DSDT.pcie.dsl 2021-08-03 16:22:40.102286317 -0400 @@ -1302,14 +1302,9 @@ DefinitionBlock ("", "DSDT", 2, "BOCHS " { Return (Buffer (One) { - 0x21 // ! + 0x01 // . }) } - - If ((Arg2 == 0x05)) - { - Return (Zero) - } } Return (Buffer (One) Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/microvm/DSDT.pcie | Bin 3031 -> 3023 bytes tests/data/acpi/virt/DSDT | Bin 5204 -> 5196 bytes tests/data/acpi/virt/DSDT.memhp | Bin 6565 -> 6557 bytes tests/data/acpi/virt/DSDT.numamem | Bin 5204 -> 5196 bytes tests/data/acpi/virt/DSDT.pxb | Bin 7695 -> 7679 bytes tests/qtest/bios-tables-test-allowed-diff.h | 5 ----- 6 files changed, 5 deletions(-) diff --git a/tests/data/acpi/microvm/DSDT.pcie b/tests/data/acpi/microvm/DSDT.pcie index 3fb373fd970f0a33f30f57b1917720754396f0e9..765f14ef3d1e54d3cadccbf0a880f8adb73b3f1f 100644 GIT binary patch delta 51 zcmcaEeqNl*CD#U6GCFLIXMD`bp&RcK?8~x1ak3Y;JR{@e HBJNZGj^hr8 delta 59 zcmX>veqEf)CDA8`aGj89g?~Gd||zFpYN!_GMY1IoXR_o>OrF P`{XPx)+G#+v$#_M_<|6J diff --git a/tests/data/acpi/virt/DSDT b/tests/data/acpi/virt/DSDT index 134d8ae5b602e0aaade6756b99c9abca45279284..c47503990715d389914fdf9c8bccb510761741ac 100644 GIT binary patch delta 50 zcmcbjaYlp7CD?thI$T+!B G_%Q%n84Z^J delta 58 zcmX@3aYcj6CD diff --git a/tests/data/acpi/virt/DSDT.memhp b/tests/data/acpi/virt/DSDT.memhp index 140976b23ebea792bec12435a2a547ac5f5cd8f9..bae36cdd397473afe3923c52f030641a5ab19d5d 100644 GIT binary patch delta 52 zcmZ2#JlB}ZCDyi;GWjiE?8wQ*p&RcK?8~x1ak8hdJR{@g ILSYj&0ETJ})&Kwi delta 60 zcmbPhywsS>CDOrF Q`{XPx)+G#^Glfmq0PR!{)&Kwi diff --git a/tests/data/acpi/virt/DSDT.numamem b/tests/data/acpi/virt/DSDT.numamem index 134d8ae5b602e0aaade6756b99c9abca45279284..c47503990715d389914fdf9c8bccb510761741ac 100644 GIT binary patch delta 50 zcmcbjaYlp7CD?thI$T+!B G_%Q%n84Z^J delta 58 zcmX@3aYcj6CD diff --git a/tests/data/acpi/virt/DSDT.pxb b/tests/data/acpi/virt/DSDT.pxb index 46b9c4cad5d65cb1b578410fb3168b70a05021be..fbd78f44c4785d19759daea909fe6d6f9a6e6b01 100644 GIT binary patch delta 78 zcmeCT`ESkT66_N4UzUM^Y5znn8OFOC)g?F?9XC60Hgj_5#=8XjvMf-Xd|F7Ji*bn{ YGb2NEli%{ie}uSD&QL^0Gn_Z9smFU delta 94 zcmexw-EYI?66_MfFUP>ZG;bo84CB3x>Jprco|_#wn>jg5<6VM%Sr%wc{v#tVq_}{6 hauyfs5{4y$%!~}tO>Qd|e-YwBQNsyWGg(IVF#z_a8;k$| diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 8a7fe463c5..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,6 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/virt/DSDT", -"tests/data/acpi/virt/DSDT.memhp", -"tests/data/acpi/virt/DSDT.numamem", -"tests/data/acpi/virt/DSDT.pxb", -"tests/data/acpi/microvm/DSDT.pcie", From e0366f9f2ba22cea264dac26e03120fc153653ed Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 12 Jul 2021 17:02:14 +0200 Subject: [PATCH 481/531] docs/devel/qapi-code-gen: Update examples to match current code Signed-off-by: Markus Armbruster Message-Id: <20210712150214.624281-1-armbru@redhat.com> Acked-by: John Snow --- docs/devel/qapi-code-gen.txt | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index c1cb6f987d..233022184b 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -1496,8 +1496,12 @@ Example: bool visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error **errp); - bool visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, Error **errp); - bool visit_type_UserDefOneList(Visitor *v, const char *name, UserDefOneList **obj, Error **errp); + + bool visit_type_UserDefOne(Visitor *v, const char *name, + UserDefOne **obj, Error **errp); + + bool visit_type_UserDefOneList(Visitor *v, const char *name, + UserDefOneList **obj, Error **errp); bool visit_type_q_obj_my_command_arg_members(Visitor *v, q_obj_my_command_arg *obj, Error **errp); @@ -1518,7 +1522,8 @@ Example: return true; } - bool visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, Error **errp) + bool visit_type_UserDefOne(Visitor *v, const char *name, + UserDefOne **obj, Error **errp) { bool ok = false; @@ -1528,6 +1533,7 @@ Example: if (!*obj) { /* incomplete */ assert(visit_is_dealloc(v)); + ok = true; goto out_obj; } if (!visit_type_UserDefOne_members(v, *obj, errp)) { @@ -1543,7 +1549,8 @@ Example: return ok; } - bool visit_type_UserDefOneList(Visitor *v, const char *name, UserDefOneList **obj, Error **errp) + bool visit_type_UserDefOneList(Visitor *v, const char *name, + UserDefOneList **obj, Error **errp) { bool ok = false; UserDefOneList *tail; @@ -1628,11 +1635,13 @@ Example: $ cat qapi-generated/example-qapi-commands.c [Uninteresting stuff omitted...] - static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, QObject **ret_out, Error **errp) + + static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, + QObject **ret_out, Error **errp) { Visitor *v; - v = qobject_output_visitor_new(ret_out); + v = qobject_output_visitor_new_qmp(ret_out); if (visit_type_UserDefOne(v, "unused", &ret_in, errp)) { visit_complete(v, ret_out); } @@ -1650,7 +1659,7 @@ Example: UserDefOne *retval; q_obj_my_command_arg arg = {0}; - v = qobject_input_visitor_new(QOBJECT(args)); + v = qobject_input_visitor_new_qmp(QOBJECT(args)); if (!visit_start_struct(v, NULL, NULL, 0, errp)) { goto out; } From f7aa076dbdfcd569c79166ff0980c261190a5d53 Mon Sep 17 00:00:00 2001 From: John Snow Date: Tue, 20 Jul 2021 19:56:17 -0400 Subject: [PATCH 482/531] docs: convert qapi-code-gen.txt to ReST This is a very rudimentary conversion from .txt to .rst changing as little as possible, but getting it to render somewhat nicely; without using any Sphinx directives. (It is 'native' ReST.) Further patches will add cross-references and Sphinx-specific extensions to make it sparkle. Signed-off-by: John Snow Message-Id: <20210720235619.2048797-2-jsnow@redhat.com> Reviewed-by: Peter Maydell Signed-off-by: Markus Armbruster --- docs/devel/index.rst | 1 + .../{qapi-code-gen.txt => qapi-code-gen.rst} | 559 ++++++++++-------- 2 files changed, 312 insertions(+), 248 deletions(-) rename docs/devel/{qapi-code-gen.txt => qapi-code-gen.rst} (86%) diff --git a/docs/devel/index.rst b/docs/devel/index.rst index 153979caf4..bfba3a8daa 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -42,3 +42,4 @@ modifying QEMU's source code. multi-process ebpf_rss vfio-migration + qapi-code-gen diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.rst similarity index 86% rename from docs/devel/qapi-code-gen.txt rename to docs/devel/qapi-code-gen.rst index 233022184b..9155dba262 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.rst @@ -1,12 +1,17 @@ -= How to use the QAPI code generator = +================================== +How to use the QAPI code generator +================================== -Copyright IBM Corp. 2011 -Copyright (C) 2012-2016 Red Hat, Inc. +.. + Copyright IBM Corp. 2011 + Copyright (C) 2012-2016 Red Hat, Inc. -This work is licensed under the terms of the GNU GPL, version 2 or -later. See the COPYING file in the top-level directory. + This work is licensed under the terms of the GNU GPL, version 2 or + later. See the COPYING file in the top-level directory. -== Introduction == + +Introduction +============ QAPI is a native C API within QEMU which provides management-level functionality to internal and external users. For external @@ -23,7 +28,8 @@ Protocol and to C. It additionally provides guidance on maintaining Client JSON Protocol compatibility. -== The QAPI schema language == +The QAPI schema language +======================== The QAPI schema defines the Client JSON Protocol's commands and events, as well as types used by them. Forward references are @@ -39,9 +45,10 @@ complex types (structs and two flavors of unions), and alternate types (a choice between other types). -=== Schema syntax === +Schema syntax +------------- -Syntax is loosely based on JSON (http://www.ietf.org/rfc/rfc8259.txt). +Syntax is loosely based on `JSON `_. Differences: * Comments: start with a hash character (#) that is not part of a @@ -79,7 +86,7 @@ syntax in an EBNF-like notation: The order of members within JSON objects does not matter unless explicitly noted. -A QAPI schema consists of a series of top-level expressions: +A QAPI schema consists of a series of top-level expressions:: SCHEMA = TOP-LEVEL-EXPR... @@ -87,11 +94,11 @@ The top-level expressions are all JSON objects. Code and documentation is generated in schema definition order. Code order should not matter. -A top-level expressions is either a directive or a definition: +A top-level expressions is either a directive or a definition:: TOP-LEVEL-EXPR = DIRECTIVE | DEFINITION -There are two kinds of directives and six kinds of definitions: +There are two kinds of directives and six kinds of definitions:: DIRECTIVE = INCLUDE | PRAGMA DEFINITION = ENUM | STRUCT | UNION | ALTERNATE | COMMAND | EVENT @@ -99,9 +106,10 @@ There are two kinds of directives and six kinds of definitions: These are discussed in detail below. -=== Built-in Types === +Built-in Types +-------------- -The following types are predefined, and map to C as follows: +The following types are predefined, and map to C as follows:: Schema C JSON str char * any JSON string, UTF-8 @@ -124,12 +132,14 @@ The following types are predefined, and map to C as follows: QType QType JSON string matching enum QType values -=== Include directives === +Include directives +------------------ + +Syntax:: -Syntax: INCLUDE = { 'include': STRING } -The QAPI schema definitions can be modularized using the 'include' directive: +The QAPI schema definitions can be modularized using the 'include' directive:: { 'include': 'path/to/file.json' } @@ -144,9 +154,11 @@ an outer file. The parser may be made stricter in the future to prevent incomplete include files. -=== Pragma directives === +Pragma directives +----------------- + +Syntax:: -Syntax: PRAGMA = { 'pragma': { '*doc-required': BOOL, '*command-name-exceptions': [ STRING, ... ], @@ -172,9 +184,11 @@ names may contain uppercase letters, and '_' instead of '-'. Default is none. -=== Enumeration types === +Enumeration types +----------------- + +Syntax:: -Syntax: ENUM = { 'enum': STRING, 'data': [ ENUM-VALUE, ... ], '*prefix': STRING, @@ -189,7 +203,7 @@ Each member of the 'data' array defines a value of the enumeration type. The form STRING is shorthand for { 'name': STRING }. The 'name' values must be be distinct. -Example: +Example:: { 'enum': 'MyEnum', 'data': [ 'value1', 'value2', 'value3' ] } @@ -218,9 +232,11 @@ The optional 'features' member specifies features. See "Features" below for more on this. -=== Type references and array types === +Type references and array types +------------------------------- + +Syntax:: -Syntax: TYPE-REF = STRING | ARRAY-TYPE ARRAY-TYPE = [ STRING ] @@ -230,9 +246,11 @@ A one-element array containing a string denotes an array of the type named by the string. Example: ['int'] denotes an array of 'int'. -=== Struct types === +Struct types +------------ + +Syntax:: -Syntax: STRUCT = { 'struct': STRING, 'data': MEMBERS, '*base': STRING, @@ -254,7 +272,7 @@ struct member name. If '*' is present, the member is optional. The MEMBER's value defines its properties, in particular its type. The form TYPE-REF is shorthand for { 'type': TYPE-REF }. -Example: +Example:: { 'struct': 'MyType', 'data': { 'member1': 'str', 'member2': ['int'], '*member3': 'str' } } @@ -265,7 +283,7 @@ The C struct's members are generated in QAPI schema order. The optional 'base' member names a struct type whose members are to be included in this type. They go first in the C struct. -Example: +Example:: { 'struct': 'BlockdevOptionsGenericFormat', 'data': { 'file': 'str' } } @@ -274,7 +292,7 @@ Example: 'data': { '*backing': 'str' } } An example BlockdevOptionsGenericCOWFormat object on the wire could use -both members like this: +both members like this:: { "file": "/some/place/my-image", "backing": "/some/place/my-backing-file" } @@ -286,9 +304,11 @@ The optional 'features' member specifies features. See "Features" below for more on this. -=== Union types === +Union types +----------- + +Syntax:: -Syntax: UNION = { 'union': STRING, 'data': BRANCHES, '*if': COND, @@ -317,7 +337,7 @@ The BRANCH's value defines the branch's properties, in particular its type. The form TYPE-REF is shorthand for { 'type': TYPE-REF }. A simple union type defines a mapping from automatic discriminator -values to data types like in this example: +values to data types like in this example:: { 'struct': 'BlockdevOptionsFile', 'data': { 'filename': 'str' } } { 'struct': 'BlockdevOptionsQcow2', @@ -330,7 +350,7 @@ values to data types like in this example: In the Client JSON Protocol, a simple union is represented by an object that contains the 'type' member as a discriminator, and a 'data' member that is of the specified data type corresponding to the -discriminator value, as in these examples: +discriminator value, as in these examples:: { "type": "file", "data": { "filename": "/some/place/my-image" } } { "type": "qcow2", "data": { "backing": "/some/place/my-image", @@ -361,7 +381,7 @@ struct. The following example enhances the above simple union example by adding an optional common member 'read-only', renaming the discriminator to something more applicable than the simple union's -default of 'type', and reducing the number of {} required on the wire: +default of 'type', and reducing the number of {} required on the wire:: { 'enum': 'BlockdevDriver', 'data': [ 'file', 'qcow2' ] } { 'union': 'BlockdevOptions', @@ -370,7 +390,7 @@ default of 'type', and reducing the number of {} required on the wire: 'data': { 'file': 'BlockdevOptionsFile', 'qcow2': 'BlockdevOptionsQcow2' } } -Resulting in these JSON objects: +Resulting in these JSON objects:: { "driver": "file", "read-only": true, "filename": "/some/place/my-image" } @@ -390,11 +410,11 @@ struct. A simple union can always be re-written as a flat union where the base class has a single member named 'type', and where each branch of the -union has a struct with a single member named 'data'. That is, +union has a struct with a single member named 'data'. That is, :: { 'union': 'Simple', 'data': { 'one': 'str', 'two': 'int' } } -is identical on the wire to: +is identical on the wire to:: { 'enum': 'Enum', 'data': ['one', 'two'] } { 'struct': 'Branch1', 'data': { 'data': 'str' } } @@ -409,9 +429,11 @@ The optional 'features' member specifies features. See "Features" below for more on this. -=== Alternate types === +Alternate types +--------------- + +Syntax:: -Syntax: ALTERNATE = { 'alternate': STRING, 'data': ALTERNATIVES, '*if': COND, @@ -430,7 +452,7 @@ The ALTERNATIVE's STRING name is the branch name. The ALTERNATIVE's value defines the branch's properties, in particular its type. The form STRING is shorthand for { 'type': STRING }. -Example: +Example:: { 'alternate': 'BlockdevRef', 'data': { 'definition': 'BlockdevOptions', @@ -449,7 +471,7 @@ as the 'null' built-in, it accepts JSON null; and if it is typed as a complex type (struct or union), it accepts a JSON object. The example alternate declaration above allows using both of the -following example objects: +following example objects:: { "file": "my_existing_block_device_id" } { "file": { "driver": "file", @@ -463,9 +485,11 @@ The optional 'features' member specifies features. See "Features" below for more on this. -=== Commands === +Commands +-------- + +Syntax:: -Syntax: COMMAND = { 'command': STRING, ( '*data': ( MEMBERS | STRING ), @@ -508,7 +532,7 @@ member is the command name. The value of the "arguments" member then has to conform to the arguments, and the value of the success response's "return" member will conform to the return type. -Some example commands: +Some example commands:: { 'command': 'my-first-command', 'data': { 'arg1': 'str', '*arg2': 'str' } } @@ -516,7 +540,7 @@ Some example commands: { 'command': 'my-second-command', 'returns': [ 'MyType' ] } -which would validate this Client JSON Protocol transaction: +which would validate this Client JSON Protocol transaction:: => { "execute": "my-first-command", "arguments": { "arg1": "hello" } } @@ -543,7 +567,7 @@ In rare cases, QAPI cannot express a type-safe representation of a corresponding Client JSON Protocol command. You then have to suppress generation of a marshalling function by including a member 'gen' with boolean value false, and instead write your own function. For -example: +example:: { 'command': 'netdev_add', 'data': {'type': 'str', 'id': 'str'}, @@ -561,7 +585,7 @@ the command definition includes the optional member 'success-response' with boolean value false. So far, only QGA makes use of this member. Member 'allow-oob' declares whether the command supports out-of-band -(OOB) execution. It defaults to false. For example: +(OOB) execution. It defaults to false. For example:: { 'command': 'migrate_recover', 'data': { 'uri': 'str' }, 'allow-oob': true } @@ -594,7 +618,7 @@ other "slow" lock. When in doubt, do not implement OOB execution support. Member 'allow-preconfig' declares whether the command is available -before the machine is built. It defaults to false. For example: +before the machine is built. It defaults to false. For example:: { 'enum': 'QMPCapability', 'data': [ 'oob' ] } @@ -640,9 +664,11 @@ The optional 'features' member specifies features. See "Features" below for more on this. -=== Events === +Events +------ + +Syntax:: -Syntax: EVENT = { 'event': STRING, ( '*data': ( MEMBERS | STRING ), @@ -665,16 +691,16 @@ data just like a struct type's 'data' defines struct type members. If 'data' is a STRING, then STRING names a complex type whose members are the event-specific data. A union type requires 'boxed': true. -An example event is: +An example event is:: -{ 'event': 'EVENT_C', - 'data': { '*a': 'int', 'b': 'str' } } + { 'event': 'EVENT_C', + 'data': { '*a': 'int', 'b': 'str' } } -Resulting in this JSON object: +Resulting in this JSON object:: -{ "event": "EVENT_C", - "data": { "b": "test string" }, - "timestamp": { "seconds": 1267020223, "microseconds": 435656 } } + { "event": "EVENT_C", + "data": { "b": "test string" }, + "timestamp": { "seconds": 1267020223, "microseconds": 435656 } } The generator emits a function to send the event. When member 'boxed' is absent, it takes event-specific data one by one, in QAPI schema @@ -688,9 +714,11 @@ The optional 'features' member specifies features. See "Features" below for more on this. -=== Features === +Features +-------- + +Syntax:: -Syntax: FEATURES = [ FEATURE, ... ] FEATURE = STRING | { 'name': STRING, '*if': COND } @@ -701,17 +729,17 @@ that previously resulted in an error). QMP clients may still need to know whether the extension is available. For this purpose, a list of features can be specified for a command or -struct type. Each list member can either be { 'name': STRING, '*if': -COND }, or STRING, which is shorthand for { 'name': STRING }. +struct type. Each list member can either be ``{ 'name': STRING, '*if': +COND }``, or STRING, which is shorthand for ``{ 'name': STRING }``. The optional 'if' member specifies a conditional. See "Configuring the schema" below for more on this. -Example: +Example:: -{ 'struct': 'TestType', - 'data': { 'number': 'int' }, - 'features': [ 'allow-negative-numbers' ] } + { 'struct': 'TestType', + 'data': { 'number': 'int' }, + 'features': [ 'allow-negative-numbers' ] } The feature strings are exposed to clients in introspection, as explained in section "Client JSON Protocol introspection". @@ -720,20 +748,22 @@ Intended use is to have each feature string signal that this build of QEMU shows a certain behaviour. -==== Special features ==== +Special features +~~~~~~~~~~~~~~~~ Feature "deprecated" marks a command, event, or struct member as deprecated. It is not supported elsewhere so far. -=== Naming rules and reserved names === +Naming rules and reserved names +------------------------------- All names must begin with a letter, and contain only ASCII letters, digits, hyphen, and underscore. There are two exceptions: enum values may start with a digit, and names that are downstream extensions (see section Downstream extensions) start with underscore. -Names beginning with 'q_' are reserved for the generator, which uses +Names beginning with 'q\_' are reserved for the generator, which uses them for munging QMP names that resemble C keywords or other problematic strings. For example, a member named "default" in qapi becomes "q_default" in the generated C code. @@ -753,7 +783,7 @@ consistency is preferred over blindly avoiding underscore. Event names should be ALL_CAPS with words separated by underscore. -Member name 'u' and names starting with 'has-' or 'has_' are reserved +Member name 'u' and names starting with 'has-' or 'has\_' are reserved for the generator, which uses them for unions and for tracking optional members. @@ -765,7 +795,8 @@ Pragmas 'command-name-exceptions' and 'member-name-exceptions' let you violate naming rules. Use for new code is strongly discouraged. -=== Downstream extensions === +Downstream extensions +--------------------- QAPI schema names that are externally visible, say in the Client JSON Protocol, need to be managed with care. Names starting with a @@ -777,9 +808,11 @@ Example: Red Hat, Inc. controls redhat.com, and may therefore add a downstream command __com.redhat_drive-mirror. -=== Configuring the schema === +Configuring the schema +---------------------- + +Syntax:: -Syntax: COND = STRING | [ STRING, ... ] @@ -788,12 +821,12 @@ string or a list of strings. A string is shorthand for a list containing just that string. The code generated for the definition will then be guarded by #if STRING for each STRING in the COND list. -Example: a conditional struct +Example: a conditional struct :: { 'struct': 'IfStruct', 'data': { 'foo': 'int' }, 'if': ['defined(CONFIG_FOO)', 'defined(HAVE_BAR)'] } -gets its generated code guarded like this: +gets its generated code guarded like this:: #if defined(CONFIG_FOO) #if defined(HAVE_BAR) @@ -806,11 +839,11 @@ event-specific data can also be made conditional. This requires the longhand form of MEMBER. Example: a struct type with unconditional member 'foo' and conditional -member 'bar' +member 'bar' :: -{ 'struct': 'IfStruct', 'data': - { 'foo': 'int', - 'bar': { 'type': 'int', 'if': 'defined(IFCOND)'} } } + { 'struct': 'IfStruct', 'data': + { 'foo': 'int', + 'bar': { 'type': 'int', 'if': 'defined(IFCOND)'} } } A union's discriminator may not be conditional. @@ -818,21 +851,21 @@ Likewise, individual enumeration values be conditional. This requires the longhand form of ENUM-VALUE. Example: an enum type with unconditional value 'foo' and conditional -value 'bar' +value 'bar' :: -{ 'enum': 'IfEnum', 'data': - [ 'foo', - { 'name' : 'bar', 'if': 'defined(IFCOND)' } ] } + { 'enum': 'IfEnum', 'data': + [ 'foo', + { 'name' : 'bar', 'if': 'defined(IFCOND)' } ] } Likewise, features can be conditional. This requires the longhand form of FEATURE. -Example: a struct with conditional feature 'allow-negative-numbers' +Example: a struct with conditional feature 'allow-negative-numbers' :: -{ 'struct': 'TestType', - 'data': { 'number': 'int' }, - 'features': [ { 'name': 'allow-negative-numbers', - 'if': 'defined(IFCOND)' } ] } + { 'struct': 'TestType', + 'data': { 'number': 'int' }, + 'features': [ { 'name': 'allow-negative-numbers', + 'if': 'defined(IFCOND)' } ] } Please note that you are responsible to ensure that the C code will compile with an arbitrary combination of conditions, since the @@ -843,12 +876,13 @@ shows a conditional entity only when the condition is satisfied in this particular build. -=== Documentation comments === +Documentation comments +---------------------- A multi-line comment that starts and ends with a '##' line is a documentation comment. -If the documentation comment starts like +If the documentation comment starts like :: ## # @SYMBOL: @@ -861,10 +895,12 @@ See below for more on definition documentation. Free-form documentation may be used to provide additional text and structuring content. -==== Headings and subheadings ==== + +Headings and subheadings +~~~~~~~~~~~~~~~~~~~~~~~~ A free-form documentation comment containing a line which starts with -some '=' symbols and then a space defines a section heading: +some '=' symbols and then a space defines a section heading:: ## # = This is a top level heading @@ -883,17 +919,19 @@ comment block. Section headings must always be correctly nested, so you can only define a third-level heading inside a second-level heading, and so on. -==== Documentation markup ==== + +Documentation markup +~~~~~~~~~~~~~~~~~~~~ Documentation comments can use most rST markup. In particular, -a '::' literal block can be used for examples: +a '::' literal block can be used for examples:: # :: # # Text of the example, may span # multiple lines -'*' starts an itemized list: +'*' starts an itemized list:: # * First item, may span # multiple lines @@ -901,7 +939,7 @@ a '::' literal block can be used for examples: You can also use '-' instead of '*'. -A decimal number followed by '.' starts a numbered list: +A decimal number followed by '.' starts a numbered list:: # 1. First item, may span # multiple lines @@ -920,24 +958,25 @@ backslash-escape it. As an extension beyond the usual rST syntax, you can also use '@foo' to reference a name in the schema; this is rendered the same way as '``foo``'. -Example: +Example:: -## -# Some text foo with **bold** and *emphasis* -# 1. with a list -# 2. like that -# -# And some code: -# -# :: -# -# $ echo foo -# -> do this -# <- get that -## + ## + # Some text foo with **bold** and *emphasis* + # 1. with a list + # 2. like that + # + # And some code: + # + # :: + # + # $ echo foo + # -> do this + # <- get that + ## -==== Definition documentation ==== +Definition documentation +~~~~~~~~~~~~~~~~~~~~~~~~ Definition documentation, if present, must immediately precede the definition it documents. @@ -956,14 +995,14 @@ text can start on the line following the '@argname:', in which case it must not be indented at all. It can also start on the same line as the '@argname:'. In this case if it spans multiple lines then second and subsequent lines must be indented to line up with the first -character of the first line of the description: +character of the first line of the description:: -# @argone: -# This is a two line description -# in the first style. -# -# @argtwo: This is a two line description -# in the second style. + # @argone: + # This is a two line description + # in the first style. + # + # @argtwo: This is a two line description + # in the second style. The number of spaces between the ':' and the text is not significant. @@ -997,52 +1036,53 @@ An 'Example' or 'Examples' section is automatically rendered entirely as literal fixed-width text. In other sections, the text is formatted, and rST markup can be used. -For example: +For example:: -## -# @BlockStats: -# -# Statistics of a virtual block device or a block backing device. -# -# @device: If the stats are for a virtual block device, the name -# corresponding to the virtual block device. -# -# @node-name: The node name of the device. (since 2.3) -# -# ... more members ... -# -# Since: 0.14.0 -## -{ 'struct': 'BlockStats', - 'data': {'*device': 'str', '*node-name': 'str', - ... more members ... } } + ## + # @BlockStats: + # + # Statistics of a virtual block device or a block backing device. + # + # @device: If the stats are for a virtual block device, the name + # corresponding to the virtual block device. + # + # @node-name: The node name of the device. (since 2.3) + # + # ... more members ... + # + # Since: 0.14.0 + ## + { 'struct': 'BlockStats', + 'data': {'*device': 'str', '*node-name': 'str', + ... more members ... } } -## -# @query-blockstats: -# -# Query the @BlockStats for all virtual block devices. -# -# @query-nodes: If true, the command will query all the -# block nodes ... explain, explain ... (since 2.3) -# -# Returns: A list of @BlockStats for each virtual block devices. -# -# Since: 0.14.0 -# -# Example: -# -# -> { "execute": "query-blockstats" } -# <- { -# ... lots of output ... -# } -# -## -{ 'command': 'query-blockstats', - 'data': { '*query-nodes': 'bool' }, - 'returns': ['BlockStats'] } + ## + # @query-blockstats: + # + # Query the @BlockStats for all virtual block devices. + # + # @query-nodes: If true, the command will query all the + # block nodes ... explain, explain ... (since 2.3) + # + # Returns: A list of @BlockStats for each virtual block devices. + # + # Since: 0.14.0 + # + # Example: + # + # -> { "execute": "query-blockstats" } + # <- { + # ... lots of output ... + # } + # + ## + { 'command': 'query-blockstats', + 'data': { '*query-nodes': 'bool' }, + 'returns': ['BlockStats'] } -== Client JSON Protocol introspection == +Client JSON Protocol introspection +================================== Clients of a Client JSON Protocol commonly need to figure out what exactly the server (QEMU) supports. @@ -1114,13 +1154,13 @@ If the command takes no arguments, "arg-type" names an object type without members. Likewise, if the command returns nothing, "ret-type" names an object type without members. -Example: the SchemaInfo for command query-qmp-schema +Example: the SchemaInfo for command query-qmp-schema :: - { "name": "query-qmp-schema", "meta-type": "command", - "arg-type": "q_empty", "ret-type": "SchemaInfoList" } + { "name": "query-qmp-schema", "meta-type": "command", + "arg-type": "q_empty", "ret-type": "SchemaInfoList" } - Type "q_empty" is an automatic object type without members, and type - "SchemaInfoList" is the array of SchemaInfo type. + Type "q_empty" is an automatic object type without members, and type + "SchemaInfoList" is the array of SchemaInfo type. The SchemaInfo for an event has meta-type "event", and variant member "arg-type". On the wire, a "data" member that the server passes in an @@ -1133,7 +1173,7 @@ the wire then. Each command or event defined with 'data' as MEMBERS object in the QAPI schema implicitly defines an object type. -Example: the SchemaInfo for EVENT_C from section Events +Example: the SchemaInfo for EVENT_C from section Events :: { "name": "EVENT_C", "meta-type": "event", "arg-type": "q_obj-EVENT_C-arg" } @@ -1157,7 +1197,7 @@ extensions. The "members" array is in no particular order; clients must search the entire object when learning whether a particular member is supported. -Example: the SchemaInfo for MyType from section Struct types +Example: the SchemaInfo for MyType from section Struct types :: { "name": "MyType", "meta-type": "object", "members": [ @@ -1168,7 +1208,7 @@ Example: the SchemaInfo for MyType from section Struct types "features" exposes the command's feature strings as a JSON array of strings. -Example: the SchemaInfo for TestType from section Features: +Example: the SchemaInfo for TestType from section Features:: { "name": "TestType", "meta-type": "object", "members": [ @@ -1184,7 +1224,7 @@ that provides the variant members for this type tag value). The list cases in the same order as the corresponding "tag" enum type. Example: the SchemaInfo for flat union BlockdevOptions from section -Union types +Union types :: { "name": "BlockdevOptions", "meta-type": "object", "members": [ @@ -1205,7 +1245,7 @@ A simple union implicitly defines an object type for each of its variants. Example: the SchemaInfo for simple union BlockdevOptionsSimple from section -Union types +Union types :: { "name": "BlockdevOptionsSimple", "meta-type": "object", "members": [ @@ -1225,7 +1265,7 @@ a JSON object with member "type", which names a type. Values of the alternate type conform to exactly one of its member types. There is no guarantee on the order in which "members" will be listed. -Example: the SchemaInfo for BlockdevRef from section Alternate types +Example: the SchemaInfo for BlockdevRef from section Alternate types :: { "name": "BlockdevRef", "meta-type": "alternate", "members": [ @@ -1239,7 +1279,7 @@ resemble the element type; however, clients should examine member "element-type" instead of making assumptions based on parsing member "name". -Example: the SchemaInfo for ['str'] +Example: the SchemaInfo for ['str'] :: { "name": "[str]", "meta-type": "array", "element-type": "str" } @@ -1249,7 +1289,7 @@ variant member "values". The values are listed in no particular order; clients must search the entire enum when learning whether a particular value is supported. -Example: the SchemaInfo for MyEnum from section Enumeration types +Example: the SchemaInfo for MyEnum from section Enumeration types :: { "name": "MyEnum", "meta-type": "enum", "values": [ "value1", "value2", "value3" ] } @@ -1259,7 +1299,7 @@ the QAPI schema (see section Built-in Types), with one exception detailed below. It has variant member "json-type" that shows how values of this type are encoded on the wire. -Example: the SchemaInfo for str +Example: the SchemaInfo for str :: { "name": "str", "meta-type": "builtin", "json-type": "string" } @@ -1273,7 +1313,8 @@ the names of built-in types. Clients should examine member "json-type" instead of hard-coding names of built-in types. -== Compatibility considerations == +Compatibility considerations +============================ Maintaining backward compatibility at the Client JSON Protocol level while evolving the schema requires some care. This section is about @@ -1333,7 +1374,8 @@ may be freely renamed. Even certain refactorings are invisible, such as splitting members from one type into a common base type. -== Code generation == +Code generation +=============== The QAPI code generator qapi-gen.py generates code and documentation from the schema. Together with the core QAPI libraries, this code @@ -1347,7 +1389,7 @@ As an example, we'll use the following schema, which describes a single complex user-defined type, along with command which takes a list of that type as a parameter, and returns a single element of that type. The user is responsible for writing the implementation of -qmp_my_command(); everything else is produced by the generator. +qmp_my_command(); everything else is produced by the generator. :: $ cat example-schema.json { 'struct': 'UserDefOne', @@ -1359,7 +1401,7 @@ qmp_my_command(); everything else is produced by the generator. { 'event': 'MY_EVENT' } -We run qapi-gen.py like this: +We run qapi-gen.py like this:: $ python scripts/qapi-gen.py --output-dir="qapi-generated" \ --prefix="example-" example-schema.json @@ -1369,24 +1411,27 @@ tests/qapi-schema/qapi-schema-tests.json that covers more examples of what the generator will accept, and compiles the resulting C code as part of 'make check-unit'. -=== Code generated for QAPI types === + +Code generated for QAPI types +----------------------------- The following files are created: -$(prefix)qapi-types.h - C types corresponding to types defined in - the schema + ``$(prefix)qapi-types.h`` + C types corresponding to types defined in the schema -$(prefix)qapi-types.c - Cleanup functions for the above C types + ``$(prefix)qapi-types.c`` + Cleanup functions for the above C types The $(prefix) is an optional parameter used as a namespace to keep the generated code from one schema/code-generation separated from others so code can be generated/used from multiple schemas without clobbering previously created code. -Example: +Example:: $ cat qapi-generated/example-qapi-types.h -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] #ifndef EXAMPLE_QAPI_TYPES_H #define EXAMPLE_QAPI_TYPES_H @@ -1422,7 +1467,7 @@ Example: #endif /* EXAMPLE_QAPI_TYPES_H */ $ cat qapi-generated/example-qapi-types.c -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] void qapi_free_UserDefOne(UserDefOne *obj) { @@ -1450,22 +1495,26 @@ Example: visit_free(v); } -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] For a modular QAPI schema (see section Include directives), code for -each sub-module SUBDIR/SUBMODULE.json is actually generated into +each sub-module SUBDIR/SUBMODULE.json is actually generated into :: -SUBDIR/$(prefix)qapi-types-SUBMODULE.h -SUBDIR/$(prefix)qapi-types-SUBMODULE.c + SUBDIR/$(prefix)qapi-types-SUBMODULE.h + SUBDIR/$(prefix)qapi-types-SUBMODULE.c If qapi-gen.py is run with option --builtins, additional files are created: -qapi-builtin-types.h - C types corresponding to built-in types + ``qapi-builtin-types.h`` + C types corresponding to built-in types -qapi-builtin-types.c - Cleanup functions for the above C types + ``qapi-builtin-types.c`` + Cleanup functions for the above C types -=== Code generated for visiting QAPI types === + +Code generated for visiting QAPI types +-------------------------------------- These are the visitor functions used to walk through and convert between a native QAPI C data structure and some other format (such as @@ -1474,19 +1523,18 @@ visit_type_FOO_members(). The following files are generated: -$(prefix)qapi-visit.c: Visitor function for a particular C type, used - to automagically convert QObjects into the - corresponding C type and vice-versa, as well - as for deallocating memory for an existing C - type + ``$(prefix)qapi-visit.c`` + Visitor function for a particular C type, used to automagically + convert QObjects into the corresponding C type and vice-versa, as + well as for deallocating memory for an existing C type -$(prefix)qapi-visit.h: Declarations for previously mentioned visitor - functions + ``$(prefix)qapi-visit.h`` + Declarations for previously mentioned visitor functions -Example: +Example:: $ cat qapi-generated/example-qapi-visit.h -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] #ifndef EXAMPLE_QAPI_VISIT_H #define EXAMPLE_QAPI_VISIT_H @@ -1507,7 +1555,7 @@ Example: #endif /* EXAMPLE_QAPI_VISIT_H */ $ cat qapi-generated/example-qapi-visit.c -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] bool visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error **errp) { @@ -1585,22 +1633,26 @@ Example: return true; } -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] For a modular QAPI schema (see section Include directives), code for -each sub-module SUBDIR/SUBMODULE.json is actually generated into +each sub-module SUBDIR/SUBMODULE.json is actually generated into :: -SUBDIR/$(prefix)qapi-visit-SUBMODULE.h -SUBDIR/$(prefix)qapi-visit-SUBMODULE.c + SUBDIR/$(prefix)qapi-visit-SUBMODULE.h + SUBDIR/$(prefix)qapi-visit-SUBMODULE.c If qapi-gen.py is run with option --builtins, additional files are created: -qapi-builtin-visit.h - Visitor functions for built-in types + ``qapi-builtin-visit.h`` + Visitor functions for built-in types -qapi-builtin-visit.c - Declarations for these visitor functions + ``qapi-builtin-visit.c`` + Declarations for these visitor functions -=== Code generated for commands === + +Code generated for commands +--------------------------- These are the marshaling/dispatch functions for the commands defined in the schema. The generated code provides qmp_marshal_COMMAND(), and @@ -1608,20 +1660,23 @@ declares qmp_COMMAND() that the user must implement. The following files are generated: -$(prefix)qapi-commands.c: Command marshal/dispatch functions for each - QMP command defined in the schema + ``$(prefix)qapi-commands.c`` + Command marshal/dispatch functions for each QMP command defined in + the schema -$(prefix)qapi-commands.h: Function prototypes for the QMP commands - specified in the schema + ``$(prefix)qapi-commands.h`` + Function prototypes for the QMP commands specified in the schema -$(prefix)qapi-init-commands.h - Command initialization prototype + ``$(prefix)qapi-init-commands.h`` + Command initialization prototype -$(prefix)qapi-init-commands.c - Command initialization code + ``$(prefix)qapi-init-commands.c`` + Command initialization code -Example: +Example:: $ cat qapi-generated/example-qapi-commands.h -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] #ifndef EXAMPLE_QAPI_COMMANDS_H #define EXAMPLE_QAPI_COMMANDS_H @@ -1633,7 +1688,7 @@ Example: #endif /* EXAMPLE_QAPI_COMMANDS_H */ $ cat qapi-generated/example-qapi-commands.c -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, @@ -1688,9 +1743,9 @@ Example: visit_free(v); } -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] $ cat qapi-generated/example-qapi-init-commands.h -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] #ifndef EXAMPLE_QAPI_INIT_COMMANDS_H #define EXAMPLE_QAPI_INIT_COMMANDS_H @@ -1700,7 +1755,7 @@ Example: #endif /* EXAMPLE_QAPI_INIT_COMMANDS_H */ $ cat qapi-generated/example-qapi-init-commands.c -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] void example_qmp_init_marshal(QmpCommandList *cmds) { QTAILQ_INIT(cmds); @@ -1708,34 +1763,39 @@ Example: qmp_register_command(cmds, "my-command", qmp_marshal_my_command, QCO_NO_OPTIONS); } -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] For a modular QAPI schema (see section Include directives), code for -each sub-module SUBDIR/SUBMODULE.json is actually generated into +each sub-module SUBDIR/SUBMODULE.json is actually generated into:: -SUBDIR/$(prefix)qapi-commands-SUBMODULE.h -SUBDIR/$(prefix)qapi-commands-SUBMODULE.c + SUBDIR/$(prefix)qapi-commands-SUBMODULE.h + SUBDIR/$(prefix)qapi-commands-SUBMODULE.c -=== Code generated for events === + +Code generated for events +------------------------- This is the code related to events defined in the schema, providing qapi_event_send_EVENT(). The following files are created: -$(prefix)qapi-events.h - Function prototypes for each event type + ``$(prefix)qapi-events.h`` + Function prototypes for each event type -$(prefix)qapi-events.c - Implementation of functions to send an event + ``$(prefix)qapi-events.c`` + Implementation of functions to send an event -$(prefix)qapi-emit-events.h - Enumeration of all event names, and - common event code declarations + ``$(prefix)qapi-emit-events.h`` + Enumeration of all event names, and common event code declarations -$(prefix)qapi-emit-events.c - Common event code definitions + ``$(prefix)qapi-emit-events.c`` + Common event code definitions -Example: +Example:: $ cat qapi-generated/example-qapi-events.h -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] #ifndef EXAMPLE_QAPI_EVENTS_H #define EXAMPLE_QAPI_EVENTS_H @@ -1747,7 +1807,7 @@ Example: #endif /* EXAMPLE_QAPI_EVENTS_H */ $ cat qapi-generated/example-qapi-events.c -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] void qapi_event_send_my_event(void) { @@ -1760,9 +1820,9 @@ Example: qobject_unref(qmp); } -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] $ cat qapi-generated/example-qapi-emit-events.h -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] #ifndef EXAMPLE_QAPI_EMIT_EVENTS_H #define EXAMPLE_QAPI_EMIT_EVENTS_H @@ -1783,7 +1843,7 @@ Example: #endif /* EXAMPLE_QAPI_EMIT_EVENTS_H */ $ cat qapi-generated/example-qapi-emit-events.c -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] const QEnumLookup example_QAPIEvent_lookup = { .array = (const char *const[]) { @@ -1792,27 +1852,30 @@ Example: .size = EXAMPLE_QAPI_EVENT__MAX }; -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] For a modular QAPI schema (see section Include directives), code for -each sub-module SUBDIR/SUBMODULE.json is actually generated into +each sub-module SUBDIR/SUBMODULE.json is actually generated into :: -SUBDIR/$(prefix)qapi-events-SUBMODULE.h -SUBDIR/$(prefix)qapi-events-SUBMODULE.c + SUBDIR/$(prefix)qapi-events-SUBMODULE.h + SUBDIR/$(prefix)qapi-events-SUBMODULE.c -=== Code generated for introspection === + +Code generated for introspection +-------------------------------- The following files are created: -$(prefix)qapi-introspect.c - Defines a string holding a JSON - description of the schema + ``$(prefix)qapi-introspect.c`` + Defines a string holding a JSON description of the schema -$(prefix)qapi-introspect.h - Declares the above string + ``$(prefix)qapi-introspect.h`` + Declares the above string -Example: +Example:: $ cat qapi-generated/example-qapi-introspect.h -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] #ifndef EXAMPLE_QAPI_INTROSPECT_H #define EXAMPLE_QAPI_INTROSPECT_H @@ -1823,7 +1886,7 @@ Example: #endif /* EXAMPLE_QAPI_INTROSPECT_H */ $ cat qapi-generated/example-qapi-introspect.c -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] const QLitObject example_qmp_schema_qlit = QLIT_QLIST(((QLitObject[]) { QLIT_QDICT(((QLitDictEntry[]) { @@ -1903,4 +1966,4 @@ Example: {} })); -[Uninteresting stuff omitted...] + [Uninteresting stuff omitted...] From 55927c5f3283fe47e77a64ffe3bcab4c1117a07d Mon Sep 17 00:00:00 2001 From: John Snow Date: Tue, 20 Jul 2021 19:56:18 -0400 Subject: [PATCH 483/531] docs/qapi-code-gen: Beautify formatting Mostly, add ``literal`` markers to a lot of things like C types, add code blocks, and fix the way a few things render. Signed-off-by: John Snow Message-Id: <20210720235619.2048797-3-jsnow@redhat.com> Reviewed-by: Peter Maydell Signed-off-by: Markus Armbruster --- docs/devel/qapi-code-gen.rst | 172 ++++++++++++++++++----------------- 1 file changed, 90 insertions(+), 82 deletions(-) diff --git a/docs/devel/qapi-code-gen.rst b/docs/devel/qapi-code-gen.rst index 9155dba262..07b11e2a40 100644 --- a/docs/devel/qapi-code-gen.rst +++ b/docs/devel/qapi-code-gen.rst @@ -40,7 +40,7 @@ by any commands or events, for the side effect of generated C code used internally. There are several kinds of types: simple types (a number of built-in -types, such as 'int' and 'str'; as well as enumerations), arrays, +types, such as ``int`` and ``str``; as well as enumerations), arrays, complex types (structs and two flavors of unions), and alternate types (a choice between other types). @@ -51,37 +51,37 @@ Schema syntax Syntax is loosely based on `JSON `_. Differences: -* Comments: start with a hash character (#) that is not part of a +* Comments: start with a hash character (``#``) that is not part of a string, and extend to the end of the line. -* Strings are enclosed in 'single quotes', not "double quotes". +* Strings are enclosed in ``'single quotes'``, not ``"double quotes"``. * Strings are restricted to printable ASCII, and escape sequences to - just '\\'. + just ``\\``. -* Numbers and null are not supported. +* Numbers and ``null`` are not supported. A second layer of syntax defines the sequences of JSON texts that are a correctly structured QAPI schema. We provide a grammar for this syntax in an EBNF-like notation: -* Production rules look like non-terminal = expression -* Concatenation: expression A B matches expression A, then B -* Alternation: expression A | B matches expression A or B -* Repetition: expression A... matches zero or more occurrences of - expression A -* Repetition: expression A, ... matches zero or more occurrences of - expression A separated by , -* Grouping: expression ( A ) matches expression A -* JSON's structural characters are terminals: { } [ ] : , -* JSON's literal names are terminals: false true -* String literals enclosed in 'single quotes' are terminal, and match - this JSON string, with a leading '*' stripped off -* When JSON object member's name starts with '*', the member is +* Production rules look like ``non-terminal = expression`` +* Concatenation: expression ``A B`` matches expression ``A``, then ``B`` +* Alternation: expression ``A | B`` matches expression ``A`` or ``B`` +* Repetition: expression ``A...`` matches zero or more occurrences of + expression ``A`` +* Repetition: expression ``A, ...`` matches zero or more occurrences of + expression ``A`` separated by ``,`` +* Grouping: expression ``( A )`` matches expression ``A`` +* JSON's structural characters are terminals: ``{ } [ ] : ,`` +* JSON's literal names are terminals: ``false true`` +* String literals enclosed in ``'single quotes'`` are terminal, and match + this JSON string, with a leading ``*`` stripped off +* When JSON object member's name starts with ``*``, the member is optional. -* The symbol STRING is a terminal, and matches any JSON string -* The symbol BOOL is a terminal, and matches JSON false or true -* ALL-CAPS words other than STRING are non-terminals +* The symbol ``STRING`` is a terminal, and matches any JSON string +* The symbol ``BOOL`` is a terminal, and matches JSON ``false`` or ``true`` +* ALL-CAPS words other than ``STRING`` are non-terminals The order of members within JSON objects does not matter unless explicitly noted. @@ -109,27 +109,30 @@ These are discussed in detail below. Built-in Types -------------- -The following types are predefined, and map to C as follows:: +The following types are predefined, and map to C as follows: - Schema C JSON - str char * any JSON string, UTF-8 - number double any JSON number - int int64_t a JSON number without fractional part - that fits into the C integer type - int8 int8_t likewise - int16 int16_t likewise - int32 int32_t likewise - int64 int64_t likewise - uint8 uint8_t likewise - uint16 uint16_t likewise - uint32 uint32_t likewise - uint64 uint64_t likewise - size uint64_t like uint64_t, except StringInputVisitor - accepts size suffixes - bool bool JSON true or false - null QNull * JSON null - any QObject * any JSON value - QType QType JSON string matching enum QType values + ============= ============== ============================================ + Schema C JSON + ============= ============== ============================================ + ``str`` ``char *`` any JSON string, UTF-8 + ``number`` ``double`` any JSON number + ``int`` ``int64_t`` a JSON number without fractional part + that fits into the C integer type + ``int8`` ``int8_t`` likewise + ``int16`` ``int16_t`` likewise + ``int32`` ``int32_t`` likewise + ``int64`` ``int64_t`` likewise + ``uint8`` ``uint8_t`` likewise + ``uint16`` ``uint16_t`` likewise + ``uint32`` ``uint32_t`` likewise + ``uint64`` ``uint64_t`` likewise + ``size`` ``uint64_t`` like ``uint64_t``, except + ``StringInputVisitor`` accepts size suffixes + ``bool`` ``bool`` JSON ``true`` or ``false`` + ``null`` ``QNull *`` JSON ``null`` + ``any`` ``QObject *`` any JSON value + ``QType`` ``QType`` JSON string matching enum ``QType`` values + ============= ============== ============================================ Include directives @@ -174,14 +177,14 @@ Pragma 'doc-required' takes a boolean value. If true, documentation is required. Default is false. Pragma 'command-name-exceptions' takes a list of commands whose names -may contain '_' instead of '-'. Default is none. +may contain ``"_"`` instead of ``"-"``. Default is none. Pragma 'command-returns-exceptions' takes a list of commands that may violate the rules on permitted return types. Default is none. Pragma 'member-name-exceptions' takes a list of types whose member -names may contain uppercase letters, and '_' instead of '-'. Default -is none. +names may contain uppercase letters, and ``"_"`` instead of ``"-"``. +Default is none. Enumeration types @@ -200,7 +203,7 @@ Syntax:: Member 'enum' names the enum type. Each member of the 'data' array defines a value of the enumeration -type. The form STRING is shorthand for { 'name': STRING }. The +type. The form STRING is shorthand for :code:`{ 'name': STRING }`. The 'name' values must be be distinct. Example:: @@ -243,7 +246,7 @@ Syntax:: A string denotes the type named by the string. A one-element array containing a string denotes an array of the type -named by the string. Example: ['int'] denotes an array of 'int'. +named by the string. Example: ``['int']`` denotes an array of ``int``. Struct types @@ -266,11 +269,11 @@ Member 'struct' names the struct type. Each MEMBER of the 'data' object defines a member of the struct type. -The MEMBER's STRING name consists of an optional '*' prefix and the -struct member name. If '*' is present, the member is optional. +The MEMBER's STRING name consists of an optional ``*`` prefix and the +struct member name. If ``*`` is present, the member is optional. The MEMBER's value defines its properties, in particular its type. -The form TYPE-REF is shorthand for { 'type': TYPE-REF }. +The form TYPE-REF is shorthand for :code:`{ 'type': TYPE-REF }`. Example:: @@ -334,7 +337,7 @@ union must have at least one branch. The BRANCH's STRING name is the branch name. The BRANCH's value defines the branch's properties, in particular its -type. The form TYPE-REF is shorthand for { 'type': TYPE-REF }. +type. The form TYPE-REF is shorthand for :code:`{ 'type': TYPE-REF }`. A simple union type defines a mapping from automatic discriminator values to data types like in this example:: @@ -381,7 +384,7 @@ struct. The following example enhances the above simple union example by adding an optional common member 'read-only', renaming the discriminator to something more applicable than the simple union's -default of 'type', and reducing the number of {} required on the wire:: +default of 'type', and reducing the number of ``{}`` required on the wire:: { 'enum': 'BlockdevDriver', 'data': [ 'file', 'qcow2' ] } { 'union': 'BlockdevOptions', @@ -450,7 +453,7 @@ alternate. An alternate must have at least one branch. The ALTERNATIVE's STRING name is the branch name. The ALTERNATIVE's value defines the branch's properties, in particular -its type. The form STRING is shorthand for { 'type': STRING }. +its type. The form STRING is shorthand for :code:`{ 'type': STRING }`. Example:: @@ -515,7 +518,7 @@ If 'data' is a MEMBERS object, then MEMBERS defines arguments just like a struct type's 'data' defines struct type members. If 'data' is a STRING, then STRING names a complex type whose members -are the arguments. A union type requires 'boxed': true. +are the arguments. A union type requires ``'boxed': true``. Member 'returns' defines the command's return type. It defaults to an empty struct type. It must normally be a complex type or an array of @@ -555,7 +558,7 @@ section "Code generated for commands" for examples. The function returns the return type. When member 'boxed' is absent, it takes the command arguments as arguments one by one, in QAPI schema order. Else it takes them wrapped in the C struct generated for the -complex argument type. It takes an additional Error ** argument in +complex argument type. It takes an additional ``Error **`` argument in either case. The generator also emits a marshalling function that extracts @@ -638,11 +641,11 @@ blocking the guest and other background operations. Coroutine safety can be hard to prove, similar to thread safety. Common pitfalls are: -- The global mutex isn't held across qemu_coroutine_yield(), so +- The global mutex isn't held across ``qemu_coroutine_yield()``, so operations that used to assume that they execute atomically may have to be more careful to protect against changes in the global state. -- Nested event loops (AIO_WAIT_WHILE() etc.) are problematic in +- Nested event loops (``AIO_WAIT_WHILE()`` etc.) are problematic in coroutine context and can easily lead to deadlocks. They should be replaced by yielding and reentering the coroutine when the condition becomes false. @@ -650,9 +653,9 @@ pitfalls are: Since the command handler may assume coroutine context, any callers other than the QMP dispatcher must also call it in coroutine context. In particular, HMP commands calling such a QMP command handler must be -marked .coroutine = true in hmp-commands.hx. +marked ``.coroutine = true`` in hmp-commands.hx. -It is an error to specify both 'coroutine': true and 'allow-oob': true +It is an error to specify both ``'coroutine': true`` and ``'allow-oob': true`` for a command. We don't currently have a use case for both together and without a use case, it's not entirely clear what the semantics should be. @@ -689,7 +692,7 @@ If 'data' is a MEMBERS object, then MEMBERS defines event-specific data just like a struct type's 'data' defines struct type members. If 'data' is a STRING, then STRING names a complex type whose members -are the event-specific data. A union type requires 'boxed': true. +are the event-specific data. A union type requires ``'boxed': true``. An example event is:: @@ -763,16 +766,16 @@ digits, hyphen, and underscore. There are two exceptions: enum values may start with a digit, and names that are downstream extensions (see section Downstream extensions) start with underscore. -Names beginning with 'q\_' are reserved for the generator, which uses +Names beginning with ``q_`` are reserved for the generator, which uses them for munging QMP names that resemble C keywords or other -problematic strings. For example, a member named "default" in qapi -becomes "q_default" in the generated C code. +problematic strings. For example, a member named ``default`` in qapi +becomes ``q_default`` in the generated C code. Types, commands, and events share a common namespace. Therefore, generally speaking, type definitions should always use CamelCase for user-defined type names, while built-in types are lowercase. -Type names ending with 'Kind' or 'List' are reserved for the +Type names ending with ``Kind`` or ``List`` are reserved for the generator, which uses them for implicit union enums and array types, respectively. @@ -783,15 +786,15 @@ consistency is preferred over blindly avoiding underscore. Event names should be ALL_CAPS with words separated by underscore. -Member name 'u' and names starting with 'has-' or 'has\_' are reserved +Member name ``u`` and names starting with ``has-`` or ``has_`` are reserved for the generator, which uses them for unions and for tracking optional members. Any name (command, event, type, member, or enum value) beginning with -"x-" is marked experimental, and may be withdrawn or changed +``x-`` is marked experimental, and may be withdrawn or changed incompatibly in a future release. -Pragmas 'command-name-exceptions' and 'member-name-exceptions' let you +Pragmas ``command-name-exceptions`` and ``member-name-exceptions`` let you violate naming rules. Use for new code is strongly discouraged. @@ -805,7 +808,7 @@ who controls the valid, reverse fully qualified domain name RFQDN. RFQDN may only contain ASCII letters, digits, hyphen and period. Example: Red Hat, Inc. controls redhat.com, and may therefore add a -downstream command __com.redhat_drive-mirror. +downstream command ``__com.redhat_drive-mirror``. Configuring the schema @@ -879,7 +882,7 @@ this particular build. Documentation comments ---------------------- -A multi-line comment that starts and ends with a '##' line is a +A multi-line comment that starts and ends with a ``##`` line is a documentation comment. If the documentation comment starts like :: @@ -887,7 +890,7 @@ If the documentation comment starts like :: ## # @SYMBOL: -it documents the definition if SYMBOL, else it's free-form +it documents the definition of SYMBOL, else it's free-form documentation. See below for more on definition documentation. @@ -900,7 +903,7 @@ Headings and subheadings ~~~~~~~~~~~~~~~~~~~~~~~~ A free-form documentation comment containing a line which starts with -some '=' symbols and then a space defines a section heading:: +some ``=`` symbols and then a space defines a section heading:: ## # = This is a top level heading @@ -924,22 +927,22 @@ Documentation markup ~~~~~~~~~~~~~~~~~~~~ Documentation comments can use most rST markup. In particular, -a '::' literal block can be used for examples:: +a ``::`` literal block can be used for examples:: # :: # # Text of the example, may span # multiple lines -'*' starts an itemized list:: +``*`` starts an itemized list:: # * First item, may span # multiple lines # * Second item -You can also use '-' instead of '*'. +You can also use ``-`` instead of ``*``. -A decimal number followed by '.' starts a numbered list:: +A decimal number followed by ``.`` starts a numbered list:: # 1. First item, may span # multiple lines @@ -952,11 +955,11 @@ If a list item's text spans multiple lines, then the second and subsequent lines must be correctly indented to line up with the first character of the first line. -The usual '**strong**', '*emphasised*' and '``literal``' markup should -be used. If you need a single literal '*' you will need to +The usual ****strong****, *\*emphasized\** and ````literal```` markup +should be used. If you need a single literal ``*``, you will need to backslash-escape it. As an extension beyond the usual rST syntax, you -can also use '@foo' to reference a name in the schema; this is -rendered the same way as '``foo``'. +can also use ``@foo`` to reference a name in the schema; this is rendered +the same way as ````foo````. Example:: @@ -991,9 +994,9 @@ alternates), or value (for enums), and finally optional tagged sections. Descriptions of arguments can span multiple lines. The description -text can start on the line following the '@argname:', in which case it +text can start on the line following the '\@argname:', in which case it must not be indented at all. It can also start on the same line as -the '@argname:'. In this case if it spans multiple lines then second +the '\@argname:'. In this case if it spans multiple lines then second and subsequent lines must be indented to line up with the first character of the first line of the description:: @@ -1006,8 +1009,13 @@ character of the first line of the description:: The number of spaces between the ':' and the text is not significant. -FIXME: the parser accepts these things in almost any order. -FIXME: union branches should be described, too. +.. admonition:: FIXME + + The parser accepts these things in almost any order. + +.. admonition:: FIXME + + union branches should be described, too. Extensions added after the definition was first released carry a '(since x.y.z)' comment. From 9c66762a6015aaf503ceb7f2bbbf3a9affd9368d Mon Sep 17 00:00:00 2001 From: John Snow Date: Tue, 20 Jul 2021 19:56:19 -0400 Subject: [PATCH 484/531] docs/qapi-code-gen: add cross-references Add clickables to many places. Signed-off-by: John Snow Message-Id: <20210720235619.2048797-4-jsnow@redhat.com> Reviewed-by: Peter Maydell Signed-off-by: Markus Armbruster --- docs/devel/qapi-code-gen.rst | 107 +++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 49 deletions(-) diff --git a/docs/devel/qapi-code-gen.rst b/docs/devel/qapi-code-gen.rst index 07b11e2a40..26c62b0e7b 100644 --- a/docs/devel/qapi-code-gen.rst +++ b/docs/devel/qapi-code-gen.rst @@ -156,6 +156,7 @@ from making a forward reference to a type that is only introduced by an outer file. The parser may be made stricter in the future to prevent incomplete include files. +.. _pragma: Pragma directives ----------------- @@ -186,6 +187,7 @@ Pragma 'member-name-exceptions' takes a list of types whose member names may contain uppercase letters, and ``"_"`` instead of ``"-"``. Default is none. +.. _ENUM-VALUE: Enumeration types ----------------- @@ -228,13 +230,15 @@ additional enumeration constant PREFIX__MAX with value N. Do not use string or an integer type when an enumeration type can do the job satisfactorily. -The optional 'if' member specifies a conditional. See "Configuring -the schema" below for more on this. +The optional 'if' member specifies a conditional. See `Configuring the +schema`_ below for more on this. -The optional 'features' member specifies features. See "Features" +The optional 'features' member specifies features. See Features_ below for more on this. +.. _TYPE-REF: + Type references and array types ------------------------------- @@ -269,11 +273,13 @@ Member 'struct' names the struct type. Each MEMBER of the 'data' object defines a member of the struct type. +.. _MEMBERS: + The MEMBER's STRING name consists of an optional ``*`` prefix and the struct member name. If ``*`` is present, the member is optional. The MEMBER's value defines its properties, in particular its type. -The form TYPE-REF is shorthand for :code:`{ 'type': TYPE-REF }`. +The form TYPE-REF_ is shorthand for :code:`{ 'type': TYPE-REF }`. Example:: @@ -300,10 +306,10 @@ both members like this:: { "file": "/some/place/my-image", "backing": "/some/place/my-backing-file" } -The optional 'if' member specifies a conditional. See "Configuring -the schema" below for more on this. +The optional 'if' member specifies a conditional. See `Configuring +the schema`_ below for more on this. -The optional 'features' member specifies features. See "Features" +The optional 'features' member specifies features. See Features_ below for more on this. @@ -337,7 +343,7 @@ union must have at least one branch. The BRANCH's STRING name is the branch name. The BRANCH's value defines the branch's properties, in particular its -type. The form TYPE-REF is shorthand for :code:`{ 'type': TYPE-REF }`. +type. The form TYPE-REF_ is shorthand for :code:`{ 'type': TYPE-REF }`. A simple union type defines a mapping from automatic discriminator values to data types like in this example:: @@ -368,12 +374,12 @@ Flat unions permit arbitrary common members that occur in all variants of the union, not just a discriminator. Their discriminators need not be named 'type'. They also avoid nesting on the wire. -The 'base' member defines the common members. If it is a MEMBERS +The 'base' member defines the common members. If it is a MEMBERS_ object, it defines common members just like a struct type's 'data' member defines struct type members. If it is a STRING, it names a struct type whose members are the common members. -All flat union branches must be of struct type. +All flat union branches must be `Struct types`_. In the Client JSON Protocol, a flat union is represented by an object with the common members (from the base type) and the selected branch's @@ -425,10 +431,10 @@ is identical on the wire to:: { 'union': 'Flat', 'base': { 'type': 'Enum' }, 'discriminator': 'type', 'data': { 'one': 'Branch1', 'two': 'Branch2' } } -The optional 'if' member specifies a conditional. See "Configuring -the schema" below for more on this. +The optional 'if' member specifies a conditional. See `Configuring +the schema`_ below for more on this. -The optional 'features' member specifies features. See "Features" +The optional 'features' member specifies features. See Features_ below for more on this. @@ -481,10 +487,10 @@ following example objects:: "read-only": false, "filename": "/tmp/mydisk.qcow2" } } -The optional 'if' member specifies a conditional. See "Configuring -the schema" below for more on this. +The optional 'if' member specifies a conditional. See `Configuring +the schema`_ below for more on this. -The optional 'features' member specifies features. See "Features" +The optional 'features' member specifies features. See Features_ below for more on this. @@ -511,10 +517,10 @@ Syntax:: Member 'command' names the command. -Member 'data' defines the arguments. It defaults to an empty MEMBERS +Member 'data' defines the arguments. It defaults to an empty MEMBERS_ object. -If 'data' is a MEMBERS object, then MEMBERS defines arguments just +If 'data' is a MEMBERS_ object, then MEMBERS defines arguments just like a struct type's 'data' defines struct type members. If 'data' is a STRING, then STRING names a complex type whose members @@ -553,7 +559,7 @@ which would validate this Client JSON Protocol transaction:: The generator emits a prototype for the C function implementing the command. The function itself needs to be written by hand. See -section "Code generated for commands" for examples. +section `Code generated for commands`_ for examples. The function returns the return type. When member 'boxed' is absent, it takes the command arguments as arguments one by one, in QAPI schema @@ -660,10 +666,10 @@ for a command. We don't currently have a use case for both together and without a use case, it's not entirely clear what the semantics should be. -The optional 'if' member specifies a conditional. See "Configuring -the schema" below for more on this. +The optional 'if' member specifies a conditional. See `Configuring +the schema`_ below for more on this. -The optional 'features' member specifies features. See "Features" +The optional 'features' member specifies features. See Features_ below for more on this. @@ -708,15 +714,17 @@ Resulting in this JSON object:: The generator emits a function to send the event. When member 'boxed' is absent, it takes event-specific data one by one, in QAPI schema order. Else it takes them wrapped in the C struct generated for the -complex type. See section "Code generated for events" for examples. +complex type. See section `Code generated for events`_ for examples. -The optional 'if' member specifies a conditional. See "Configuring -the schema" below for more on this. +The optional 'if' member specifies a conditional. See `Configuring +the schema`_ below for more on this. -The optional 'features' member specifies features. See "Features" +The optional 'features' member specifies features. See Features_ below for more on this. +.. _FEATURE: + Features -------- @@ -735,8 +743,8 @@ For this purpose, a list of features can be specified for a command or struct type. Each list member can either be ``{ 'name': STRING, '*if': COND }``, or STRING, which is shorthand for ``{ 'name': STRING }``. -The optional 'if' member specifies a conditional. See "Configuring -the schema" below for more on this. +The optional 'if' member specifies a conditional. See `Configuring +the schema`_ below for more on this. Example:: @@ -745,7 +753,7 @@ Example:: 'features': [ 'allow-negative-numbers' ] } The feature strings are exposed to clients in introspection, as -explained in section "Client JSON Protocol introspection". +explained in section `Client JSON Protocol introspection`_. Intended use is to have each feature string signal that this build of QEMU shows a certain behaviour. @@ -764,7 +772,7 @@ Naming rules and reserved names All names must begin with a letter, and contain only ASCII letters, digits, hyphen, and underscore. There are two exceptions: enum values may start with a digit, and names that are downstream extensions (see -section Downstream extensions) start with underscore. +section `Downstream extensions`_) start with underscore. Names beginning with ``q_`` are reserved for the generator, which uses them for munging QMP names that resemble C keywords or other @@ -794,8 +802,9 @@ Any name (command, event, type, member, or enum value) beginning with ``x-`` is marked experimental, and may be withdrawn or changed incompatibly in a future release. -Pragmas ``command-name-exceptions`` and ``member-name-exceptions`` let you -violate naming rules. Use for new code is strongly discouraged. +Pragmas ``command-name-exceptions`` and ``member-name-exceptions`` let +you violate naming rules. Use for new code is strongly discouraged. See +`Pragma directives`_ for details. Downstream extensions @@ -851,7 +860,7 @@ member 'bar' :: A union's discriminator may not be conditional. Likewise, individual enumeration values be conditional. This requires -the longhand form of ENUM-VALUE. +the longhand form of ENUM-VALUE_. Example: an enum type with unconditional value 'foo' and conditional value 'bar' :: @@ -861,7 +870,7 @@ value 'bar' :: { 'name' : 'bar', 'if': 'defined(IFCOND)' } ] } Likewise, features can be conditional. This requires the longhand -form of FEATURE. +form of FEATURE_. Example: a struct with conditional feature 'allow-negative-numbers' :: @@ -893,7 +902,7 @@ If the documentation comment starts like :: it documents the definition of SYMBOL, else it's free-form documentation. -See below for more on definition documentation. +See below for more on `Definition documentation`_. Free-form documentation may be used to provide additional text and structuring content. @@ -984,7 +993,7 @@ Definition documentation Definition documentation, if present, must immediately precede the definition it documents. -When documentation is required (see pragma 'doc-required'), every +When documentation is required (see pragma_ 'doc-required'), every definition must have documentation. Definition documentation starts with a line naming the definition, @@ -1181,7 +1190,7 @@ the wire then. Each command or event defined with 'data' as MEMBERS object in the QAPI schema implicitly defines an object type. -Example: the SchemaInfo for EVENT_C from section Events :: +Example: the SchemaInfo for EVENT_C from section Events_ :: { "name": "EVENT_C", "meta-type": "event", "arg-type": "q_obj-EVENT_C-arg" } @@ -1205,7 +1214,7 @@ extensions. The "members" array is in no particular order; clients must search the entire object when learning whether a particular member is supported. -Example: the SchemaInfo for MyType from section Struct types :: +Example: the SchemaInfo for MyType from section `Struct types`_ :: { "name": "MyType", "meta-type": "object", "members": [ @@ -1216,7 +1225,7 @@ Example: the SchemaInfo for MyType from section Struct types :: "features" exposes the command's feature strings as a JSON array of strings. -Example: the SchemaInfo for TestType from section Features:: +Example: the SchemaInfo for TestType from section Features_:: { "name": "TestType", "meta-type": "object", "members": [ @@ -1232,7 +1241,7 @@ that provides the variant members for this type tag value). The list cases in the same order as the corresponding "tag" enum type. Example: the SchemaInfo for flat union BlockdevOptions from section -Union types :: +`Union types`_ :: { "name": "BlockdevOptions", "meta-type": "object", "members": [ @@ -1247,13 +1256,13 @@ Note that base types are "flattened": its members are included in the "members" array. A simple union implicitly defines an enumeration type for its implicit -discriminator (called "type" on the wire, see section Union types). +discriminator (called "type" on the wire, see section `Union types`_). A simple union implicitly defines an object type for each of its variants. Example: the SchemaInfo for simple union BlockdevOptionsSimple from section -Union types :: +`Union types`_ :: { "name": "BlockdevOptionsSimple", "meta-type": "object", "members": [ @@ -1273,7 +1282,7 @@ a JSON object with member "type", which names a type. Values of the alternate type conform to exactly one of its member types. There is no guarantee on the order in which "members" will be listed. -Example: the SchemaInfo for BlockdevRef from section Alternate types :: +Example: the SchemaInfo for BlockdevRef from section `Alternate types`_ :: { "name": "BlockdevRef", "meta-type": "alternate", "members": [ @@ -1297,13 +1306,13 @@ variant member "values". The values are listed in no particular order; clients must search the entire enum when learning whether a particular value is supported. -Example: the SchemaInfo for MyEnum from section Enumeration types :: +Example: the SchemaInfo for MyEnum from section `Enumeration types`_ :: { "name": "MyEnum", "meta-type": "enum", "values": [ "value1", "value2", "value3" ] } The SchemaInfo for a built-in type has the same name as the type in -the QAPI schema (see section Built-in Types), with one exception +the QAPI schema (see section `Built-in Types`_), with one exception detailed below. It has variant member "json-type" that shows how values of this type are encoded on the wire. @@ -1505,7 +1514,7 @@ Example:: [Uninteresting stuff omitted...] -For a modular QAPI schema (see section Include directives), code for +For a modular QAPI schema (see section `Include directives`_), code for each sub-module SUBDIR/SUBMODULE.json is actually generated into :: SUBDIR/$(prefix)qapi-types-SUBMODULE.h @@ -1643,7 +1652,7 @@ Example:: [Uninteresting stuff omitted...] -For a modular QAPI schema (see section Include directives), code for +For a modular QAPI schema (see section `Include directives`_), code for each sub-module SUBDIR/SUBMODULE.json is actually generated into :: SUBDIR/$(prefix)qapi-visit-SUBMODULE.h @@ -1773,7 +1782,7 @@ Example:: } [Uninteresting stuff omitted...] -For a modular QAPI schema (see section Include directives), code for +For a modular QAPI schema (see section `Include directives`_), code for each sub-module SUBDIR/SUBMODULE.json is actually generated into:: SUBDIR/$(prefix)qapi-commands-SUBMODULE.h @@ -1862,7 +1871,7 @@ Example:: [Uninteresting stuff omitted...] -For a modular QAPI schema (see section Include directives), code for +For a modular QAPI schema (see section `Include directives`_), code for each sub-module SUBDIR/SUBMODULE.json is actually generated into :: SUBDIR/$(prefix)qapi-events-SUBMODULE.h From 68e6dc594a44a7077657f2ea878806e38dfa50cf Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Jul 2021 12:50:15 -0400 Subject: [PATCH 485/531] docs: convert writing-qmp-commands.txt to writing-qmp-commands.rst This does about the bare minimum, converting section headers to ReST ones and adding an indent for code blocks. Signed-off-by: John Snow Message-Id: <20210721165015.2180311-1-jsnow@redhat.com> Reviewed-by: Connor Kuehl Signed-off-by: Markus Armbruster --- docs/devel/index.rst | 1 + ...-commands.txt => writing-qmp-commands.rst} | 567 +++++++++--------- 2 files changed, 297 insertions(+), 271 deletions(-) rename docs/devel/{writing-qmp-commands.txt => writing-qmp-commands.rst} (61%) diff --git a/docs/devel/index.rst b/docs/devel/index.rst index bfba3a8daa..5522db7241 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -43,3 +43,4 @@ modifying QEMU's source code. ebpf_rss vfio-migration qapi-code-gen + writing-qmp-commands diff --git a/docs/devel/writing-qmp-commands.txt b/docs/devel/writing-qmp-commands.rst similarity index 61% rename from docs/devel/writing-qmp-commands.txt rename to docs/devel/writing-qmp-commands.rst index b1e31d56c0..6a10a06c48 100644 --- a/docs/devel/writing-qmp-commands.txt +++ b/docs/devel/writing-qmp-commands.rst @@ -1,4 +1,5 @@ -= How to write QMP commands using the QAPI framework = +How to write QMP commands using the QAPI framework +================================================== This document is a step-by-step guide on how to write new QMP commands using the QAPI framework. It also shows how to implement new style HMP commands. @@ -10,7 +11,9 @@ For an in-depth introduction to the QAPI framework, please refer to docs/devel/qapi-code-gen.txt. For documentation about the QMP protocol, start with docs/interop/qmp-intro.txt. -== Overview == + +Overview +-------- Generally speaking, the following steps should be taken in order to write a new QMP command. @@ -31,55 +34,59 @@ new QMP command. The following sections will demonstrate each of the steps above. We will start very simple and get more complex as we progress. -=== Testing === + +Testing +------- For all the examples in the next sections, the test setup is the same and is shown here. -First, QEMU should be started like this: +First, QEMU should be started like this:: -# qemu-system-TARGET [...] \ - -chardev socket,id=qmp,port=4444,host=localhost,server=on \ - -mon chardev=qmp,mode=control,pretty=on + # qemu-system-TARGET [...] \ + -chardev socket,id=qmp,port=4444,host=localhost,server=on \ + -mon chardev=qmp,mode=control,pretty=on -Then, in a different terminal: +Then, in a different terminal:: -$ telnet localhost 4444 -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. -{ - "QMP": { - "version": { - "qemu": { - "micro": 50, - "minor": 15, - "major": 0 - }, - "package": "" - }, - "capabilities": [ - ] - } -} + $ telnet localhost 4444 + Trying 127.0.0.1... + Connected to localhost. + Escape character is '^]'. + { + "QMP": { + "version": { + "qemu": { + "micro": 50, + "minor": 15, + "major": 0 + }, + "package": "" + }, + "capabilities": [ + ] + } + } The above output is the QMP server saying you're connected. The server is -actually in capabilities negotiation mode. To enter in command mode type: +actually in capabilities negotiation mode. To enter in command mode type:: -{ "execute": "qmp_capabilities" } + { "execute": "qmp_capabilities" } -Then the server should respond: +Then the server should respond:: -{ - "return": { - } -} + { + "return": { + } + } Which is QMP's way of saying "the latest command executed OK and didn't return any data". Now you're ready to enter the QMP example commands as explained in the following sections. -== Writing a command that doesn't return data == + +Writing a command that doesn't return data +------------------------------------------ That's the most simple QMP command that can be written. Usually, this kind of command carries some meaningful action in QEMU but here it will just print @@ -90,9 +97,9 @@ return any data. The first step is defining the command in the appropriate QAPI schema module. We pick module qapi/misc.json, and add the following line at -the bottom: +the bottom:: -{ 'command': 'hello-world' } + { 'command': 'hello-world' } The "command" keyword defines a new QMP command. It's an JSON object. All schema entries are JSON objects. The line above will instruct the QAPI to @@ -102,19 +109,19 @@ protocol data. The next step is to write the "hello-world" implementation. As explained earlier, it's preferable for commands to live in QEMU subsystems. But "hello-world" doesn't pertain to any, so we put its implementation in -monitor/qmp-cmds.c: +monitor/qmp-cmds.c:: -void qmp_hello_world(Error **errp) -{ - printf("Hello, world!\n"); -} + void qmp_hello_world(Error **errp) + { + printf("Hello, world!\n"); + } There are a few things to be noticed: -1. QMP command implementation functions must be prefixed with "qmp_" +1. QMP command implementation functions must be prefixed with "qmp\_" 2. qmp_hello_world() returns void, this is in accordance with the fact that the command doesn't return any data -3. It takes an "Error **" argument. This is required. Later we will see how to +3. It takes an "Error \*\*" argument. This is required. Later we will see how to return errors and take additional arguments. The Error argument should not be touched if the command doesn't return errors 4. We won't add the function's prototype. That's automatically done by the QAPI @@ -122,23 +129,25 @@ There are a few things to be noticed: because it's the easiest way to demonstrate a QMP command You're done. Now build qemu, run it as suggested in the "Testing" section, -and then type the following QMP command: +and then type the following QMP command:: -{ "execute": "hello-world" } + { "execute": "hello-world" } Then check the terminal running qemu and look for the "Hello, world" string. If you don't see it then something went wrong. -=== Arguments === + +Arguments +~~~~~~~~~ Let's add an argument called "message" to our "hello-world" command. The new argument will contain the string to be printed to stdout. It's an optional argument, if it's not present we print our default "Hello, World" string. The first change we have to do is to modify the command specification in the -schema file to the following: +schema file to the following:: -{ 'command': 'hello-world', 'data': { '*message': 'str' } } + { 'command': 'hello-world', 'data': { '*message': 'str' } } Notice the new 'data' member in the schema. It's an JSON object whose each element is an argument to the command in question. Also notice the asterisk, @@ -147,80 +156,82 @@ for mandatory arguments). Finally, 'str' is the argument's type, which stands for "string". The QAPI also supports integers, booleans, enumerations and user defined types. -Now, let's update our C implementation in monitor/qmp-cmds.c: +Now, let's update our C implementation in monitor/qmp-cmds.c:: -void qmp_hello_world(bool has_message, const char *message, Error **errp) -{ - if (has_message) { - printf("%s\n", message); - } else { - printf("Hello, world\n"); - } -} + void qmp_hello_world(bool has_message, const char *message, Error **errp) + { + if (has_message) { + printf("%s\n", message); + } else { + printf("Hello, world\n"); + } + } There are two important details to be noticed: -1. All optional arguments are accompanied by a 'has_' boolean, which is set +1. All optional arguments are accompanied by a 'has\_' boolean, which is set if the optional argument is present or false otherwise 2. The C implementation signature must follow the schema's argument ordering, which is defined by the "data" member Time to test our new version of the "hello-world" command. Build qemu, run it as -described in the "Testing" section and then send two commands: +described in the "Testing" section and then send two commands:: -{ "execute": "hello-world" } -{ - "return": { - } -} + { "execute": "hello-world" } + { + "return": { + } + } -{ "execute": "hello-world", "arguments": { "message": "We love qemu" } } -{ - "return": { - } -} + { "execute": "hello-world", "arguments": { "message": "We love qemu" } } + { + "return": { + } + } You should see "Hello, world" and "We love qemu" in the terminal running qemu, if you don't see these strings, then something went wrong. -=== Errors === + +Errors +~~~~~~ QMP commands should use the error interface exported by the error.h header file. Basically, most errors are set by calling the error_setg() function. Let's say we don't accept the string "message" to contain the word "love". If -it does contain it, we want the "hello-world" command to return an error: +it does contain it, we want the "hello-world" command to return an error:: -void qmp_hello_world(bool has_message, const char *message, Error **errp) -{ - if (has_message) { - if (strstr(message, "love")) { - error_setg(errp, "the word 'love' is not allowed"); - return; - } - printf("%s\n", message); - } else { - printf("Hello, world\n"); - } -} + void qmp_hello_world(bool has_message, const char *message, Error **errp) + { + if (has_message) { + if (strstr(message, "love")) { + error_setg(errp, "the word 'love' is not allowed"); + return; + } + printf("%s\n", message); + } else { + printf("Hello, world\n"); + } + } The first argument to the error_setg() function is the Error pointer to pointer, which is passed to all QMP functions. The next argument is a human description of the error, this is a free-form printf-like string. Let's test the example above. Build qemu, run it as defined in the "Testing" -section, and then issue the following command: +section, and then issue the following command:: -{ "execute": "hello-world", "arguments": { "message": "all you need is love" } } + { "execute": "hello-world", "arguments": { "message": "all you need is love" } } -The QMP server's response should be: +The QMP server's response should be:: -{ - "error": { - "class": "GenericError", - "desc": "the word 'love' is not allowed" - } -} + { + "error": { + "class": "GenericError", + "desc": "the word 'love' is not allowed" + } + } Note that error_setg() produces a "GenericError" class. In general, all QMP errors should have that error class. There are two exceptions @@ -234,34 +245,38 @@ to this rule: If the failure you want to report falls into one of the two cases above, use error_set() with a second argument of an ErrorClass value. -=== Command Documentation === + +Command Documentation +~~~~~~~~~~~~~~~~~~~~~ There's only one step missing to make "hello-world"'s implementation complete, and that's its documentation in the schema file. There are many examples of such documentation in the schema file already, but -here goes "hello-world"'s new entry for qapi/misc.json: +here goes "hello-world"'s new entry for qapi/misc.json:: -## -# @hello-world: -# -# Print a client provided string to the standard output stream. -# -# @message: string to be printed -# -# Returns: Nothing on success. -# -# Notes: if @message is not provided, the "Hello, world" string will -# be printed instead -# -# Since: -## -{ 'command': 'hello-world', 'data': { '*message': 'str' } } + ## + # @hello-world: + # + # Print a client provided string to the standard output stream. + # + # @message: string to be printed + # + # Returns: Nothing on success. + # + # Notes: if @message is not provided, the "Hello, world" string will + # be printed instead + # + # Since: + ## + { 'command': 'hello-world', 'data': { '*message': 'str' } } Please, note that the "Returns" clause is optional if a command doesn't return any data nor any errors. -=== Implementing the HMP command === + +Implementing the HMP command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Now that the QMP command is in place, we can also make it available in the human monitor (HMP). @@ -270,20 +285,20 @@ With the introduction of the QAPI, HMP commands make QMP calls. Most of the time HMP commands are simple wrappers. All HMP commands implementation exist in the monitor/hmp-cmds.c file. -Here's the implementation of the "hello-world" HMP command: +Here's the implementation of the "hello-world" HMP command:: -void hmp_hello_world(Monitor *mon, const QDict *qdict) -{ - const char *message = qdict_get_try_str(qdict, "message"); - Error *err = NULL; + void hmp_hello_world(Monitor *mon, const QDict *qdict) + { + const char *message = qdict_get_try_str(qdict, "message"); + Error *err = NULL; - qmp_hello_world(!!message, message, &err); - if (err) { - monitor_printf(mon, "%s\n", error_get_pretty(err)); - error_free(err); - return; - } -} + qmp_hello_world(!!message, message, &err); + if (err) { + monitor_printf(mon, "%s\n", error_get_pretty(err)); + error_free(err); + return; + } + } Also, you have to add the function's prototype to the hmp.h file. @@ -299,7 +314,7 @@ There are three important points to be noticed: QMP call There's one last step to actually make the command available to monitor users, -we should add it to the hmp-commands.hx file: +we should add it to the hmp-commands.hx file:: { .name = "hello-world", @@ -309,11 +324,13 @@ we should add it to the hmp-commands.hx file: .cmd = hmp_hello_world, }, -STEXI -@item hello_world @var{message} -@findex hello_world -Print message to the standard output -ETEXI +:: + + STEXI + @item hello_world @var{message} + @findex hello_world + Print message to the standard output + ETEXI To test this you have to open a user monitor and issue the "hello-world" command. It might be instructive to check the command's documentation with @@ -322,7 +339,9 @@ HMP's "help" command. Please, check the "-monitor" command-line option to know how to open a user monitor. -== Writing a command that returns data == + +Writing a command that returns data +----------------------------------- A QMP command is capable of returning any data the QAPI supports like integers, strings, booleans, enumerations and user defined types. @@ -330,7 +349,9 @@ strings, booleans, enumerations and user defined types. In this section we will focus on user defined types. Please, check the QAPI documentation for information about the other types. -=== User Defined Types === + +User Defined Types +~~~~~~~~~~~~~~~~~~ FIXME This example needs to be redone after commit 6d32717 @@ -344,63 +365,63 @@ returned as a string, the latter is an integer in nanoseconds (which is not very useful in practice, as the timer has probably already fired when the information reaches the client). -The best way to return that data is to create a new QAPI type, as shown below: +The best way to return that data is to create a new QAPI type, as shown below:: -## -# @QemuAlarmClock -# -# QEMU alarm clock information. -# -# @clock-name: The alarm clock method's name. -# -# @next-deadline: The time (in nanoseconds) the next alarm will fire. -# -# Since: 1.0 -## -{ 'type': 'QemuAlarmClock', - 'data': { 'clock-name': 'str', '*next-deadline': 'int' } } + ## + # @QemuAlarmClock + # + # QEMU alarm clock information. + # + # @clock-name: The alarm clock method's name. + # + # @next-deadline: The time (in nanoseconds) the next alarm will fire. + # + # Since: 1.0 + ## + { 'type': 'QemuAlarmClock', + 'data': { 'clock-name': 'str', '*next-deadline': 'int' } } The "type" keyword defines a new QAPI type. Its "data" member contains the type's members. In this example our members are the "clock-name" and the "next-deadline" one, which is optional. -Now let's define the query-alarm-clock command: +Now let's define the query-alarm-clock command:: -## -# @query-alarm-clock -# -# Return information about QEMU's alarm clock. -# -# Returns a @QemuAlarmClock instance describing the alarm clock method -# being currently used by QEMU (this is usually set by the '-clock' -# command-line option). -# -# Since: 1.0 -## -{ 'command': 'query-alarm-clock', 'returns': 'QemuAlarmClock' } + ## + # @query-alarm-clock + # + # Return information about QEMU's alarm clock. + # + # Returns a @QemuAlarmClock instance describing the alarm clock method + # being currently used by QEMU (this is usually set by the '-clock' + # command-line option). + # + # Since: 1.0 + ## + { 'command': 'query-alarm-clock', 'returns': 'QemuAlarmClock' } Notice the "returns" keyword. As its name suggests, it's used to define the data returned by a command. It's time to implement the qmp_query_alarm_clock() function, you can put it -in the qemu-timer.c file: +in the qemu-timer.c file:: -QemuAlarmClock *qmp_query_alarm_clock(Error **errp) -{ - QemuAlarmClock *clock; - int64_t deadline; + QemuAlarmClock *qmp_query_alarm_clock(Error **errp) + { + QemuAlarmClock *clock; + int64_t deadline; - clock = g_malloc0(sizeof(*clock)); + clock = g_malloc0(sizeof(*clock)); - deadline = qemu_next_alarm_deadline(); - if (deadline > 0) { - clock->has_next_deadline = true; - clock->next_deadline = deadline; - } - clock->clock_name = g_strdup(alarm_timer->name); + deadline = qemu_next_alarm_deadline(); + if (deadline > 0) { + clock->has_next_deadline = true; + clock->next_deadline = deadline; + } + clock->clock_name = g_strdup(alarm_timer->name); - return clock; -} + return clock; + } There are a number of things to be noticed: @@ -423,40 +444,42 @@ There are a number of things to be noticed: 6. You have to include "qapi/qapi-commands-misc.h" in qemu-timer.c Time to test the new command. Build qemu, run it as described in the "Testing" -section and try this: +section and try this:: -{ "execute": "query-alarm-clock" } -{ - "return": { - "next-deadline": 2368219, - "clock-name": "dynticks" - } -} + { "execute": "query-alarm-clock" } + { + "return": { + "next-deadline": 2368219, + "clock-name": "dynticks" + } + } -==== The HMP command ==== -Here's the HMP counterpart of the query-alarm-clock command: +The HMP command +~~~~~~~~~~~~~~~ -void hmp_info_alarm_clock(Monitor *mon) -{ - QemuAlarmClock *clock; - Error *err = NULL; +Here's the HMP counterpart of the query-alarm-clock command:: - clock = qmp_query_alarm_clock(&err); - if (err) { - monitor_printf(mon, "Could not query alarm clock information\n"); - error_free(err); - return; - } + void hmp_info_alarm_clock(Monitor *mon) + { + QemuAlarmClock *clock; + Error *err = NULL; - monitor_printf(mon, "Alarm clock method in use: '%s'\n", clock->clock_name); - if (clock->has_next_deadline) { - monitor_printf(mon, "Next alarm will fire in %" PRId64 " nanoseconds\n", - clock->next_deadline); - } + clock = qmp_query_alarm_clock(&err); + if (err) { + monitor_printf(mon, "Could not query alarm clock information\n"); + error_free(err); + return; + } - qapi_free_QemuAlarmClock(clock); -} + monitor_printf(mon, "Alarm clock method in use: '%s'\n", clock->clock_name); + if (clock->has_next_deadline) { + monitor_printf(mon, "Next alarm will fire in %" PRId64 " nanoseconds\n", + clock->next_deadline); + } + + qapi_free_QemuAlarmClock(clock); + } It's important to notice that hmp_info_alarm_clock() calls qapi_free_QemuAlarmClock() to free the data returned by qmp_query_alarm_clock(). @@ -471,7 +494,7 @@ it's good practice to always check for errors. Another important detail is that HMP's "info" commands don't go into the hmp-commands.hx. Instead, they go into the info_cmds[] table, which is defined -in the monitor/misc.c file. The entry for the "info alarmclock" follows: +in the monitor/misc.c file. The entry for the "info alarmclock" follows:: { .name = "alarmclock", @@ -483,63 +506,65 @@ in the monitor/misc.c file. The entry for the "info alarmclock" follows: To test this, run qemu and type "info alarmclock" in the user monitor. -=== Returning Lists === + +Returning Lists +~~~~~~~~~~~~~~~ For this example, we're going to return all available methods for the timer alarm, which is pretty much what the command-line option "-clock ?" does, except that we're also going to inform which method is in use. -This first step is to define a new type: +This first step is to define a new type:: -## -# @TimerAlarmMethod -# -# Timer alarm method information. -# -# @method-name: The method's name. -# -# @current: true if this alarm method is currently in use, false otherwise -# -# Since: 1.0 -## -{ 'type': 'TimerAlarmMethod', - 'data': { 'method-name': 'str', 'current': 'bool' } } + ## + # @TimerAlarmMethod + # + # Timer alarm method information. + # + # @method-name: The method's name. + # + # @current: true if this alarm method is currently in use, false otherwise + # + # Since: 1.0 + ## + { 'type': 'TimerAlarmMethod', + 'data': { 'method-name': 'str', 'current': 'bool' } } The command will be called "query-alarm-methods", here is its schema -specification: +specification:: -## -# @query-alarm-methods -# -# Returns information about available alarm methods. -# -# Returns: a list of @TimerAlarmMethod for each method -# -# Since: 1.0 -## -{ 'command': 'query-alarm-methods', 'returns': ['TimerAlarmMethod'] } + ## + # @query-alarm-methods + # + # Returns information about available alarm methods. + # + # Returns: a list of @TimerAlarmMethod for each method + # + # Since: 1.0 + ## + { 'command': 'query-alarm-methods', 'returns': ['TimerAlarmMethod'] } Notice the syntax for returning lists "'returns': ['TimerAlarmMethod']", this should be read as "returns a list of TimerAlarmMethod instances". -The C implementation follows: +The C implementation follows:: -TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp) -{ - TimerAlarmMethodList *method_list = NULL; - const struct qemu_alarm_timer *p; - bool current = true; + TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp) + { + TimerAlarmMethodList *method_list = NULL; + const struct qemu_alarm_timer *p; + bool current = true; - for (p = alarm_timers; p->name; p++) { - TimerAlarmMethod *value = g_malloc0(*value); - value->method_name = g_strdup(p->name); - value->current = current; - QAPI_LIST_PREPEND(method_list, value); - current = false; - } + for (p = alarm_timers; p->name; p++) { + TimerAlarmMethod *value = g_malloc0(*value); + value->method_name = g_strdup(p->name); + value->current = current; + QAPI_LIST_PREPEND(method_list, value); + current = false; + } - return method_list; -} + return method_list; + } The most important difference from the previous examples is the TimerAlarmMethodList type, which is automatically generated by the QAPI from @@ -557,41 +582,41 @@ first element of the alarm_timers array. Also notice that QAPI lists are handled by hand and we return the head of the list. Now Build qemu, run it as explained in the "Testing" section and try our new -command: +command:: -{ "execute": "query-alarm-methods" } -{ - "return": [ - { - "current": false, - "method-name": "unix" - }, - { - "current": true, - "method-name": "dynticks" - } - ] -} + { "execute": "query-alarm-methods" } + { + "return": [ + { + "current": false, + "method-name": "unix" + }, + { + "current": true, + "method-name": "dynticks" + } + ] + } The HMP counterpart is a bit more complex than previous examples because it -has to traverse the list, it's shown below for reference: +has to traverse the list, it's shown below for reference:: -void hmp_info_alarm_methods(Monitor *mon) -{ - TimerAlarmMethodList *method_list, *method; - Error *err = NULL; + void hmp_info_alarm_methods(Monitor *mon) + { + TimerAlarmMethodList *method_list, *method; + Error *err = NULL; - method_list = qmp_query_alarm_methods(&err); - if (err) { - monitor_printf(mon, "Could not query alarm methods\n"); - error_free(err); - return; - } + method_list = qmp_query_alarm_methods(&err); + if (err) { + monitor_printf(mon, "Could not query alarm methods\n"); + error_free(err); + return; + } - for (method = method_list; method; method = method->next) { - monitor_printf(mon, "%c %s\n", method->value->current ? '*' : ' ', - method->value->method_name); - } + for (method = method_list; method; method = method->next) { + monitor_printf(mon, "%c %s\n", method->value->current ? '*' : ' ', + method->value->method_name); + } - qapi_free_TimerAlarmMethodList(method_list); -} + qapi_free_TimerAlarmMethodList(method_list); + } From bccabb3a5d60182645c7749e89f21a9ff307a9eb Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 4 Aug 2021 16:56:14 +0100 Subject: [PATCH 486/531] Update version for v6.1.0-rc2 release Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index f51337edb0..7c5f12f378 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.91 +6.0.92 From 4cfd970ec188558daa6214f26203fe553fb1e01f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 19 Jul 2021 16:54:17 +0400 Subject: [PATCH 487/531] util: fix abstract socket path copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 776b97d360 "qemu-sockets: add abstract UNIX domain socket support" neglected to update socket_sockaddr_to_address_unix() and copied the whole sun_path without taking "salen" into account. Later, commit 3b14b4ec49 "sockets: Fix socket_sockaddr_to_address_unix() for abstract sockets" handled the abstract UNIX path, by stripping the leading \0 character and fixing address details, but didn't use salen either. Not taking "salen" into account may result in incorrect "path" being returned in monitors commands, as we read past the address which is not necessarily \0-terminated. Fixes: 776b97d3605ed0fc94443048fdf988c7725e38a9 Fixes: 3b14b4ec49a801067da19d6b8469eb1c1911c020 Signed-off-by: Marc-André Lureau Reviewed-by: xiaoqiang zhao Reviewed-by: Daniel P. Berrangé --- util/qemu-sockets.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 080a240b74..f2f3676d1f 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -1345,13 +1345,16 @@ socket_sockaddr_to_address_unix(struct sockaddr_storage *sa, SocketAddress *addr; struct sockaddr_un *su = (struct sockaddr_un *)sa; + assert(salen >= sizeof(su->sun_family) + 1 && + salen <= sizeof(struct sockaddr_un)); + addr = g_new0(SocketAddress, 1); addr->type = SOCKET_ADDRESS_TYPE_UNIX; #ifdef CONFIG_LINUX if (!su->sun_path[0]) { /* Linux abstract socket */ addr->u.q_unix.path = g_strndup(su->sun_path + 1, - sizeof(su->sun_path) - 1); + salen - sizeof(su->sun_family) - 1); addr->u.q_unix.has_abstract = true; addr->u.q_unix.abstract = true; addr->u.q_unix.has_tight = true; From 30f80be34ba6142dc7ba2015b98d661a9529b7c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 21 Jul 2021 16:55:53 +0400 Subject: [PATCH 488/531] chardev/socket: print a more correct command-line address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Better reflect the command line version of the socket address arguments, following the now recommended long-form opt=on syntax. Complement/fixes commit 9d902d51 "chardev: do not use short form boolean options in non-QemuOpts character device descriptions". Signed-off-by: Marc-André Lureau Reviewed-by: Philippe Mathieu-Daudé --- chardev/char-socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index d0fb545963..c43668cc15 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -468,9 +468,9 @@ static char *qemu_chr_socket_address(SocketChardev *s, const char *prefix) #ifdef CONFIG_LINUX if (sa->has_abstract && sa->abstract) { - abstract = ",abstract"; + abstract = ",abstract=on"; if (sa->has_tight && sa->tight) { - tight = ",tight"; + tight = ",tight=on"; } } #endif From 0c40c18ecd564a5c3f27f1408aaf9848fe210349 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 3 Aug 2021 19:18:58 +0200 Subject: [PATCH 489/531] linux-user: fix guest/host address mixup in i386 setup_rt_frame() setup_rt_frame() passes siginfo and ucontext host addresses to guest signal handlers, causing problems when e.g. emulating x86_64 on s390x. Signed-off-by: Ilya Leoshkevich Reviewed-by: Richard Henderson Message-Id: <20210803171858.148394-1-iii@linux.ibm.com> Signed-off-by: Laurent Vivier --- linux-user/i386/signal.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c index 8701774e37..841cd19651 100644 --- a/linux-user/i386/signal.c +++ b/linux-user/i386/signal.c @@ -436,13 +436,13 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, #ifndef TARGET_X86_64 env->regs[R_EAX] = sig; - env->regs[R_EDX] = (unsigned long)&frame->info; - env->regs[R_ECX] = (unsigned long)&frame->uc; + env->regs[R_EDX] = frame_addr + offsetof(struct rt_sigframe, info); + env->regs[R_ECX] = frame_addr + offsetof(struct rt_sigframe, uc); #else env->regs[R_EAX] = 0; env->regs[R_EDI] = sig; - env->regs[R_ESI] = (unsigned long)&frame->info; - env->regs[R_EDX] = (unsigned long)&frame->uc; + env->regs[R_ESI] = frame_addr + offsetof(struct rt_sigframe, info); + env->regs[R_EDX] = frame_addr + offsetof(struct rt_sigframe, uc); #endif cpu_x86_load_seg(env, R_DS, __USER_DS); From 030912e01c0385b6b09e76549c1a8a04b624f49a Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 3 Aug 2021 19:20:13 +0200 Subject: [PATCH 490/531] linux-user/elfload: byteswap i386 registers when dumping core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Core dumps from emulating x86_64 on big-endian hosts contain incorrect register values. Signed-off-by: Ilya Leoshkevich Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210803172013.148446-1-iii@linux.ibm.com> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 88 ++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 42ef2a1148..01e9a833fb 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -172,33 +172,33 @@ typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; */ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env) { - (*regs)[0] = env->regs[15]; - (*regs)[1] = env->regs[14]; - (*regs)[2] = env->regs[13]; - (*regs)[3] = env->regs[12]; - (*regs)[4] = env->regs[R_EBP]; - (*regs)[5] = env->regs[R_EBX]; - (*regs)[6] = env->regs[11]; - (*regs)[7] = env->regs[10]; - (*regs)[8] = env->regs[9]; - (*regs)[9] = env->regs[8]; - (*regs)[10] = env->regs[R_EAX]; - (*regs)[11] = env->regs[R_ECX]; - (*regs)[12] = env->regs[R_EDX]; - (*regs)[13] = env->regs[R_ESI]; - (*regs)[14] = env->regs[R_EDI]; - (*regs)[15] = env->regs[R_EAX]; /* XXX */ - (*regs)[16] = env->eip; - (*regs)[17] = env->segs[R_CS].selector & 0xffff; - (*regs)[18] = env->eflags; - (*regs)[19] = env->regs[R_ESP]; - (*regs)[20] = env->segs[R_SS].selector & 0xffff; - (*regs)[21] = env->segs[R_FS].selector & 0xffff; - (*regs)[22] = env->segs[R_GS].selector & 0xffff; - (*regs)[23] = env->segs[R_DS].selector & 0xffff; - (*regs)[24] = env->segs[R_ES].selector & 0xffff; - (*regs)[25] = env->segs[R_FS].selector & 0xffff; - (*regs)[26] = env->segs[R_GS].selector & 0xffff; + (*regs)[0] = tswapreg(env->regs[15]); + (*regs)[1] = tswapreg(env->regs[14]); + (*regs)[2] = tswapreg(env->regs[13]); + (*regs)[3] = tswapreg(env->regs[12]); + (*regs)[4] = tswapreg(env->regs[R_EBP]); + (*regs)[5] = tswapreg(env->regs[R_EBX]); + (*regs)[6] = tswapreg(env->regs[11]); + (*regs)[7] = tswapreg(env->regs[10]); + (*regs)[8] = tswapreg(env->regs[9]); + (*regs)[9] = tswapreg(env->regs[8]); + (*regs)[10] = tswapreg(env->regs[R_EAX]); + (*regs)[11] = tswapreg(env->regs[R_ECX]); + (*regs)[12] = tswapreg(env->regs[R_EDX]); + (*regs)[13] = tswapreg(env->regs[R_ESI]); + (*regs)[14] = tswapreg(env->regs[R_EDI]); + (*regs)[15] = tswapreg(env->regs[R_EAX]); /* XXX */ + (*regs)[16] = tswapreg(env->eip); + (*regs)[17] = tswapreg(env->segs[R_CS].selector & 0xffff); + (*regs)[18] = tswapreg(env->eflags); + (*regs)[19] = tswapreg(env->regs[R_ESP]); + (*regs)[20] = tswapreg(env->segs[R_SS].selector & 0xffff); + (*regs)[21] = tswapreg(env->segs[R_FS].selector & 0xffff); + (*regs)[22] = tswapreg(env->segs[R_GS].selector & 0xffff); + (*regs)[23] = tswapreg(env->segs[R_DS].selector & 0xffff); + (*regs)[24] = tswapreg(env->segs[R_ES].selector & 0xffff); + (*regs)[25] = tswapreg(env->segs[R_FS].selector & 0xffff); + (*regs)[26] = tswapreg(env->segs[R_GS].selector & 0xffff); } #else @@ -244,23 +244,23 @@ typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; */ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env) { - (*regs)[0] = env->regs[R_EBX]; - (*regs)[1] = env->regs[R_ECX]; - (*regs)[2] = env->regs[R_EDX]; - (*regs)[3] = env->regs[R_ESI]; - (*regs)[4] = env->regs[R_EDI]; - (*regs)[5] = env->regs[R_EBP]; - (*regs)[6] = env->regs[R_EAX]; - (*regs)[7] = env->segs[R_DS].selector & 0xffff; - (*regs)[8] = env->segs[R_ES].selector & 0xffff; - (*regs)[9] = env->segs[R_FS].selector & 0xffff; - (*regs)[10] = env->segs[R_GS].selector & 0xffff; - (*regs)[11] = env->regs[R_EAX]; /* XXX */ - (*regs)[12] = env->eip; - (*regs)[13] = env->segs[R_CS].selector & 0xffff; - (*regs)[14] = env->eflags; - (*regs)[15] = env->regs[R_ESP]; - (*regs)[16] = env->segs[R_SS].selector & 0xffff; + (*regs)[0] = tswapreg(env->regs[R_EBX]); + (*regs)[1] = tswapreg(env->regs[R_ECX]); + (*regs)[2] = tswapreg(env->regs[R_EDX]); + (*regs)[3] = tswapreg(env->regs[R_ESI]); + (*regs)[4] = tswapreg(env->regs[R_EDI]); + (*regs)[5] = tswapreg(env->regs[R_EBP]); + (*regs)[6] = tswapreg(env->regs[R_EAX]); + (*regs)[7] = tswapreg(env->segs[R_DS].selector & 0xffff); + (*regs)[8] = tswapreg(env->segs[R_ES].selector & 0xffff); + (*regs)[9] = tswapreg(env->segs[R_FS].selector & 0xffff); + (*regs)[10] = tswapreg(env->segs[R_GS].selector & 0xffff); + (*regs)[11] = tswapreg(env->regs[R_EAX]); /* XXX */ + (*regs)[12] = tswapreg(env->eip); + (*regs)[13] = tswapreg(env->segs[R_CS].selector & 0xffff); + (*regs)[14] = tswapreg(env->eflags); + (*regs)[15] = tswapreg(env->regs[R_ESP]); + (*regs)[16] = tswapreg(env->segs[R_SS].selector & 0xffff); } #endif From bf7b1eab252bc56b6bbb12a8909eae738435d6ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 4 Aug 2021 17:01:14 +0400 Subject: [PATCH 491/531] chardev: mark explicitly first argument as poisoned MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 9894dc0cdcc397ee5b26370bc53da6d360a363c2 "char: convert from GIOChannel to QIOChannel", the first argument to the watch callback can actually be a QIOChannel, which is not a GIOChannel (but a QEMU Object). Even though we never used that pointer, change the callback type to warn the users. Possibly a better fix later, we may want to store the callback and call it from intermediary functions. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- chardev/char-fe.c | 2 +- hw/char/cadence_uart.c | 2 +- hw/char/cmsdk-apb-uart.c | 2 +- hw/char/ibex_uart.c | 2 +- hw/char/nrf51_uart.c | 2 +- hw/char/serial.c | 2 +- hw/char/virtio-console.c | 2 +- hw/usb/redirect.c | 2 +- hw/virtio/vhost-user.c | 2 +- include/chardev/char-fe.h | 8 +++++++- monitor/monitor.c | 2 +- net/vhost-user.c | 4 ++-- 12 files changed, 19 insertions(+), 13 deletions(-) diff --git a/chardev/char-fe.c b/chardev/char-fe.c index 474715c5a9..7789f7be9c 100644 --- a/chardev/char-fe.c +++ b/chardev/char-fe.c @@ -354,7 +354,7 @@ void qemu_chr_fe_set_open(CharBackend *be, int fe_open) } guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond, - GIOFunc func, void *user_data) + FEWatchFunc func, void *user_data) { Chardev *s = be->chr; GSource *src; diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index ceb677bc5a..b4b5e8a3ee 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -288,7 +288,7 @@ static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size) uart_update_status(s); } -static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond, +static gboolean cadence_uart_xmit(void *do_not_use, GIOCondition cond, void *opaque) { CadenceUARTState *s = opaque; diff --git a/hw/char/cmsdk-apb-uart.c b/hw/char/cmsdk-apb-uart.c index ba2cbbee3d..f8dc89ee3d 100644 --- a/hw/char/cmsdk-apb-uart.c +++ b/hw/char/cmsdk-apb-uart.c @@ -191,7 +191,7 @@ static uint64_t uart_read(void *opaque, hwaddr offset, unsigned size) /* Try to send tx data, and arrange to be called back later if * we can't (ie the char backend is busy/blocking). */ -static gboolean uart_transmit(GIOChannel *chan, GIOCondition cond, void *opaque) +static gboolean uart_transmit(void *do_not_use, GIOCondition cond, void *opaque) { CMSDKAPBUART *s = CMSDK_APB_UART(opaque); int ret; diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c index 6b0c9330bf..9b0a817713 100644 --- a/hw/char/ibex_uart.c +++ b/hw/char/ibex_uart.c @@ -135,7 +135,7 @@ static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size) ibex_uart_update_irqs(s); } -static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond, +static gboolean ibex_uart_xmit(void *do_not_use, GIOCondition cond, void *opaque) { IbexUartState *s = opaque; diff --git a/hw/char/nrf51_uart.c b/hw/char/nrf51_uart.c index 045ca5fa40..3c6f982de9 100644 --- a/hw/char/nrf51_uart.c +++ b/hw/char/nrf51_uart.c @@ -75,7 +75,7 @@ static uint64_t uart_read(void *opaque, hwaddr addr, unsigned int size) return r; } -static gboolean uart_transmit(GIOChannel *chan, GIOCondition cond, void *opaque) +static gboolean uart_transmit(void *do_not_use, GIOCondition cond, void *opaque) { NRF51UARTState *s = NRF51_UART(opaque); int r; diff --git a/hw/char/serial.c b/hw/char/serial.c index bc2e322970..7061aacbce 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -220,7 +220,7 @@ static void serial_update_msl(SerialState *s) } } -static gboolean serial_watch_cb(GIOChannel *chan, GIOCondition cond, +static gboolean serial_watch_cb(void *do_not_use, GIOCondition cond, void *opaque) { SerialState *s = opaque; diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c index 6b132caa29..dd5a02e339 100644 --- a/hw/char/virtio-console.c +++ b/hw/char/virtio-console.c @@ -38,7 +38,7 @@ struct VirtConsole { * Callback function that's called from chardevs when backend becomes * writable. */ -static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond, +static gboolean chr_write_unblocked(void *do_not_use, GIOCondition cond, void *opaque) { VirtConsole *vcon = opaque; diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 1ec909a63a..5f0ef9cb3b 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -270,7 +270,7 @@ static int usbredir_read(void *priv, uint8_t *data, int count) return count; } -static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond, +static gboolean usbredir_write_unblocked(void *do_not_use, GIOCondition cond, void *opaque) { USBRedirDevice *dev = opaque; diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 29ea2b4fce..aec6cc1990 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -303,7 +303,7 @@ struct vhost_user_read_cb_data { int ret; }; -static gboolean vhost_user_read_cb(GIOChannel *source, GIOCondition condition, +static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, gpointer opaque) { struct vhost_user_read_cb_data *data = opaque; diff --git a/include/chardev/char-fe.h b/include/chardev/char-fe.h index a553843364..867ef1b3b2 100644 --- a/include/chardev/char-fe.h +++ b/include/chardev/char-fe.h @@ -174,6 +174,9 @@ void qemu_chr_fe_set_open(CharBackend *be, int fe_open); void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...) GCC_FMT_ATTR(2, 3); + +typedef gboolean (*FEWatchFunc)(void *do_not_use, GIOCondition condition, void *data); + /** * qemu_chr_fe_add_watch: * @cond: the condition to poll for @@ -188,10 +191,13 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...) * Note that you are responsible to update the front-end sources if * you are switching the main context with qemu_chr_fe_set_handlers(). * + * Warning: DO NOT use the first callback argument (it may be either + * a GIOChannel or a QIOChannel, depending on the underlying chardev) + * * Returns: the source tag */ guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond, - GIOFunc func, void *user_data); + FEWatchFunc func, void *user_data); /** * qemu_chr_fe_write: diff --git a/monitor/monitor.c b/monitor/monitor.c index b90c0f4051..46a171bca6 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -156,7 +156,7 @@ static inline bool monitor_is_hmp_non_interactive(const Monitor *mon) static void monitor_flush_locked(Monitor *mon); -static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond, +static gboolean monitor_unblocked(void *do_not_use, GIOCondition cond, void *opaque) { Monitor *mon = opaque; diff --git a/net/vhost-user.c b/net/vhost-user.c index ffbd94d944..6adfcd623a 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -208,8 +208,8 @@ static NetClientInfo net_vhost_user_info = { .set_vnet_le = vhost_user_set_vnet_endianness, }; -static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond, - void *opaque) +static gboolean net_vhost_user_watch(void *do_not_use, GIOCondition cond, + void *opaque) { NetVhostUserState *s = opaque; From bb2b058f1a4e4fe9031133f2f7876fb12b2104d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 4 Aug 2021 15:08:46 +0400 Subject: [PATCH 492/531] chardev: fix fd_chr_add_watch() when in != out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create child sources for the different streams, and dispatch on the parent source with the synthesized conditions. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- chardev/char-fd.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/chardev/char-fd.c b/chardev/char-fd.c index 1cd62f2779..743d3989b4 100644 --- a/chardev/char-fd.c +++ b/chardev/char-fd.c @@ -28,6 +28,7 @@ #include "qemu/sockets.h" #include "qapi/error.h" #include "chardev/char.h" +#include "chardev/char-fe.h" #include "io/channel-file.h" #include "chardev/char-fd.h" @@ -80,10 +81,85 @@ static int fd_chr_read_poll(void *opaque) return s->max_size; } +typedef struct FDSource { + GSource parent; + + GIOCondition cond; +} FDSource; + +static gboolean +fd_source_prepare(GSource *source, + gint *timeout_) +{ + FDSource *src = (FDSource *)source; + + return src->cond != 0; +} + +static gboolean +fd_source_check(GSource *source) +{ + FDSource *src = (FDSource *)source; + + return src->cond != 0; +} + +static gboolean +fd_source_dispatch(GSource *source, GSourceFunc callback, + gpointer user_data) +{ + FDSource *src = (FDSource *)source; + FEWatchFunc func = (FEWatchFunc)callback; + gboolean ret = G_SOURCE_CONTINUE; + + if (src->cond) { + ret = func(NULL, src->cond, user_data); + src->cond = 0; + } + + return ret; +} + +static GSourceFuncs fd_source_funcs = { + fd_source_prepare, + fd_source_check, + fd_source_dispatch, + NULL, NULL, NULL +}; + +static GSource *fd_source_new(FDChardev *chr) +{ + return g_source_new(&fd_source_funcs, sizeof(FDSource)); +} + +static gboolean child_func(GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + FDSource *parent = data; + + parent->cond |= condition; + + return G_SOURCE_CONTINUE; +} + static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond) { FDChardev *s = FD_CHARDEV(chr); - return qio_channel_create_watch(s->ioc_out, cond); + g_autoptr(GSource) source = fd_source_new(s); + + if (s->ioc_out) { + g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_out, cond & ~G_IO_IN); + g_source_set_callback(child, (GSourceFunc)child_func, source, NULL); + g_source_add_child_source(source, child); + } + if (s->ioc_in) { + g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_in, cond & ~G_IO_OUT); + g_source_set_callback(child, (GSourceFunc)child_func, source, NULL); + g_source_add_child_source(source, child); + } + + return g_steal_pointer(&source); } static void fd_chr_update_read_handler(Chardev *chr) From 46fe3ff6ea3e7a642b8545c0322ef5df873bd560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 23 Jul 2021 13:54:54 +0400 Subject: [PATCH 493/531] chardev: fix qemu_chr_open_fd() being called with fd=-1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "file" chardev may call qemu_chr_open_fd() with fd_in=-1. This may cause invalid system calls, as the QIOChannel is assumed to be properly initialized later on. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- chardev/char-fd.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/chardev/char-fd.c b/chardev/char-fd.c index 743d3989b4..c11b1037f9 100644 --- a/chardev/char-fd.c +++ b/chardev/char-fd.c @@ -39,6 +39,10 @@ static int fd_chr_write(Chardev *chr, const uint8_t *buf, int len) { FDChardev *s = FD_CHARDEV(chr); + if (!s->ioc_out) { + return -1; + } + return io_channel_send(s->ioc_out, buf, len); } @@ -209,15 +213,19 @@ void qemu_chr_open_fd(Chardev *chr, FDChardev *s = FD_CHARDEV(chr); char *name; - s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in)); - name = g_strdup_printf("chardev-file-in-%s", chr->label); - qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name); - g_free(name); - s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out)); - name = g_strdup_printf("chardev-file-out-%s", chr->label); - qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name); - g_free(name); - qemu_set_nonblock(fd_out); + if (fd_in >= 0) { + s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in)); + name = g_strdup_printf("chardev-file-in-%s", chr->label); + qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name); + g_free(name); + } + if (fd_out >= 0) { + s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out)); + name = g_strdup_printf("chardev-file-out-%s", chr->label); + qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name); + g_free(name); + qemu_set_nonblock(fd_out); + } } static void char_fd_class_init(ObjectClass *oc, void *data) From 733ba020846ccd21d832f2e9b62387a86c5ab8f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 23 Jul 2021 13:59:50 +0400 Subject: [PATCH 494/531] chardev: fix qemu_chr_open_fd() with fd_in==fd_out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "serial" chardev calls qemu_chr_open_fd() with the same fd. This may lead to double-close as each QIOChannel owns the fd. Instead, share the reference to the same QIOChannel. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- chardev/char-fd.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/chardev/char-fd.c b/chardev/char-fd.c index c11b1037f9..93c56913b4 100644 --- a/chardev/char-fd.c +++ b/chardev/char-fd.c @@ -211,20 +211,31 @@ void qemu_chr_open_fd(Chardev *chr, int fd_in, int fd_out) { FDChardev *s = FD_CHARDEV(chr); - char *name; + g_autofree char *name = NULL; + + if (fd_out >= 0) { + qemu_set_nonblock(fd_out); + } + + if (fd_out == fd_in && fd_in >= 0) { + s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in)); + name = g_strdup_printf("chardev-file-%s", chr->label); + qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name); + s->ioc_out = QIO_CHANNEL(object_ref(s->ioc_in)); + return; + } if (fd_in >= 0) { s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in)); name = g_strdup_printf("chardev-file-in-%s", chr->label); qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name); - g_free(name); } + if (fd_out >= 0) { s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out)); + g_free(name); name = g_strdup_printf("chardev-file-out-%s", chr->label); qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name); - g_free(name); - qemu_set_nonblock(fd_out); } } From 64195b0d365712c05ae922b7ff22cf136aac1400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 28 Jul 2021 15:34:43 +0400 Subject: [PATCH 495/531] chardev: give some context on chardev-add error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Description from Daniel P. Berrangé: > The original code reported: > > "attempt to add duplicate property 'char2' to object (type 'container')" > > Since adding yank support, the current code reports > > "duplicate yank instance" > > With this patch applied it now reports: > > "Failed to add chardev 'char2': duplicate yank instance" > > This is marginally better, but still not great, not that the original > error was great either. > > It would be nice if we could report > > "chardev with id 'char2' already exists" Related to: https://bugzilla.redhat.com/show_bug.cgi?id=1984721 Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- chardev/char.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/chardev/char.c b/chardev/char.c index d959eec522..f59a61774b 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -1031,27 +1031,26 @@ Chardev *qemu_chardev_new(const char *id, const char *typename, ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, Error **errp) { + ERRP_GUARD(); const ChardevClass *cc; ChardevReturn *ret; - Chardev *chr; + g_autoptr(Chardev) chr = NULL; cc = char_get_class(ChardevBackendKind_str(backend->type), errp); if (!cc) { - return NULL; + goto err; } chr = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)), backend, NULL, false, errp); if (!chr) { - return NULL; + goto err; } if (!object_property_try_add_child(get_chardevs_root(), id, OBJECT(chr), errp)) { - object_unref(OBJECT(chr)); - return NULL; + goto err; } - object_unref(OBJECT(chr)); ret = g_new0(ChardevReturn, 1); if (CHARDEV_IS_PTY(chr)) { @@ -1060,6 +1059,10 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, } return ret; + +err: + error_prepend(errp, "Failed to add chardev '%s': ", id); + return NULL; } ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend, From a68403b0a6843f106e381b0bbeaacb29f6d27255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 4 Aug 2021 19:12:54 +0400 Subject: [PATCH 496/531] chardev: report a simpler error about duplicated id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Report: "Chardev with id 'char2' already exists" Rather than: "Failed to add chardev 'char2': duplicate yank instance" Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- chardev/char.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/chardev/char.c b/chardev/char.c index f59a61774b..4595a8d430 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -1036,6 +1036,11 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, ChardevReturn *ret; g_autoptr(Chardev) chr = NULL; + if (qemu_chr_find(id)) { + error_setg(errp, "Chardev with id '%s' already exists", id); + return NULL; + } + cc = char_get_class(ChardevBackendKind_str(backend->type), errp); if (!cc) { goto err; From abc14fd05606274d8350f1f90d1ec7bc9e51aa21 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Fri, 6 Aug 2021 14:49:47 +0000 Subject: [PATCH 497/531] meson: fix logic for gnutls check The logic before was if not get_option('gnutls').auto() or have_system Which is equivalent to if get_option('gnutls').enabled() or get_option('gnutls').disabled() or have_system This means that the check for gnutls is performed even if gnutls is disabled, which means that the build system will insist on having libtasn1 if gnutls is found, even if gnutls support is disabled. When gnutls is disabled, the check for gnutls shouldn't be performed, to ensure that further build system logic (like the check for libtasn1) doesn't make decisions based on the presence of gnutls, rather than the gnutls option. After making this change, I can successfully ./configure --disable-gnutls on my system with gnutls installed, but not libtasn1. Signed-off-by: Alyssa Ross Message-Id: <20210806144947.321647-1-hi@alyssa.is> Acked-by: Paolo Bonzini --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index af9bbb83db..b3e7ec0e92 100644 --- a/meson.build +++ b/meson.build @@ -824,7 +824,7 @@ endif gnutls = not_found gnutls_crypto = not_found -if not get_option('gnutls').auto() or have_system +if get_option('gnutls').enabled() or (get_option('gnutls').auto() and have_system) # For general TLS support our min gnutls matches # that implied by our platform support matrix # From 5f4884c4412318a1adc105dea9cc28f7625ce730 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Mon, 9 Aug 2021 12:34:40 +0200 Subject: [PATCH 498/531] hw/nvme: fix missing variable initializers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coverity found that 'uuid', 'csi' and 'eui64' are uninitialized. While we set most of the fields, we do not explicitly set the rsvd2 field in the NvmeIdNsDescr header. Fix this by explicitly zero-initializing the variables. Reported-by: Coverity (CID 1458835, 1459295 and 1459580) Fixes: 6870cfb8140d ("hw/nvme: namespace parameter for EUI-64") Suggested-by: Peter Maydell Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé --- hw/nvme/ctrl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 43dfaeac9f..6baf9e0420 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -4663,15 +4663,15 @@ static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeRequest *req) struct { NvmeIdNsDescr hdr; uint8_t v[NVME_NIDL_UUID]; - } QEMU_PACKED uuid; + } QEMU_PACKED uuid = {}; struct { NvmeIdNsDescr hdr; uint64_t v; - } QEMU_PACKED eui64; + } QEMU_PACKED eui64 = {}; struct { NvmeIdNsDescr hdr; uint8_t v; - } QEMU_PACKED csi; + } QEMU_PACKED csi = {}; trace_pci_nvme_identify_ns_descr_list(nsid); From 50482fda98bd62e072c30b7ea73c985c4e9d9bbb Mon Sep 17 00:00:00 2001 From: Fabrice Fontaine Date: Mon, 9 Aug 2021 11:51:01 +0200 Subject: [PATCH 499/531] block/export/fuse.c: fix musl build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following build failure on musl raised since version 6.0.0 and https://gitlab.com/qemu-project/qemu/-/commit/4ca37a96a75aafe7a37ba51ab1912b09b7190a6b because musl does not define FALLOC_FL_ZERO_RANGE: ../block/export/fuse.c: In function 'fuse_fallocate': ../block/export/fuse.c:563:23: error: 'FALLOC_FL_ZERO_RANGE' undeclared (first use in this function) 563 | } else if (mode & FALLOC_FL_ZERO_RANGE) { | ^~~~~~~~~~~~~~~~~~~~ Fixes: - http://autobuild.buildroot.org/results/b96e3d364fd1f8bbfb18904a742e73327d308f64 Signed-off-by: Fabrice Fontaine Message-Id: <20210809095101.1101336-1-fontaine.fabrice@gmail.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Denis V. Lunev Signed-off-by: Hanna Reitz --- block/export/fuse.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index ada9e263eb..fc7b07d2b5 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -635,7 +635,9 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode, offset += size; length -= size; } while (ret == 0 && length > 0); - } else if (mode & FALLOC_FL_ZERO_RANGE) { + } +#ifdef CONFIG_FALLOCATE_ZERO_RANGE + else if (mode & FALLOC_FL_ZERO_RANGE) { if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + length > blk_len) { /* No need for zeroes, we are going to write them ourselves */ ret = fuse_do_truncate(exp, offset + length, false, @@ -654,7 +656,9 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode, offset += size; length -= size; } while (ret == 0 && length > 0); - } else if (!mode) { + } +#endif /* CONFIG_FALLOCATE_ZERO_RANGE */ + else if (!mode) { /* We can only fallocate at the EOF with a truncate */ if (offset < blk_len) { fuse_reply_err(req, EOPNOTSUPP); From a6d2bb25cf945cd16f29a575055c6f1a1f9cf6c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 4 Aug 2021 19:03:30 +0100 Subject: [PATCH 500/531] tests: filter out TLS distinguished name in certificate checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The version of GNUTLS in Fedora 34 has changed the order in which encodes fields when generating new TLS certificates. This in turn changes the order seen when querying the distinguished name. This ultimately breaks the expected output in the NBD TLS iotests. We don't need to be comparing the exact distinguished name text for the purpose of the test though, so it is fine to filter it out. Reported-by: Eric Blake Signed-off-by: Daniel P. Berrangé Message-Id: <20210804180330.3469683-1-berrange@redhat.com> Reviewed-by: Eric Blake Tested-by: Eric Blake Signed-off-by: Hanna Reitz --- tests/qemu-iotests/233 | 2 +- tests/qemu-iotests/233.out | 4 ++-- tests/qemu-iotests/common.filter | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233 index da150cd27b..9ca7b68f42 100755 --- a/tests/qemu-iotests/233 +++ b/tests/qemu-iotests/233 @@ -148,7 +148,7 @@ $QEMU_IMG info --image-opts \ echo echo "== final server log ==" -cat "$TEST_DIR/server.log" +cat "$TEST_DIR/server.log" | _filter_authz_check_tls rm -f "$TEST_DIR/server.log" # success, all done diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out index c3c344811b..4b1f6a0e15 100644 --- a/tests/qemu-iotests/233.out +++ b/tests/qemu-iotests/233.out @@ -65,6 +65,6 @@ qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': F == final server log == qemu-nbd: option negotiation failed: Verify failed: No certificate was found. qemu-nbd: option negotiation failed: Verify failed: No certificate was found. -qemu-nbd: option negotiation failed: TLS x509 authz check for CN=localhost,O=Cthulhu Dark Lord Enterprises client1,L=R'lyeh,C=South Pacific is denied -qemu-nbd: option negotiation failed: TLS x509 authz check for CN=localhost,O=Cthulhu Dark Lord Enterprises client3,L=R'lyeh,C=South Pacific is denied +qemu-nbd: option negotiation failed: TLS x509 authz check for DISTINGUISHED-NAME is denied +qemu-nbd: option negotiation failed: TLS x509 authz check for DISTINGUISHED-NAME is denied *** done diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 268b749e2f..2b2b53946c 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -332,5 +332,10 @@ for fname in fnames: sys.stdout.write(result)' } +_filter_authz_check_tls() +{ + $SED -e 's/TLS x509 authz check for .* is denied/TLS x509 authz check for DISTINGUISHED-NAME is denied/' +} + # make sure this script returns success true From 057489dd1586612b99b4b98d211bf7f0a9d6f0e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 9 Aug 2021 14:10:29 +0100 Subject: [PATCH 501/531] qga: fix leak of base64 decoded data on command error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the guest command fails to be spawned, then we would leak the decoded base64 input used for the command's stdin feed. Signed-off-by: Daniel P. Berrangé Reviewed-by: Marc-André Lureau Signed-off-by: Michael Roth --- qga/commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qga/commands.c b/qga/commands.c index a6491d2cf8..80501e4a73 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -402,7 +402,7 @@ GuestExec *qmp_guest_exec(const char *path, GIOChannel *in_ch, *out_ch, *err_ch; GSpawnFlags flags; bool has_output = (has_capture_output && capture_output); - uint8_t *input = NULL; + g_autofree uint8_t *input = NULL; size_t ninput = 0; arglist.value = (char *)path; @@ -441,7 +441,7 @@ GuestExec *qmp_guest_exec(const char *path, g_child_watch_add(pid, guest_exec_child_watch, gei); if (has_input_data) { - gei->in.data = input; + gei->in.data = g_steal_pointer(&input); gei->in.size = ninput; #ifdef G_OS_WIN32 in_ch = g_io_channel_win32_new_fd(in_fd); From 7bce330ae4040860ddb5ce66dc7999f16577855c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Tue, 10 Aug 2021 08:32:57 +0200 Subject: [PATCH 502/531] ui/gtk: retry sending VTE console input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 584af1f1d9 ("ui/gtk: add a keyboard fifo to the VTE consoles") changed the VTE chardev backend code to rely on the chr_accept_input() callback function. The code expects a chr_accept_input() call whenever qemu_chr_be_can_write() bytes were written. It turns out this is wrong. Some chardev frontends only call this callback after can_write was 0. Change the code to send data until the keyboard fifo is empty or qemu_chr_be_can_write() returns 0. Fixes: 584af1f1d9 ("ui/gtk: add a keyboard fifo to the VTE consoles") Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Message-Id: <20210810063257.17411-1-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 974e4dfc0b..cfb0728d1f 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1646,16 +1646,14 @@ static void gd_vc_send_chars(VirtualConsole *vc) len = qemu_chr_be_can_write(vc->vte.chr); avail = fifo8_num_used(&vc->vte.out_fifo); - if (len > avail) { - len = avail; - } - while (len > 0) { + while (len > 0 && avail > 0) { const uint8_t *buf; uint32_t size; - buf = fifo8_pop_buf(&vc->vte.out_fifo, len, &size); + buf = fifo8_pop_buf(&vc->vte.out_fifo, MIN(len, avail), &size); qemu_chr_be_write(vc->vte.chr, (uint8_t *)buf, size); - len -= size; + len = qemu_chr_be_can_write(vc->vte.chr); + avail -= size; } } From da77adbaf619c4d170cb42d769145ad1803fbad9 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 9 Aug 2021 18:09:56 +0100 Subject: [PATCH 503/531] audio: Never send migration section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The audio migration vmstate is empty, and always has been; we can't just remove it though because an old qemu might send it us. Changes with -audiodev now mean it's sometimes created when it didn't used to be, and can confuse migration to old qemu. Change it so that vmstate_audio is never sent; if it's received it should still be accepted, and old qemu's shouldn't be too upset if it's missing. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Daniel P. Berrangé Tested-by: Daniel P. Berrangé Message-Id: <20210809170956.78536-1-dgilbert@redhat.com> Signed-off-by: Gerd Hoffmann --- audio/audio.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/audio/audio.c b/audio/audio.c index 59453ef856..54a153c0ef 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1622,10 +1622,20 @@ void audio_cleanup(void) } } +static bool vmstate_audio_needed(void *opaque) +{ + /* + * Never needed, this vmstate only exists in case + * an old qemu sends it to us. + */ + return false; +} + static const VMStateDescription vmstate_audio = { .name = "audio", .version_id = 1, .minimum_version_id = 1, + .needed = vmstate_audio_needed, .fields = (VMStateField[]) { VMSTATE_END_OF_LIST() } From 6ff5b5d6d521001135d1bd5c609e8834099f01d8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 9 Aug 2021 17:14:24 +0100 Subject: [PATCH 504/531] ui/sdl2: Check return value from g_setenv() Setting environment variables can fail; check the return value from g_setenv() and bail out if we couldn't set SDL_VIDEODRIVER. Fixes: Coverity 1458798 Signed-off-by: Peter Maydell Message-Id: <20210809161424.32355-1-peter.maydell@linaro.org> Signed-off-by: Gerd Hoffmann --- ui/sdl2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/sdl2.c b/ui/sdl2.c index 36d9010cb6..17c0ec30eb 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -817,7 +817,10 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) * This is a bit hackish but saves us from bigger problem. * Maybe it's a good idea to fix this in SDL instead. */ - g_setenv("SDL_VIDEODRIVER", "x11", 0); + if (!g_setenv("SDL_VIDEODRIVER", "x11", 0)) { + fprintf(stderr, "Could not set SDL_VIDEODRIVER environment variable\n"); + exit(1); + } #endif if (SDL_Init(SDL_INIT_VIDEO)) { From b0c4798f97e812e3372455e14bcdb10f41823732 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Tue, 10 Aug 2021 16:04:11 +0200 Subject: [PATCH 505/531] MAINTAINERS: Name and email address change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I have changed my name and email address. Update the MAINTAINERS file to match, and .mailmap in case anyone wants to send me an email because of some past commit I authored. (As suggested by Philippe, I put the .mailmap line into the "preferred name forms" section, considering it counts as a git author config change.) Signed-off-by: Hanna Reitz Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- .mailmap | 1 + MAINTAINERS | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.mailmap b/.mailmap index 082ff893ab..f029d1c21f 100644 --- a/.mailmap +++ b/.mailmap @@ -100,6 +100,7 @@ Gautham R. Shenoy Gonglei (Arei) Guang Wang Hailiang Zhang +Hanna Reitz Hervé Poussineau Jakub Jermář Jakub Jermář diff --git a/MAINTAINERS b/MAINTAINERS index 37b1a8e442..694973ed23 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2270,7 +2270,7 @@ F: tests/qtest/fuzz-sb16-test.c Block layer core M: Kevin Wolf -M: Max Reitz +M: Hanna Reitz L: qemu-block@nongnu.org S: Supported F: block* @@ -3265,7 +3265,7 @@ F: stubs/io_uring.c qcow2 M: Kevin Wolf -M: Max Reitz +M: Hanna Reitz L: qemu-block@nongnu.org S: Supported F: block/qcow2* @@ -3279,7 +3279,7 @@ F: block/qcow.c blkdebug M: Kevin Wolf -M: Max Reitz +M: Hanna Reitz L: qemu-block@nongnu.org S: Supported F: block/blkdebug.c @@ -3314,7 +3314,7 @@ F: tests/qtest/vhost-user-blk-test.c F: util/vhost-user-server.c FUSE block device exports -M: Max Reitz +M: Hanna Reitz L: qemu-block@nongnu.org S: Supported F: block/export/fuse.c From 703e8cd6189cf699c8d5c094bc68b5f3afa6ad71 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 10 Aug 2021 19:08:09 +0100 Subject: [PATCH 506/531] Update version for v6.1.0-rc3 release Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7c5f12f378..71858d966e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.92 +6.0.93 From a62354915bd5285f338e6c624b146ae5e25b50b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 10 Aug 2021 15:06:52 +0100 Subject: [PATCH 507/531] gitlab: exclude sparc-softmmu and riscv32-softmmu from cross builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to cut down compile time by excluding more targets. Both these targets still have their 64-bit variant enabled, so the loss of coverage is mitigated to some degree. Signed-off-by: Daniel P. Berrangé Reviewed-by: Willian Rampazzo Message-Id: <20210810140653.3969823-2-berrange@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/crossbuild-template.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.d/crossbuild-template.yml b/.gitlab-ci.d/crossbuild-template.yml index 7d3ad00a1e..cfb576b54c 100644 --- a/.gitlab-ci.d/crossbuild-template.yml +++ b/.gitlab-ci.d/crossbuild-template.yml @@ -9,7 +9,8 @@ ../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS --disable-user --target-list-exclude="arm-softmmu cris-softmmu i386-softmmu microblaze-softmmu mips-softmmu mipsel-softmmu - mips64-softmmu ppc-softmmu sh4-softmmu xtensa-softmmu" + mips64-softmmu ppc-softmmu riscv32-softmmu sh4-softmmu + sparc-softmmu xtensa-softmmu" - make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS - if grep -q "EXESUF=.exe" config-host.mak; then make installer; From f492bdf4abeb593f95eb9026d5bce54afb65d575 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 10 Aug 2021 10:34:44 +0200 Subject: [PATCH 508/531] MAINTAINERS: update edk2 entry. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I want keep an eye on the edk2 things happening in qemu. Cc: Philippe Mathieu-Daudé Signed-off-by: Gerd Hoffmann Message-Id: <20210810083450.2377374-2-kraxel@redhat.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 694973ed23..d6c84bd0a9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2947,6 +2947,7 @@ F: docs/interop/firmware.json EDK2 Firmware M: Philippe Mathieu-Daudé +R: Gerd Hoffmann S: Supported F: hw/i386/*ovmf* F: pc-bios/descriptors/??-edk2-*.json From 8f6259055a1aac60663b4a853cf8e383e30d1de0 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 10 Aug 2021 10:34:45 +0200 Subject: [PATCH 509/531] MAINTAINERS: update sockets entry. I have not touched the code for years. Make the entry match reality and drop my name. Cc: Daniel P. Berrange Signed-off-by: Gerd Hoffmann Message-Id: <20210810083450.2377374-3-kraxel@redhat.com> --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index d6c84bd0a9..79b0148cfc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2843,7 +2843,6 @@ F: tests/unit/test-authz-* Sockets M: Daniel P. Berrange -M: Gerd Hoffmann S: Maintained F: include/qemu/sockets.h F: util/qemu-sockets.c From 6bc915f31a436a44119b8e1ef7413518eb8865d1 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 10 Aug 2021 10:34:46 +0200 Subject: [PATCH 510/531] MAINTAINERS: update audio entry. New maintainer wanted. Downgrade status to "Odd Fixes" for now. Signed-off-by: Gerd Hoffmann Message-Id: <20210810083450.2377374-4-kraxel@redhat.com> --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 79b0148cfc..5cb402d402 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2258,7 +2258,7 @@ Subsystems ---------- Audio M: Gerd Hoffmann -S: Maintained +S: Odd Fixes F: audio/ F: hw/audio/ F: include/hw/audio/ From 227b1638ba39b7b3dedf0d9ad6ae2c4908688a8c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 10 Aug 2021 10:34:47 +0200 Subject: [PATCH 511/531] MAINTAINERS: update spice entry. New maintainer wanted. Downgrade status to "Odd Fixes" for now. Signed-off-by: Gerd Hoffmann Message-Id: <20210810083450.2377374-5-kraxel@redhat.com> --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5cb402d402..33b4fc25e3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2470,7 +2470,7 @@ F: scripts/coccinelle/memory-region-housekeeping.cocci SPICE M: Gerd Hoffmann -S: Supported +S: Odd Fixes F: include/ui/qemu-spice.h F: include/ui/spice-display.h F: ui/spice-*.c From cd02c965c4b65a488af44f1bf52d466f5c858cc2 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 10 Aug 2021 10:34:48 +0200 Subject: [PATCH 512/531] MAINTAINERS: update usb entries. New maintainer wanted. Switch role to "Reviewer" for usb-serial, downgrade status to "Odd Fixes" for everything else. Cc: Samuel Thibault Signed-off-by: Gerd Hoffmann Message-Id: <20210810083450.2377374-6-kraxel@redhat.com> --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 33b4fc25e3..b84b7e33e4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1832,7 +1832,7 @@ F: tests/qtest/sdhci-test.c USB M: Gerd Hoffmann -S: Maintained +S: Odd Fixes F: hw/usb/* F: stubs/usb-dev-stub.c F: tests/qtest/usb-*-test.c @@ -1841,7 +1841,7 @@ F: include/hw/usb.h F: include/hw/usb/ USB (serial adapter) -M: Gerd Hoffmann +R: Gerd Hoffmann M: Samuel Thibault S: Maintained F: hw/usb/dev-serial.c From 1e2edb986608a35e874a77c5e8e71f056c1681b6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 10 Aug 2021 10:34:49 +0200 Subject: [PATCH 513/531] MAINTAINERS: update virtio-input entry. New maintainer wanted. Downgrade status to "Odd Fixes" for now. Signed-off-by: Gerd Hoffmann Message-Id: <20210810083450.2377374-7-kraxel@redhat.com> --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index b84b7e33e4..6e86426572 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1951,7 +1951,7 @@ L: virtio-fs@redhat.com virtio-input M: Gerd Hoffmann -S: Maintained +S: Odd Fixes F: hw/input/vhost-user-input.c F: hw/input/virtio-input*.c F: include/hw/virtio/virtio-input.h From a4de5e8a0667e3ee43ca9953ec7fd11ff19f2c92 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 10 Aug 2021 10:34:50 +0200 Subject: [PATCH 514/531] MAINTAINERS: update virtio-gpu entry. New maintainer wanted. Downgrade status to "Odd Fixes" for now. Signed-off-by: Gerd Hoffmann Message-Id: <20210810083450.2377374-8-kraxel@redhat.com> --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 6e86426572..6b3697962c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2157,7 +2157,7 @@ F: include/hw/display/ramfb.h virtio-gpu M: Gerd Hoffmann -S: Maintained +S: Odd Fixes F: hw/display/virtio-gpu* F: hw/display/virtio-vga.* F: include/hw/virtio/virtio-gpu.h @@ -2176,7 +2176,7 @@ F: include/hw/virtio/vhost-user-scsi.h vhost-user-gpu M: Marc-André Lureau -M: Gerd Hoffmann +R: Gerd Hoffmann S: Maintained F: docs/interop/vhost-user-gpu.rst F: contrib/vhost-user-gpu From a1f0f36838caa8d8dbde4b5be2f889942fb66fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 10 Aug 2021 15:06:53 +0100 Subject: [PATCH 515/531] gitlab: skip many more targets in windows cross builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The windows cross builds still take way too long in gitlab CI, so need more targets to be skipped. We don't want to hurt coverage of other cross builds more though, so we let jobs fine tune with a new env variale $CROSS_SKIP_TARGETS. We take the set of targets that are considered relatively niche or very old architectures, and skip approx half of them in win32 builds and the other half of them in win64. Signed-off-by: Daniel P. Berrangé Reviewed-by: Willian Rampazzo Message-Id: <20210810140653.3969823-3-berrange@redhat.com> [thuth: Swapped the "CROSS_SKIP_TARGETS:" lines as suggested by philmd] Signed-off-by: Thomas Huth --- .gitlab-ci.d/crossbuild-template.yml | 2 +- .gitlab-ci.d/crossbuilds.yml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.d/crossbuild-template.yml b/.gitlab-ci.d/crossbuild-template.yml index cfb576b54c..10d22dcf6c 100644 --- a/.gitlab-ci.d/crossbuild-template.yml +++ b/.gitlab-ci.d/crossbuild-template.yml @@ -10,7 +10,7 @@ --disable-user --target-list-exclude="arm-softmmu cris-softmmu i386-softmmu microblaze-softmmu mips-softmmu mipsel-softmmu mips64-softmmu ppc-softmmu riscv32-softmmu sh4-softmmu - sparc-softmmu xtensa-softmmu" + sparc-softmmu xtensa-softmmu $CROSS_SKIP_TARGETS" - make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS - if grep -q "EXESUF=.exe" config-host.mak; then make installer; diff --git a/.gitlab-ci.d/crossbuilds.yml b/.gitlab-ci.d/crossbuilds.yml index 4ff3aa3cfc..f10168db2e 100644 --- a/.gitlab-ci.d/crossbuilds.yml +++ b/.gitlab-ci.d/crossbuilds.yml @@ -160,6 +160,8 @@ cross-win32-system: job: win32-fedora-cross-container variables: IMAGE: fedora-win32-cross + CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu m68k-softmmu + microblazeel-softmmu mips64el-softmmu nios2-softmmu artifacts: paths: - build/qemu-setup*.exe @@ -170,6 +172,8 @@ cross-win64-system: job: win64-fedora-cross-container variables: IMAGE: fedora-win64-cross + CROSS_SKIP_TARGETS: or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu + tricore-softmmu xtensaeb-softmmu artifacts: paths: - build/qemu-setup*.exe From cc1838c25d55e7f478cd493431679337e24e1b72 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 11 Aug 2021 11:47:05 +0200 Subject: [PATCH 516/531] storage-daemon: Add missing build dependency to the vhost-user-blk-test vhost-user-blk-test needs the qemu-storage-daemon, otherwise it currently hangs. So make sure that we build the daemon before running the tests. Message-Id: <20210811094705.131314-1-thuth@redhat.com> Tested-by: Alexander Bulekov Signed-off-by: Thomas Huth --- storage-daemon/meson.build | 8 ++++---- tests/qtest/meson.build | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/storage-daemon/meson.build b/storage-daemon/meson.build index 68852f3d25..49c9d2eac9 100644 --- a/storage-daemon/meson.build +++ b/storage-daemon/meson.build @@ -6,8 +6,8 @@ subdir('qapi') if have_tools qsd_ss = qsd_ss.apply(config_host, strict: false) - executable('qemu-storage-daemon', - qsd_ss.sources(), - dependencies: qsd_ss.dependencies(), - install: true) + qsd = executable('qemu-storage-daemon', + qsd_ss.sources(), + dependencies: qsd_ss.dependencies(), + install: true) endif diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index e22a0792c5..2bc3efd49f 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -276,8 +276,11 @@ foreach dir : target_dirs endif qtest_env.set('G_TEST_DBUS_DAEMON', meson.source_root() / 'tests/dbus-vmstate-daemon.sh') qtest_env.set('QTEST_QEMU_BINARY', './qemu-system-' + target_base) - qtest_env.set('QTEST_QEMU_STORAGE_DAEMON_BINARY', './storage-daemon/qemu-storage-daemon') - + if have_tools and have_vhost_user_blk_server + qtest_env.set('QTEST_QEMU_STORAGE_DAEMON_BINARY', './storage-daemon/qemu-storage-daemon') + test_deps += [qsd] + endif + foreach test : target_qtests # Executables are shared across targets, declare them only the first time we # encounter them From b063c290f3d28a3142e90a1717b26b55ec1a7d17 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 11 Aug 2021 11:59:49 +0200 Subject: [PATCH 517/531] tests/qtest/vhost-user-blk-test: Check whether qemu-storage-daemon is available The vhost-user-blk-test currently hangs if QTEST_QEMU_STORAGE_DAEMON_BINARY points to a non-existing binary. Let's improve this situation by checking for the availability of the binary first, so we can fail gracefully if it is not accessible. Message-Id: <20210811095949.133462-1-thuth@redhat.com> Reviewed-by: Alexander Bulekov Tested-by: Alexander Bulekov Signed-off-by: Thomas Huth --- tests/qtest/vhost-user-blk-test.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk-test.c index 8796c74ca4..6f108a1b62 100644 --- a/tests/qtest/vhost-user-blk-test.c +++ b/tests/qtest/vhost-user-blk-test.c @@ -789,6 +789,14 @@ static const char *qtest_qemu_storage_daemon_binary(void) exit(0); } + /* If we've got a path to the binary, check whether we can access it */ + if (strchr(qemu_storage_daemon_bin, '/') && + access(qemu_storage_daemon_bin, X_OK) != 0) { + fprintf(stderr, "ERROR: '%s' is not accessible\n", + qemu_storage_daemon_bin); + exit(1); + } + return qemu_storage_daemon_bin; } From 3973e7ae63cdbd974731e590fcca694d46a82bd2 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Mon, 9 Aug 2021 07:16:21 -0400 Subject: [PATCH 518/531] fuzz: avoid building twice, when running on gitlab On oss-fuzz, we build twice, to put together a build that is portable to the runner containers. On gitlab ci, this is wasteful and contributes to timeouts on the build-oss-fuzz job. Avoid building twice on gitlab, at the remote cost of potentially missing some cases that break oss-fuzz builds. Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny Message-Id: <20210809111621.54454-1-alxndr@bu.edu> Signed-off-by: Thomas Huth --- scripts/oss-fuzz/build.sh | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/scripts/oss-fuzz/build.sh b/scripts/oss-fuzz/build.sh index c1af43fded..98b56e0521 100755 --- a/scripts/oss-fuzz/build.sh +++ b/scripts/oss-fuzz/build.sh @@ -73,17 +73,19 @@ if ! make "-j$(nproc)" qemu-fuzz-i386; then "\nFor example: CC=clang CXX=clang++ $0" fi -for i in $(ldd ./qemu-fuzz-i386 | cut -f3 -d' '); do - cp "$i" "$DEST_DIR/lib/" -done -rm qemu-fuzz-i386 +if [ "$GITLAB_CI" != "true" ]; then + for i in $(ldd ./qemu-fuzz-i386 | cut -f3 -d' '); do + cp "$i" "$DEST_DIR/lib/" + done + rm qemu-fuzz-i386 -# Build a second time to build the final binary with correct rpath -../configure --disable-werror --cc="$CC" --cxx="$CXX" --enable-fuzzing \ - --prefix="$DEST_DIR" --bindir="$DEST_DIR" --datadir="$DEST_DIR/data/" \ - --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="-Wl,-rpath,\$ORIGIN/lib" \ - --target-list="i386-softmmu" -make "-j$(nproc)" qemu-fuzz-i386 V=1 + # Build a second time to build the final binary with correct rpath + ../configure --disable-werror --cc="$CC" --cxx="$CXX" --enable-fuzzing \ + --prefix="$DEST_DIR" --bindir="$DEST_DIR" --datadir="$DEST_DIR/data/" \ + --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="-Wl,-rpath,\$ORIGIN/lib" \ + --target-list="i386-softmmu" + make "-j$(nproc)" qemu-fuzz-i386 V=1 +fi # Copy over the datadir cp -r ../pc-bios/ "$DEST_DIR/pc-bios" From 3d9c7ec95583bf51cfc21f64fd62567711b895eb Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 11 Aug 2021 10:40:58 +0200 Subject: [PATCH 519/531] docs/about/removed-features: Document removed CLI options from QEMU v2.12 These CLI options had been removed/replaced in QEMU v2.12. Still, some people might want to update from older versions to the recent QEMU version, so we should give some recommendations for the replacements in our documentation. Message-Id: <20210811084103.74832-2-thuth@redhat.com> Signed-off-by: Thomas Huth --- docs/about/removed-features.rst | 39 +++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 07d597847c..c18af3c76f 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -9,8 +9,43 @@ trouble after a recent upgrade. System emulator command line arguments -------------------------------------- -``-net ...,name=``\ *name* (removed in 5.1) -''''''''''''''''''''''''''''''''''''''''''' +``-hdachs`` (removed in 2.12) +''''''''''''''''''''''''''''' + +The geometry defined by ``-hdachs c,h,s,t`` should now be specified via +``-device ide-hd,drive=dr,cyls=c,heads=h,secs=s,bios-chs-trans=t`` +(together with ``-drive if=none,id=dr,...``). + +``-net channel`` (removed in 2.12) +'''''''''''''''''''''''''''''''''' + +This option has been replaced by ``-net user,guestfwd=...``. + +``-net dump`` (removed in 2.12) +''''''''''''''''''''''''''''''' + +``-net dump[,vlan=n][,file=filename][,len=maxlen]`` has been replaced by +``-object filter-dump,id=id,netdev=dev[,file=filename][,maxlen=maxlen]``. +Note that the new syntax works with netdev IDs instead of the old "vlan" hubs. + +``-no-kvm-pit`` (removed in 2.12) +''''''''''''''''''''''''''''''''' + +This was just a dummy option that has been ignored, since the in-kernel PIT +cannot be disabled separately from the irqchip anymore. A similar effect +(which also disables the KVM IOAPIC) can be obtained with +``-M kernel_irqchip=split``. + +``-tdf`` (removed in 2.12) +'''''''''''''''''''''''''' + +There is no replacement, the ``-tdf`` option has just been ignored since the +behaviour that could be changed by this option in qemu-kvm is now the default +when using the KVM PIT. It still can be requested explicitly using +``-global kvm-pit.lost_tick_policy=delay``. + +``-net ...,name=...`` (removed in 5.1) +'''''''''''''''''''''''''''''''''''''' The ``name`` parameter of the ``-net`` option was a synonym for the ``id`` parameter, which should now be used instead. From 8cc461c18554e058a6dcd5cdebea1fdcba3debb7 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 11 Aug 2021 10:40:59 +0200 Subject: [PATCH 520/531] docs/about/removed-features: Document removed CLI options from QEMU v3.0 These CLI options had been removed/replaced in QEMU v3.0. Still, some people might want to update from older versions to the recent QEMU version, so we should give some recommendations for the replacements in our documentation. Message-Id: <20210811084103.74832-3-thuth@redhat.com> Signed-off-by: Thomas Huth --- docs/about/removed-features.rst | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index c18af3c76f..c4b702968e 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -44,6 +44,41 @@ behaviour that could be changed by this option in qemu-kvm is now the default when using the KVM PIT. It still can be requested explicitly using ``-global kvm-pit.lost_tick_policy=delay``. +``-drive secs=s``, ``-drive heads=h`` & ``-drive cyls=c`` (removed in 3.0) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The drive geometry should now be specified via +``-device ...,drive=dr,cyls=c,heads=h,secs=s`` (together with +``-drive if=none,id=dr,...``). + +``-drive serial=``, ``-drive trans=`` & ``-drive addr=`` (removed in 3.0) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Use ``-device ...,drive=dr,serial=r,bios-chs-trans=t,addr=a`` instead +(together with ``-drive if=none,id=dr,...``). + +``-net ...,vlan=x`` (removed in 3.0) +'''''''''''''''''''''''''''''''''''' + +The term "vlan" was very confusing for most users in this context (it's about +specifying a hub ID, not about IEEE 802.1Q or something similar), so this +has been removed. To connect one NIC frontend with a network backend, either +use ``-nic ...`` (e.g. for on-board NICs) or use ``-netdev ...,id=n`` together +with ``-device ...,netdev=n`` (for full control over pluggable NICs). To +connect multiple NICs or network backends via a hub device (which is what +vlan did), use ``-nic hubport,hubid=x,...`` or +``-netdev hubport,id=n,hubid=x,...`` (with ``-device ...,netdev=n``) instead. + +``-no-kvm-irqchip`` (removed in 3.0) +'''''''''''''''''''''''''''''''''''' + +Use ``-machine kernel_irqchip=off`` instead. + +``-no-kvm-pit-reinjection`` (removed in 3.0) +'''''''''''''''''''''''''''''''''''''''''''' + +Use ``-global kvm-pit.lost_tick_policy=discard`` instead. + ``-net ...,name=...`` (removed in 5.1) '''''''''''''''''''''''''''''''''''''' From 29e0447551fac46a6e70670035e239a27e362fce Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 11 Aug 2021 10:41:00 +0200 Subject: [PATCH 521/531] docs/about/removed-features: Document removed CLI options from QEMU v3.1 These CLI options had been removed/replaced in QEMU v3.1. Still, some people might want to update from older versions to the recent QEMU version, so we should give some recommendations for the replacements in our documentation. Message-Id: <20210811084103.74832-4-thuth@redhat.com> Signed-off-by: Thomas Huth --- docs/about/removed-features.rst | 67 +++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index c4b702968e..40d2cc4ffa 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -79,6 +79,73 @@ Use ``-machine kernel_irqchip=off`` instead. Use ``-global kvm-pit.lost_tick_policy=discard`` instead. +``-balloon`` (removed in 3.1) +''''''''''''''''''''''''''''' + +The ``-balloon virtio`` option has been replaced by ``-device virtio-balloon``. +The ``-balloon none`` option was a no-op and has no replacement. + +``-bootp`` (removed in 3.1) +''''''''''''''''''''''''''' + +The ``-bootp /some/file`` argument is replaced by either +``-netdev user,id=x,bootp=/some/file`` (for pluggable NICs, accompanied with +``-device ...,netdev=x``), or ``-nic user,bootp=/some/file`` (for on-board NICs). +The new syntax allows different settings to be provided per NIC. + +``-redir`` (removed in 3.1) +''''''''''''''''''''''''''' + +The ``-redir [tcp|udp]:hostport:[guestaddr]:guestport`` option is replaced +by either ``-netdev +user,id=x,hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport`` +(for pluggable NICs, accompanied with ``-device ...,netdev=x``) or by the option +``-nic user,hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport`` +(for on-board NICs). The new syntax allows different settings to be provided +per NIC. + +``-smb`` (removed in 3.1) +''''''''''''''''''''''''' + +The ``-smb /some/dir`` argument is replaced by either +``-netdev user,id=x,smb=/some/dir`` (for pluggable NICs, accompanied with +``-device ...,netdev=x``), or ``-nic user,smb=/some/dir`` (for on-board NICs). +The new syntax allows different settings to be provided per NIC. + +``-tftp`` (removed in 3.1) +'''''''''''''''''''''''''' + +The ``-tftp /some/dir`` argument is replaced by either +``-netdev user,id=x,tftp=/some/dir`` (for pluggable NICs, accompanied with +``-device ...,netdev=x``), or ``-nic user,tftp=/some/dir`` (for embedded NICs). +The new syntax allows different settings to be provided per NIC. + +``-localtime`` (removed in 3.1) +''''''''''''''''''''''''''''''' + +Replaced by ``-rtc base=localtime``. + +``-nodefconfig`` (removed in 3.1) +''''''''''''''''''''''''''''''''' + +Use ``-no-user-config`` instead. + +``-rtc-td-hack`` (removed in 3.1) +''''''''''''''''''''''''''''''''' + +Use ``-rtc driftfix=slew`` instead. + +``-startdate`` (removed in 3.1) +''''''''''''''''''''''''''''''' + +Replaced by ``-rtc base=date``. + +``-vnc ...,tls=...``, ``-vnc ...,x509=...`` & ``-vnc ...,x509verify=...`` +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The "tls-creds" option should be used instead to point to a "tls-creds-x509" +object created using "-object". + ``-net ...,name=...`` (removed in 5.1) '''''''''''''''''''''''''''''''''''''' From 5d82c1016064a5c51b77182485743f865dbe308e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 11 Aug 2021 10:41:01 +0200 Subject: [PATCH 522/531] docs/about/removed-features: Document removed HMP commands from QEMU v2.12 These HMP commands had been removed/replaced in QEMU v2.12. Still, some people might want to update from older versions to the recent QEMU version, so we should give some recommendations for the replacements in our documentation. Message-Id: <20210811084103.74832-5-thuth@redhat.com> Signed-off-by: Thomas Huth --- docs/about/removed-features.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 40d2cc4ffa..8bf3ebecab 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -356,6 +356,17 @@ Specify the properties for the object as top-level arguments instead. Human Monitor Protocol (HMP) commands ------------------------------------- +``usb_add`` and ``usb_remove`` (removed in 2.12) +'''''''''''''''''''''''''''''''''''''''''''''''' + +Replaced by ``device_add`` and ``device_del`` (use ``device_add help`` for a +list of available devices). + +``host_net_add`` and ``host_net_remove`` (removed in 2.12) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Replaced by ``netdev_add`` and ``netdev_del``. + The ``hub_id`` parameter of ``hostfwd_add`` / ``hostfwd_remove`` (removed in 5.0) ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' From 5643fcdd421afe898d812b9b41816b2ec3e3a516 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 11 Aug 2021 10:41:02 +0200 Subject: [PATCH 523/531] docs/about/removed-features: Document removed devices from older QEMU versions These devices had been removed/replaced in QEMU v2.12 and v4.0. Message-Id: <20210811084103.74832-6-thuth@redhat.com> Signed-off-by: Thomas Huth --- docs/about/removed-features.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 8bf3ebecab..0c860be62d 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -513,6 +513,17 @@ running the old binaries, you can use older versions of QEMU. System emulator devices ----------------------- +``spapr-pci-vfio-host-bridge`` (removed in 2.12) +''''''''''''''''''''''''''''''''''''''''''''''''' + +The ``spapr-pci-vfio-host-bridge`` device type has been replaced by the +``spapr-pci-host-bridge`` device type. + +``ivshmem`` (removed in 4.0) +'''''''''''''''''''''''''''' + +Replaced by either the ``ivshmem-plain`` or ``ivshmem-doorbell``. + ``ide-drive`` (removed in 6.0) '''''''''''''''''''''''''''''' From 36b508993c4dcc6b3ef4b5c00e293ee9560926ee Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 11 Aug 2021 10:41:03 +0200 Subject: [PATCH 524/531] docs/about/removed-features: Document removed machines from older QEMU versions These machines had been removed in the QEMU v2.6 up to 4.0 time frame. Message-Id: <20210811084103.74832-7-thuth@redhat.com> Signed-off-by: Thomas Huth --- docs/about/removed-features.rst | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 0c860be62d..cbfa1a8e31 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -473,6 +473,22 @@ Removed without replacement. System emulator machines ------------------------ +``s390-virtio`` (removed in 2.6) +'''''''''''''''''''''''''''''''' + +Use the ``s390-ccw-virtio`` machine instead. + +The m68k ``dummy`` machine (removed in 2.9) +''''''''''''''''''''''''''''''''''''''''''' + +Use the ``none`` machine with the ``loader`` device instead. + +``xlnx-ep108`` (removed in 3.0) +''''''''''''''''''''''''''''''' + +The EP108 was an early access development board that is no longer used. +Use the ``xlnx-zcu102`` machine instead. + ``spike_v1.9.1`` and ``spike_v1.10`` (removed in 5.1) ''''''''''''''''''''''''''''''''''''''''''''''''''''' @@ -491,8 +507,8 @@ mips ``fulong2e`` machine alias (removed in 6.0) This machine has been renamed ``fuloong2e``. -``pc-1.0``, ``pc-1.1``, ``pc-1.2`` and ``pc-1.3`` (removed in 6.0) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +``pc-0.10`` up to ``pc-1.3`` (removed in 4.0 up to 6.0) +''''''''''''''''''''''''''''''''''''''''''''''''''''''' These machine types were very old and likely could not be used for live migration from old QEMU versions anymore. Use a newer machine type instead. From a7686d5d8528469b596e98eff098a5d3f8328fb3 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 12 Aug 2021 06:53:09 -0500 Subject: [PATCH 525/531] Hexagon (disas/hexagon.c) fix memory leak for early exit cases Don't allocate the string until error conditions have been checked Fixes: a00cfed0e ("Hexagon (disas) disassembler") Eliminate Coverity CID 1460121 (Resource leak) Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daud? Signed-off-by: Taylor Simpson --- disas/hexagon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/disas/hexagon.c b/disas/hexagon.c index 3c24e2a94a..c1a4ffc5f6 100644 --- a/disas/hexagon.c +++ b/disas/hexagon.c @@ -33,7 +33,7 @@ int print_insn_hexagon(bfd_vma memaddr, struct disassemble_info *info) { uint32_t words[PACKET_WORDS_MAX]; bool found_end = false; - GString *buf = g_string_sized_new(PACKET_BUFFER_LEN); + GString *buf; int i, len; for (i = 0; i < PACKET_WORDS_MAX && !found_end; i++) { @@ -57,6 +57,7 @@ int print_insn_hexagon(bfd_vma memaddr, struct disassemble_info *info) return PACKET_WORDS_MAX * sizeof(uint32_t); } + buf = g_string_sized_new(PACKET_BUFFER_LEN); len = disassemble_hexagon(words, i, memaddr, buf); (*info->fprintf_func)(info->stream, "%s", buf->str); g_string_free(buf, true); From 24d84c7e4806da0c362edd2ee76678f15becd17d Mon Sep 17 00:00:00 2001 From: Lara Lazier Date: Thu, 12 Aug 2021 13:10:56 +0200 Subject: [PATCH 526/531] target/i386: Fixed size of constant for Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ~0UL has 64 bits on Linux and 32 bits on Windows. Fixes: https://gitlab.com/qemu-project/qemu/-/issues/512 Reported-by: Volker Rümelin Signed-off-by: Lara Lazier Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210812111056.26926-1-laramglazier@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/tcg/sysemu/misc_helper.c | 2 +- target/i386/tcg/sysemu/svm_helper.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c index d347af2a99..e7a2ebde81 100644 --- a/target/i386/tcg/sysemu/misc_helper.c +++ b/target/i386/tcg/sysemu/misc_helper.c @@ -97,7 +97,7 @@ void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) break; case 3: if ((env->efer & MSR_EFER_LMA) && - (t0 & ((~0UL) << env_archcpu(env)->phys_bits))) { + (t0 & ((~0ULL) << env_archcpu(env)->phys_bits))) { cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); } if (!(env->efer & MSR_EFER_LMA)) { diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index e151104b4e..0d549b3d6c 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -264,7 +264,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) } new_cr3 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr3)); if ((env->efer & MSR_EFER_LMA) && - (new_cr3 & ((~0UL) << cpu->phys_bits))) { + (new_cr3 & ((~0ULL) << cpu->phys_bits))) { cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); } new_cr4 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr4)); From 0b46318170bf2782564e1c444e01a47cda308c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 13 Aug 2021 13:26:06 +0200 Subject: [PATCH 527/531] hw/core: Add missing return on error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If dies is not supported by this machine's CPU topology, don't keep processing options and return directly. Fixes: 0aebebb561c ("machine: reject -smp dies!=1 for non-PC machines") Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210813112608.1452541-2-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index 943974d411..abaeda589b 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -752,6 +752,7 @@ static void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp) if (config->has_dies && config->dies != 0 && config->dies != 1) { error_setg(errp, "dies not supported by this machine's CPU topology"); + return; } /* compute missing values, prefer sockets over cores over threads */ From ea0aa1752ca88f7856cbf40eef0db62f90f28dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 12 Aug 2021 18:53:53 +0100 Subject: [PATCH 528/531] hw/core: fix error checking in smp_parse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit machine_set_smp() mistakenly checks 'errp' not '*errp', and so thinks there is an error every single time it runs. This causes it to jump to the end of the method, skipping the max CPUs checks. The caller meanwhile sees no error and so carries on execution. The result of all this is: $ qemu-system-x86_64 -smp -1 qemu-system-x86_64: GLib: ../glib/gmem.c:142: failed to allocate 481036337048 bytes instead of $ qemu-system-x86_64 -smp -1 qemu-system-x86_64: Invalid SMP CPUs -1. The max CPUs supported by machine 'pc-i440fx-6.1' is 255 This is a regression from commit fe68090e8fbd6e831aaf3fc3bb0459c5cccf14cf Author: Paolo Bonzini Date: Thu May 13 09:03:48 2021 -0400 machine: add smp compound property Closes: https://gitlab.com/qemu-project/qemu/-/issues/524 Signed-off-by: Daniel P. Berrangé Message-Id: <20210812175353.4128471-1-berrange@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index abaeda589b..54e040587d 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -833,7 +833,7 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name, } mc->smp_parse(ms, config, errp); - if (errp) { + if (*errp) { goto out_free; } From 0572edc55b7bb862efadc2f061e4d9abb87171cc Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 17 Aug 2021 14:53:56 +0200 Subject: [PATCH 529/531] qapi/machine.json: Remove zero value reference from SMPConfiguration documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 1e63fe685804 ("machine: pass QAPI struct to mc->smp_parse") introduced documentation stating that a zero input value for an SMP parameter indicates that its value should be automatically configured. This is indeed how things work today, but we'd like to change that. Avoid documenting behaviors we want to leave undefined for the time being, giving us freedom to change it later. Fixes: 1e63fe685804 ("machine: pass QAPI struct to mc->smp_parse") Signed-off-by: Andrew Jones Acked-by: Paolo Bonzini Reviewed-by: Cornelia Huck Reviewed-by: Yanan Wang Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- qapi/machine.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qapi/machine.json b/qapi/machine.json index c3210ee1fb..157712f006 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1288,7 +1288,7 @@ ## # @SMPConfiguration: # -# Schema for CPU topology configuration. "0" or a missing value lets +# Schema for CPU topology configuration. A missing value lets # QEMU figure out a suitable value based on the ones that are provided. # # @cpus: number of virtual CPUs in the virtual machine From 1c4c68593610e81fc3ba8d3919ec3fc9f26e063d Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 5 Aug 2021 11:23:50 +0200 Subject: [PATCH 530/531] softmmu/physmem: fix wrong assertion in qemu_ram_alloc_internal() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When adding RAM_NORESERVE, we forgot to remove the old assertion when adding the updated one, most probably when reworking the patches or rebasing. We can easily crash QEMU by adding -object memory-backend-ram,id=mem0,size=500G,reserve=off to the QEMU cmdline: qemu-system-x86_64: ../softmmu/physmem.c:2146: qemu_ram_alloc_internal: Assertion `(ram_flags & ~(RAM_SHARED | RAM_RESIZEABLE | RAM_PREALLOC)) == 0' failed. Fix it by removing the old assertion. Fixes: 8dbe22c6868b ("memory: Introduce RAM_NORESERVE and wire it up in qemu_ram_mmap()") Reviewed-by: Peter Xu Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Reviewed-by: Pankaj Gupta Signed-off-by: David Hildenbrand Message-id: 20210805092350.31195-1-david@redhat.com Cc: Paolo Bonzini Cc: Peter Xu Cc: Philippe Mathieu-Daudé Signed-off-by: David Hildenbrand Signed-off-by: Peter Maydell --- softmmu/physmem.c | 1 - 1 file changed, 1 deletion(-) diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 3c1912a1a0..2e18947598 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -2143,7 +2143,6 @@ RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size, RAMBlock *new_block; Error *local_err = NULL; - assert((ram_flags & ~(RAM_SHARED | RAM_RESIZEABLE | RAM_PREALLOC)) == 0); assert((ram_flags & ~(RAM_SHARED | RAM_RESIZEABLE | RAM_PREALLOC | RAM_NORESERVE)) == 0); assert(!host ^ (ram_flags & RAM_PREALLOC)); From ecf2706e271fa705621f0d5ad9517fe15a22bf22 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 17 Aug 2021 19:14:08 +0100 Subject: [PATCH 531/531] Update version for v6.1.0-rc4 release Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 71858d966e..241f2cb536 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.93 +6.0.94