summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS8
-rw-r--r--block.c4
-rw-r--r--block/block-backend.c11
-rw-r--r--block/export/fuse.c45
-rw-r--r--block/export/vhost-user-blk-server.c5
-rw-r--r--block/io.c6
-rw-r--r--block/qcow2.c58
-rw-r--r--block/rbd.c52
-rw-r--r--bsd-user/arm/signal.c59
-rw-r--r--bsd-user/arm/target_arch_cpu.h101
-rw-r--r--bsd-user/freebsd/target_os_siginfo.h15
-rw-r--r--bsd-user/freebsd/target_os_signal.h3
-rw-r--r--bsd-user/freebsd/target_os_ucontext.h6
-rw-r--r--bsd-user/host/arm/host-signal.h35
-rw-r--r--bsd-user/host/i386/host-signal.h37
-rw-r--r--bsd-user/host/x86_64/host-signal.h37
-rw-r--r--bsd-user/i386/signal.c13
-rw-r--r--bsd-user/i386/target_arch_cpu.h5
-rw-r--r--bsd-user/main.c14
-rw-r--r--bsd-user/qemu.h66
-rw-r--r--bsd-user/signal-common.h75
-rw-r--r--bsd-user/signal.c1013
-rw-r--r--bsd-user/strace.c97
-rw-r--r--bsd-user/syscall_defs.h1
-rw-r--r--bsd-user/trace-events11
-rw-r--r--bsd-user/trace.h1
-rw-r--r--bsd-user/x86_64/signal.c13
-rw-r--r--bsd-user/x86_64/target_arch_cpu.h5
-rwxr-xr-xconfigure6
-rw-r--r--docs/about/deprecated.rst13
-rw-r--r--docs/conf.py2
-rw-r--r--docs/devel/qapi-code-gen.rst25
-rw-r--r--docs/devel/testing.rst2
-rw-r--r--docs/devel/tracing.rst2
-rw-r--r--docs/tools/qemu-img.rst2
-rw-r--r--docs/tools/qemu-storage-daemon.rst9
-rw-r--r--hw/acpi/Kconfig6
-rw-r--r--hw/acpi/aml-build.c4
-rw-r--r--hw/acpi/cpu.c2
-rw-r--r--hw/acpi/erst.c1051
-rw-r--r--hw/acpi/ich9.c3
-rw-r--r--hw/acpi/memory_hotplug.c2
-rw-r--r--hw/acpi/meson.build1
-rw-r--r--hw/acpi/piix4.c2
-rw-r--r--hw/acpi/tco.c1
-rw-r--r--hw/acpi/trace-events15
-rw-r--r--hw/arm/armv7m.c4
-rw-r--r--hw/arm/aspeed_ast2600.c2
-rw-r--r--hw/arm/omap1.c2
-rw-r--r--hw/arm/pxa2xx.c2
-rw-r--r--hw/arm/strongarm.c2
-rw-r--r--hw/arm/xlnx-versal-virt.c25
-rw-r--r--hw/arm/xlnx-versal.c190
-rw-r--r--hw/audio/pcspk.c1
-rw-r--r--hw/block/m25p80.c2
-rw-r--r--hw/char/exynos4210_uart.c2
-rw-r--r--hw/display/artist.c463
-rw-r--r--hw/display/macfb.c1
-rw-r--r--hw/display/trace-events8
-rw-r--r--hw/dma/xlnx-zdma.c1
-rw-r--r--hw/dma/xlnx_csu_dma.c18
-rw-r--r--hw/gpio/imx_gpio.c1
-rw-r--r--hw/hppa/hppa_hardware.h5
-rw-r--r--hw/hppa/machine.c35
-rw-r--r--hw/i386/acpi-build.c15
-rw-r--r--hw/i386/acpi-microvm.c15
-rw-r--r--hw/i386/pc_piix.c5
-rw-r--r--hw/i386/sgx.c11
-rw-r--r--hw/i386/xen/xen-hvm.c6
-rw-r--r--hw/i386/xen/xen-mapcache.c8
-rw-r--r--hw/intc/arm_gicv3.c1
-rw-r--r--hw/intc/arm_gicv3_common.c9
-rw-r--r--hw/intc/arm_gicv3_its.c258
-rw-r--r--hw/intc/arm_gicv3_redist.c115
-rw-r--r--hw/intc/gicv3_internal.h43
-rw-r--r--hw/intc/i8259_common.c6
-rw-r--r--hw/intc/ioapic_common.c2
-rw-r--r--hw/intc/pnv_xive.c22
-rw-r--r--hw/intc/trace-events8
-rw-r--r--hw/misc/bcm2835_mbox.c1
-rw-r--r--hw/misc/mac_via.c2
-rw-r--r--hw/misc/macio/cuda.c2
-rw-r--r--hw/misc/macio/pmu.c2
-rw-r--r--hw/misc/meson.build5
-rw-r--r--hw/misc/xlnx-versal-pmc-iou-slcr.c1446
-rw-r--r--hw/net/can/can_kvaser_pci.c1
-rw-r--r--hw/net/can/can_mioe3680_pci.c1
-rw-r--r--hw/net/can/can_pcm3680_pci.c1
-rw-r--r--hw/net/can/can_sja1000.c2
-rw-r--r--hw/net/can/ctucan_core.c2
-rw-r--r--hw/net/can/ctucan_pci.c1
-rw-r--r--hw/pci-host/pnv_phb3.c17
-rw-r--r--hw/pci-host/pnv_phb4.c17
-rw-r--r--hw/ppc/ppc.c1
-rw-r--r--hw/ppc/spapr.c2
-rw-r--r--hw/ppc/spapr_cpu_core.c5
-rw-r--r--hw/ppc/spapr_rtc.c2
-rw-r--r--hw/ppc/spapr_vof.c2
-rw-r--r--hw/ppc/vof.c1
-rw-r--r--hw/rtc/allwinner-rtc.c2
-rw-r--r--hw/rtc/aspeed_rtc.c2
-rw-r--r--hw/rtc/ds1338.c2
-rw-r--r--hw/rtc/exynos4210_rtc.c2
-rw-r--r--hw/rtc/goldfish_rtc.c2
-rw-r--r--hw/rtc/m41t80.c2
-rw-r--r--hw/rtc/m48t59.c2
-rw-r--r--hw/rtc/mc146818rtc.c2
-rw-r--r--hw/rtc/pl031.c2
-rw-r--r--hw/rtc/twl92230.c2
-rw-r--r--hw/rtc/xlnx-zynqmp-rtc.c2
-rw-r--r--hw/s390x/tod-tcg.c2
-rw-r--r--hw/scsi/megasas.c3
-rw-r--r--hw/scsi/mptsas.c1
-rw-r--r--hw/ssi/meson.build1
-rw-r--r--hw/ssi/xlnx-versal-ospi.c1853
-rw-r--r--hw/virtio/virtio-mmio.c1
-rw-r--r--hw/virtio/virtio-pci.c1
-rw-r--r--hw/virtio/virtio.c1
-rw-r--r--include/block/block.h1
-rw-r--r--include/exec/cpu-all.h9
-rw-r--r--include/exec/cpu-common.h9
-rw-r--r--include/hw/acpi/erst.h24
-rw-r--r--include/hw/arm/xlnx-versal.h30
-rw-r--r--include/hw/dma/xlnx_csu_dma.h24
-rw-r--r--include/hw/i386/ioapic_internal.h1
-rw-r--r--include/hw/intc/arm_gicv3_its_common.h1
-rw-r--r--include/hw/isa/i8259_internal.h3
-rw-r--r--include/hw/misc/xlnx-versal-pmc-iou-slcr.h78
-rw-r--r--include/hw/pci/pci.h1
-rw-r--r--include/hw/ppc/vof.h5
-rw-r--r--include/hw/ssi/xlnx-versal-ospi.h111
-rw-r--r--include/qemu-common.h5
-rw-r--r--include/qemu/vhost-user-server.h5
-rw-r--r--include/sysemu/rtc.h58
-rw-r--r--meson.build25
-rw-r--r--migration/migration.c26
-rw-r--r--migration/multifd-zlib.c61
-rw-r--r--migration/multifd-zstd.c63
-rw-r--r--migration/multifd.c148
-rw-r--r--migration/multifd.h33
-rw-r--r--migration/postcopy-ram.c96
-rw-r--r--migration/ram.c293
-rw-r--r--migration/ram.h4
-rw-r--r--migration/savevm.c5
-rw-r--r--migration/trace-events29
-rw-r--r--monitor/hmp-cmds.c12
-rw-r--r--nbd/server.c1
-rw-r--r--net/dump.c2
-rw-r--r--pc-bios/hppa-firmware.imgbin757144 -> 701964 bytes
-rw-r--r--python/Pipfile.lock66
-rw-r--r--python/qemu/aqmp/legacy.py3
-rw-r--r--python/qemu/aqmp/protocol.py41
-rw-r--r--python/qemu/aqmp/qmp_client.py4
-rw-r--r--python/qemu/machine/machine.py45
-rw-r--r--python/setup.cfg2
-rw-r--r--qapi/audio.json1
-rw-r--r--qapi/block-export.json3
-rw-r--r--qapi/compat.json1
-rw-r--r--qapi/machine.json4
-rw-r--r--qapi/meson.build7
-rw-r--r--qapi/migration.json13
-rw-r--r--qapi/misc-target.json22
-rw-r--r--qapi/replay.json1
-rw-r--r--qapi/trace.json1
-rw-r--r--qemu-img-cmds.hx4
-rw-r--r--qga/meson.build12
m---------roms/seabios-hppa0
-rw-r--r--scripts/mtest2make.py20
-rw-r--r--scripts/qapi/commands.py100
-rw-r--r--scripts/qapi/gen.py31
-rw-r--r--scripts/qapi/main.py14
-rwxr-xr-xscripts/update-linux-headers.sh16
-rw-r--r--softmmu/rtc.c2
-rw-r--r--storage-daemon/qemu-storage-daemon.c4
-rw-r--r--subprojects/libvhost-user/libvhost-user.c86
-rw-r--r--subprojects/libvhost-user/libvhost-user.h2
-rw-r--r--target/arm/helper.c13
-rw-r--r--target/arm/internals.h2
-rw-r--r--target/arm/m_helper.c2
-rw-r--r--target/hppa/cpu.c2
-rw-r--r--target/hppa/cpu.h5
-rw-r--r--target/hppa/helper.h1
-rw-r--r--target/hppa/insns.decode1
-rw-r--r--target/hppa/int_helper.c19
-rw-r--r--target/hppa/op_helper.c7
-rw-r--r--target/hppa/translate.c10
-rw-r--r--target/openrisc/machine.c1
-rw-r--r--target/ppc/cpu-models.c2
-rw-r--r--target/ppc/cpu-models.h1
-rw-r--r--target/ppc/cpu.h9
-rw-r--r--target/ppc/cpu_init.c150
-rw-r--r--target/ppc/excp_helper.c674
-rw-r--r--target/ppc/helper.h2
-rw-r--r--target/ppc/helper_regs.c12
-rw-r--r--target/ppc/int_helper.c21
-rw-r--r--target/ppc/machine.c2
-rw-r--r--target/ppc/mfrom_table.c.inc78
-rw-r--r--target/ppc/mfrom_table_gen.c34
-rw-r--r--target/ppc/mmu_common.c18
-rw-r--r--target/ppc/mmu_helper.c12
-rw-r--r--target/ppc/translate.c32
-rw-r--r--target/sparc/machine.c4
-rw-r--r--tcg/i386/tcg-target.c.inc2
-rw-r--r--tests/Makefile.include16
-rwxr-xr-xtests/check-block.sh52
-rw-r--r--tests/data/acpi/microvm/ERST.pciebin0 -> 912 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.acpierstbin0 -> 5969 bytes
-rw-r--r--tests/data/acpi/pc/ERST.acpierstbin0 -> 912 bytes
-rw-r--r--tests/data/acpi/pc/SSDT.dimmpxmbin734 -> 734 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.acpierstbin0 -> 8306 bytes
-rw-r--r--tests/data/acpi/q35/ERST.acpierstbin0 -> 912 bytes
-rw-r--r--tests/data/acpi/q35/FACP.slicbin244 -> 244 bytes
-rw-r--r--tests/data/acpi/q35/SSDT.dimmpxmbin734 -> 734 bytes
-rw-r--r--tests/data/acpi/virt/SSDT.memhpbin736 -> 736 bytes
-rw-r--r--tests/docker/dockerfiles/fedora-win32-cross.docker1
-rw-r--r--tests/docker/dockerfiles/fedora-win64-cross.docker1
-rw-r--r--tests/meson.build11
-rwxr-xr-xtests/qemu-iotests/03111
-rwxr-xr-xtests/qemu-iotests/0366
-rwxr-xr-xtests/qemu-iotests/03922
-rwxr-xr-xtests/qemu-iotests/0448
-rw-r--r--tests/qemu-iotests/044.out1
-rwxr-xr-xtests/qemu-iotests/0519
-rwxr-xr-xtests/qemu-iotests/06022
-rw-r--r--tests/qemu-iotests/060.out2
-rwxr-xr-xtests/qemu-iotests/06142
-rw-r--r--tests/qemu-iotests/061.out12
-rwxr-xr-xtests/qemu-iotests/06519
-rw-r--r--tests/qemu-iotests/082.out14
-rwxr-xr-xtests/qemu-iotests/1123
-rwxr-xr-xtests/qemu-iotests/1372
-rw-r--r--tests/qemu-iotests/149.out21
-rwxr-xr-xtests/qemu-iotests/1633
-rwxr-xr-xtests/qemu-iotests/1653
-rwxr-xr-xtests/qemu-iotests/1963
-rw-r--r--tests/qemu-iotests/198.out4
-rw-r--r--tests/qemu-iotests/206.out10
-rwxr-xr-xtests/qemu-iotests/2097
-rw-r--r--tests/qemu-iotests/209.out2
-rwxr-xr-xtests/qemu-iotests/2108
-rwxr-xr-xtests/qemu-iotests/2142
-rw-r--r--tests/qemu-iotests/237.out3
-rwxr-xr-xtests/qemu-iotests/2423
-rw-r--r--tests/qemu-iotests/242.out10
-rwxr-xr-xtests/qemu-iotests/2463
-rwxr-xr-xtests/qemu-iotests/2543
-rw-r--r--tests/qemu-iotests/255.out4
-rwxr-xr-xtests/qemu-iotests/2603
-rwxr-xr-xtests/qemu-iotests/2743
-rw-r--r--tests/qemu-iotests/274.out39
-rw-r--r--tests/qemu-iotests/280.out1
-rwxr-xr-xtests/qemu-iotests/2813
-rwxr-xr-xtests/qemu-iotests/2878
-rwxr-xr-xtests/qemu-iotests/2902
-rw-r--r--tests/qemu-iotests/296.out10
-rwxr-xr-xtests/qemu-iotests/3024
-rw-r--r--tests/qemu-iotests/302.out7
-rwxr-xr-xtests/qemu-iotests/30326
-rw-r--r--tests/qemu-iotests/303.out30
-rwxr-xr-xtests/qemu-iotests/check6
-rw-r--r--tests/qemu-iotests/common.filter8
-rw-r--r--tests/qemu-iotests/common.rc22
-rw-r--r--tests/qemu-iotests/iotests.py99
-rw-r--r--tests/qemu-iotests/meson.build30
-rw-r--r--tests/qemu-iotests/testenv.py30
-rw-r--r--tests/qemu-iotests/testrunner.py49
-rwxr-xr-xtests/qemu-iotests/tests/block-status-cache139
-rw-r--r--tests/qemu-iotests/tests/block-status-cache.out5
-rwxr-xr-xtests/qemu-iotests/tests/migrate-bitmaps-postcopy-test3
-rwxr-xr-xtests/qemu-iotests/tests/migrate-bitmaps-test3
-rwxr-xr-xtests/qemu-iotests/tests/migration-permissions101
-rw-r--r--tests/qemu-iotests/tests/migration-permissions.out5
-rwxr-xr-xtests/qemu-iotests/tests/mirror-ready-cancel-error7
-rwxr-xr-xtests/qemu-iotests/tests/mirror-top-perms3
-rwxr-xr-xtests/qemu-iotests/tests/remove-bitmap-from-backing3
-rw-r--r--tests/qtest/bios-tables-test.c65
-rw-r--r--tests/qtest/cdrom-test.c2
-rw-r--r--tests/qtest/erst-test.c164
-rw-r--r--tests/qtest/meson.build4
-rw-r--r--trace/meson.build11
-rw-r--r--util/bufferiszero.c2
-rw-r--r--util/oslib-posix.c1
-rw-r--r--util/vhost-user-server.c22
283 files changed, 9888 insertions, 1789 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index e4b3a4bcdf..9814580975 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -818,7 +818,6 @@ F: docs/system/arm/palm.rst
Raspberry Pi
M: Peter Maydell <peter.maydell@linaro.org>
-R: Andrew Baumann <Andrew.Baumann@microsoft.com>
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
L: qemu-arm@nongnu.org
S: Odd Fixes
@@ -958,6 +957,12 @@ F: hw/display/dpcd.c
F: include/hw/display/dpcd.h
F: docs/system/arm/xlnx-versal-virt.rst
+Xilinx Versal OSPI
+M: Francisco Iglesias <francisco.iglesias@xilinx.com>
+S: Maintained
+F: hw/ssi/xlnx-versal-ospi.c
+F: include/hw/ssi/xlnx-versal-ospi.h
+
ARM ACPI Subsystem
M: Shannon Zhao <shannon.zhaosl@gmail.com>
L: qemu-arm@nongnu.org
@@ -3181,6 +3186,7 @@ R: Kyle Evans <kevans@freebsd.org>
S: Maintained
F: bsd-user/
F: configs/targets/*-bsd-user.mak
+F: tests/vm/*bsd
T: git https://github.com/qemu-bsd-user/qemu-bsd-user bsd-user-rebase-3.1
Linux user
diff --git a/block.c b/block.c
index 7b3ce415d8..b54d59d1fa 100644
--- a/block.c
+++ b/block.c
@@ -3341,6 +3341,8 @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
int ret;
Transaction *tran = tran_new();
+ bdrv_drained_begin(bs);
+
ret = bdrv_set_backing_noperm(bs, backing_hd, tran, errp);
if (ret < 0) {
goto out;
@@ -3350,6 +3352,8 @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
out:
tran_finalize(tran, ret);
+ bdrv_drained_end(bs);
+
return ret;
}
diff --git a/block/block-backend.c b/block/block-backend.c
index 23e727199b..4ff6b4d785 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -190,6 +190,7 @@ static void blk_root_activate(BdrvChild *child, Error **errp)
{
BlockBackend *blk = child->opaque;
Error *local_err = NULL;
+ uint64_t saved_shared_perm;
if (!blk->disable_perm) {
return;
@@ -197,12 +198,22 @@ static void blk_root_activate(BdrvChild *child, Error **errp)
blk->disable_perm = false;
+ /*
+ * blk->shared_perm contains the permissions we want to share once
+ * migration is really completely done. For now, we need to share
+ * all; but we also need to retain blk->shared_perm, which is
+ * overwritten by a successful blk_set_perm() call. Save it and
+ * restore it below.
+ */
+ saved_shared_perm = blk->shared_perm;
+
blk_set_perm(blk, blk->perm, BLK_PERM_ALL, &local_err);
if (local_err) {
error_propagate(errp, local_err);
blk->disable_perm = true;
return;
}
+ blk->shared_perm = saved_shared_perm;
if (runstate_check(RUN_STATE_INMIGRATE)) {
/* Activation can happen when migration process is still active, for
diff --git a/block/export/fuse.c b/block/export/fuse.c
index 6710d8aed8..fdda8e3c81 100644
--- a/block/export/fuse.c
+++ b/block/export/fuse.c
@@ -625,11 +625,33 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode,
return;
}
+#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
if (mode & FALLOC_FL_KEEP_SIZE) {
length = MIN(length, blk_len - offset);
}
+#endif /* CONFIG_FALLOCATE_PUNCH_HOLE */
- if (mode & FALLOC_FL_PUNCH_HOLE) {
+ if (!mode) {
+ /* We can only fallocate at the EOF with a truncate */
+ if (offset < blk_len) {
+ fuse_reply_err(req, EOPNOTSUPP);
+ return;
+ }
+
+ if (offset > blk_len) {
+ /* No preallocation needed here */
+ ret = fuse_do_truncate(exp, offset, true, PREALLOC_MODE_OFF);
+ if (ret < 0) {
+ fuse_reply_err(req, -ret);
+ return;
+ }
+ }
+
+ ret = fuse_do_truncate(exp, offset + length, true,
+ PREALLOC_MODE_FALLOC);
+ }
+#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
+ else if (mode & FALLOC_FL_PUNCH_HOLE) {
if (!(mode & FALLOC_FL_KEEP_SIZE)) {
fuse_reply_err(req, EINVAL);
return;
@@ -643,6 +665,7 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode,
length -= size;
} while (ret == 0 && length > 0);
}
+#endif /* CONFIG_FALLOCATE_PUNCH_HOLE */
#ifdef CONFIG_FALLOCATE_ZERO_RANGE
else if (mode & FALLOC_FL_ZERO_RANGE) {
if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + length > blk_len) {
@@ -665,25 +688,7 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode,
} while (ret == 0 && length > 0);
}
#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);
- return;
- }
-
- if (offset > blk_len) {
- /* No preallocation needed here */
- ret = fuse_do_truncate(exp, offset, true, PREALLOC_MODE_OFF);
- if (ret < 0) {
- fuse_reply_err(req, -ret);
- return;
- }
- }
-
- ret = fuse_do_truncate(exp, offset + length, true,
- PREALLOC_MODE_FALLOC);
- } else {
+ else {
ret = -EOPNOTSUPP;
}
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
index 1862563336..a129204c44 100644
--- a/block/export/vhost-user-blk-server.c
+++ b/block/export/vhost-user-blk-server.c
@@ -172,6 +172,7 @@ vu_blk_discard_write_zeroes(VuBlkExport *vexp, struct iovec *iov,
return VIRTIO_BLK_S_IOERR;
}
+/* Called with server refcount increased, must decrease before returning */
static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
{
VuBlkReq *req = opaque;
@@ -286,10 +287,12 @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
}
vu_blk_req_complete(req);
+ vhost_user_server_unref(server);
return;
err:
free(req);
+ vhost_user_server_unref(server);
}
static void vu_blk_process_vq(VuDev *vu_dev, int idx)
@@ -310,6 +313,8 @@ static void vu_blk_process_vq(VuDev *vu_dev, int idx)
Coroutine *co =
qemu_coroutine_create(vu_blk_virtio_process_req, req);
+
+ vhost_user_server_ref(server);
qemu_coroutine_enter(co);
}
}
diff --git a/block/io.c b/block/io.c
index bb0a254def..4e4cb556c5 100644
--- a/block/io.c
+++ b/block/io.c
@@ -2497,8 +2497,12 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
* non-protocol nodes, and then it is never used. However, filling
* the cache requires an RCU update, so double check here to avoid
* such an update if possible.
+ *
+ * Check want_zero, because we only want to update the cache when we
+ * have accurate information about what is zero and what is data.
*/
- if (ret == (BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID) &&
+ if (want_zero &&
+ ret == (BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID) &&
QLIST_EMPTY(&bs->children))
{
/*
diff --git a/block/qcow2.c b/block/qcow2.c
index d509016756..c8115e1cba 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -5279,6 +5279,38 @@ static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0);
}
+static int qcow2_has_compressed_clusters(BlockDriverState *bs)
+{
+ int64_t offset = 0;
+ int64_t bytes = bdrv_getlength(bs);
+
+ if (bytes < 0) {
+ return bytes;
+ }
+
+ while (bytes != 0) {
+ int ret;
+ QCow2SubclusterType type;
+ unsigned int cur_bytes = MIN(INT_MAX, bytes);
+ uint64_t host_offset;
+
+ ret = qcow2_get_host_offset(bs, offset, &cur_bytes, &host_offset,
+ &type);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (type == QCOW2_SUBCLUSTER_COMPRESSED) {
+ return 1;
+ }
+
+ offset += cur_bytes;
+ bytes -= cur_bytes;
+ }
+
+ return 0;
+}
+
/*
* Downgrades an image's version. To achieve this, any incompatible features
* have to be removed.
@@ -5336,9 +5368,10 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
* the first place; if that happens nonetheless, returning -ENOTSUP is the
* best thing to do anyway */
- if (s->incompatible_features) {
+ if (s->incompatible_features & ~QCOW2_INCOMPAT_COMPRESSION) {
error_setg(errp, "Cannot downgrade an image with incompatible features "
- "%#" PRIx64 " set", s->incompatible_features);
+ "0x%" PRIx64 " set",
+ s->incompatible_features & ~QCOW2_INCOMPAT_COMPRESSION);
return -ENOTSUP;
}
@@ -5356,6 +5389,27 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
return ret;
}
+ if (s->incompatible_features & QCOW2_INCOMPAT_COMPRESSION) {
+ ret = qcow2_has_compressed_clusters(bs);
+ if (ret < 0) {
+ error_setg(errp, "Failed to check block status");
+ return -EINVAL;
+ }
+ if (ret) {
+ error_setg(errp, "Cannot downgrade an image with zstd compression "
+ "type and existing compressed clusters");
+ return -ENOTSUP;
+ }
+ /*
+ * No compressed clusters for now, so just chose default zlib
+ * compression.
+ */
+ s->incompatible_features &= ~QCOW2_INCOMPAT_COMPRESSION;
+ s->compression_type = QCOW2_COMPRESSION_TYPE_ZLIB;
+ }
+
+ assert(s->incompatible_features == 0);
+
s->qcow_version = target_version;
ret = qcow2_update_header(bs);
if (ret < 0) {
diff --git a/block/rbd.c b/block/rbd.c
index def96292e0..8f183eba2a 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -1279,11 +1279,11 @@ static int qemu_rbd_diff_iterate_cb(uint64_t offs, size_t len,
RBDDiffIterateReq *req = opaque;
assert(req->offs + req->bytes <= offs);
- /*
- * we do not diff against a snapshot so we should never receive a callback
- * for a hole.
- */
- assert(exists);
+
+ /* treat a hole like an unallocated area and bail out */
+ if (!exists) {
+ return 0;
+ }
if (!req->exists && offs > req->offs) {
/*
@@ -1320,6 +1320,7 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
int status, r;
RBDDiffIterateReq req = { .offs = offset };
uint64_t features, flags;
+ uint64_t head = 0;
assert(offset + bytes <= s->image_size);
@@ -1347,7 +1348,43 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
return status;
}
- r = rbd_diff_iterate2(s->image, NULL, offset, bytes, true, true,
+#if LIBRBD_VERSION_CODE < LIBRBD_VERSION(1, 17, 0)
+ /*
+ * librbd had a bug until early 2022 that affected all versions of ceph that
+ * supported fast-diff. This bug results in reporting of incorrect offsets
+ * if the offset parameter to rbd_diff_iterate2 is not object aligned.
+ * Work around this bug by rounding down the offset to object boundaries.
+ * This is OK because we call rbd_diff_iterate2 with whole_object = true.
+ * However, this workaround only works for non cloned images with default
+ * striping.
+ *
+ * See: https://tracker.ceph.com/issues/53784
+ */
+
+ /* check if RBD image has non-default striping enabled */
+ if (features & RBD_FEATURE_STRIPINGV2) {
+ return status;
+ }
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+ /*
+ * check if RBD image is a clone (= has a parent).
+ *
+ * rbd_get_parent_info is deprecated from Nautilus onwards, but the
+ * replacement rbd_get_parent is not present in Luminous and Mimic.
+ */
+ if (rbd_get_parent_info(s->image, NULL, 0, NULL, 0, NULL, 0) != -ENOENT) {
+ return status;
+ }
+#pragma GCC diagnostic pop
+
+ head = req.offs & (s->object_size - 1);
+ req.offs -= head;
+ bytes += head;
+#endif
+
+ r = rbd_diff_iterate2(s->image, NULL, req.offs, bytes, true, true,
qemu_rbd_diff_iterate_cb, &req);
if (r < 0 && r != QEMU_RBD_EXIT_DIFF_ITERATE2) {
return status;
@@ -1366,7 +1403,8 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
status = BDRV_BLOCK_ZERO | BDRV_BLOCK_OFFSET_VALID;
}
- *pnum = req.bytes;
+ assert(req.bytes > head);
+ *pnum = req.bytes - head;
return status;
}
diff --git a/bsd-user/arm/signal.c b/bsd-user/arm/signal.c
index 1478f008d1..2b1dd745d1 100644
--- a/bsd-user/arm/signal.c
+++ b/bsd-user/arm/signal.c
@@ -59,19 +59,31 @@ abi_long set_sigtramp_args(CPUARMState *env, int sig,
return 0;
}
+static abi_long get_vfpcontext(CPUARMState *env, abi_ulong frame_addr,
+ struct target_sigframe *frame)
+{
+ /* see sendsig and get_vfpcontext in sys/arm/arm/exec_machdep.c */
+ target_mcontext_vfp_t *vfp = &frame->sf_vfp;
+ target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
+
+ /* Assumes that mcp and vfp are locked */
+ for (int i = 0; i < 32; i++) {
+ vfp->mcv_reg[i] = tswap64(*aa32_vfp_dreg(env, i));
+ }
+ vfp->mcv_fpscr = tswap32(vfp_get_fpscr(env));
+ mcp->mc_vfp_size = tswap32(sizeof(*vfp));
+ mcp->mc_vfp_ptr = tswap32(frame_addr + ((uintptr_t)vfp - (uintptr_t)frame));
+ return 0;
+}
+
/*
- * Compare to arm/arm/machdep.c get_mcontext()
+ * Compare to arm/arm/exec_machdep.c get_mcontext()
* Assumes that the memory is locked if mcp points to user memory.
*/
abi_long get_mcontext(CPUARMState *env, target_mcontext_t *mcp, int flags)
{
- int err = 0;
uint32_t *gr = mcp->__gregs;
- if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_size != sizeof(target_mcontext_vfp_t)) {
- return -TARGET_EINVAL;
- }
-
gr[TARGET_REG_CPSR] = tswap32(cpsr_read(env));
if (flags & TARGET_MC_GET_CLEAR_RET) {
gr[TARGET_REG_R0] = 0;
@@ -97,17 +109,30 @@ abi_long get_mcontext(CPUARMState *env, target_mcontext_t *mcp, int flags)
gr[TARGET_REG_LR] = tswap32(env->regs[14]);
gr[TARGET_REG_PC] = tswap32(env->regs[15]);
- if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_ptr != 0) {
- /* see get_vfpcontext in sys/arm/arm/exec_machdep.c */
- target_mcontext_vfp_t *vfp;
- vfp = lock_user(VERIFY_WRITE, mcp->mc_vfp_ptr, sizeof(*vfp), 0);
- for (int i = 0; i < 32; i++) {
- vfp->mcv_reg[i] = tswap64(*aa32_vfp_dreg(env, i));
- }
- vfp->mcv_fpscr = tswap32(vfp_get_fpscr(env));
- unlock_user(vfp, mcp->mc_vfp_ptr, sizeof(*vfp));
- }
- return err;
+ /*
+ * FreeBSD's get_mcontext doesn't save VFP info, but sets the pointer and
+ * size to zero. Applications that need the VFP state use
+ * sysarch(ARM_GET_VFPSTATE) and are expected to adjust mcontext after that.
+ */
+ mcp->mc_vfp_size = 0;
+ mcp->mc_vfp_ptr = 0;
+ memset(&mcp->mc_spare, 0, sizeof(mcp->mc_spare));
+
+ return 0;
+}
+
+/*
+ * Compare to arm/arm/exec_machdep.c sendsig()
+ * Assumes that the memory is locked if frame points to user memory.
+ */
+abi_long setup_sigframe_arch(CPUARMState *env, abi_ulong frame_addr,
+ struct target_sigframe *frame, int flags)
+{
+ target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
+
+ get_mcontext(env, mcp, flags);
+ get_vfpcontext(env, frame_addr, frame);
+ return 0;
}
/* Compare to arm/arm/exec_machdep.c set_mcontext() */
diff --git a/bsd-user/arm/target_arch_cpu.h b/bsd-user/arm/target_arch_cpu.h
index c675419c30..b087db48fa 100644
--- a/bsd-user/arm/target_arch_cpu.h
+++ b/bsd-user/arm/target_arch_cpu.h
@@ -21,6 +21,7 @@
#define _TARGET_ARCH_CPU_H_
#include "target_arch.h"
+#include "signal-common.h"
#define TARGET_DEFAULT_CPU_MODEL "any"
@@ -38,8 +39,7 @@ static inline void target_cpu_init(CPUARMState *env,
static inline void target_cpu_loop(CPUARMState *env)
{
- int trapnr;
- target_siginfo_t info;
+ int trapnr, si_signo, si_code;
unsigned int n;
CPUState *cs = env_cpu(env);
@@ -50,33 +50,22 @@ static inline void target_cpu_loop(CPUARMState *env)
process_queued_cpu_work(cs);
switch (trapnr) {
case EXCP_UDEF:
- {
- /* See arm/arm/undefined.c undefinedinstruction(); */
- info.si_addr = env->regs[15];
-
- /* illegal instruction */
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPC;
- queue_signal(env, info.si_signo, &info);
-
- /* TODO: What about instruction emulation? */
- }
+ case EXCP_NOCP:
+ case EXCP_INVSTATE:
+ /*
+ * See arm/arm/undefined.c undefinedinstruction();
+ *
+ * A number of details aren't emulated (they likely don't matter):
+ * o Misaligned PC generates ILL_ILLADR (these can't come from qemu)
+ * o Thumb-2 instructions generate ILLADR
+ * o Both modes implement coprocessor instructions, which we don't
+ * do here. FreeBSD just implements them for the VFP coprocessor
+ * and special kernel breakpoints, trace points, dtrace, etc.
+ */
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->regs[15]);
break;
case EXCP_SWI:
- case EXCP_BKPT:
{
- /*
- * system call
- * See arm/arm/trap.c cpu_fetch_syscall_args()
- */
- if (trapnr == EXCP_BKPT) {
- if (env->thumb) {
- env->regs[15] += 2;
- } else {
- env->regs[15] += 4;
- }
- }
n = env->regs[7];
if (bsd_type == target_freebsd) {
int ret;
@@ -84,7 +73,7 @@ static inline void target_cpu_loop(CPUARMState *env)
int32_t syscall_nr = n;
int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
- /* See arm/arm/trap.c cpu_fetch_syscall_args() */
+ /* See arm/arm/syscall.c cpu_fetch_syscall_args() */
if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
syscall_nr = env->regs[0];
arg1 = env->regs[1];
@@ -160,32 +149,52 @@ static inline void target_cpu_loop(CPUARMState *env)
/* just indicate that signals should be handled asap */
break;
case EXCP_PREFETCH_ABORT:
- /* See arm/arm/trap.c prefetch_abort_handler() */
case EXCP_DATA_ABORT:
- /* See arm/arm/trap.c data_abort_handler() */
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = 0;
- info.si_addr = env->exception.vaddress;
- queue_signal(env, info.si_signo, &info);
- break;
- case EXCP_DEBUG:
- {
+ /*
+ * See arm/arm/trap-v6.c prefetch_abort_handler() and
+ * data_abort_handler()
+ *
+ * However, FreeBSD maps these to a generic value and then uses that
+ * to maybe fault in pages in vm/vm_fault.c:vm_fault_trap(). I
+ * believe that the indirection maps the same as Linux, but haven't
+ * chased down every single possible indirection.
+ */
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- info.si_addr = env->exception.vaddress;
- queue_signal(env, info.si_signo, &info);
+ /* For user-only we don't set TTBCR_EAE, so look at the FSR. */
+ switch (env->exception.fsr & 0x1f) {
+ case 0x1: /* Alignment */
+ si_signo = TARGET_SIGBUS;
+ si_code = TARGET_BUS_ADRALN;
+ break;
+ case 0x3: /* Access flag fault, level 1 */
+ case 0x6: /* Access flag fault, level 2 */
+ case 0x9: /* Domain fault, level 1 */
+ case 0xb: /* Domain fault, level 2 */
+ case 0xd: /* Permission fault, level 1 */
+ case 0xf: /* Permission fault, level 2 */
+ si_signo = TARGET_SIGSEGV;
+ si_code = TARGET_SEGV_ACCERR;
+ break;
+ case 0x5: /* Translation fault, level 1 */
+ case 0x7: /* Translation fault, level 2 */
+ si_signo = TARGET_SIGSEGV;
+ si_code = TARGET_SEGV_MAPERR;
+ break;
+ default:
+ g_assert_not_reached();
}
+ force_sig_fault(si_signo, si_code, env->exception.vaddress);
break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
+ case EXCP_DEBUG:
+ case EXCP_BKPT:
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->regs[15]);
break;
case EXCP_YIELD:
/* nothing to do here for user-mode, just resume guest code */
break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
default:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
@@ -204,7 +213,7 @@ static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp)
env->regs[0] = 0;
}
-static inline void target_cpu_reset(CPUArchState *cpu)
+static inline void target_cpu_reset(CPUArchState *env)
{
}
diff --git a/bsd-user/freebsd/target_os_siginfo.h b/bsd-user/freebsd/target_os_siginfo.h
index 84944faa4d..d50a3034a8 100644
--- a/bsd-user/freebsd/target_os_siginfo.h
+++ b/bsd-user/freebsd/target_os_siginfo.h
@@ -71,12 +71,25 @@ typedef struct target_siginfo {
int32_t _mqd;
} _mesgp;
- /* SIGPOLL */
+ /* SIGPOLL -- Not really genreated in FreeBSD ??? */
struct {
int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
} _poll;
struct {
+ int _mqd;
+ } _mesgq;
+
+ struct {
+ /*
+ * Syscall number for signals delivered as a result of system calls
+ * denied by Capsicum.
+ */
+ int _syscall;
+ } _capsicum;
+
+ /* Spare for future growth */
+ struct {
abi_long __spare1__;
int32_t __spare2_[7];
} __spare__;
diff --git a/bsd-user/freebsd/target_os_signal.h b/bsd-user/freebsd/target_os_signal.h
index 3ed454e086..43700d08f7 100644
--- a/bsd-user/freebsd/target_os_signal.h
+++ b/bsd-user/freebsd/target_os_signal.h
@@ -4,6 +4,9 @@
#include "target_os_siginfo.h"
#include "target_arch_signal.h"
+abi_long setup_sigframe_arch(CPUArchState *env, abi_ulong frame_addr,
+ struct target_sigframe *frame, int flags);
+
/* Compare to sys/signal.h */
#define TARGET_SIGHUP 1 /* hangup */
#define TARGET_SIGINT 2 /* interrupt */
diff --git a/bsd-user/freebsd/target_os_ucontext.h b/bsd-user/freebsd/target_os_ucontext.h
index 41b28b2c15..b196b1c629 100644
--- a/bsd-user/freebsd/target_os_ucontext.h
+++ b/bsd-user/freebsd/target_os_ucontext.h
@@ -36,9 +36,9 @@ abi_long set_sigtramp_args(CPUArchState *env, int sig,
struct target_sigframe *frame,
abi_ulong frame_addr,
struct target_sigaction *ka);
-abi_long get_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags);
-abi_long set_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int srflag);
-abi_long get_ucontext_sigreturn(CPUArchState *regs, abi_ulong target_sf,
+abi_long get_mcontext(CPUArchState *env, target_mcontext_t *mcp, int flags);
+abi_long set_mcontext(CPUArchState *env, target_mcontext_t *mcp, int srflag);
+abi_long get_ucontext_sigreturn(CPUArchState *env, abi_ulong target_sf,
abi_ulong *target_uc);
#endif /* TARGET_OS_UCONTEXT_H */
diff --git a/bsd-user/host/arm/host-signal.h b/bsd-user/host/arm/host-signal.h
new file mode 100644
index 0000000000..56679bd699
--- /dev/null
+++ b/bsd-user/host/arm/host-signal.h
@@ -0,0 +1,35 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (c) 2021 Warner Losh
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef ARM_HOST_SIGNAL_H
+#define ARM_HOST_SIGNAL_H
+
+#include <sys/ucontext.h>
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+ return uc->uc_mcontext.__gregs[_REG_PC];
+}
+
+static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+{
+ uc->uc_mcontext.__gregs[_REG_PC] = pc;
+}
+
+static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+{
+ /*
+ * In the FSR, bit 11 is WnR. FreeBSD returns this as part of the
+ * si_info.si_trapno.
+ */
+ uint32_t fsr = info->si_trapno;
+
+ return extract32(fsr, 11, 1);
+}
+
+#endif
diff --git a/bsd-user/host/i386/host-signal.h b/bsd-user/host/i386/host-signal.h
new file mode 100644
index 0000000000..169e61b154
--- /dev/null
+++ b/bsd-user/host/i386/host-signal.h
@@ -0,0 +1,37 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (c) 2021 Warner Losh
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef I386_HOST_SIGNAL_H
+#define I386_HOST_SIGNAL_H
+
+#include <sys/ucontext.h>
+#include <machine/trap.h>
+#include <vm/pmap.h>
+#include <machine/pmap.h>
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+ return uc->uc_mcontext.mc_eip;
+}
+
+static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+{
+ uc->uc_mcontext.mc_eip = pc;
+}
+
+static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+{
+ /*
+ * Look in sys/i386/i386/trap.c. NOTE: mc_err == tr_err due to type punning
+ * between a trapframe and mcontext on FreeBSD/i386.
+ */
+ return uc->uc_mcontext.mc_trapno == T_PAGEFLT &&
+ uc->uc_mcontext.mc_err & PGEX_W;
+}
+
+#endif
diff --git a/bsd-user/host/x86_64/host-signal.h b/bsd-user/host/x86_64/host-signal.h
new file mode 100644
index 0000000000..47ca19f881
--- /dev/null
+++ b/bsd-user/host/x86_64/host-signal.h
@@ -0,0 +1,37 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (c) 2021 Warner Losh
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef X86_64_HOST_SIGNAL_H
+#define X86_64_HOST_SIGNAL_H
+
+#include <sys/ucontext.h>
+#include <machine/trap.h>
+#include <vm/pmap.h>
+#include <machine/pmap.h>
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+ return uc->uc_mcontext.mc_rip;
+}
+
+static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+{
+ uc->uc_mcontext.mc_rip = pc;
+}
+
+static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+{
+ /*
+ * Look in sys/amd64/amd64/trap.c. NOTE: mc_err == tr_err due to type
+ * punning between a trapframe and mcontext on FreeBSD/amd64.
+ */
+ return uc->uc_mcontext.mc_trapno == T_PAGEFLT &&
+ uc->uc_mcontext.mc_err & PGEX_W;
+}
+
+#endif
diff --git a/bsd-user/i386/signal.c b/bsd-user/i386/signal.c
index 2939d32400..5dd975ce56 100644
--- a/bsd-user/i386/signal.c
+++ b/bsd-user/i386/signal.c
@@ -32,6 +32,19 @@ abi_long set_sigtramp_args(CPUX86State *env, int sig,
return 0;
}
+/*
+ * Compare to i386/i386/exec_machdep.c sendsig()
+ * Assumes that the memory is locked if frame points to user memory.
+ */
+abi_long setup_sigframe_arch(CPUX86State *env, abi_ulong frame_addr,
+ struct target_sigframe *frame, int flags)
+{
+ target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
+
+ get_mcontext(env, mcp, flags);
+ return 0;
+}
+
/* Compare to i386/i386/machdep.c get_mcontext() */
abi_long get_mcontext(CPUX86State *regs, target_mcontext_t *mcp, int flags)
{
diff --git a/bsd-user/i386/target_arch_cpu.h b/bsd-user/i386/target_arch_cpu.h
index b28602adbb..3cbf69d8af 100644
--- a/bsd-user/i386/target_arch_cpu.h
+++ b/bsd-user/i386/target_arch_cpu.h
@@ -20,6 +20,7 @@
#define _TARGET_ARCH_CPU_H_
#include "target_arch.h"
+#include "signal-common.h"
#define TARGET_DEFAULT_CPU_MODEL "qemu32"
@@ -199,9 +200,9 @@ static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
env->regs[R_EAX] = 0;
}
-static inline void target_cpu_reset(CPUArchState *cpu)
+static inline void target_cpu_reset(CPUArchState *env)
{
- cpu_reset(env_cpu(cpu));
+ cpu_reset(env_cpu(env));
}
#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/main.c b/bsd-user/main.c
index cb5ea40236..f1d58e905e 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -215,15 +215,13 @@ void qemu_cpu_kick(CPUState *cpu)
}
/* Assumes contents are already zeroed. */
-void init_task_state(TaskState *ts)
+static void init_task_state(TaskState *ts)
{
- int i;
-
- ts->first_free = ts->sigqueue_table;
- for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
- ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
- }
- ts->sigqueue_table[i].next = NULL;
+ ts->sigaltstack_used = (struct target_sigaltstack) {
+ .ss_sp = 0,
+ .ss_size = 0,
+ .ss_flags = TARGET_SS_DISABLE,
+ };
}
void gemu_log(const char *fmt, ...)
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 1b3b974afe..02921ac8b3 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -70,17 +70,9 @@ struct image_info {
uint32_t elf_flags;
};
-#define MAX_SIGQUEUE_SIZE 1024
-
-struct qemu_sigqueue {
- struct qemu_sigqueue *next;
- target_siginfo_t info;
-};
-
struct emulated_sigtable {
int pending; /* true if signal is pending */
- struct qemu_sigqueue *first;
- struct qemu_sigqueue info; /* Put first signal info here */
+ target_siginfo_t info;
};
/*
@@ -93,15 +85,39 @@ typedef struct TaskState {
struct bsd_binprm *bprm;
struct image_info *info;
+ struct emulated_sigtable sync_signal;
+ /*
+ * TODO: Since we block all signals while returning to the main CPU
+ * loop, this needn't be an array
+ */
struct emulated_sigtable sigtab[TARGET_NSIG];
- struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
- struct qemu_sigqueue *first_free; /* first free siginfo queue entry */
- int signal_pending; /* non zero if a signal may be pending */
-
- uint8_t stack[];
+ /*
+ * Nonzero if process_pending_signals() needs to do something (either
+ * handle a pending signal or unblock signals).
+ * This flag is written from a signal handler so should be accessed via
+ * the qatomic_read() and qatomic_set() functions. (It is not accessed
+ * from multiple threads.)
+ */
+ int signal_pending;
+ /* True if we're leaving a sigsuspend and sigsuspend_mask is valid. */
+ bool in_sigsuspend;
+ /*
+ * This thread's signal mask, as requested by the guest program.
+ * The actual signal mask of this thread may differ:
+ * + we don't let SIGSEGV and SIGBUS be blocked while running guest code
+ * + sometimes we block all signals to avoid races
+ */
+ sigset_t signal_mask;
+ /*
+ * The signal mask imposed by a guest sigsuspend syscall, if we are
+ * currently in the middle of such a syscall
+ */
+ sigset_t sigsuspend_mask;
+
+ /* This thread's sigaltstack, if it has one */
+ struct target_sigaltstack sigaltstack_used;
} __attribute__((aligned(16))) TaskState;
-void init_task_state(TaskState *ts);
void stop_all_tasks(void);
extern const char *qemu_uname_release;
@@ -201,16 +217,18 @@ print_openbsd_syscall(int num,
abi_long arg1, abi_long arg2, abi_long arg3,
abi_long arg4, abi_long arg5, abi_long arg6);
void print_openbsd_syscall_ret(int num, abi_long ret);
+/**
+ * print_taken_signal:
+ * @target_signum: target signal being taken
+ * @tinfo: target_siginfo_t which will be passed to the guest for the signal
+ *
+ * Print strace output indicating that this signal is being taken by the guest,
+ * in a format similar to:
+ * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
+ */
+void print_taken_signal(int target_signum, const target_siginfo_t *tinfo);
extern int do_strace;
-/* signal.c */
-void process_pending_signals(CPUArchState *cpu_env);
-void signal_init(void);
-long do_sigreturn(CPUArchState *env);
-long do_rt_sigreturn(CPUArchState *env);
-void queue_signal(CPUArchState *env, int sig, target_siginfo_t *info);
-abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
-
/* mmap.c */
int target_mprotect(abi_ulong start, abi_ulong len, int prot);
abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
@@ -451,4 +469,6 @@ static inline void *lock_user_string(abi_ulong guest_addr)
#include <pthread.h>
+#include "user/safe-syscall.h"
+
#endif /* QEMU_H */
diff --git a/bsd-user/signal-common.h b/bsd-user/signal-common.h
new file mode 100644
index 0000000000..6f90345bb2
--- /dev/null
+++ b/bsd-user/signal-common.h
@@ -0,0 +1,75 @@
+/*
+ * Emulation of BSD signals
+ *
+ * Copyright (c) 2013 Stacey Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef SIGNAL_COMMON_H
+#define SIGNAL_COMMON_H
+
+/**
+ * block_signals: block all signals while handling this guest syscall
+ *
+ * Block all signals, and arrange that the signal mask is returned to
+ * its correct value for the guest before we resume execution of guest code.
+ * If this function returns non-zero, then the caller should immediately
+ * return -TARGET_ERESTARTSYS to the main loop, which will take the pending
+ * signal and restart execution of the syscall.
+ * If block_signals() returns zero, then the caller can continue with
+ * emulation of the system call knowing that no signals can be taken
+ * (and therefore that no race conditions will result).
+ * This should only be called once, because if it is called a second time
+ * it will always return non-zero. (Think of it like a mutex that can't
+ * be recursively locked.)
+ * Signals will be unblocked again by process_pending_signals().
+ *
+ * Return value: non-zero if there was a pending signal, zero if not.
+ */
+int block_signals(void); /* Returns non zero if signal pending */
+
+long do_rt_sigreturn(CPUArchState *env);
+int do_sigaction(int sig, const struct target_sigaction *act,
+ struct target_sigaction *oact);
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
+long do_sigreturn(CPUArchState *env, abi_ulong addr);
+void force_sig_fault(int sig, int code, abi_ulong addr);
+int host_to_target_signal(int sig);
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
+void process_pending_signals(CPUArchState *env);
+void queue_signal(CPUArchState *env, int sig, int si_type,
+ target_siginfo_t *info);
+void signal_init(void);
+int target_to_host_signal(int sig);
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
+
+/*
+ * Within QEMU the top 8 bits of si_code indicate which of the parts of the
+ * union in target_siginfo is valid. This only applies between
+ * host_to_target_siginfo_noswap() and tswap_siginfo(); it does not appear
+ * either within host siginfo_t or in target_siginfo structures which we get
+ * from the guest userspace program. Linux kenrels use this internally, but BSD
+ * kernels don't do this, but its a useful abstraction.
+ *
+ * The linux-user version of this uses the top 16 bits, but FreeBSD's SI_USER
+ * and other signal indepenent SI_ codes have bit 16 set, so we only use the top
+ * byte instead.
+ *
+ * For FreeBSD, we have si_pid, si_uid, si_status, and si_addr always. Linux and
+ * {Open,Net}BSD have a different approach (where their reason field is larger,
+ * but whose siginfo has fewer fields always).
+ *
+ * QEMU_SI_CAPSICUM is currently only FreeBSD 14 current only, so only define
+ * it where _capsicum is available.
+ */
+#define QEMU_SI_NOINFO 0 /* nothing other than si_signo valid */
+#define QEMU_SI_FAULT 1 /* _fault is valid in _reason */
+#define QEMU_SI_TIMER 2 /* _timer is valid in _reason */
+#define QEMU_SI_MESGQ 3 /* _mesgq is valid in _reason */
+#define QEMU_SI_POLL 4 /* _poll is valid in _reason */
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 1400026
+#define QEMU_SI_CAPSICUM 5 /* _capsicum is valid in _reason */
+#endif
+
+#endif
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
index 05b277c642..0bc6d2edbd 100644
--- a/bsd-user/signal.c
+++ b/bsd-user/signal.c
@@ -2,6 +2,7 @@
* Emulation of BSD signals
*
* Copyright (c) 2003 - 2008 Fabrice Bellard
+ * Copyright (c) 2013 Stacey Son
*
* 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
@@ -19,41 +20,1031 @@
#include "qemu/osdep.h"
#include "qemu.h"
+#include "signal-common.h"
+#include "trace.h"
+#include "hw/core/tcg-cpu-ops.h"
+#include "host-signal.h"
+
+static struct target_sigaction sigact_table[TARGET_NSIG];
+static void host_signal_handler(int host_sig, siginfo_t *info, void *puc);
+static void target_to_host_sigset_internal(sigset_t *d,
+ const target_sigset_t *s);
+
+static inline int on_sig_stack(TaskState *ts, unsigned long sp)
+{
+ return sp - ts->sigaltstack_used.ss_sp < ts->sigaltstack_used.ss_size;
+}
+
+static inline int sas_ss_flags(TaskState *ts, unsigned long sp)
+{
+ return ts->sigaltstack_used.ss_size == 0 ? SS_DISABLE :
+ on_sig_stack(ts, sp) ? SS_ONSTACK : 0;
+}
+
+/*
+ * The BSD ABIs use the same singal numbers across all the CPU architectures, so
+ * (unlike Linux) these functions are just the identity mapping. This might not
+ * be true for XyzBSD running on AbcBSD, which doesn't currently work.
+ */
+int host_to_target_signal(int sig)
+{
+ return sig;
+}
+
+int target_to_host_signal(int sig)
+{
+ return sig;
+}
+
+static inline void target_sigemptyset(target_sigset_t *set)
+{
+ memset(set, 0, sizeof(*set));
+}
+
+static inline void target_sigaddset(target_sigset_t *set, int signum)
+{
+ signum--;
+ uint32_t mask = (uint32_t)1 << (signum % TARGET_NSIG_BPW);
+ set->__bits[signum / TARGET_NSIG_BPW] |= mask;
+}
+
+static inline int target_sigismember(const target_sigset_t *set, int signum)
+{
+ signum--;
+ abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
+ return (set->__bits[signum / TARGET_NSIG_BPW] & mask) != 0;
+}
+
+/* Adjust the signal context to rewind out of safe-syscall if we're in it */
+static inline void rewind_if_in_safe_syscall(void *puc)
+{
+ ucontext_t *uc = (ucontext_t *)puc;
+ uintptr_t pcreg = host_signal_pc(uc);
+
+ if (pcreg > (uintptr_t)safe_syscall_start
+ && pcreg < (uintptr_t)safe_syscall_end) {
+ host_signal_set_pc(uc, (uintptr_t)safe_syscall_start);
+ }
+}
/*
- * Stubbed out routines until we merge signal support from bsd-user
- * fork.
+ * Note: The following take advantage of the BSD signal property that all
+ * signals are available on all architectures.
*/
+static void host_to_target_sigset_internal(target_sigset_t *d,
+ const sigset_t *s)
+{
+ int i;
+
+ target_sigemptyset(d);
+ for (i = 1; i <= NSIG; i++) {
+ if (sigismember(s, i)) {
+ target_sigaddset(d, host_to_target_signal(i));
+ }
+ }
+}
+
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
+{
+ target_sigset_t d1;
+ int i;
+
+ host_to_target_sigset_internal(&d1, s);
+ for (i = 0; i < _SIG_WORDS; i++) {
+ d->__bits[i] = tswap32(d1.__bits[i]);
+ }
+}
+
+static void target_to_host_sigset_internal(sigset_t *d,
+ const target_sigset_t *s)
+{
+ int i;
+
+ sigemptyset(d);
+ for (i = 1; i <= TARGET_NSIG; i++) {
+ if (target_sigismember(s, i)) {
+ sigaddset(d, target_to_host_signal(i));
+ }
+ }
+}
+
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
+{
+ target_sigset_t s1;
+ int i;
+
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ s1.__bits[i] = tswap32(s->__bits[i]);
+ }
+ target_to_host_sigset_internal(d, &s1);
+}
+
+static bool has_trapno(int tsig)
+{
+ return tsig == TARGET_SIGILL ||
+ tsig == TARGET_SIGFPE ||
+ tsig == TARGET_SIGSEGV ||
+ tsig == TARGET_SIGBUS ||
+ tsig == TARGET_SIGTRAP;
+}
+
+/* Siginfo conversion. */
+
+/*
+ * Populate tinfo w/o swapping based on guessing which fields are valid.
+ */
+static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
+ const siginfo_t *info)
+{
+ int sig = host_to_target_signal(info->si_signo);
+ int si_code = info->si_code;
+ int si_type;
+
+ /*
+ * Make sure we that the variable portion of the target siginfo is zeroed
+ * out so we don't leak anything into that.
+ */
+ memset(&tinfo->_reason, 0, sizeof(tinfo->_reason));
+
+ /*
+ * This is awkward, because we have to use a combination of the si_code and
+ * si_signo to figure out which of the union's members are valid.o We
+ * therefore make our best guess.
+ *
+ * Once we have made our guess, we record it in the top 16 bits of
+ * the si_code, so that tswap_siginfo() later can use it.
+ * tswap_siginfo() will strip these top bits out before writing
+ * si_code to the guest (sign-extending the lower bits).
+ */
+ tinfo->si_signo = sig;
+ tinfo->si_errno = info->si_errno;
+ tinfo->si_code = info->si_code;
+ tinfo->si_pid = info->si_pid;
+ tinfo->si_uid = info->si_uid;
+ tinfo->si_status = info->si_status;
+ tinfo->si_addr = (abi_ulong)(unsigned long)info->si_addr;
+ /*
+ * si_value is opaque to kernel. On all FreeBSD platforms,
+ * sizeof(sival_ptr) >= sizeof(sival_int) so the following
+ * always will copy the larger element.
+ */
+ tinfo->si_value.sival_ptr =
+ (abi_ulong)(unsigned long)info->si_value.sival_ptr;
+
+ switch (si_code) {
+ /*
+ * All the SI_xxx codes that are defined here are global to
+ * all the signals (they have values that none of the other,
+ * more specific signal info will set).
+ */
+ case SI_USER:
+ case SI_LWP:
+ case SI_KERNEL:
+ case SI_QUEUE:
+ case SI_ASYNCIO:
+ /*
+ * Only the fixed parts are valid (though FreeBSD doesn't always
+ * set all the fields to non-zero values.
+ */
+ si_type = QEMU_SI_NOINFO;
+ break;
+ case SI_TIMER:
+ tinfo->_reason._timer._timerid = info->_reason._timer._timerid;
+ tinfo->_reason._timer._overrun = info->_reason._timer._overrun;
+ si_type = QEMU_SI_TIMER;
+ break;
+ case SI_MESGQ:
+ tinfo->_reason._mesgq._mqd = info->_reason._mesgq._mqd;
+ si_type = QEMU_SI_MESGQ;
+ break;
+ default:
+ /*
+ * We have to go based on the signal number now to figure out
+ * what's valid.
+ */
+ si_type = QEMU_SI_NOINFO;
+ if (has_trapno(sig)) {
+ tinfo->_reason._fault._trapno = info->_reason._fault._trapno;
+ si_type = QEMU_SI_FAULT;
+ }
+#ifdef TARGET_SIGPOLL
+ /*
+ * FreeBSD never had SIGPOLL, but emulates it for Linux so there's
+ * a chance it may popup in the future.
+ */
+ if (sig == TARGET_SIGPOLL) {
+ tinfo->_reason._poll._band = info->_reason._poll._band;
+ si_type = QEMU_SI_POLL;
+ }
+#endif
+ /*
+ * Unsure that this can actually be generated, and our support for
+ * capsicum is somewhere between weak and non-existant, but if we get
+ * one, then we know what to save.
+ */
+#ifdef QEMU_SI_CAPSICUM
+ if (sig == TARGET_SIGTRAP) {
+ tinfo->_reason._capsicum._syscall =
+ info->_reason._capsicum._syscall;
+ si_type = QEMU_SI_CAPSICUM;
+ }
+#endif
+ break;
+ }
+ tinfo->si_code = deposit32(si_code, 24, 8, si_type);
+}
+
+static void tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info)
+{
+ int si_type = extract32(info->si_code, 24, 8);
+ int si_code = sextract32(info->si_code, 0, 24);
+
+ __put_user(info->si_signo, &tinfo->si_signo);
+ __put_user(info->si_errno, &tinfo->si_errno);
+ __put_user(si_code, &tinfo->si_code); /* Zero out si_type, it's internal */
+ __put_user(info->si_pid, &tinfo->si_pid);
+ __put_user(info->si_uid, &tinfo->si_uid);
+ __put_user(info->si_status, &tinfo->si_status);
+ __put_user(info->si_addr, &tinfo->si_addr);
+ /*
+ * Unswapped, because we passed it through mostly untouched. si_value is
+ * opaque to the kernel, so we didn't bother with potentially wasting cycles
+ * to swap it into host byte order.
+ */
+ tinfo->si_value.sival_ptr = info->si_value.sival_ptr;
+
+ /*
+ * We can use our internal marker of which fields in the structure
+ * are valid, rather than duplicating the guesswork of
+ * host_to_target_siginfo_noswap() here.
+ */
+ switch (si_type) {
+ case QEMU_SI_NOINFO: /* No additional info */
+ break;
+ case QEMU_SI_FAULT:
+ __put_user(info->_reason._fault._trapno,
+ &tinfo->_reason._fault._trapno);
+ break;
+ case QEMU_SI_TIMER:
+ __put_user(info->_reason._timer._timerid,
+ &tinfo->_reason._timer._timerid);
+ __put_user(info->_reason._timer._overrun,
+ &tinfo->_reason._timer._overrun);
+ break;
+ case QEMU_SI_MESGQ:
+ __put_user(info->_reason._mesgq._mqd, &tinfo->_reason._mesgq._mqd);
+ break;
+ case QEMU_SI_POLL:
+ /* Note: Not generated on FreeBSD */
+ __put_user(info->_reason._poll._band, &tinfo->_reason._poll._band);
+ break;
+#ifdef QEMU_SI_CAPSICUM
+ case QEMU_SI_CAPSICUM:
+ __put_user(info->_reason._capsicum._syscall,
+ &tinfo->_reason._capsicum._syscall);
+ break;
+#endif
+ default:
+ g_assert_not_reached();
+ }
+}
+
+int block_signals(void)
+{
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
+ sigset_t set;
+
+ /*
+ * It's OK to block everything including SIGSEGV, because we won't run any
+ * further guest code before unblocking signals in
+ * process_pending_signals(). We depend on the FreeBSD behaivor here where
+ * this will only affect this thread's signal mask. We don't use
+ * pthread_sigmask which might seem more correct because that routine also
+ * does odd things with SIGCANCEL to implement pthread_cancel().
+ */
+ sigfillset(&set);
+ sigprocmask(SIG_SETMASK, &set, 0);
+
+ return qatomic_xchg(&ts->signal_pending, 1);
+}
+
+/* Returns 1 if given signal should dump core if not handled. */
+static int core_dump_signal(int sig)
+{
+ switch (sig) {
+ case TARGET_SIGABRT:
+ case TARGET_SIGFPE:
+ case TARGET_SIGILL:
+ case TARGET_SIGQUIT:
+ case TARGET_SIGSEGV:
+ case TARGET_SIGTRAP:
+ case TARGET_SIGBUS:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* Abort execution with signal. */
+static void QEMU_NORETURN dump_core_and_abort(int target_sig)
+{
+ CPUArchState *env = thread_cpu->env_ptr;
+ CPUState *cpu = env_cpu(env);
+ TaskState *ts = cpu->opaque;
+ int core_dumped = 0;
+ int host_sig;
+ struct sigaction act;
+
+ host_sig = target_to_host_signal(target_sig);
+ gdb_signalled(env, target_sig);
+
+ /* Dump core if supported by target binary format */
+ if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
+ stop_all_tasks();
+ core_dumped =
+ ((*ts->bprm->core_dump)(target_sig, env) == 0);
+ }
+ if (core_dumped) {
+ struct rlimit nodump;
+
+ /*
+ * We already dumped the core of target process, we don't want
+ * a coredump of qemu itself.
+ */
+ getrlimit(RLIMIT_CORE, &nodump);
+ nodump.rlim_cur = 0;
+ setrlimit(RLIMIT_CORE, &nodump);
+ (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) "
+ "- %s\n", target_sig, strsignal(host_sig), "core dumped");
+ }
+
+ /*
+ * The proper exit code for dying from an uncaught signal is
+ * -<signal>. The kernel doesn't allow exit() or _exit() to pass
+ * a negative value. To get the proper exit code we need to
+ * actually die from an uncaught signal. Here the default signal
+ * handler is installed, we send ourself a signal and we wait for
+ * it to arrive.
+ */
+ memset(&act, 0, sizeof(act));
+ sigfillset(&act.sa_mask);
+ act.sa_handler = SIG_DFL;
+ sigaction(host_sig, &act, NULL);
+
+ kill(getpid(), host_sig);
+
+ /*
+ * Make sure the signal isn't masked (just reuse the mask inside
+ * of act).
+ */
+ sigdelset(&act.sa_mask, host_sig);
+ sigsuspend(&act.sa_mask);
+
+ /* unreachable */
+ abort();
+}
/*
* Queue a signal so that it will be send to the virtual CPU as soon as
* possible.
*/
-void queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
+void queue_signal(CPUArchState *env, int sig, int si_type,
+ target_siginfo_t *info)
{
- qemu_log_mask(LOG_UNIMP, "No signal queueing, dropping signal %d\n", sig);
+ CPUState *cpu = env_cpu(env);
+ TaskState *ts = cpu->opaque;
+
+ trace_user_queue_signal(env, sig);
+
+ info->si_code = deposit32(info->si_code, 24, 8, si_type);
+
+ ts->sync_signal.info = *info;
+ ts->sync_signal.pending = sig;
+ /* Signal that a new signal is pending. */
+ qatomic_set(&ts->signal_pending, 1);
+ return;
+}
+
+static int fatal_signal(int sig)
+{
+
+ switch (sig) {
+ case TARGET_SIGCHLD:
+ case TARGET_SIGURG:
+ case TARGET_SIGWINCH:
+ case TARGET_SIGINFO:
+ /* Ignored by default. */
+ return 0;
+ case TARGET_SIGCONT:
+ case TARGET_SIGSTOP:
+ case TARGET_SIGTSTP:
+ case TARGET_SIGTTIN:
+ case TARGET_SIGTTOU:
+ /* Job control signals. */
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+/*
+ * Force a synchronously taken QEMU_SI_FAULT signal. For QEMU the
+ * 'force' part is handled in process_pending_signals().
+ */
+void force_sig_fault(int sig, int code, abi_ulong addr)
+{
+ CPUState *cpu = thread_cpu;
+ CPUArchState *env = cpu->env_ptr;
+ target_siginfo_t info = {};
+
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = code;
+ info.si_addr = addr;
+ queue_signal(env, sig, QEMU_SI_FAULT, &info);
+}
+
+static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
+{
+ CPUArchState *env = thread_cpu->env_ptr;
+ CPUState *cpu = env_cpu(env);
+ TaskState *ts = cpu->opaque;
+ target_siginfo_t tinfo;
+ ucontext_t *uc = puc;
+ struct emulated_sigtable *k;
+ int guest_sig;
+ uintptr_t pc = 0;
+ bool sync_sig = false;
+
+ /*
+ * Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
+ * handling wrt signal blocking and unwinding.
+ */
+ if ((host_sig == SIGSEGV || host_sig == SIGBUS) && info->si_code > 0) {
+ MMUAccessType access_type;
+ uintptr_t host_addr;
+ abi_ptr guest_addr;
+ bool is_write;
+
+ host_addr = (uintptr_t)info->si_addr;
+
+ /*
+ * Convert forcefully to guest address space: addresses outside
+ * reserved_va are still valid to report via SEGV_MAPERR.
+ */
+ guest_addr = h2g_nocheck(host_addr);
+
+ pc = host_signal_pc(uc);
+ is_write = host_signal_write(info, uc);
+ access_type = adjust_signal_pc(&pc, is_write);
+
+ if (host_sig == SIGSEGV) {
+ bool maperr = true;
+
+ if (info->si_code == SEGV_ACCERR && h2g_valid(host_addr)) {
+ /* If this was a write to a TB protected page, restart. */
+ if (is_write &&
+ handle_sigsegv_accerr_write(cpu, &uc->uc_sigmask,
+ pc, guest_addr)) {
+ return;
+ }
+
+ /*
+ * With reserved_va, the whole address space is PROT_NONE,
+ * which means that we may get ACCERR when we want MAPERR.
+ */
+ if (page_get_flags(guest_addr) & PAGE_VALID) {
+ maperr = false;
+ } else {
+ info->si_code = SEGV_MAPERR;
+ }
+ }
+
+ sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+ cpu_loop_exit_sigsegv(cpu, guest_addr, access_type, maperr, pc);
+ } else {
+ sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+ if (info->si_code == BUS_ADRALN) {
+ cpu_loop_exit_sigbus(cpu, guest_addr, access_type, pc);
+ }
+ }
+
+ sync_sig = true;
+ }
+
+ /* Get the target signal number. */
+ guest_sig = host_to_target_signal(host_sig);
+ if (guest_sig < 1 || guest_sig > TARGET_NSIG) {
+ return;
+ }
+ trace_user_host_signal(cpu, host_sig, guest_sig);
+
+ host_to_target_siginfo_noswap(&tinfo, info);
+
+ k = &ts->sigtab[guest_sig - 1];
+ k->info = tinfo;
+ k->pending = guest_sig;
+ ts->signal_pending = 1;
+
+ /*
+ * For synchronous signals, unwind the cpu state to the faulting
+ * insn and then exit back to the main loop so that the signal
+ * is delivered immediately.
+ */
+ if (sync_sig) {
+ cpu->exception_index = EXCP_INTERRUPT;
+ cpu_loop_exit_restore(cpu, pc);
+ }
+
+ rewind_if_in_safe_syscall(puc);
+
+ /*
+ * Block host signals until target signal handler entered. We
+ * can't block SIGSEGV or SIGBUS while we're executing guest
+ * code in case the guest code provokes one in the window between
+ * now and it getting out to the main loop. Signals will be
+ * unblocked again in process_pending_signals().
+ */
+ sigfillset(&uc->uc_sigmask);
+ sigdelset(&uc->uc_sigmask, SIGSEGV);
+ sigdelset(&uc->uc_sigmask, SIGBUS);
+
+ /* Interrupt the virtual CPU as soon as possible. */
+ cpu_exit(thread_cpu);
+}
+
+/* do_sigaltstack() returns target values and errnos. */
+/* compare to kern/kern_sig.c sys_sigaltstack() and kern_sigaltstack() */
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
+{
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
+ int ret;
+ target_stack_t oss;
+
+ if (uoss_addr) {
+ /* Save current signal stack params */
+ oss.ss_sp = tswapl(ts->sigaltstack_used.ss_sp);
+ oss.ss_size = tswapl(ts->sigaltstack_used.ss_size);
+ oss.ss_flags = tswapl(sas_ss_flags(ts, sp));
+ }
+
+ if (uss_addr) {
+ target_stack_t *uss;
+ target_stack_t ss;
+ size_t minstacksize = TARGET_MINSIGSTKSZ;
+
+ ret = -TARGET_EFAULT;
+ if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
+ goto out;
+ }
+ __get_user(ss.ss_sp, &uss->ss_sp);
+ __get_user(ss.ss_size, &uss->ss_size);
+ __get_user(ss.ss_flags, &uss->ss_flags);
+ unlock_user_struct(uss, uss_addr, 0);
+
+ ret = -TARGET_EPERM;
+ if (on_sig_stack(ts, sp)) {
+ goto out;
+ }
+
+ ret = -TARGET_EINVAL;
+ if (ss.ss_flags != TARGET_SS_DISABLE
+ && ss.ss_flags != TARGET_SS_ONSTACK
+ && ss.ss_flags != 0) {
+ goto out;
+ }
+
+ if (ss.ss_flags == TARGET_SS_DISABLE) {
+ ss.ss_size = 0;
+ ss.ss_sp = 0;
+ } else {
+ ret = -TARGET_ENOMEM;
+ if (ss.ss_size < minstacksize) {
+ goto out;
+ }
+ }
+
+ ts->sigaltstack_used.ss_sp = ss.ss_sp;
+ ts->sigaltstack_used.ss_size = ss.ss_size;
+ }
+
+ if (uoss_addr) {
+ ret = -TARGET_EFAULT;
+ if (copy_to_user(uoss_addr, &oss, sizeof(oss))) {
+ goto out;
+ }
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+/* do_sigaction() return host values and errnos */
+int do_sigaction(int sig, const struct target_sigaction *act,
+ struct target_sigaction *oact)
+{
+ struct target_sigaction *k;
+ struct sigaction act1;
+ int host_sig;
+ int ret = 0;
+
+ if (sig < 1 || sig > TARGET_NSIG) {
+ return -TARGET_EINVAL;
+ }
+
+ if ((sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP) &&
+ act != NULL && act->_sa_handler != TARGET_SIG_DFL) {
+ return -TARGET_EINVAL;
+ }
+
+ if (block_signals()) {
+ return -TARGET_ERESTART;
+ }
+
+ k = &sigact_table[sig - 1];
+ if (oact) {
+ oact->_sa_handler = tswapal(k->_sa_handler);
+ oact->sa_flags = tswap32(k->sa_flags);
+ oact->sa_mask = k->sa_mask;
+ }
+ if (act) {
+ k->_sa_handler = tswapal(act->_sa_handler);
+ k->sa_flags = tswap32(act->sa_flags);
+ k->sa_mask = act->sa_mask;
+
+ /* Update the host signal state. */
+ host_sig = target_to_host_signal(sig);
+ if (host_sig != SIGSEGV && host_sig != SIGBUS) {
+ memset(&act1, 0, sizeof(struct sigaction));
+ sigfillset(&act1.sa_mask);
+ act1.sa_flags = SA_SIGINFO;
+ if (k->sa_flags & TARGET_SA_RESTART) {
+ act1.sa_flags |= SA_RESTART;
+ }
+ /*
+ * Note: It is important to update the host kernel signal mask to
+ * avoid getting unexpected interrupted system calls.
+ */
+ if (k->_sa_handler == TARGET_SIG_IGN) {
+ act1.sa_sigaction = (void *)SIG_IGN;
+ } else if (k->_sa_handler == TARGET_SIG_DFL) {
+ if (fatal_signal(sig)) {
+ act1.sa_sigaction = host_signal_handler;
+ } else {
+ act1.sa_sigaction = (void *)SIG_DFL;
+ }
+ } else {
+ act1.sa_sigaction = host_signal_handler;
+ }
+ ret = sigaction(host_sig, &act1, NULL);
+ }
+ }
+ return ret;
+}
+
+static inline abi_ulong get_sigframe(struct target_sigaction *ka,
+ CPUArchState *env, size_t frame_size)
+{
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
+ abi_ulong sp;
+
+ /* Use default user stack */
+ sp = get_sp_from_cpustate(env);
+
+ if ((ka->sa_flags & TARGET_SA_ONSTACK) && sas_ss_flags(ts, sp) == 0) {
+ sp = ts->sigaltstack_used.ss_sp + ts->sigaltstack_used.ss_size;
+ }
+
+/* TODO: make this a target_arch function / define */
+#if defined(TARGET_ARM)
+ return (sp - frame_size) & ~7;
+#elif defined(TARGET_AARCH64)
+ return (sp - frame_size) & ~15;
+#else
+ return sp - frame_size;
+#endif
+}
+
+/* compare to $M/$M/exec_machdep.c sendsig and sys/kern/kern_sig.c sigexit */
+
+static void setup_frame(int sig, int code, struct target_sigaction *ka,
+ target_sigset_t *set, target_siginfo_t *tinfo, CPUArchState *env)
+{
+ struct target_sigframe *frame;
+ abi_ulong frame_addr;
+ int i;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ unlock_user_struct(frame, frame_addr, 1);
+ dump_core_and_abort(TARGET_SIGILL);
+ return;
+ }
+
+ memset(frame, 0, sizeof(*frame));
+ setup_sigframe_arch(env, frame_addr, frame, 0);
+
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->__bits[i], &frame->sf_uc.uc_sigmask.__bits[i]);
+ }
+
+ if (tinfo) {
+ frame->sf_si.si_signo = tinfo->si_signo;
+ frame->sf_si.si_errno = tinfo->si_errno;
+ frame->sf_si.si_code = tinfo->si_code;
+ frame->sf_si.si_pid = tinfo->si_pid;
+ frame->sf_si.si_uid = tinfo->si_uid;
+ frame->sf_si.si_status = tinfo->si_status;
+ frame->sf_si.si_addr = tinfo->si_addr;
+ /* see host_to_target_siginfo_noswap() for more details */
+ frame->sf_si.si_value.sival_ptr = tinfo->si_value.sival_ptr;
+ /*
+ * At this point, whatever is in the _reason union is complete
+ * and in target order, so just copy the whole thing over, even
+ * if it's too large for this specific signal.
+ * host_to_target_siginfo_noswap() and tswap_siginfo() have ensured
+ * that's so.
+ */
+ memcpy(&frame->sf_si._reason, &tinfo->_reason,
+ sizeof(tinfo->_reason));
+ }
+
+ set_sigtramp_args(env, sig, frame, frame_addr, ka);
+
+ unlock_user_struct(frame, frame_addr, 1);
+}
+
+static int reset_signal_mask(target_ucontext_t *ucontext)
+{
+ int i;
+ sigset_t blocked;
+ target_sigset_t target_set;
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
+
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ if (__get_user(target_set.__bits[i],
+ &ucontext->uc_sigmask.__bits[i])) {
+ return -TARGET_EFAULT;
+ }
+ }
+ target_to_host_sigset_internal(&blocked, &target_set);
+ ts->signal_mask = blocked;
+
+ return 0;
+}
+
+/* See sys/$M/$M/exec_machdep.c sigreturn() */
+long do_sigreturn(CPUArchState *env, abi_ulong addr)
+{
+ long ret;
+ abi_ulong target_ucontext;
+ target_ucontext_t *ucontext = NULL;
+
+ /* Get the target ucontext address from the stack frame */
+ ret = get_ucontext_sigreturn(env, addr, &target_ucontext);
+ if (is_error(ret)) {
+ return ret;
+ }
+ trace_user_do_sigreturn(env, addr);
+ if (!lock_user_struct(VERIFY_READ, ucontext, target_ucontext, 0)) {
+ goto badframe;
+ }
+
+ /* Set the register state back to before the signal. */
+ if (set_mcontext(env, &ucontext->uc_mcontext, 1)) {
+ goto badframe;
+ }
+
+ /* And reset the signal mask. */
+ if (reset_signal_mask(ucontext)) {
+ goto badframe;
+ }
+
+ unlock_user_struct(ucontext, target_ucontext, 0);
+ return -TARGET_EJUSTRETURN;
+
+badframe:
+ if (ucontext != NULL) {
+ unlock_user_struct(ucontext, target_ucontext, 0);
+ }
+ return -TARGET_EFAULT;
}
void signal_init(void)
{
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
+ struct sigaction act;
+ struct sigaction oact;
+ int i;
+ int host_sig;
+
+ /* Set the signal mask from the host mask. */
+ sigprocmask(0, 0, &ts->signal_mask);
+
+ sigfillset(&act.sa_mask);
+ act.sa_sigaction = host_signal_handler;
+ act.sa_flags = SA_SIGINFO;
+
+ for (i = 1; i <= TARGET_NSIG; i++) {
+#ifdef CONFIG_GPROF
+ if (i == TARGET_SIGPROF) {
+ continue;
+ }
+#endif
+ host_sig = target_to_host_signal(i);
+ sigaction(host_sig, NULL, &oact);
+ if (oact.sa_sigaction == (void *)SIG_IGN) {
+ sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
+ } else if (oact.sa_sigaction == (void *)SIG_DFL) {
+ sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
+ }
+ /*
+ * If there's already a handler installed then something has
+ * gone horribly wrong, so don't even try to handle that case.
+ * Install some handlers for our own use. We need at least
+ * SIGSEGV and SIGBUS, to detect exceptions. We can not just
+ * trap all signals because it affects syscall interrupt
+ * behavior. But do trap all default-fatal signals.
+ */
+ if (fatal_signal(i)) {
+ sigaction(host_sig, &act, NULL);
+ }
+ }
}
-void process_pending_signals(CPUArchState *cpu_env)
+static void handle_pending_signal(CPUArchState *env, int sig,
+ struct emulated_sigtable *k)
{
+ CPUState *cpu = env_cpu(env);
+ TaskState *ts = cpu->opaque;
+ struct target_sigaction *sa;
+ int code;
+ sigset_t set;
+ abi_ulong handler;
+ target_siginfo_t tinfo;
+ target_sigset_t target_old_set;
+
+ trace_user_handle_signal(env, sig);
+
+ k->pending = 0;
+
+ sig = gdb_handlesig(cpu, sig);
+ if (!sig) {
+ sa = NULL;
+ handler = TARGET_SIG_IGN;
+ } else {
+ sa = &sigact_table[sig - 1];
+ handler = sa->_sa_handler;
+ }
+
+ if (do_strace) {
+ print_taken_signal(sig, &k->info);
+ }
+
+ if (handler == TARGET_SIG_DFL) {
+ /*
+ * default handler : ignore some signal. The other are job
+ * control or fatal.
+ */
+ if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN ||
+ sig == TARGET_SIGTTOU) {
+ kill(getpid(), SIGSTOP);
+ } else if (sig != TARGET_SIGCHLD && sig != TARGET_SIGURG &&
+ sig != TARGET_SIGINFO && sig != TARGET_SIGWINCH &&
+ sig != TARGET_SIGCONT) {
+ dump_core_and_abort(sig);
+ }
+ } else if (handler == TARGET_SIG_IGN) {
+ /* ignore sig */
+ } else if (handler == TARGET_SIG_ERR) {
+ dump_core_and_abort(sig);
+ } else {
+ /* compute the blocked signals during the handler execution */
+ sigset_t *blocked_set;
+
+ target_to_host_sigset(&set, &sa->sa_mask);
+ /*
+ * SA_NODEFER indicates that the current signal should not be
+ * blocked during the handler.
+ */
+ if (!(sa->sa_flags & TARGET_SA_NODEFER)) {
+ sigaddset(&set, target_to_host_signal(sig));
+ }
+
+ /*
+ * Save the previous blocked signal state to restore it at the
+ * end of the signal execution (see do_sigreturn).
+ */
+ host_to_target_sigset_internal(&target_old_set, &ts->signal_mask);
+
+ blocked_set = ts->in_sigsuspend ?
+ &ts->sigsuspend_mask : &ts->signal_mask;
+ sigorset(&ts->signal_mask, blocked_set, &set);
+ ts->in_sigsuspend = false;
+ sigprocmask(SIG_SETMASK, &ts->signal_mask, NULL);
+
+ /* XXX VM86 on x86 ??? */
+
+ code = k->info.si_code; /* From host, so no si_type */
+ /* prepare the stack frame of the virtual CPU */
+ if (sa->sa_flags & TARGET_SA_SIGINFO) {
+ tswap_siginfo(&tinfo, &k->info);
+ setup_frame(sig, code, sa, &target_old_set, &tinfo, env);
+ } else {
+ setup_frame(sig, code, sa, &target_old_set, NULL, env);
+ }
+ if (sa->sa_flags & TARGET_SA_RESETHAND) {
+ sa->_sa_handler = TARGET_SIG_DFL;
+ }
+ }
+}
+
+void process_pending_signals(CPUArchState *env)
+{
+ CPUState *cpu = env_cpu(env);
+ int sig;
+ sigset_t *blocked_set, set;
+ struct emulated_sigtable *k;
+ TaskState *ts = cpu->opaque;
+
+ while (qatomic_read(&ts->signal_pending)) {
+ sigfillset(&set);
+ sigprocmask(SIG_SETMASK, &set, 0);
+
+ restart_scan:
+ sig = ts->sync_signal.pending;
+ if (sig) {
+ /*
+ * Synchronous signals are forced by the emulated CPU in some way.
+ * If they are set to ignore, restore the default handler (see
+ * sys/kern_sig.c trapsignal() and execsigs() for this behavior)
+ * though maybe this is done only when forcing exit for non SIGCHLD.
+ */
+ if (sigismember(&ts->signal_mask, target_to_host_signal(sig)) ||
+ sigact_table[sig - 1]._sa_handler == TARGET_SIG_IGN) {
+ sigdelset(&ts->signal_mask, target_to_host_signal(sig));
+ sigact_table[sig - 1]._sa_handler = TARGET_SIG_DFL;
+ }
+ handle_pending_signal(env, sig, &ts->sync_signal);
+ }
+
+ k = ts->sigtab;
+ for (sig = 1; sig <= TARGET_NSIG; sig++, k++) {
+ blocked_set = ts->in_sigsuspend ?
+ &ts->sigsuspend_mask : &ts->signal_mask;
+ if (k->pending &&
+ !sigismember(blocked_set, target_to_host_signal(sig))) {
+ handle_pending_signal(env, sig, k);
+ /*
+ * Restart scan from the beginning, as handle_pending_signal
+ * might have resulted in a new synchronous signal (eg SIGSEGV).
+ */
+ goto restart_scan;
+ }
+ }
+
+ /*
+ * Unblock signals and check one more time. Unblocking signals may cause
+ * us to take another host signal, which will set signal_pending again.
+ */
+ qatomic_set(&ts->signal_pending, 0);
+ ts->in_sigsuspend = false;
+ set = ts->signal_mask;
+ sigdelset(&set, SIGSEGV);
+ sigdelset(&set, SIGBUS);
+ sigprocmask(SIG_SETMASK, &set, 0);
+ }
+ ts->in_sigsuspend = false;
}
void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
MMUAccessType access_type, bool maperr, uintptr_t ra)
{
- qemu_log_mask(LOG_UNIMP, "No signal support for SIGSEGV\n");
- /* unreachable */
- abort();
+ const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
+
+ if (tcg_ops->record_sigsegv) {
+ tcg_ops->record_sigsegv(cpu, addr, access_type, maperr, ra);
+ }
+
+ force_sig_fault(TARGET_SIGSEGV,
+ maperr ? TARGET_SEGV_MAPERR : TARGET_SEGV_ACCERR,
+ addr);
+ cpu->exception_index = EXCP_INTERRUPT;
+ cpu_loop_exit_restore(cpu, ra);
}
void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr,
MMUAccessType access_type, uintptr_t ra)
{
- qemu_log_mask(LOG_UNIMP, "No signal support for SIGBUS\n");
- /* unreachable */
- abort();
+ const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
+
+ if (tcg_ops->record_sigbus) {
+ tcg_ops->record_sigbus(cpu, addr, access_type, ra);
+ }
+
+ force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN, addr);
+ cpu->exception_index = EXCP_INTERRUPT;
+ cpu_loop_exit_restore(cpu, ra);
}
diff --git a/bsd-user/strace.c b/bsd-user/strace.c
index be40b8a20c..a77d10dd6b 100644
--- a/bsd-user/strace.c
+++ b/bsd-user/strace.c
@@ -31,6 +31,24 @@ int do_strace;
/*
* Utility functions
*/
+static const char *
+get_comma(int last)
+{
+ return (last) ? "" : ",";
+}
+
+/*
+ * Prints out raw parameter using given format. Caller needs
+ * to do byte swapping if needed.
+ */
+static void
+print_raw_param(const char *fmt, abi_long param, int last)
+{
+ char format[64];
+
+ (void)snprintf(format, sizeof(format), "%s%s", fmt, get_comma(last));
+ gemu_log(format, param);
+}
static void print_sysctl(const struct syscallname *name, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
@@ -239,3 +257,82 @@ void print_openbsd_syscall_ret(int num, abi_long ret)
print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames));
}
+
+static void
+print_signal(abi_ulong arg, int last)
+{
+ const char *signal_name = NULL;
+ switch (arg) {
+ case TARGET_SIGHUP:
+ signal_name = "SIGHUP";
+ break;
+ case TARGET_SIGINT:
+ signal_name = "SIGINT";
+ break;
+ case TARGET_SIGQUIT:
+ signal_name = "SIGQUIT";
+ break;
+ case TARGET_SIGILL:
+ signal_name = "SIGILL";
+ break;
+ case TARGET_SIGABRT:
+ signal_name = "SIGABRT";
+ break;
+ case TARGET_SIGFPE:
+ signal_name = "SIGFPE";
+ break;
+ case TARGET_SIGKILL:
+ signal_name = "SIGKILL";
+ break;
+ case TARGET_SIGSEGV:
+ signal_name = "SIGSEGV";
+ break;
+ case TARGET_SIGPIPE:
+ signal_name = "SIGPIPE";
+ break;
+ case TARGET_SIGALRM:
+ signal_name = "SIGALRM";
+ break;
+ case TARGET_SIGTERM:
+ signal_name = "SIGTERM";
+ break;
+ case TARGET_SIGUSR1:
+ signal_name = "SIGUSR1";
+ break;
+ case TARGET_SIGUSR2:
+ signal_name = "SIGUSR2";
+ break;
+ case TARGET_SIGCHLD:
+ signal_name = "SIGCHLD";
+ break;
+ case TARGET_SIGCONT:
+ signal_name = "SIGCONT";
+ break;
+ case TARGET_SIGSTOP:
+ signal_name = "SIGSTOP";
+ break;
+ case TARGET_SIGTTIN:
+ signal_name = "SIGTTIN";
+ break;
+ case TARGET_SIGTTOU:
+ signal_name = "SIGTTOU";
+ break;
+ }
+ if (signal_name == NULL) {
+ print_raw_param("%ld", arg, last);
+ return;
+ }
+ gemu_log("%s%s", signal_name, get_comma(last));
+}
+
+void print_taken_signal(int target_signum, const target_siginfo_t *tinfo)
+{
+ /*
+ * Print the strace output for a signal being taken:
+ * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
+ */
+ gemu_log("%d ", getpid());
+ gemu_log("--- ");
+ print_signal(target_signum, 1);
+ gemu_log(" ---\n");
+}
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 04a1a886d7..62b472b990 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -21,6 +21,7 @@
#define _SYSCALL_DEFS_H_
#include <sys/syscall.h>
+#include <sys/resource.h>
#include "errno_defs.h"
diff --git a/bsd-user/trace-events b/bsd-user/trace-events
new file mode 100644
index 0000000000..843896f627
--- /dev/null
+++ b/bsd-user/trace-events
@@ -0,0 +1,11 @@
+# See docs/tracing.txt for syntax documentation.
+
+# bsd-user/signal.c
+user_setup_frame(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
+user_setup_rt_frame(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
+user_do_rt_sigreturn(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
+user_do_sigreturn(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
+user_dump_core_and_abort(void *env, int target_sig, int host_sig) "env=%p signal %d (host %d)"
+user_handle_signal(void *env, int target_sig) "env=%p signal %d"
+user_host_signal(void *env, int host_sig, int target_sig) "env=%p signal %d (target %d("
+user_queue_signal(void *env, int target_sig) "env=%p signal %d"
diff --git a/bsd-user/trace.h b/bsd-user/trace.h
new file mode 100644
index 0000000000..593c0204ad
--- /dev/null
+++ b/bsd-user/trace.h
@@ -0,0 +1 @@
+#include "trace/trace-bsd_user.h"
diff --git a/bsd-user/x86_64/signal.c b/bsd-user/x86_64/signal.c
index 8885152a7d..c3875bc4c6 100644
--- a/bsd-user/x86_64/signal.c
+++ b/bsd-user/x86_64/signal.c
@@ -30,6 +30,19 @@ abi_long set_sigtramp_args(CPUX86State *regs,
return 0;
}
+/*
+ * Compare to amd64/amd64/exec_machdep.c sendsig()
+ * Assumes that the memory is locked if frame points to user memory.
+ */
+abi_long setup_sigframe_arch(CPUX86State *env, abi_ulong frame_addr,
+ struct target_sigframe *frame, int flags)
+{
+ target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
+
+ get_mcontext(env, mcp, flags);
+ return 0;
+}
+
/* Compare to amd64/amd64/machdep.c get_mcontext() */
abi_long get_mcontext(CPUX86State *regs,
target_mcontext_t *mcp, int flags)
diff --git a/bsd-user/x86_64/target_arch_cpu.h b/bsd-user/x86_64/target_arch_cpu.h
index 5172b230f0..0a9c0f0894 100644
--- a/bsd-user/x86_64/target_arch_cpu.h
+++ b/bsd-user/x86_64/target_arch_cpu.h
@@ -20,6 +20,7 @@
#define _TARGET_ARCH_CPU_H_
#include "target_arch.h"
+#include "signal-common.h"
#define TARGET_DEFAULT_CPU_MODEL "qemu64"
@@ -237,9 +238,9 @@ static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
env->regs[R_EAX] = 0;
}
-static inline void target_cpu_reset(CPUArchState *cpu)
+static inline void target_cpu_reset(CPUArchState *env)
{
- cpu_reset(env_cpu(cpu));
+ cpu_reset(env_cpu(env));
}
#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/configure b/configure
index e1a31fb332..dfb9019b24 100755
--- a/configure
+++ b/configure
@@ -402,7 +402,7 @@ for opt do
;;
--cross-cc-*[!a-zA-Z0-9_-]*=*) error_exit "Passed bad --cross-cc-FOO option"
;;
- --cross-cc-cflags-*) cc_arch=${opt#--cross-cc-flags-}; cc_arch=${cc_arch%%=*}
+ --cross-cc-cflags-*) cc_arch=${opt#--cross-cc-cflags-}; cc_arch=${cc_arch%%=*}
eval "cross_cc_cflags_${cc_arch}=\$optarg"
cross_cc_vars="$cross_cc_vars cross_cc_cflags_${cc_arch}"
;;
@@ -1328,7 +1328,7 @@ Advanced options (experts only):
--extra-cxxflags=CXXFLAGS append extra C++ compiler flags CXXFLAGS
--extra-ldflags=LDFLAGS append extra linker flags LDFLAGS
--cross-cc-ARCH=CC use compiler when building ARCH guest test cases
- --cross-cc-flags-ARCH= use compiler flags when building ARCH guest tests
+ --cross-cc-cflags-ARCH= use compiler flags when building ARCH guest tests
--make=MAKE use specified make [$make]
--python=PYTHON use specified python [$python]
--sphinx-build=SPHINX use specified sphinx-build [$sphinx_build]
@@ -2768,7 +2768,7 @@ cat > $TMPC << EOF
#include <cpuid.h>
int main(void) {
unsigned a, b, c, d;
- int max = __get_cpuid_max(0, 0);
+ unsigned max = __get_cpuid_max(0, 0);
if (max >= 1) {
__cpuid(1, a, b, c, d);
diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index e21e07478f..47a594a3b6 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -264,6 +264,19 @@ accepted incorrect commands will return an error. Users should make sure that
all arguments passed to ``device_add`` are consistent with the documented
property types.
+``query-sgx`` return value member ``section-size`` (since 7.0)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Member ``section-size`` in return value elements with meta-type ``uint64`` is
+deprecated. Use ``sections`` instead.
+
+
+``query-sgx-capabilities`` return value member ``section-size`` (since 7.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Member ``section-size`` in return value elements with meta-type ``uint64`` is
+deprecated. Use ``sections`` instead.
+
System accelerators
-------------------
diff --git a/docs/conf.py b/docs/conf.py
index e79015975e..49dab44cca 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -98,7 +98,7 @@ default_role = 'any'
# General information about the project.
project = u'QEMU'
-copyright = u'2021, The QEMU Project Developers'
+copyright = u'2022, The QEMU Project Developers'
author = u'The QEMU Project Developers'
# The version info for the project you're documenting, acts as replacement for
diff --git a/docs/devel/qapi-code-gen.rst b/docs/devel/qapi-code-gen.rst
index a3b5473089..246709ede8 100644
--- a/docs/devel/qapi-code-gen.rst
+++ b/docs/devel/qapi-code-gen.rst
@@ -1630,6 +1630,9 @@ The following files are generated:
``$(prefix)qapi-commands.h``
Function prototypes for the QMP commands specified in the schema
+ ``$(prefix)qapi-commands.trace-events``
+ Trace event declarations, see :ref:`tracing`.
+
``$(prefix)qapi-init-commands.h``
Command initialization prototype
@@ -1650,6 +1653,13 @@ Example::
void qmp_marshal_my_command(QDict *args, QObject **ret, Error **errp);
#endif /* EXAMPLE_QAPI_COMMANDS_H */
+
+ $ cat qapi-generated/example-qapi-commands.trace-events
+ # AUTOMATICALLY GENERATED, DO NOT MODIFY
+
+ qmp_enter_my_command(const char *json) "%s"
+ qmp_exit_my_command(const char *result, bool succeeded) "%s %d"
+
$ cat qapi-generated/example-qapi-commands.c
[Uninteresting stuff omitted...]
@@ -1689,14 +1699,27 @@ Example::
goto out;
}
+ if (trace_event_get_state_backends(TRACE_QMP_ENTER_MY_COMMAND)) {
+ g_autoptr(GString) req_json = qobject_to_json(QOBJECT(args));
+
+ trace_qmp_enter_my_command(req_json->str);
+ }
+
retval = qmp_my_command(arg.arg1, &err);
- error_propagate(errp, err);
if (err) {
+ trace_qmp_exit_my_command(error_get_pretty(err), false);
+ error_propagate(errp, err);
goto out;
}
qmp_marshal_output_UserDefOne(retval, ret, errp);
+ if (trace_event_get_state_backends(TRACE_QMP_EXIT_MY_COMMAND)) {
+ g_autoptr(GString) ret_json = qobject_to_json(*ret);
+
+ trace_qmp_exit_my_command(ret_json->str, true);
+ }
+
out:
visit_free(v);
v = qapi_dealloc_visitor_new();
diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst
index d744b5909c..92d40cdd19 100644
--- a/docs/devel/testing.rst
+++ b/docs/devel/testing.rst
@@ -1324,7 +1324,7 @@ for the architecture in question, for example::
$(configure) --cross-cc-aarch64=aarch64-cc
-There is also a ``--cross-cc-flags-ARCH`` flag in case additional
+There is also a ``--cross-cc-cflags-ARCH`` flag in case additional
compiler flags are needed to build for a given target.
If you have the ability to run containers as the user the build system
diff --git a/docs/devel/tracing.rst b/docs/devel/tracing.rst
index ba83954899..4290ac42ee 100644
--- a/docs/devel/tracing.rst
+++ b/docs/devel/tracing.rst
@@ -1,3 +1,5 @@
+.. _tracing:
+
=======
Tracing
=======
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index d663dd92bd..8885ea11cf 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -463,7 +463,7 @@ Command description:
``--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]
+.. 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
*FMT*. Depending on the file format, you can add one or more *OPTIONS*
diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst
index 9b0eaba6e5..878e6a5c5c 100644
--- a/docs/tools/qemu-storage-daemon.rst
+++ b/docs/tools/qemu-storage-daemon.rst
@@ -76,7 +76,7 @@ Standard options:
.. option:: --export [type=]nbd,id=<id>,node-name=<node-name>[,name=<export-name>][,writable=on|off][,bitmap=<name>]
--export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=unix,addr.path=<socket-path>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>]
--export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=fd,addr.str=<fd>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>]
- --export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file>[,growable=on|off][,writable=on|off]
+ --export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file>[,growable=on|off][,writable=on|off][,allow-other=on|off|auto]
is a block export definition. ``node-name`` is the block node that should be
exported. ``writable`` determines whether or not the export allows write
@@ -103,7 +103,12 @@ Standard options:
mounted). Consequently, applications that have opened the given file before
the export became active will continue to see its original content. If
``growable`` is set, writes after the end of the exported file will grow the
- block node to fit.
+ block node to fit. The ``allow-other`` option controls whether users other
+ than the user running the process will be allowed to access the export. Note
+ that enabling this option as a non-root user requires enabling the
+ user_allow_other option in the global fuse.conf configuration file. Setting
+ ``allow-other`` to auto (the default) will try enabling this option, and on
+ error fall back to disabling it.
.. option:: --monitor MONITORDEF
diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig
index 622b0b50b7..19caebde6c 100644
--- a/hw/acpi/Kconfig
+++ b/hw/acpi/Kconfig
@@ -10,6 +10,7 @@ config ACPI_X86
select ACPI_HMAT
select ACPI_PIIX4
select ACPI_PCIHP
+ select ACPI_ERST
config ACPI_X86_ICH
bool
@@ -60,3 +61,8 @@ config ACPI_HW_REDUCED
select ACPI
select ACPI_MEMORY_HOTPLUG
select ACPI_NVDIMM
+
+config ACPI_ERST
+ bool
+ default y
+ depends on ACPI && PCI
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index bb2cad63b5..8966e16320 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1724,9 +1724,9 @@ void acpi_table_begin(AcpiTable *desc, GArray *array)
build_append_int_noprefix(array, 0, 4); /* Length */
build_append_int_noprefix(array, desc->rev, 1); /* Revision */
build_append_int_noprefix(array, 0, 1); /* Checksum */
- build_append_padded_str(array, desc->oem_id, 6, ' '); /* OEMID */
+ build_append_padded_str(array, desc->oem_id, 6, '\0'); /* OEMID */
/* OEM Table ID */
- build_append_padded_str(array, desc->oem_table_id, 8, ' ');
+ build_append_padded_str(array, desc->oem_table_id, 8, '\0');
build_append_int_noprefix(array, 1, 4); /* OEM Revision */
g_array_append_vals(array, ACPI_BUILD_APPNAME8, 4); /* Creator ID */
build_append_int_noprefix(array, 1, 4); /* Creator Revision */
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index b20903ea30..3646dbfe68 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -297,7 +297,6 @@ static const VMStateDescription vmstate_cpuhp_sts = {
.name = "CPU hotplug device state",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_BOOL(is_inserting, AcpiCpuStatus),
VMSTATE_BOOL(is_removing, AcpiCpuStatus),
@@ -311,7 +310,6 @@ const VMStateDescription vmstate_cpu_hotplug = {
.name = "CPU hotplug state",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(selector, CPUHotplugState),
VMSTATE_UINT8(command, CPUHotplugState),
diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c
new file mode 100644
index 0000000000..c0a23cf467
--- /dev/null
+++ b/hw/acpi/erst.c
@@ -0,0 +1,1051 @@
+/*
+ * ACPI Error Record Serialization Table, ERST, Implementation
+ *
+ * ACPI ERST introduced in ACPI 4.0, June 16, 2009.
+ * ACPI Platform Error Interfaces : Error Serialization
+ *
+ * Copyright (c) 2021 Oracle and/or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/qdev-core.h"
+#include "exec/memory.h"
+#include "qom/object.h"
+#include "hw/pci/pci.h"
+#include "qom/object_interfaces.h"
+#include "qemu/error-report.h"
+#include "migration/vmstate.h"
+#include "hw/qdev-properties.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/acpi-defs.h"
+#include "hw/acpi/aml-build.h"
+#include "hw/acpi/bios-linker-loader.h"
+#include "exec/address-spaces.h"
+#include "sysemu/hostmem.h"
+#include "hw/acpi/erst.h"
+#include "trace.h"
+
+/* ACPI 4.0: Table 17-16 Serialization Actions */
+#define ACTION_BEGIN_WRITE_OPERATION 0x0
+#define ACTION_BEGIN_READ_OPERATION 0x1
+#define ACTION_BEGIN_CLEAR_OPERATION 0x2
+#define ACTION_END_OPERATION 0x3
+#define ACTION_SET_RECORD_OFFSET 0x4
+#define ACTION_EXECUTE_OPERATION 0x5
+#define ACTION_CHECK_BUSY_STATUS 0x6
+#define ACTION_GET_COMMAND_STATUS 0x7
+#define ACTION_GET_RECORD_IDENTIFIER 0x8
+#define ACTION_SET_RECORD_IDENTIFIER 0x9
+#define ACTION_GET_RECORD_COUNT 0xA
+#define ACTION_BEGIN_DUMMY_WRITE_OPERATION 0xB
+#define ACTION_RESERVED 0xC
+#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE 0xD
+#define ACTION_GET_ERROR_LOG_ADDRESS_LENGTH 0xE
+#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0xF
+#define ACTION_GET_EXECUTE_OPERATION_TIMINGS 0x10 /* ACPI 6.3 */
+
+/* ACPI 4.0: Table 17-17 Command Status Definitions */
+#define STATUS_SUCCESS 0x00
+#define STATUS_NOT_ENOUGH_SPACE 0x01
+#define STATUS_HARDWARE_NOT_AVAILABLE 0x02
+#define STATUS_FAILED 0x03
+#define STATUS_RECORD_STORE_EMPTY 0x04
+#define STATUS_RECORD_NOT_FOUND 0x05
+
+/* ACPI 4.0: Table 17-19 Serialization Instructions */
+#define INST_READ_REGISTER 0x00
+#define INST_READ_REGISTER_VALUE 0x01
+#define INST_WRITE_REGISTER 0x02
+#define INST_WRITE_REGISTER_VALUE 0x03
+#define INST_NOOP 0x04
+#define INST_LOAD_VAR1 0x05
+#define INST_LOAD_VAR2 0x06
+#define INST_STORE_VAR1 0x07
+#define INST_ADD 0x08
+#define INST_SUBTRACT 0x09
+#define INST_ADD_VALUE 0x0A
+#define INST_SUBTRACT_VALUE 0x0B
+#define INST_STALL 0x0C
+#define INST_STALL_WHILE_TRUE 0x0D
+#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E
+#define INST_GOTO 0x0F
+#define INST_SET_SRC_ADDRESS_BASE 0x10
+#define INST_SET_DST_ADDRESS_BASE 0x11
+#define INST_MOVE_DATA 0x12
+
+/* UEFI 2.1: Appendix N Common Platform Error Record */
+#define UEFI_CPER_RECORD_MIN_SIZE 128U
+#define UEFI_CPER_RECORD_LENGTH_OFFSET 20U
+#define UEFI_CPER_RECORD_ID_OFFSET 96U
+#define IS_UEFI_CPER_RECORD(ptr) \
+ (((ptr)[0] == 'C') && \
+ ((ptr)[1] == 'P') && \
+ ((ptr)[2] == 'E') && \
+ ((ptr)[3] == 'R'))
+
+/*
+ * NOTE that when accessing CPER fields within a record, memcpy()
+ * is utilized to avoid a possible misaligned access on the host.
+ */
+
+/*
+ * This implementation is an ACTION (cmd) and VALUE (data)
+ * interface consisting of just two 64-bit registers.
+ */
+#define ERST_REG_SIZE (16UL)
+#define ERST_ACTION_OFFSET (0UL) /* action (cmd) */
+#define ERST_VALUE_OFFSET (8UL) /* argument/value (data) */
+
+/*
+ * ERST_RECORD_SIZE is the buffer size for exchanging ERST
+ * record contents. Thus, it defines the maximum record size.
+ * As this is mapped through a PCI BAR, it must be a power of
+ * two and larger than UEFI_CPER_RECORD_MIN_SIZE.
+ * The backing storage is divided into fixed size "slots",
+ * each ERST_RECORD_SIZE in length, and each "slot"
+ * storing a single record. No attempt at optimizing storage
+ * through compression, compaction, etc is attempted.
+ * NOTE that slot 0 is reserved for the backing storage header.
+ * Depending upon the size of the backing storage, additional
+ * slots will be part of the slot 0 header in order to account
+ * for a record_id for each available remaining slot.
+ */
+/* 8KiB records, not too small, not too big */
+#define ERST_RECORD_SIZE (8192UL)
+
+#define ACPI_ERST_MEMDEV_PROP "memdev"
+#define ACPI_ERST_RECORD_SIZE_PROP "record_size"
+
+/*
+ * From the ACPI ERST spec sections:
+ * A record id of all 0s is used to indicate 'unspecified' record id.
+ * A record id of all 1s is used to indicate empty or end.
+ */
+#define ERST_UNSPECIFIED_RECORD_ID (0UL)
+#define ERST_EMPTY_END_RECORD_ID (~0UL)
+
+#define ERST_IS_VALID_RECORD_ID(rid) \
+ ((rid != ERST_UNSPECIFIED_RECORD_ID) && \
+ (rid != ERST_EMPTY_END_RECORD_ID))
+
+/*
+ * Implementation-specific definitions and types.
+ * Values are arbitrary and chosen for this implementation.
+ * See erst.rst documentation for details.
+ */
+#define ERST_EXECUTE_OPERATION_MAGIC 0x9CUL
+#define ERST_STORE_MAGIC 0x524F545354535245UL /* ERSTSTOR */
+typedef struct {
+ uint64_t magic;
+ uint32_t record_size;
+ uint32_t storage_offset; /* offset to record storage beyond header */
+ uint16_t version;
+ uint16_t reserved;
+ uint32_t record_count;
+ uint64_t map[]; /* contains record_ids, and position indicates index */
+} __attribute__((packed)) ERSTStorageHeader;
+
+/*
+ * Object cast macro
+ */
+#define ACPIERST(obj) \
+ OBJECT_CHECK(ERSTDeviceState, (obj), TYPE_ACPI_ERST)
+
+/*
+ * Main ERST device state structure
+ */
+typedef struct {
+ PCIDevice parent_obj;
+
+ /* Backend storage */
+ HostMemoryBackend *hostmem;
+ MemoryRegion *hostmem_mr;
+ uint32_t storage_size;
+ uint32_t default_record_size;
+
+ /* Programming registers */
+ MemoryRegion iomem_mr;
+
+ /* Exchange buffer */
+ MemoryRegion exchange_mr;
+
+ /* Interface state */
+ uint8_t operation;
+ uint8_t busy_status;
+ uint8_t command_status;
+ uint32_t record_offset;
+ uint64_t reg_action;
+ uint64_t reg_value;
+ uint64_t record_identifier;
+ ERSTStorageHeader *header;
+ unsigned first_record_index;
+ unsigned last_record_index;
+ unsigned next_record_index;
+
+} ERSTDeviceState;
+
+/*******************************************************************/
+/*******************************************************************/
+typedef struct {
+ GArray *table_data;
+ pcibus_t bar;
+ uint8_t instruction;
+ uint8_t flags;
+ uint8_t register_bit_width;
+ pcibus_t register_offset;
+} BuildSerializationInstructionEntry;
+
+/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */
+static void build_serialization_instruction(
+ BuildSerializationInstructionEntry *e,
+ uint8_t serialization_action,
+ uint64_t value)
+{
+ /* ACPI 4.0: Table 17-18 Serialization Instruction Entry */
+ struct AcpiGenericAddress gas;
+ uint64_t mask;
+
+ /* Serialization Action */
+ build_append_int_noprefix(e->table_data, serialization_action, 1);
+ /* Instruction */
+ build_append_int_noprefix(e->table_data, e->instruction, 1);
+ /* Flags */
+ build_append_int_noprefix(e->table_data, e->flags, 1);
+ /* Reserved */
+ build_append_int_noprefix(e->table_data, 0, 1);
+ /* Register Region */
+ gas.space_id = AML_SYSTEM_MEMORY;
+ gas.bit_width = e->register_bit_width;
+ gas.bit_offset = 0;
+ gas.access_width = (uint8_t)ctz32(e->register_bit_width) - 2;
+ gas.address = (uint64_t)(e->bar + e->register_offset);
+ build_append_gas_from_struct(e->table_data, &gas);
+ /* Value */
+ build_append_int_noprefix(e->table_data, value, 8);
+ /* Mask */
+ mask = (1ULL << (e->register_bit_width - 1) << 1) - 1;
+ build_append_int_noprefix(e->table_data, mask, 8);
+}
+
+/* ACPI 4.0: 17.4.1 Serialization Action Table */
+void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev,
+ const char *oem_id, const char *oem_table_id)
+{
+ /*
+ * Serialization Action Table
+ * The serialization action table must be generated first
+ * so that its size can be known in order to populate the
+ * Instruction Entry Count field.
+ */
+ unsigned action;
+ GArray *table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char));
+ pcibus_t bar0 = pci_get_bar_addr(PCI_DEVICE(erst_dev), 0);
+ AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id,
+ .oem_table_id = oem_table_id };
+ /* Contexts for the different ways ACTION and VALUE are accessed */
+ BuildSerializationInstructionEntry rd_value_32_val = {
+ .table_data = table_instruction_data, .bar = bar0, .flags = 0,
+ .instruction = INST_READ_REGISTER_VALUE,
+ .register_bit_width = 32,
+ .register_offset = ERST_VALUE_OFFSET,
+ };
+ BuildSerializationInstructionEntry rd_value_32 = {
+ .table_data = table_instruction_data, .bar = bar0, .flags = 0,
+ .instruction = INST_READ_REGISTER,
+ .register_bit_width = 32,
+ .register_offset = ERST_VALUE_OFFSET,
+ };
+ BuildSerializationInstructionEntry rd_value_64 = {
+ .table_data = table_instruction_data, .bar = bar0, .flags = 0,
+ .instruction = INST_READ_REGISTER,
+ .register_bit_width = 64,
+ .register_offset = ERST_VALUE_OFFSET,
+ };
+ BuildSerializationInstructionEntry wr_value_32_val = {
+ .table_data = table_instruction_data, .bar = bar0, .flags = 0,
+ .instruction = INST_WRITE_REGISTER_VALUE,
+ .register_bit_width = 32,
+ .register_offset = ERST_VALUE_OFFSET,
+ };
+ BuildSerializationInstructionEntry wr_value_32 = {
+ .table_data = table_instruction_data, .bar = bar0, .flags = 0,
+ .instruction = INST_WRITE_REGISTER,
+ .register_bit_width = 32,
+ .register_offset = ERST_VALUE_OFFSET,
+ };
+ BuildSerializationInstructionEntry wr_value_64 = {
+ .table_data = table_instruction_data, .bar = bar0, .flags = 0,
+ .instruction = INST_WRITE_REGISTER,
+ .register_bit_width = 64,
+ .register_offset = ERST_VALUE_OFFSET,
+ };
+ BuildSerializationInstructionEntry wr_action = {
+ .table_data = table_instruction_data, .bar = bar0, .flags = 0,
+ .instruction = INST_WRITE_REGISTER_VALUE,
+ .register_bit_width = 32,
+ .register_offset = ERST_ACTION_OFFSET,
+ };
+
+ trace_acpi_erst_pci_bar_0(bar0);
+
+ /* Serialization Instruction Entries */
+ action = ACTION_BEGIN_WRITE_OPERATION;
+ build_serialization_instruction(&wr_action, action, action);
+
+ action = ACTION_BEGIN_READ_OPERATION;
+ build_serialization_instruction(&wr_action, action, action);
+
+ action = ACTION_BEGIN_CLEAR_OPERATION;
+ build_serialization_instruction(&wr_action, action, action);
+
+ action = ACTION_END_OPERATION;
+ build_serialization_instruction(&wr_action, action, action);
+
+ action = ACTION_SET_RECORD_OFFSET;
+ build_serialization_instruction(&wr_value_32, action, 0);
+ build_serialization_instruction(&wr_action, action, action);
+
+ action = ACTION_EXECUTE_OPERATION;
+ build_serialization_instruction(&wr_value_32_val, action,
+ ERST_EXECUTE_OPERATION_MAGIC);
+ build_serialization_instruction(&wr_action, action, action);
+
+ action = ACTION_CHECK_BUSY_STATUS;
+ build_serialization_instruction(&wr_action, action, action);
+ build_serialization_instruction(&rd_value_32_val, action, 0x01);
+
+ action = ACTION_GET_COMMAND_STATUS;
+ build_serialization_instruction(&wr_action, action, action);
+ build_serialization_instruction(&rd_value_32, action, 0);
+
+ action = ACTION_GET_RECORD_IDENTIFIER;
+ build_serialization_instruction(&wr_action, action, action);
+ build_serialization_instruction(&rd_value_64, action, 0);
+
+ action = ACTION_SET_RECORD_IDENTIFIER;
+ build_serialization_instruction(&wr_value_64, action, 0);
+ build_serialization_instruction(&wr_action, action, action);
+
+ action = ACTION_GET_RECORD_COUNT;
+ build_serialization_instruction(&wr_action, action, action);
+ build_serialization_instruction(&rd_value_32, action, 0);
+
+ action = ACTION_BEGIN_DUMMY_WRITE_OPERATION;
+ build_serialization_instruction(&wr_action, action, action);
+
+ action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE;
+ build_serialization_instruction(&wr_action, action, action);
+ build_serialization_instruction(&rd_value_64, action, 0);
+
+ action = ACTION_GET_ERROR_LOG_ADDRESS_LENGTH;
+ build_serialization_instruction(&wr_action, action, action);
+ build_serialization_instruction(&rd_value_64, action, 0);
+
+ action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES;
+ build_serialization_instruction(&wr_action, action, action);
+ build_serialization_instruction(&rd_value_32, action, 0);
+
+ action = ACTION_GET_EXECUTE_OPERATION_TIMINGS;
+ build_serialization_instruction(&wr_action, action, action);
+ build_serialization_instruction(&rd_value_64, action, 0);
+
+ /* Serialization Header */
+ acpi_table_begin(&table, table_data);
+
+ /* Serialization Header Size */
+ build_append_int_noprefix(table_data, 48, 4);
+
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 4);
+
+ /*
+ * Instruction Entry Count
+ * Each instruction entry is 32 bytes
+ */
+ g_assert((table_instruction_data->len) % 32 == 0);
+ build_append_int_noprefix(table_data,
+ (table_instruction_data->len / 32), 4);
+
+ /* Serialization Instruction Entries */
+ g_array_append_vals(table_data, table_instruction_data->data,
+ table_instruction_data->len);
+ g_array_free(table_instruction_data, TRUE);
+
+ acpi_table_end(linker, &table);
+}
+
+/*******************************************************************/
+/*******************************************************************/
+static uint8_t *get_nvram_ptr_by_index(ERSTDeviceState *s, unsigned index)
+{
+ uint8_t *rc = NULL;
+ off_t offset = (index * le32_to_cpu(s->header->record_size));
+
+ g_assert(offset < s->storage_size);
+
+ rc = memory_region_get_ram_ptr(s->hostmem_mr);
+ rc += offset;
+
+ return rc;
+}
+
+static void make_erst_storage_header(ERSTDeviceState *s)
+{
+ ERSTStorageHeader *header = s->header;
+ unsigned mapsz, headersz;
+
+ header->magic = cpu_to_le64(ERST_STORE_MAGIC);
+ header->record_size = cpu_to_le32(s->default_record_size);
+ header->version = cpu_to_le16(0x0100);
+ header->reserved = cpu_to_le16(0x0000);
+
+ /* Compute mapsize */
+ mapsz = s->storage_size / s->default_record_size;
+ mapsz *= sizeof(uint64_t);
+ /* Compute header+map size */
+ headersz = sizeof(ERSTStorageHeader) + mapsz;
+ /* Round up to nearest integer multiple of ERST_RECORD_SIZE */
+ headersz = QEMU_ALIGN_UP(headersz, s->default_record_size);
+ header->storage_offset = cpu_to_le32(headersz);
+
+ /*
+ * The HostMemoryBackend initializes contents to zero,
+ * so all record_ids stashed in the map are zero'd.
+ * As well the record_count is zero. Properly initialized.
+ */
+}
+
+static void check_erst_backend_storage(ERSTDeviceState *s, Error **errp)
+{
+ ERSTStorageHeader *header;
+ uint32_t record_size;
+
+ header = memory_region_get_ram_ptr(s->hostmem_mr);
+ s->header = header;
+
+ /* Ensure pointer to header is 64-bit aligned */
+ g_assert(QEMU_PTR_IS_ALIGNED(header, sizeof(uint64_t)));
+
+ /*
+ * Check if header is uninitialized; HostMemoryBackend inits to 0
+ */
+ if (le64_to_cpu(header->magic) == 0UL) {
+ make_erst_storage_header(s);
+ }
+
+ /* Validity check record_size */
+ record_size = le32_to_cpu(header->record_size);
+ if (!(
+ (record_size) && /* non zero */
+ (record_size >= UEFI_CPER_RECORD_MIN_SIZE) &&
+ (((record_size - 1) & record_size) == 0) && /* is power of 2 */
+ (record_size >= 4096) /* PAGE_SIZE */
+ )) {
+ error_setg(errp, "ERST record_size %u is invalid", record_size);
+ }
+
+ /* Validity check header */
+ if (!(
+ (le64_to_cpu(header->magic) == ERST_STORE_MAGIC) &&
+ ((le32_to_cpu(header->storage_offset) % record_size) == 0) &&
+ (le16_to_cpu(header->version) == 0x0100) &&
+ (le16_to_cpu(header->reserved) == 0)
+ )) {
+ error_setg(errp, "ERST backend storage header is invalid");
+ }
+
+ /* Check storage_size against record_size */
+ if (((s->storage_size % record_size) != 0) ||
+ (record_size > s->storage_size)) {
+ error_setg(errp, "ACPI ERST requires storage size be multiple of "
+ "record size (%uKiB)", record_size);
+ }
+
+ /* Compute offset of first and last record storage slot */
+ s->first_record_index = le32_to_cpu(header->storage_offset)
+ / record_size;
+ s->last_record_index = (s->storage_size / record_size);
+}
+
+static void update_map_entry(ERSTDeviceState *s, unsigned index,
+ uint64_t record_id)
+{
+ if (index < s->last_record_index) {
+ s->header->map[index] = cpu_to_le64(record_id);
+ }
+}
+
+static unsigned find_next_empty_record_index(ERSTDeviceState *s)
+{
+ unsigned rc = 0; /* 0 not a valid index */
+ unsigned index = s->first_record_index;
+
+ for (; index < s->last_record_index; ++index) {
+ if (le64_to_cpu(s->header->map[index]) == ERST_UNSPECIFIED_RECORD_ID) {
+ rc = index;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static unsigned lookup_erst_record(ERSTDeviceState *s,
+ uint64_t record_identifier)
+{
+ unsigned rc = 0; /* 0 not a valid index */
+
+ /* Find the record_identifier in the map */
+ if (record_identifier != ERST_UNSPECIFIED_RECORD_ID) {
+ /*
+ * Count number of valid records encountered, and
+ * short-circuit the loop if identifier not found
+ */
+ uint32_t record_count = le32_to_cpu(s->header->record_count);
+ unsigned count = 0;
+ unsigned index;
+ for (index = s->first_record_index; index < s->last_record_index &&
+ count < record_count; ++index) {
+ if (le64_to_cpu(s->header->map[index]) == record_identifier) {
+ rc = index;
+ break;
+ }
+ if (le64_to_cpu(s->header->map[index]) !=
+ ERST_UNSPECIFIED_RECORD_ID) {
+ ++count;
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * ACPI 4.0: 17.4.1.1 Serialization Actions, also see
+ * ACPI 4.0: 17.4.2.2 Operations - Reading 6.c and 2.c
+ */
+static unsigned get_next_record_identifier(ERSTDeviceState *s,
+ uint64_t *record_identifier, bool first)
+{
+ unsigned found = 0;
+ unsigned index;
+
+ /* For operations needing to return 'first' record identifier */
+ if (first) {
+ /* Reset initial index to beginning */
+ s->next_record_index = s->first_record_index;
+ }
+ index = s->next_record_index;
+
+ *record_identifier = ERST_EMPTY_END_RECORD_ID;
+
+ if (le32_to_cpu(s->header->record_count)) {
+ for (; index < s->last_record_index; ++index) {
+ if (le64_to_cpu(s->header->map[index]) !=
+ ERST_UNSPECIFIED_RECORD_ID) {
+ /* where to start next time */
+ s->next_record_index = index + 1;
+ *record_identifier = le64_to_cpu(s->header->map[index]);
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ /* at end (ie scan complete), reset */
+ s->next_record_index = s->first_record_index;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/* ACPI 4.0: 17.4.2.3 Operations - Clearing */
+static unsigned clear_erst_record(ERSTDeviceState *s)
+{
+ unsigned rc = STATUS_RECORD_NOT_FOUND;
+ unsigned index;
+
+ /* Check for valid record identifier */
+ if (!ERST_IS_VALID_RECORD_ID(s->record_identifier)) {
+ return STATUS_FAILED;
+ }
+
+ index = lookup_erst_record(s, s->record_identifier);
+ if (index) {
+ /* No need to wipe record, just invalidate its map entry */
+ uint32_t record_count;
+ update_map_entry(s, index, ERST_UNSPECIFIED_RECORD_ID);
+ record_count = le32_to_cpu(s->header->record_count);
+ record_count -= 1;
+ s->header->record_count = cpu_to_le32(record_count);
+ rc = STATUS_SUCCESS;
+ }
+
+ return rc;
+}
+
+/* ACPI 4.0: 17.4.2.2 Operations - Reading */
+static unsigned read_erst_record(ERSTDeviceState *s)
+{
+ unsigned rc = STATUS_RECORD_NOT_FOUND;
+ unsigned exchange_length;
+ unsigned index;
+
+ /* Check if backend storage is empty */
+ if (le32_to_cpu(s->header->record_count) == 0) {
+ return STATUS_RECORD_STORE_EMPTY;
+ }
+
+ exchange_length = memory_region_size(&s->exchange_mr);
+
+ /* Check for record identifier of all 0s */
+ if (s->record_identifier == ERST_UNSPECIFIED_RECORD_ID) {
+ /* Set to 'first' record in storage */
+ get_next_record_identifier(s, &s->record_identifier, true);
+ /* record_identifier is now a valid id, or all 1s */
+ }
+
+ /* Check for record identifier of all 1s */
+ if (s->record_identifier == ERST_EMPTY_END_RECORD_ID) {
+ return STATUS_FAILED;
+ }
+
+ /* Validate record_offset */
+ if (s->record_offset > (exchange_length - UEFI_CPER_RECORD_MIN_SIZE)) {
+ return STATUS_FAILED;
+ }
+
+ index = lookup_erst_record(s, s->record_identifier);
+ if (index) {
+ uint8_t *nvram;
+ uint8_t *exchange;
+ uint32_t record_length;
+
+ /* Obtain pointer to the exchange buffer */
+ exchange = memory_region_get_ram_ptr(&s->exchange_mr);
+ exchange += s->record_offset;
+ /* Obtain pointer to slot in storage */
+ nvram = get_nvram_ptr_by_index(s, index);
+ /* Validate CPER record_length */
+ memcpy((uint8_t *)&record_length,
+ &nvram[UEFI_CPER_RECORD_LENGTH_OFFSET],
+ sizeof(uint32_t));
+ record_length = le32_to_cpu(record_length);
+ if (record_length < UEFI_CPER_RECORD_MIN_SIZE) {
+ rc = STATUS_FAILED;
+ }
+ if ((s->record_offset + record_length) > exchange_length) {
+ rc = STATUS_FAILED;
+ }
+ /* If all is ok, copy the record to the exchange buffer */
+ if (rc != STATUS_FAILED) {
+ memcpy(exchange, nvram, record_length);
+ rc = STATUS_SUCCESS;
+ }
+ } else {
+ /*
+ * See "Reading : 'The steps performed by the platform ...' 2.c"
+ * Set to 'first' record in storage
+ */
+ get_next_record_identifier(s, &s->record_identifier, true);
+ }
+
+ return rc;
+}
+
+/* ACPI 4.0: 17.4.2.1 Operations - Writing */
+static unsigned write_erst_record(ERSTDeviceState *s)
+{
+ unsigned rc = STATUS_FAILED;
+ unsigned exchange_length;
+ unsigned index;
+ uint64_t record_identifier;
+ uint32_t record_length;
+ uint8_t *exchange;
+ uint8_t *nvram = NULL;
+ bool record_found = false;
+
+ exchange_length = memory_region_size(&s->exchange_mr);
+
+ /* Validate record_offset */
+ if (s->record_offset > (exchange_length - UEFI_CPER_RECORD_MIN_SIZE)) {
+ return STATUS_FAILED;
+ }
+
+ /* Obtain pointer to record in the exchange buffer */
+ exchange = memory_region_get_ram_ptr(&s->exchange_mr);
+ exchange += s->record_offset;
+
+ /* Validate CPER record_length */
+ memcpy((uint8_t *)&record_length, &exchange[UEFI_CPER_RECORD_LENGTH_OFFSET],
+ sizeof(uint32_t));
+ record_length = le32_to_cpu(record_length);
+ if (record_length < UEFI_CPER_RECORD_MIN_SIZE) {
+ return STATUS_FAILED;
+ }
+ if ((s->record_offset + record_length) > exchange_length) {
+ return STATUS_FAILED;
+ }
+
+ /* Extract record identifier */
+ memcpy((uint8_t *)&record_identifier, &exchange[UEFI_CPER_RECORD_ID_OFFSET],
+ sizeof(uint64_t));
+ record_identifier = le64_to_cpu(record_identifier);
+
+ /* Check for valid record identifier */
+ if (!ERST_IS_VALID_RECORD_ID(record_identifier)) {
+ return STATUS_FAILED;
+ }
+
+ index = lookup_erst_record(s, record_identifier);
+ if (index) {
+ /* Record found, overwrite existing record */
+ nvram = get_nvram_ptr_by_index(s, index);
+ record_found = true;
+ } else {
+ /* Record not found, not an overwrite, allocate for write */
+ index = find_next_empty_record_index(s);
+ if (index) {
+ nvram = get_nvram_ptr_by_index(s, index);
+ } else {
+ /* All slots are occupied */
+ rc = STATUS_NOT_ENOUGH_SPACE;
+ }
+ }
+ if (nvram) {
+ /* Write the record into the slot */
+ memcpy(nvram, exchange, record_length);
+ memset(nvram + record_length, exchange_length - record_length, 0xFF);
+ /* If a new record, increment the record_count */
+ if (!record_found) {
+ uint32_t record_count;
+ record_count = le32_to_cpu(s->header->record_count);
+ record_count += 1; /* writing new record */
+ s->header->record_count = cpu_to_le32(record_count);
+ }
+ update_map_entry(s, index, record_identifier);
+ rc = STATUS_SUCCESS;
+ }
+
+ return rc;
+}
+
+/*******************************************************************/
+
+static uint64_t erst_rd_reg64(hwaddr addr,
+ uint64_t reg, unsigned size)
+{
+ uint64_t rdval;
+ uint64_t mask;
+ unsigned shift;
+
+ if (size == sizeof(uint64_t)) {
+ /* 64b access */
+ mask = 0xFFFFFFFFFFFFFFFFUL;
+ shift = 0;
+ } else {
+ /* 32b access */
+ mask = 0x00000000FFFFFFFFUL;
+ shift = ((addr & 0x4) == 0x4) ? 32 : 0;
+ }
+
+ rdval = reg;
+ rdval >>= shift;
+ rdval &= mask;
+
+ return rdval;
+}
+
+static uint64_t erst_wr_reg64(hwaddr addr,
+ uint64_t reg, uint64_t val, unsigned size)
+{
+ uint64_t wrval;
+ uint64_t mask;
+ unsigned shift;
+
+ if (size == sizeof(uint64_t)) {
+ /* 64b access */
+ mask = 0xFFFFFFFFFFFFFFFFUL;
+ shift = 0;
+ } else {
+ /* 32b access */
+ mask = 0x00000000FFFFFFFFUL;
+ shift = ((addr & 0x4) == 0x4) ? 32 : 0;
+ }
+
+ val &= mask;
+ val <<= shift;
+ mask <<= shift;
+ wrval = reg;
+ wrval &= ~mask;
+ wrval |= val;
+
+ return wrval;
+}
+
+static void erst_reg_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ ERSTDeviceState *s = (ERSTDeviceState *)opaque;
+
+ /*
+ * NOTE: All actions/operations/side effects happen on the WRITE,
+ * by this implementation's design. The READs simply return the
+ * reg_value contents.
+ */
+ trace_acpi_erst_reg_write(addr, val, size);
+
+ switch (addr) {
+ case ERST_VALUE_OFFSET + 0:
+ case ERST_VALUE_OFFSET + 4:
+ s->reg_value = erst_wr_reg64(addr, s->reg_value, val, size);
+ break;
+ case ERST_ACTION_OFFSET + 0:
+ /*
+ * NOTE: all valid values written to this register are of the
+ * ACTION_* variety. Thus there is no need to make this a 64-bit
+ * register, 32-bits is appropriate. As such ERST_ACTION_OFFSET+4
+ * is not needed.
+ */
+ switch (val) {
+ case ACTION_BEGIN_WRITE_OPERATION:
+ case ACTION_BEGIN_READ_OPERATION:
+ case ACTION_BEGIN_CLEAR_OPERATION:
+ case ACTION_BEGIN_DUMMY_WRITE_OPERATION:
+ case ACTION_END_OPERATION:
+ s->operation = val;
+ break;
+ case ACTION_SET_RECORD_OFFSET:
+ s->record_offset = s->reg_value;
+ break;
+ case ACTION_EXECUTE_OPERATION:
+ if ((uint8_t)s->reg_value == ERST_EXECUTE_OPERATION_MAGIC) {
+ s->busy_status = 1;
+ switch (s->operation) {
+ case ACTION_BEGIN_WRITE_OPERATION:
+ s->command_status = write_erst_record(s);
+ break;
+ case ACTION_BEGIN_READ_OPERATION:
+ s->command_status = read_erst_record(s);
+ break;
+ case ACTION_BEGIN_CLEAR_OPERATION:
+ s->command_status = clear_erst_record(s);
+ break;
+ case ACTION_BEGIN_DUMMY_WRITE_OPERATION:
+ s->command_status = STATUS_SUCCESS;
+ break;
+ case ACTION_END_OPERATION:
+ s->command_status = STATUS_SUCCESS;
+ break;
+ default:
+ s->command_status = STATUS_FAILED;
+ break;
+ }
+ s->busy_status = 0;
+ }
+ break;
+ case ACTION_CHECK_BUSY_STATUS:
+ s->reg_value = s->busy_status;
+ break;
+ case ACTION_GET_COMMAND_STATUS:
+ s->reg_value = s->command_status;
+ break;
+ case ACTION_GET_RECORD_IDENTIFIER:
+ s->command_status = get_next_record_identifier(s,
+ &s->reg_value, false);
+ break;
+ case ACTION_SET_RECORD_IDENTIFIER:
+ s->record_identifier = s->reg_value;
+ break;
+ case ACTION_GET_RECORD_COUNT:
+ s->reg_value = le32_to_cpu(s->header->record_count);
+ break;
+ case ACTION_GET_ERROR_LOG_ADDRESS_RANGE:
+ s->reg_value = (hwaddr)pci_get_bar_addr(PCI_DEVICE(s), 1);
+ break;
+ case ACTION_GET_ERROR_LOG_ADDRESS_LENGTH:
+ s->reg_value = le32_to_cpu(s->header->record_size);
+ break;
+ case ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES:
+ s->reg_value = 0x0; /* intentional, not NVRAM mode */
+ break;
+ case ACTION_GET_EXECUTE_OPERATION_TIMINGS:
+ s->reg_value =
+ (100ULL << 32) | /* 100us max time */
+ (10ULL << 0) ; /* 10us min time */
+ break;
+ default:
+ /* Unknown action/command, NOP */
+ break;
+ }
+ break;
+ default:
+ /* This should not happen, but if it does, NOP */
+ break;
+ }
+}
+
+static uint64_t erst_reg_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ ERSTDeviceState *s = (ERSTDeviceState *)opaque;
+ uint64_t val = 0;
+
+ switch (addr) {
+ case ERST_ACTION_OFFSET + 0:
+ case ERST_ACTION_OFFSET + 4:
+ val = erst_rd_reg64(addr, s->reg_action, size);
+ break;
+ case ERST_VALUE_OFFSET + 0:
+ case ERST_VALUE_OFFSET + 4:
+ val = erst_rd_reg64(addr, s->reg_value, size);
+ break;
+ default:
+ break;
+ }
+ trace_acpi_erst_reg_read(addr, val, size);
+ return val;
+}
+
+static const MemoryRegionOps erst_reg_ops = {
+ .read = erst_reg_read,
+ .write = erst_reg_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/*******************************************************************/
+/*******************************************************************/
+static int erst_post_load(void *opaque, int version_id)
+{
+ ERSTDeviceState *s = opaque;
+
+ /* Recompute pointer to header */
+ s->header = (ERSTStorageHeader *)get_nvram_ptr_by_index(s, 0);
+ trace_acpi_erst_post_load(s->header, le32_to_cpu(s->header->record_size));
+
+ return 0;
+}
+
+static const VMStateDescription erst_vmstate = {
+ .name = "acpi-erst",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = erst_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(operation, ERSTDeviceState),
+ VMSTATE_UINT8(busy_status, ERSTDeviceState),
+ VMSTATE_UINT8(command_status, ERSTDeviceState),
+ VMSTATE_UINT32(record_offset, ERSTDeviceState),
+ VMSTATE_UINT64(reg_action, ERSTDeviceState),
+ VMSTATE_UINT64(reg_value, ERSTDeviceState),
+ VMSTATE_UINT64(record_identifier, ERSTDeviceState),
+ VMSTATE_UINT32(next_record_index, ERSTDeviceState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void erst_realizefn(PCIDevice *pci_dev, Error **errp)
+{
+ ERSTDeviceState *s = ACPIERST(pci_dev);
+
+ trace_acpi_erst_realizefn_in();
+
+ if (!s->hostmem) {
+ error_setg(errp, "'" ACPI_ERST_MEMDEV_PROP "' property is not set");
+ return;
+ } else if (host_memory_backend_is_mapped(s->hostmem)) {
+ error_setg(errp, "can't use already busy memdev: %s",
+ object_get_canonical_path_component(OBJECT(s->hostmem)));
+ return;
+ }
+
+ s->hostmem_mr = host_memory_backend_get_memory(s->hostmem);
+
+ /* HostMemoryBackend size will be multiple of PAGE_SIZE */
+ s->storage_size = object_property_get_int(OBJECT(s->hostmem), "size", errp);
+
+ /* Initialize backend storage and record_count */
+ check_erst_backend_storage(s, errp);
+
+ /* BAR 0: Programming registers */
+ memory_region_init_io(&s->iomem_mr, OBJECT(pci_dev), &erst_reg_ops, s,
+ TYPE_ACPI_ERST, ERST_REG_SIZE);
+ pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->iomem_mr);
+
+ /* BAR 1: Exchange buffer memory */
+ memory_region_init_ram(&s->exchange_mr, OBJECT(pci_dev),
+ "erst.exchange",
+ le32_to_cpu(s->header->record_size), errp);
+ pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
+ &s->exchange_mr);
+
+ /* Include the backend storage in the migration stream */
+ vmstate_register_ram_global(s->hostmem_mr);
+
+ trace_acpi_erst_realizefn_out(s->storage_size);
+}
+
+static void erst_reset(DeviceState *dev)
+{
+ ERSTDeviceState *s = ACPIERST(dev);
+
+ trace_acpi_erst_reset_in(le32_to_cpu(s->header->record_count));
+ s->operation = 0;
+ s->busy_status = 0;
+ s->command_status = STATUS_SUCCESS;
+ s->record_identifier = ERST_UNSPECIFIED_RECORD_ID;
+ s->record_offset = 0;
+ s->next_record_index = s->first_record_index;
+ /* NOTE: first/last_record_index are computed only once */
+ trace_acpi_erst_reset_out(le32_to_cpu(s->header->record_count));
+}
+
+static Property erst_properties[] = {
+ DEFINE_PROP_LINK(ACPI_ERST_MEMDEV_PROP, ERSTDeviceState, hostmem,
+ TYPE_MEMORY_BACKEND, HostMemoryBackend *),
+ DEFINE_PROP_UINT32(ACPI_ERST_RECORD_SIZE_PROP, ERSTDeviceState,
+ default_record_size, ERST_RECORD_SIZE),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void erst_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ trace_acpi_erst_class_init_in();
+ k->realize = erst_realizefn;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT;
+ k->device_id = PCI_DEVICE_ID_REDHAT_ACPI_ERST;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_OTHERS;
+ dc->reset = erst_reset;
+ dc->vmsd = &erst_vmstate;
+ dc->user_creatable = true;
+ dc->hotpluggable = false;
+ device_class_set_props(dc, erst_properties);
+ dc->desc = "ACPI Error Record Serialization Table (ERST) device";
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ trace_acpi_erst_class_init_out();
+}
+
+static const TypeInfo erst_type_info = {
+ .name = TYPE_ACPI_ERST,
+ .parent = TYPE_PCI_DEVICE,
+ .class_init = erst_class_init,
+ .instance_size = sizeof(ERSTDeviceState),
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { }
+ }
+};
+
+static void erst_register_types(void)
+{
+ type_register_static(&erst_type_info);
+}
+
+type_init(erst_register_types)
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index ebe08ed831..bd9bbade70 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -163,7 +163,6 @@ static const VMStateDescription vmstate_memhp_state = {
.name = "ich9_pm/memhp",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.needed = vmstate_test_use_memhp,
.fields = (VMStateField[]) {
VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs),
@@ -181,7 +180,6 @@ static const VMStateDescription vmstate_tco_io_state = {
.name = "ich9_pm/tco",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.needed = vmstate_test_use_tco,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts,
@@ -208,7 +206,6 @@ static const VMStateDescription vmstate_cpuhp_state = {
.name = "ich9_pm/cpuhp",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.needed = vmstate_test_use_cpuhp,
.pre_load = vmstate_cpuhp_pre_load,
.fields = (VMStateField[]) {
diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c
index d0fffcf787..a581a2183b 100644
--- a/hw/acpi/memory_hotplug.c
+++ b/hw/acpi/memory_hotplug.c
@@ -318,7 +318,6 @@ static const VMStateDescription vmstate_memhp_sts = {
.name = "memory hotplug device state",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_BOOL(is_enabled, MemStatus),
VMSTATE_BOOL(is_inserting, MemStatus),
@@ -332,7 +331,6 @@ const VMStateDescription vmstate_memory_hotplug = {
.name = "memory hotplug state",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(selector, MemHotplugState),
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(devs, MemHotplugState, dev_count,
diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build
index adf6347bc4..f5b22983bb 100644
--- a/hw/acpi/meson.build
+++ b/hw/acpi/meson.build
@@ -22,6 +22,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c'))
acpi_ss.add(when: 'CONFIG_ACPI_X86_ICH', if_true: files('ich9.c', 'tco.c'))
+acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.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'))
acpi_ss.add(when: 'CONFIG_TPM', if_true: files('tpm.c'))
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index f0b5fac44a..cc37fa3416 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -230,7 +230,6 @@ static const VMStateDescription vmstate_memhp_state = {
.name = "piix4_pm/memhp",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.needed = vmstate_test_use_memhp,
.fields = (VMStateField[]) {
VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, PIIX4PMState),
@@ -255,7 +254,6 @@ static const VMStateDescription vmstate_cpuhp_state = {
.name = "piix4_pm/cpuhp",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.needed = vmstate_test_use_cpuhp,
.pre_load = vmstate_cpuhp_pre_load,
.fields = (VMStateField[]) {
diff --git a/hw/acpi/tco.c b/hw/acpi/tco.c
index cf1e68a539..4783721e4e 100644
--- a/hw/acpi/tco.c
+++ b/hw/acpi/tco.c
@@ -239,7 +239,6 @@ const VMStateDescription vmstate_tco_io_sts = {
.name = "tco io device status",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT16(tco.rld, TCOIORegs),
VMSTATE_UINT8(tco.din, TCOIORegs),
diff --git a/hw/acpi/trace-events b/hw/acpi/trace-events
index 974d770e8b..2250126a22 100644
--- a/hw/acpi/trace-events
+++ b/hw/acpi/trace-events
@@ -55,3 +55,18 @@ piix4_gpe_writeb(uint64_t addr, unsigned width, uint64_t val) "addr: 0x%" PRIx64
# tco.c
tco_timer_reload(int ticks, int msec) "ticks=%d (%d ms)"
tco_timer_expired(int timeouts_no, bool strap, bool no_reboot) "timeouts_no=%d no_reboot=%d/%d"
+
+# erst.c
+acpi_erst_reg_write(uint64_t addr, uint64_t val, unsigned size) "addr: 0x%04" PRIx64 " <== 0x%016" PRIx64 " (size: %u)"
+acpi_erst_reg_read(uint64_t addr, uint64_t val, unsigned size) " addr: 0x%04" PRIx64 " ==> 0x%016" PRIx64 " (size: %u)"
+acpi_erst_mem_write(uint64_t addr, uint64_t val, unsigned size) "addr: 0x%06" PRIx64 " <== 0x%016" PRIx64 " (size: %u)"
+acpi_erst_mem_read(uint64_t addr, uint64_t val, unsigned size) " addr: 0x%06" PRIx64 " ==> 0x%016" PRIx64 " (size: %u)"
+acpi_erst_pci_bar_0(uint64_t addr) "BAR0: 0x%016" PRIx64
+acpi_erst_pci_bar_1(uint64_t addr) "BAR1: 0x%016" PRIx64
+acpi_erst_realizefn_in(void)
+acpi_erst_realizefn_out(unsigned size) "total nvram size %u bytes"
+acpi_erst_reset_in(unsigned record_count) "record_count %u"
+acpi_erst_reset_out(unsigned record_count) "record_count %u"
+acpi_erst_post_load(void *header, unsigned slot_size) "header: 0x%p slot_size %u"
+acpi_erst_class_init_in(void)
+acpi_erst_class_init_out(void)
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index 8d08db80be..ceb76df3cd 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -520,8 +520,8 @@ static const VMStateDescription vmstate_armv7m = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_CLOCK(refclk, SysTickState),
- VMSTATE_CLOCK(cpuclk, SysTickState),
+ VMSTATE_CLOCK(refclk, ARMv7MState),
+ VMSTATE_CLOCK(cpuclk, ARMv7MState),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index 8f37bdb1d8..12f6edc081 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -29,7 +29,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = {
[ASPEED_DEV_PWM] = 0x1E610000,
[ASPEED_DEV_FMC] = 0x1E620000,
[ASPEED_DEV_SPI1] = 0x1E630000,
- [ASPEED_DEV_SPI2] = 0x1E641000,
+ [ASPEED_DEV_SPI2] = 0x1E631000,
[ASPEED_DEV_EHCI1] = 0x1E6A1000,
[ASPEED_DEV_EHCI2] = 0x1E6A3000,
[ASPEED_DEV_MII1] = 0x1E650000,
diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c
index 180d3788f8..9852c2a07e 100644
--- a/hw/arm/omap1.c
+++ b/hw/arm/omap1.c
@@ -21,7 +21,6 @@
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qapi/error.h"
-#include "qemu-common.h"
#include "cpu.h"
#include "exec/address-spaces.h"
#include "hw/hw.h"
@@ -35,6 +34,7 @@
#include "sysemu/qtest.h"
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
+#include "sysemu/rtc.h"
#include "qemu/range.h"
#include "hw/sysbus.h"
#include "qemu/cutils.h"
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 15a247efae..a6f938f115 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -8,7 +8,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qapi/error.h"
@@ -27,6 +26,7 @@
#include "chardev/char-fe.h"
#include "sysemu/blockdev.h"
#include "sysemu/qtest.h"
+#include "sysemu/rtc.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
#include "qom/object.h"
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index 939a57dda5..39b8f01ac4 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -28,7 +28,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "cpu.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
@@ -41,6 +40,7 @@
#include "chardev/char-fe.h"
#include "chardev/char-serial.h"
#include "sysemu/sysemu.h"
+#include "sysemu/rtc.h"
#include "hw/ssi/ssi.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
index 0c5edc898e..3f56ae28ee 100644
--- a/hw/arm/xlnx-versal-virt.c
+++ b/hw/arm/xlnx-versal-virt.c
@@ -25,6 +25,8 @@
#define TYPE_XLNX_VERSAL_VIRT_MACHINE MACHINE_TYPE_NAME("xlnx-versal-virt")
OBJECT_DECLARE_SIMPLE_TYPE(VersalVirt, XLNX_VERSAL_VIRT_MACHINE)
+#define XLNX_VERSAL_NUM_OSPI_FLASH 4
+
struct VersalVirt {
MachineState parent_obj;
@@ -365,7 +367,7 @@ static void fdt_add_bbram_node(VersalVirt *s)
qemu_fdt_add_subnode(s->fdt, name);
qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, VERSAL_BBRAM_APB_IRQ_0,
+ GIC_FDT_IRQ_TYPE_SPI, VERSAL_PMC_APB_IRQ,
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
qemu_fdt_setprop(s->fdt, name, "interrupt-names",
interrupt_names, sizeof(interrupt_names));
@@ -691,6 +693,27 @@ static void versal_virt_init(MachineState *machine)
exit(EXIT_FAILURE);
}
}
+
+ for (i = 0; i < XLNX_VERSAL_NUM_OSPI_FLASH; i++) {
+ BusState *spi_bus;
+ DeviceState *flash_dev;
+ qemu_irq cs_line;
+ DriveInfo *dinfo = drive_get(IF_MTD, 0, i);
+
+ spi_bus = qdev_get_child_bus(DEVICE(&s->soc.pmc.iou.ospi), "spi0");
+
+ flash_dev = qdev_new("mt35xu01g");
+ if (dinfo) {
+ qdev_prop_set_drive_err(flash_dev, "drive",
+ blk_by_legacy_dinfo(dinfo), &error_fatal);
+ }
+ qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal);
+
+ cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.pmc.iou.ospi),
+ i + 1, cs_line);
+ }
}
static void versal_virt_machine_instance_init(Object *obj)
diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c
index b2705b6925..ab58bebfd2 100644
--- a/hw/arm/xlnx-versal.c
+++ b/hw/arm/xlnx-versal.c
@@ -21,10 +21,15 @@
#include "kvm_arm.h"
#include "hw/misc/unimp.h"
#include "hw/arm/xlnx-versal.h"
+#include "qemu/log.h"
+#include "hw/sysbus.h"
#define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72")
#define GEM_REVISION 0x40070106
+#define VERSAL_NUM_PMC_APB_IRQS 3
+#define NUM_OSPI_IRQ_LINES 3
+
static void versal_create_apu_cpus(Versal *s)
{
int i;
@@ -260,6 +265,26 @@ static void versal_create_sds(Versal *s, qemu_irq *pic)
}
}
+static void versal_create_pmc_apb_irq_orgate(Versal *s, qemu_irq *pic)
+{
+ DeviceState *orgate;
+
+ /*
+ * The VERSAL_PMC_APB_IRQ is an 'or' of the interrupts from the following
+ * models:
+ * - RTC
+ * - BBRAM
+ * - PMC SLCR
+ */
+ object_initialize_child(OBJECT(s), "pmc-apb-irq-orgate",
+ &s->pmc.apb_irq_orgate, TYPE_OR_IRQ);
+ orgate = DEVICE(&s->pmc.apb_irq_orgate);
+ object_property_set_int(OBJECT(orgate),
+ "num-lines", VERSAL_NUM_PMC_APB_IRQS, &error_fatal);
+ qdev_realize(orgate, NULL, &error_fatal);
+ qdev_connect_gpio_out(orgate, 0, pic[VERSAL_PMC_APB_IRQ]);
+}
+
static void versal_create_rtc(Versal *s, qemu_irq *pic)
{
SysBusDevice *sbd;
@@ -277,7 +302,8 @@ static void versal_create_rtc(Versal *s, qemu_irq *pic)
* TODO: Connect the ALARM and SECONDS interrupts once our RTC model
* supports them.
*/
- sysbus_connect_irq(sbd, 1, pic[VERSAL_RTC_APB_ERR_IRQ]);
+ sysbus_connect_irq(sbd, 1,
+ qdev_get_gpio_in(DEVICE(&s->pmc.apb_irq_orgate), 0));
}
static void versal_create_xrams(Versal *s, qemu_irq *pic)
@@ -328,7 +354,8 @@ static void versal_create_bbram(Versal *s, qemu_irq *pic)
sysbus_realize(sbd, &error_fatal);
memory_region_add_subregion(&s->mr_ps, MM_PMC_BBRAM_CTRL,
sysbus_mmio_get_region(sbd, 0));
- sysbus_connect_irq(sbd, 0, pic[VERSAL_BBRAM_APB_IRQ_0]);
+ sysbus_connect_irq(sbd, 0,
+ qdev_get_gpio_in(DEVICE(&s->pmc.apb_irq_orgate), 1));
}
static void versal_realize_efuse_part(Versal *s, Object *dev, hwaddr base)
@@ -369,6 +396,114 @@ static void versal_create_efuse(Versal *s, qemu_irq *pic)
sysbus_connect_irq(SYS_BUS_DEVICE(ctrl), 0, pic[VERSAL_EFUSE_IRQ]);
}
+static void versal_create_pmc_iou_slcr(Versal *s, qemu_irq *pic)
+{
+ SysBusDevice *sbd;
+
+ object_initialize_child(OBJECT(s), "versal-pmc-iou-slcr", &s->pmc.iou.slcr,
+ TYPE_XILINX_VERSAL_PMC_IOU_SLCR);
+
+ sbd = SYS_BUS_DEVICE(&s->pmc.iou.slcr);
+ sysbus_realize(sbd, &error_fatal);
+
+ memory_region_add_subregion(&s->mr_ps, MM_PMC_PMC_IOU_SLCR,
+ sysbus_mmio_get_region(sbd, 0));
+
+ sysbus_connect_irq(sbd, 0,
+ qdev_get_gpio_in(DEVICE(&s->pmc.apb_irq_orgate), 2));
+}
+
+static void versal_create_ospi(Versal *s, qemu_irq *pic)
+{
+ SysBusDevice *sbd;
+ MemoryRegion *mr_dac;
+ qemu_irq ospi_mux_sel;
+ DeviceState *orgate;
+
+ memory_region_init(&s->pmc.iou.ospi.linear_mr, OBJECT(s),
+ "versal-ospi-linear-mr" , MM_PMC_OSPI_DAC_SIZE);
+
+ object_initialize_child(OBJECT(s), "versal-ospi", &s->pmc.iou.ospi.ospi,
+ TYPE_XILINX_VERSAL_OSPI);
+
+ mr_dac = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->pmc.iou.ospi.ospi), 1);
+ memory_region_add_subregion(&s->pmc.iou.ospi.linear_mr, 0x0, mr_dac);
+
+ /* Create the OSPI destination DMA */
+ object_initialize_child(OBJECT(s), "versal-ospi-dma-dst",
+ &s->pmc.iou.ospi.dma_dst,
+ TYPE_XLNX_CSU_DMA);
+
+ object_property_set_link(OBJECT(&s->pmc.iou.ospi.dma_dst),
+ "dma", OBJECT(get_system_memory()),
+ &error_abort);
+
+ sbd = SYS_BUS_DEVICE(&s->pmc.iou.ospi.dma_dst);
+ sysbus_realize(sbd, &error_fatal);
+
+ memory_region_add_subregion(&s->mr_ps, MM_PMC_OSPI_DMA_DST,
+ sysbus_mmio_get_region(sbd, 0));
+
+ /* Create the OSPI source DMA */
+ object_initialize_child(OBJECT(s), "versal-ospi-dma-src",
+ &s->pmc.iou.ospi.dma_src,
+ TYPE_XLNX_CSU_DMA);
+
+ object_property_set_bool(OBJECT(&s->pmc.iou.ospi.dma_src), "is-dst",
+ false, &error_abort);
+
+ object_property_set_link(OBJECT(&s->pmc.iou.ospi.dma_src),
+ "dma", OBJECT(mr_dac), &error_abort);
+
+ object_property_set_link(OBJECT(&s->pmc.iou.ospi.dma_src),
+ "stream-connected-dma",
+ OBJECT(&s->pmc.iou.ospi.dma_dst),
+ &error_abort);
+
+ sbd = SYS_BUS_DEVICE(&s->pmc.iou.ospi.dma_src);
+ sysbus_realize(sbd, &error_fatal);
+
+ memory_region_add_subregion(&s->mr_ps, MM_PMC_OSPI_DMA_SRC,
+ sysbus_mmio_get_region(sbd, 0));
+
+ /* Realize the OSPI */
+ object_property_set_link(OBJECT(&s->pmc.iou.ospi.ospi), "dma-src",
+ OBJECT(&s->pmc.iou.ospi.dma_src), &error_abort);
+
+ sbd = SYS_BUS_DEVICE(&s->pmc.iou.ospi.ospi);
+ sysbus_realize(sbd, &error_fatal);
+
+ memory_region_add_subregion(&s->mr_ps, MM_PMC_OSPI,
+ sysbus_mmio_get_region(sbd, 0));
+
+ memory_region_add_subregion(&s->mr_ps, MM_PMC_OSPI_DAC,
+ &s->pmc.iou.ospi.linear_mr);
+
+ /* ospi_mux_sel */
+ ospi_mux_sel = qdev_get_gpio_in_named(DEVICE(&s->pmc.iou.ospi.ospi),
+ "ospi-mux-sel", 0);
+ qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr), "ospi-mux-sel", 0,
+ ospi_mux_sel);
+
+ /* OSPI irq */
+ object_initialize_child(OBJECT(s), "ospi-irq-orgate",
+ &s->pmc.iou.ospi.irq_orgate, TYPE_OR_IRQ);
+ object_property_set_int(OBJECT(&s->pmc.iou.ospi.irq_orgate),
+ "num-lines", NUM_OSPI_IRQ_LINES, &error_fatal);
+
+ orgate = DEVICE(&s->pmc.iou.ospi.irq_orgate);
+ qdev_realize(orgate, NULL, &error_fatal);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pmc.iou.ospi.ospi), 0,
+ qdev_get_gpio_in(orgate, 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pmc.iou.ospi.dma_src), 0,
+ qdev_get_gpio_in(orgate, 1));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pmc.iou.ospi.dma_dst), 0,
+ qdev_get_gpio_in(orgate, 2));
+
+ qdev_connect_gpio_out(orgate, 0, pic[VERSAL_OSPI_IRQ]);
+}
+
/* This takes the board allocated linear DDR memory and creates aliases
* for each split DDR range/aperture on the Versal address map.
*/
@@ -425,8 +560,31 @@ static void versal_unimp_area(Versal *s, const char *name,
memory_region_add_subregion(mr, base, mr_dev);
}
+static void versal_unimp_sd_emmc_sel(void *opaque, int n, int level)
+{
+ qemu_log_mask(LOG_UNIMP,
+ "Selecting between enabling SD mode or eMMC mode on "
+ "controller %d is not yet implemented\n", n);
+}
+
+static void versal_unimp_qspi_ospi_mux_sel(void *opaque, int n, int level)
+{
+ qemu_log_mask(LOG_UNIMP,
+ "Selecting between enabling the QSPI or OSPI linear address "
+ "region is not yet implemented\n");
+}
+
+static void versal_unimp_irq_parity_imr(void *opaque, int n, int level)
+{
+ qemu_log_mask(LOG_UNIMP,
+ "PMC SLCR parity interrupt behaviour "
+ "is not yet implemented\n");
+}
+
static void versal_unimp(Versal *s)
{
+ qemu_irq gpio_in;
+
versal_unimp_area(s, "psm", &s->mr_ps,
MM_PSM_START, MM_PSM_END - MM_PSM_START);
versal_unimp_area(s, "crl", &s->mr_ps,
@@ -441,6 +599,31 @@ static void versal_unimp(Versal *s)
MM_IOU_SCNTR, MM_IOU_SCNTR_SIZE);
versal_unimp_area(s, "iou-scntr-seucre", &s->mr_ps,
MM_IOU_SCNTRS, MM_IOU_SCNTRS_SIZE);
+
+ qdev_init_gpio_in_named(DEVICE(s), versal_unimp_sd_emmc_sel,
+ "sd-emmc-sel-dummy", 2);
+ qdev_init_gpio_in_named(DEVICE(s), versal_unimp_qspi_ospi_mux_sel,
+ "qspi-ospi-mux-sel-dummy", 1);
+ qdev_init_gpio_in_named(DEVICE(s), versal_unimp_irq_parity_imr,
+ "irq-parity-imr-dummy", 1);
+
+ gpio_in = qdev_get_gpio_in_named(DEVICE(s), "sd-emmc-sel-dummy", 0);
+ qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr), "sd-emmc-sel", 0,
+ gpio_in);
+
+ gpio_in = qdev_get_gpio_in_named(DEVICE(s), "sd-emmc-sel-dummy", 1);
+ qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr), "sd-emmc-sel", 1,
+ gpio_in);
+
+ gpio_in = qdev_get_gpio_in_named(DEVICE(s), "qspi-ospi-mux-sel-dummy", 0);
+ qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr),
+ "qspi-ospi-mux-sel", 0,
+ gpio_in);
+
+ gpio_in = qdev_get_gpio_in_named(DEVICE(s), "irq-parity-imr-dummy", 0);
+ qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr),
+ SYSBUS_DEVICE_GPIO_IRQ, 0,
+ gpio_in);
}
static void versal_realize(DeviceState *dev, Error **errp)
@@ -455,10 +638,13 @@ static void versal_realize(DeviceState *dev, Error **errp)
versal_create_gems(s, pic);
versal_create_admas(s, pic);
versal_create_sds(s, pic);
+ versal_create_pmc_apb_irq_orgate(s, pic);
versal_create_rtc(s, pic);
versal_create_xrams(s, pic);
versal_create_bbram(s, pic);
versal_create_efuse(s, pic);
+ versal_create_pmc_iou_slcr(s, pic);
+ versal_create_ospi(s, pic);
versal_map_ddr(s);
versal_unimp(s);
diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c
index b056c05387..dfc7ebca4e 100644
--- a/hw/audio/pcspk.c
+++ b/hw/audio/pcspk.c
@@ -209,7 +209,6 @@ static const VMStateDescription vmstate_spk = {
.name = "pcspk",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.needed = migrate_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(data_on, PCSpkState),
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index b77503dc84..c6bf3c6bfa 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -255,6 +255,8 @@ static const FlashPartInfo known_devices[] = {
{ INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
{ INFO("n25q512ax3", 0x20ba20, 0x1000, 64 << 10, 1024, ER_4K) },
{ INFO("mt25ql512ab", 0x20ba20, 0x1044, 64 << 10, 1024, ER_4K | ER_32K) },
+ { INFO_STACKED("mt35xu01g", 0x2c5b1b, 0x104100, 128 << 10, 1024,
+ ER_4K | ER_32K, 2) },
{ INFO_STACKED("n25q00", 0x20ba21, 0x1000, 64 << 10, 2048, ER_4K, 4) },
{ INFO_STACKED("n25q00a", 0x20bb21, 0x1000, 64 << 10, 2048, ER_4K, 4) },
{ INFO_STACKED("mt25ql01g", 0x20ba21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 80d401a379..addcd59b02 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -628,7 +628,6 @@ static const VMStateDescription vmstate_exynos4210_uart_fifo = {
.name = "exynos4210.uart.fifo",
.version_id = 1,
.minimum_version_id = 1,
- .post_load = exynos4210_uart_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT32(sp, Exynos4210UartFIFO),
VMSTATE_UINT32(rp, Exynos4210UartFIFO),
@@ -641,6 +640,7 @@ static const VMStateDescription vmstate_exynos4210_uart = {
.name = "exynos4210.uart",
.version_id = 1,
.minimum_version_id = 1,
+ .post_load = exynos4210_uart_post_load,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(rx, Exynos4210UartState, 1,
vmstate_exynos4210_uart_fifo, Exynos4210UartFIFO),
diff --git a/hw/display/artist.c b/hw/display/artist.c
index 21b7fd1b44..1d877998b9 100644
--- a/hw/display/artist.c
+++ b/hw/display/artist.c
@@ -80,6 +80,7 @@ struct ARTISTState {
uint32_t line_pattern_skip;
uint32_t cursor_pos;
+ uint32_t cursor_cntrl;
uint32_t cursor_height;
uint32_t cursor_width;
@@ -91,7 +92,6 @@ struct ARTISTState {
uint32_t reg_300208;
uint32_t reg_300218;
- uint32_t cmap_bm_access;
uint32_t dst_bm_access;
uint32_t src_bm_access;
uint32_t control_plane;
@@ -134,7 +134,7 @@ typedef enum {
PATTERN_LINE_START = 0x100ecc,
LINE_SIZE = 0x100e04,
LINE_END = 0x100e44,
- CMAP_BM_ACCESS = 0x118000,
+ DST_SRC_BM_ACCESS = 0x118000,
DST_BM_ACCESS = 0x118004,
SRC_BM_ACCESS = 0x118008,
CONTROL_PLANE = 0x11800c,
@@ -176,7 +176,7 @@ static const char *artist_reg_name(uint64_t addr)
REG_NAME(TRANSFER_DATA);
REG_NAME(CONTROL_PLANE);
REG_NAME(IMAGE_BITMAP_OP);
- REG_NAME(CMAP_BM_ACCESS);
+ REG_NAME(DST_SRC_BM_ACCESS);
REG_NAME(DST_BM_ACCESS);
REG_NAME(SRC_BM_ACCESS);
REG_NAME(CURSOR_POS);
@@ -222,40 +222,14 @@ static void artist_invalidate_lines(struct vram_buffer *buf,
}
}
-static int vram_write_pix_per_transfer(ARTISTState *s)
-{
- if (s->cmap_bm_access) {
- return 1 << ((s->cmap_bm_access >> 27) & 0x0f);
- } else {
- return 1 << ((s->dst_bm_access >> 27) & 0x0f);
- }
-}
-
-static int vram_pixel_length(ARTISTState *s)
-{
- if (s->cmap_bm_access) {
- return (s->cmap_bm_access >> 24) & 0x07;
- } else {
- return (s->dst_bm_access >> 24) & 0x07;
- }
-}
-
static int vram_write_bufidx(ARTISTState *s)
{
- if (s->cmap_bm_access) {
- return (s->cmap_bm_access >> 12) & 0x0f;
- } else {
- return (s->dst_bm_access >> 12) & 0x0f;
- }
+ return (s->dst_bm_access >> 12) & 0x0f;
}
static int vram_read_bufidx(ARTISTState *s)
{
- if (s->cmap_bm_access) {
- return (s->cmap_bm_access >> 12) & 0x0f;
- } else {
- return (s->src_bm_access >> 12) & 0x0f;
- }
+ return (s->src_bm_access >> 12) & 0x0f;
}
static struct vram_buffer *vram_read_buffer(ARTISTState *s)
@@ -328,19 +302,42 @@ static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y)
{
/*
* Don't know whether these magic offset values are configurable via
- * some register. They are the same for all resolutions, so don't
- * bother about it.
+ * some register. They seem to be the same for all resolutions.
+ * The cursor values provided in the registers are:
+ * X-value: -295 (for HP-UX 11) and 338 (for HP-UX 10.20) up to 2265
+ * Y-value: 1146 down to 0
+ * The emulated Artist graphic is like a CRX graphic, and as such
+ * it's usually fixed at 1280x1024 pixels.
+ * Because of the maximum Y-value of 1146 you can not choose a higher
+ * vertical resolution on HP-UX (unless you disable the mouse).
*/
- *y = 0x47a - artist_get_y(s->cursor_pos);
- *x = ((artist_get_x(s->cursor_pos) - 338) / 2);
+ static int offset = 338;
+ int lx;
+
+ /* ignore if uninitialized */
+ if (s->cursor_pos == 0) {
+ *x = *y = 0;
+ return;
+ }
+
+ lx = artist_get_x(s->cursor_pos);
+ if (lx < offset)
+ offset = lx;
+ *x = (lx - offset) / 2;
+
+ *y = 1146 - artist_get_y(s->cursor_pos);
+
+ /* subtract cursor offset from cursor control register */
+ *x -= (s->cursor_cntrl & 0xf0) >> 4;
+ *y -= (s->cursor_cntrl & 0x0f);
if (*x > s->width) {
- *x = 0;
+ *x = s->width;
}
if (*y > s->height) {
- *y = 0;
+ *y = s->height;
}
}
@@ -352,130 +349,6 @@ static void artist_invalidate_cursor(ARTISTState *s)
y, s->cursor_height);
}
-static void vram_bit_write(ARTISTState *s, int posy, bool incr_x,
- int size, uint32_t data)
-{
- struct vram_buffer *buf;
- uint32_t vram_bitmask = s->vram_bitmask;
- int mask, i, pix_count, pix_length;
- unsigned int posx, offset, width;
- uint8_t *data8, *p;
-
- pix_count = vram_write_pix_per_transfer(s);
- pix_length = vram_pixel_length(s);
-
- buf = vram_write_buffer(s);
- width = buf->width;
-
- if (s->cmap_bm_access) {
- offset = s->vram_pos;
- } else {
- posx = ADDR_TO_X(s->vram_pos >> 2);
- posy += ADDR_TO_Y(s->vram_pos >> 2);
- offset = posy * width + posx;
- }
-
- if (!buf->size || offset >= buf->size) {
- return;
- }
-
- p = buf->data;
-
- if (pix_count > size * 8) {
- pix_count = size * 8;
- }
-
- switch (pix_length) {
- case 0:
- if (s->image_bitmap_op & 0x20000000) {
- data &= vram_bitmask;
- }
-
- for (i = 0; i < pix_count; i++) {
- uint32_t off = offset + pix_count - 1 - i;
- if (off < buf->size) {
- artist_rop8(s, buf, off,
- (data & 1) ? (s->plane_mask >> 24) : 0);
- }
- data >>= 1;
- }
- memory_region_set_dirty(&buf->mr, offset, pix_count);
- break;
-
- case 3:
- if (s->cmap_bm_access) {
- if (offset + 3 < buf->size) {
- *(uint32_t *)(p + offset) = data;
- }
- break;
- }
- data8 = (uint8_t *)&data;
-
- for (i = 3; i >= 0; i--) {
- if (!(s->image_bitmap_op & 0x20000000) ||
- s->vram_bitmask & (1 << (28 + i))) {
- uint32_t off = offset + 3 - i;
- if (off < buf->size) {
- artist_rop8(s, buf, off, data8[ROP8OFF(i)]);
- }
- }
- }
- memory_region_set_dirty(&buf->mr, offset, 3);
- break;
-
- case 6:
- switch (size) {
- default:
- case 4:
- vram_bitmask = s->vram_bitmask;
- break;
-
- case 2:
- vram_bitmask = s->vram_bitmask >> 16;
- break;
-
- case 1:
- vram_bitmask = s->vram_bitmask >> 24;
- break;
- }
-
- for (i = 0; i < pix_count && offset + i < buf->size; i++) {
- mask = 1 << (pix_count - 1 - i);
-
- if (!(s->image_bitmap_op & 0x20000000) ||
- (vram_bitmask & mask)) {
- if (data & mask) {
- artist_rop8(s, buf, offset + i, s->fg_color);
- } else {
- if (!(s->image_bitmap_op & 0x10000002)) {
- artist_rop8(s, buf, offset + i, s->bg_color);
- }
- }
- }
- }
- memory_region_set_dirty(&buf->mr, offset, pix_count);
- break;
-
- default:
- qemu_log_mask(LOG_UNIMP, "%s: unknown pixel length %d\n",
- __func__, pix_length);
- break;
- }
-
- if (incr_x) {
- if (s->cmap_bm_access) {
- s->vram_pos += 4;
- } else {
- s->vram_pos += pix_count << 2;
- }
- }
-
- if (vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR1 ||
- vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR2) {
- artist_invalidate_cursor(s);
- }
-}
-
static void block_move(ARTISTState *s,
unsigned int source_x, unsigned int source_y,
unsigned int dest_x, unsigned int dest_y,
@@ -680,10 +553,11 @@ static void draw_line(ARTISTState *s,
}
x++;
} while (x <= x2 && (max_pix == -1 || --max_pix > 0));
+
if (c1)
- artist_invalidate_lines(buf, x, dy+1);
+ artist_invalidate_lines(buf, x1, x2 - x1);
else
- artist_invalidate_lines(buf, y, dx+1);
+ artist_invalidate_lines(buf, y1 > y2 ? y2 : y1, x2 - x1);
}
static void draw_line_pattern_start(ARTISTState *s)
@@ -860,6 +734,151 @@ static void combine_write_reg(hwaddr addr, uint64_t val, int size, void *out)
}
}
+static void artist_vram_write4(ARTISTState *s, struct vram_buffer *buf,
+ uint32_t offset, uint32_t data)
+{
+ int i;
+ int mask = s->vram_bitmask >> 28;
+
+ for (i = 0; i < 4; i++) {
+ if (!(s->image_bitmap_op & 0x20000000) || (mask & 8)) {
+ artist_rop8(s, buf, offset + i, data >> 24);
+ data <<= 8;
+ mask <<= 1;
+ }
+ }
+ memory_region_set_dirty(&buf->mr, offset, 3);
+}
+
+static void artist_vram_write32(ARTISTState *s, struct vram_buffer *buf,
+ uint32_t offset, int size, uint32_t data,
+ int fg, int bg)
+{
+ uint32_t mask, vram_bitmask = s->vram_bitmask >> ((4 - size) * 8);
+ int i, pix_count = size * 8;
+
+ for (i = 0; i < pix_count && offset + i < buf->size; i++) {
+ mask = 1 << (pix_count - 1 - i);
+
+ if (!(s->image_bitmap_op & 0x20000000) || (vram_bitmask & mask)) {
+ if (data & mask) {
+ artist_rop8(s, buf, offset + i, fg);
+ } else {
+ if (!(s->image_bitmap_op & 0x10000002)) {
+ artist_rop8(s, buf, offset + i, bg);
+ }
+ }
+ }
+ }
+ memory_region_set_dirty(&buf->mr, offset, pix_count);
+}
+
+static int get_vram_offset(ARTISTState *s, struct vram_buffer *buf,
+ int pos, int posy)
+{
+ unsigned int posx, width;
+
+ width = buf->width;
+ posx = ADDR_TO_X(pos);
+ posy += ADDR_TO_Y(pos);
+ return posy * width + posx;
+}
+
+static int vram_bit_write(ARTISTState *s, uint32_t pos, int posy,
+ uint32_t data, int size)
+{
+ struct vram_buffer *buf = vram_write_buffer(s);
+
+ switch (s->dst_bm_access >> 16) {
+ case 0x3ba0:
+ case 0xbbe0:
+ artist_vram_write4(s, buf, pos, bswap32(data));
+ pos += 4;
+ break;
+
+ case 0x1360: /* linux */
+ artist_vram_write4(s, buf, get_vram_offset(s, buf, pos, posy), data);
+ pos += 4;
+ break;
+
+ case 0x13a0:
+ artist_vram_write4(s, buf, get_vram_offset(s, buf, pos >> 2, posy),
+ data);
+ pos += 16;
+ break;
+
+ case 0x2ea0:
+ artist_vram_write32(s, buf, get_vram_offset(s, buf, pos >> 2, posy),
+ size, data, s->fg_color, s->bg_color);
+ pos += 4;
+ break;
+
+ case 0x28a0:
+ artist_vram_write32(s, buf, get_vram_offset(s, buf, pos >> 2, posy),
+ size, data, 1, 0);
+ pos += 4;
+ break;
+
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unknown dst bm access %08x\n",
+ __func__, s->dst_bm_access);
+ break;
+ }
+
+ if (vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR1 ||
+ vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR2) {
+ artist_invalidate_cursor(s);
+ }
+ return pos;
+}
+
+static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ ARTISTState *s = opaque;
+ s->vram_char_y = 0;
+ trace_artist_vram_write(size, addr, val);
+ vram_bit_write(opaque, addr, 0, val, size);
+}
+
+static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size)
+{
+ ARTISTState *s = opaque;
+ struct vram_buffer *buf;
+ unsigned int offset;
+ uint64_t val;
+
+ buf = vram_read_buffer(s);
+ if (!buf->size) {
+ return 0;
+ }
+
+ offset = get_vram_offset(s, buf, addr >> 2, 0);
+
+ if (offset > buf->size) {
+ return 0;
+ }
+
+ switch (s->src_bm_access >> 16) {
+ case 0x3ba0:
+ val = *(uint32_t *)(buf->data + offset);
+ break;
+
+ case 0x13a0:
+ case 0x2ea0:
+ val = bswap32(*(uint32_t *)(buf->data + offset));
+ break;
+
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unknown src bm access %08x\n",
+ __func__, s->dst_bm_access);
+ val = -1ULL;
+ break;
+ }
+ trace_artist_vram_read(size, addr, val);
+ return val;
+}
+
static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
@@ -886,12 +905,12 @@ static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val,
break;
case VRAM_WRITE_INCR_Y:
- vram_bit_write(s, s->vram_char_y++, false, size, val);
+ vram_bit_write(s, s->vram_pos, s->vram_char_y++, val, size);
break;
case VRAM_WRITE_INCR_X:
case VRAM_WRITE_INCR_X2:
- vram_bit_write(s, s->vram_char_y, true, size, val);
+ s->vram_pos = vram_bit_write(s, s->vram_pos, s->vram_char_y, val, size);
break;
case VRAM_IDX:
@@ -993,18 +1012,17 @@ static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val,
combine_write_reg(addr, val, size, &s->plane_mask);
break;
- case CMAP_BM_ACCESS:
- combine_write_reg(addr, val, size, &s->cmap_bm_access);
+ case DST_SRC_BM_ACCESS:
+ combine_write_reg(addr, val, size, &s->dst_bm_access);
+ combine_write_reg(addr, val, size, &s->src_bm_access);
break;
case DST_BM_ACCESS:
combine_write_reg(addr, val, size, &s->dst_bm_access);
- s->cmap_bm_access = 0;
break;
case SRC_BM_ACCESS:
combine_write_reg(addr, val, size, &s->src_bm_access);
- s->cmap_bm_access = 0;
break;
case CONTROL_PLANE:
@@ -1034,6 +1052,7 @@ static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val,
break;
case CURSOR_CTRL:
+ combine_write_reg(addr, val, size, &s->cursor_cntrl);
break;
case IMAGE_BITMAP_OP:
@@ -1152,98 +1171,6 @@ static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size)
return val;
}
-static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- ARTISTState *s = opaque;
- struct vram_buffer *buf;
- unsigned int posy, posx;
- unsigned int offset;
- trace_artist_vram_write(size, addr, val);
-
- if (s->cmap_bm_access) {
- buf = &s->vram_buffer[ARTIST_BUFFER_CMAP];
- if (addr + 3 < buf->size) {
- *(uint32_t *)(buf->data + addr) = val;
- }
- return;
- }
-
- buf = vram_write_buffer(s);
- posy = ADDR_TO_Y(addr >> 2);
- posx = ADDR_TO_X(addr >> 2);
-
- if (!buf->size) {
- return;
- }
-
- if (posy > buf->height || posx > buf->width) {
- return;
- }
-
- offset = posy * buf->width + posx;
- if (offset >= buf->size) {
- return;
- }
-
- switch (size) {
- case 4:
- if (offset + 3 < buf->size) {
- *(uint32_t *)(buf->data + offset) = be32_to_cpu(val);
- memory_region_set_dirty(&buf->mr, offset, 4);
- }
- break;
- case 2:
- if (offset + 1 < buf->size) {
- *(uint16_t *)(buf->data + offset) = be16_to_cpu(val);
- memory_region_set_dirty(&buf->mr, offset, 2);
- }
- break;
- case 1:
- if (offset < buf->size) {
- *(uint8_t *)(buf->data + offset) = val;
- memory_region_set_dirty(&buf->mr, offset, 1);
- }
- break;
- default:
- break;
- }
-}
-
-static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size)
-{
- ARTISTState *s = opaque;
- struct vram_buffer *buf;
- uint64_t val;
- unsigned int posy, posx;
-
- if (s->cmap_bm_access) {
- buf = &s->vram_buffer[ARTIST_BUFFER_CMAP];
- val = 0;
- if (addr < buf->size && addr + 3 < buf->size) {
- val = *(uint32_t *)(buf->data + addr);
- }
- trace_artist_vram_read(size, addr, 0, 0, val);
- return val;
- }
-
- buf = vram_read_buffer(s);
- if (!buf->size) {
- return 0;
- }
-
- posy = ADDR_TO_Y(addr >> 2);
- posx = ADDR_TO_X(addr >> 2);
-
- if (posy > buf->height || posx > buf->width) {
- return 0;
- }
-
- val = cpu_to_be32(*(uint32_t *)(buf->data + posy * buf->width + posx));
- trace_artist_vram_read(size, addr, posx, posy, val);
- return val;
-}
-
static const MemoryRegionOps artist_reg_ops = {
.read = artist_reg_read,
.write = artist_reg_write,
@@ -1410,6 +1337,14 @@ static void artist_realizefn(DeviceState *dev, Error **errp)
s->cursor_height = 32;
s->cursor_width = 32;
+ /*
+ * These two registers are not initialized by seabios's STI implementation.
+ * Initialize them here to sane values so artist also works with older
+ * (not-fixed) seabios versions.
+ */
+ s->image_bitmap_op = 0x23000300;
+ s->plane_mask = 0xff;
+
s->con = graphic_console_init(dev, 0, &artist_ops, s);
qemu_console_resize(s->con, s->width, s->height);
}
@@ -1422,8 +1357,8 @@ static int vmstate_artist_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_artist = {
.name = "artist",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.post_load = vmstate_artist_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT16(height, ARTISTState),
@@ -1443,6 +1378,7 @@ static const VMStateDescription vmstate_artist = {
VMSTATE_UINT32(line_end, ARTISTState),
VMSTATE_UINT32(line_xy, ARTISTState),
VMSTATE_UINT32(cursor_pos, ARTISTState),
+ VMSTATE_UINT32(cursor_cntrl, ARTISTState),
VMSTATE_UINT32(cursor_height, ARTISTState),
VMSTATE_UINT32(cursor_width, ARTISTState),
VMSTATE_UINT32(plane_mask, ARTISTState),
@@ -1450,7 +1386,6 @@ static const VMStateDescription vmstate_artist = {
VMSTATE_UINT32(reg_300200, ARTISTState),
VMSTATE_UINT32(reg_300208, ARTISTState),
VMSTATE_UINT32(reg_300218, ARTISTState),
- VMSTATE_UINT32(cmap_bm_access, ARTISTState),
VMSTATE_UINT32(dst_bm_access, ARTISTState),
VMSTATE_UINT32(src_bm_access, ARTISTState),
VMSTATE_UINT32(control_plane, ARTISTState),
diff --git a/hw/display/macfb.c b/hw/display/macfb.c
index 4bd7c3ad6a..2eeb80cc3f 100644
--- a/hw/display/macfb.c
+++ b/hw/display/macfb.c
@@ -616,7 +616,6 @@ static const VMStateDescription vmstate_macfb = {
.name = "macfb",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.post_load = macfb_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT8_ARRAY(color_palette, MacfbState, 256 * 3),
diff --git a/hw/display/trace-events b/hw/display/trace-events
index 3a7a2c957f..4a687d1b8e 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -140,10 +140,10 @@ ati_mm_read(unsigned int size, uint64_t addr, const char *name, uint64_t val) "%
ati_mm_write(unsigned int size, uint64_t addr, const char *name, uint64_t val) "%u 0x%"PRIx64 " %s <- 0x%"PRIx64
# artist.c
-artist_reg_read(unsigned int size, uint64_t addr, const char *name, uint64_t val) "%u 0x%"PRIx64 "%s -> 0x%"PRIx64
-artist_reg_write(unsigned int size, uint64_t addr, const char *name, uint64_t val) "%u 0x%"PRIx64 "%s <- 0x%"PRIx64
-artist_vram_read(unsigned int size, uint64_t addr, int posx, int posy, uint64_t val) "%u 0x%"PRIx64 " %ux%u-> 0x%"PRIx64
-artist_vram_write(unsigned int size, uint64_t addr, uint64_t val) "%u 0x%"PRIx64 " <- 0x%"PRIx64
+artist_reg_read(unsigned int size, uint64_t addr, const char *name, uint64_t val) "%u 0x%"PRIx64 "%s -> 0x%08"PRIx64
+artist_reg_write(unsigned int size, uint64_t addr, const char *name, uint64_t val) "%u 0x%"PRIx64 "%s <- 0x%08"PRIx64
+artist_vram_read(unsigned int size, uint64_t addr, uint64_t val) "%u 0x%08"PRIx64 " -> 0x%08"PRIx64
+artist_vram_write(unsigned int size, uint64_t addr, uint64_t val) "%u 0x%08"PRIx64 " <- 0x%08"PRIx64
artist_fill_window(unsigned int start_x, unsigned int start_y, unsigned int width, unsigned int height, uint32_t op, uint32_t ctlpln) "start=%ux%u length=%ux%u op=0x%08x ctlpln=0x%08x"
artist_block_move(unsigned int start_x, unsigned int start_y, unsigned int dest_x, unsigned int dest_y, unsigned int width, unsigned int height) "source %ux%u -> dest %ux%u size %ux%u"
artist_draw_line(unsigned int start_x, unsigned int start_y, unsigned int end_x, unsigned int end_y) "%ux%u %ux%u"
diff --git a/hw/dma/xlnx-zdma.c b/hw/dma/xlnx-zdma.c
index a5a92b4ff8..4eb7f66e9f 100644
--- a/hw/dma/xlnx-zdma.c
+++ b/hw/dma/xlnx-zdma.c
@@ -806,7 +806,6 @@ static const VMStateDescription vmstate_zdma = {
.name = TYPE_XLNX_ZDMA,
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, XlnxZDMA, ZDMA_R_MAX),
VMSTATE_UINT32(state, XlnxZDMA),
diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c
index 896bb3574d..84f782fcdc 100644
--- a/hw/dma/xlnx_csu_dma.c
+++ b/hw/dma/xlnx_csu_dma.c
@@ -472,6 +472,20 @@ static uint64_t addr_msb_pre_write(RegisterInfo *reg, uint64_t val)
return val & R_ADDR_MSB_ADDR_MSB_MASK;
}
+static MemTxResult xlnx_csu_dma_class_read(XlnxCSUDMA *s, hwaddr addr,
+ uint32_t len)
+{
+ RegisterInfo *reg = &s->regs_info[R_SIZE];
+ uint64_t we = MAKE_64BIT_MASK(0, 4 * 8);
+
+ s->regs[R_ADDR] = addr;
+ s->regs[R_ADDR_MSB] = (uint64_t)addr >> 32;
+
+ register_write(reg, len, we, object_get_typename(OBJECT(s)), false);
+
+ return (s->regs[R_SIZE] == 0) ? MEMTX_OK : MEMTX_ERROR;
+}
+
static const RegisterAccessInfo *xlnx_csu_dma_regs_info[] = {
#define DMACH_REGINFO(NAME, snd) \
(const RegisterAccessInfo []) { \
@@ -663,7 +677,6 @@ static const VMStateDescription vmstate_xlnx_csu_dma = {
.name = TYPE_XLNX_CSU_DMA,
.version_id = 0,
.minimum_version_id = 0,
- .minimum_version_id_old = 0,
.fields = (VMStateField[]) {
VMSTATE_PTIMER(src_timer, XlnxCSUDMA),
VMSTATE_UINT16(width, XlnxCSUDMA),
@@ -696,6 +709,7 @@ static void xlnx_csu_dma_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
+ XlnxCSUDMAClass *xcdc = XLNX_CSU_DMA_CLASS(klass);
dc->reset = xlnx_csu_dma_reset;
dc->realize = xlnx_csu_dma_realize;
@@ -704,6 +718,8 @@ static void xlnx_csu_dma_class_init(ObjectClass *klass, void *data)
ssc->push = xlnx_csu_dma_stream_push;
ssc->can_push = xlnx_csu_dma_stream_can_push;
+
+ xcdc->read = xlnx_csu_dma_class_read;
}
static void xlnx_csu_dma_init(Object *obj)
diff --git a/hw/gpio/imx_gpio.c b/hw/gpio/imx_gpio.c
index 7a591804a9..c7f98b7bb1 100644
--- a/hw/gpio/imx_gpio.c
+++ b/hw/gpio/imx_gpio.c
@@ -277,7 +277,6 @@ static const VMStateDescription vmstate_imx_gpio = {
.name = TYPE_IMX_GPIO,
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(dr, IMXGPIOState),
VMSTATE_UINT32(gdir, IMXGPIOState),
diff --git a/hw/hppa/hppa_hardware.h b/hw/hppa/hppa_hardware.h
index bc258895c9..5edf577563 100644
--- a/hw/hppa/hppa_hardware.h
+++ b/hw/hppa/hppa_hardware.h
@@ -25,7 +25,7 @@
#define LASI_GFX_HPA 0xf8000000
#define ARTIST_FB_ADDR 0xf9000000
#define CPU_HPA 0xfffb0000
-#define MEMORY_HPA 0xfffbf000
+#define MEMORY_HPA 0xfffff000
#define PCI_HPA DINO_HPA /* PCI bus */
#define IDE_HPA 0xf9000000 /* Boot disc controller */
@@ -43,9 +43,10 @@
#define PORT_SERIAL1 (DINO_UART_HPA + 0x800)
#define PORT_SERIAL2 (LASI_UART_HPA + 0x800)
-#define HPPA_MAX_CPUS 8 /* max. number of SMP CPUs */
+#define HPPA_MAX_CPUS 16 /* max. number of SMP CPUs */
#define CPU_CLOCK_MHZ 250 /* emulate a 250 MHz CPU */
#define CPU_HPA_CR_REG 7 /* store CPU HPA in cr7 (SeaBIOS internal) */
+#define PIM_STORAGE_SIZE 600 /* storage size of pdc_pim_toc_struct (64bit) */
#endif
diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c
index 2a46af5bc9..98b30e0395 100644
--- a/hw/hppa/machine.c
+++ b/hw/hppa/machine.c
@@ -17,6 +17,7 @@
#include "hw/timer/i8254.h"
#include "hw/char/serial.h"
#include "hw/net/lasi_82596.h"
+#include "hw/nmi.h"
#include "hppa_sys.h"
#include "qemu/units.h"
#include "qapi/error.h"
@@ -355,6 +356,14 @@ static void hppa_machine_reset(MachineState *ms)
cpu[0]->env.gr[19] = FW_CFG_IO_BASE;
}
+static void hppa_nmi(NMIState *n, int cpu_index, Error **errp)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ cpu_interrupt(cs, CPU_INTERRUPT_NMI);
+ }
+}
static void machine_hppa_machine_init(MachineClass *mc)
{
@@ -371,4 +380,28 @@ static void machine_hppa_machine_init(MachineClass *mc)
mc->default_ram_id = "ram";
}
-DEFINE_MACHINE("hppa", machine_hppa_machine_init)
+static void machine_hppa_machine_init_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ machine_hppa_machine_init(mc);
+
+ NMIClass *nc = NMI_CLASS(oc);
+ nc->nmi_monitor_handler = hppa_nmi;
+}
+
+static const TypeInfo machine_hppa_machine_init_typeinfo = {
+ .name = ("hppa" "-machine"),
+ .parent = "machine",
+ .class_init = machine_hppa_machine_init_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_NMI },
+ { }
+ },
+};
+
+static void machine_hppa_machine_init_register_types(void)
+{
+ type_register_static(&machine_hppa_machine_init_typeinfo);
+}
+
+type_init(machine_hppa_machine_init_register_types)
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index ce823e8fcb..ebd47aa26f 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -43,6 +43,7 @@
#include "sysemu/tpm.h"
#include "hw/acpi/tpm.h"
#include "hw/acpi/vmgenid.h"
+#include "hw/acpi/erst.h"
#include "sysemu/tpm_backend.h"
#include "hw/rtc/mc146818rtc_regs.h"
#include "migration/vmstate.h"
@@ -74,6 +75,8 @@
#include "hw/acpi/hmat.h"
#include "hw/acpi/viot.h"
+#include CONFIG_DEVICES
+
/* These are used to size the ACPI tables for -M pc-i440fx-1.7 and
* -M pc-i440fx-2.0. Even if the actual amount of AML generated grows
* a little bit, there should be plenty of free space since the DSDT
@@ -2575,6 +2578,18 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id,
x86ms->oem_table_id);
+#ifdef CONFIG_ACPI_ERST
+ {
+ Object *erst_dev;
+ erst_dev = find_erst_dev();
+ if (erst_dev) {
+ acpi_add_table(table_offsets, tables_blob);
+ build_erst(tables_blob, tables->linker, erst_dev,
+ x86ms->oem_id, x86ms->oem_table_id);
+ }
+ }
+#endif
+
vmgenid_dev = find_vmgenid_dev();
if (vmgenid_dev) {
acpi_add_table(table_offsets, tables_blob);
diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c
index 196d318499..68ca7e7fc2 100644
--- a/hw/i386/acpi-microvm.c
+++ b/hw/i386/acpi-microvm.c
@@ -30,6 +30,7 @@
#include "hw/acpi/bios-linker-loader.h"
#include "hw/acpi/generic_event_device.h"
#include "hw/acpi/utils.h"
+#include "hw/acpi/erst.h"
#include "hw/i386/fw_cfg.h"
#include "hw/i386/microvm.h"
#include "hw/pci/pci.h"
@@ -40,6 +41,8 @@
#include "acpi-common.h"
#include "acpi-microvm.h"
+#include CONFIG_DEVICES
+
static void acpi_dsdt_add_virtio(Aml *scope,
MicrovmMachineState *mms)
{
@@ -207,6 +210,18 @@ static void acpi_build_microvm(AcpiBuildTables *tables,
ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id,
x86ms->oem_table_id);
+#ifdef CONFIG_ACPI_ERST
+ {
+ Object *erst_dev;
+ erst_dev = find_erst_dev();
+ if (erst_dev) {
+ acpi_add_table(table_offsets, tables_blob);
+ build_erst(tables_blob, tables->linker, erst_dev,
+ x86ms->oem_id, x86ms->oem_table_id);
+ }
+ }
+#endif
+
xsdt = tables_blob->len;
build_xsdt(tables_blob, tables->linker, table_offsets, x86ms->oem_id,
x86ms->oem_table_id);
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 7c7790a5ce..d9b344248d 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -357,10 +357,12 @@ static void pc_compat_1_4_fn(MachineState *machine)
pc_compat_1_5_fn(machine);
}
+#ifdef CONFIG_ISAPC
static void pc_init_isa(MachineState *machine)
{
pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE);
}
+#endif
#ifdef CONFIG_XEN
static void pc_xen_hvm_init_pci(MachineState *machine)
@@ -916,6 +918,7 @@ void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id)
pci_config_set_revision(bridge_dev->config, pch_rev_id);
}
+#ifdef CONFIG_ISAPC
static void isapc_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
@@ -935,7 +938,7 @@ static void isapc_machine_options(MachineClass *m)
DEFINE_PC_MACHINE(isapc, "isapc", pc_init_isa,
isapc_machine_options);
-
+#endif
#ifdef CONFIG_XEN
static void xenfv_4_2_machine_options(MachineClass *m)
diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c
index 5de5dd0893..a2b318dd93 100644
--- a/hw/i386/sgx.c
+++ b/hw/i386/sgx.c
@@ -83,7 +83,7 @@ static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high)
((high & MAKE_64BIT_MASK(0, 20)) << 32);
}
-static SGXEPCSectionList *sgx_calc_host_epc_sections(void)
+static SGXEPCSectionList *sgx_calc_host_epc_sections(uint64_t *size)
{
SGXEPCSectionList *head = NULL, **tail = &head;
SGXEPCSection *section;
@@ -106,6 +106,7 @@ static SGXEPCSectionList *sgx_calc_host_epc_sections(void)
section = g_new0(SGXEPCSection, 1);
section->node = j++;
section->size = sgx_calc_section_metric(ecx, edx);
+ *size += section->size;
QAPI_LIST_APPEND(tail, section);
}
@@ -156,6 +157,7 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp)
{
SGXInfo *info = NULL;
uint32_t eax, ebx, ecx, edx;
+ uint64_t size = 0;
int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
if (fd < 0) {
@@ -173,7 +175,8 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp)
info->sgx1 = eax & (1U << 0) ? true : false;
info->sgx2 = eax & (1U << 1) ? true : false;
- info->sections = sgx_calc_host_epc_sections();
+ info->sections = sgx_calc_host_epc_sections(&size);
+ info->section_size = size;
close(fd);
@@ -220,12 +223,14 @@ SGXInfo *qmp_query_sgx(Error **errp)
return NULL;
}
+ SGXEPCState *sgx_epc = &pcms->sgx_epc;
info = g_new0(SGXInfo, 1);
info->sgx = true;
info->sgx1 = true;
info->sgx2 = true;
info->flc = true;
+ info->section_size = sgx_epc->size;
info->sections = sgx_get_epc_sections_list();
return info;
@@ -249,6 +254,8 @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict)
info->sgx2 ? "enabled" : "disabled");
monitor_printf(mon, "FLC support: %s\n",
info->flc ? "enabled" : "disabled");
+ monitor_printf(mon, "size: %" PRIu64 "\n",
+ info->section_size);
section_list = info->sections;
for (section = section_list; section; section = section->next) {
diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c
index 482be95415..cf8e500514 100644
--- a/hw/i386/xen/xen-hvm.c
+++ b/hw/i386/xen/xen-hvm.c
@@ -1087,10 +1087,11 @@ static void handle_ioreq(XenIOState *state, ioreq_t *req)
}
}
-static int handle_buffered_iopage(XenIOState *state)
+static bool handle_buffered_iopage(XenIOState *state)
{
buffered_iopage_t *buf_page = state->buffered_io_page;
buf_ioreq_t *buf_req = NULL;
+ bool handled_ioreq = false;
ioreq_t req;
int qw;
@@ -1144,9 +1145,10 @@ static int handle_buffered_iopage(XenIOState *state)
assert(!req.data_is_ptr);
qatomic_add(&buf_page->read_pointer, qw + 1);
+ handled_ioreq = true;
}
- return req.count;
+ return handled_ioreq;
}
static void handle_buffered_io(void *opaque)
diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c
index bd47c3d672..f2ef977963 100644
--- a/hw/i386/xen/xen-mapcache.c
+++ b/hw/i386/xen/xen-mapcache.c
@@ -52,7 +52,7 @@ typedef struct MapCacheEntry {
hwaddr paddr_index;
uint8_t *vaddr_base;
unsigned long *valid_mapping;
- uint8_t lock;
+ uint32_t lock;
#define XEN_MAPCACHE_ENTRY_DUMMY (1 << 0)
uint8_t flags;
hwaddr size;
@@ -355,6 +355,12 @@ tryagain:
if (lock) {
MapCacheRev *reventry = g_malloc0(sizeof(MapCacheRev));
entry->lock++;
+ if (entry->lock == 0) {
+ fprintf(stderr,
+ "mapcache entry lock overflow: "TARGET_FMT_plx" -> %p\n",
+ entry->paddr_index, entry->vaddr_base);
+ abort();
+ }
reventry->dma = dma;
reventry->vaddr_req = mapcache->last_entry->vaddr_base + address_offset;
reventry->paddr_index = mapcache->last_entry->paddr_index;
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 715df5421d..6d3c8ee231 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -166,6 +166,7 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
}
if ((cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) && cs->gic->lpi_enable &&
+ (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1NS) &&
(cs->hpplpi.prio != 0xff)) {
if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio)) {
cs->hppi.irq = cs->hpplpi.irq;
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 9884d2e39b..4ca5ae9bc5 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -357,6 +357,11 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
return;
}
+ if (s->lpi_enable) {
+ address_space_init(&s->dma_as, s->dma,
+ "gicv3-its-sysmem");
+ }
+
s->cpu = g_new0(GICv3CPUState, s->num_cpu);
for (i = 0; i < s->num_cpu; i++) {
@@ -424,6 +429,10 @@ static void arm_gicv3_common_reset(DeviceState *dev)
cs->level = 0;
cs->gicr_ctlr = 0;
+ if (s->lpi_enable) {
+ /* Our implementation supports clearing GICR_CTLR.EnableLPIs */
+ cs->gicr_ctlr |= GICR_CTLR_CES;
+ }
cs->gicr_statusr[GICV3_S] = 0;
cs->gicr_statusr[GICV3_NS] = 0;
cs->gicr_waker = GICR_WAKER_ProcessorSleep | GICR_WAKER_ChildrenAsleep;
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index b2f6a8c7f0..51d9be4ae6 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -13,6 +13,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
+#include "trace.h"
#include "hw/qdev-properties.h"
#include "hw/intc/arm_gicv3_its_common.h"
#include "gicv3_internal.h"
@@ -255,10 +256,10 @@ static ItsCmdResult process_its_cmd(GICv3ITSState *s, uint64_t value,
eventid = (value & EVENTID_MASK);
- if (devid >= s->dt.num_ids) {
+ if (devid >= s->dt.num_entries) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid command attributes: devid %d>=%d",
- __func__, devid, s->dt.num_ids);
+ __func__, devid, s->dt.num_entries);
return CMD_CONTINUE;
}
@@ -299,7 +300,7 @@ static ItsCmdResult process_its_cmd(GICv3ITSState *s, uint64_t value,
return CMD_CONTINUE;
}
- if (icid >= s->ct.num_ids) {
+ if (icid >= s->ct.num_entries) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid ICID 0x%x in ITE (table corrupted?)\n",
__func__, icid);
@@ -383,10 +384,10 @@ static ItsCmdResult process_mapti(GICv3ITSState *s, uint64_t value,
icid = value & ICID_MASK;
- if (devid >= s->dt.num_ids) {
+ if (devid >= s->dt.num_entries) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid command attributes: devid %d>=%d",
- __func__, devid, s->dt.num_ids);
+ __func__, devid, s->dt.num_entries);
return CMD_CONTINUE;
}
@@ -399,7 +400,7 @@ static ItsCmdResult process_mapti(GICv3ITSState *s, uint64_t value,
num_eventids = 1ULL << (FIELD_EX64(dte, DTE, SIZE) + 1);
num_intids = 1ULL << (GICD_TYPER_IDBITS + 1);
- if ((icid >= s->ct.num_ids)
+ if ((icid >= s->ct.num_entries)
|| !dte_valid || (eventid >= num_eventids) ||
(((pIntid < GICV3_LPI_INTID_START) || (pIntid >= num_intids)) &&
(pIntid != INTID_SPURIOUS))) {
@@ -484,7 +485,7 @@ static ItsCmdResult process_mapc(GICv3ITSState *s, uint32_t offset)
valid = (value & CMD_FIELD_VALID_MASK);
- if ((icid >= s->ct.num_ids) || (rdbase >= s->gicv3->num_cpu)) {
+ if ((icid >= s->ct.num_entries) || (rdbase >= s->gicv3->num_cpu)) {
qemu_log_mask(LOG_GUEST_ERROR,
"ITS MAPC: invalid collection table attributes "
"icid %d rdbase %" PRIu64 "\n", icid, rdbase);
@@ -565,7 +566,7 @@ static ItsCmdResult process_mapd(GICv3ITSState *s, uint64_t value,
valid = (value & CMD_FIELD_VALID_MASK);
- if ((devid >= s->dt.num_ids) ||
+ if ((devid >= s->dt.num_entries) ||
(size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS))) {
qemu_log_mask(LOG_GUEST_ERROR,
"ITS MAPD: invalid device table attributes "
@@ -581,6 +582,201 @@ static ItsCmdResult process_mapd(GICv3ITSState *s, uint64_t value,
return update_dte(s, devid, valid, size, itt_addr) ? CMD_CONTINUE : CMD_STALL;
}
+static ItsCmdResult process_movall(GICv3ITSState *s, uint64_t value,
+ uint32_t offset)
+{
+ AddressSpace *as = &s->gicv3->dma_as;
+ MemTxResult res = MEMTX_OK;
+ uint64_t rd1, rd2;
+
+ /* No fields in dwords 0 or 1 */
+ offset += NUM_BYTES_IN_DW;
+ offset += NUM_BYTES_IN_DW;
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
+ MEMTXATTRS_UNSPECIFIED, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+
+ rd1 = FIELD_EX64(value, MOVALL_2, RDBASE1);
+ if (rd1 >= s->gicv3->num_cpu) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: RDBASE1 %" PRId64
+ " out of range (must be less than %d)\n",
+ __func__, rd1, s->gicv3->num_cpu);
+ return CMD_CONTINUE;
+ }
+
+ offset += NUM_BYTES_IN_DW;
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
+ MEMTXATTRS_UNSPECIFIED, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+
+ rd2 = FIELD_EX64(value, MOVALL_3, RDBASE2);
+ if (rd2 >= s->gicv3->num_cpu) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: RDBASE2 %" PRId64
+ " out of range (must be less than %d)\n",
+ __func__, rd2, s->gicv3->num_cpu);
+ return CMD_CONTINUE;
+ }
+
+ if (rd1 == rd2) {
+ /* Move to same target must succeed as a no-op */
+ return CMD_CONTINUE;
+ }
+
+ /* Move all pending LPIs from redistributor 1 to redistributor 2 */
+ gicv3_redist_movall_lpis(&s->gicv3->cpu[rd1], &s->gicv3->cpu[rd2]);
+
+ return CMD_CONTINUE;
+}
+
+static ItsCmdResult process_movi(GICv3ITSState *s, uint64_t value,
+ uint32_t offset)
+{
+ AddressSpace *as = &s->gicv3->dma_as;
+ MemTxResult res = MEMTX_OK;
+ uint32_t devid, eventid, intid;
+ uint16_t old_icid, new_icid;
+ uint64_t old_cte, new_cte;
+ uint64_t old_rdbase, new_rdbase;
+ uint64_t dte;
+ bool dte_valid, ite_valid, cte_valid;
+ uint64_t num_eventids;
+ IteEntry ite = {};
+
+ devid = FIELD_EX64(value, MOVI_0, DEVICEID);
+
+ offset += NUM_BYTES_IN_DW;
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
+ MEMTXATTRS_UNSPECIFIED, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+ eventid = FIELD_EX64(value, MOVI_1, EVENTID);
+
+ offset += NUM_BYTES_IN_DW;
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
+ MEMTXATTRS_UNSPECIFIED, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+ new_icid = FIELD_EX64(value, MOVI_2, ICID);
+
+ if (devid >= s->dt.num_entries) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: devid %d>=%d",
+ __func__, devid, s->dt.num_entries);
+ return CMD_CONTINUE;
+ }
+ dte = get_dte(s, devid, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+
+ dte_valid = FIELD_EX64(dte, DTE, VALID);
+ if (!dte_valid) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: "
+ "invalid dte: %"PRIx64" for %d\n",
+ __func__, dte, devid);
+ return CMD_CONTINUE;
+ }
+
+ num_eventids = 1ULL << (FIELD_EX64(dte, DTE, SIZE) + 1);
+ if (eventid >= num_eventids) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: eventid %d >= %"
+ PRId64 "\n",
+ __func__, eventid, num_eventids);
+ return CMD_CONTINUE;
+ }
+
+ ite_valid = get_ite(s, eventid, dte, &old_icid, &intid, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+
+ if (!ite_valid) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: invalid ITE\n",
+ __func__);
+ return CMD_CONTINUE;
+ }
+
+ if (old_icid >= s->ct.num_entries) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid ICID 0x%x in ITE (table corrupted?)\n",
+ __func__, old_icid);
+ return CMD_CONTINUE;
+ }
+
+ if (new_icid >= s->ct.num_entries) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: ICID 0x%x\n",
+ __func__, new_icid);
+ return CMD_CONTINUE;
+ }
+
+ cte_valid = get_cte(s, old_icid, &old_cte, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+ if (!cte_valid) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: "
+ "invalid cte: %"PRIx64"\n",
+ __func__, old_cte);
+ return CMD_CONTINUE;
+ }
+
+ cte_valid = get_cte(s, new_icid, &new_cte, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+ if (!cte_valid) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: "
+ "invalid cte: %"PRIx64"\n",
+ __func__, new_cte);
+ return CMD_CONTINUE;
+ }
+
+ old_rdbase = FIELD_EX64(old_cte, CTE, RDBASE);
+ if (old_rdbase >= s->gicv3->num_cpu) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: CTE has invalid rdbase 0x%"PRIx64"\n",
+ __func__, old_rdbase);
+ return CMD_CONTINUE;
+ }
+
+ new_rdbase = FIELD_EX64(new_cte, CTE, RDBASE);
+ if (new_rdbase >= s->gicv3->num_cpu) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: CTE has invalid rdbase 0x%"PRIx64"\n",
+ __func__, new_rdbase);
+ return CMD_CONTINUE;
+ }
+
+ if (old_rdbase != new_rdbase) {
+ /* Move the LPI from the old redistributor to the new one */
+ gicv3_redist_mov_lpi(&s->gicv3->cpu[old_rdbase],
+ &s->gicv3->cpu[new_rdbase],
+ intid);
+ }
+
+ /* Update the ICID field in the interrupt translation table entry */
+ ite.itel = FIELD_DP64(ite.itel, ITE_L, VALID, 1);
+ ite.itel = FIELD_DP64(ite.itel, ITE_L, INTTYPE, ITE_INTTYPE_PHYSICAL);
+ ite.itel = FIELD_DP64(ite.itel, ITE_L, INTID, intid);
+ ite.itel = FIELD_DP64(ite.itel, ITE_L, DOORBELL, INTID_SPURIOUS);
+ ite.iteh = FIELD_DP32(ite.iteh, ITE_H, ICID, new_icid);
+ return update_ite(s, eventid, dte, ite) ? CMD_CONTINUE : CMD_STALL;
+}
+
/*
* Current implementation blocks until all
* commands are processed
@@ -634,6 +830,8 @@ static void process_cmdq(GICv3ITSState *s)
cmd = (data & CMD_MASK);
+ trace_gicv3_its_process_command(rd_offset, cmd);
+
switch (cmd) {
case GITS_CMD_INT:
result = process_its_cmd(s, data, cq_offset, INTERRUPT);
@@ -676,6 +874,12 @@ static void process_cmdq(GICv3ITSState *s)
gicv3_redist_update_lpi(&s->gicv3->cpu[i]);
}
break;
+ case GITS_CMD_MOVI:
+ result = process_movi(s, data, cq_offset);
+ break;
+ case GITS_CMD_MOVALL:
+ result = process_movall(s, data, cq_offset);
+ break;
default:
break;
}
@@ -788,7 +992,7 @@ static void extract_table_params(GICv3ITSState *s)
L1TABLE_ENTRY_SIZE) *
(page_sz / td->entry_sz));
}
- td->num_ids = 1ULL << idbits;
+ td->num_entries = MIN(td->num_entries, 1ULL << idbits);
}
}
@@ -810,6 +1014,18 @@ static void extract_cmdq_params(GICv3ITSState *s)
}
}
+static MemTxResult gicv3_its_translation_read(void *opaque, hwaddr offset,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
+{
+ /*
+ * GITS_TRANSLATER is write-only, and all other addresses
+ * in the interrupt translation space frame are RES0.
+ */
+ *data = 0;
+ return MEMTX_OK;
+}
+
static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
uint64_t data, unsigned size,
MemTxAttrs attrs)
@@ -818,6 +1034,8 @@ static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
bool result = true;
uint32_t devid = 0;
+ trace_gicv3_its_translation_write(offset, data, size, attrs.requester_id);
+
switch (offset) {
case GITS_TRANSLATER:
if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
@@ -848,7 +1066,6 @@ static bool its_writel(GICv3ITSState *s, hwaddr offset,
s->ctlr |= R_GITS_CTLR_ENABLED_MASK;
extract_table_params(s);
extract_cmdq_params(s);
- s->creadr = 0;
process_cmdq(s);
} else {
s->ctlr &= ~R_GITS_CTLR_ENABLED_MASK;
@@ -862,7 +1079,6 @@ static bool its_writel(GICv3ITSState *s, hwaddr offset,
if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
s->cbaser = deposit64(s->cbaser, 0, 32, value);
s->creadr = 0;
- s->cwriter = s->creadr;
}
break;
case GITS_CBASER + 4:
@@ -873,7 +1089,6 @@ static bool its_writel(GICv3ITSState *s, hwaddr offset,
if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
s->cbaser = deposit64(s->cbaser, 32, 32, value);
s->creadr = 0;
- s->cwriter = s->creadr;
}
break;
case GITS_CWRITER:
@@ -915,6 +1130,10 @@ static bool its_writel(GICv3ITSState *s, hwaddr offset,
if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
index = (offset - GITS_BASER) / 8;
+ if (s->baser[index] == 0) {
+ /* Unimplemented GITS_BASERn: RAZ/WI */
+ break;
+ }
if (offset & 7) {
value <<= 32;
value &= ~GITS_BASER_RO_MASK;
@@ -1011,6 +1230,10 @@ static bool its_writell(GICv3ITSState *s, hwaddr offset,
*/
if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
index = (offset - GITS_BASER) / 8;
+ if (s->baser[index] == 0) {
+ /* Unimplemented GITS_BASERn: RAZ/WI */
+ break;
+ }
s->baser[index] &= GITS_BASER_RO_MASK;
s->baser[index] |= (value & ~GITS_BASER_RO_MASK);
}
@@ -1023,7 +1246,6 @@ static bool its_writell(GICv3ITSState *s, hwaddr offset,
if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
s->cbaser = value;
s->creadr = 0;
- s->cwriter = s->creadr;
}
break;
case GITS_CWRITER:
@@ -1107,6 +1329,7 @@ static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid guest read at offset " TARGET_FMT_plx
"size %u\n", __func__, offset, size);
+ trace_gicv3_its_badread(offset, size);
/*
* The spec requires that reserved registers are RAZ/WI;
* so use false returns from leaf functions as a way to
@@ -1114,6 +1337,8 @@ static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
* the caller, or we'll cause a spurious guest data abort.
*/
*data = 0;
+ } else {
+ trace_gicv3_its_read(offset, *data, size);
}
return MEMTX_OK;
}
@@ -1140,12 +1365,15 @@ static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data,
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid guest write at offset " TARGET_FMT_plx
"size %u\n", __func__, offset, size);
+ trace_gicv3_its_badwrite(offset, data, size);
/*
* The spec requires that reserved registers are RAZ/WI;
* so use false returns from leaf functions as a way to
* trigger the guest-error logging but don't return it to
* the caller, or we'll cause a spurious guest data abort.
*/
+ } else {
+ trace_gicv3_its_write(offset, data, size);
}
return MEMTX_OK;
}
@@ -1161,6 +1389,7 @@ static const MemoryRegionOps gicv3_its_control_ops = {
};
static const MemoryRegionOps gicv3_its_translation_ops = {
+ .read_with_attrs = gicv3_its_translation_read,
.write_with_attrs = gicv3_its_translation_write,
.valid.min_access_size = 2,
.valid.max_access_size = 4,
@@ -1183,9 +1412,6 @@ static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
gicv3_its_init_mmio(s, &gicv3_its_control_ops, &gicv3_its_translation_ops);
- address_space_init(&s->gicv3->dma_as, s->gicv3->dma,
- "gicv3-its-sysmem");
-
/* set the ITS default features supported */
s->typer = FIELD_DP64(s->typer, GITS_TYPER, PHYSICAL, 1);
s->typer = FIELD_DP64(s->typer, GITS_TYPER, ITT_ENTRY_SIZE,
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index 99b11ca5ee..412a04f59c 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -591,8 +591,7 @@ void gicv3_redist_update_lpi_only(GICv3CPUState *cs)
idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
GICD_TYPER_IDBITS);
- if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
- !cs->gicr_pendbaser) {
+ if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) {
return;
}
@@ -673,9 +672,8 @@ void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level)
idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
GICD_TYPER_IDBITS);
- if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
- !cs->gicr_pendbaser || (irq > (1ULL << (idbits + 1)) - 1) ||
- irq < GICV3_LPI_INTID_START) {
+ if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) ||
+ (irq > (1ULL << (idbits + 1)) - 1) || irq < GICV3_LPI_INTID_START) {
return;
}
@@ -683,6 +681,113 @@ void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level)
gicv3_redist_lpi_pending(cs, irq, level);
}
+void gicv3_redist_mov_lpi(GICv3CPUState *src, GICv3CPUState *dest, int irq)
+{
+ /*
+ * Move the specified LPI's pending state from the source redistributor
+ * to the destination.
+ *
+ * If LPIs are disabled on dest this is CONSTRAINED UNPREDICTABLE:
+ * we choose to NOP. If LPIs are disabled on source there's nothing
+ * to be transferred anyway.
+ */
+ AddressSpace *as = &src->gic->dma_as;
+ uint64_t idbits;
+ uint32_t pendt_size;
+ uint64_t src_baddr;
+ uint8_t src_pend;
+
+ if (!(src->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) ||
+ !(dest->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) {
+ return;
+ }
+
+ idbits = MIN(FIELD_EX64(src->gicr_propbaser, GICR_PROPBASER, IDBITS),
+ GICD_TYPER_IDBITS);
+ idbits = MIN(FIELD_EX64(dest->gicr_propbaser, GICR_PROPBASER, IDBITS),
+ idbits);
+
+ pendt_size = 1ULL << (idbits + 1);
+ if ((irq / 8) >= pendt_size) {
+ return;
+ }
+
+ src_baddr = src->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
+
+ address_space_read(as, src_baddr + (irq / 8),
+ MEMTXATTRS_UNSPECIFIED, &src_pend, sizeof(src_pend));
+ if (!extract32(src_pend, irq % 8, 1)) {
+ /* Not pending on source, nothing to do */
+ return;
+ }
+ src_pend &= ~(1 << (irq % 8));
+ address_space_write(as, src_baddr + (irq / 8),
+ MEMTXATTRS_UNSPECIFIED, &src_pend, sizeof(src_pend));
+ if (irq == src->hpplpi.irq) {
+ /*
+ * We just made this LPI not-pending so only need to update
+ * if it was previously the highest priority pending LPI
+ */
+ gicv3_redist_update_lpi(src);
+ }
+ /* Mark it pending on the destination */
+ gicv3_redist_lpi_pending(dest, irq, 1);
+}
+
+void gicv3_redist_movall_lpis(GICv3CPUState *src, GICv3CPUState *dest)
+{
+ /*
+ * We must move all pending LPIs from the source redistributor
+ * to the destination. That is, for every pending LPI X on
+ * src, we must set it not-pending on src and pending on dest.
+ * LPIs that are already pending on dest are not cleared.
+ *
+ * If LPIs are disabled on dest this is CONSTRAINED UNPREDICTABLE:
+ * we choose to NOP. If LPIs are disabled on source there's nothing
+ * to be transferred anyway.
+ */
+ AddressSpace *as = &src->gic->dma_as;
+ uint64_t idbits;
+ uint32_t pendt_size;
+ uint64_t src_baddr, dest_baddr;
+ int i;
+
+ if (!(src->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) ||
+ !(dest->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) {
+ return;
+ }
+
+ idbits = MIN(FIELD_EX64(src->gicr_propbaser, GICR_PROPBASER, IDBITS),
+ GICD_TYPER_IDBITS);
+ idbits = MIN(FIELD_EX64(dest->gicr_propbaser, GICR_PROPBASER, IDBITS),
+ idbits);
+
+ pendt_size = 1ULL << (idbits + 1);
+ src_baddr = src->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
+ dest_baddr = dest->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
+
+ for (i = GICV3_LPI_INTID_START / 8; i < pendt_size / 8; i++) {
+ uint8_t src_pend, dest_pend;
+
+ address_space_read(as, src_baddr + i, MEMTXATTRS_UNSPECIFIED,
+ &src_pend, sizeof(src_pend));
+ if (!src_pend) {
+ continue;
+ }
+ address_space_read(as, dest_baddr + i, MEMTXATTRS_UNSPECIFIED,
+ &dest_pend, sizeof(dest_pend));
+ dest_pend |= src_pend;
+ src_pend = 0;
+ address_space_write(as, src_baddr + i, MEMTXATTRS_UNSPECIFIED,
+ &src_pend, sizeof(src_pend));
+ address_space_write(as, dest_baddr + i, MEMTXATTRS_UNSPECIFIED,
+ &dest_pend, sizeof(dest_pend));
+ }
+
+ gicv3_redist_update_lpi(src);
+ gicv3_redist_update_lpi(dest);
+}
+
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level)
{
/* Update redistributor state for a change in an external PPI input line */
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 1eeb99035d..b1af26df9f 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -110,6 +110,7 @@
#define GICR_NSACR (GICR_SGI_OFFSET + 0x0E00)
#define GICR_CTLR_ENABLE_LPIS (1U << 0)
+#define GICR_CTLR_CES (1U << 1)
#define GICR_CTLR_RWP (1U << 3)
#define GICR_CTLR_DPG0 (1U << 24)
#define GICR_CTLR_DPG1NS (1U << 25)
@@ -314,16 +315,18 @@ FIELD(GITS_TYPER, CIL, 36, 1)
#define CMD_MASK 0xff
/* ITS Commands */
-#define GITS_CMD_CLEAR 0x04
-#define GITS_CMD_DISCARD 0x0F
+#define GITS_CMD_MOVI 0x01
#define GITS_CMD_INT 0x03
-#define GITS_CMD_MAPC 0x09
+#define GITS_CMD_CLEAR 0x04
+#define GITS_CMD_SYNC 0x05
#define GITS_CMD_MAPD 0x08
-#define GITS_CMD_MAPI 0x0B
+#define GITS_CMD_MAPC 0x09
#define GITS_CMD_MAPTI 0x0A
+#define GITS_CMD_MAPI 0x0B
#define GITS_CMD_INV 0x0C
#define GITS_CMD_INVALL 0x0D
-#define GITS_CMD_SYNC 0x05
+#define GITS_CMD_MOVALL 0x0E
+#define GITS_CMD_DISCARD 0x0F
/* MAPC command fields */
#define ICID_LENGTH 16
@@ -354,6 +357,15 @@ FIELD(MAPC, RDBASE, 16, 32)
#define L2_TABLE_VALID_MASK CMD_FIELD_VALID_MASK
#define TABLE_ENTRY_VALID_MASK (1ULL << 0)
+/* MOVALL command fields */
+FIELD(MOVALL_2, RDBASE1, 16, 36)
+FIELD(MOVALL_3, RDBASE2, 16, 36)
+
+/* MOVI command fields */
+FIELD(MOVI_0, DEVICEID, 32, 32)
+FIELD(MOVI_1, EVENTID, 0, 32)
+FIELD(MOVI_2, ICID, 0, 16)
+
/*
* 12 bytes Interrupt translation Table Entry size
* as per Table 5.3 in GICv3 spec
@@ -496,6 +508,27 @@ void gicv3_redist_update_lpi(GICv3CPUState *cs);
* an incoming migration has loaded new state.
*/
void gicv3_redist_update_lpi_only(GICv3CPUState *cs);
+/**
+ * gicv3_redist_mov_lpi:
+ * @src: source redistributor
+ * @dest: destination redistributor
+ * @irq: LPI to update
+ *
+ * Move the pending state of the specified LPI from @src to @dest,
+ * as required by the ITS MOVI command.
+ */
+void gicv3_redist_mov_lpi(GICv3CPUState *src, GICv3CPUState *dest, int irq);
+/**
+ * gicv3_redist_movall_lpis:
+ * @src: source redistributor
+ * @dest: destination redistributor
+ *
+ * Scan the LPI pending table for @src, and for each pending LPI there
+ * mark it as not-pending for @src and pending for @dest, as required
+ * by the ITS MOVALL command.
+ */
+void gicv3_redist_movall_lpis(GICv3CPUState *src, GICv3CPUState *dest);
+
void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns);
void gicv3_init_cpuif(GICv3State *s);
diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c
index d90b40fe4c..af2e4a2241 100644
--- a/hw/intc/i8259_common.c
+++ b/hw/intc/i8259_common.c
@@ -116,8 +116,8 @@ void pic_stat_update_irq(int irq, int level)
}
}
-bool pic_get_statistics(InterruptStatsProvider *obj,
- uint64_t **irq_counts, unsigned int *nb_irqs)
+static bool pic_get_statistics(InterruptStatsProvider *obj,
+ uint64_t **irq_counts, unsigned int *nb_irqs)
{
PICCommonState *s = PIC_COMMON(obj);
@@ -132,7 +132,7 @@ bool pic_get_statistics(InterruptStatsProvider *obj,
return true;
}
-void pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
+static void pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
{
PICCommonState *s = PIC_COMMON(obj);
diff --git a/hw/intc/ioapic_common.c b/hw/intc/ioapic_common.c
index 3cccfc1556..aa5f760871 100644
--- a/hw/intc/ioapic_common.c
+++ b/hw/intc/ioapic_common.c
@@ -76,7 +76,7 @@ static void ioapic_irr_dump(Monitor *mon, const char *name, uint32_t bitmap)
monitor_printf(mon, "\n");
}
-void ioapic_print_redtbl(Monitor *mon, IOAPICCommonState *s)
+static void ioapic_print_redtbl(Monitor *mon, IOAPICCommonState *s)
{
static const char *delm_str[] = {
"fixed", "lowest", "SMI", "...", "NMI", "INIT", "...", "extINT"};
diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c
index bb207514f2..621b20a03f 100644
--- a/hw/intc/pnv_xive.c
+++ b/hw/intc/pnv_xive.c
@@ -172,7 +172,12 @@ static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type,
/* Get the page size of the indirect table. */
vsd_addr = vsd & VSD_ADDRESS_MASK;
- ldq_be_dma(&address_space_memory, vsd_addr, &vsd, MEMTXATTRS_UNSPECIFIED);
+ if (ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
+ MEMTXATTRS_UNSPECIFIED)) {
+ xive_error(xive, "VST: failed to access %s entry %x @0x%" PRIx64,
+ info->name, idx, vsd_addr);
+ return 0;
+ }
if (!(vsd & VSD_ADDRESS_MASK)) {
#ifdef XIVE_DEBUG
@@ -195,8 +200,12 @@ static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type,
/* Load the VSD we are looking for, if not already done */
if (vsd_idx) {
vsd_addr = vsd_addr + vsd_idx * XIVE_VSD_SIZE;
- ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
- MEMTXATTRS_UNSPECIFIED);
+ if (ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
+ MEMTXATTRS_UNSPECIFIED)) {
+ xive_error(xive, "VST: failed to access %s entry %x @0x%"
+ PRIx64, info->name, vsd_idx, vsd_addr);
+ return 0;
+ }
if (!(vsd & VSD_ADDRESS_MASK)) {
#ifdef XIVE_DEBUG
@@ -543,7 +552,12 @@ static uint64_t pnv_xive_vst_per_subpage(PnvXive *xive, uint32_t type)
/* Get the page size of the indirect table. */
vsd_addr = vsd & VSD_ADDRESS_MASK;
- ldq_be_dma(&address_space_memory, vsd_addr, &vsd, MEMTXATTRS_UNSPECIFIED);
+ if (ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
+ MEMTXATTRS_UNSPECIFIED)) {
+ xive_error(xive, "VST: failed to access %s entry @0x%" PRIx64,
+ info->name, vsd_addr);
+ return 0;
+ }
if (!(vsd & VSD_ADDRESS_MASK)) {
#ifdef XIVE_DEBUG
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 9aba7e3a7a..b28cda4e08 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -169,6 +169,14 @@ gicv3_redist_badwrite(uint32_t cpu, uint64_t offset, uint64_t data, unsigned siz
gicv3_redist_set_irq(uint32_t cpu, int irq, int level) "GICv3 redistributor 0x%x interrupt %d level changed to %d"
gicv3_redist_send_sgi(uint32_t cpu, int irq) "GICv3 redistributor 0x%x pending SGI %d"
+# arm_gicv3_its.c
+gicv3_its_read(uint64_t offset, uint64_t data, unsigned size) "GICv3 ITS read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+gicv3_its_badread(uint64_t offset, unsigned size) "GICv3 ITS read: offset 0x%" PRIx64 " size %u: error"
+gicv3_its_write(uint64_t offset, uint64_t data, unsigned size) "GICv3 ITS write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+gicv3_its_badwrite(uint64_t offset, uint64_t data, unsigned size) "GICv3 ITS write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u: error"
+gicv3_its_translation_write(uint64_t offset, uint64_t data, unsigned size, uint32_t requester_id) "GICv3 ITS TRANSLATER write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u requester_id 0x%x"
+gicv3_its_process_command(uint32_t rd_offset, uint8_t cmd) "GICv3 ITS: processing command at offset 0x%x: 0x%x"
+
# armv7m_nvic.c
nvic_recompute_state(int vectpending, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d vectpending_prio %d exception_prio %d"
nvic_recompute_state_secure(int vectpending, bool vectpending_is_s_banked, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d is_s_banked %d vectpending_prio %d exception_prio %d"
diff --git a/hw/misc/bcm2835_mbox.c b/hw/misc/bcm2835_mbox.c
index 9f73cbd5e4..04e53c9828 100644
--- a/hw/misc/bcm2835_mbox.c
+++ b/hw/misc/bcm2835_mbox.c
@@ -271,7 +271,6 @@ static const VMStateDescription vmstate_bcm2835_mbox = {
.name = TYPE_BCM2835_MBOX,
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_BOOL_ARRAY(available, BCM2835MboxState, MBOX_CHAN_COUNT),
VMSTATE_STRUCT_ARRAY(mbox, BCM2835MboxState, 2, 1,
diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c
index b378e6b305..71b74c3372 100644
--- a/hw/misc/mac_via.c
+++ b/hw/misc/mac_via.c
@@ -16,7 +16,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "migration/vmstate.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
@@ -30,6 +29,7 @@
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "sysemu/block-backend.h"
+#include "sysemu/rtc.h"
#include "trace.h"
#include "qemu/log.h"
diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c
index e917a6a095..233daf1405 100644
--- a/hw/misc/macio/cuda.c
+++ b/hw/misc/macio/cuda.c
@@ -24,7 +24,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/ppc/mac.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
@@ -34,6 +33,7 @@
#include "qapi/error.h"
#include "qemu/timer.h"
#include "sysemu/runstate.h"
+#include "sysemu/rtc.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c
index eb39c64694..76c608ee19 100644
--- a/hw/misc/macio/pmu.c
+++ b/hw/misc/macio/pmu.c
@@ -29,7 +29,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/ppc/mac.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
@@ -41,6 +40,7 @@
#include "qapi/error.h"
#include "qemu/timer.h"
#include "sysemu/runstate.h"
+#include "sysemu/rtc.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index d1a1169108..6dcbe044f3 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -84,7 +84,10 @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files(
))
softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c'))
softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c'))
-softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-xramc.c'))
+softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files(
+ 'xlnx-versal-xramc.c',
+ 'xlnx-versal-pmc-iou-slcr.c',
+))
softmmu_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.c'))
softmmu_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c'))
softmmu_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: files('stm32f4xx_exti.c'))
diff --git a/hw/misc/xlnx-versal-pmc-iou-slcr.c b/hw/misc/xlnx-versal-pmc-iou-slcr.c
new file mode 100644
index 0000000000..07b7ebc217
--- /dev/null
+++ b/hw/misc/xlnx-versal-pmc-iou-slcr.c
@@ -0,0 +1,1446 @@
+/*
+ * QEMU model of Versal's PMC IOU SLCR (system level control registers)
+ *
+ * Copyright (c) 2021 Xilinx Inc.
+ * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
+ *
+ * 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/sysbus.h"
+#include "hw/register.h"
+#include "hw/irq.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "migration/vmstate.h"
+#include "hw/qdev-properties.h"
+#include "hw/misc/xlnx-versal-pmc-iou-slcr.h"
+
+#ifndef XILINX_VERSAL_PMC_IOU_SLCR_ERR_DEBUG
+#define XILINX_VERSAL_PMC_IOU_SLCR_ERR_DEBUG 0
+#endif
+
+REG32(MIO_PIN_0, 0x0)
+ FIELD(MIO_PIN_0, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_0, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_0, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_0, L0_SEL, 1, 2)
+REG32(MIO_PIN_1, 0x4)
+ FIELD(MIO_PIN_1, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_1, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_1, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_1, L0_SEL, 1, 2)
+REG32(MIO_PIN_2, 0x8)
+ FIELD(MIO_PIN_2, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_2, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_2, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_2, L0_SEL, 1, 2)
+REG32(MIO_PIN_3, 0xc)
+ FIELD(MIO_PIN_3, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_3, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_3, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_3, L0_SEL, 1, 2)
+REG32(MIO_PIN_4, 0x10)
+ FIELD(MIO_PIN_4, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_4, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_4, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_4, L0_SEL, 1, 2)
+REG32(MIO_PIN_5, 0x14)
+ FIELD(MIO_PIN_5, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_5, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_5, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_5, L0_SEL, 1, 2)
+REG32(MIO_PIN_6, 0x18)
+ FIELD(MIO_PIN_6, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_6, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_6, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_6, L0_SEL, 1, 2)
+REG32(MIO_PIN_7, 0x1c)
+ FIELD(MIO_PIN_7, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_7, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_7, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_7, L0_SEL, 1, 2)
+REG32(MIO_PIN_8, 0x20)
+ FIELD(MIO_PIN_8, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_8, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_8, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_8, L0_SEL, 1, 2)
+REG32(MIO_PIN_9, 0x24)
+ FIELD(MIO_PIN_9, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_9, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_9, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_9, L0_SEL, 1, 2)
+REG32(MIO_PIN_10, 0x28)
+ FIELD(MIO_PIN_10, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_10, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_10, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_10, L0_SEL, 1, 2)
+REG32(MIO_PIN_11, 0x2c)
+ FIELD(MIO_PIN_11, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_11, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_11, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_11, L0_SEL, 1, 2)
+REG32(MIO_PIN_12, 0x30)
+ FIELD(MIO_PIN_12, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_12, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_12, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_12, L0_SEL, 1, 2)
+REG32(MIO_PIN_13, 0x34)
+ FIELD(MIO_PIN_13, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_13, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_13, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_13, L0_SEL, 1, 2)
+REG32(MIO_PIN_14, 0x38)
+ FIELD(MIO_PIN_14, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_14, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_14, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_14, L0_SEL, 1, 2)
+REG32(MIO_PIN_15, 0x3c)
+ FIELD(MIO_PIN_15, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_15, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_15, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_15, L0_SEL, 1, 2)
+REG32(MIO_PIN_16, 0x40)
+ FIELD(MIO_PIN_16, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_16, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_16, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_16, L0_SEL, 1, 2)
+REG32(MIO_PIN_17, 0x44)
+ FIELD(MIO_PIN_17, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_17, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_17, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_17, L0_SEL, 1, 2)
+REG32(MIO_PIN_18, 0x48)
+ FIELD(MIO_PIN_18, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_18, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_18, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_18, L0_SEL, 1, 2)
+REG32(MIO_PIN_19, 0x4c)
+ FIELD(MIO_PIN_19, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_19, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_19, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_19, L0_SEL, 1, 2)
+REG32(MIO_PIN_20, 0x50)
+ FIELD(MIO_PIN_20, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_20, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_20, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_20, L0_SEL, 1, 2)
+REG32(MIO_PIN_21, 0x54)
+ FIELD(MIO_PIN_21, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_21, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_21, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_21, L0_SEL, 1, 2)
+REG32(MIO_PIN_22, 0x58)
+ FIELD(MIO_PIN_22, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_22, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_22, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_22, L0_SEL, 1, 2)
+REG32(MIO_PIN_23, 0x5c)
+ FIELD(MIO_PIN_23, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_23, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_23, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_23, L0_SEL, 1, 2)
+REG32(MIO_PIN_24, 0x60)
+ FIELD(MIO_PIN_24, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_24, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_24, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_24, L0_SEL, 1, 2)
+REG32(MIO_PIN_25, 0x64)
+ FIELD(MIO_PIN_25, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_25, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_25, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_25, L0_SEL, 1, 2)
+REG32(MIO_PIN_26, 0x68)
+ FIELD(MIO_PIN_26, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_26, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_26, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_26, L0_SEL, 1, 2)
+REG32(MIO_PIN_27, 0x6c)
+ FIELD(MIO_PIN_27, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_27, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_27, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_27, L0_SEL, 1, 2)
+REG32(MIO_PIN_28, 0x70)
+ FIELD(MIO_PIN_28, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_28, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_28, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_28, L0_SEL, 1, 2)
+REG32(MIO_PIN_29, 0x74)
+ FIELD(MIO_PIN_29, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_29, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_29, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_29, L0_SEL, 1, 2)
+REG32(MIO_PIN_30, 0x78)
+ FIELD(MIO_PIN_30, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_30, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_30, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_30, L0_SEL, 1, 2)
+REG32(MIO_PIN_31, 0x7c)
+ FIELD(MIO_PIN_31, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_31, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_31, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_31, L0_SEL, 1, 2)
+REG32(MIO_PIN_32, 0x80)
+ FIELD(MIO_PIN_32, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_32, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_32, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_32, L0_SEL, 1, 2)
+REG32(MIO_PIN_33, 0x84)
+ FIELD(MIO_PIN_33, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_33, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_33, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_33, L0_SEL, 1, 2)
+REG32(MIO_PIN_34, 0x88)
+ FIELD(MIO_PIN_34, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_34, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_34, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_34, L0_SEL, 1, 2)
+REG32(MIO_PIN_35, 0x8c)
+ FIELD(MIO_PIN_35, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_35, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_35, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_35, L0_SEL, 1, 2)
+REG32(MIO_PIN_36, 0x90)
+ FIELD(MIO_PIN_36, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_36, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_36, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_36, L0_SEL, 1, 2)
+REG32(MIO_PIN_37, 0x94)
+ FIELD(MIO_PIN_37, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_37, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_37, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_37, L0_SEL, 1, 2)
+REG32(MIO_PIN_38, 0x98)
+ FIELD(MIO_PIN_38, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_38, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_38, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_38, L0_SEL, 1, 2)
+REG32(MIO_PIN_39, 0x9c)
+ FIELD(MIO_PIN_39, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_39, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_39, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_39, L0_SEL, 1, 2)
+REG32(MIO_PIN_40, 0xa0)
+ FIELD(MIO_PIN_40, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_40, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_40, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_40, L0_SEL, 1, 2)
+REG32(MIO_PIN_41, 0xa4)
+ FIELD(MIO_PIN_41, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_41, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_41, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_41, L0_SEL, 1, 2)
+REG32(MIO_PIN_42, 0xa8)
+ FIELD(MIO_PIN_42, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_42, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_42, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_42, L0_SEL, 1, 2)
+REG32(MIO_PIN_43, 0xac)
+ FIELD(MIO_PIN_43, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_43, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_43, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_43, L0_SEL, 1, 2)
+REG32(MIO_PIN_44, 0xb0)
+ FIELD(MIO_PIN_44, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_44, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_44, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_44, L0_SEL, 1, 2)
+REG32(MIO_PIN_45, 0xb4)
+ FIELD(MIO_PIN_45, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_45, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_45, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_45, L0_SEL, 1, 2)
+REG32(MIO_PIN_46, 0xb8)
+ FIELD(MIO_PIN_46, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_46, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_46, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_46, L0_SEL, 1, 2)
+REG32(MIO_PIN_47, 0xbc)
+ FIELD(MIO_PIN_47, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_47, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_47, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_47, L0_SEL, 1, 2)
+REG32(MIO_PIN_48, 0xc0)
+ FIELD(MIO_PIN_48, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_48, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_48, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_48, L0_SEL, 1, 2)
+REG32(MIO_PIN_49, 0xc4)
+ FIELD(MIO_PIN_49, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_49, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_49, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_49, L0_SEL, 1, 2)
+REG32(MIO_PIN_50, 0xc8)
+ FIELD(MIO_PIN_50, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_50, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_50, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_50, L0_SEL, 1, 2)
+REG32(MIO_PIN_51, 0xcc)
+ FIELD(MIO_PIN_51, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_51, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_51, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_51, L0_SEL, 1, 2)
+REG32(BNK0_EN_RX, 0x100)
+ FIELD(BNK0_EN_RX, BNK0_EN_RX, 0, 26)
+REG32(BNK0_SEL_RX0, 0x104)
+REG32(BNK0_SEL_RX1, 0x108)
+ FIELD(BNK0_SEL_RX1, BNK0_SEL_RX, 0, 20)
+REG32(BNK0_EN_RX_SCHMITT_HYST, 0x10c)
+ FIELD(BNK0_EN_RX_SCHMITT_HYST, BNK0_EN_RX_SCHMITT_HYST, 0, 26)
+REG32(BNK0_EN_WK_PD, 0x110)
+ FIELD(BNK0_EN_WK_PD, BNK0_EN_WK_PD, 0, 26)
+REG32(BNK0_EN_WK_PU, 0x114)
+ FIELD(BNK0_EN_WK_PU, BNK0_EN_WK_PU, 0, 26)
+REG32(BNK0_SEL_DRV0, 0x118)
+REG32(BNK0_SEL_DRV1, 0x11c)
+ FIELD(BNK0_SEL_DRV1, BNK0_SEL_DRV, 0, 20)
+REG32(BNK0_SEL_SLEW, 0x120)
+ FIELD(BNK0_SEL_SLEW, BNK0_SEL_SLEW, 0, 26)
+REG32(BNK0_EN_DFT_OPT_INV, 0x124)
+ FIELD(BNK0_EN_DFT_OPT_INV, BNK0_EN_DFT_OPT_INV, 0, 26)
+REG32(BNK0_EN_PAD2PAD_LOOPBACK, 0x128)
+ FIELD(BNK0_EN_PAD2PAD_LOOPBACK, BNK0_EN_PAD2PAD_LOOPBACK, 0, 13)
+REG32(BNK0_RX_SPARE0, 0x12c)
+REG32(BNK0_RX_SPARE1, 0x130)
+ FIELD(BNK0_RX_SPARE1, BNK0_RX_SPARE, 0, 20)
+REG32(BNK0_TX_SPARE0, 0x134)
+REG32(BNK0_TX_SPARE1, 0x138)
+ FIELD(BNK0_TX_SPARE1, BNK0_TX_SPARE, 0, 20)
+REG32(BNK0_SEL_EN1P8, 0x13c)
+ FIELD(BNK0_SEL_EN1P8, BNK0_SEL_EN1P8, 0, 1)
+REG32(BNK0_EN_B_POR_DETECT, 0x140)
+ FIELD(BNK0_EN_B_POR_DETECT, BNK0_EN_B_POR_DETECT, 0, 1)
+REG32(BNK0_LPF_BYP_POR_DETECT, 0x144)
+ FIELD(BNK0_LPF_BYP_POR_DETECT, BNK0_LPF_BYP_POR_DETECT, 0, 1)
+REG32(BNK0_EN_LATCH, 0x148)
+ FIELD(BNK0_EN_LATCH, BNK0_EN_LATCH, 0, 1)
+REG32(BNK0_VBG_LPF_BYP_B, 0x14c)
+ FIELD(BNK0_VBG_LPF_BYP_B, BNK0_VBG_LPF_BYP_B, 0, 1)
+REG32(BNK0_EN_AMP_B, 0x150)
+ FIELD(BNK0_EN_AMP_B, BNK0_EN_AMP_B, 0, 2)
+REG32(BNK0_SPARE_BIAS, 0x154)
+ FIELD(BNK0_SPARE_BIAS, BNK0_SPARE_BIAS, 0, 4)
+REG32(BNK0_DRIVER_BIAS, 0x158)
+ FIELD(BNK0_DRIVER_BIAS, BNK0_DRIVER_BIAS, 0, 15)
+REG32(BNK0_VMODE, 0x15c)
+ FIELD(BNK0_VMODE, BNK0_VMODE, 0, 1)
+REG32(BNK0_SEL_AUX_IO_RX, 0x160)
+ FIELD(BNK0_SEL_AUX_IO_RX, BNK0_SEL_AUX_IO_RX, 0, 26)
+REG32(BNK0_EN_TX_HS_MODE, 0x164)
+ FIELD(BNK0_EN_TX_HS_MODE, BNK0_EN_TX_HS_MODE, 0, 26)
+REG32(MIO_MST_TRI0, 0x200)
+ FIELD(MIO_MST_TRI0, PIN_25_TRI, 25, 1)
+ FIELD(MIO_MST_TRI0, PIN_24_TRI, 24, 1)
+ FIELD(MIO_MST_TRI0, PIN_23_TRI, 23, 1)
+ FIELD(MIO_MST_TRI0, PIN_22_TRI, 22, 1)
+ FIELD(MIO_MST_TRI0, PIN_21_TRI, 21, 1)
+ FIELD(MIO_MST_TRI0, PIN_20_TRI, 20, 1)
+ FIELD(MIO_MST_TRI0, PIN_19_TRI, 19, 1)
+ FIELD(MIO_MST_TRI0, PIN_18_TRI, 18, 1)
+ FIELD(MIO_MST_TRI0, PIN_17_TRI, 17, 1)
+ FIELD(MIO_MST_TRI0, PIN_16_TRI, 16, 1)
+ FIELD(MIO_MST_TRI0, PIN_15_TRI, 15, 1)
+ FIELD(MIO_MST_TRI0, PIN_14_TRI, 14, 1)
+ FIELD(MIO_MST_TRI0, PIN_13_TRI, 13, 1)
+ FIELD(MIO_MST_TRI0, PIN_12_TRI, 12, 1)
+ FIELD(MIO_MST_TRI0, PIN_11_TRI, 11, 1)
+ FIELD(MIO_MST_TRI0, PIN_10_TRI, 10, 1)
+ FIELD(MIO_MST_TRI0, PIN_09_TRI, 9, 1)
+ FIELD(MIO_MST_TRI0, PIN_08_TRI, 8, 1)
+ FIELD(MIO_MST_TRI0, PIN_07_TRI, 7, 1)
+ FIELD(MIO_MST_TRI0, PIN_06_TRI, 6, 1)
+ FIELD(MIO_MST_TRI0, PIN_05_TRI, 5, 1)
+ FIELD(MIO_MST_TRI0, PIN_04_TRI, 4, 1)
+ FIELD(MIO_MST_TRI0, PIN_03_TRI, 3, 1)
+ FIELD(MIO_MST_TRI0, PIN_02_TRI, 2, 1)
+ FIELD(MIO_MST_TRI0, PIN_01_TRI, 1, 1)
+ FIELD(MIO_MST_TRI0, PIN_00_TRI, 0, 1)
+REG32(MIO_MST_TRI1, 0x204)
+ FIELD(MIO_MST_TRI1, PIN_51_TRI, 25, 1)
+ FIELD(MIO_MST_TRI1, PIN_50_TRI, 24, 1)
+ FIELD(MIO_MST_TRI1, PIN_49_TRI, 23, 1)
+ FIELD(MIO_MST_TRI1, PIN_48_TRI, 22, 1)
+ FIELD(MIO_MST_TRI1, PIN_47_TRI, 21, 1)
+ FIELD(MIO_MST_TRI1, PIN_46_TRI, 20, 1)
+ FIELD(MIO_MST_TRI1, PIN_45_TRI, 19, 1)
+ FIELD(MIO_MST_TRI1, PIN_44_TRI, 18, 1)
+ FIELD(MIO_MST_TRI1, PIN_43_TRI, 17, 1)
+ FIELD(MIO_MST_TRI1, PIN_42_TRI, 16, 1)
+ FIELD(MIO_MST_TRI1, PIN_41_TRI, 15, 1)
+ FIELD(MIO_MST_TRI1, PIN_40_TRI, 14, 1)
+ FIELD(MIO_MST_TRI1, PIN_39_TRI, 13, 1)
+ FIELD(MIO_MST_TRI1, PIN_38_TRI, 12, 1)
+ FIELD(MIO_MST_TRI1, PIN_37_TRI, 11, 1)
+ FIELD(MIO_MST_TRI1, PIN_36_TRI, 10, 1)
+ FIELD(MIO_MST_TRI1, PIN_35_TRI, 9, 1)
+ FIELD(MIO_MST_TRI1, PIN_34_TRI, 8, 1)
+ FIELD(MIO_MST_TRI1, PIN_33_TRI, 7, 1)
+ FIELD(MIO_MST_TRI1, PIN_32_TRI, 6, 1)
+ FIELD(MIO_MST_TRI1, PIN_31_TRI, 5, 1)
+ FIELD(MIO_MST_TRI1, PIN_30_TRI, 4, 1)
+ FIELD(MIO_MST_TRI1, PIN_29_TRI, 3, 1)
+ FIELD(MIO_MST_TRI1, PIN_28_TRI, 2, 1)
+ FIELD(MIO_MST_TRI1, PIN_27_TRI, 1, 1)
+ FIELD(MIO_MST_TRI1, PIN_26_TRI, 0, 1)
+REG32(BNK1_EN_RX, 0x300)
+ FIELD(BNK1_EN_RX, BNK1_EN_RX, 0, 26)
+REG32(BNK1_SEL_RX0, 0x304)
+REG32(BNK1_SEL_RX1, 0x308)
+ FIELD(BNK1_SEL_RX1, BNK1_SEL_RX, 0, 20)
+REG32(BNK1_EN_RX_SCHMITT_HYST, 0x30c)
+ FIELD(BNK1_EN_RX_SCHMITT_HYST, BNK1_EN_RX_SCHMITT_HYST, 0, 26)
+REG32(BNK1_EN_WK_PD, 0x310)
+ FIELD(BNK1_EN_WK_PD, BNK1_EN_WK_PD, 0, 26)
+REG32(BNK1_EN_WK_PU, 0x314)
+ FIELD(BNK1_EN_WK_PU, BNK1_EN_WK_PU, 0, 26)
+REG32(BNK1_SEL_DRV0, 0x318)
+REG32(BNK1_SEL_DRV1, 0x31c)
+ FIELD(BNK1_SEL_DRV1, BNK1_SEL_DRV, 0, 20)
+REG32(BNK1_SEL_SLEW, 0x320)
+ FIELD(BNK1_SEL_SLEW, BNK1_SEL_SLEW, 0, 26)
+REG32(BNK1_EN_DFT_OPT_INV, 0x324)
+ FIELD(BNK1_EN_DFT_OPT_INV, BNK1_EN_DFT_OPT_INV, 0, 26)
+REG32(BNK1_EN_PAD2PAD_LOOPBACK, 0x328)
+ FIELD(BNK1_EN_PAD2PAD_LOOPBACK, BNK1_EN_PAD2PAD_LOOPBACK, 0, 13)
+REG32(BNK1_RX_SPARE0, 0x32c)
+REG32(BNK1_RX_SPARE1, 0x330)
+ FIELD(BNK1_RX_SPARE1, BNK1_RX_SPARE, 0, 20)
+REG32(BNK1_TX_SPARE0, 0x334)
+REG32(BNK1_TX_SPARE1, 0x338)
+ FIELD(BNK1_TX_SPARE1, BNK1_TX_SPARE, 0, 20)
+REG32(BNK1_SEL_EN1P8, 0x33c)
+ FIELD(BNK1_SEL_EN1P8, BNK1_SEL_EN1P8, 0, 1)
+REG32(BNK1_EN_B_POR_DETECT, 0x340)
+ FIELD(BNK1_EN_B_POR_DETECT, BNK1_EN_B_POR_DETECT, 0, 1)
+REG32(BNK1_LPF_BYP_POR_DETECT, 0x344)
+ FIELD(BNK1_LPF_BYP_POR_DETECT, BNK1_LPF_BYP_POR_DETECT, 0, 1)
+REG32(BNK1_EN_LATCH, 0x348)
+ FIELD(BNK1_EN_LATCH, BNK1_EN_LATCH, 0, 1)
+REG32(BNK1_VBG_LPF_BYP_B, 0x34c)
+ FIELD(BNK1_VBG_LPF_BYP_B, BNK1_VBG_LPF_BYP_B, 0, 1)
+REG32(BNK1_EN_AMP_B, 0x350)
+ FIELD(BNK1_EN_AMP_B, BNK1_EN_AMP_B, 0, 2)
+REG32(BNK1_SPARE_BIAS, 0x354)
+ FIELD(BNK1_SPARE_BIAS, BNK1_SPARE_BIAS, 0, 4)
+REG32(BNK1_DRIVER_BIAS, 0x358)
+ FIELD(BNK1_DRIVER_BIAS, BNK1_DRIVER_BIAS, 0, 15)
+REG32(BNK1_VMODE, 0x35c)
+ FIELD(BNK1_VMODE, BNK1_VMODE, 0, 1)
+REG32(BNK1_SEL_AUX_IO_RX, 0x360)
+ FIELD(BNK1_SEL_AUX_IO_RX, BNK1_SEL_AUX_IO_RX, 0, 26)
+REG32(BNK1_EN_TX_HS_MODE, 0x364)
+ FIELD(BNK1_EN_TX_HS_MODE, BNK1_EN_TX_HS_MODE, 0, 26)
+REG32(SD0_CLK_CTRL, 0x400)
+ FIELD(SD0_CLK_CTRL, SDIO0_FBCLK_SEL, 2, 1)
+ FIELD(SD0_CLK_CTRL, SDIO0_RX_SRC_SEL, 0, 2)
+REG32(SD0_CTRL_REG, 0x404)
+ FIELD(SD0_CTRL_REG, SD0_EMMC_SEL, 0, 1)
+REG32(SD0_CONFIG_REG1, 0x410)
+ FIELD(SD0_CONFIG_REG1, SD0_BASECLK, 7, 8)
+ FIELD(SD0_CONFIG_REG1, SD0_TUNIGCOUNT, 1, 6)
+ FIELD(SD0_CONFIG_REG1, SD0_ASYNCWKPENA, 0, 1)
+REG32(SD0_CONFIG_REG2, 0x414)
+ FIELD(SD0_CONFIG_REG2, SD0_SLOTTYPE, 12, 2)
+ FIELD(SD0_CONFIG_REG2, SD0_ASYCINTR, 11, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_64BIT, 10, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_1P8V, 9, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_3P0V, 8, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_3P3V, 7, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_SUSPRES, 6, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_SDMA, 5, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_HIGHSPEED, 4, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_ADMA2, 3, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_8BIT, 2, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_MAXBLK, 0, 2)
+REG32(SD0_CONFIG_REG3, 0x418)
+ FIELD(SD0_CONFIG_REG3, SD0_TUNINGSDR50, 10, 1)
+ FIELD(SD0_CONFIG_REG3, SD0_RETUNETMR, 6, 4)
+ FIELD(SD0_CONFIG_REG3, SD0_DDRIVER, 5, 1)
+ FIELD(SD0_CONFIG_REG3, SD0_CDRIVER, 4, 1)
+ FIELD(SD0_CONFIG_REG3, SD0_ADRIVER, 3, 1)
+ FIELD(SD0_CONFIG_REG3, SD0_DDR50, 2, 1)
+ FIELD(SD0_CONFIG_REG3, SD0_SDR104, 1, 1)
+ FIELD(SD0_CONFIG_REG3, SD0_SDR50, 0, 1)
+REG32(SD0_INITPRESET, 0x41c)
+ FIELD(SD0_INITPRESET, SD0_INITPRESET, 0, 13)
+REG32(SD0_DSPPRESET, 0x420)
+ FIELD(SD0_DSPPRESET, SD0_DSPPRESET, 0, 13)
+REG32(SD0_HSPDPRESET, 0x424)
+ FIELD(SD0_HSPDPRESET, SD0_HSPDPRESET, 0, 13)
+REG32(SD0_SDR12PRESET, 0x428)
+ FIELD(SD0_SDR12PRESET, SD0_SDR12PRESET, 0, 13)
+REG32(SD0_SDR25PRESET, 0x42c)
+ FIELD(SD0_SDR25PRESET, SD0_SDR25PRESET, 0, 13)
+REG32(SD0_SDR50PRSET, 0x430)
+ FIELD(SD0_SDR50PRSET, SD0_SDR50PRESET, 0, 13)
+REG32(SD0_SDR104PRST, 0x434)
+ FIELD(SD0_SDR104PRST, SD0_SDR104PRESET, 0, 13)
+REG32(SD0_DDR50PRESET, 0x438)
+ FIELD(SD0_DDR50PRESET, SD0_DDR50PRESET, 0, 13)
+REG32(SD0_MAXCUR1P8, 0x43c)
+ FIELD(SD0_MAXCUR1P8, SD0_MAXCUR1P8, 0, 8)
+REG32(SD0_MAXCUR3P0, 0x440)
+ FIELD(SD0_MAXCUR3P0, SD0_MAXCUR3P0, 0, 8)
+REG32(SD0_MAXCUR3P3, 0x444)
+ FIELD(SD0_MAXCUR3P3, SD0_MAXCUR3P3, 0, 8)
+REG32(SD0_DLL_CTRL, 0x448)
+ FIELD(SD0_DLL_CTRL, SD0_CLKSTABLE_CFG, 9, 1)
+ FIELD(SD0_DLL_CTRL, SD0_DLL_CFG, 5, 4)
+ FIELD(SD0_DLL_CTRL, SD0_DLL_PSDONE, 4, 1)
+ FIELD(SD0_DLL_CTRL, SD0_DLL_OVF, 3, 1)
+ FIELD(SD0_DLL_CTRL, SD0_DLL_RST, 2, 1)
+ FIELD(SD0_DLL_CTRL, SD0_DLL_TESTMODE, 1, 1)
+ FIELD(SD0_DLL_CTRL, SD0_DLL_LOCK, 0, 1)
+REG32(SD0_CDN_CTRL, 0x44c)
+ FIELD(SD0_CDN_CTRL, SD0_CDN_CTRL, 0, 1)
+REG32(SD0_DLL_TEST, 0x450)
+ FIELD(SD0_DLL_TEST, DLL_DIV, 16, 8)
+ FIELD(SD0_DLL_TEST, DLL_TX_SEL, 9, 7)
+ FIELD(SD0_DLL_TEST, DLL_RX_SEL, 0, 9)
+REG32(SD0_RX_TUNING_SEL, 0x454)
+ FIELD(SD0_RX_TUNING_SEL, SD0_RX_SEL, 0, 9)
+REG32(SD0_DLL_DIV_MAP0, 0x458)
+ FIELD(SD0_DLL_DIV_MAP0, DIV_3, 24, 8)
+ FIELD(SD0_DLL_DIV_MAP0, DIV_2, 16, 8)
+ FIELD(SD0_DLL_DIV_MAP0, DIV_1, 8, 8)
+ FIELD(SD0_DLL_DIV_MAP0, DIV_0, 0, 8)
+REG32(SD0_DLL_DIV_MAP1, 0x45c)
+ FIELD(SD0_DLL_DIV_MAP1, DIV_7, 24, 8)
+ FIELD(SD0_DLL_DIV_MAP1, DIV_6, 16, 8)
+ FIELD(SD0_DLL_DIV_MAP1, DIV_5, 8, 8)
+ FIELD(SD0_DLL_DIV_MAP1, DIV_4, 0, 8)
+REG32(SD0_IOU_COHERENT_CTRL, 0x460)
+ FIELD(SD0_IOU_COHERENT_CTRL, SD0_AXI_COH, 0, 4)
+REG32(SD0_IOU_INTERCONNECT_ROUTE, 0x464)
+ FIELD(SD0_IOU_INTERCONNECT_ROUTE, SD0, 0, 1)
+REG32(SD0_IOU_RAM, 0x468)
+ FIELD(SD0_IOU_RAM, EMASA0, 6, 1)
+ FIELD(SD0_IOU_RAM, EMAB0, 3, 3)
+ FIELD(SD0_IOU_RAM, EMAA0, 0, 3)
+REG32(SD0_IOU_INTERCONNECT_QOS, 0x46c)
+ FIELD(SD0_IOU_INTERCONNECT_QOS, SD0_QOS, 0, 4)
+REG32(SD1_CLK_CTRL, 0x480)
+ FIELD(SD1_CLK_CTRL, SDIO1_FBCLK_SEL, 1, 1)
+ FIELD(SD1_CLK_CTRL, SDIO1_RX_SRC_SEL, 0, 1)
+REG32(SD1_CTRL_REG, 0x484)
+ FIELD(SD1_CTRL_REG, SD1_EMMC_SEL, 0, 1)
+REG32(SD1_CONFIG_REG1, 0x490)
+ FIELD(SD1_CONFIG_REG1, SD1_BASECLK, 7, 8)
+ FIELD(SD1_CONFIG_REG1, SD1_TUNIGCOUNT, 1, 6)
+ FIELD(SD1_CONFIG_REG1, SD1_ASYNCWKPENA, 0, 1)
+REG32(SD1_CONFIG_REG2, 0x494)
+ FIELD(SD1_CONFIG_REG2, SD1_SLOTTYPE, 12, 2)
+ FIELD(SD1_CONFIG_REG2, SD1_ASYCINTR, 11, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_64BIT, 10, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_1P8V, 9, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_3P0V, 8, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_3P3V, 7, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_SUSPRES, 6, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_SDMA, 5, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_HIGHSPEED, 4, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_ADMA2, 3, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_8BIT, 2, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_MAXBLK, 0, 2)
+REG32(SD1_CONFIG_REG3, 0x498)
+ FIELD(SD1_CONFIG_REG3, SD1_TUNINGSDR50, 10, 1)
+ FIELD(SD1_CONFIG_REG3, SD1_RETUNETMR, 6, 4)
+ FIELD(SD1_CONFIG_REG3, SD1_DDRIVER, 5, 1)
+ FIELD(SD1_CONFIG_REG3, SD1_CDRIVER, 4, 1)
+ FIELD(SD1_CONFIG_REG3, SD1_ADRIVER, 3, 1)
+ FIELD(SD1_CONFIG_REG3, SD1_DDR50, 2, 1)
+ FIELD(SD1_CONFIG_REG3, SD1_SDR104, 1, 1)
+ FIELD(SD1_CONFIG_REG3, SD1_SDR50, 0, 1)
+REG32(SD1_INITPRESET, 0x49c)
+ FIELD(SD1_INITPRESET, SD1_INITPRESET, 0, 13)
+REG32(SD1_DSPPRESET, 0x4a0)
+ FIELD(SD1_DSPPRESET, SD1_DSPPRESET, 0, 13)
+REG32(SD1_HSPDPRESET, 0x4a4)
+ FIELD(SD1_HSPDPRESET, SD1_HSPDPRESET, 0, 13)
+REG32(SD1_SDR12PRESET, 0x4a8)
+ FIELD(SD1_SDR12PRESET, SD1_SDR12PRESET, 0, 13)
+REG32(SD1_SDR25PRESET, 0x4ac)
+ FIELD(SD1_SDR25PRESET, SD1_SDR25PRESET, 0, 13)
+REG32(SD1_SDR50PRSET, 0x4b0)
+ FIELD(SD1_SDR50PRSET, SD1_SDR50PRESET, 0, 13)
+REG32(SD1_SDR104PRST, 0x4b4)
+ FIELD(SD1_SDR104PRST, SD1_SDR104PRESET, 0, 13)
+REG32(SD1_DDR50PRESET, 0x4b8)
+ FIELD(SD1_DDR50PRESET, SD1_DDR50PRESET, 0, 13)
+REG32(SD1_MAXCUR1P8, 0x4bc)
+ FIELD(SD1_MAXCUR1P8, SD1_MAXCUR1P8, 0, 8)
+REG32(SD1_MAXCUR3P0, 0x4c0)
+ FIELD(SD1_MAXCUR3P0, SD1_MAXCUR3P0, 0, 8)
+REG32(SD1_MAXCUR3P3, 0x4c4)
+ FIELD(SD1_MAXCUR3P3, SD1_MAXCUR3P3, 0, 8)
+REG32(SD1_DLL_CTRL, 0x4c8)
+ FIELD(SD1_DLL_CTRL, SD1_CLKSTABLE_CFG, 9, 1)
+ FIELD(SD1_DLL_CTRL, SD1_DLL_CFG, 5, 4)
+ FIELD(SD1_DLL_CTRL, SD1_DLL_PSDONE, 4, 1)
+ FIELD(SD1_DLL_CTRL, SD1_DLL_OVF, 3, 1)
+ FIELD(SD1_DLL_CTRL, SD1_DLL_RST, 2, 1)
+ FIELD(SD1_DLL_CTRL, SD1_DLL_TESTMODE, 1, 1)
+ FIELD(SD1_DLL_CTRL, SD1_DLL_LOCK, 0, 1)
+REG32(SD1_CDN_CTRL, 0x4cc)
+ FIELD(SD1_CDN_CTRL, SD1_CDN_CTRL, 0, 1)
+REG32(SD1_DLL_TEST, 0x4d0)
+ FIELD(SD1_DLL_TEST, DLL_DIV, 16, 8)
+ FIELD(SD1_DLL_TEST, DLL_TX_SEL, 9, 7)
+ FIELD(SD1_DLL_TEST, DLL_RX_SEL, 0, 9)
+REG32(SD1_RX_TUNING_SEL, 0x4d4)
+ FIELD(SD1_RX_TUNING_SEL, SD1_RX_SEL, 0, 9)
+REG32(SD1_DLL_DIV_MAP0, 0x4d8)
+ FIELD(SD1_DLL_DIV_MAP0, DIV_3, 24, 8)
+ FIELD(SD1_DLL_DIV_MAP0, DIV_2, 16, 8)
+ FIELD(SD1_DLL_DIV_MAP0, DIV_1, 8, 8)
+ FIELD(SD1_DLL_DIV_MAP0, DIV_0, 0, 8)
+REG32(SD1_DLL_DIV_MAP1, 0x4dc)
+ FIELD(SD1_DLL_DIV_MAP1, DIV_7, 24, 8)
+ FIELD(SD1_DLL_DIV_MAP1, DIV_6, 16, 8)
+ FIELD(SD1_DLL_DIV_MAP1, DIV_5, 8, 8)
+ FIELD(SD1_DLL_DIV_MAP1, DIV_4, 0, 8)
+REG32(SD1_IOU_COHERENT_CTRL, 0x4e0)
+ FIELD(SD1_IOU_COHERENT_CTRL, SD1_AXI_COH, 0, 4)
+REG32(SD1_IOU_INTERCONNECT_ROUTE, 0x4e4)
+ FIELD(SD1_IOU_INTERCONNECT_ROUTE, SD1, 0, 1)
+REG32(SD1_IOU_RAM, 0x4e8)
+ FIELD(SD1_IOU_RAM, EMASA0, 6, 1)
+ FIELD(SD1_IOU_RAM, EMAB0, 3, 3)
+ FIELD(SD1_IOU_RAM, EMAA0, 0, 3)
+REG32(SD1_IOU_INTERCONNECT_QOS, 0x4ec)
+ FIELD(SD1_IOU_INTERCONNECT_QOS, SD1_QOS, 0, 4)
+REG32(OSPI_QSPI_IOU_AXI_MUX_SEL, 0x504)
+ FIELD(OSPI_QSPI_IOU_AXI_MUX_SEL, OSPI_MUX_SEL, 1, 1)
+ FIELD(OSPI_QSPI_IOU_AXI_MUX_SEL, QSPI_OSPI_MUX_SEL, 0, 1)
+REG32(QSPI_IOU_COHERENT_CTRL, 0x508)
+ FIELD(QSPI_IOU_COHERENT_CTRL, QSPI_AXI_COH, 0, 4)
+REG32(QSPI_IOU_INTERCONNECT_ROUTE, 0x50c)
+ FIELD(QSPI_IOU_INTERCONNECT_ROUTE, QSPI, 0, 1)
+REG32(QSPI_IOU_RAM, 0x510)
+ FIELD(QSPI_IOU_RAM, EMASA1, 13, 1)
+ FIELD(QSPI_IOU_RAM, EMAB1, 10, 3)
+ FIELD(QSPI_IOU_RAM, EMAA1, 7, 3)
+ FIELD(QSPI_IOU_RAM, EMASA0, 6, 1)
+ FIELD(QSPI_IOU_RAM, EMAB0, 3, 3)
+ FIELD(QSPI_IOU_RAM, EMAA0, 0, 3)
+REG32(QSPI_IOU_INTERCONNECT_QOS, 0x514)
+ FIELD(QSPI_IOU_INTERCONNECT_QOS, QSPI_QOS, 0, 4)
+REG32(OSPI_IOU_COHERENT_CTRL, 0x530)
+ FIELD(OSPI_IOU_COHERENT_CTRL, OSPI_AXI_COH, 0, 4)
+REG32(OSPI_IOU_INTERCONNECT_ROUTE, 0x534)
+ FIELD(OSPI_IOU_INTERCONNECT_ROUTE, OSPI, 0, 1)
+REG32(OSPI_IOU_RAM, 0x538)
+ FIELD(OSPI_IOU_RAM, EMAS0, 5, 1)
+ FIELD(OSPI_IOU_RAM, EMAW0, 3, 2)
+ FIELD(OSPI_IOU_RAM, EMA0, 0, 3)
+REG32(OSPI_IOU_INTERCONNECT_QOS, 0x53c)
+ FIELD(OSPI_IOU_INTERCONNECT_QOS, OSPI_QOS, 0, 4)
+REG32(OSPI_REFCLK_DLY_CTRL, 0x540)
+ FIELD(OSPI_REFCLK_DLY_CTRL, DLY1, 3, 2)
+ FIELD(OSPI_REFCLK_DLY_CTRL, DLY0, 0, 3)
+REG32(CUR_PWR_ST, 0x600)
+ FIELD(CUR_PWR_ST, U2PMU, 0, 2)
+REG32(CONNECT_ST, 0x604)
+ FIELD(CONNECT_ST, U2PMU, 0, 1)
+REG32(PW_STATE_REQ, 0x608)
+ FIELD(PW_STATE_REQ, BIT_1_0, 0, 2)
+REG32(HOST_U2_PORT_DISABLE, 0x60c)
+ FIELD(HOST_U2_PORT_DISABLE, BIT_0, 0, 1)
+REG32(DBG_U2PMU, 0x610)
+REG32(DBG_U2PMU_EXT1, 0x614)
+REG32(DBG_U2PMU_EXT2, 0x618)
+ FIELD(DBG_U2PMU_EXT2, BIT_67_64, 0, 4)
+REG32(PME_GEN_U2PMU, 0x61c)
+ FIELD(PME_GEN_U2PMU, BIT_0, 0, 1)
+REG32(PWR_CONFIG_USB2, 0x620)
+ FIELD(PWR_CONFIG_USB2, STRAP, 0, 30)
+REG32(PHY_HUB, 0x624)
+ FIELD(PHY_HUB, VBUS_CTRL, 1, 1)
+ FIELD(PHY_HUB, OVER_CURRENT, 0, 1)
+REG32(CTRL, 0x700)
+ FIELD(CTRL, SLVERR_ENABLE, 0, 1)
+REG32(ISR, 0x800)
+ FIELD(ISR, ADDR_DECODE_ERR, 0, 1)
+REG32(IMR, 0x804)
+ FIELD(IMR, ADDR_DECODE_ERR, 0, 1)
+REG32(IER, 0x808)
+ FIELD(IER, ADDR_DECODE_ERR, 0, 1)
+REG32(IDR, 0x80c)
+ FIELD(IDR, ADDR_DECODE_ERR, 0, 1)
+REG32(ITR, 0x810)
+ FIELD(ITR, ADDR_DECODE_ERR, 0, 1)
+REG32(PARITY_ISR, 0x814)
+ FIELD(PARITY_ISR, PERR_AXI_SD1_IOU, 12, 1)
+ FIELD(PARITY_ISR, PERR_AXI_SD0_IOU, 11, 1)
+ FIELD(PARITY_ISR, PERR_AXI_QSPI_IOU, 10, 1)
+ FIELD(PARITY_ISR, PERR_AXI_OSPI_IOU, 9, 1)
+ FIELD(PARITY_ISR, PERR_IOU_SD1, 8, 1)
+ FIELD(PARITY_ISR, PERR_IOU_SD0, 7, 1)
+ FIELD(PARITY_ISR, PERR_IOU_QSPI1, 6, 1)
+ FIELD(PARITY_ISR, PERR_IOUSLCR_SECURE_APB, 5, 1)
+ FIELD(PARITY_ISR, PERR_IOUSLCR_APB, 4, 1)
+ FIELD(PARITY_ISR, PERR_QSPI0_APB, 3, 1)
+ FIELD(PARITY_ISR, PERR_OSPI_APB, 2, 1)
+ FIELD(PARITY_ISR, PERR_I2C_APB, 1, 1)
+ FIELD(PARITY_ISR, PERR_GPIO_APB, 0, 1)
+REG32(PARITY_IMR, 0x818)
+ FIELD(PARITY_IMR, PERR_AXI_SD1_IOU, 12, 1)
+ FIELD(PARITY_IMR, PERR_AXI_SD0_IOU, 11, 1)
+ FIELD(PARITY_IMR, PERR_AXI_QSPI_IOU, 10, 1)
+ FIELD(PARITY_IMR, PERR_AXI_OSPI_IOU, 9, 1)
+ FIELD(PARITY_IMR, PERR_IOU_SD1, 8, 1)
+ FIELD(PARITY_IMR, PERR_IOU_SD0, 7, 1)
+ FIELD(PARITY_IMR, PERR_IOU_QSPI1, 6, 1)
+ FIELD(PARITY_IMR, PERR_IOUSLCR_SECURE_APB, 5, 1)
+ FIELD(PARITY_IMR, PERR_IOUSLCR_APB, 4, 1)
+ FIELD(PARITY_IMR, PERR_QSPI0_APB, 3, 1)
+ FIELD(PARITY_IMR, PERR_OSPI_APB, 2, 1)
+ FIELD(PARITY_IMR, PERR_I2C_APB, 1, 1)
+ FIELD(PARITY_IMR, PERR_GPIO_APB, 0, 1)
+REG32(PARITY_IER, 0x81c)
+ FIELD(PARITY_IER, PERR_AXI_SD1_IOU, 12, 1)
+ FIELD(PARITY_IER, PERR_AXI_SD0_IOU, 11, 1)
+ FIELD(PARITY_IER, PERR_AXI_QSPI_IOU, 10, 1)
+ FIELD(PARITY_IER, PERR_AXI_OSPI_IOU, 9, 1)
+ FIELD(PARITY_IER, PERR_IOU_SD1, 8, 1)
+ FIELD(PARITY_IER, PERR_IOU_SD0, 7, 1)
+ FIELD(PARITY_IER, PERR_IOU_QSPI1, 6, 1)
+ FIELD(PARITY_IER, PERR_IOUSLCR_SECURE_APB, 5, 1)
+ FIELD(PARITY_IER, PERR_IOUSLCR_APB, 4, 1)
+ FIELD(PARITY_IER, PERR_QSPI0_APB, 3, 1)
+ FIELD(PARITY_IER, PERR_OSPI_APB, 2, 1)
+ FIELD(PARITY_IER, PERR_I2C_APB, 1, 1)
+ FIELD(PARITY_IER, PERR_GPIO_APB, 0, 1)
+REG32(PARITY_IDR, 0x820)
+ FIELD(PARITY_IDR, PERR_AXI_SD1_IOU, 12, 1)
+ FIELD(PARITY_IDR, PERR_AXI_SD0_IOU, 11, 1)
+ FIELD(PARITY_IDR, PERR_AXI_QSPI_IOU, 10, 1)
+ FIELD(PARITY_IDR, PERR_AXI_OSPI_IOU, 9, 1)
+ FIELD(PARITY_IDR, PERR_IOU_SD1, 8, 1)
+ FIELD(PARITY_IDR, PERR_IOU_SD0, 7, 1)
+ FIELD(PARITY_IDR, PERR_IOU_QSPI1, 6, 1)
+ FIELD(PARITY_IDR, PERR_IOUSLCR_SECURE_APB, 5, 1)
+ FIELD(PARITY_IDR, PERR_IOUSLCR_APB, 4, 1)
+ FIELD(PARITY_IDR, PERR_QSPI0_APB, 3, 1)
+ FIELD(PARITY_IDR, PERR_OSPI_APB, 2, 1)
+ FIELD(PARITY_IDR, PERR_I2C_APB, 1, 1)
+ FIELD(PARITY_IDR, PERR_GPIO_APB, 0, 1)
+REG32(PARITY_ITR, 0x824)
+ FIELD(PARITY_ITR, PERR_AXI_SD1_IOU, 12, 1)
+ FIELD(PARITY_ITR, PERR_AXI_SD0_IOU, 11, 1)
+ FIELD(PARITY_ITR, PERR_AXI_QSPI_IOU, 10, 1)
+ FIELD(PARITY_ITR, PERR_AXI_OSPI_IOU, 9, 1)
+ FIELD(PARITY_ITR, PERR_IOU_SD1, 8, 1)
+ FIELD(PARITY_ITR, PERR_IOU_SD0, 7, 1)
+ FIELD(PARITY_ITR, PERR_IOU_QSPI1, 6, 1)
+ FIELD(PARITY_ITR, PERR_IOUSLCR_SECURE_APB, 5, 1)
+ FIELD(PARITY_ITR, PERR_IOUSLCR_APB, 4, 1)
+ FIELD(PARITY_ITR, PERR_QSPI0_APB, 3, 1)
+ FIELD(PARITY_ITR, PERR_OSPI_APB, 2, 1)
+ FIELD(PARITY_ITR, PERR_I2C_APB, 1, 1)
+ FIELD(PARITY_ITR, PERR_GPIO_APB, 0, 1)
+REG32(WPROT0, 0x828)
+ FIELD(WPROT0, ACTIVE, 0, 1)
+
+static void parity_imr_update_irq(XlnxVersalPmcIouSlcr *s)
+{
+ bool pending = s->regs[R_PARITY_ISR] & ~s->regs[R_PARITY_IMR];
+ qemu_set_irq(s->irq_parity_imr, pending);
+}
+
+static void parity_isr_postw(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ parity_imr_update_irq(s);
+}
+
+static uint64_t parity_ier_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val = val64;
+
+ s->regs[R_PARITY_IMR] &= ~val;
+ parity_imr_update_irq(s);
+ return 0;
+}
+
+static uint64_t parity_idr_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val = val64;
+
+ s->regs[R_PARITY_IMR] |= val;
+ parity_imr_update_irq(s);
+ return 0;
+}
+
+static uint64_t parity_itr_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val = val64;
+
+ s->regs[R_PARITY_ISR] |= val;
+ parity_imr_update_irq(s);
+ return 0;
+}
+
+static void imr_update_irq(XlnxVersalPmcIouSlcr *s)
+{
+ bool pending = s->regs[R_ISR] & ~s->regs[R_IMR];
+ qemu_set_irq(s->irq_imr, pending);
+}
+
+static void isr_postw(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ imr_update_irq(s);
+}
+
+static uint64_t ier_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val = val64;
+
+ s->regs[R_IMR] &= ~val;
+ imr_update_irq(s);
+ return 0;
+}
+
+static uint64_t idr_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val = val64;
+
+ s->regs[R_IMR] |= val;
+ imr_update_irq(s);
+ return 0;
+}
+
+static uint64_t itr_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val = val64;
+
+ s->regs[R_ISR] |= val;
+ imr_update_irq(s);
+ return 0;
+}
+
+static uint64_t sd0_ctrl_reg_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t prev = ARRAY_FIELD_EX32(s->regs, SD0_CTRL_REG, SD0_EMMC_SEL);
+
+ if (prev != (val64 & R_SD0_CTRL_REG_SD0_EMMC_SEL_MASK)) {
+ qemu_set_irq(s->sd_emmc_sel[0], !!val64);
+ }
+
+ return val64;
+}
+
+static uint64_t sd1_ctrl_reg_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t prev = ARRAY_FIELD_EX32(s->regs, SD1_CTRL_REG, SD1_EMMC_SEL);
+
+ if (prev != (val64 & R_SD1_CTRL_REG_SD1_EMMC_SEL_MASK)) {
+ qemu_set_irq(s->sd_emmc_sel[1], !!val64);
+ }
+
+ return val64;
+}
+
+static uint64_t ospi_qspi_iou_axi_mux_sel_prew(RegisterInfo *reg,
+ uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val32 = (uint32_t) val64;
+ uint8_t ospi_mux_sel = FIELD_EX32(val32, OSPI_QSPI_IOU_AXI_MUX_SEL,
+ OSPI_MUX_SEL);
+ uint8_t qspi_ospi_mux_sel = FIELD_EX32(val32, OSPI_QSPI_IOU_AXI_MUX_SEL,
+ QSPI_OSPI_MUX_SEL);
+
+ if (ospi_mux_sel !=
+ ARRAY_FIELD_EX32(s->regs, OSPI_QSPI_IOU_AXI_MUX_SEL, OSPI_MUX_SEL)) {
+ qemu_set_irq(s->ospi_mux_sel, !!ospi_mux_sel);
+ }
+
+ if (qspi_ospi_mux_sel !=
+ ARRAY_FIELD_EX32(s->regs, OSPI_QSPI_IOU_AXI_MUX_SEL,
+ QSPI_OSPI_MUX_SEL)) {
+ qemu_set_irq(s->qspi_ospi_mux_sel, !!qspi_ospi_mux_sel);
+ }
+
+ return val64;
+}
+
+static RegisterAccessInfo pmc_iou_slcr_regs_info[] = {
+ { .name = "MIO_PIN_0", .addr = A_MIO_PIN_0,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_1", .addr = A_MIO_PIN_1,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_2", .addr = A_MIO_PIN_2,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_3", .addr = A_MIO_PIN_3,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_4", .addr = A_MIO_PIN_4,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_5", .addr = A_MIO_PIN_5,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_6", .addr = A_MIO_PIN_6,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_7", .addr = A_MIO_PIN_7,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_8", .addr = A_MIO_PIN_8,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_9", .addr = A_MIO_PIN_9,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_10", .addr = A_MIO_PIN_10,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_11", .addr = A_MIO_PIN_11,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_12", .addr = A_MIO_PIN_12,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_13", .addr = A_MIO_PIN_13,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_14", .addr = A_MIO_PIN_14,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_15", .addr = A_MIO_PIN_15,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_16", .addr = A_MIO_PIN_16,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_17", .addr = A_MIO_PIN_17,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_18", .addr = A_MIO_PIN_18,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_19", .addr = A_MIO_PIN_19,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_20", .addr = A_MIO_PIN_20,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_21", .addr = A_MIO_PIN_21,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_22", .addr = A_MIO_PIN_22,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_23", .addr = A_MIO_PIN_23,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_24", .addr = A_MIO_PIN_24,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_25", .addr = A_MIO_PIN_25,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_26", .addr = A_MIO_PIN_26,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_27", .addr = A_MIO_PIN_27,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_28", .addr = A_MIO_PIN_28,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_29", .addr = A_MIO_PIN_29,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_30", .addr = A_MIO_PIN_30,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_31", .addr = A_MIO_PIN_31,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_32", .addr = A_MIO_PIN_32,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_33", .addr = A_MIO_PIN_33,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_34", .addr = A_MIO_PIN_34,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_35", .addr = A_MIO_PIN_35,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_36", .addr = A_MIO_PIN_36,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_37", .addr = A_MIO_PIN_37,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_38", .addr = A_MIO_PIN_38,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_39", .addr = A_MIO_PIN_39,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_40", .addr = A_MIO_PIN_40,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_41", .addr = A_MIO_PIN_41,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_42", .addr = A_MIO_PIN_42,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_43", .addr = A_MIO_PIN_43,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_44", .addr = A_MIO_PIN_44,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_45", .addr = A_MIO_PIN_45,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_46", .addr = A_MIO_PIN_46,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_47", .addr = A_MIO_PIN_47,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_48", .addr = A_MIO_PIN_48,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_49", .addr = A_MIO_PIN_49,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_50", .addr = A_MIO_PIN_50,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_51", .addr = A_MIO_PIN_51,
+ .rsvd = 0xfffffc01,
+ },{ .name = "BNK0_EN_RX", .addr = A_BNK0_EN_RX,
+ .reset = 0x3ffffff,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_SEL_RX0", .addr = A_BNK0_SEL_RX0,
+ .reset = 0xffffffff,
+ },{ .name = "BNK0_SEL_RX1", .addr = A_BNK0_SEL_RX1,
+ .reset = 0xfffff,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK0_EN_RX_SCHMITT_HYST", .addr = A_BNK0_EN_RX_SCHMITT_HYST,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_EN_WK_PD", .addr = A_BNK0_EN_WK_PD,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_EN_WK_PU", .addr = A_BNK0_EN_WK_PU,
+ .reset = 0x3ffffff,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_SEL_DRV0", .addr = A_BNK0_SEL_DRV0,
+ .reset = 0xffffffff,
+ },{ .name = "BNK0_SEL_DRV1", .addr = A_BNK0_SEL_DRV1,
+ .reset = 0xfffff,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK0_SEL_SLEW", .addr = A_BNK0_SEL_SLEW,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_EN_DFT_OPT_INV", .addr = A_BNK0_EN_DFT_OPT_INV,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_EN_PAD2PAD_LOOPBACK",
+ .addr = A_BNK0_EN_PAD2PAD_LOOPBACK,
+ .rsvd = 0xffffe000,
+ },{ .name = "BNK0_RX_SPARE0", .addr = A_BNK0_RX_SPARE0,
+ },{ .name = "BNK0_RX_SPARE1", .addr = A_BNK0_RX_SPARE1,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK0_TX_SPARE0", .addr = A_BNK0_TX_SPARE0,
+ },{ .name = "BNK0_TX_SPARE1", .addr = A_BNK0_TX_SPARE1,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK0_SEL_EN1P8", .addr = A_BNK0_SEL_EN1P8,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK0_EN_B_POR_DETECT", .addr = A_BNK0_EN_B_POR_DETECT,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK0_LPF_BYP_POR_DETECT", .addr = A_BNK0_LPF_BYP_POR_DETECT,
+ .reset = 0x1,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK0_EN_LATCH", .addr = A_BNK0_EN_LATCH,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK0_VBG_LPF_BYP_B", .addr = A_BNK0_VBG_LPF_BYP_B,
+ .reset = 0x1,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK0_EN_AMP_B", .addr = A_BNK0_EN_AMP_B,
+ .rsvd = 0xfffffffc,
+ },{ .name = "BNK0_SPARE_BIAS", .addr = A_BNK0_SPARE_BIAS,
+ .rsvd = 0xfffffff0,
+ },{ .name = "BNK0_DRIVER_BIAS", .addr = A_BNK0_DRIVER_BIAS,
+ .rsvd = 0xffff8000,
+ },{ .name = "BNK0_VMODE", .addr = A_BNK0_VMODE,
+ .rsvd = 0xfffffffe,
+ .ro = 0x1,
+ },{ .name = "BNK0_SEL_AUX_IO_RX", .addr = A_BNK0_SEL_AUX_IO_RX,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_EN_TX_HS_MODE", .addr = A_BNK0_EN_TX_HS_MODE,
+ .rsvd = 0xfc000000,
+ },{ .name = "MIO_MST_TRI0", .addr = A_MIO_MST_TRI0,
+ .reset = 0x3ffffff,
+ .rsvd = 0xfc000000,
+ },{ .name = "MIO_MST_TRI1", .addr = A_MIO_MST_TRI1,
+ .reset = 0x3ffffff,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_EN_RX", .addr = A_BNK1_EN_RX,
+ .reset = 0x3ffffff,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_SEL_RX0", .addr = A_BNK1_SEL_RX0,
+ .reset = 0xffffffff,
+ },{ .name = "BNK1_SEL_RX1", .addr = A_BNK1_SEL_RX1,
+ .reset = 0xfffff,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK1_EN_RX_SCHMITT_HYST", .addr = A_BNK1_EN_RX_SCHMITT_HYST,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_EN_WK_PD", .addr = A_BNK1_EN_WK_PD,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_EN_WK_PU", .addr = A_BNK1_EN_WK_PU,
+ .reset = 0x3ffffff,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_SEL_DRV0", .addr = A_BNK1_SEL_DRV0,
+ .reset = 0xffffffff,
+ },{ .name = "BNK1_SEL_DRV1", .addr = A_BNK1_SEL_DRV1,
+ .reset = 0xfffff,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK1_SEL_SLEW", .addr = A_BNK1_SEL_SLEW,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_EN_DFT_OPT_INV", .addr = A_BNK1_EN_DFT_OPT_INV,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_EN_PAD2PAD_LOOPBACK",
+ .addr = A_BNK1_EN_PAD2PAD_LOOPBACK,
+ .rsvd = 0xffffe000,
+ },{ .name = "BNK1_RX_SPARE0", .addr = A_BNK1_RX_SPARE0,
+ },{ .name = "BNK1_RX_SPARE1", .addr = A_BNK1_RX_SPARE1,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK1_TX_SPARE0", .addr = A_BNK1_TX_SPARE0,
+ },{ .name = "BNK1_TX_SPARE1", .addr = A_BNK1_TX_SPARE1,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK1_SEL_EN1P8", .addr = A_BNK1_SEL_EN1P8,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK1_EN_B_POR_DETECT", .addr = A_BNK1_EN_B_POR_DETECT,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK1_LPF_BYP_POR_DETECT", .addr = A_BNK1_LPF_BYP_POR_DETECT,
+ .reset = 0x1,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK1_EN_LATCH", .addr = A_BNK1_EN_LATCH,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK1_VBG_LPF_BYP_B", .addr = A_BNK1_VBG_LPF_BYP_B,
+ .reset = 0x1,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK1_EN_AMP_B", .addr = A_BNK1_EN_AMP_B,
+ .rsvd = 0xfffffffc,
+ },{ .name = "BNK1_SPARE_BIAS", .addr = A_BNK1_SPARE_BIAS,
+ .rsvd = 0xfffffff0,
+ },{ .name = "BNK1_DRIVER_BIAS", .addr = A_BNK1_DRIVER_BIAS,
+ .rsvd = 0xffff8000,
+ },{ .name = "BNK1_VMODE", .addr = A_BNK1_VMODE,
+ .rsvd = 0xfffffffe,
+ .ro = 0x1,
+ },{ .name = "BNK1_SEL_AUX_IO_RX", .addr = A_BNK1_SEL_AUX_IO_RX,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_EN_TX_HS_MODE", .addr = A_BNK1_EN_TX_HS_MODE,
+ .rsvd = 0xfc000000,
+ },{ .name = "SD0_CLK_CTRL", .addr = A_SD0_CLK_CTRL,
+ .rsvd = 0xfffffff8,
+ },{ .name = "SD0_CTRL_REG", .addr = A_SD0_CTRL_REG,
+ .rsvd = 0xfffffffe,
+ .pre_write = sd0_ctrl_reg_prew,
+ },{ .name = "SD0_CONFIG_REG1", .addr = A_SD0_CONFIG_REG1,
+ .reset = 0x3250,
+ .rsvd = 0xffff8000,
+ },{ .name = "SD0_CONFIG_REG2", .addr = A_SD0_CONFIG_REG2,
+ .reset = 0xffc,
+ .rsvd = 0xffffc000,
+ },{ .name = "SD0_CONFIG_REG3", .addr = A_SD0_CONFIG_REG3,
+ .reset = 0x407,
+ .rsvd = 0xfffff800,
+ },{ .name = "SD0_INITPRESET", .addr = A_SD0_INITPRESET,
+ .reset = 0x100,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_DSPPRESET", .addr = A_SD0_DSPPRESET,
+ .reset = 0x4,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_HSPDPRESET", .addr = A_SD0_HSPDPRESET,
+ .reset = 0x2,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_SDR12PRESET", .addr = A_SD0_SDR12PRESET,
+ .reset = 0x4,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_SDR25PRESET", .addr = A_SD0_SDR25PRESET,
+ .reset = 0x2,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_SDR50PRSET", .addr = A_SD0_SDR50PRSET,
+ .reset = 0x1,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_SDR104PRST", .addr = A_SD0_SDR104PRST,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_DDR50PRESET", .addr = A_SD0_DDR50PRESET,
+ .reset = 0x2,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_MAXCUR1P8", .addr = A_SD0_MAXCUR1P8,
+ .rsvd = 0xffffff00,
+ },{ .name = "SD0_MAXCUR3P0", .addr = A_SD0_MAXCUR3P0,
+ .rsvd = 0xffffff00,
+ },{ .name = "SD0_MAXCUR3P3", .addr = A_SD0_MAXCUR3P3,
+ .rsvd = 0xffffff00,
+ },{ .name = "SD0_DLL_CTRL", .addr = A_SD0_DLL_CTRL,
+ .reset = 0x1,
+ .rsvd = 0xfffffc00,
+ .ro = 0x19,
+ },{ .name = "SD0_CDN_CTRL", .addr = A_SD0_CDN_CTRL,
+ .rsvd = 0xfffffffe,
+ },{ .name = "SD0_DLL_TEST", .addr = A_SD0_DLL_TEST,
+ .rsvd = 0xff000000,
+ },{ .name = "SD0_RX_TUNING_SEL", .addr = A_SD0_RX_TUNING_SEL,
+ .rsvd = 0xfffffe00,
+ .ro = 0x1ff,
+ },{ .name = "SD0_DLL_DIV_MAP0", .addr = A_SD0_DLL_DIV_MAP0,
+ .reset = 0x50505050,
+ },{ .name = "SD0_DLL_DIV_MAP1", .addr = A_SD0_DLL_DIV_MAP1,
+ .reset = 0x50505050,
+ },{ .name = "SD0_IOU_COHERENT_CTRL", .addr = A_SD0_IOU_COHERENT_CTRL,
+ .rsvd = 0xfffffff0,
+ },{ .name = "SD0_IOU_INTERCONNECT_ROUTE",
+ .addr = A_SD0_IOU_INTERCONNECT_ROUTE,
+ .rsvd = 0xfffffffe,
+ },{ .name = "SD0_IOU_RAM", .addr = A_SD0_IOU_RAM,
+ .reset = 0x24,
+ .rsvd = 0xffffff80,
+ },{ .name = "SD0_IOU_INTERCONNECT_QOS",
+ .addr = A_SD0_IOU_INTERCONNECT_QOS,
+ .rsvd = 0xfffffff0,
+ },{ .name = "SD1_CLK_CTRL", .addr = A_SD1_CLK_CTRL,
+ .rsvd = 0xfffffffc,
+ },{ .name = "SD1_CTRL_REG", .addr = A_SD1_CTRL_REG,
+ .rsvd = 0xfffffffe,
+ .pre_write = sd1_ctrl_reg_prew,
+ },{ .name = "SD1_CONFIG_REG1", .addr = A_SD1_CONFIG_REG1,
+ .reset = 0x3250,
+ .rsvd = 0xffff8000,
+ },{ .name = "SD1_CONFIG_REG2", .addr = A_SD1_CONFIG_REG2,
+ .reset = 0xffc,
+ .rsvd = 0xffffc000,
+ },{ .name = "SD1_CONFIG_REG3", .addr = A_SD1_CONFIG_REG3,
+ .reset = 0x407,
+ .rsvd = 0xfffff800,
+ },{ .name = "SD1_INITPRESET", .addr = A_SD1_INITPRESET,
+ .reset = 0x100,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_DSPPRESET", .addr = A_SD1_DSPPRESET,
+ .reset = 0x4,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_HSPDPRESET", .addr = A_SD1_HSPDPRESET,
+ .reset = 0x2,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_SDR12PRESET", .addr = A_SD1_SDR12PRESET,
+ .reset = 0x4,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_SDR25PRESET", .addr = A_SD1_SDR25PRESET,
+ .reset = 0x2,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_SDR50PRSET", .addr = A_SD1_SDR50PRSET,
+ .reset = 0x1,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_SDR104PRST", .addr = A_SD1_SDR104PRST,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_DDR50PRESET", .addr = A_SD1_DDR50PRESET,
+ .reset = 0x2,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_MAXCUR1P8", .addr = A_SD1_MAXCUR1P8,
+ .rsvd = 0xffffff00,
+ },{ .name = "SD1_MAXCUR3P0", .addr = A_SD1_MAXCUR3P0,
+ .rsvd = 0xffffff00,
+ },{ .name = "SD1_MAXCUR3P3", .addr = A_SD1_MAXCUR3P3,
+ .rsvd = 0xffffff00,
+ },{ .name = "SD1_DLL_CTRL", .addr = A_SD1_DLL_CTRL,
+ .reset = 0x1,
+ .rsvd = 0xfffffc00,
+ .ro = 0x19,
+ },{ .name = "SD1_CDN_CTRL", .addr = A_SD1_CDN_CTRL,
+ .rsvd = 0xfffffffe,
+ },{ .name = "SD1_DLL_TEST", .addr = A_SD1_DLL_TEST,
+ .rsvd = 0xff000000,
+ },{ .name = "SD1_RX_TUNING_SEL", .addr = A_SD1_RX_TUNING_SEL,
+ .rsvd = 0xfffffe00,
+ .ro = 0x1ff,
+ },{ .name = "SD1_DLL_DIV_MAP0", .addr = A_SD1_DLL_DIV_MAP0,
+ .reset = 0x50505050,
+ },{ .name = "SD1_DLL_DIV_MAP1", .addr = A_SD1_DLL_DIV_MAP1,
+ .reset = 0x50505050,
+ },{ .name = "SD1_IOU_COHERENT_CTRL", .addr = A_SD1_IOU_COHERENT_CTRL,
+ .rsvd = 0xfffffff0,
+ },{ .name = "SD1_IOU_INTERCONNECT_ROUTE",
+ .addr = A_SD1_IOU_INTERCONNECT_ROUTE,
+ .rsvd = 0xfffffffe,
+ },{ .name = "SD1_IOU_RAM", .addr = A_SD1_IOU_RAM,
+ .reset = 0x24,
+ .rsvd = 0xffffff80,
+ },{ .name = "SD1_IOU_INTERCONNECT_QOS",
+ .addr = A_SD1_IOU_INTERCONNECT_QOS,
+ .rsvd = 0xfffffff0,
+ },{ .name = "OSPI_QSPI_IOU_AXI_MUX_SEL",
+ .addr = A_OSPI_QSPI_IOU_AXI_MUX_SEL,
+ .reset = 0x1,
+ .rsvd = 0xfffffffc,
+ .pre_write = ospi_qspi_iou_axi_mux_sel_prew,
+ },{ .name = "QSPI_IOU_COHERENT_CTRL", .addr = A_QSPI_IOU_COHERENT_CTRL,
+ .rsvd = 0xfffffff0,
+ },{ .name = "QSPI_IOU_INTERCONNECT_ROUTE",
+ .addr = A_QSPI_IOU_INTERCONNECT_ROUTE,
+ .rsvd = 0xfffffffe,
+ },{ .name = "QSPI_IOU_RAM", .addr = A_QSPI_IOU_RAM,
+ .reset = 0x1224,
+ .rsvd = 0xffffc000,
+ },{ .name = "QSPI_IOU_INTERCONNECT_QOS",
+ .addr = A_QSPI_IOU_INTERCONNECT_QOS,
+ .rsvd = 0xfffffff0,
+ },{ .name = "OSPI_IOU_COHERENT_CTRL", .addr = A_OSPI_IOU_COHERENT_CTRL,
+ .rsvd = 0xfffffff0,
+ },{ .name = "OSPI_IOU_INTERCONNECT_ROUTE",
+ .addr = A_OSPI_IOU_INTERCONNECT_ROUTE,
+ .rsvd = 0xfffffffe,
+ },{ .name = "OSPI_IOU_RAM", .addr = A_OSPI_IOU_RAM,
+ .reset = 0xa,
+ .rsvd = 0xffffffc0,
+ },{ .name = "OSPI_IOU_INTERCONNECT_QOS",
+ .addr = A_OSPI_IOU_INTERCONNECT_QOS,
+ .rsvd = 0xfffffff0,
+ },{ .name = "OSPI_REFCLK_DLY_CTRL", .addr = A_OSPI_REFCLK_DLY_CTRL,
+ .reset = 0x13,
+ .rsvd = 0xffffffe0,
+ },{ .name = "CUR_PWR_ST", .addr = A_CUR_PWR_ST,
+ .rsvd = 0xfffffffc,
+ .ro = 0x3,
+ },{ .name = "CONNECT_ST", .addr = A_CONNECT_ST,
+ .rsvd = 0xfffffffe,
+ .ro = 0x1,
+ },{ .name = "PW_STATE_REQ", .addr = A_PW_STATE_REQ,
+ .rsvd = 0xfffffffc,
+ },{ .name = "HOST_U2_PORT_DISABLE", .addr = A_HOST_U2_PORT_DISABLE,
+ .rsvd = 0xfffffffe,
+ },{ .name = "DBG_U2PMU", .addr = A_DBG_U2PMU,
+ .ro = 0xffffffff,
+ },{ .name = "DBG_U2PMU_EXT1", .addr = A_DBG_U2PMU_EXT1,
+ .ro = 0xffffffff,
+ },{ .name = "DBG_U2PMU_EXT2", .addr = A_DBG_U2PMU_EXT2,
+ .rsvd = 0xfffffff0,
+ .ro = 0xf,
+ },{ .name = "PME_GEN_U2PMU", .addr = A_PME_GEN_U2PMU,
+ .rsvd = 0xfffffffe,
+ .ro = 0x1,
+ },{ .name = "PWR_CONFIG_USB2", .addr = A_PWR_CONFIG_USB2,
+ .rsvd = 0xc0000000,
+ },{ .name = "PHY_HUB", .addr = A_PHY_HUB,
+ .rsvd = 0xfffffffc,
+ .ro = 0x2,
+ },{ .name = "CTRL", .addr = A_CTRL,
+ },{ .name = "ISR", .addr = A_ISR,
+ .w1c = 0x1,
+ .post_write = isr_postw,
+ },{ .name = "IMR", .addr = A_IMR,
+ .reset = 0x1,
+ .ro = 0x1,
+ },{ .name = "IER", .addr = A_IER,
+ .pre_write = ier_prew,
+ },{ .name = "IDR", .addr = A_IDR,
+ .pre_write = idr_prew,
+ },{ .name = "ITR", .addr = A_ITR,
+ .pre_write = itr_prew,
+ },{ .name = "PARITY_ISR", .addr = A_PARITY_ISR,
+ .w1c = 0x1fff,
+ .post_write = parity_isr_postw,
+ },{ .name = "PARITY_IMR", .addr = A_PARITY_IMR,
+ .reset = 0x1fff,
+ .ro = 0x1fff,
+ },{ .name = "PARITY_IER", .addr = A_PARITY_IER,
+ .pre_write = parity_ier_prew,
+ },{ .name = "PARITY_IDR", .addr = A_PARITY_IDR,
+ .pre_write = parity_idr_prew,
+ },{ .name = "PARITY_ITR", .addr = A_PARITY_ITR,
+ .pre_write = parity_itr_prew,
+ },{ .name = "WPROT0", .addr = A_WPROT0,
+ .reset = 0x1,
+ }
+};
+
+static void xlnx_versal_pmc_iou_slcr_reset_init(Object *obj, ResetType type)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(obj);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
+ register_reset(&s->regs_info[i]);
+ }
+}
+
+static void xlnx_versal_pmc_iou_slcr_reset_hold(Object *obj)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(obj);
+
+ parity_imr_update_irq(s);
+ imr_update_irq(s);
+
+ /*
+ * Setup OSPI_QSPI mux
+ * By default axi slave interface is enabled for ospi-dma
+ */
+ qemu_set_irq(s->ospi_mux_sel, 0);
+ qemu_set_irq(s->qspi_ospi_mux_sel, 1);
+}
+
+static const MemoryRegionOps pmc_iou_slcr_ops = {
+ .read = register_read_memory,
+ .write = register_write_memory,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void xlnx_versal_pmc_iou_slcr_realize(DeviceState *dev, Error **errp)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(dev);
+
+ qdev_init_gpio_out_named(dev, s->sd_emmc_sel, "sd-emmc-sel", 2);
+ qdev_init_gpio_out_named(dev, &s->qspi_ospi_mux_sel,
+ "qspi-ospi-mux-sel", 1);
+ qdev_init_gpio_out_named(dev, &s->ospi_mux_sel, "ospi-mux-sel", 1);
+}
+
+static void xlnx_versal_pmc_iou_slcr_init(Object *obj)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ RegisterInfoArray *reg_array;
+
+ memory_region_init(&s->iomem, obj, TYPE_XILINX_VERSAL_PMC_IOU_SLCR,
+ XILINX_VERSAL_PMC_IOU_SLCR_R_MAX * 4);
+ reg_array =
+ register_init_block32(DEVICE(obj), pmc_iou_slcr_regs_info,
+ ARRAY_SIZE(pmc_iou_slcr_regs_info),
+ s->regs_info, s->regs,
+ &pmc_iou_slcr_ops,
+ XILINX_VERSAL_PMC_IOU_SLCR_ERR_DEBUG,
+ XILINX_VERSAL_PMC_IOU_SLCR_R_MAX * 4);
+ memory_region_add_subregion(&s->iomem,
+ 0x0,
+ &reg_array->mem);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->irq_parity_imr);
+ sysbus_init_irq(sbd, &s->irq_imr);
+}
+
+static const VMStateDescription vmstate_pmc_iou_slcr = {
+ .name = TYPE_XILINX_VERSAL_PMC_IOU_SLCR,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, XlnxVersalPmcIouSlcr,
+ XILINX_VERSAL_PMC_IOU_SLCR_R_MAX),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
+static void xlnx_versal_pmc_iou_slcr_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->realize = xlnx_versal_pmc_iou_slcr_realize;
+ dc->vmsd = &vmstate_pmc_iou_slcr;
+ rc->phases.enter = xlnx_versal_pmc_iou_slcr_reset_init;
+ rc->phases.hold = xlnx_versal_pmc_iou_slcr_reset_hold;
+}
+
+static const TypeInfo xlnx_versal_pmc_iou_slcr_info = {
+ .name = TYPE_XILINX_VERSAL_PMC_IOU_SLCR,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(XlnxVersalPmcIouSlcr),
+ .class_init = xlnx_versal_pmc_iou_slcr_class_init,
+ .instance_init = xlnx_versal_pmc_iou_slcr_init,
+};
+
+static void xlnx_versal_pmc_iou_slcr_register_types(void)
+{
+ type_register_static(&xlnx_versal_pmc_iou_slcr_info);
+}
+
+type_init(xlnx_versal_pmc_iou_slcr_register_types)
diff --git a/hw/net/can/can_kvaser_pci.c b/hw/net/can/can_kvaser_pci.c
index 168b3a620d..94b3a534f8 100644
--- a/hw/net/can/can_kvaser_pci.c
+++ b/hw/net/can/can_kvaser_pci.c
@@ -266,7 +266,6 @@ static const VMStateDescription vmstate_kvaser_pci = {
.name = "kvaser_pci",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, KvaserPCIState),
/* Load this before sja_state. */
diff --git a/hw/net/can/can_mioe3680_pci.c b/hw/net/can/can_mioe3680_pci.c
index 7a79e2605a..29dc696f7c 100644
--- a/hw/net/can/can_mioe3680_pci.c
+++ b/hw/net/can/can_mioe3680_pci.c
@@ -203,7 +203,6 @@ static const VMStateDescription vmstate_mioe3680_pci = {
.name = "mioe3680_pci",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, Mioe3680PCIState),
VMSTATE_STRUCT(sja_state[0], Mioe3680PCIState, 0, vmstate_can_sja,
diff --git a/hw/net/can/can_pcm3680_pci.c b/hw/net/can/can_pcm3680_pci.c
index 8ef4e74af0..e8e57f4f33 100644
--- a/hw/net/can/can_pcm3680_pci.c
+++ b/hw/net/can/can_pcm3680_pci.c
@@ -204,7 +204,6 @@ static const VMStateDescription vmstate_pcm3680i_pci = {
.name = "pcm3680i_pci",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, Pcm3680iPCIState),
VMSTATE_STRUCT(sja_state[0], Pcm3680iPCIState, 0,
diff --git a/hw/net/can/can_sja1000.c b/hw/net/can/can_sja1000.c
index 34eea684ce..3ba803e947 100644
--- a/hw/net/can/can_sja1000.c
+++ b/hw/net/can/can_sja1000.c
@@ -928,7 +928,6 @@ const VMStateDescription vmstate_qemu_can_filter = {
.name = "qemu_can_filter",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(can_id, qemu_can_filter),
VMSTATE_UINT32(can_mask, qemu_can_filter),
@@ -952,7 +951,6 @@ const VMStateDescription vmstate_can_sja = {
.name = "can_sja",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.post_load = can_sja_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT8(mode, CanSJA1000State),
diff --git a/hw/net/can/ctucan_core.c b/hw/net/can/ctucan_core.c
index d171c372e0..f2c3b6a706 100644
--- a/hw/net/can/ctucan_core.c
+++ b/hw/net/can/ctucan_core.c
@@ -617,7 +617,6 @@ const VMStateDescription vmstate_qemu_ctucan_tx_buffer = {
.name = "qemu_ctucan_tx_buffer",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT8_ARRAY(data, CtuCanCoreMsgBuffer, CTUCAN_CORE_MSG_MAX_LEN),
VMSTATE_END_OF_LIST()
@@ -636,7 +635,6 @@ const VMStateDescription vmstate_ctucan = {
.name = "ctucan",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.post_load = ctucan_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT32(mode_settings.u32, CtuCanCoreState),
diff --git a/hw/net/can/ctucan_pci.c b/hw/net/can/ctucan_pci.c
index f1c86cd06a..50f4ea6cd6 100644
--- a/hw/net/can/ctucan_pci.c
+++ b/hw/net/can/ctucan_pci.c
@@ -215,7 +215,6 @@ static const VMStateDescription vmstate_ctucan_pci = {
.name = "ctucan_pci",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, CtuCanPCIState),
VMSTATE_STRUCT(ctucan_state[0], CtuCanPCIState, 0, vmstate_ctucan,
diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c
index 7fb35dc031..aafd46b635 100644
--- a/hw/pci-host/pnv_phb3.c
+++ b/hw/pci-host/pnv_phb3.c
@@ -792,7 +792,9 @@ static void pnv_phb3_translate_tve(PnvPhb3DMASpace *ds, hwaddr addr,
sh = tbl_shift * lev + tce_shift;
/* TODO: Multi-level untested */
- while ((lev--) >= 0) {
+ do {
+ lev--;
+
/* Grab the TCE address */
taddr = base | (((addr >> sh) & ((1ul << tbl_shift) - 1)) << 3);
if (dma_memory_read(&address_space_memory, taddr, &tce,
@@ -813,21 +815,22 @@ static void pnv_phb3_translate_tve(PnvPhb3DMASpace *ds, hwaddr addr,
}
sh -= tbl_shift;
base = tce & ~0xfffull;
- }
+ } while (lev >= 0);
/* We exit the loop with TCE being the final TCE */
- tce_mask = ~((1ull << tce_shift) - 1);
- tlb->iova = addr & tce_mask;
- tlb->translated_addr = tce & tce_mask;
- tlb->addr_mask = ~tce_mask;
- tlb->perm = tce & 3;
if ((is_write & !(tce & 2)) || ((!is_write) && !(tce & 1))) {
phb3_error(phb, "TCE access fault at 0x%"PRIx64, taddr);
phb3_error(phb, " xlate %"PRIx64":%c TVE=%"PRIx64, addr,
is_write ? 'W' : 'R', tve);
phb3_error(phb, " tta=%"PRIx64" lev=%d tts=%d tps=%d",
tta, lev, tts, tps);
+ return;
}
+ tce_mask = ~((1ull << tce_shift) - 1);
+ tlb->iova = addr & tce_mask;
+ tlb->translated_addr = tce & tce_mask;
+ tlb->addr_mask = ~tce_mask;
+ tlb->perm = tce & 3;
}
}
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index a78add75b0..e91249ef64 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -1267,7 +1267,9 @@ static void pnv_phb4_translate_tve(PnvPhb4DMASpace *ds, hwaddr addr,
/* TODO: Limit to support IO page sizes */
/* TODO: Multi-level untested */
- while ((lev--) >= 0) {
+ do {
+ lev--;
+
/* Grab the TCE address */
taddr = base | (((addr >> sh) & ((1ul << tbl_shift) - 1)) << 3);
if (dma_memory_read(&address_space_memory, taddr, &tce,
@@ -1288,21 +1290,22 @@ static void pnv_phb4_translate_tve(PnvPhb4DMASpace *ds, hwaddr addr,
}
sh -= tbl_shift;
base = tce & ~0xfffull;
- }
+ } while (lev >= 0);
/* We exit the loop with TCE being the final TCE */
- tce_mask = ~((1ull << tce_shift) - 1);
- tlb->iova = addr & tce_mask;
- tlb->translated_addr = tce & tce_mask;
- tlb->addr_mask = ~tce_mask;
- tlb->perm = tce & 3;
if ((is_write & !(tce & 2)) || ((!is_write) && !(tce & 1))) {
phb_error(ds->phb, "TCE access fault at 0x%"PRIx64, taddr);
phb_error(ds->phb, " xlate %"PRIx64":%c TVE=%"PRIx64, addr,
is_write ? 'W' : 'R', tve);
phb_error(ds->phb, " tta=%"PRIx64" lev=%d tts=%d tps=%d",
tta, lev, tts, tps);
+ return;
}
+ tce_mask = ~((1ull << tce_shift) - 1);
+ tlb->iova = addr & tce_mask;
+ tlb->translated_addr = tce & tce_mask;
+ tlb->addr_mask = ~tce_mask;
+ tlb->perm = tce & 3;
}
}
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index bb5bee9a33..462c87dba8 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -1049,7 +1049,6 @@ const VMStateDescription vmstate_ppc_timebase = {
.name = "timebase",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.pre_save = timebase_pre_save,
.fields = (VMStateField []) {
VMSTATE_UINT64(guest_timebase, PPCTimebase),
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 72f5dce751..3d6ec309dd 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -3053,7 +3053,7 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
- if (d) {
+ if (d && bus) {
void *spapr = CAST(void, bus->parent, "spapr-vscsi");
VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index a57ba70a87..a781e97f8d 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -37,6 +37,11 @@ static void spapr_reset_vcpu(PowerPCCPU *cpu)
cpu_reset(cs);
+ /*
+ * "PowerPC Processor binding to IEEE 1275" defines the initial MSR state
+ * as 32bit (MSR_SF=0) in "8.2.1. Initial Register Values".
+ */
+ env->msr &= ~(1ULL << MSR_SF);
env->spr[SPR_HIOR] = 0;
lpcr = env->spr[SPR_LPCR];
diff --git a/hw/ppc/spapr_rtc.c b/hw/ppc/spapr_rtc.c
index fba4dfca35..94a5510e4e 100644
--- a/hw/ppc/spapr_rtc.c
+++ b/hw/ppc/spapr_rtc.c
@@ -26,9 +26,9 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
+#include "sysemu/rtc.h"
#include "hw/ppc/spapr.h"
#include "migration/vmstate.h"
#include "qapi/error.h"
diff --git a/hw/ppc/spapr_vof.c b/hw/ppc/spapr_vof.c
index 40ce8fe003..a33f940c32 100644
--- a/hw/ppc/spapr_vof.c
+++ b/hw/ppc/spapr_vof.c
@@ -88,8 +88,6 @@ void spapr_vof_reset(SpaprMachineState *spapr, void *fdt, Error **errp)
spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT,
stack_ptr, spapr->initrd_base,
spapr->initrd_size);
- /* VOF is 32bit BE so enforce MSR here */
- first_ppc_cpu->env.msr &= ~((1ULL << MSR_SF) | (1ULL << MSR_LE));
/*
* At this point the expected allocation map is:
diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c
index 73adc44ec2..2b63a62875 100644
--- a/hw/ppc/vof.c
+++ b/hw/ppc/vof.c
@@ -16,7 +16,6 @@
#include "qemu/units.h"
#include "qemu/log.h"
#include "qapi/error.h"
-#include "exec/ram_addr.h"
#include "exec/address-spaces.h"
#include "hw/ppc/vof.h"
#include "hw/ppc/fdt.h"
diff --git a/hw/rtc/allwinner-rtc.c b/hw/rtc/allwinner-rtc.c
index 5606a51d5c..7e493f0e79 100644
--- a/hw/rtc/allwinner-rtc.c
+++ b/hw/rtc/allwinner-rtc.c
@@ -23,9 +23,9 @@
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "qemu-common.h"
#include "hw/qdev-properties.h"
#include "hw/rtc/allwinner-rtc.h"
+#include "sysemu/rtc.h"
#include "trace.h"
/* RTC registers */
diff --git a/hw/rtc/aspeed_rtc.c b/hw/rtc/aspeed_rtc.c
index 3ca1183558..f6da7b666d 100644
--- a/hw/rtc/aspeed_rtc.c
+++ b/hw/rtc/aspeed_rtc.c
@@ -7,11 +7,11 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/rtc/aspeed_rtc.h"
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "qemu/timer.h"
+#include "sysemu/rtc.h"
#include "trace.h"
diff --git a/hw/rtc/ds1338.c b/hw/rtc/ds1338.c
index bc5ce1a9f4..36d8121ddd 100644
--- a/hw/rtc/ds1338.c
+++ b/hw/rtc/ds1338.c
@@ -11,12 +11,12 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/i2c/i2c.h"
#include "migration/vmstate.h"
#include "qemu/bcd.h"
#include "qemu/module.h"
#include "qom/object.h"
+#include "sysemu/rtc.h"
/* Size of NVRAM including both the user-accessible area and the
* secondary register area.
diff --git a/hw/rtc/exynos4210_rtc.c b/hw/rtc/exynos4210_rtc.c
index 45c0a951c4..ae67641de6 100644
--- a/hw/rtc/exynos4210_rtc.c
+++ b/hw/rtc/exynos4210_rtc.c
@@ -26,7 +26,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "hw/sysbus.h"
@@ -39,6 +38,7 @@
#include "hw/arm/exynos4210.h"
#include "qom/object.h"
+#include "sysemu/rtc.h"
#define DEBUG_RTC 0
diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c
index e07ff0164e..35e493be31 100644
--- a/hw/rtc/goldfish_rtc.c
+++ b/hw/rtc/goldfish_rtc.c
@@ -20,7 +20,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/rtc/goldfish_rtc.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
@@ -29,6 +28,7 @@
#include "qemu/bitops.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
+#include "sysemu/rtc.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
diff --git a/hw/rtc/m41t80.c b/hw/rtc/m41t80.c
index 396d110ba2..a00971a67e 100644
--- a/hw/rtc/m41t80.c
+++ b/hw/rtc/m41t80.c
@@ -8,13 +8,13 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/timer.h"
#include "qemu/bcd.h"
#include "hw/i2c/i2c.h"
#include "qom/object.h"
+#include "sysemu/rtc.h"
#define TYPE_M41T80 "m41t80"
OBJECT_DECLARE_SIMPLE_TYPE(M41t80State, M41T80)
diff --git a/hw/rtc/m48t59.c b/hw/rtc/m48t59.c
index 690f4e071a..74345d9d90 100644
--- a/hw/rtc/m48t59.c
+++ b/hw/rtc/m48t59.c
@@ -24,12 +24,12 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/rtc/m48t59.h"
#include "qemu/timer.h"
#include "sysemu/runstate.h"
+#include "sysemu/rtc.h"
#include "sysemu/sysemu.h"
#include "hw/sysbus.h"
#include "qapi/error.h"
diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c
index 4fbafddb22..e61a0cced4 100644
--- a/hw/rtc/mc146818rtc.c
+++ b/hw/rtc/mc146818rtc.c
@@ -23,7 +23,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/cutils.h"
#include "qemu/module.h"
#include "qemu/bcd.h"
@@ -36,6 +35,7 @@
#include "sysemu/replay.h"
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
+#include "sysemu/rtc.h"
#include "hw/rtc/mc146818rtc.h"
#include "hw/rtc/mc146818rtc_regs.h"
#include "migration/vmstate.h"
diff --git a/hw/rtc/pl031.c b/hw/rtc/pl031.c
index e7ced90b02..38d9d3c2f3 100644
--- a/hw/rtc/pl031.c
+++ b/hw/rtc/pl031.c
@@ -12,7 +12,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/rtc/pl031.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
@@ -20,6 +19,7 @@
#include "hw/sysbus.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
+#include "sysemu/rtc.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
#include "qemu/module.h"
diff --git a/hw/rtc/twl92230.c b/hw/rtc/twl92230.c
index 0922df5ad3..e8d5eda3fc 100644
--- a/hw/rtc/twl92230.c
+++ b/hw/rtc/twl92230.c
@@ -20,13 +20,13 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/timer.h"
#include "hw/i2c/i2c.h"
#include "hw/irq.h"
#include "migration/qemu-file-types.h"
#include "migration/vmstate.h"
#include "sysemu/sysemu.h"
+#include "sysemu/rtc.h"
#include "qemu/bcd.h"
#include "qemu/module.h"
#include "qom/object.h"
diff --git a/hw/rtc/xlnx-zynqmp-rtc.c b/hw/rtc/xlnx-zynqmp-rtc.c
index 2bcd14d779..3e7d61a41c 100644
--- a/hw/rtc/xlnx-zynqmp-rtc.c
+++ b/hw/rtc/xlnx-zynqmp-rtc.c
@@ -25,7 +25,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/sysbus.h"
#include "hw/register.h"
#include "qemu/bitops.h"
@@ -34,6 +33,7 @@
#include "hw/irq.h"
#include "qemu/cutils.h"
#include "sysemu/sysemu.h"
+#include "sysemu/rtc.h"
#include "trace.h"
#include "hw/rtc/xlnx-zynqmp-rtc.h"
#include "migration/vmstate.h"
diff --git a/hw/s390x/tod-tcg.c b/hw/s390x/tod-tcg.c
index 9bb94ff72b..7646b4aa38 100644
--- a/hw/s390x/tod-tcg.c
+++ b/hw/s390x/tod-tcg.c
@@ -9,7 +9,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qapi/error.h"
#include "hw/s390x/tod.h"
#include "qemu/timer.h"
@@ -17,6 +16,7 @@
#include "qemu/module.h"
#include "cpu.h"
#include "tcg/tcg_s390x.h"
+#include "sysemu/rtc.h"
static void qemu_s390_tod_get(const S390TODState *td, S390TOD *tod,
Error **errp)
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index c9da5ce0b5..cd43945827 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -19,11 +19,11 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/pci/pci.h"
#include "hw/qdev-properties.h"
#include "sysemu/dma.h"
#include "sysemu/block-backend.h"
+#include "sysemu/rtc.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "qemu/iov.h"
@@ -2315,7 +2315,6 @@ static const VMStateDescription vmstate_megasas_gen2 = {
.name = "megasas-gen2",
.version_id = 0,
.minimum_version_id = 0,
- .minimum_version_id_old = 0,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj, MegasasState),
VMSTATE_MSIX(parent_obj, MegasasState),
diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
index 5181b0c0b0..706cf0df3a 100644
--- a/hw/scsi/mptsas.c
+++ b/hw/scsi/mptsas.c
@@ -1363,7 +1363,6 @@ static const VMStateDescription vmstate_mptsas = {
.name = "mptsas",
.version_id = 0,
.minimum_version_id = 0,
- .minimum_version_id_old = 0,
.post_load = mptsas_post_load,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, MPTSASState),
diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build
index 3d6bc82ab1..0ded9cd092 100644
--- a/hw/ssi/meson.build
+++ b/hw/ssi/meson.build
@@ -7,5 +7,6 @@ softmmu_ss.add(when: 'CONFIG_SSI', if_true: files('ssi.c'))
softmmu_ss.add(when: 'CONFIG_STM32F2XX_SPI', if_true: files('stm32f2xx_spi.c'))
softmmu_ss.add(when: 'CONFIG_XILINX_SPI', if_true: files('xilinx_spi.c'))
softmmu_ss.add(when: 'CONFIG_XILINX_SPIPS', if_true: files('xilinx_spips.c'))
+softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-ospi.c'))
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi.c'))
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c'))
diff --git a/hw/ssi/xlnx-versal-ospi.c b/hw/ssi/xlnx-versal-ospi.c
new file mode 100644
index 0000000000..7ecd148fdf
--- /dev/null
+++ b/hw/ssi/xlnx-versal-ospi.c
@@ -0,0 +1,1853 @@
+/*
+ * QEMU model of Xilinx Versal's OSPI controller.
+ *
+ * Copyright (c) 2021 Xilinx Inc.
+ * Written by Francisco Iglesias <francisco.iglesias@xilinx.com>
+ *
+ * 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/sysbus.h"
+#include "migration/vmstate.h"
+#include "hw/qdev-properties.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "hw/irq.h"
+#include "hw/ssi/xlnx-versal-ospi.h"
+
+#ifndef XILINX_VERSAL_OSPI_ERR_DEBUG
+#define XILINX_VERSAL_OSPI_ERR_DEBUG 0
+#endif
+
+REG32(CONFIG_REG, 0x0)
+ FIELD(CONFIG_REG, IDLE_FLD, 31, 1)
+ FIELD(CONFIG_REG, DUAL_BYTE_OPCODE_EN_FLD, 30, 1)
+ FIELD(CONFIG_REG, CRC_ENABLE_FLD, 29, 1)
+ FIELD(CONFIG_REG, CONFIG_RESV2_FLD, 26, 3)
+ FIELD(CONFIG_REG, PIPELINE_PHY_FLD, 25, 1)
+ FIELD(CONFIG_REG, ENABLE_DTR_PROTOCOL_FLD, 24, 1)
+ FIELD(CONFIG_REG, ENABLE_AHB_DECODER_FLD, 23, 1)
+ FIELD(CONFIG_REG, MSTR_BAUD_DIV_FLD, 19, 4)
+ FIELD(CONFIG_REG, ENTER_XIP_MODE_IMM_FLD, 18, 1)
+ FIELD(CONFIG_REG, ENTER_XIP_MODE_FLD, 17, 1)
+ FIELD(CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD, 16, 1)
+ FIELD(CONFIG_REG, ENB_DMA_IF_FLD, 15, 1)
+ FIELD(CONFIG_REG, WR_PROT_FLASH_FLD, 14, 1)
+ FIELD(CONFIG_REG, PERIPH_CS_LINES_FLD, 10, 4)
+ FIELD(CONFIG_REG, PERIPH_SEL_DEC_FLD, 9, 1)
+ FIELD(CONFIG_REG, ENB_LEGACY_IP_MODE_FLD, 8, 1)
+ FIELD(CONFIG_REG, ENB_DIR_ACC_CTLR_FLD, 7, 1)
+ FIELD(CONFIG_REG, RESET_CFG_FLD, 6, 1)
+ FIELD(CONFIG_REG, RESET_PIN_FLD, 5, 1)
+ FIELD(CONFIG_REG, HOLD_PIN_FLD, 4, 1)
+ FIELD(CONFIG_REG, PHY_MODE_ENABLE_FLD, 3, 1)
+ FIELD(CONFIG_REG, SEL_CLK_PHASE_FLD, 2, 1)
+ FIELD(CONFIG_REG, SEL_CLK_POL_FLD, 1, 1)
+ FIELD(CONFIG_REG, ENB_SPI_FLD, 0, 1)
+REG32(DEV_INSTR_RD_CONFIG_REG, 0x4)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV5_FLD, 29, 3)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, DUMMY_RD_CLK_CYCLES_FLD, 24, 5)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV4_FLD, 21, 3)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, MODE_BIT_ENABLE_FLD, 20, 1)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV3_FLD, 18, 2)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, DATA_XFER_TYPE_EXT_MODE_FLD, 16, 2)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV2_FLD, 14, 2)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, ADDR_XFER_TYPE_STD_MODE_FLD, 12, 2)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, PRED_DIS_FLD, 11, 1)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, DDR_EN_FLD, 10, 1)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, INSTR_TYPE_FLD, 8, 2)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, RD_OPCODE_NON_XIP_FLD, 0, 8)
+REG32(DEV_INSTR_WR_CONFIG_REG, 0x8)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV4_FLD, 29, 3)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, DUMMY_WR_CLK_CYCLES_FLD, 24, 5)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV3_FLD, 18, 6)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, DATA_XFER_TYPE_EXT_MODE_FLD, 16, 2)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV2_FLD, 14, 2)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, ADDR_XFER_TYPE_STD_MODE_FLD, 12, 2)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV1_FLD, 9, 3)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, WEL_DIS_FLD, 8, 1)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, WR_OPCODE_FLD, 0, 8)
+REG32(DEV_DELAY_REG, 0xc)
+ FIELD(DEV_DELAY_REG, D_NSS_FLD, 24, 8)
+ FIELD(DEV_DELAY_REG, D_BTWN_FLD, 16, 8)
+ FIELD(DEV_DELAY_REG, D_AFTER_FLD, 8, 8)
+ FIELD(DEV_DELAY_REG, D_INIT_FLD, 0, 8)
+REG32(RD_DATA_CAPTURE_REG, 0x10)
+ FIELD(RD_DATA_CAPTURE_REG, RD_DATA_RESV3_FLD, 20, 12)
+ FIELD(RD_DATA_CAPTURE_REG, DDR_READ_DELAY_FLD, 16, 4)
+ FIELD(RD_DATA_CAPTURE_REG, RD_DATA_RESV2_FLD, 9, 7)
+ FIELD(RD_DATA_CAPTURE_REG, DQS_ENABLE_FLD, 8, 1)
+ FIELD(RD_DATA_CAPTURE_REG, RD_DATA_RESV1_FLD, 6, 2)
+ FIELD(RD_DATA_CAPTURE_REG, SAMPLE_EDGE_SEL_FLD, 5, 1)
+ FIELD(RD_DATA_CAPTURE_REG, DELAY_FLD, 1, 4)
+ FIELD(RD_DATA_CAPTURE_REG, BYPASS_FLD, 0, 1)
+REG32(DEV_SIZE_CONFIG_REG, 0x14)
+ FIELD(DEV_SIZE_CONFIG_REG, DEV_SIZE_RESV_FLD, 29, 3)
+ FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS3_FLD, 27, 2)
+ FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS2_FLD, 25, 2)
+ FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS1_FLD, 23, 2)
+ FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS0_FLD, 21, 2)
+ FIELD(DEV_SIZE_CONFIG_REG, BYTES_PER_SUBSECTOR_FLD, 16, 5)
+ FIELD(DEV_SIZE_CONFIG_REG, BYTES_PER_DEVICE_PAGE_FLD, 4, 12)
+ FIELD(DEV_SIZE_CONFIG_REG, NUM_ADDR_BYTES_FLD, 0, 4)
+REG32(SRAM_PARTITION_CFG_REG, 0x18)
+ FIELD(SRAM_PARTITION_CFG_REG, SRAM_PARTITION_RESV_FLD, 8, 24)
+ FIELD(SRAM_PARTITION_CFG_REG, ADDR_FLD, 0, 8)
+REG32(IND_AHB_ADDR_TRIGGER_REG, 0x1c)
+REG32(DMA_PERIPH_CONFIG_REG, 0x20)
+ FIELD(DMA_PERIPH_CONFIG_REG, DMA_PERIPH_RESV2_FLD, 12, 20)
+ FIELD(DMA_PERIPH_CONFIG_REG, NUM_BURST_REQ_BYTES_FLD, 8, 4)
+ FIELD(DMA_PERIPH_CONFIG_REG, DMA_PERIPH_RESV1_FLD, 4, 4)
+ FIELD(DMA_PERIPH_CONFIG_REG, NUM_SINGLE_REQ_BYTES_FLD, 0, 4)
+REG32(REMAP_ADDR_REG, 0x24)
+REG32(MODE_BIT_CONFIG_REG, 0x28)
+ FIELD(MODE_BIT_CONFIG_REG, RX_CRC_DATA_LOW_FLD, 24, 8)
+ FIELD(MODE_BIT_CONFIG_REG, RX_CRC_DATA_UP_FLD, 16, 8)
+ FIELD(MODE_BIT_CONFIG_REG, CRC_OUT_ENABLE_FLD, 15, 1)
+ FIELD(MODE_BIT_CONFIG_REG, MODE_BIT_RESV1_FLD, 11, 4)
+ FIELD(MODE_BIT_CONFIG_REG, CHUNK_SIZE_FLD, 8, 3)
+ FIELD(MODE_BIT_CONFIG_REG, MODE_FLD, 0, 8)
+REG32(SRAM_FILL_REG, 0x2c)
+ FIELD(SRAM_FILL_REG, SRAM_FILL_INDAC_WRITE_FLD, 16, 16)
+ FIELD(SRAM_FILL_REG, SRAM_FILL_INDAC_READ_FLD, 0, 16)
+REG32(TX_THRESH_REG, 0x30)
+ FIELD(TX_THRESH_REG, TX_THRESH_RESV_FLD, 5, 27)
+ FIELD(TX_THRESH_REG, LEVEL_FLD, 0, 5)
+REG32(RX_THRESH_REG, 0x34)
+ FIELD(RX_THRESH_REG, RX_THRESH_RESV_FLD, 5, 27)
+ FIELD(RX_THRESH_REG, LEVEL_FLD, 0, 5)
+REG32(WRITE_COMPLETION_CTRL_REG, 0x38)
+ FIELD(WRITE_COMPLETION_CTRL_REG, POLL_REP_DELAY_FLD, 24, 8)
+ FIELD(WRITE_COMPLETION_CTRL_REG, POLL_COUNT_FLD, 16, 8)
+ FIELD(WRITE_COMPLETION_CTRL_REG, ENABLE_POLLING_EXP_FLD, 15, 1)
+ FIELD(WRITE_COMPLETION_CTRL_REG, DISABLE_POLLING_FLD, 14, 1)
+ FIELD(WRITE_COMPLETION_CTRL_REG, POLLING_POLARITY_FLD, 13, 1)
+ FIELD(WRITE_COMPLETION_CTRL_REG, WR_COMP_CTRL_RESV1_FLD, 12, 1)
+ FIELD(WRITE_COMPLETION_CTRL_REG, POLLING_ADDR_EN_FLD, 11, 1)
+ FIELD(WRITE_COMPLETION_CTRL_REG, POLLING_BIT_INDEX_FLD, 8, 3)
+ FIELD(WRITE_COMPLETION_CTRL_REG, OPCODE_FLD, 0, 8)
+REG32(NO_OF_POLLS_BEF_EXP_REG, 0x3c)
+REG32(IRQ_STATUS_REG, 0x40)
+ FIELD(IRQ_STATUS_REG, IRQ_STAT_RESV_FLD, 20, 12)
+ FIELD(IRQ_STATUS_REG, ECC_FAIL_FLD, 19, 1)
+ FIELD(IRQ_STATUS_REG, TX_CRC_CHUNK_BRK_FLD, 18, 1)
+ FIELD(IRQ_STATUS_REG, RX_CRC_DATA_VAL_FLD, 17, 1)
+ FIELD(IRQ_STATUS_REG, RX_CRC_DATA_ERR_FLD, 16, 1)
+ FIELD(IRQ_STATUS_REG, IRQ_STAT_RESV1_FLD, 15, 1)
+ FIELD(IRQ_STATUS_REG, STIG_REQ_INT_FLD, 14, 1)
+ FIELD(IRQ_STATUS_REG, POLL_EXP_INT_FLD, 13, 1)
+ FIELD(IRQ_STATUS_REG, INDRD_SRAM_FULL_FLD, 12, 1)
+ FIELD(IRQ_STATUS_REG, RX_FIFO_FULL_FLD, 11, 1)
+ FIELD(IRQ_STATUS_REG, RX_FIFO_NOT_EMPTY_FLD, 10, 1)
+ FIELD(IRQ_STATUS_REG, TX_FIFO_FULL_FLD, 9, 1)
+ FIELD(IRQ_STATUS_REG, TX_FIFO_NOT_FULL_FLD, 8, 1)
+ FIELD(IRQ_STATUS_REG, RECV_OVERFLOW_FLD, 7, 1)
+ FIELD(IRQ_STATUS_REG, INDIRECT_XFER_LEVEL_BREACH_FLD, 6, 1)
+ FIELD(IRQ_STATUS_REG, ILLEGAL_ACCESS_DET_FLD, 5, 1)
+ FIELD(IRQ_STATUS_REG, PROT_WR_ATTEMPT_FLD, 4, 1)
+ FIELD(IRQ_STATUS_REG, INDIRECT_TRANSFER_REJECT_FLD, 3, 1)
+ FIELD(IRQ_STATUS_REG, INDIRECT_OP_DONE_FLD, 2, 1)
+ FIELD(IRQ_STATUS_REG, UNDERFLOW_DET_FLD, 1, 1)
+ FIELD(IRQ_STATUS_REG, MODE_M_FAIL_FLD, 0, 1)
+REG32(IRQ_MASK_REG, 0x44)
+ FIELD(IRQ_MASK_REG, IRQ_MASK_RESV_FLD, 20, 12)
+ FIELD(IRQ_MASK_REG, ECC_FAIL_MASK_FLD, 19, 1)
+ FIELD(IRQ_MASK_REG, TX_CRC_CHUNK_BRK_MASK_FLD, 18, 1)
+ FIELD(IRQ_MASK_REG, RX_CRC_DATA_VAL_MASK_FLD, 17, 1)
+ FIELD(IRQ_MASK_REG, RX_CRC_DATA_ERR_MASK_FLD, 16, 1)
+ FIELD(IRQ_MASK_REG, IRQ_MASK_RESV1_FLD, 15, 1)
+ FIELD(IRQ_MASK_REG, STIG_REQ_MASK_FLD, 14, 1)
+ FIELD(IRQ_MASK_REG, POLL_EXP_INT_MASK_FLD, 13, 1)
+ FIELD(IRQ_MASK_REG, INDRD_SRAM_FULL_MASK_FLD, 12, 1)
+ FIELD(IRQ_MASK_REG, RX_FIFO_FULL_MASK_FLD, 11, 1)
+ FIELD(IRQ_MASK_REG, RX_FIFO_NOT_EMPTY_MASK_FLD, 10, 1)
+ FIELD(IRQ_MASK_REG, TX_FIFO_FULL_MASK_FLD, 9, 1)
+ FIELD(IRQ_MASK_REG, TX_FIFO_NOT_FULL_MASK_FLD, 8, 1)
+ FIELD(IRQ_MASK_REG, RECV_OVERFLOW_MASK_FLD, 7, 1)
+ FIELD(IRQ_MASK_REG, INDIRECT_XFER_LEVEL_BREACH_MASK_FLD, 6, 1)
+ FIELD(IRQ_MASK_REG, ILLEGAL_ACCESS_DET_MASK_FLD, 5, 1)
+ FIELD(IRQ_MASK_REG, PROT_WR_ATTEMPT_MASK_FLD, 4, 1)
+ FIELD(IRQ_MASK_REG, INDIRECT_TRANSFER_REJECT_MASK_FLD, 3, 1)
+ FIELD(IRQ_MASK_REG, INDIRECT_OP_DONE_MASK_FLD, 2, 1)
+ FIELD(IRQ_MASK_REG, UNDERFLOW_DET_MASK_FLD, 1, 1)
+ FIELD(IRQ_MASK_REG, MODE_M_FAIL_MASK_FLD, 0, 1)
+REG32(LOWER_WR_PROT_REG, 0x50)
+REG32(UPPER_WR_PROT_REG, 0x54)
+REG32(WR_PROT_CTRL_REG, 0x58)
+ FIELD(WR_PROT_CTRL_REG, WR_PROT_CTRL_RESV_FLD, 2, 30)
+ FIELD(WR_PROT_CTRL_REG, ENB_FLD, 1, 1)
+ FIELD(WR_PROT_CTRL_REG, INV_FLD, 0, 1)
+REG32(INDIRECT_READ_XFER_CTRL_REG, 0x60)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, INDIR_RD_XFER_RESV_FLD, 8, 24)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, NUM_IND_OPS_DONE_FLD, 6, 2)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, IND_OPS_DONE_STATUS_FLD, 5, 1)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, RD_QUEUED_FLD, 4, 1)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, SRAM_FULL_FLD, 3, 1)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, RD_STATUS_FLD, 2, 1)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, CANCEL_FLD, 1, 1)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, START_FLD, 0, 1)
+REG32(INDIRECT_READ_XFER_WATERMARK_REG, 0x64)
+REG32(INDIRECT_READ_XFER_START_REG, 0x68)
+REG32(INDIRECT_READ_XFER_NUM_BYTES_REG, 0x6c)
+REG32(INDIRECT_WRITE_XFER_CTRL_REG, 0x70)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, INDIR_WR_XFER_RESV2_FLD, 8, 24)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, NUM_IND_OPS_DONE_FLD, 6, 2)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, IND_OPS_DONE_STATUS_FLD, 5, 1)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, WR_QUEUED_FLD, 4, 1)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, INDIR_WR_XFER_RESV1_FLD, 3, 1)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, WR_STATUS_FLD, 2, 1)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, CANCEL_FLD, 1, 1)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, START_FLD, 0, 1)
+REG32(INDIRECT_WRITE_XFER_WATERMARK_REG, 0x74)
+REG32(INDIRECT_WRITE_XFER_START_REG, 0x78)
+REG32(INDIRECT_WRITE_XFER_NUM_BYTES_REG, 0x7c)
+REG32(INDIRECT_TRIGGER_ADDR_RANGE_REG, 0x80)
+ FIELD(INDIRECT_TRIGGER_ADDR_RANGE_REG, IND_RANGE_RESV1_FLD, 4, 28)
+ FIELD(INDIRECT_TRIGGER_ADDR_RANGE_REG, IND_RANGE_WIDTH_FLD, 0, 4)
+REG32(FLASH_COMMAND_CTRL_MEM_REG, 0x8c)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, FLASH_COMMAND_CTRL_MEM_RESV1_FLD, 29, 3)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_ADDR_FLD, 20, 9)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, FLASH_COMMAND_CTRL_MEM_RESV2_FLD, 19, 1)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, NB_OF_STIG_READ_BYTES_FLD, 16, 3)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_READ_DATA_FLD, 8, 8)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, FLASH_COMMAND_CTRL_MEM_RESV3_FLD, 2, 6)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_REQ_IN_PROGRESS_FLD, 1, 1)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, TRIGGER_MEM_BANK_REQ_FLD, 0, 1)
+REG32(FLASH_CMD_CTRL_REG, 0x90)
+ FIELD(FLASH_CMD_CTRL_REG, CMD_OPCODE_FLD, 24, 8)
+ FIELD(FLASH_CMD_CTRL_REG, ENB_READ_DATA_FLD, 23, 1)
+ FIELD(FLASH_CMD_CTRL_REG, NUM_RD_DATA_BYTES_FLD, 20, 3)
+ FIELD(FLASH_CMD_CTRL_REG, ENB_COMD_ADDR_FLD, 19, 1)
+ FIELD(FLASH_CMD_CTRL_REG, ENB_MODE_BIT_FLD, 18, 1)
+ FIELD(FLASH_CMD_CTRL_REG, NUM_ADDR_BYTES_FLD, 16, 2)
+ FIELD(FLASH_CMD_CTRL_REG, ENB_WRITE_DATA_FLD, 15, 1)
+ FIELD(FLASH_CMD_CTRL_REG, NUM_WR_DATA_BYTES_FLD, 12, 3)
+ FIELD(FLASH_CMD_CTRL_REG, NUM_DUMMY_CYCLES_FLD, 7, 5)
+ FIELD(FLASH_CMD_CTRL_REG, FLASH_CMD_CTRL_RESV1_FLD, 3, 4)
+ FIELD(FLASH_CMD_CTRL_REG, STIG_MEM_BANK_EN_FLD, 2, 1)
+ FIELD(FLASH_CMD_CTRL_REG, CMD_EXEC_STATUS_FLD, 1, 1)
+ FIELD(FLASH_CMD_CTRL_REG, CMD_EXEC_FLD, 0, 1)
+REG32(FLASH_CMD_ADDR_REG, 0x94)
+REG32(FLASH_RD_DATA_LOWER_REG, 0xa0)
+REG32(FLASH_RD_DATA_UPPER_REG, 0xa4)
+REG32(FLASH_WR_DATA_LOWER_REG, 0xa8)
+REG32(FLASH_WR_DATA_UPPER_REG, 0xac)
+REG32(POLLING_FLASH_STATUS_REG, 0xb0)
+ FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_RSVD_FLD2, 21, 11)
+ FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_NB_DUMMY, 16, 5)
+ FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_RSVD_FLD1, 9, 7)
+ FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_VALID_FLD, 8, 1)
+ FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_FLD, 0, 8)
+REG32(PHY_CONFIGURATION_REG, 0xb4)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESYNC_FLD, 31, 1)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESET_FLD, 30, 1)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RX_DLL_BYPASS_FLD, 29, 1)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESV2_FLD, 23, 6)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_TX_DLL_DELAY_FLD, 16, 7)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESV1_FLD, 7, 9)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RX_DLL_DELAY_FLD, 0, 7)
+REG32(PHY_MASTER_CONTROL_REG, 0xb8)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_CONTROL_RESV3_FLD, 25, 7)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_LOCK_MODE_FLD, 24, 1)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_BYPASS_MODE_FLD, 23, 1)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_PHASE_DETECT_SELECTOR_FLD, 20, 3)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_CONTROL_RESV2_FLD, 19, 1)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_NB_INDICATIONS_FLD, 16, 3)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_CONTROL_RESV1_FLD, 7, 9)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_INITIAL_DELAY_FLD, 0, 7)
+REG32(DLL_OBSERVABLE_LOWER_REG, 0xbc)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_DLL_LOCK_INC_FLD, 24, 8)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_DLL_LOCK_DEC_FLD, 16, 8)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_LOOPBACK_LOCK_FLD, 15, 1)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_LOCK_VALUE_FLD, 8, 7)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_UNLOCK_COUNTER_FLD, 3, 5)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_LOCK_MODE_FLD, 1, 2)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_DLL_LOCK_FLD, 0, 1)
+REG32(DLL_OBSERVABLE_UPPER_REG, 0xc0)
+ FIELD(DLL_OBSERVABLE_UPPER_REG,
+ DLL_OBSERVABLE_UPPER_RESV2_FLD, 23, 9)
+ FIELD(DLL_OBSERVABLE_UPPER_REG,
+ DLL_OBSERVABLE_UPPER_TX_DECODER_OUTPUT_FLD, 16, 7)
+ FIELD(DLL_OBSERVABLE_UPPER_REG,
+ DLL_OBSERVABLE_UPPER_RESV1_FLD, 7, 9)
+ FIELD(DLL_OBSERVABLE_UPPER_REG,
+ DLL_OBSERVABLE__UPPER_RX_DECODER_OUTPUT_FLD, 0, 7)
+REG32(OPCODE_EXT_LOWER_REG, 0xe0)
+ FIELD(OPCODE_EXT_LOWER_REG, EXT_READ_OPCODE_FLD, 24, 8)
+ FIELD(OPCODE_EXT_LOWER_REG, EXT_WRITE_OPCODE_FLD, 16, 8)
+ FIELD(OPCODE_EXT_LOWER_REG, EXT_POLL_OPCODE_FLD, 8, 8)
+ FIELD(OPCODE_EXT_LOWER_REG, EXT_STIG_OPCODE_FLD, 0, 8)
+REG32(OPCODE_EXT_UPPER_REG, 0xe4)
+ FIELD(OPCODE_EXT_UPPER_REG, WEL_OPCODE_FLD, 24, 8)
+ FIELD(OPCODE_EXT_UPPER_REG, EXT_WEL_OPCODE_FLD, 16, 8)
+ FIELD(OPCODE_EXT_UPPER_REG, OPCODE_EXT_UPPER_RESV1_FLD, 0, 16)
+REG32(MODULE_ID_REG, 0xfc)
+ FIELD(MODULE_ID_REG, FIX_PATCH_FLD, 24, 8)
+ FIELD(MODULE_ID_REG, MODULE_ID_FLD, 8, 16)
+ FIELD(MODULE_ID_REG, MODULE_ID_RESV_FLD, 2, 6)
+ FIELD(MODULE_ID_REG, CONF_FLD, 0, 2)
+
+#define RXFF_SZ 1024
+#define TXFF_SZ 1024
+
+#define MAX_RX_DEC_OUT 8
+
+#define SZ_512MBIT (512 * 1024 * 1024)
+#define SZ_1GBIT (1024 * 1024 * 1024)
+#define SZ_2GBIT (2ULL * SZ_1GBIT)
+#define SZ_4GBIT (4ULL * SZ_1GBIT)
+
+#define IS_IND_DMA_START(op) (op->done_bytes == 0)
+/*
+ * Bit field size of R_INDIRECT_WRITE_XFER_CTRL_REG_NUM_IND_OPS_DONE_FLD
+ * is 2 bits, which can record max of 3 indac operations.
+ */
+#define IND_OPS_DONE_MAX 3
+
+typedef enum {
+ WREN = 0x6,
+} FlashCMD;
+
+static unsigned int ospi_stig_addr_len(XlnxVersalOspi *s)
+{
+ /* Num address bytes is NUM_ADDR_BYTES_FLD + 1 */
+ return ARRAY_FIELD_EX32(s->regs,
+ FLASH_CMD_CTRL_REG, NUM_ADDR_BYTES_FLD) + 1;
+}
+
+static unsigned int ospi_stig_wr_data_len(XlnxVersalOspi *s)
+{
+ /* Num write data bytes is NUM_WR_DATA_BYTES_FLD + 1 */
+ return ARRAY_FIELD_EX32(s->regs,
+ FLASH_CMD_CTRL_REG, NUM_WR_DATA_BYTES_FLD) + 1;
+}
+
+static unsigned int ospi_stig_rd_data_len(XlnxVersalOspi *s)
+{
+ /* Num read data bytes is NUM_RD_DATA_BYTES_FLD + 1 */
+ return ARRAY_FIELD_EX32(s->regs,
+ FLASH_CMD_CTRL_REG, NUM_RD_DATA_BYTES_FLD) + 1;
+}
+
+/*
+ * Status bits in R_IRQ_STATUS_REG are set when the event occurs and the
+ * interrupt is enabled in the mask register ([1] Section 2.3.17)
+ */
+static void set_irq(XlnxVersalOspi *s, uint32_t set_mask)
+{
+ s->regs[R_IRQ_STATUS_REG] |= s->regs[R_IRQ_MASK_REG] & set_mask;
+}
+
+static void ospi_update_irq_line(XlnxVersalOspi *s)
+{
+ qemu_set_irq(s->irq, !!(s->regs[R_IRQ_STATUS_REG] &
+ s->regs[R_IRQ_MASK_REG]));
+}
+
+static uint8_t ospi_get_wr_opcode(XlnxVersalOspi *s)
+{
+ return ARRAY_FIELD_EX32(s->regs,
+ DEV_INSTR_WR_CONFIG_REG, WR_OPCODE_FLD);
+}
+
+static uint8_t ospi_get_rd_opcode(XlnxVersalOspi *s)
+{
+ return ARRAY_FIELD_EX32(s->regs,
+ DEV_INSTR_RD_CONFIG_REG, RD_OPCODE_NON_XIP_FLD);
+}
+
+static uint32_t ospi_get_num_addr_bytes(XlnxVersalOspi *s)
+{
+ /* Num address bytes is NUM_ADDR_BYTES_FLD + 1 */
+ return ARRAY_FIELD_EX32(s->regs,
+ DEV_SIZE_CONFIG_REG, NUM_ADDR_BYTES_FLD) + 1;
+}
+
+static void ospi_stig_membank_req(XlnxVersalOspi *s)
+{
+ int idx = ARRAY_FIELD_EX32(s->regs,
+ FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_ADDR_FLD);
+
+ ARRAY_FIELD_DP32(s->regs, FLASH_COMMAND_CTRL_MEM_REG,
+ MEM_BANK_READ_DATA_FLD, s->stig_membank[idx]);
+}
+
+static int ospi_stig_membank_rd_bytes(XlnxVersalOspi *s)
+{
+ int rd_data_fld = ARRAY_FIELD_EX32(s->regs, FLASH_COMMAND_CTRL_MEM_REG,
+ NB_OF_STIG_READ_BYTES_FLD);
+ static const int sizes[6] = { 16, 32, 64, 128, 256, 512 };
+ return (rd_data_fld < 6) ? sizes[rd_data_fld] : 0;
+}
+
+static uint32_t ospi_get_page_sz(XlnxVersalOspi *s)
+{
+ return ARRAY_FIELD_EX32(s->regs,
+ DEV_SIZE_CONFIG_REG, BYTES_PER_DEVICE_PAGE_FLD);
+}
+
+static bool ospi_ind_rd_watermark_enabled(XlnxVersalOspi *s)
+{
+ return s->regs[R_INDIRECT_READ_XFER_WATERMARK_REG];
+}
+
+static void ind_op_advance(IndOp *op, unsigned int len)
+{
+ op->done_bytes += len;
+ assert(op->done_bytes <= op->num_bytes);
+ if (op->done_bytes == op->num_bytes) {
+ op->completed = true;
+ }
+}
+
+static uint32_t ind_op_next_byte(IndOp *op)
+{
+ return op->flash_addr + op->done_bytes;
+}
+
+static uint32_t ind_op_end_byte(IndOp *op)
+{
+ return op->flash_addr + op->num_bytes;
+}
+
+static void ospi_ind_op_next(IndOp *op)
+{
+ op[0] = op[1];
+ op[1].completed = true;
+}
+
+static void ind_op_setup(IndOp *op, uint32_t flash_addr, uint32_t num_bytes)
+{
+ if (num_bytes & 0x3) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "OSPI indirect op num bytes not word aligned\n");
+ }
+ op->flash_addr = flash_addr;
+ op->num_bytes = num_bytes;
+ op->done_bytes = 0;
+ op->completed = false;
+}
+
+static bool ospi_ind_op_completed(IndOp *op)
+{
+ return op->completed;
+}
+
+static bool ospi_ind_op_all_completed(XlnxVersalOspi *s)
+{
+ return s->rd_ind_op[0].completed && s->wr_ind_op[0].completed;
+}
+
+static void ospi_ind_op_cancel(IndOp *op)
+{
+ op[0].completed = true;
+ op[1].completed = true;
+}
+
+static bool ospi_ind_op_add(IndOp *op, Fifo8 *fifo,
+ uint32_t flash_addr, uint32_t num_bytes)
+{
+ /* Check if first indirect op has been completed */
+ if (op->completed) {
+ fifo8_reset(fifo);
+ ind_op_setup(op, flash_addr, num_bytes);
+ return false;
+ }
+
+ /* Check if second indirect op has been completed */
+ op++;
+ if (op->completed) {
+ ind_op_setup(op, flash_addr, num_bytes);
+ return false;
+ }
+ return true;
+}
+
+static void ospi_ind_op_queue_up_rd(XlnxVersalOspi *s)
+{
+ uint32_t num_bytes = s->regs[R_INDIRECT_READ_XFER_NUM_BYTES_REG];
+ uint32_t flash_addr = s->regs[R_INDIRECT_READ_XFER_START_REG];
+ bool failed;
+
+ failed = ospi_ind_op_add(s->rd_ind_op, &s->rx_sram, flash_addr, num_bytes);
+ /* If two already queued set rd reject interrupt */
+ if (failed) {
+ set_irq(s, R_IRQ_STATUS_REG_INDIRECT_TRANSFER_REJECT_FLD_MASK);
+ }
+}
+
+static void ospi_ind_op_queue_up_wr(XlnxVersalOspi *s)
+{
+ uint32_t num_bytes = s->regs[R_INDIRECT_WRITE_XFER_NUM_BYTES_REG];
+ uint32_t flash_addr = s->regs[R_INDIRECT_WRITE_XFER_START_REG];
+ bool failed;
+
+ failed = ospi_ind_op_add(s->wr_ind_op, &s->tx_sram, flash_addr, num_bytes);
+ /* If two already queued set rd reject interrupt */
+ if (failed) {
+ set_irq(s, R_IRQ_STATUS_REG_INDIRECT_TRANSFER_REJECT_FLD_MASK);
+ }
+}
+
+static uint64_t flash_sz(XlnxVersalOspi *s, unsigned int cs)
+{
+ /* Flash sizes in MB */
+ static const uint64_t sizes[4] = { SZ_512MBIT / 8, SZ_1GBIT / 8,
+ SZ_2GBIT / 8, SZ_4GBIT / 8 };
+ uint32_t v = s->regs[R_DEV_SIZE_CONFIG_REG];
+
+ v >>= cs * R_DEV_SIZE_CONFIG_REG_MEM_SIZE_ON_CS0_FLD_LENGTH;
+ return sizes[FIELD_EX32(v, DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS0_FLD)];
+}
+
+static unsigned int ospi_get_block_sz(XlnxVersalOspi *s)
+{
+ unsigned int block_fld = ARRAY_FIELD_EX32(s->regs,
+ DEV_SIZE_CONFIG_REG,
+ BYTES_PER_SUBSECTOR_FLD);
+ return 1 << block_fld;
+}
+
+static unsigned int flash_blocks(XlnxVersalOspi *s, unsigned int cs)
+{
+ unsigned int b_sz = ospi_get_block_sz(s);
+ unsigned int f_sz = flash_sz(s, cs);
+
+ return f_sz / b_sz;
+}
+
+static int ospi_ahb_decoder_cs(XlnxVersalOspi *s, hwaddr addr)
+{
+ uint64_t end_addr = 0;
+ int cs;
+
+ for (cs = 0; cs < s->num_cs; cs++) {
+ end_addr += flash_sz(s, cs);
+ if (addr < end_addr) {
+ break;
+ }
+ }
+
+ if (cs == s->num_cs) {
+ /* Address is out of range */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "OSPI flash address does not fit in configuration\n");
+ return -1;
+ }
+ return cs;
+}
+
+static void ospi_ahb_decoder_enable_cs(XlnxVersalOspi *s, hwaddr addr)
+{
+ int cs = ospi_ahb_decoder_cs(s, addr);
+
+ if (cs >= 0) {
+ for (int i = 0; i < s->num_cs; i++) {
+ qemu_set_irq(s->cs_lines[i], cs != i);
+ }
+ }
+}
+
+static unsigned int single_cs(XlnxVersalOspi *s)
+{
+ unsigned int field = ARRAY_FIELD_EX32(s->regs,
+ CONFIG_REG, PERIPH_CS_LINES_FLD);
+
+ /*
+ * Below one liner is a trick that finds the rightmost zero and makes sure
+ * all other bits are turned to 1. It is a variant of the 'Isolate the
+ * rightmost 0-bit' trick found below at the time of writing:
+ *
+ * https://emre.me/computer-science/bit-manipulation-tricks/
+ *
+ * 4'bXXX0 -> 4'b1110
+ * 4'bXX01 -> 4'b1101
+ * 4'bX011 -> 4'b1011
+ * 4'b0111 -> 4'b0111
+ * 4'b1111 -> 4'b1111
+ */
+ return (field | ~(field + 1)) & 0xf;
+}
+
+static void ospi_update_cs_lines(XlnxVersalOspi *s)
+{
+ unsigned int all_cs;
+ int i;
+
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, PERIPH_SEL_DEC_FLD)) {
+ all_cs = ARRAY_FIELD_EX32(s->regs, CONFIG_REG, PERIPH_CS_LINES_FLD);
+ } else {
+ all_cs = single_cs(s);
+ }
+
+ for (i = 0; i < s->num_cs; i++) {
+ bool cs = (all_cs >> i) & 1;
+
+ qemu_set_irq(s->cs_lines[i], cs);
+ }
+}
+
+static void ospi_dac_cs(XlnxVersalOspi *s, hwaddr addr)
+{
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENABLE_AHB_DECODER_FLD)) {
+ ospi_ahb_decoder_enable_cs(s, addr);
+ } else {
+ ospi_update_cs_lines(s);
+ }
+}
+
+static void ospi_disable_cs(XlnxVersalOspi *s)
+{
+ int i;
+
+ for (i = 0; i < s->num_cs; i++) {
+ qemu_set_irq(s->cs_lines[i], 1);
+ }
+}
+
+static void ospi_flush_txfifo(XlnxVersalOspi *s)
+{
+ while (!fifo8_is_empty(&s->tx_fifo)) {
+ uint32_t tx_rx = fifo8_pop(&s->tx_fifo);
+
+ tx_rx = ssi_transfer(s->spi, tx_rx);
+ fifo8_push(&s->rx_fifo, tx_rx);
+ }
+}
+
+static void ospi_tx_fifo_push_address_raw(XlnxVersalOspi *s,
+ uint32_t flash_addr,
+ unsigned int addr_bytes)
+{
+ /* Push write address */
+ if (addr_bytes == 4) {
+ fifo8_push(&s->tx_fifo, flash_addr >> 24);
+ }
+ if (addr_bytes >= 3) {
+ fifo8_push(&s->tx_fifo, flash_addr >> 16);
+ }
+ if (addr_bytes >= 2) {
+ fifo8_push(&s->tx_fifo, flash_addr >> 8);
+ }
+ fifo8_push(&s->tx_fifo, flash_addr);
+}
+
+static void ospi_tx_fifo_push_address(XlnxVersalOspi *s, uint32_t flash_addr)
+{
+ /* Push write address */
+ int addr_bytes = ospi_get_num_addr_bytes(s);
+
+ ospi_tx_fifo_push_address_raw(s, flash_addr, addr_bytes);
+}
+
+static void ospi_tx_fifo_push_stig_addr(XlnxVersalOspi *s)
+{
+ uint32_t flash_addr = s->regs[R_FLASH_CMD_ADDR_REG];
+ unsigned int addr_bytes = ospi_stig_addr_len(s);
+
+ ospi_tx_fifo_push_address_raw(s, flash_addr, addr_bytes);
+}
+
+static void ospi_tx_fifo_push_rd_op_addr(XlnxVersalOspi *s, uint32_t flash_addr)
+{
+ uint8_t inst_code = ospi_get_rd_opcode(s);
+
+ fifo8_reset(&s->tx_fifo);
+
+ /* Push read opcode */
+ fifo8_push(&s->tx_fifo, inst_code);
+
+ /* Push read address */
+ ospi_tx_fifo_push_address(s, flash_addr);
+}
+
+static void ospi_tx_fifo_push_stig_wr_data(XlnxVersalOspi *s)
+{
+ uint64_t data = s->regs[R_FLASH_WR_DATA_LOWER_REG];
+ int wr_data_len = ospi_stig_wr_data_len(s);
+ int i;
+
+ data |= (uint64_t) s->regs[R_FLASH_WR_DATA_UPPER_REG] << 32;
+ for (i = 0; i < wr_data_len; i++) {
+ int shift = i * 8;
+ fifo8_push(&s->tx_fifo, data >> shift);
+ }
+}
+
+static void ospi_tx_fifo_push_stig_rd_data(XlnxVersalOspi *s)
+{
+ int rd_data_len;
+ int i;
+
+ if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, STIG_MEM_BANK_EN_FLD)) {
+ rd_data_len = ospi_stig_membank_rd_bytes(s);
+ } else {
+ rd_data_len = ospi_stig_rd_data_len(s);
+ }
+
+ /* transmit second part (data) */
+ for (i = 0; i < rd_data_len; ++i) {
+ fifo8_push(&s->tx_fifo, 0);
+ }
+}
+
+static void ospi_rx_fifo_pop_stig_rd_data(XlnxVersalOspi *s)
+{
+ int size = ospi_stig_rd_data_len(s);
+ uint8_t bytes[8] = {};
+ int i;
+
+ size = MIN(fifo8_num_used(&s->rx_fifo), size);
+
+ assert(size <= 8);
+
+ for (i = 0; i < size; i++) {
+ bytes[i] = fifo8_pop(&s->rx_fifo);
+ }
+
+ s->regs[R_FLASH_RD_DATA_LOWER_REG] = ldl_le_p(bytes);
+ s->regs[R_FLASH_RD_DATA_UPPER_REG] = ldl_le_p(bytes + 4);
+}
+
+static void ospi_ind_read(XlnxVersalOspi *s, uint32_t flash_addr, uint32_t len)
+{
+ int i;
+
+ /* Create first section of read cmd */
+ ospi_tx_fifo_push_rd_op_addr(s, flash_addr);
+
+ /* transmit first part */
+ ospi_update_cs_lines(s);
+ ospi_flush_txfifo(s);
+
+ fifo8_reset(&s->rx_fifo);
+
+ /* transmit second part (data) */
+ for (i = 0; i < len; ++i) {
+ fifo8_push(&s->tx_fifo, 0);
+ }
+ ospi_flush_txfifo(s);
+
+ for (i = 0; i < len; ++i) {
+ fifo8_push(&s->rx_sram, fifo8_pop(&s->rx_fifo));
+ }
+
+ /* done */
+ ospi_disable_cs(s);
+}
+
+static unsigned int ospi_dma_burst_size(XlnxVersalOspi *s)
+{
+ return 1 << ARRAY_FIELD_EX32(s->regs,
+ DMA_PERIPH_CONFIG_REG,
+ NUM_BURST_REQ_BYTES_FLD);
+}
+
+static unsigned int ospi_dma_single_size(XlnxVersalOspi *s)
+{
+ return 1 << ARRAY_FIELD_EX32(s->regs,
+ DMA_PERIPH_CONFIG_REG,
+ NUM_SINGLE_REQ_BYTES_FLD);
+}
+
+static void ind_rd_inc_num_done(XlnxVersalOspi *s)
+{
+ unsigned int done = ARRAY_FIELD_EX32(s->regs,
+ INDIRECT_READ_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD);
+ if (done < IND_OPS_DONE_MAX) {
+ done++;
+ }
+ done &= 0x3;
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD, done);
+}
+
+static void ospi_ind_rd_completed(XlnxVersalOspi *s)
+{
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG,
+ IND_OPS_DONE_STATUS_FLD, 1);
+
+ ind_rd_inc_num_done(s);
+ ospi_ind_op_next(s->rd_ind_op);
+ if (ospi_ind_op_all_completed(s)) {
+ set_irq(s, R_IRQ_STATUS_REG_INDIRECT_OP_DONE_FLD_MASK);
+ }
+}
+
+static void ospi_dma_read(XlnxVersalOspi *s)
+{
+ IndOp *op = s->rd_ind_op;
+ uint32_t dma_len = op->num_bytes;
+ uint32_t burst_sz = ospi_dma_burst_size(s);
+ uint32_t single_sz = ospi_dma_single_size(s);
+ uint32_t ind_trig_range;
+ uint32_t remainder;
+ XlnxCSUDMAClass *xcdc = XLNX_CSU_DMA_GET_CLASS(s->dma_src);
+
+ ind_trig_range = (1 << ARRAY_FIELD_EX32(s->regs,
+ INDIRECT_TRIGGER_ADDR_RANGE_REG,
+ IND_RANGE_WIDTH_FLD));
+ remainder = dma_len % burst_sz;
+ remainder = remainder % single_sz;
+ if (burst_sz > ind_trig_range || single_sz > ind_trig_range ||
+ remainder != 0) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "OSPI DMA burst size / single size config error\n");
+ }
+
+ s->src_dma_inprog = true;
+ if (xcdc->read(s->dma_src, 0, dma_len) != MEMTX_OK) {
+ qemu_log_mask(LOG_GUEST_ERROR, "OSPI DMA configuration error\n");
+ }
+ s->src_dma_inprog = false;
+}
+
+static void ospi_do_ind_read(XlnxVersalOspi *s)
+{
+ IndOp *op = s->rd_ind_op;
+ uint32_t next_b;
+ uint32_t end_b;
+ uint32_t len;
+ bool start_dma = IS_IND_DMA_START(op) && !s->src_dma_inprog;
+
+ /* Continue to read flash until we run out of space in sram */
+ while (!ospi_ind_op_completed(op) &&
+ !fifo8_is_full(&s->rx_sram)) {
+ /* Read reqested number of bytes, max bytes limited to size of sram */
+ next_b = ind_op_next_byte(op);
+ end_b = next_b + fifo8_num_free(&s->rx_sram);
+ end_b = MIN(end_b, ind_op_end_byte(op));
+
+ len = end_b - next_b;
+ ospi_ind_read(s, next_b, len);
+ ind_op_advance(op, len);
+
+ if (ospi_ind_rd_watermark_enabled(s)) {
+ ARRAY_FIELD_DP32(s->regs, IRQ_STATUS_REG,
+ INDIRECT_XFER_LEVEL_BREACH_FLD, 1);
+ set_irq(s,
+ R_IRQ_STATUS_REG_INDIRECT_XFER_LEVEL_BREACH_FLD_MASK);
+ }
+
+ if (!s->src_dma_inprog &&
+ ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DMA_IF_FLD)) {
+ ospi_dma_read(s);
+ }
+ }
+
+ /* Set sram full */
+ if (fifo8_num_used(&s->rx_sram) == RXFF_SZ) {
+ ARRAY_FIELD_DP32(s->regs,
+ INDIRECT_READ_XFER_CTRL_REG, SRAM_FULL_FLD, 1);
+ set_irq(s, R_IRQ_STATUS_REG_INDRD_SRAM_FULL_FLD_MASK);
+ }
+
+ /* Signal completion if done, unless inside recursion via ospi_dma_read */
+ if (!ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DMA_IF_FLD) || start_dma) {
+ if (ospi_ind_op_completed(op)) {
+ ospi_ind_rd_completed(s);
+ }
+ }
+}
+
+/* Transmit write enable instruction */
+static void ospi_transmit_wel(XlnxVersalOspi *s, bool ahb_decoder_cs,
+ hwaddr addr)
+{
+ fifo8_reset(&s->tx_fifo);
+ fifo8_push(&s->tx_fifo, WREN);
+
+ if (ahb_decoder_cs) {
+ ospi_ahb_decoder_enable_cs(s, addr);
+ } else {
+ ospi_update_cs_lines(s);
+ }
+
+ ospi_flush_txfifo(s);
+ ospi_disable_cs(s);
+
+ fifo8_reset(&s->rx_fifo);
+}
+
+static void ospi_ind_write(XlnxVersalOspi *s, uint32_t flash_addr, uint32_t len)
+{
+ bool ahb_decoder_cs = false;
+ uint8_t inst_code;
+ int i;
+
+ assert(fifo8_num_used(&s->tx_sram) >= len);
+
+ if (!ARRAY_FIELD_EX32(s->regs, DEV_INSTR_WR_CONFIG_REG, WEL_DIS_FLD)) {
+ ospi_transmit_wel(s, ahb_decoder_cs, 0);
+ }
+
+ /* reset fifos */
+ fifo8_reset(&s->tx_fifo);
+ fifo8_reset(&s->rx_fifo);
+
+ /* Push write opcode */
+ inst_code = ospi_get_wr_opcode(s);
+ fifo8_push(&s->tx_fifo, inst_code);
+
+ /* Push write address */
+ ospi_tx_fifo_push_address(s, flash_addr);
+
+ /* data */
+ for (i = 0; i < len; i++) {
+ fifo8_push(&s->tx_fifo, fifo8_pop(&s->tx_sram));
+ }
+
+ /* transmit */
+ ospi_update_cs_lines(s);
+ ospi_flush_txfifo(s);
+
+ /* done */
+ ospi_disable_cs(s);
+ fifo8_reset(&s->rx_fifo);
+}
+
+static void ind_wr_inc_num_done(XlnxVersalOspi *s)
+{
+ unsigned int done = ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD);
+ if (done < IND_OPS_DONE_MAX) {
+ done++;
+ }
+ done &= 0x3;
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD, done);
+}
+
+static void ospi_ind_wr_completed(XlnxVersalOspi *s)
+{
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,
+ IND_OPS_DONE_STATUS_FLD, 1);
+ ind_wr_inc_num_done(s);
+ ospi_ind_op_next(s->wr_ind_op);
+ /* Set indirect op done interrupt if enabled */
+ if (ospi_ind_op_all_completed(s)) {
+ set_irq(s, R_IRQ_STATUS_REG_INDIRECT_OP_DONE_FLD_MASK);
+ }
+}
+
+static void ospi_do_indirect_write(XlnxVersalOspi *s)
+{
+ uint32_t write_watermark = s->regs[R_INDIRECT_WRITE_XFER_WATERMARK_REG];
+ uint32_t pagesz = ospi_get_page_sz(s);
+ uint32_t page_mask = ~(pagesz - 1);
+ IndOp *op = s->wr_ind_op;
+ uint32_t next_b;
+ uint32_t end_b;
+ uint32_t len;
+
+ /* Write out tx_fifo in maximum page sz chunks */
+ while (!ospi_ind_op_completed(op) && fifo8_num_used(&s->tx_sram) > 0) {
+ next_b = ind_op_next_byte(op);
+ end_b = next_b + MIN(fifo8_num_used(&s->tx_sram), pagesz);
+
+ /* Dont cross page boundary */
+ if ((end_b & page_mask) > next_b) {
+ end_b &= page_mask;
+ }
+
+ len = end_b - next_b;
+ len = MIN(len, op->num_bytes - op->done_bytes);
+ ospi_ind_write(s, next_b, len);
+ ind_op_advance(op, len);
+ }
+
+ /*
+ * Always set indirect transfer level breached interrupt if enabled
+ * (write watermark > 0) since the tx_sram always will be emptied
+ */
+ if (write_watermark > 0) {
+ set_irq(s, R_IRQ_STATUS_REG_INDIRECT_XFER_LEVEL_BREACH_FLD_MASK);
+ }
+
+ /* Signal completions if done */
+ if (ospi_ind_op_completed(op)) {
+ ospi_ind_wr_completed(s);
+ }
+}
+
+static void ospi_stig_fill_membank(XlnxVersalOspi *s)
+{
+ int num_rd_bytes = ospi_stig_membank_rd_bytes(s);
+ int idx = num_rd_bytes - 8; /* first of last 8 */
+ int i;
+
+ for (i = 0; i < num_rd_bytes; i++) {
+ s->stig_membank[i] = fifo8_pop(&s->rx_fifo);
+ }
+
+ g_assert((idx + 4) < ARRAY_SIZE(s->stig_membank));
+
+ /* Fill in lower upper regs */
+ s->regs[R_FLASH_RD_DATA_LOWER_REG] = ldl_le_p(&s->stig_membank[idx]);
+ s->regs[R_FLASH_RD_DATA_UPPER_REG] = ldl_le_p(&s->stig_membank[idx + 4]);
+}
+
+static void ospi_stig_cmd_exec(XlnxVersalOspi *s)
+{
+ uint8_t inst_code;
+
+ /* Reset fifos */
+ fifo8_reset(&s->tx_fifo);
+ fifo8_reset(&s->rx_fifo);
+
+ /* Push write opcode */
+ inst_code = ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, CMD_OPCODE_FLD);
+ fifo8_push(&s->tx_fifo, inst_code);
+
+ /* Push address if enabled */
+ if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, ENB_COMD_ADDR_FLD)) {
+ ospi_tx_fifo_push_stig_addr(s);
+ }
+
+ /* Enable cs */
+ ospi_update_cs_lines(s);
+
+ /* Data */
+ if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, ENB_WRITE_DATA_FLD)) {
+ ospi_tx_fifo_push_stig_wr_data(s);
+ } else if (ARRAY_FIELD_EX32(s->regs,
+ FLASH_CMD_CTRL_REG, ENB_READ_DATA_FLD)) {
+ /* transmit first part */
+ ospi_flush_txfifo(s);
+ fifo8_reset(&s->rx_fifo);
+ ospi_tx_fifo_push_stig_rd_data(s);
+ }
+
+ /* Transmit */
+ ospi_flush_txfifo(s);
+ ospi_disable_cs(s);
+
+ if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, ENB_READ_DATA_FLD)) {
+ if (ARRAY_FIELD_EX32(s->regs,
+ FLASH_CMD_CTRL_REG, STIG_MEM_BANK_EN_FLD)) {
+ ospi_stig_fill_membank(s);
+ } else {
+ ospi_rx_fifo_pop_stig_rd_data(s);
+ }
+ }
+}
+
+static uint32_t ospi_block_address(XlnxVersalOspi *s, unsigned int block)
+{
+ unsigned int block_sz = ospi_get_block_sz(s);
+ unsigned int cs = 0;
+ uint32_t addr = 0;
+
+ while (cs < s->num_cs && block >= flash_blocks(s, cs)) {
+ block -= flash_blocks(s, 0);
+ addr += flash_sz(s, cs);
+ }
+ addr += block * block_sz;
+ return addr;
+}
+
+static uint32_t ospi_get_wr_prot_addr_low(XlnxVersalOspi *s)
+{
+ unsigned int block = s->regs[R_LOWER_WR_PROT_REG];
+
+ return ospi_block_address(s, block);
+}
+
+static uint32_t ospi_get_wr_prot_addr_upper(XlnxVersalOspi *s)
+{
+ unsigned int block = s->regs[R_UPPER_WR_PROT_REG];
+
+ /* Get address of first block out of defined range */
+ return ospi_block_address(s, block + 1);
+}
+
+static bool ospi_is_write_protected(XlnxVersalOspi *s, hwaddr addr)
+{
+ uint32_t wr_prot_addr_upper = ospi_get_wr_prot_addr_upper(s);
+ uint32_t wr_prot_addr_low = ospi_get_wr_prot_addr_low(s);
+ bool in_range = false;
+
+ if (addr >= wr_prot_addr_low && addr < wr_prot_addr_upper) {
+ in_range = true;
+ }
+
+ if (ARRAY_FIELD_EX32(s->regs, WR_PROT_CTRL_REG, INV_FLD)) {
+ in_range = !in_range;
+ }
+ return in_range;
+}
+
+static uint64_t ospi_rx_sram_read(XlnxVersalOspi *s, unsigned int size)
+{
+ uint8_t bytes[8] = {};
+ int i;
+
+ if (size < 4 && fifo8_num_used(&s->rx_sram) >= 4) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "OSPI only last read of internal "
+ "sram is allowed to be < 32 bits\n");
+ }
+
+ size = MIN(fifo8_num_used(&s->rx_sram), size);
+
+ assert(size <= 8);
+
+ for (i = 0; i < size; i++) {
+ bytes[i] = fifo8_pop(&s->rx_sram);
+ }
+
+ return ldq_le_p(bytes);
+}
+
+static void ospi_tx_sram_write(XlnxVersalOspi *s, uint64_t value,
+ unsigned int size)
+{
+ int i;
+ for (i = 0; i < size && !fifo8_is_full(&s->tx_sram); i++) {
+ fifo8_push(&s->tx_sram, value >> 8 * i);
+ }
+}
+
+static uint64_t ospi_do_dac_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+ uint8_t bytes[8] = {};
+ int i;
+
+ /* Create first section of read cmd */
+ ospi_tx_fifo_push_rd_op_addr(s, (uint32_t) addr);
+
+ /* Enable cs and transmit first part */
+ ospi_dac_cs(s, addr);
+ ospi_flush_txfifo(s);
+
+ fifo8_reset(&s->rx_fifo);
+
+ /* transmit second part (data) */
+ for (i = 0; i < size; ++i) {
+ fifo8_push(&s->tx_fifo, 0);
+ }
+ ospi_flush_txfifo(s);
+
+ /* fill in result */
+ size = MIN(fifo8_num_used(&s->rx_fifo), size);
+
+ assert(size <= 8);
+
+ for (i = 0; i < size; i++) {
+ bytes[i] = fifo8_pop(&s->rx_fifo);
+ }
+
+ /* done */
+ ospi_disable_cs(s);
+
+ return ldq_le_p(bytes);
+}
+
+static void ospi_do_dac_write(void *opaque,
+ hwaddr addr,
+ uint64_t value,
+ unsigned int size)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+ bool ahb_decoder_cs = ARRAY_FIELD_EX32(s->regs, CONFIG_REG,
+ ENABLE_AHB_DECODER_FLD);
+ uint8_t inst_code;
+ unsigned int i;
+
+ if (!ARRAY_FIELD_EX32(s->regs, DEV_INSTR_WR_CONFIG_REG, WEL_DIS_FLD)) {
+ ospi_transmit_wel(s, ahb_decoder_cs, addr);
+ }
+
+ /* reset fifos */
+ fifo8_reset(&s->tx_fifo);
+ fifo8_reset(&s->rx_fifo);
+
+ /* Push write opcode */
+ inst_code = ospi_get_wr_opcode(s);
+ fifo8_push(&s->tx_fifo, inst_code);
+
+ /* Push write address */
+ ospi_tx_fifo_push_address(s, addr);
+
+ /* data */
+ for (i = 0; i < size; i++) {
+ fifo8_push(&s->tx_fifo, value >> 8 * i);
+ }
+
+ /* Enable cs and transmit */
+ ospi_dac_cs(s, addr);
+ ospi_flush_txfifo(s);
+ ospi_disable_cs(s);
+
+ fifo8_reset(&s->rx_fifo);
+}
+
+static void flash_cmd_ctrl_mem_reg_post_write(RegisterInfo *reg,
+ uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) {
+ if (ARRAY_FIELD_EX32(s->regs,
+ FLASH_COMMAND_CTRL_MEM_REG,
+ TRIGGER_MEM_BANK_REQ_FLD)) {
+ ospi_stig_membank_req(s);
+ ARRAY_FIELD_DP32(s->regs, FLASH_COMMAND_CTRL_MEM_REG,
+ TRIGGER_MEM_BANK_REQ_FLD, 0);
+ }
+ }
+}
+
+static void flash_cmd_ctrl_reg_post_write(RegisterInfo *reg, uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD) &&
+ ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, CMD_EXEC_FLD)) {
+ ospi_stig_cmd_exec(s);
+ set_irq(s, R_IRQ_STATUS_REG_STIG_REQ_INT_FLD_MASK);
+ ARRAY_FIELD_DP32(s->regs, FLASH_CMD_CTRL_REG, CMD_EXEC_FLD, 0);
+ }
+}
+
+static uint64_t ind_wr_dec_num_done(XlnxVersalOspi *s, uint64_t val)
+{
+ unsigned int done = ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD);
+ done--;
+ done &= 0x3;
+ val = FIELD_DP32(val, INDIRECT_WRITE_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD, done);
+ return val;
+}
+
+static bool ind_wr_clearing_op_done(XlnxVersalOspi *s, uint64_t new_val)
+{
+ bool set_in_reg = ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,
+ IND_OPS_DONE_STATUS_FLD);
+ bool set_in_new_val = FIELD_EX32(new_val, INDIRECT_WRITE_XFER_CTRL_REG,
+ IND_OPS_DONE_STATUS_FLD);
+ /* return true if clearing bit */
+ return set_in_reg && !set_in_new_val;
+}
+
+static uint64_t ind_wr_xfer_ctrl_reg_pre_write(RegisterInfo *reg,
+ uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+
+ if (ind_wr_clearing_op_done(s, val)) {
+ val = ind_wr_dec_num_done(s, val);
+ }
+ return val;
+}
+
+static void ind_wr_xfer_ctrl_reg_post_write(RegisterInfo *reg, uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+
+ if (s->ind_write_disabled) {
+ return;
+ }
+
+ if (ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, START_FLD)) {
+ ospi_ind_op_queue_up_wr(s);
+ ospi_do_indirect_write(s);
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, START_FLD, 0);
+ }
+
+ if (ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, CANCEL_FLD)) {
+ ospi_ind_op_cancel(s->wr_ind_op);
+ fifo8_reset(&s->tx_sram);
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, CANCEL_FLD, 0);
+ }
+}
+
+static uint64_t ind_wr_xfer_ctrl_reg_post_read(RegisterInfo *reg,
+ uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+ IndOp *op = s->wr_ind_op;
+
+ /* Check if ind ops is ongoing */
+ if (!ospi_ind_op_completed(&op[0])) {
+ /* Check if two ind ops are queued */
+ if (!ospi_ind_op_completed(&op[1])) {
+ val = FIELD_DP32(val, INDIRECT_WRITE_XFER_CTRL_REG,
+ WR_QUEUED_FLD, 1);
+ }
+ val = FIELD_DP32(val, INDIRECT_WRITE_XFER_CTRL_REG, WR_STATUS_FLD, 1);
+ }
+ return val;
+}
+
+static uint64_t ind_rd_dec_num_done(XlnxVersalOspi *s, uint64_t val)
+{
+ unsigned int done = ARRAY_FIELD_EX32(s->regs, INDIRECT_READ_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD);
+ done--;
+ done &= 0x3;
+ val = FIELD_DP32(val, INDIRECT_READ_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD, done);
+ return val;
+}
+
+static uint64_t ind_rd_xfer_ctrl_reg_pre_write(RegisterInfo *reg,
+ uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+
+ if (FIELD_EX32(val, INDIRECT_READ_XFER_CTRL_REG,
+ IND_OPS_DONE_STATUS_FLD)) {
+ val = ind_rd_dec_num_done(s, val);
+ val &= ~R_INDIRECT_READ_XFER_CTRL_REG_IND_OPS_DONE_STATUS_FLD_MASK;
+ }
+ return val;
+}
+
+static void ind_rd_xfer_ctrl_reg_post_write(RegisterInfo *reg, uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+
+ if (ARRAY_FIELD_EX32(s->regs, INDIRECT_READ_XFER_CTRL_REG, START_FLD)) {
+ ospi_ind_op_queue_up_rd(s);
+ ospi_do_ind_read(s);
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG, START_FLD, 0);
+ }
+
+ if (ARRAY_FIELD_EX32(s->regs, INDIRECT_READ_XFER_CTRL_REG, CANCEL_FLD)) {
+ ospi_ind_op_cancel(s->rd_ind_op);
+ fifo8_reset(&s->rx_sram);
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG, CANCEL_FLD, 0);
+ }
+}
+
+static uint64_t ind_rd_xfer_ctrl_reg_post_read(RegisterInfo *reg,
+ uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+ IndOp *op = s->rd_ind_op;
+
+ /* Check if ind ops is ongoing */
+ if (!ospi_ind_op_completed(&op[0])) {
+ /* Check if two ind ops are queued */
+ if (!ospi_ind_op_completed(&op[1])) {
+ val = FIELD_DP32(val, INDIRECT_READ_XFER_CTRL_REG,
+ RD_QUEUED_FLD, 1);
+ }
+ val = FIELD_DP32(val, INDIRECT_READ_XFER_CTRL_REG, RD_STATUS_FLD, 1);
+ }
+ return val;
+}
+
+static uint64_t sram_fill_reg_post_read(RegisterInfo *reg, uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+ val = ((fifo8_num_used(&s->tx_sram) & 0xFFFF) << 16) |
+ (fifo8_num_used(&s->rx_sram) & 0xFFFF);
+ return val;
+}
+
+static uint64_t dll_obs_upper_reg_post_read(RegisterInfo *reg, uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+ uint32_t rx_dec_out;
+
+ rx_dec_out = FIELD_EX32(val, DLL_OBSERVABLE_UPPER_REG,
+ DLL_OBSERVABLE__UPPER_RX_DECODER_OUTPUT_FLD);
+
+ if (rx_dec_out < MAX_RX_DEC_OUT) {
+ ARRAY_FIELD_DP32(s->regs, DLL_OBSERVABLE_UPPER_REG,
+ DLL_OBSERVABLE__UPPER_RX_DECODER_OUTPUT_FLD,
+ rx_dec_out + 1);
+ }
+
+ return val;
+}
+
+
+static void xlnx_versal_ospi_reset(DeviceState *dev)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(dev);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
+ register_reset(&s->regs_info[i]);
+ }
+
+ fifo8_reset(&s->rx_fifo);
+ fifo8_reset(&s->tx_fifo);
+ fifo8_reset(&s->rx_sram);
+ fifo8_reset(&s->tx_sram);
+
+ s->rd_ind_op[0].completed = true;
+ s->rd_ind_op[1].completed = true;
+ s->wr_ind_op[0].completed = true;
+ s->wr_ind_op[1].completed = true;
+ ARRAY_FIELD_DP32(s->regs, DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_DLL_LOCK_FLD, 1);
+ ARRAY_FIELD_DP32(s->regs, DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_LOOPBACK_LOCK_FLD, 1);
+}
+
+static RegisterAccessInfo ospi_regs_info[] = {
+ { .name = "CONFIG_REG",
+ .addr = A_CONFIG_REG,
+ .reset = 0x80780081,
+ .ro = 0x9c000000,
+ },{ .name = "DEV_INSTR_RD_CONFIG_REG",
+ .addr = A_DEV_INSTR_RD_CONFIG_REG,
+ .reset = 0x3,
+ .ro = 0xe0ecc800,
+ },{ .name = "DEV_INSTR_WR_CONFIG_REG",
+ .addr = A_DEV_INSTR_WR_CONFIG_REG,
+ .reset = 0x2,
+ .ro = 0xe0fcce00,
+ },{ .name = "DEV_DELAY_REG",
+ .addr = A_DEV_DELAY_REG,
+ },{ .name = "RD_DATA_CAPTURE_REG",
+ .addr = A_RD_DATA_CAPTURE_REG,
+ .reset = 0x1,
+ .ro = 0xfff0fec0,
+ },{ .name = "DEV_SIZE_CONFIG_REG",
+ .addr = A_DEV_SIZE_CONFIG_REG,
+ .reset = 0x101002,
+ .ro = 0xe0000000,
+ },{ .name = "SRAM_PARTITION_CFG_REG",
+ .addr = A_SRAM_PARTITION_CFG_REG,
+ .reset = 0x80,
+ .ro = 0xffffff00,
+ },{ .name = "IND_AHB_ADDR_TRIGGER_REG",
+ .addr = A_IND_AHB_ADDR_TRIGGER_REG,
+ },{ .name = "DMA_PERIPH_CONFIG_REG",
+ .addr = A_DMA_PERIPH_CONFIG_REG,
+ .ro = 0xfffff0f0,
+ },{ .name = "REMAP_ADDR_REG",
+ .addr = A_REMAP_ADDR_REG,
+ },{ .name = "MODE_BIT_CONFIG_REG",
+ .addr = A_MODE_BIT_CONFIG_REG,
+ .reset = 0x200,
+ .ro = 0xffff7800,
+ },{ .name = "SRAM_FILL_REG",
+ .addr = A_SRAM_FILL_REG,
+ .ro = 0xffffffff,
+ .post_read = sram_fill_reg_post_read,
+ },{ .name = "TX_THRESH_REG",
+ .addr = A_TX_THRESH_REG,
+ .reset = 0x1,
+ .ro = 0xffffffe0,
+ },{ .name = "RX_THRESH_REG",
+ .addr = A_RX_THRESH_REG,
+ .reset = 0x1,
+ .ro = 0xffffffe0,
+ },{ .name = "WRITE_COMPLETION_CTRL_REG",
+ .addr = A_WRITE_COMPLETION_CTRL_REG,
+ .reset = 0x10005,
+ .ro = 0x1800,
+ },{ .name = "NO_OF_POLLS_BEF_EXP_REG",
+ .addr = A_NO_OF_POLLS_BEF_EXP_REG,
+ .reset = 0xffffffff,
+ },{ .name = "IRQ_STATUS_REG",
+ .addr = A_IRQ_STATUS_REG,
+ .ro = 0xfff08000,
+ .w1c = 0xf7fff,
+ },{ .name = "IRQ_MASK_REG",
+ .addr = A_IRQ_MASK_REG,
+ .ro = 0xfff08000,
+ },{ .name = "LOWER_WR_PROT_REG",
+ .addr = A_LOWER_WR_PROT_REG,
+ },{ .name = "UPPER_WR_PROT_REG",
+ .addr = A_UPPER_WR_PROT_REG,
+ },{ .name = "WR_PROT_CTRL_REG",
+ .addr = A_WR_PROT_CTRL_REG,
+ .ro = 0xfffffffc,
+ },{ .name = "INDIRECT_READ_XFER_CTRL_REG",
+ .addr = A_INDIRECT_READ_XFER_CTRL_REG,
+ .ro = 0xffffffd4,
+ .w1c = 0x08,
+ .pre_write = ind_rd_xfer_ctrl_reg_pre_write,
+ .post_write = ind_rd_xfer_ctrl_reg_post_write,
+ .post_read = ind_rd_xfer_ctrl_reg_post_read,
+ },{ .name = "INDIRECT_READ_XFER_WATERMARK_REG",
+ .addr = A_INDIRECT_READ_XFER_WATERMARK_REG,
+ },{ .name = "INDIRECT_READ_XFER_START_REG",
+ .addr = A_INDIRECT_READ_XFER_START_REG,
+ },{ .name = "INDIRECT_READ_XFER_NUM_BYTES_REG",
+ .addr = A_INDIRECT_READ_XFER_NUM_BYTES_REG,
+ },{ .name = "INDIRECT_WRITE_XFER_CTRL_REG",
+ .addr = A_INDIRECT_WRITE_XFER_CTRL_REG,
+ .ro = 0xffffffdc,
+ .w1c = 0x20,
+ .pre_write = ind_wr_xfer_ctrl_reg_pre_write,
+ .post_write = ind_wr_xfer_ctrl_reg_post_write,
+ .post_read = ind_wr_xfer_ctrl_reg_post_read,
+ },{ .name = "INDIRECT_WRITE_XFER_WATERMARK_REG",
+ .addr = A_INDIRECT_WRITE_XFER_WATERMARK_REG,
+ .reset = 0xffffffff,
+ },{ .name = "INDIRECT_WRITE_XFER_START_REG",
+ .addr = A_INDIRECT_WRITE_XFER_START_REG,
+ },{ .name = "INDIRECT_WRITE_XFER_NUM_BYTES_REG",
+ .addr = A_INDIRECT_WRITE_XFER_NUM_BYTES_REG,
+ },{ .name = "INDIRECT_TRIGGER_ADDR_RANGE_REG",
+ .addr = A_INDIRECT_TRIGGER_ADDR_RANGE_REG,
+ .reset = 0x4,
+ .ro = 0xfffffff0,
+ },{ .name = "FLASH_COMMAND_CTRL_MEM_REG",
+ .addr = A_FLASH_COMMAND_CTRL_MEM_REG,
+ .ro = 0xe008fffe,
+ .post_write = flash_cmd_ctrl_mem_reg_post_write,
+ },{ .name = "FLASH_CMD_CTRL_REG",
+ .addr = A_FLASH_CMD_CTRL_REG,
+ .ro = 0x7a,
+ .post_write = flash_cmd_ctrl_reg_post_write,
+ },{ .name = "FLASH_CMD_ADDR_REG",
+ .addr = A_FLASH_CMD_ADDR_REG,
+ },{ .name = "FLASH_RD_DATA_LOWER_REG",
+ .addr = A_FLASH_RD_DATA_LOWER_REG,
+ .ro = 0xffffffff,
+ },{ .name = "FLASH_RD_DATA_UPPER_REG",
+ .addr = A_FLASH_RD_DATA_UPPER_REG,
+ .ro = 0xffffffff,
+ },{ .name = "FLASH_WR_DATA_LOWER_REG",
+ .addr = A_FLASH_WR_DATA_LOWER_REG,
+ },{ .name = "FLASH_WR_DATA_UPPER_REG",
+ .addr = A_FLASH_WR_DATA_UPPER_REG,
+ },{ .name = "POLLING_FLASH_STATUS_REG",
+ .addr = A_POLLING_FLASH_STATUS_REG,
+ .ro = 0xfff0ffff,
+ },{ .name = "PHY_CONFIGURATION_REG",
+ .addr = A_PHY_CONFIGURATION_REG,
+ .reset = 0x40000000,
+ .ro = 0x1f80ff80,
+ },{ .name = "PHY_MASTER_CONTROL_REG",
+ .addr = A_PHY_MASTER_CONTROL_REG,
+ .reset = 0x800000,
+ .ro = 0xfe08ff80,
+ },{ .name = "DLL_OBSERVABLE_LOWER_REG",
+ .addr = A_DLL_OBSERVABLE_LOWER_REG,
+ .ro = 0xffffffff,
+ },{ .name = "DLL_OBSERVABLE_UPPER_REG",
+ .addr = A_DLL_OBSERVABLE_UPPER_REG,
+ .ro = 0xffffffff,
+ .post_read = dll_obs_upper_reg_post_read,
+ },{ .name = "OPCODE_EXT_LOWER_REG",
+ .addr = A_OPCODE_EXT_LOWER_REG,
+ .reset = 0x13edfa00,
+ },{ .name = "OPCODE_EXT_UPPER_REG",
+ .addr = A_OPCODE_EXT_UPPER_REG,
+ .reset = 0x6f90000,
+ .ro = 0xffff,
+ },{ .name = "MODULE_ID_REG",
+ .addr = A_MODULE_ID_REG,
+ .reset = 0x300,
+ .ro = 0xffffffff,
+ }
+};
+
+/* Return dev-obj from reg-region created by register_init_block32 */
+static XlnxVersalOspi *xilinx_ospi_of_mr(void *mr_accessor)
+{
+ RegisterInfoArray *reg_array = mr_accessor;
+ Object *dev;
+
+ dev = reg_array->mem.owner;
+ assert(dev);
+
+ return XILINX_VERSAL_OSPI(dev);
+}
+
+static void ospi_write(void *opaque, hwaddr addr, uint64_t value,
+ unsigned int size)
+{
+ XlnxVersalOspi *s = xilinx_ospi_of_mr(opaque);
+
+ register_write_memory(opaque, addr, value, size);
+ ospi_update_irq_line(s);
+}
+
+static const MemoryRegionOps ospi_ops = {
+ .read = register_read_memory,
+ .write = ospi_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static uint64_t ospi_indac_read(void *opaque, unsigned int size)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+ uint64_t ret = ospi_rx_sram_read(s, size);
+
+ if (!ospi_ind_op_completed(s->rd_ind_op)) {
+ ospi_do_ind_read(s);
+ }
+ return ret;
+}
+
+static void ospi_indac_write(void *opaque, uint64_t value, unsigned int size)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+
+ g_assert(!s->ind_write_disabled);
+
+ if (!ospi_ind_op_completed(s->wr_ind_op)) {
+ ospi_tx_sram_write(s, value, size);
+ ospi_do_indirect_write(s);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "OSPI wr into indac area while no ongoing indac wr\n");
+ }
+}
+
+static bool is_inside_indac_range(XlnxVersalOspi *s, hwaddr addr)
+{
+ uint32_t range_start;
+ uint32_t range_end;
+
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DMA_IF_FLD)) {
+ return true;
+ }
+
+ range_start = s->regs[R_IND_AHB_ADDR_TRIGGER_REG];
+ range_end = range_start +
+ (1 << ARRAY_FIELD_EX32(s->regs,
+ INDIRECT_TRIGGER_ADDR_RANGE_REG,
+ IND_RANGE_WIDTH_FLD));
+
+ addr += s->regs[R_IND_AHB_ADDR_TRIGGER_REG] & 0xF0000000;
+
+ return addr >= range_start && addr < range_end;
+}
+
+static bool ospi_is_indac_active(XlnxVersalOspi *s)
+{
+ /*
+ * When dac and indac cannot be active at the same time,
+ * return true when dac is disabled.
+ */
+ return s->dac_with_indac || !s->dac_enable;
+}
+
+static uint64_t ospi_dac_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) {
+ if (ospi_is_indac_active(s) &&
+ is_inside_indac_range(s, addr)) {
+ return ospi_indac_read(s, size);
+ }
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DIR_ACC_CTLR_FLD)
+ && s->dac_enable) {
+ if (ARRAY_FIELD_EX32(s->regs,
+ CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD)) {
+ addr += s->regs[R_REMAP_ADDR_REG];
+ }
+ return ospi_do_dac_read(opaque, addr, size);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB rd while DAC disabled\n");
+ }
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB rd while OSPI disabled\n");
+ }
+
+ return 0;
+}
+
+static void ospi_dac_write(void *opaque, hwaddr addr, uint64_t value,
+ unsigned int size)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) {
+ if (ospi_is_indac_active(s) &&
+ !s->ind_write_disabled &&
+ is_inside_indac_range(s, addr)) {
+ return ospi_indac_write(s, value, size);
+ }
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DIR_ACC_CTLR_FLD) &&
+ s->dac_enable) {
+ if (ARRAY_FIELD_EX32(s->regs,
+ CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD)) {
+ addr += s->regs[R_REMAP_ADDR_REG];
+ }
+ /* Check if addr is write protected */
+ if (ARRAY_FIELD_EX32(s->regs, WR_PROT_CTRL_REG, ENB_FLD) &&
+ ospi_is_write_protected(s, addr)) {
+ set_irq(s, R_IRQ_STATUS_REG_PROT_WR_ATTEMPT_FLD_MASK);
+ ospi_update_irq_line(s);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "OSPI writing into write protected area\n");
+ return;
+ }
+ ospi_do_dac_write(opaque, addr, value, size);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB wr while DAC disabled\n");
+ }
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB wr while OSPI disabled\n");
+ }
+}
+
+static const MemoryRegionOps ospi_dac_ops = {
+ .read = ospi_dac_read,
+ .write = ospi_dac_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void ospi_update_dac_status(void *opaque, int n, int level)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+
+ s->dac_enable = level;
+}
+
+static void xlnx_versal_ospi_realize(DeviceState *dev, Error **errp)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ s->num_cs = 4;
+ s->spi = ssi_create_bus(dev, "spi0");
+ s->cs_lines = g_new0(qemu_irq, s->num_cs);
+ for (int i = 0; i < s->num_cs; ++i) {
+ sysbus_init_irq(sbd, &s->cs_lines[i]);
+ }
+
+ fifo8_create(&s->rx_fifo, RXFF_SZ);
+ fifo8_create(&s->tx_fifo, TXFF_SZ);
+ fifo8_create(&s->rx_sram, RXFF_SZ);
+ fifo8_create(&s->tx_sram, TXFF_SZ);
+}
+
+static void xlnx_versal_ospi_init(Object *obj)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ DeviceState *dev = DEVICE(obj);
+ RegisterInfoArray *reg_array;
+
+ memory_region_init(&s->iomem, obj, TYPE_XILINX_VERSAL_OSPI,
+ XILINX_VERSAL_OSPI_R_MAX * 4);
+ reg_array =
+ register_init_block32(DEVICE(obj), ospi_regs_info,
+ ARRAY_SIZE(ospi_regs_info),
+ s->regs_info, s->regs,
+ &ospi_ops,
+ XILINX_VERSAL_OSPI_ERR_DEBUG,
+ XILINX_VERSAL_OSPI_R_MAX * 4);
+ memory_region_add_subregion(&s->iomem, 0x0, &reg_array->mem);
+ sysbus_init_mmio(sbd, &s->iomem);
+
+ memory_region_init_io(&s->iomem_dac, obj, &ospi_dac_ops, s,
+ TYPE_XILINX_VERSAL_OSPI "-dac", 0x20000000);
+ sysbus_init_mmio(sbd, &s->iomem_dac);
+
+ sysbus_init_irq(sbd, &s->irq);
+
+ object_property_add_link(obj, "dma-src", TYPE_XLNX_CSU_DMA,
+ (Object **)&s->dma_src,
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_STRONG);
+
+ qdev_init_gpio_in_named(dev, ospi_update_dac_status, "ospi-mux-sel", 1);
+}
+
+static const VMStateDescription vmstate_ind_op = {
+ .name = "OSPIIndOp",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(flash_addr, IndOp),
+ VMSTATE_UINT32(num_bytes, IndOp),
+ VMSTATE_UINT32(done_bytes, IndOp),
+ VMSTATE_BOOL(completed, IndOp),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_xlnx_versal_ospi = {
+ .name = TYPE_XILINX_VERSAL_OSPI,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_FIFO8(rx_fifo, XlnxVersalOspi),
+ VMSTATE_FIFO8(tx_fifo, XlnxVersalOspi),
+ VMSTATE_FIFO8(rx_sram, XlnxVersalOspi),
+ VMSTATE_FIFO8(tx_sram, XlnxVersalOspi),
+ VMSTATE_BOOL(ind_write_disabled, XlnxVersalOspi),
+ VMSTATE_BOOL(dac_with_indac, XlnxVersalOspi),
+ VMSTATE_BOOL(dac_enable, XlnxVersalOspi),
+ VMSTATE_BOOL(src_dma_inprog, XlnxVersalOspi),
+ VMSTATE_STRUCT_ARRAY(rd_ind_op, XlnxVersalOspi, 2, 1,
+ vmstate_ind_op, IndOp),
+ VMSTATE_STRUCT_ARRAY(wr_ind_op, XlnxVersalOspi, 2, 1,
+ vmstate_ind_op, IndOp),
+ VMSTATE_UINT32_ARRAY(regs, XlnxVersalOspi, XILINX_VERSAL_OSPI_R_MAX),
+ VMSTATE_UINT8_ARRAY(stig_membank, XlnxVersalOspi, 512),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
+static Property xlnx_versal_ospi_properties[] = {
+ DEFINE_PROP_BOOL("dac-with-indac", XlnxVersalOspi, dac_with_indac, false),
+ DEFINE_PROP_BOOL("indac-write-disabled", XlnxVersalOspi,
+ ind_write_disabled, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xlnx_versal_ospi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = xlnx_versal_ospi_reset;
+ dc->realize = xlnx_versal_ospi_realize;
+ dc->vmsd = &vmstate_xlnx_versal_ospi;
+ device_class_set_props(dc, xlnx_versal_ospi_properties);
+}
+
+static const TypeInfo xlnx_versal_ospi_info = {
+ .name = TYPE_XILINX_VERSAL_OSPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(XlnxVersalOspi),
+ .class_init = xlnx_versal_ospi_class_init,
+ .instance_init = xlnx_versal_ospi_init,
+};
+
+static void xlnx_versal_ospi_register_types(void)
+{
+ type_register_static(&xlnx_versal_ospi_info);
+}
+
+type_init(xlnx_versal_ospi_register_types)
diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
index 72da12fea5..688eccda94 100644
--- a/hw/virtio/virtio-mmio.c
+++ b/hw/virtio/virtio-mmio.c
@@ -592,7 +592,6 @@ static const VMStateDescription vmstate_virtio_mmio = {
.name = "virtio_mmio",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_END_OF_LIST()
},
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 750aa47ec1..f9cf9592fd 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -131,7 +131,6 @@ static const VMStateDescription vmstate_virtio_pci = {
.name = "virtio_pci",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_END_OF_LIST()
},
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index aae72fb8b7..9e8f51dfb0 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2808,7 +2808,6 @@ static const VMStateDescription vmstate_virtio = {
.name = "virtio",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_END_OF_LIST()
},
diff --git a/include/block/block.h b/include/block/block.h
index 9d4050220b..e1713ee306 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -344,7 +344,6 @@ typedef unsigned int BdrvChildRole;
char *bdrv_perm_names(uint64_t perm);
uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm);
-/* disk I/O throttling */
void bdrv_init(void);
void bdrv_init_with_whitelist(void);
bool bdrv_uses_whitelist(void);
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index bb37239efa..84caf5c3d9 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -234,15 +234,6 @@ extern const TargetPageBits target_page;
#define TARGET_PAGE_ALIGN(addr) ROUND_UP((addr), TARGET_PAGE_SIZE)
-/* Using intptr_t ensures that qemu_*_page_mask is sign-extended even
- * when intptr_t is 32-bit and we are aligning a long long.
- */
-extern uintptr_t qemu_host_page_size;
-extern intptr_t qemu_host_page_mask;
-
-#define HOST_PAGE_ALIGN(addr) ROUND_UP((addr), qemu_host_page_size)
-#define REAL_HOST_PAGE_ALIGN(addr) ROUND_UP((addr), qemu_real_host_page_size)
-
/* same as PROT_xxx */
#define PAGE_READ 0x0001
#define PAGE_WRITE 0x0002
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index 039d422bf4..de5f444b19 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -7,6 +7,15 @@
#include "exec/hwaddr.h"
#endif
+/* Using intptr_t ensures that qemu_*_page_mask is sign-extended even
+ * when intptr_t is 32-bit and we are aligning a long long.
+ */
+extern uintptr_t qemu_host_page_size;
+extern intptr_t qemu_host_page_mask;
+
+#define HOST_PAGE_ALIGN(addr) ROUND_UP((addr), qemu_host_page_size)
+#define REAL_HOST_PAGE_ALIGN(addr) ROUND_UP((addr), qemu_real_host_page_size)
+
/* The CPU list lock nests outside page_(un)lock or mmap_(un)lock */
void qemu_init_cpu_list(void);
void cpu_list_lock(void);
diff --git a/include/hw/acpi/erst.h b/include/hw/acpi/erst.h
new file mode 100644
index 0000000000..b747fe7739
--- /dev/null
+++ b/include/hw/acpi/erst.h
@@ -0,0 +1,24 @@
+/*
+ * ACPI Error Record Serialization Table, ERST, Implementation
+ *
+ * ACPI ERST introduced in ACPI 4.0, June 16, 2009.
+ * ACPI Platform Error Interfaces : Error Serialization
+ *
+ * Copyright (c) 2021 Oracle and/or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef HW_ACPI_ERST_H
+#define HW_ACPI_ERST_H
+
+void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev,
+ const char *oem_id, const char *oem_table_id);
+
+#define TYPE_ACPI_ERST "acpi-erst"
+
+/* returns NULL unless there is exactly one device */
+static inline Object *find_erst_dev(void)
+{
+ return object_resolve_path_type("", TYPE_ACPI_ERST, NULL);
+}
+#endif
diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h
index 895ba12c61..1b5ad4de80 100644
--- a/include/hw/arm/xlnx-versal.h
+++ b/include/hw/arm/xlnx-versal.h
@@ -26,6 +26,9 @@
#include "hw/misc/xlnx-versal-xramc.h"
#include "hw/nvram/xlnx-bbram.h"
#include "hw/nvram/xlnx-versal-efuse.h"
+#include "hw/ssi/xlnx-versal-ospi.h"
+#include "hw/dma/xlnx_csu_dma.h"
+#include "hw/misc/xlnx-versal-pmc-iou-slcr.h"
#define TYPE_XLNX_VERSAL "xlnx-versal"
OBJECT_DECLARE_SIMPLE_TYPE(Versal, XLNX_VERSAL)
@@ -78,6 +81,15 @@ struct Versal {
struct {
struct {
SDHCIState sd[XLNX_VERSAL_NR_SDS];
+ XlnxVersalPmcIouSlcr slcr;
+
+ struct {
+ XlnxVersalOspi ospi;
+ XlnxCSUDMA dma_src;
+ XlnxCSUDMA dma_dst;
+ MemoryRegion linear_mr;
+ qemu_or_irq irq_orgate;
+ } ospi;
} iou;
XlnxZynqMPRTC rtc;
@@ -85,6 +97,8 @@ struct Versal {
XlnxEFuse efuse;
XlnxVersalEFuseCtrl efuse_ctrl;
XlnxVersalEFuseCache efuse_cache;
+
+ qemu_or_irq apb_irq_orgate;
} pmc;
struct {
@@ -111,8 +125,8 @@ struct Versal {
#define VERSAL_GEM1_WAKE_IRQ_0 59
#define VERSAL_ADMA_IRQ_0 60
#define VERSAL_XRAM_IRQ_0 79
-#define VERSAL_BBRAM_APB_IRQ_0 121
-#define VERSAL_RTC_APB_ERR_IRQ 121
+#define VERSAL_PMC_APB_IRQ 121
+#define VERSAL_OSPI_IRQ 124
#define VERSAL_SD0_IRQ_0 126
#define VERSAL_EFUSE_IRQ 139
#define VERSAL_RTC_ALARM_IRQ 142
@@ -178,6 +192,18 @@ struct Versal {
#define MM_FPD_FPD_APU 0xfd5c0000
#define MM_FPD_FPD_APU_SIZE 0x100
+#define MM_PMC_PMC_IOU_SLCR 0xf1060000
+#define MM_PMC_PMC_IOU_SLCR_SIZE 0x10000
+
+#define MM_PMC_OSPI 0xf1010000
+#define MM_PMC_OSPI_SIZE 0x10000
+
+#define MM_PMC_OSPI_DAC 0xc0000000
+#define MM_PMC_OSPI_DAC_SIZE 0x20000000
+
+#define MM_PMC_OSPI_DMA_DST 0xf1011800
+#define MM_PMC_OSPI_DMA_SRC 0xf1011000
+
#define MM_PMC_SD0 0xf1040000U
#define MM_PMC_SD0_SIZE 0x10000
#define MM_PMC_BBRAM_CTRL 0xf11f0000
diff --git a/include/hw/dma/xlnx_csu_dma.h b/include/hw/dma/xlnx_csu_dma.h
index 9e9dc551e9..922ab80eb6 100644
--- a/include/hw/dma/xlnx_csu_dma.h
+++ b/include/hw/dma/xlnx_csu_dma.h
@@ -21,6 +21,11 @@
#ifndef XLNX_CSU_DMA_H
#define XLNX_CSU_DMA_H
+#include "hw/sysbus.h"
+#include "hw/register.h"
+#include "hw/ptimer.h"
+#include "hw/stream.h"
+
#define TYPE_XLNX_CSU_DMA "xlnx.csu_dma"
#define XLNX_CSU_DMA_R_MAX (0x2c / 4)
@@ -46,7 +51,22 @@ typedef struct XlnxCSUDMA {
RegisterInfo regs_info[XLNX_CSU_DMA_R_MAX];
} XlnxCSUDMA;
-#define XLNX_CSU_DMA(obj) \
- OBJECT_CHECK(XlnxCSUDMA, (obj), TYPE_XLNX_CSU_DMA)
+OBJECT_DECLARE_TYPE(XlnxCSUDMA, XlnxCSUDMAClass, XLNX_CSU_DMA)
+
+struct XlnxCSUDMAClass {
+ SysBusDeviceClass parent_class;
+
+ /*
+ * read: Start a read transfer on a Xilinx CSU DMA engine
+ *
+ * @s: the Xilinx CSU DMA engine to start the transfer on
+ * @addr: the address to read
+ * @len: the number of bytes to read at 'addr'
+ *
+ * @return a MemTxResult indicating whether the operation succeeded ('len'
+ * bytes were read) or failed.
+ */
+ MemTxResult (*read)(XlnxCSUDMA *s, hwaddr addr, uint32_t len);
+};
#endif
diff --git a/include/hw/i386/ioapic_internal.h b/include/hw/i386/ioapic_internal.h
index 021e715f11..9880443cc7 100644
--- a/include/hw/i386/ioapic_internal.h
+++ b/include/hw/i386/ioapic_internal.h
@@ -112,7 +112,6 @@ struct IOAPICCommonState {
void ioapic_reset_common(DeviceState *dev);
-void ioapic_print_redtbl(Monitor *mon, IOAPICCommonState *s);
void ioapic_stat_update_irq(IOAPICCommonState *s, int irq, int level);
#endif /* QEMU_IOAPIC_INTERNAL_H */
diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h
index b32c697207..3e2ad2dff6 100644
--- a/include/hw/intc/arm_gicv3_its_common.h
+++ b/include/hw/intc/arm_gicv3_its_common.h
@@ -47,7 +47,6 @@ typedef struct {
uint16_t entry_sz;
uint32_t page_sz;
uint32_t num_entries;
- uint32_t num_ids;
uint64_t base_addr;
} TableDesc;
diff --git a/include/hw/isa/i8259_internal.h b/include/hw/isa/i8259_internal.h
index a6ae8a583f..d272d879fb 100644
--- a/include/hw/isa/i8259_internal.h
+++ b/include/hw/isa/i8259_internal.h
@@ -72,8 +72,5 @@ struct PICCommonState {
void pic_reset_common(PICCommonState *s);
ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master);
void pic_stat_update_irq(int irq, int level);
-bool pic_get_statistics(InterruptStatsProvider *obj,
- uint64_t **irq_counts, unsigned int *nb_irqs);
-void pic_print_info(InterruptStatsProvider *obj, Monitor *mon);
#endif /* QEMU_I8259_INTERNAL_H */
diff --git a/include/hw/misc/xlnx-versal-pmc-iou-slcr.h b/include/hw/misc/xlnx-versal-pmc-iou-slcr.h
new file mode 100644
index 0000000000..ab4e4b4f18
--- /dev/null
+++ b/include/hw/misc/xlnx-versal-pmc-iou-slcr.h
@@ -0,0 +1,78 @@
+/*
+ * Header file for the Xilinx Versal's PMC IOU SLCR
+ *
+ * Copyright (C) 2021 Xilinx Inc
+ * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
+ *
+ * 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.
+ */
+
+/*
+ * This is a model of Xilinx Versal's PMC I/O Peripheral Control and Status
+ * module documented in Versal's Technical Reference manual [1] and the Versal
+ * ACAP Register reference [2].
+ *
+ * References:
+ *
+ * [1] Versal ACAP Technical Reference Manual,
+ * https://www.xilinx.com/support/documentation/architecture-manuals/am011-versal-acap-trm.pdf
+ *
+ * [2] Versal ACAP Register Reference,
+ * https://www.xilinx.com/html_docs/registers/am012/am012-versal-register-reference.html#mod___pmc_iop_slcr.html
+ *
+ * QEMU interface:
+ * + sysbus MMIO region 0: MemoryRegion for the device's registers
+ * + sysbus IRQ 0: PMC (AXI and APB) parity error interrupt detected by the PMC
+ * I/O peripherals.
+ * + sysbus IRQ 1: Device interrupt.
+ * + Named GPIO output "sd-emmc-sel[0]": Enables 0: SD mode or 1: eMMC mode on
+ * SD/eMMC controller 0.
+ * + Named GPIO output "sd-emmc-sel[1]": Enables 0: SD mode or 1: eMMC mode on
+ * SD/eMMC controller 1.
+ * + Named GPIO output "qspi-ospi-mux-sel": Selects 0: QSPI linear region or 1:
+ * OSPI linear region.
+ * + Named GPIO output "ospi-mux-sel": Selects 0: OSPI Indirect access mode or
+ * 1: OSPI direct access mode.
+ */
+
+#ifndef XILINX_VERSAL_PMC_IOU_SLCR_H
+#define XILINX_VERSAL_PMC_IOU_SLCR_H
+
+#include "hw/register.h"
+
+#define TYPE_XILINX_VERSAL_PMC_IOU_SLCR "xlnx.versal-pmc-iou-slcr"
+
+OBJECT_DECLARE_SIMPLE_TYPE(XlnxVersalPmcIouSlcr, XILINX_VERSAL_PMC_IOU_SLCR)
+
+#define XILINX_VERSAL_PMC_IOU_SLCR_R_MAX (0x828 / 4 + 1)
+
+struct XlnxVersalPmcIouSlcr {
+ SysBusDevice parent_obj;
+ MemoryRegion iomem;
+ qemu_irq irq_parity_imr;
+ qemu_irq irq_imr;
+ qemu_irq sd_emmc_sel[2];
+ qemu_irq qspi_ospi_mux_sel;
+ qemu_irq ospi_mux_sel;
+
+ uint32_t regs[XILINX_VERSAL_PMC_IOU_SLCR_R_MAX];
+ RegisterInfo regs_info[XILINX_VERSAL_PMC_IOU_SLCR_R_MAX];
+};
+
+#endif /* XILINX_VERSAL_PMC_IOU_SLCR_H */
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 023abc0f79..c3f3c90473 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -108,6 +108,7 @@ extern bool pci_available;
#define PCI_DEVICE_ID_REDHAT_MDPY 0x000f
#define PCI_DEVICE_ID_REDHAT_NVME 0x0010
#define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011
+#define PCI_DEVICE_ID_REDHAT_ACPI_ERST 0x0012
#define PCI_DEVICE_ID_REDHAT_QXL 0x0100
#define FMT_PCIBUS PRIx64
diff --git a/include/hw/ppc/vof.h b/include/hw/ppc/vof.h
index 97fdef758b..f8c0effcaf 100644
--- a/include/hw/ppc/vof.h
+++ b/include/hw/ppc/vof.h
@@ -6,6 +6,11 @@
#ifndef HW_VOF_H
#define HW_VOF_H
+#include "qom/object.h"
+#include "exec/address-spaces.h"
+#include "exec/memory.h"
+#include "cpu.h"
+
typedef struct Vof {
uint64_t top_addr; /* copied from rma_size */
GArray *claimed; /* array of SpaprOfClaimed */
diff --git a/include/hw/ssi/xlnx-versal-ospi.h b/include/hw/ssi/xlnx-versal-ospi.h
new file mode 100644
index 0000000000..14d1263497
--- /dev/null
+++ b/include/hw/ssi/xlnx-versal-ospi.h
@@ -0,0 +1,111 @@
+/*
+ * Header file for the Xilinx Versal's OSPI controller
+ *
+ * Copyright (C) 2021 Xilinx Inc
+ * Written by Francisco Iglesias <francisco.iglesias@xilinx.com>
+ *
+ * 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.
+ */
+
+/*
+ * This is a model of Xilinx Versal's Octal SPI flash memory controller
+ * documented in Versal's Technical Reference manual [1] and the Versal ACAP
+ * Register reference [2].
+ *
+ * References:
+ *
+ * [1] Versal ACAP Technical Reference Manual,
+ * https://www.xilinx.com/support/documentation/architecture-manuals/am011-versal-acap-trm.pdf
+ *
+ * [2] Versal ACAP Register Reference,
+ * https://www.xilinx.com/html_docs/registers/am012/am012-versal-register-reference.html#mod___ospi.html
+ *
+ *
+ * QEMU interface:
+ * + sysbus MMIO region 0: MemoryRegion for the device's registers
+ * + sysbus MMIO region 1: MemoryRegion for flash memory linear address space
+ * (data transfer).
+ * + sysbus IRQ 0: Device interrupt.
+ * + Named GPIO input "ospi-mux-sel": 0: enables indirect access mode
+ * and 1: enables direct access mode.
+ * + Property "dac-with-indac": Allow both direct accesses and indirect
+ * accesses simultaneously.
+ * + Property "indac-write-disabled": Disable indirect access writes.
+ */
+
+#ifndef XILINX_VERSAL_OSPI_H
+#define XILINX_VERSAL_OSPI_H
+
+#include "hw/register.h"
+#include "hw/ssi/ssi.h"
+#include "qemu/fifo8.h"
+#include "hw/dma/xlnx_csu_dma.h"
+
+#define TYPE_XILINX_VERSAL_OSPI "xlnx.versal-ospi"
+
+OBJECT_DECLARE_SIMPLE_TYPE(XlnxVersalOspi, XILINX_VERSAL_OSPI)
+
+#define XILINX_VERSAL_OSPI_R_MAX (0xfc / 4 + 1)
+
+/*
+ * Indirect operations
+ */
+typedef struct IndOp {
+ uint32_t flash_addr;
+ uint32_t num_bytes;
+ uint32_t done_bytes;
+ bool completed;
+} IndOp;
+
+struct XlnxVersalOspi {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ MemoryRegion iomem_dac;
+
+ uint8_t num_cs;
+ qemu_irq *cs_lines;
+
+ SSIBus *spi;
+
+ Fifo8 rx_fifo;
+ Fifo8 tx_fifo;
+
+ Fifo8 rx_sram;
+ Fifo8 tx_sram;
+
+ qemu_irq irq;
+
+ XlnxCSUDMA *dma_src;
+ bool ind_write_disabled;
+ bool dac_with_indac;
+ bool dac_enable;
+ bool src_dma_inprog;
+
+ IndOp rd_ind_op[2];
+ IndOp wr_ind_op[2];
+
+ uint32_t regs[XILINX_VERSAL_OSPI_R_MAX];
+ RegisterInfo regs_info[XILINX_VERSAL_OSPI_R_MAX];
+
+ /* Maximum inferred membank size is 512 bytes */
+ uint8_t stig_membank[512];
+};
+
+#endif /* XILINX_VERSAL_OSPI_H */
diff --git a/include/qemu-common.h b/include/qemu-common.h
index 73bcf763ed..68b2e3bc10 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -13,7 +13,7 @@
#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
/* Copyright string for -version arguments, About dialogs, etc */
-#define QEMU_COPYRIGHT "Copyright (c) 2003-2021 " \
+#define QEMU_COPYRIGHT "Copyright (c) 2003-2022 " \
"Fabrice Bellard and the QEMU Project developers"
/* Bug reporting information for --help arguments, About dialogs, etc */
@@ -26,9 +26,6 @@
int qemu_main(int argc, char **argv, char **envp);
#endif
-void qemu_get_timedate(struct tm *tm, int offset);
-int qemu_timedate_diff(struct tm *tm);
-
void *qemu_oom_check(void *ptr);
ssize_t qemu_write_full(int fd, const void *buf, size_t count)
diff --git a/include/qemu/vhost-user-server.h b/include/qemu/vhost-user-server.h
index 121ea1dedf..cd43193b80 100644
--- a/include/qemu/vhost-user-server.h
+++ b/include/qemu/vhost-user-server.h
@@ -42,6 +42,8 @@ typedef struct {
const VuDevIface *vu_iface;
/* Protected by ctx lock */
+ unsigned int refcount;
+ bool wait_idle;
VuDev vu_dev;
QIOChannel *ioc; /* The I/O channel with the client */
QIOChannelSocket *sioc; /* The underlying data channel with the client */
@@ -59,6 +61,9 @@ bool vhost_user_server_start(VuServer *server,
void vhost_user_server_stop(VuServer *server);
+void vhost_user_server_ref(VuServer *server);
+void vhost_user_server_unref(VuServer *server);
+
void vhost_user_server_attach_aio_context(VuServer *server, AioContext *ctx);
void vhost_user_server_detach_aio_context(VuServer *server);
diff --git a/include/sysemu/rtc.h b/include/sysemu/rtc.h
new file mode 100644
index 0000000000..159702b45b
--- /dev/null
+++ b/include/sysemu/rtc.h
@@ -0,0 +1,58 @@
+/*
+ * RTC configuration and clock read
+ *
+ * Copyright (c) 2003-2021 QEMU contributors
+ *
+ * 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.
+ */
+
+#ifndef SYSEMU_RTC_H
+#define SYSEMU_RTC_H
+
+/**
+ * qemu_get_timedate: Get the current RTC time
+ * @tm: struct tm to fill in with RTC time
+ * @offset: offset in seconds to adjust the RTC time by before
+ * converting to struct tm format.
+ *
+ * This function fills in @tm with the current RTC time, as adjusted
+ * by @offset (for example, if @offset is 3600 then the returned time/date
+ * will be one hour further ahead than the current RTC time).
+ *
+ * The usual use is by RTC device models, which should call this function
+ * to find the time/date value that they should return to the guest
+ * when it reads the RTC registers.
+ *
+ * The behaviour of the clock whose value this function returns will
+ * depend on the -rtc command line option passed by the user.
+ */
+void qemu_get_timedate(struct tm *tm, int offset);
+
+/**
+ * qemu_timedate_diff: Return difference between a struct tm and the RTC
+ * @tm: struct tm containing the date/time to compare against
+ *
+ * Returns the difference in seconds between the RTC clock time
+ * and the date/time specified in @tm. For example, if @tm specifies
+ * a timestamp one hour further ahead than the current RTC time
+ * then this function will return 3600.
+ */
+int qemu_timedate_diff(struct tm *tm);
+
+#endif
diff --git a/meson.build b/meson.build
index 833fd6bc4c..5f43355071 100644
--- a/meson.build
+++ b/meson.build
@@ -3,8 +3,9 @@ project('qemu', ['c'], meson_version: '>=0.58.2',
'b_staticpic=false', 'stdsplit=false'],
version: files('VERSION'))
-add_test_setup('quick', exclude_suites: 'slow', is_default: true)
-add_test_setup('slow', env: ['G_TEST_SLOW=1', 'SPEED=slow'])
+add_test_setup('quick', exclude_suites: ['block', 'slow', 'thorough'], is_default: true)
+add_test_setup('slow', exclude_suites: ['block', 'thorough'], env: ['G_TEST_SLOW=1', 'SPEED=slow'])
+add_test_setup('thorough', exclude_suites: ['block'], env: ['G_TEST_SLOW=1', 'SPEED=thorough'])
not_found = dependency('', required: false)
keyval = import('keyval')
@@ -41,6 +42,7 @@ qemu_icondir = get_option('datadir') / 'icons'
config_host_data = configuration_data()
genh = []
+qapi_trace_events = []
target_dirs = config_host['TARGET_DIRS'].split()
have_linux_user = false
@@ -2279,7 +2281,7 @@ if have_system
if fdt.found() and cc.links('''
#include <libfdt.h>
#include <libfdt_env.h>
- int main(void) { fdt_check_full(NULL, 0); return 0; }''',
+ int main(void) { fdt_find_max_phandle(NULL, NULL); return 0; }''',
dependencies: fdt)
fdt_opt = 'system'
elif fdt_opt == 'system'
@@ -2456,9 +2458,12 @@ trace_events_subdirs = [
'monitor',
'util',
]
-if have_user
+if have_linux_user
trace_events_subdirs += [ 'linux-user' ]
endif
+if have_bsd_user
+ trace_events_subdirs += [ 'bsd-user' ]
+endif
if have_block
trace_events_subdirs += [
'authz',
@@ -2557,6 +2562,8 @@ if 'CONFIG_VHOST_USER' in config_host
vhost_user = libvhost_user.get_variable('vhost_user_dep')
endif
+# NOTE: the trace/ subdirectory needs the qapi_trace_events variable
+# that is filled in by qapi/.
subdir('qapi')
subdir('qobject')
subdir('stubs')
@@ -2943,6 +2950,7 @@ foreach target : target_dirs
if 'CONFIG_BSD_USER' in config_target
base_dir = 'bsd-user'
target_inc += include_directories('bsd-user/' / targetos)
+ target_inc += include_directories('bsd-user/host/' / host_arch)
dir = base_dir / abi
arch_srcs += files(dir / 'signal.c', dir / 'target_arch_cpu.c')
endif
@@ -3052,17 +3060,14 @@ foreach target : target_dirs
install_input += meson.current_source_dir() / entitlements
endif
+ entitlement = find_program('scripts/entitlement.sh')
emulators += {exe['name'] : custom_target(exe['name'],
input: build_input,
output: exe['name'],
- command: [
- files('scripts/entitlement.sh'),
- '@OUTPUT@',
- '@INPUT@'
- ])
+ command: [entitlement, '@OUTPUT@', '@INPUT@'])
}
- meson.add_install_script('scripts/entitlement.sh', '--install',
+ meson.add_install_script(entitlement, '--install',
get_option('bindir') / exe['name'],
install_input)
else
diff --git a/migration/migration.c b/migration/migration.c
index 0652165610..bcc385b94b 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1014,6 +1014,9 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s)
info->ram->page_size = page_size;
info->ram->multifd_bytes = ram_counters.multifd_bytes;
info->ram->pages_per_second = s->pages_per_second;
+ info->ram->precopy_bytes = ram_counters.precopy_bytes;
+ info->ram->downtime_bytes = ram_counters.downtime_bytes;
+ info->ram->postcopy_bytes = ram_counters.postcopy_bytes;
if (migrate_use_xbzrle()) {
info->has_xbzrle_cache = true;
@@ -2991,10 +2994,7 @@ static int postcopy_start(MigrationState *ms)
* that are dirty
*/
if (migrate_postcopy_ram()) {
- if (ram_postcopy_send_discard_bitmap(ms)) {
- error_report("postcopy send discard bitmap failed");
- goto fail;
- }
+ ram_postcopy_send_discard_bitmap(ms);
}
/*
@@ -3205,7 +3205,7 @@ static void migration_completion(MigrationState *s)
qemu_mutex_unlock_iothread();
trace_migration_completion_postcopy_end_after_complete();
- } else if (s->state == MIGRATION_STATUS_CANCELLING) {
+ } else {
goto fail;
}
@@ -3230,7 +3230,11 @@ static void migration_completion(MigrationState *s)
goto fail_invalidate;
}
- if (!migrate_colo_enabled()) {
+ if (migrate_colo_enabled() && s->state == MIGRATION_STATUS_ACTIVE) {
+ /* COLO does not support postcopy */
+ migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE,
+ MIGRATION_STATUS_COLO);
+ } else {
migrate_set_state(&s->state, current_active_state,
MIGRATION_STATUS_COMPLETED);
}
@@ -3621,16 +3625,6 @@ static void migration_iteration_finish(MigrationState *s)
"COLO enabled", __func__);
}
migrate_start_colo_process(s);
- /*
- * Fixme: we will run VM in COLO no matter its old running state.
- * After exited COLO, we will keep running.
- */
- /* Fallthrough */
- case MIGRATION_STATUS_ACTIVE:
- /*
- * We should really assert here, but since it's during
- * migration, let's try to reduce the usage of assertions.
- */
s->vm_was_running = true;
/* Fallthrough */
case MIGRATION_STATUS_FAILED:
diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c
index da6201704c..aba1c88a0c 100644
--- a/migration/multifd-zlib.c
+++ b/migration/multifd-zlib.c
@@ -51,16 +51,16 @@ static int zlib_send_setup(MultiFDSendParams *p, Error **errp)
zs->opaque = Z_NULL;
if (deflateInit(zs, migrate_multifd_zlib_level()) != Z_OK) {
g_free(z);
- error_setg(errp, "multifd %d: deflate init failed", p->id);
+ error_setg(errp, "multifd %u: deflate init failed", p->id);
return -1;
}
- /* To be safe, we reserve twice the size of the packet */
- z->zbuff_len = MULTIFD_PACKET_SIZE * 2;
+ /* This is the maxium size of the compressed buffer */
+ z->zbuff_len = compressBound(MULTIFD_PACKET_SIZE);
z->zbuff = g_try_malloc(z->zbuff_len);
if (!z->zbuff) {
deflateEnd(&z->zs);
g_free(z);
- error_setg(errp, "multifd %d: out of memory for zbuff", p->id);
+ error_setg(errp, "multifd %u: out of memory for zbuff", p->id);
return -1;
}
p->data = z;
@@ -106,16 +106,16 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
int ret;
uint32_t i;
- for (i = 0; i < p->pages->num; i++) {
+ for (i = 0; i < p->normal_num; i++) {
uint32_t available = z->zbuff_len - out_size;
int flush = Z_NO_FLUSH;
- if (i == p->pages->num - 1) {
+ if (i == p->normal_num - 1) {
flush = Z_SYNC_FLUSH;
}
zs->avail_in = page_size;
- zs->next_in = p->pages->block->host + p->pages->offset[i];
+ zs->next_in = p->pages->block->host + p->normal[i];
zs->avail_out = available;
zs->next_out = z->zbuff + out_size;
@@ -132,17 +132,20 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
ret = deflate(zs, flush);
} while (ret == Z_OK && zs->avail_in && zs->avail_out);
if (ret == Z_OK && zs->avail_in) {
- error_setg(errp, "multifd %d: deflate failed to compress all input",
+ error_setg(errp, "multifd %u: deflate failed to compress all input",
p->id);
return -1;
}
if (ret != Z_OK) {
- error_setg(errp, "multifd %d: deflate returned %d instead of Z_OK",
+ error_setg(errp, "multifd %u: deflate returned %d instead of Z_OK",
p->id, ret);
return -1;
}
out_size += available - zs->avail_out;
}
+ p->iov[p->iovs_num].iov_base = z->zbuff;
+ p->iov[p->iovs_num].iov_len = out_size;
+ p->iovs_num++;
p->next_packet_size = out_size;
p->flags |= MULTIFD_FLAG_ZLIB;
@@ -150,25 +153,6 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
}
/**
- * zlib_send_write: do the actual write of the data
- *
- * Do the actual write of the comprresed buffer.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @used: number of pages used
- * @errp: pointer to an error
- */
-static int zlib_send_write(MultiFDSendParams *p, uint32_t used, Error **errp)
-{
- struct zlib_data *z = p->data;
-
- return qio_channel_write_all(p->c, (void *)z->zbuff, p->next_packet_size,
- errp);
-}
-
-/**
* zlib_recv_setup: setup receive side
*
* Create the compressed channel and buffer.
@@ -190,7 +174,7 @@ static int zlib_recv_setup(MultiFDRecvParams *p, Error **errp)
zs->avail_in = 0;
zs->next_in = Z_NULL;
if (inflateInit(zs) != Z_OK) {
- error_setg(errp, "multifd %d: inflate init failed", p->id);
+ error_setg(errp, "multifd %u: inflate init failed", p->id);
return -1;
}
/* To be safe, we reserve twice the size of the packet */
@@ -198,7 +182,7 @@ static int zlib_recv_setup(MultiFDRecvParams *p, Error **errp)
z->zbuff = g_try_malloc(z->zbuff_len);
if (!z->zbuff) {
inflateEnd(zs);
- error_setg(errp, "multifd %d: out of memory for zbuff", p->id);
+ error_setg(errp, "multifd %u: out of memory for zbuff", p->id);
return -1;
}
return 0;
@@ -241,13 +225,13 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp)
uint32_t in_size = p->next_packet_size;
/* we measure the change of total_out */
uint32_t out_size = zs->total_out;
- uint32_t expected_size = p->pages->num * qemu_target_page_size();
+ uint32_t expected_size = p->normal_num * page_size;
uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
int ret;
int i;
if (flags != MULTIFD_FLAG_ZLIB) {
- error_setg(errp, "multifd %d: flags received %x flags expected %x",
+ error_setg(errp, "multifd %u: flags received %x flags expected %x",
p->id, flags, MULTIFD_FLAG_ZLIB);
return -1;
}
@@ -260,16 +244,16 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp)
zs->avail_in = in_size;
zs->next_in = z->zbuff;
- for (i = 0; i < p->pages->num; i++) {
+ for (i = 0; i < p->normal_num; i++) {
int flush = Z_NO_FLUSH;
unsigned long start = zs->total_out;
- if (i == p->pages->num - 1) {
+ if (i == p->normal_num - 1) {
flush = Z_SYNC_FLUSH;
}
zs->avail_out = page_size;
- zs->next_out = p->pages->block->host + p->pages->offset[i];
+ zs->next_out = p->host + p->normal[i];
/*
* Welcome to inflate semantics
@@ -284,19 +268,19 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp)
} while (ret == Z_OK && zs->avail_in
&& (zs->total_out - start) < page_size);
if (ret == Z_OK && (zs->total_out - start) < page_size) {
- error_setg(errp, "multifd %d: inflate generated too few output",
+ error_setg(errp, "multifd %u: inflate generated too few output",
p->id);
return -1;
}
if (ret != Z_OK) {
- error_setg(errp, "multifd %d: inflate returned %d instead of Z_OK",
+ error_setg(errp, "multifd %u: inflate returned %d instead of Z_OK",
p->id, ret);
return -1;
}
}
out_size = zs->total_out - out_size;
if (out_size != expected_size) {
- error_setg(errp, "multifd %d: packet size received %d size expected %d",
+ error_setg(errp, "multifd %u: packet size received %u size expected %u",
p->id, out_size, expected_size);
return -1;
}
@@ -307,7 +291,6 @@ static MultiFDMethods multifd_zlib_ops = {
.send_setup = zlib_send_setup,
.send_cleanup = zlib_send_cleanup,
.send_prepare = zlib_send_prepare,
- .send_write = zlib_send_write,
.recv_setup = zlib_recv_setup,
.recv_cleanup = zlib_recv_cleanup,
.recv_pages = zlib_recv_pages
diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c
index 2d5b61106c..d788d309f2 100644
--- a/migration/multifd-zstd.c
+++ b/migration/multifd-zstd.c
@@ -55,7 +55,7 @@ static int zstd_send_setup(MultiFDSendParams *p, Error **errp)
z->zcs = ZSTD_createCStream();
if (!z->zcs) {
g_free(z);
- error_setg(errp, "multifd %d: zstd createCStream failed", p->id);
+ error_setg(errp, "multifd %u: zstd createCStream failed", p->id);
return -1;
}
@@ -63,17 +63,17 @@ static int zstd_send_setup(MultiFDSendParams *p, Error **errp)
if (ZSTD_isError(res)) {
ZSTD_freeCStream(z->zcs);
g_free(z);
- error_setg(errp, "multifd %d: initCStream failed with error %s",
+ error_setg(errp, "multifd %u: initCStream failed with error %s",
p->id, ZSTD_getErrorName(res));
return -1;
}
- /* To be safe, we reserve twice the size of the packet */
- z->zbuff_len = MULTIFD_PACKET_SIZE * 2;
+ /* This is the maxium size of the compressed buffer */
+ z->zbuff_len = ZSTD_compressBound(MULTIFD_PACKET_SIZE);
z->zbuff = g_try_malloc(z->zbuff_len);
if (!z->zbuff) {
ZSTD_freeCStream(z->zcs);
g_free(z);
- error_setg(errp, "multifd %d: out of memory for zbuff", p->id);
+ error_setg(errp, "multifd %u: out of memory for zbuff", p->id);
return -1;
}
return 0;
@@ -121,13 +121,13 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
z->out.size = z->zbuff_len;
z->out.pos = 0;
- for (i = 0; i < p->pages->num; i++) {
+ for (i = 0; i < p->normal_num; i++) {
ZSTD_EndDirective flush = ZSTD_e_continue;
- if (i == p->pages->num - 1) {
+ if (i == p->normal_num - 1) {
flush = ZSTD_e_flush;
}
- z->in.src = p->pages->block->host + p->pages->offset[i];
+ z->in.src = p->pages->block->host + p->normal[i];
z->in.size = page_size;
z->in.pos = 0;
@@ -144,16 +144,19 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
} while (ret > 0 && (z->in.size - z->in.pos > 0)
&& (z->out.size - z->out.pos > 0));
if (ret > 0 && (z->in.size - z->in.pos > 0)) {
- error_setg(errp, "multifd %d: compressStream buffer too small",
+ error_setg(errp, "multifd %u: compressStream buffer too small",
p->id);
return -1;
}
if (ZSTD_isError(ret)) {
- error_setg(errp, "multifd %d: compressStream error %s",
+ error_setg(errp, "multifd %u: compressStream error %s",
p->id, ZSTD_getErrorName(ret));
return -1;
}
}
+ p->iov[p->iovs_num].iov_base = z->zbuff;
+ p->iov[p->iovs_num].iov_len = z->out.pos;
+ p->iovs_num++;
p->next_packet_size = z->out.pos;
p->flags |= MULTIFD_FLAG_ZSTD;
@@ -161,25 +164,6 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
}
/**
- * zstd_send_write: do the actual write of the data
- *
- * Do the actual write of the comprresed buffer.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @used: number of pages used
- * @errp: pointer to an error
- */
-static int zstd_send_write(MultiFDSendParams *p, uint32_t used, Error **errp)
-{
- struct zstd_data *z = p->data;
-
- return qio_channel_write_all(p->c, (void *)z->zbuff, p->next_packet_size,
- errp);
-}
-
-/**
* zstd_recv_setup: setup receive side
*
* Create the compressed channel and buffer.
@@ -198,7 +182,7 @@ static int zstd_recv_setup(MultiFDRecvParams *p, Error **errp)
z->zds = ZSTD_createDStream();
if (!z->zds) {
g_free(z);
- error_setg(errp, "multifd %d: zstd createDStream failed", p->id);
+ error_setg(errp, "multifd %u: zstd createDStream failed", p->id);
return -1;
}
@@ -206,7 +190,7 @@ static int zstd_recv_setup(MultiFDRecvParams *p, Error **errp)
if (ZSTD_isError(ret)) {
ZSTD_freeDStream(z->zds);
g_free(z);
- error_setg(errp, "multifd %d: initDStream failed with error %s",
+ error_setg(errp, "multifd %u: initDStream failed with error %s",
p->id, ZSTD_getErrorName(ret));
return -1;
}
@@ -217,7 +201,7 @@ static int zstd_recv_setup(MultiFDRecvParams *p, Error **errp)
if (!z->zbuff) {
ZSTD_freeDStream(z->zds);
g_free(z);
- error_setg(errp, "multifd %d: out of memory for zbuff", p->id);
+ error_setg(errp, "multifd %u: out of memory for zbuff", p->id);
return -1;
}
return 0;
@@ -258,14 +242,14 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp)
uint32_t in_size = p->next_packet_size;
uint32_t out_size = 0;
size_t page_size = qemu_target_page_size();
- uint32_t expected_size = p->pages->num * page_size;
+ uint32_t expected_size = p->normal_num * page_size;
uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
struct zstd_data *z = p->data;
int ret;
int i;
if (flags != MULTIFD_FLAG_ZSTD) {
- error_setg(errp, "multifd %d: flags received %x flags expected %x",
+ error_setg(errp, "multifd %u: flags received %x flags expected %x",
p->id, flags, MULTIFD_FLAG_ZSTD);
return -1;
}
@@ -279,8 +263,8 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp)
z->in.size = in_size;
z->in.pos = 0;
- for (i = 0; i < p->pages->num; i++) {
- z->out.dst = p->pages->block->host + p->pages->offset[i];
+ for (i = 0; i < p->normal_num; i++) {
+ z->out.dst = p->host + p->normal[i];
z->out.size = page_size;
z->out.pos = 0;
@@ -297,19 +281,19 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp)
} while (ret > 0 && (z->in.size - z->in.pos > 0)
&& (z->out.pos < page_size));
if (ret > 0 && (z->out.pos < page_size)) {
- error_setg(errp, "multifd %d: decompressStream buffer too small",
+ error_setg(errp, "multifd %u: decompressStream buffer too small",
p->id);
return -1;
}
if (ZSTD_isError(ret)) {
- error_setg(errp, "multifd %d: decompressStream returned %s",
+ error_setg(errp, "multifd %u: decompressStream returned %s",
p->id, ZSTD_getErrorName(ret));
return ret;
}
out_size += z->out.pos;
}
if (out_size != expected_size) {
- error_setg(errp, "multifd %d: packet size received %d size expected %d",
+ error_setg(errp, "multifd %u: packet size received %u size expected %u",
p->id, out_size, expected_size);
return -1;
}
@@ -320,7 +304,6 @@ static MultiFDMethods multifd_zstd_ops = {
.send_setup = zstd_send_setup,
.send_cleanup = zstd_send_cleanup,
.send_prepare = zstd_send_prepare,
- .send_write = zstd_send_write,
.recv_setup = zstd_recv_setup,
.recv_cleanup = zstd_recv_cleanup,
.recv_pages = zstd_recv_pages
diff --git a/migration/multifd.c b/migration/multifd.c
index 3242f688e5..76b57a7177 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -86,28 +86,21 @@ static void nocomp_send_cleanup(MultiFDSendParams *p, Error **errp)
*/
static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp)
{
- p->next_packet_size = p->pages->num * qemu_target_page_size();
+ MultiFDPages_t *pages = p->pages;
+ size_t page_size = qemu_target_page_size();
+
+ for (int i = 0; i < p->normal_num; i++) {
+ p->iov[p->iovs_num].iov_base = pages->block->host + p->normal[i];
+ p->iov[p->iovs_num].iov_len = page_size;
+ p->iovs_num++;
+ }
+
+ p->next_packet_size = p->normal_num * page_size;
p->flags |= MULTIFD_FLAG_NOCOMP;
return 0;
}
/**
- * nocomp_send_write: do the actual write of the data
- *
- * For no compression we just have to write the data.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @used: number of pages used
- * @errp: pointer to an error
- */
-static int nocomp_send_write(MultiFDSendParams *p, uint32_t used, Error **errp)
-{
- return qio_channel_writev_all(p->c, p->pages->iov, used, errp);
-}
-
-/**
* nocomp_recv_setup: setup receive side
*
* For no compression this function does nothing.
@@ -146,20 +139,24 @@ static void nocomp_recv_cleanup(MultiFDRecvParams *p)
static int nocomp_recv_pages(MultiFDRecvParams *p, Error **errp)
{
uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
+ size_t page_size = qemu_target_page_size();
if (flags != MULTIFD_FLAG_NOCOMP) {
- error_setg(errp, "multifd %d: flags received %x flags expected %x",
+ error_setg(errp, "multifd %u: flags received %x flags expected %x",
p->id, flags, MULTIFD_FLAG_NOCOMP);
return -1;
}
- return qio_channel_readv_all(p->c, p->pages->iov, p->pages->num, errp);
+ for (int i = 0; i < p->normal_num; i++) {
+ p->iov[i].iov_base = p->host + p->normal[i];
+ p->iov[i].iov_len = page_size;
+ }
+ return qio_channel_readv_all(p->c, p->iov, p->normal_num, errp);
}
static MultiFDMethods multifd_nocomp_ops = {
.send_setup = nocomp_send_setup,
.send_cleanup = nocomp_send_cleanup,
.send_prepare = nocomp_send_prepare,
- .send_write = nocomp_send_write,
.recv_setup = nocomp_recv_setup,
.recv_cleanup = nocomp_recv_cleanup,
.recv_pages = nocomp_recv_pages
@@ -212,8 +209,8 @@ static int multifd_recv_initial_packet(QIOChannel *c, Error **errp)
}
if (msg.version != MULTIFD_VERSION) {
- error_setg(errp, "multifd: received packet version %d "
- "expected %d", msg.version, MULTIFD_VERSION);
+ error_setg(errp, "multifd: received packet version %u "
+ "expected %u", msg.version, MULTIFD_VERSION);
return -1;
}
@@ -229,8 +226,8 @@ static int multifd_recv_initial_packet(QIOChannel *c, Error **errp)
}
if (msg.id > migrate_multifd_channels()) {
- error_setg(errp, "multifd: received channel version %d "
- "expected %d", msg.version, MULTIFD_VERSION);
+ error_setg(errp, "multifd: received channel version %u "
+ "expected %u", msg.version, MULTIFD_VERSION);
return -1;
}
@@ -242,7 +239,6 @@ static MultiFDPages_t *multifd_pages_init(size_t size)
MultiFDPages_t *pages = g_new0(MultiFDPages_t, 1);
pages->allocated = size;
- pages->iov = g_new0(struct iovec, size);
pages->offset = g_new0(ram_addr_t, size);
return pages;
@@ -254,8 +250,6 @@ static void multifd_pages_clear(MultiFDPages_t *pages)
pages->allocated = 0;
pages->packet_num = 0;
pages->block = NULL;
- g_free(pages->iov);
- pages->iov = NULL;
g_free(pages->offset);
pages->offset = NULL;
g_free(pages);
@@ -268,7 +262,7 @@ static void multifd_send_fill_packet(MultiFDSendParams *p)
packet->flags = cpu_to_be32(p->flags);
packet->pages_alloc = cpu_to_be32(p->pages->allocated);
- packet->pages_used = cpu_to_be32(p->pages->num);
+ packet->normal_pages = cpu_to_be32(p->normal_num);
packet->next_packet_size = cpu_to_be32(p->next_packet_size);
packet->packet_num = cpu_to_be64(p->packet_num);
@@ -276,9 +270,9 @@ static void multifd_send_fill_packet(MultiFDSendParams *p)
strncpy(packet->ramblock, p->pages->block->idstr, 256);
}
- for (i = 0; i < p->pages->num; i++) {
+ for (i = 0; i < p->normal_num; i++) {
/* there are architectures where ram_addr_t is 32 bit */
- uint64_t temp = p->pages->offset[i];
+ uint64_t temp = p->normal[i];
packet->offset[i] = cpu_to_be64(temp);
}
@@ -288,7 +282,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
{
MultiFDPacket_t *packet = p->packet;
size_t page_size = qemu_target_page_size();
- uint32_t pages_max = MULTIFD_PACKET_SIZE / page_size;
+ uint32_t page_count = MULTIFD_PACKET_SIZE / page_size;
RAMBlock *block;
int i;
@@ -303,7 +297,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
packet->version = be32_to_cpu(packet->version);
if (packet->version != MULTIFD_VERSION) {
error_setg(errp, "multifd: received packet "
- "version %d and expected version %d",
+ "version %u and expected version %u",
packet->version, MULTIFD_VERSION);
return -1;
}
@@ -315,33 +309,25 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
* If we received a packet that is 100 times bigger than expected
* just stop migration. It is a magic number.
*/
- if (packet->pages_alloc > pages_max * 100) {
+ if (packet->pages_alloc > page_count) {
error_setg(errp, "multifd: received packet "
- "with size %d and expected a maximum size of %d",
- packet->pages_alloc, pages_max * 100) ;
+ "with size %u and expected a size of %u",
+ packet->pages_alloc, page_count) ;
return -1;
}
- /*
- * We received a packet that is bigger than expected but inside
- * reasonable limits (see previous comment). Just reallocate.
- */
- if (packet->pages_alloc > p->pages->allocated) {
- multifd_pages_clear(p->pages);
- p->pages = multifd_pages_init(packet->pages_alloc);
- }
- p->pages->num = be32_to_cpu(packet->pages_used);
- if (p->pages->num > packet->pages_alloc) {
+ p->normal_num = be32_to_cpu(packet->normal_pages);
+ if (p->normal_num > packet->pages_alloc) {
error_setg(errp, "multifd: received packet "
- "with %d pages and expected maximum pages are %d",
- p->pages->num, packet->pages_alloc) ;
+ "with %u pages and expected maximum pages are %u",
+ p->normal_num, packet->pages_alloc) ;
return -1;
}
p->next_packet_size = be32_to_cpu(packet->next_packet_size);
p->packet_num = be64_to_cpu(packet->packet_num);
- if (p->pages->num == 0) {
+ if (p->normal_num == 0) {
return 0;
}
@@ -354,8 +340,8 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
return -1;
}
- p->pages->block = block;
- for (i = 0; i < p->pages->num; i++) {
+ p->host = block->host;
+ for (i = 0; i < p->normal_num; i++) {
uint64_t offset = be64_to_cpu(packet->offset[i]);
if (offset > (block->used_length - page_size)) {
@@ -364,9 +350,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
offset, block->used_length);
return -1;
}
- p->pages->offset[i] = offset;
- p->pages->iov[i].iov_base = block->host + offset;
- p->pages->iov[i].iov_len = page_size;
+ p->normal[i] = offset;
}
return 0;
@@ -470,8 +454,6 @@ int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset)
if (pages->block == block) {
pages->offset[pages->num] = offset;
- pages->iov[pages->num].iov_base = block->host + offset;
- pages->iov[pages->num].iov_len = qemu_target_page_size();
pages->num++;
if (pages->num < pages->allocated) {
@@ -567,6 +549,10 @@ void multifd_save_cleanup(void)
p->packet_len = 0;
g_free(p->packet);
p->packet = NULL;
+ g_free(p->iov);
+ p->iov = NULL;
+ g_free(p->normal);
+ p->normal = NULL;
multifd_send_state->ops->send_cleanup(p, &local_err);
if (local_err) {
migrate_set_error(migrate_get_current(), local_err);
@@ -651,11 +637,17 @@ static void *multifd_send_thread(void *opaque)
qemu_mutex_lock(&p->mutex);
if (p->pending_job) {
- uint32_t used = p->pages->num;
uint64_t packet_num = p->packet_num;
uint32_t flags = p->flags;
+ p->iovs_num = 1;
+ p->normal_num = 0;
+
+ for (int i = 0; i < p->pages->num; i++) {
+ p->normal[p->normal_num] = p->pages->offset[i];
+ p->normal_num++;
+ }
- if (used) {
+ if (p->normal_num) {
ret = multifd_send_state->ops->send_prepare(p, &local_err);
if (ret != 0) {
qemu_mutex_unlock(&p->mutex);
@@ -665,27 +657,23 @@ static void *multifd_send_thread(void *opaque)
multifd_send_fill_packet(p);
p->flags = 0;
p->num_packets++;
- p->num_pages += used;
+ p->total_normal_pages += p->normal_num;
p->pages->num = 0;
p->pages->block = NULL;
qemu_mutex_unlock(&p->mutex);
- trace_multifd_send(p->id, packet_num, used, flags,
+ trace_multifd_send(p->id, packet_num, p->normal_num, flags,
p->next_packet_size);
- ret = qio_channel_write_all(p->c, (void *)p->packet,
- p->packet_len, &local_err);
+ p->iov[0].iov_len = p->packet_len;
+ p->iov[0].iov_base = p->packet;
+
+ ret = qio_channel_writev_all(p->c, p->iov, p->iovs_num,
+ &local_err);
if (ret != 0) {
break;
}
- if (used) {
- ret = multifd_send_state->ops->send_write(p, used, &local_err);
- if (ret != 0) {
- break;
- }
- }
-
qemu_mutex_lock(&p->mutex);
p->pending_job--;
qemu_mutex_unlock(&p->mutex);
@@ -724,7 +712,7 @@ out:
qemu_mutex_unlock(&p->mutex);
rcu_unregister_thread();
- trace_multifd_send_thread_end(p->id, p->num_packets, p->num_pages);
+ trace_multifd_send_thread_end(p->id, p->num_packets, p->total_normal_pages);
return NULL;
}
@@ -922,6 +910,9 @@ int multifd_save_setup(Error **errp)
p->packet->version = cpu_to_be32(MULTIFD_VERSION);
p->name = g_strdup_printf("multifdsend_%d", i);
p->tls_hostname = g_strdup(s->hostname);
+ /* We need one extra place for the packet header */
+ p->iov = g_new0(struct iovec, page_count + 1);
+ p->normal = g_new0(ram_addr_t, page_count);
socket_send_channel_create(multifd_new_send_channel_async, p);
}
@@ -1016,11 +1007,13 @@ int multifd_load_cleanup(Error **errp)
qemu_sem_destroy(&p->sem_sync);
g_free(p->name);
p->name = NULL;
- multifd_pages_clear(p->pages);
- p->pages = NULL;
p->packet_len = 0;
g_free(p->packet);
p->packet = NULL;
+ g_free(p->iov);
+ p->iov = NULL;
+ g_free(p->normal);
+ p->normal = NULL;
multifd_recv_state->ops->recv_cleanup(p);
}
qemu_sem_destroy(&multifd_recv_state->sem_sync);
@@ -1069,7 +1062,6 @@ static void *multifd_recv_thread(void *opaque)
rcu_register_thread();
while (true) {
- uint32_t used;
uint32_t flags;
if (p->quit) {
@@ -1092,17 +1084,16 @@ static void *multifd_recv_thread(void *opaque)
break;
}
- used = p->pages->num;
flags = p->flags;
/* recv methods don't know how to handle the SYNC flag */
p->flags &= ~MULTIFD_FLAG_SYNC;
- trace_multifd_recv(p->id, p->packet_num, used, flags,
+ trace_multifd_recv(p->id, p->packet_num, p->normal_num, flags,
p->next_packet_size);
p->num_packets++;
- p->num_pages += used;
+ p->total_normal_pages += p->normal_num;
qemu_mutex_unlock(&p->mutex);
- if (used) {
+ if (p->normal_num) {
ret = multifd_recv_state->ops->recv_pages(p, &local_err);
if (ret != 0) {
break;
@@ -1124,7 +1115,7 @@ static void *multifd_recv_thread(void *opaque)
qemu_mutex_unlock(&p->mutex);
rcu_unregister_thread();
- trace_multifd_recv_thread_end(p->id, p->num_packets, p->num_pages);
+ trace_multifd_recv_thread_end(p->id, p->num_packets, p->total_normal_pages);
return NULL;
}
@@ -1156,11 +1147,12 @@ int multifd_load_setup(Error **errp)
qemu_sem_init(&p->sem_sync, 0);
p->quit = false;
p->id = i;
- p->pages = multifd_pages_init(page_count);
p->packet_len = sizeof(MultiFDPacket_t)
+ sizeof(uint64_t) * page_count;
p->packet = g_malloc0(p->packet_len);
p->name = g_strdup_printf("multifdrecv_%d", i);
+ p->iov = g_new0(struct iovec, page_count);
+ p->normal = g_new0(ram_addr_t, page_count);
}
for (i = 0; i < thread_count; i++) {
diff --git a/migration/multifd.h b/migration/multifd.h
index e57adc783b..4dda900a0b 100644
--- a/migration/multifd.h
+++ b/migration/multifd.h
@@ -44,7 +44,8 @@ typedef struct {
uint32_t flags;
/* maximum number of allocated pages */
uint32_t pages_alloc;
- uint32_t pages_used;
+ /* non zero pages */
+ uint32_t normal_pages;
/* size of the next packet that contains pages */
uint32_t next_packet_size;
uint64_t packet_num;
@@ -62,8 +63,6 @@ typedef struct {
uint64_t packet_num;
/* offset of each page */
ram_addr_t *offset;
- /* pointer to each page */
- struct iovec *iov;
RAMBlock *block;
} MultiFDPages_t;
@@ -106,10 +105,18 @@ typedef struct {
/* thread local variables */
/* packets sent through this channel */
uint64_t num_packets;
- /* pages sent through this channel */
- uint64_t num_pages;
+ /* non zero pages sent through this channel */
+ uint64_t total_normal_pages;
/* syncs main thread and channels */
QemuSemaphore sem_sync;
+ /* buffers to send */
+ struct iovec *iov;
+ /* number of iovs used */
+ uint32_t iovs_num;
+ /* Pages that are not zero */
+ ram_addr_t *normal;
+ /* num of non zero pages */
+ uint32_t normal_num;
/* used for compression methods */
void *data;
} MultiFDSendParams;
@@ -130,8 +137,8 @@ typedef struct {
bool running;
/* should this thread finish */
bool quit;
- /* array of pages to receive */
- MultiFDPages_t *pages;
+ /* ramblock host address */
+ uint8_t *host;
/* packet allocated len */
uint32_t packet_len;
/* pointer to the packet */
@@ -145,10 +152,16 @@ typedef struct {
uint32_t next_packet_size;
/* packets sent through this channel */
uint64_t num_packets;
- /* pages sent through this channel */
- uint64_t num_pages;
+ /* non zero pages recv through this channel */
+ uint64_t total_normal_pages;
/* syncs main thread and channels */
QemuSemaphore sem_sync;
+ /* buffers to recv */
+ struct iovec *iov;
+ /* Pages that are not zero */
+ ram_addr_t *normal;
+ /* num of non zero pages */
+ uint32_t normal_num;
/* used for de-compression methods */
void *data;
} MultiFDRecvParams;
@@ -160,8 +173,6 @@ typedef struct {
void (*send_cleanup)(MultiFDSendParams *p, Error **errp);
/* Prepare the send packet */
int (*send_prepare)(MultiFDSendParams *p, Error **errp);
- /* Write the send packet */
- int (*send_write)(MultiFDSendParams *p, uint32_t used, Error **errp);
/* Setup for receiving side */
int (*recv_setup)(MultiFDRecvParams *p, Error **errp);
/* Cleanup for receiving side */
diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index d18b5d05b2..e662dd05cc 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -283,15 +283,13 @@ static bool ufd_check_and_apply(int ufd, MigrationIncomingState *mis)
}
#ifdef UFFD_FEATURE_THREAD_ID
- if (migrate_postcopy_blocktime() && mis &&
- UFFD_FEATURE_THREAD_ID & supported_features) {
- /* kernel supports that feature */
- /* don't create blocktime_context if it exists */
- if (!mis->blocktime_ctx) {
- mis->blocktime_ctx = blocktime_context_new();
- }
-
+ if (UFFD_FEATURE_THREAD_ID & supported_features) {
asked_features |= UFFD_FEATURE_THREAD_ID;
+ if (migrate_postcopy_blocktime()) {
+ if (!mis->blocktime_ctx) {
+ mis->blocktime_ctx = blocktime_context_new();
+ }
+ }
}
#endif
@@ -525,6 +523,19 @@ int postcopy_ram_incoming_init(MigrationIncomingState *mis)
return 0;
}
+static void postcopy_temp_pages_cleanup(MigrationIncomingState *mis)
+{
+ if (mis->postcopy_tmp_page) {
+ munmap(mis->postcopy_tmp_page, mis->largest_page_size);
+ mis->postcopy_tmp_page = NULL;
+ }
+
+ if (mis->postcopy_tmp_zero_page) {
+ munmap(mis->postcopy_tmp_zero_page, mis->largest_page_size);
+ mis->postcopy_tmp_zero_page = NULL;
+ }
+}
+
/*
* At the end of a migration where postcopy_ram_incoming_init was called.
*/
@@ -566,14 +577,8 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis)
}
}
- if (mis->postcopy_tmp_page) {
- munmap(mis->postcopy_tmp_page, mis->largest_page_size);
- mis->postcopy_tmp_page = NULL;
- }
- if (mis->postcopy_tmp_zero_page) {
- munmap(mis->postcopy_tmp_zero_page, mis->largest_page_size);
- mis->postcopy_tmp_zero_page = NULL;
- }
+ postcopy_temp_pages_cleanup(mis);
+
trace_postcopy_ram_incoming_cleanup_blocktime(
get_postcopy_total_blocktime());
@@ -1084,6 +1089,40 @@ retry:
return NULL;
}
+static int postcopy_temp_pages_setup(MigrationIncomingState *mis)
+{
+ int err;
+
+ mis->postcopy_tmp_page = mmap(NULL, mis->largest_page_size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (mis->postcopy_tmp_page == MAP_FAILED) {
+ err = errno;
+ mis->postcopy_tmp_page = NULL;
+ error_report("%s: Failed to map postcopy_tmp_page %s",
+ __func__, strerror(err));
+ return -err;
+ }
+
+ /*
+ * Map large zero page when kernel can't use UFFDIO_ZEROPAGE for hugepages
+ */
+ mis->postcopy_tmp_zero_page = mmap(NULL, mis->largest_page_size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (mis->postcopy_tmp_zero_page == MAP_FAILED) {
+ err = errno;
+ mis->postcopy_tmp_zero_page = NULL;
+ error_report("%s: Failed to map large zero page %s",
+ __func__, strerror(err));
+ return -err;
+ }
+
+ memset(mis->postcopy_tmp_zero_page, '\0', mis->largest_page_size);
+
+ return 0;
+}
+
int postcopy_ram_incoming_setup(MigrationIncomingState *mis)
{
/* Open the fd for the kernel to give us userfaults */
@@ -1124,32 +1163,11 @@ int postcopy_ram_incoming_setup(MigrationIncomingState *mis)
return -1;
}
- mis->postcopy_tmp_page = mmap(NULL, mis->largest_page_size,
- PROT_READ | PROT_WRITE, MAP_PRIVATE |
- MAP_ANONYMOUS, -1, 0);
- if (mis->postcopy_tmp_page == MAP_FAILED) {
- mis->postcopy_tmp_page = NULL;
- error_report("%s: Failed to map postcopy_tmp_page %s",
- __func__, strerror(errno));
+ if (postcopy_temp_pages_setup(mis)) {
+ /* Error dumped in the sub-function */
return -1;
}
- /*
- * Map large zero page when kernel can't use UFFDIO_ZEROPAGE for hugepages
- */
- mis->postcopy_tmp_zero_page = mmap(NULL, mis->largest_page_size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1, 0);
- if (mis->postcopy_tmp_zero_page == MAP_FAILED) {
- int e = errno;
- mis->postcopy_tmp_zero_page = NULL;
- error_report("%s: Failed to map large zero page %s",
- __func__, strerror(e));
- return -e;
- }
- memset(mis->postcopy_tmp_zero_page, '\0', mis->largest_page_size);
-
trace_postcopy_ram_enable_notify();
return 0;
diff --git a/migration/ram.c b/migration/ram.c
index 57efa67f20..91ca743ac8 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -325,7 +325,8 @@ struct RAMState {
uint64_t xbzrle_bytes_prev;
/* Start using XBZRLE (e.g., after the first round). */
bool xbzrle_enabled;
-
+ /* Are we on the last stage of migration */
+ bool last_stage;
/* compression statistics since the beginning of the period */
/* amount of count that no free thread to compress data */
uint64_t compress_thread_busy_prev;
@@ -354,6 +355,12 @@ static RAMState *ram_state;
static NotifierWithReturnList precopy_notifier_list;
+/* Whether postcopy has queued requests? */
+static bool postcopy_has_request(RAMState *rs)
+{
+ return !QSIMPLEQ_EMPTY_ATOMIC(&rs->src_page_requests);
+}
+
void precopy_infrastructure_init(void)
{
notifier_with_return_list_init(&precopy_notifier_list);
@@ -386,6 +393,18 @@ uint64_t ram_bytes_remaining(void)
MigrationStats ram_counters;
+static void ram_transferred_add(uint64_t bytes)
+{
+ if (runstate_is_running()) {
+ ram_counters.precopy_bytes += bytes;
+ } else if (migration_in_postcopy()) {
+ ram_counters.postcopy_bytes += bytes;
+ } else {
+ ram_counters.downtime_bytes += bytes;
+ }
+ ram_counters.transferred += bytes;
+}
+
/* used by the search for pages to send */
struct PageSearchStatus {
/* Current block being searched */
@@ -683,11 +702,10 @@ static void xbzrle_cache_zero_page(RAMState *rs, ram_addr_t current_addr)
* @current_addr: addr of the page
* @block: block that contains the page we want to send
* @offset: offset inside the block for the page
- * @last_stage: if we are at the completion stage
*/
static int save_xbzrle_page(RAMState *rs, uint8_t **current_data,
ram_addr_t current_addr, RAMBlock *block,
- ram_addr_t offset, bool last_stage)
+ ram_addr_t offset)
{
int encoded_len = 0, bytes_xbzrle;
uint8_t *prev_cached_page;
@@ -695,7 +713,7 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data,
if (!cache_is_cached(XBZRLE.cache, current_addr,
ram_counters.dirty_sync_count)) {
xbzrle_counters.cache_miss++;
- if (!last_stage) {
+ if (!rs->last_stage) {
if (cache_insert(XBZRLE.cache, current_addr, *current_data,
ram_counters.dirty_sync_count) == -1) {
return -1;
@@ -734,7 +752,7 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data,
* Update the cache contents, so that it corresponds to the data
* sent, in all cases except where we skip the page.
*/
- if (!last_stage && encoded_len != 0) {
+ if (!rs->last_stage && encoded_len != 0) {
memcpy(prev_cached_page, XBZRLE.current_buf, TARGET_PAGE_SIZE);
/*
* In the case where we couldn't compress, ensure that the caller
@@ -767,7 +785,7 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data,
* RAM_SAVE_FLAG_CONTINUE.
*/
xbzrle_counters.bytes += bytes_xbzrle - 8;
- ram_counters.transferred += bytes_xbzrle;
+ ram_transferred_add(bytes_xbzrle);
return 1;
}
@@ -1158,6 +1176,15 @@ static void migration_bitmap_sync_precopy(RAMState *rs)
}
}
+static void ram_release_page(const char *rbname, uint64_t offset)
+{
+ if (!migrate_release_ram() || !migration_in_postcopy()) {
+ return;
+ }
+
+ ram_discard_range(rbname, offset, TARGET_PAGE_SIZE);
+}
+
/**
* save_zero_page_to_file: send the zero page to the file
*
@@ -1179,6 +1206,7 @@ static int save_zero_page_to_file(RAMState *rs, QEMUFile *file,
len += save_page_header(rs, file, block, offset | RAM_SAVE_FLAG_ZERO);
qemu_put_byte(file, 0);
len += 1;
+ ram_release_page(block->idstr, offset);
}
return len;
}
@@ -1198,21 +1226,12 @@ static int save_zero_page(RAMState *rs, RAMBlock *block, ram_addr_t offset)
if (len) {
ram_counters.duplicate++;
- ram_counters.transferred += len;
+ ram_transferred_add(len);
return 1;
}
return -1;
}
-static void ram_release_pages(const char *rbname, uint64_t offset, int pages)
-{
- if (!migrate_release_ram() || !migration_in_postcopy()) {
- return;
- }
-
- ram_discard_range(rbname, offset, ((ram_addr_t)pages) << TARGET_PAGE_BITS);
-}
-
/*
* @pages: the number of pages written by the control path,
* < 0 - error
@@ -1234,7 +1253,7 @@ static bool control_save_page(RAMState *rs, RAMBlock *block, ram_addr_t offset,
}
if (bytes_xmit) {
- ram_counters.transferred += bytes_xmit;
+ ram_transferred_add(bytes_xmit);
*pages = 1;
}
@@ -1265,8 +1284,8 @@ static bool control_save_page(RAMState *rs, RAMBlock *block, ram_addr_t offset,
static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset,
uint8_t *buf, bool async)
{
- ram_counters.transferred += save_page_header(rs, rs->f, block,
- offset | RAM_SAVE_FLAG_PAGE);
+ ram_transferred_add(save_page_header(rs, rs->f, block,
+ offset | RAM_SAVE_FLAG_PAGE));
if (async) {
qemu_put_buffer_async(rs->f, buf, TARGET_PAGE_SIZE,
migrate_release_ram() &
@@ -1274,7 +1293,7 @@ static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset,
} else {
qemu_put_buffer(rs->f, buf, TARGET_PAGE_SIZE);
}
- ram_counters.transferred += TARGET_PAGE_SIZE;
+ ram_transferred_add(TARGET_PAGE_SIZE);
ram_counters.normal++;
return 1;
}
@@ -1290,9 +1309,8 @@ static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset,
* @rs: current RAM state
* @block: block that contains the page we want to send
* @offset: offset inside the block for the page
- * @last_stage: if we are at the completion stage
*/
-static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage)
+static int ram_save_page(RAMState *rs, PageSearchStatus *pss)
{
int pages = -1;
uint8_t *p;
@@ -1307,8 +1325,8 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage)
XBZRLE_cache_lock();
if (rs->xbzrle_enabled && !migration_in_postcopy()) {
pages = save_xbzrle_page(rs, &p, current_addr, block,
- offset, last_stage);
- if (!last_stage) {
+ offset);
+ if (!rs->last_stage) {
/* Can't send this cached data async, since the cache page
* might get updated before it gets to the wire
*/
@@ -1341,13 +1359,11 @@ static bool do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block,
ram_addr_t offset, uint8_t *source_buf)
{
RAMState *rs = ram_state;
- uint8_t *p = block->host + (offset & TARGET_PAGE_MASK);
- bool zero_page = false;
+ uint8_t *p = block->host + offset;
int ret;
if (save_zero_page_to_file(rs, f, block, offset)) {
- zero_page = true;
- goto exit;
+ return true;
}
save_page_header(rs, f, block, offset | RAM_SAVE_FLAG_COMPRESS_PAGE);
@@ -1362,18 +1378,14 @@ static bool do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block,
if (ret < 0) {
qemu_file_set_error(migrate_get_current()->to_dst_file, ret);
error_report("compressed data failed!");
- return false;
}
-
-exit:
- ram_release_pages(block->idstr, offset & TARGET_PAGE_MASK, 1);
- return zero_page;
+ return false;
}
static void
update_compress_thread_counts(const CompressParam *param, int bytes_xmit)
{
- ram_counters.transferred += bytes_xmit;
+ ram_transferred_add(bytes_xmit);
if (param->zero_page) {
ram_counters.duplicate++;
@@ -1533,30 +1545,42 @@ static bool find_dirty_block(RAMState *rs, PageSearchStatus *pss, bool *again)
*/
static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset)
{
+ struct RAMSrcPageRequest *entry;
RAMBlock *block = NULL;
+ size_t page_size;
- if (QSIMPLEQ_EMPTY_ATOMIC(&rs->src_page_requests)) {
+ if (!postcopy_has_request(rs)) {
return NULL;
}
QEMU_LOCK_GUARD(&rs->src_page_req_mutex);
- if (!QSIMPLEQ_EMPTY(&rs->src_page_requests)) {
- struct RAMSrcPageRequest *entry =
- QSIMPLEQ_FIRST(&rs->src_page_requests);
- block = entry->rb;
- *offset = entry->offset;
-
- if (entry->len > TARGET_PAGE_SIZE) {
- entry->len -= TARGET_PAGE_SIZE;
- entry->offset += TARGET_PAGE_SIZE;
- } else {
- memory_region_unref(block->mr);
- QSIMPLEQ_REMOVE_HEAD(&rs->src_page_requests, next_req);
- g_free(entry);
- migration_consume_urgent_request();
- }
+
+ /*
+ * This should _never_ change even after we take the lock, because no one
+ * should be taking anything off the request list other than us.
+ */
+ assert(postcopy_has_request(rs));
+
+ entry = QSIMPLEQ_FIRST(&rs->src_page_requests);
+ block = entry->rb;
+ *offset = entry->offset;
+ page_size = qemu_ram_pagesize(block);
+ /* Each page request should only be multiple page size of the ramblock */
+ assert((entry->len % page_size) == 0);
+
+ if (entry->len > page_size) {
+ entry->len -= page_size;
+ entry->offset += page_size;
+ } else {
+ memory_region_unref(block->mr);
+ QSIMPLEQ_REMOVE_HEAD(&rs->src_page_requests, next_req);
+ g_free(entry);
+ migration_consume_urgent_request();
}
+ trace_unqueue_page(block->idstr, *offset,
+ test_bit((*offset >> TARGET_PAGE_BITS), block->bmap));
+
return block;
}
@@ -1611,7 +1635,7 @@ static int ram_save_release_protection(RAMState *rs, PageSearchStatus *pss,
/* Check if page is from UFFD-managed region. */
if (pss->block->flags & RAM_UF_WRITEPROTECT) {
void *page_address = pss->block->host + (start_page << TARGET_PAGE_BITS);
- uint64_t run_length = (pss->page - start_page + 1) << TARGET_PAGE_BITS;
+ uint64_t run_length = (pss->page - start_page) << TARGET_PAGE_BITS;
/* Flush async buffers before un-protect. */
qemu_fflush(rs->f);
@@ -1931,30 +1955,8 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss)
{
RAMBlock *block;
ram_addr_t offset;
- bool dirty;
-
- do {
- block = unqueue_page(rs, &offset);
- /*
- * We're sending this page, and since it's postcopy nothing else
- * will dirty it, and we must make sure it doesn't get sent again
- * even if this queue request was received after the background
- * search already sent it.
- */
- if (block) {
- unsigned long page;
- page = offset >> TARGET_PAGE_BITS;
- dirty = test_bit(page, block->bmap);
- if (!dirty) {
- trace_get_queued_page_not_dirty(block->idstr, (uint64_t)offset,
- page);
- } else {
- trace_get_queued_page(block->idstr, (uint64_t)offset, page);
- }
- }
-
- } while (block && !dirty);
+ block = unqueue_page(rs, &offset);
if (!block) {
/*
@@ -2129,10 +2131,8 @@ static bool save_compress_page(RAMState *rs, RAMBlock *block, ram_addr_t offset)
*
* @rs: current RAM state
* @pss: data about the page we want to send
- * @last_stage: if we are at the completion stage
*/
-static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss,
- bool last_stage)
+static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss)
{
RAMBlock *block = pss->block;
ram_addr_t offset = ((ram_addr_t)pss->page) << TARGET_PAGE_BITS;
@@ -2156,7 +2156,6 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss,
xbzrle_cache_zero_page(rs, block->offset + offset);
XBZRLE_cache_unlock();
}
- ram_release_pages(block->idstr, offset, res);
return res;
}
@@ -2171,7 +2170,7 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss,
return ram_save_multifd_page(rs, block, offset);
}
- return ram_save_page(rs, pss, last_stage);
+ return ram_save_page(rs, pss);
}
/**
@@ -2188,12 +2187,9 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss,
* Returns the number of pages written or negative on error
*
* @rs: current RAM state
- * @ms: current migration state
* @pss: data about the page we want to send
- * @last_stage: if we are at the completion stage
*/
-static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss,
- bool last_stage)
+static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss)
{
int tmppages, pages = 0;
size_t pagesize_bits =
@@ -2211,7 +2207,7 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss,
do {
/* Check the pages is dirty and if it is send it */
if (migration_bitmap_clear_dirty(rs, pss->block, pss->page)) {
- tmppages = ram_save_target_page(rs, pss, last_stage);
+ tmppages = ram_save_target_page(rs, pss);
if (tmppages < 0) {
return tmppages;
}
@@ -2230,7 +2226,7 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss,
offset_in_ramblock(pss->block,
((ram_addr_t)pss->page) << TARGET_PAGE_BITS));
/* The offset we leave with is the min boundary of host page and block */
- pss->page = MIN(pss->page, hostpage_boundary) - 1;
+ pss->page = MIN(pss->page, hostpage_boundary);
res = ram_save_release_protection(rs, pss, start_page);
return (res < 0 ? res : pages);
@@ -2245,13 +2241,11 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss,
* or negative on error
*
* @rs: current RAM state
- * @last_stage: if we are at the completion stage
*
* On systems where host-page-size > target-page-size it will send all the
* pages in a host page that are dirty.
*/
-
-static int ram_find_and_save_block(RAMState *rs, bool last_stage)
+static int ram_find_and_save_block(RAMState *rs)
{
PageSearchStatus pss;
int pages = 0;
@@ -2280,7 +2274,7 @@ static int ram_find_and_save_block(RAMState *rs, bool last_stage)
}
if (found) {
- pages = ram_save_host_page(rs, &pss, last_stage);
+ pages = ram_save_host_page(rs, &pss);
}
} while (!pages && again);
@@ -2298,7 +2292,7 @@ void acct_update_position(QEMUFile *f, size_t size, bool zero)
ram_counters.duplicate += pages;
} else {
ram_counters.normal += pages;
- ram_counters.transferred += size;
+ ram_transferred_add(size);
qemu_update_position(f, size);
}
}
@@ -2408,40 +2402,6 @@ static void ram_state_reset(RAMState *rs)
#define MAX_WAIT 50 /* ms, half buffered_file limit */
-/*
- * 'expected' is the value you expect the bitmap mostly to be full
- * of; it won't bother printing lines that are all this value.
- * If 'todump' is null the migration bitmap is dumped.
- */
-void ram_debug_dump_bitmap(unsigned long *todump, bool expected,
- unsigned long pages)
-{
- int64_t cur;
- int64_t linelen = 128;
- char linebuf[129];
-
- for (cur = 0; cur < pages; cur += linelen) {
- int64_t curb;
- bool found = false;
- /*
- * Last line; catch the case where the line length
- * is longer than remaining ram
- */
- if (cur + linelen > pages) {
- linelen = pages - cur;
- }
- for (curb = 0; curb < linelen; curb++) {
- bool thisbit = test_bit(cur + curb, todump);
- linebuf[curb] = thisbit ? '1' : '.';
- found = found || (thisbit != expected);
- }
- if (found) {
- linebuf[curb] = '\0';
- fprintf(stderr, "0x%08" PRIx64 " : %s\n", cur, linebuf);
- }
- }
-}
-
/* **** functions for postcopy ***** */
void ram_postcopy_migrated_memory_release(MigrationState *ms)
@@ -2467,14 +2427,12 @@ void ram_postcopy_migrated_memory_release(MigrationState *ms)
/**
* postcopy_send_discard_bm_ram: discard a RAMBlock
*
- * Returns zero on success
- *
* Callback from postcopy_each_ram_send_discard for each RAMBlock
*
* @ms: current migration state
* @block: RAMBlock to discard
*/
-static int postcopy_send_discard_bm_ram(MigrationState *ms, RAMBlock *block)
+static void postcopy_send_discard_bm_ram(MigrationState *ms, RAMBlock *block)
{
unsigned long end = block->used_length >> TARGET_PAGE_BITS;
unsigned long current;
@@ -2498,15 +2456,13 @@ static int postcopy_send_discard_bm_ram(MigrationState *ms, RAMBlock *block)
postcopy_discard_send_range(ms, one, discard_length);
current = one + discard_length;
}
-
- return 0;
}
+static void postcopy_chunk_hostpages_pass(MigrationState *ms, RAMBlock *block);
+
/**
* postcopy_each_ram_send_discard: discard all RAMBlocks
*
- * Returns 0 for success or negative for error
- *
* Utility for the outgoing postcopy code.
* Calls postcopy_send_discard_bm_ram for each RAMBlock
* passing it bitmap indexes and name.
@@ -2515,27 +2471,29 @@ static int postcopy_send_discard_bm_ram(MigrationState *ms, RAMBlock *block)
*
* @ms: current migration state
*/
-static int postcopy_each_ram_send_discard(MigrationState *ms)
+static void postcopy_each_ram_send_discard(MigrationState *ms)
{
struct RAMBlock *block;
- int ret;
RAMBLOCK_FOREACH_NOT_IGNORED(block) {
postcopy_discard_send_init(ms, block->idstr);
/*
+ * Deal with TPS != HPS and huge pages. It discard any partially sent
+ * host-page size chunks, mark any partially dirty host-page size
+ * chunks as all dirty. In this case the host-page is the host-page
+ * for the particular RAMBlock, i.e. it might be a huge page.
+ */
+ postcopy_chunk_hostpages_pass(ms, block);
+
+ /*
* Postcopy sends chunks of bitmap over the wire, but it
* just needs indexes at this point, avoids it having
* target page specific code.
*/
- ret = postcopy_send_discard_bm_ram(ms, block);
+ postcopy_send_discard_bm_ram(ms, block);
postcopy_discard_send_finish(ms);
- if (ret) {
- return ret;
- }
}
-
- return 0;
}
/**
@@ -2606,37 +2564,8 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, RAMBlock *block)
}
/**
- * postcopy_chunk_hostpages: discard any partially sent host page
- *
- * Utility for the outgoing postcopy code.
- *
- * Discard any partially sent host-page size chunks, mark any partially
- * dirty host-page size chunks as all dirty. In this case the host-page
- * is the host-page for the particular RAMBlock, i.e. it might be a huge page
- *
- * Returns zero on success
- *
- * @ms: current migration state
- * @block: block we want to work with
- */
-static int postcopy_chunk_hostpages(MigrationState *ms, RAMBlock *block)
-{
- postcopy_discard_send_init(ms, block->idstr);
-
- /*
- * Ensure that all partially dirty host pages are made fully dirty.
- */
- postcopy_chunk_hostpages_pass(ms, block);
-
- postcopy_discard_send_finish(ms);
- return 0;
-}
-
-/**
* ram_postcopy_send_discard_bitmap: transmit the discard bitmap
*
- * Returns zero on success
- *
* Transmit the set of pages to be discarded after precopy to the target
* these are pages that:
* a) Have been previously transmitted but are now dirty again
@@ -2647,11 +2576,9 @@ static int postcopy_chunk_hostpages(MigrationState *ms, RAMBlock *block)
*
* @ms: current migration state
*/
-int ram_postcopy_send_discard_bitmap(MigrationState *ms)
+void ram_postcopy_send_discard_bitmap(MigrationState *ms)
{
RAMState *rs = ram_state;
- RAMBlock *block;
- int ret;
RCU_READ_LOCK_GUARD();
@@ -2663,21 +2590,9 @@ int ram_postcopy_send_discard_bitmap(MigrationState *ms)
rs->last_sent_block = NULL;
rs->last_page = 0;
- RAMBLOCK_FOREACH_NOT_IGNORED(block) {
- /* Deal with TPS != HPS and huge pages */
- ret = postcopy_chunk_hostpages(ms, block);
- if (ret) {
- return ret;
- }
+ postcopy_each_ram_send_discard(ms);
-#ifdef DEBUG_POSTCOPY
- ram_debug_dump_bitmap(block->bmap, true,
- block->used_length >> TARGET_PAGE_BITS);
-#endif
- }
trace_ram_postcopy_send_discard_bitmap();
-
- return postcopy_each_ram_send_discard(ms);
}
/**
@@ -3073,14 +2988,14 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
t0 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
i = 0;
while ((ret = qemu_file_rate_limit(f)) == 0 ||
- !QSIMPLEQ_EMPTY(&rs->src_page_requests)) {
+ postcopy_has_request(rs)) {
int pages;
if (qemu_file_get_error(f)) {
break;
}
- pages = ram_find_and_save_block(rs, false);
+ pages = ram_find_and_save_block(rs);
/* no more pages to sent */
if (pages == 0) {
done = 1;
@@ -3133,7 +3048,7 @@ out:
multifd_send_sync_main(rs->f);
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
qemu_fflush(f);
- ram_counters.transferred += 8;
+ ram_transferred_add(8);
ret = qemu_file_get_error(f);
}
@@ -3160,6 +3075,8 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
RAMState *rs = *temp;
int ret = 0;
+ rs->last_stage = !migration_in_colo_state();
+
WITH_RCU_READ_LOCK_GUARD() {
if (!migration_in_postcopy()) {
migration_bitmap_sync_precopy(rs);
@@ -3173,7 +3090,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
while (true) {
int pages;
- pages = ram_find_and_save_block(rs, !migration_in_colo_state());
+ pages = ram_find_and_save_block(rs);
/* no more blocks to sent */
if (pages == 0) {
break;
diff --git a/migration/ram.h b/migration/ram.h
index c515396a9a..2c6dc3675d 100644
--- a/migration/ram.h
+++ b/migration/ram.h
@@ -55,11 +55,9 @@ void mig_throttle_counter_reset(void);
uint64_t ram_pagesize_summary(void);
int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len);
void acct_update_position(QEMUFile *f, size_t size, bool zero);
-void ram_debug_dump_bitmap(unsigned long *todump, bool expected,
- unsigned long pages);
void ram_postcopy_migrated_memory_release(MigrationState *ms);
/* For outgoing discard bitmap */
-int ram_postcopy_send_discard_bitmap(MigrationState *ms);
+void ram_postcopy_send_discard_bitmap(MigrationState *ms);
/* For incoming postcopy discard */
int ram_discard_range(const char *block_name, uint64_t start, size_t length);
int ram_postcopy_incoming_init(MigrationIncomingState *mis);
diff --git a/migration/savevm.c b/migration/savevm.c
index 0bef031acb..1599b02fbc 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1298,8 +1298,9 @@ int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy)
save_section_footer(f, se);
if (ret < 0) {
- error_report("failed to save SaveStateEntry with id(name): %d(%s)",
- se->section_id, se->idstr);
+ error_report("failed to save SaveStateEntry with id(name): "
+ "%d(%s): %d",
+ se->section_id, se->idstr, ret);
qemu_file_set_error(f, ret);
}
if (ret <= 0) {
diff --git a/migration/trace-events b/migration/trace-events
index b48d873b8a..48aa7b10ee 100644
--- a/migration/trace-events
+++ b/migration/trace-events
@@ -86,8 +86,6 @@ put_qlist_end(const char *field_name, const char *vmsd_name) "%s(%s)"
qemu_file_fclose(void) ""
# ram.c
-get_queued_page(const char *block_name, uint64_t tmp_offset, unsigned long page_abs) "%s/0x%" PRIx64 " page_abs=0x%lx"
-get_queued_page_not_dirty(const char *block_name, uint64_t tmp_offset, unsigned long page_abs) "%s/0x%" PRIx64 " page_abs=0x%lx"
migration_bitmap_sync_start(void) ""
migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64
migration_bitmap_clear_dirty(char *str, uint64_t start, uint64_t size, unsigned long page) "rb %s start 0x%"PRIx64" size 0x%"PRIx64" page 0x%lx"
@@ -113,25 +111,26 @@ ram_save_iterate_big_wait(uint64_t milliconds, int iterations) "big wait: %" PRI
ram_load_complete(int ret, uint64_t seq_iter) "exit_code %d seq iteration %" PRIu64
ram_write_tracking_ramblock_start(const char *block_id, size_t page_size, void *addr, size_t length) "%s: page_size: %zu addr: %p length: %zu"
ram_write_tracking_ramblock_stop(const char *block_id, size_t page_size, void *addr, size_t length) "%s: page_size: %zu addr: %p length: %zu"
+unqueue_page(char *block, uint64_t offset, bool dirty) "ramblock '%s' offset 0x%"PRIx64" dirty %d"
# multifd.c
-multifd_new_send_channel_async(uint8_t id) "channel %d"
-multifd_recv(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %d packet_num %" PRIu64 " pages %d flags 0x%x next packet size %d"
-multifd_recv_new_channel(uint8_t id) "channel %d"
+multifd_new_send_channel_async(uint8_t id) "channel %u"
+multifd_recv(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " pages %u flags 0x%x next packet size %u"
+multifd_recv_new_channel(uint8_t id) "channel %u"
multifd_recv_sync_main(long packet_num) "packet num %ld"
-multifd_recv_sync_main_signal(uint8_t id) "channel %d"
-multifd_recv_sync_main_wait(uint8_t id) "channel %d"
+multifd_recv_sync_main_signal(uint8_t id) "channel %u"
+multifd_recv_sync_main_wait(uint8_t id) "channel %u"
multifd_recv_terminate_threads(bool error) "error %d"
-multifd_recv_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %d packets %" PRIu64 " pages %" PRIu64
-multifd_recv_thread_start(uint8_t id) "%d"
-multifd_send(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %d packet_num %" PRIu64 " pages %d flags 0x%x next packet size %d"
-multifd_send_error(uint8_t id) "channel %d"
+multifd_recv_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %u packets %" PRIu64 " pages %" PRIu64
+multifd_recv_thread_start(uint8_t id) "%u"
+multifd_send(uint8_t id, uint64_t packet_num, uint32_t normal, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " normal pages %u flags 0x%x next packet size %u"
+multifd_send_error(uint8_t id) "channel %u"
multifd_send_sync_main(long packet_num) "packet num %ld"
-multifd_send_sync_main_signal(uint8_t id) "channel %d"
-multifd_send_sync_main_wait(uint8_t id) "channel %d"
+multifd_send_sync_main_signal(uint8_t id) "channel %u"
+multifd_send_sync_main_wait(uint8_t id) "channel %u"
multifd_send_terminate_threads(bool error) "error %d"
-multifd_send_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %d packets %" PRIu64 " pages %" PRIu64
-multifd_send_thread_start(uint8_t id) "%d"
+multifd_send_thread_end(uint8_t id, uint64_t packets, uint64_t normal_pages) "channel %u packets %" PRIu64 " normal pages %" PRIu64
+multifd_send_thread_start(uint8_t id) "%u"
multifd_tls_outgoing_handshake_start(void *ioc, void *tioc, const char *hostname) "ioc=%p tioc=%p hostname=%s"
multifd_tls_outgoing_handshake_error(void *ioc, const char *err) "ioc=%p err=%s"
multifd_tls_outgoing_handshake_complete(void *ioc) "ioc=%p"
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 2669156b28..8c384dc1b2 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -293,6 +293,18 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "postcopy request count: %" PRIu64 "\n",
info->ram->postcopy_requests);
}
+ if (info->ram->precopy_bytes) {
+ monitor_printf(mon, "precopy ram: %" PRIu64 " kbytes\n",
+ info->ram->precopy_bytes >> 10);
+ }
+ if (info->ram->downtime_bytes) {
+ monitor_printf(mon, "downtime ram: %" PRIu64 " kbytes\n",
+ info->ram->downtime_bytes >> 10);
+ }
+ if (info->ram->postcopy_bytes) {
+ monitor_printf(mon, "postcopy ram: %" PRIu64 " kbytes\n",
+ info->ram->postcopy_bytes >> 10);
+ }
}
if (info->has_disk) {
diff --git a/nbd/server.c b/nbd/server.c
index 4630dd7322..9fb2f26402 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -77,7 +77,6 @@ static int system_errno_to_nbd_errno(int err)
typedef struct NBDRequestData NBDRequestData;
struct NBDRequestData {
- QSIMPLEQ_ENTRY(NBDRequestData) entry;
NBDClient *client;
uint8_t *data;
bool complete;
diff --git a/net/dump.c b/net/dump.c
index a07ba62401..6a63b15359 100644
--- a/net/dump.c
+++ b/net/dump.c
@@ -23,7 +23,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "clients.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
@@ -33,6 +32,7 @@
#include "qapi/visitor.h"
#include "net/filter.h"
#include "qom/object.h"
+#include "sysemu/rtc.h"
typedef struct DumpState {
int64_t start_ts;
diff --git a/pc-bios/hppa-firmware.img b/pc-bios/hppa-firmware.img
index a34a8c84f5..0ec2d96b8f 100644
--- a/pc-bios/hppa-firmware.img
+++ b/pc-bios/hppa-firmware.img
Binary files differ
diff --git a/python/Pipfile.lock b/python/Pipfile.lock
index d2a7dbd88b..ce46404ce0 100644
--- a/python/Pipfile.lock
+++ b/python/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "784b327272db32403d5a488507853b5afba850ba26a5948e5b6a90c1baef2d9c"
+ "sha256": "f1a25654d884a5b450e38d78b1f2e3ebb9073e421cc4358d4bbb83ac251a5670"
},
"pipfile-spec": 6,
"requires": {
@@ -34,7 +34,7 @@
"sha256:09bdb456e02564731f8b5957cdd0c98a7f01d2db5e90eb1d794c353c28bfd705",
"sha256:6a8a51f64dae307f6e0c9db752b66a7951e282389d8362cc1d39a56f3feeb31d"
],
- "markers": "python_version ~= '3.6'",
+ "index": "pypi",
"version": "==2.6.0"
},
"avocado-framework": {
@@ -50,6 +50,7 @@
"sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736",
"sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"
],
+ "index": "pypi",
"version": "==0.3.2"
},
"filelock": {
@@ -57,6 +58,7 @@
"sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59",
"sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"
],
+ "index": "pypi",
"version": "==3.0.12"
},
"flake8": {
@@ -88,7 +90,7 @@
"sha256:54161657e8ffc76596c4ede7080ca68cb02962a2e074a2586b695a93a925d36e",
"sha256:e962bff7440364183203d179d7ae9ad90cb1f2b74dcb84300e88ecc42dca3351"
],
- "markers": "python_version < '3.7'",
+ "index": "pypi",
"version": "==5.1.4"
},
"isort": {
@@ -124,7 +126,7 @@
"sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93",
"sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
+ "index": "pypi",
"version": "==1.6.0"
},
"mccabe": {
@@ -136,23 +138,23 @@
},
"mypy": {
"hashes": [
- "sha256:15b948e1302682e3682f11f50208b726a246ab4e6c1b39f9264a8796bb416aa2",
- "sha256:219a3116ecd015f8dca7b5d2c366c973509dfb9a8fc97ef044a36e3da66144a1",
- "sha256:3b1fc683fb204c6b4403a1ef23f0b1fac8e4477091585e0c8c54cbdf7d7bb164",
- "sha256:3beff56b453b6ef94ecb2996bea101a08f1f8a9771d3cbf4988a61e4d9973761",
- "sha256:7687f6455ec3ed7649d1ae574136835a4272b65b3ddcf01ab8704ac65616c5ce",
- "sha256:7ec45a70d40ede1ec7ad7f95b3c94c9cf4c186a32f6bacb1795b60abd2f9ef27",
- "sha256:86c857510a9b7c3104cf4cde1568f4921762c8f9842e987bc03ed4f160925754",
- "sha256:8a627507ef9b307b46a1fea9513d5c98680ba09591253082b4c48697ba05a4ae",
- "sha256:8dfb69fbf9f3aeed18afffb15e319ca7f8da9642336348ddd6cab2713ddcf8f9",
- "sha256:a34b577cdf6313bf24755f7a0e3f3c326d5c1f4fe7422d1d06498eb25ad0c600",
- "sha256:a8ffcd53cb5dfc131850851cc09f1c44689c2812d0beb954d8138d4f5fc17f65",
- "sha256:b90928f2d9eb2f33162405f32dde9f6dcead63a0971ca8a1b50eb4ca3e35ceb8",
- "sha256:c56ffe22faa2e51054c5f7a3bc70a370939c2ed4de308c690e7949230c995913",
- "sha256:f91c7ae919bbc3f96cd5e5b2e786b2b108343d1d7972ea130f7de27fdd547cf3"
+ "sha256:00cb1964a7476e871d6108341ac9c1a857d6bd20bf5877f4773ac5e9d92cd3cd",
+ "sha256:127de5a9b817a03a98c5ae8a0c46a20dc44442af6dcfa2ae7f96cb519b312efa",
+ "sha256:1f3976a945ad7f0a0727aafdc5651c2d3278e3c88dee94e2bf75cd3386b7b2f4",
+ "sha256:2f8c098f12b402c19b735aec724cc9105cc1a9eea405d08814eb4b14a6fb1a41",
+ "sha256:4ef13b619a289aa025f2273e05e755f8049bb4eaba6d703a425de37d495d178d",
+ "sha256:5d142f219bf8c7894dfa79ebfb7d352c4c63a325e75f10dfb4c3db9417dcd135",
+ "sha256:62eb5dd4ea86bda8ce386f26684f7f26e4bfe6283c9f2b6ca6d17faf704dcfad",
+ "sha256:64c36eb0936d0bfb7d8da49f92c18e312ad2e3ed46e5548ae4ca997b0d33bd59",
+ "sha256:75eed74d2faf2759f79c5f56f17388defd2fc994222312ec54ee921e37b31ad4",
+ "sha256:974bebe3699b9b46278a7f076635d219183da26e1a675c1f8243a69221758273",
+ "sha256:a5e5bb12b7982b179af513dddb06fca12285f0316d74f3964078acbfcf4c68f2",
+ "sha256:d31291df31bafb997952dc0a17ebb2737f802c754aed31dd155a8bfe75112c57",
+ "sha256:d3b4941de44341227ece1caaf5b08b23e42ad4eeb8b603219afb11e9d4cfb437",
+ "sha256:eadb865126da4e3c4c95bdb47fe1bb087a3e3ea14d39a3b13224b8a4d9f9a102"
],
"index": "pypi",
- "version": "==0.770"
+ "version": "==0.780"
},
"mypy-extensions": {
"hashes": [
@@ -166,7 +168,7 @@
"sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5",
"sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+ "index": "pypi",
"version": "==20.9"
},
"pluggy": {
@@ -174,7 +176,7 @@
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+ "index": "pypi",
"version": "==0.13.1"
},
"py": {
@@ -182,7 +184,7 @@
"sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
"sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+ "index": "pypi",
"version": "==1.10.0"
},
"pycodestyle": {
@@ -205,7 +207,7 @@
"sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f",
"sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e"
],
- "markers": "python_version >= '3.5'",
+ "index": "pypi",
"version": "==2.9.0"
},
"pylint": {
@@ -221,13 +223,21 @@
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
],
- "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+ "index": "pypi",
"version": "==2.4.7"
},
"qemu": {
"editable": true,
"path": "."
},
+ "setuptools": {
+ "hashes": [
+ "sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373",
+ "sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e"
+ ],
+ "markers": "python_version >= '3.6'",
+ "version": "==59.6.0"
+ },
"six": {
"hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
@@ -294,19 +304,21 @@
"sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342",
"sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"
],
- "markers": "python_version < '3.8'",
+ "index": "pypi",
"version": "==3.10.0.0"
},
"urwid": {
"hashes": [
"sha256:588bee9c1cb208d0906a9f73c613d2bd32c3ed3702012f51efe318a3f2127eae"
],
+ "index": "pypi",
"version": "==2.1.2"
},
"urwid-readline": {
"hashes": [
"sha256:018020cbc864bb5ed87be17dc26b069eae2755cb29f3a9c569aac3bded1efaf4"
],
+ "index": "pypi",
"version": "==0.13"
},
"virtualenv": {
@@ -314,7 +326,7 @@
"sha256:14fdf849f80dbb29a4eb6caa9875d476ee2a5cf76a5f5415fa2f1606010ab467",
"sha256:2b0126166ea7c9c3661f5b8e06773d28f83322de7a3ff7d06f0aed18c9de6a76"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+ "index": "pypi",
"version": "==20.4.7"
},
"wrapt": {
@@ -328,7 +340,7 @@
"sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76",
"sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"
],
- "markers": "python_version < '3.10'",
+ "index": "pypi",
"version": "==3.4.1"
}
}
diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py
index 0890f95b16..6baa5f3409 100644
--- a/python/qemu/aqmp/legacy.py
+++ b/python/qemu/aqmp/legacy.py
@@ -56,6 +56,9 @@ class QEMUMonitorProtocol(qemu.qmp.QEMUMonitorProtocol):
self._address = address
self._timeout: Optional[float] = None
+ if server:
+ self._aqmp._bind_hack(address) # pylint: disable=protected-access
+
_T = TypeVar('_T')
def _sync(
diff --git a/python/qemu/aqmp/protocol.py b/python/qemu/aqmp/protocol.py
index 50e973c2f2..33358f5cd7 100644
--- a/python/qemu/aqmp/protocol.py
+++ b/python/qemu/aqmp/protocol.py
@@ -15,6 +15,7 @@ from asyncio import StreamReader, StreamWriter
from enum import Enum
from functools import wraps
import logging
+import socket
from ssl import SSLContext
from typing import (
Any,
@@ -238,6 +239,9 @@ class AsyncProtocol(Generic[T]):
self._runstate = Runstate.IDLE
self._runstate_changed: Optional[asyncio.Event] = None
+ # Workaround for bind()
+ self._sock: Optional[socket.socket] = None
+
def __repr__(self) -> str:
cls_name = type(self).__name__
tokens = []
@@ -427,6 +431,34 @@ class AsyncProtocol(Generic[T]):
else:
await self._do_connect(address, ssl)
+ def _bind_hack(self, address: Union[str, Tuple[str, int]]) -> None:
+ """
+ Used to create a socket in advance of accept().
+
+ This is a workaround to ensure that we can guarantee timing of
+ precisely when a socket exists to avoid a connection attempt
+ bouncing off of nothing.
+
+ Python 3.7+ adds a feature to separate the server creation and
+ listening phases instead, and should be used instead of this
+ hack.
+ """
+ if isinstance(address, tuple):
+ family = socket.AF_INET
+ else:
+ family = socket.AF_UNIX
+
+ sock = socket.socket(family, socket.SOCK_STREAM)
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+
+ try:
+ sock.bind(address)
+ except:
+ sock.close()
+ raise
+
+ self._sock = sock
+
@upper_half
async def _do_accept(self, address: SocketAddrT,
ssl: Optional[SSLContext] = None) -> None:
@@ -464,24 +496,27 @@ class AsyncProtocol(Generic[T]):
if isinstance(address, tuple):
coro = asyncio.start_server(
_client_connected_cb,
- host=address[0],
- port=address[1],
+ host=None if self._sock else address[0],
+ port=None if self._sock else address[1],
ssl=ssl,
backlog=1,
limit=self._limit,
+ sock=self._sock,
)
else:
coro = asyncio.start_unix_server(
_client_connected_cb,
- path=address,
+ path=None if self._sock else address,
ssl=ssl,
backlog=1,
limit=self._limit,
+ sock=self._sock,
)
server = await coro # Starts listening
await connected.wait() # Waits for the callback to fire (and finish)
assert server is None
+ self._sock = None
self.logger.debug("Connection accepted.")
diff --git a/python/qemu/aqmp/qmp_client.py b/python/qemu/aqmp/qmp_client.py
index f1a845cc82..90a8737f03 100644
--- a/python/qemu/aqmp/qmp_client.py
+++ b/python/qemu/aqmp/qmp_client.py
@@ -292,9 +292,9 @@ class QMPClient(AsyncProtocol[Message], Events):
"""
self.logger.debug("Negotiating capabilities ...")
- arguments: Dict[str, List[str]] = {'enable': []}
+ arguments: Dict[str, List[str]] = {}
if self._greeting and 'oob' in self._greeting.QMP.capabilities:
- arguments['enable'].append('oob')
+ arguments.setdefault('enable', []).append('oob')
msg = self.make_execute_msg('qmp_capabilities', arguments=arguments)
# It's not safe to use execute() here, because the reader/writers
diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py
index 67ab06ca2b..a5972fab4d 100644
--- a/python/qemu/machine/machine.py
+++ b/python/qemu/machine/machine.py
@@ -74,6 +74,35 @@ class QEMUMachineAddDeviceError(QEMUMachineError):
"""
+class VMLaunchFailure(QEMUMachineError):
+ """
+ Exception raised when a VM launch was attempted, but failed.
+ """
+ def __init__(self, exitcode: Optional[int],
+ command: str, output: Optional[str]):
+ super().__init__(exitcode, command, output)
+ self.exitcode = exitcode
+ self.command = command
+ self.output = output
+
+ def __str__(self) -> str:
+ ret = ''
+ if self.__cause__ is not None:
+ name = type(self.__cause__).__name__
+ reason = str(self.__cause__)
+ if reason:
+ ret += f"{name}: {reason}"
+ else:
+ ret += f"{name}"
+ ret += '\n'
+
+ if self.exitcode is not None:
+ ret += f"\tExit code: {self.exitcode}\n"
+ ret += f"\tCommand: {self.command}\n"
+ ret += f"\tOutput: {self.output}\n"
+ return ret
+
+
class AbnormalShutdown(QEMUMachineError):
"""
Exception raised when a graceful shutdown was requested, but not performed.
@@ -397,7 +426,7 @@ class QEMUMachine:
try:
self._launch()
- except:
+ except BaseException as exc:
# We may have launched the process but it may
# have exited before we could connect via QMP.
# Assume the VM didn't launch or is exiting.
@@ -408,11 +437,15 @@ class QEMUMachine:
else:
self._post_shutdown()
- LOG.debug('Error launching VM')
- if self._qemu_full_args:
- LOG.debug('Command: %r', ' '.join(self._qemu_full_args))
- if self._iolog:
- LOG.debug('Output: %r', self._iolog)
+ if isinstance(exc, Exception):
+ raise VMLaunchFailure(
+ exitcode=self.exitcode(),
+ command=' '.join(self._qemu_full_args),
+ output=self._iolog
+ ) from exc
+
+ # Don't wrap 'BaseException'; doing so would downgrade
+ # that exception. However, we still want to clean up.
raise
def _launch(self) -> None:
diff --git a/python/setup.cfg b/python/setup.cfg
index 3fb18f845d..18aea2bab3 100644
--- a/python/setup.cfg
+++ b/python/setup.cfg
@@ -41,7 +41,7 @@ devel =
flake8 >= 3.6.0
fusepy >= 2.0.4
isort >= 5.1.2
- mypy >= 0.770
+ mypy >= 0.780
pylint >= 2.8.0
tox >= 3.18.0
urwid >= 2.1.2
diff --git a/qapi/audio.json b/qapi/audio.json
index 693e327c6b..0785e70a50 100644
--- a/qapi/audio.json
+++ b/qapi/audio.json
@@ -1,4 +1,5 @@
# -*- mode: python -*-
+# vim: filetype=python
#
# Copyright (C) 2015-2019 Zoltán Kővágó <DirtY.iCE.hu@gmail.com>
#
diff --git a/qapi/block-export.json b/qapi/block-export.json
index f9ce79a974..f183522d0d 100644
--- a/qapi/block-export.json
+++ b/qapi/block-export.json
@@ -278,7 +278,8 @@
##
{ 'enum': 'BlockExportType',
'data': [ 'nbd',
- { 'name': 'vhost-user-blk', 'if': 'CONFIG_VHOST_USER_BLK_SERVER' },
+ { 'name': 'vhost-user-blk',
+ 'if': 'CONFIG_VHOST_USER_BLK_SERVER' },
{ 'name': 'fuse', 'if': 'CONFIG_FUSE' } ] }
##
diff --git a/qapi/compat.json b/qapi/compat.json
index dd7261ae2a..c53b69fe3f 100644
--- a/qapi/compat.json
+++ b/qapi/compat.json
@@ -1,4 +1,5 @@
# -*- Mode: Python -*-
+# vim: filetype=python
##
# = Compatibility policy
diff --git a/qapi/machine.json b/qapi/machine.json
index c87c81b803..42fc68403d 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -1207,7 +1207,7 @@
#
# @memdev: memory backend linked with device
#
-# @node: the numa node
+# @node: the numa node (Since: 7.0)
#
# Since: 6.2
##
@@ -1288,7 +1288,7 @@
#
# @memdev: memory backend linked with device
#
-# @node: the numa node
+# @node: the numa node (Since: 7.0)
#
# Since: 6.2
##
diff --git a/qapi/meson.build b/qapi/meson.build
index c0c49c15e4..656ef0e039 100644
--- a/qapi/meson.build
+++ b/qapi/meson.build
@@ -114,6 +114,7 @@ foreach module : qapi_all_modules
'qapi-events-@0@.h'.format(module),
'qapi-commands-@0@.c'.format(module),
'qapi-commands-@0@.h'.format(module),
+ 'qapi-commands-@0@.trace-events'.format(module),
]
endif
if module.endswith('-target')
@@ -137,6 +138,9 @@ foreach output : qapi_util_outputs
if output.endswith('.h')
genh += qapi_files[i]
endif
+ if output.endswith('.trace-events')
+ qapi_trace_events += qapi_files[i]
+ endif
util_ss.add(qapi_files[i])
i = i + 1
endforeach
@@ -145,6 +149,9 @@ foreach output : qapi_specific_outputs + qapi_nonmodule_outputs
if output.endswith('.h')
genh += qapi_files[i]
endif
+ if output.endswith('.trace-events')
+ qapi_trace_events += qapi_files[i]
+ endif
specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: qapi_files[i])
i = i + 1
endforeach
diff --git a/qapi/migration.json b/qapi/migration.json
index bbfd48cf0b..5975a0e104 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -46,6 +46,15 @@
# @pages-per-second: the number of memory pages transferred per second
# (Since 4.0)
#
+# @precopy-bytes: The number of bytes sent in the pre-copy phase
+# (since 7.0).
+#
+# @downtime-bytes: The number of bytes sent while the guest is paused
+# (since 7.0).
+#
+# @postcopy-bytes: The number of bytes sent during the post-copy phase
+# (since 7.0).
+#
# Since: 0.14
##
{ 'struct': 'MigrationStats',
@@ -54,7 +63,9 @@
'normal-bytes': 'int', 'dirty-pages-rate' : 'int',
'mbps' : 'number', 'dirty-sync-count' : 'int',
'postcopy-requests' : 'int', 'page-size' : 'int',
- 'multifd-bytes' : 'uint64', 'pages-per-second' : 'uint64' } }
+ 'multifd-bytes' : 'uint64', 'pages-per-second' : 'uint64',
+ 'precopy-bytes' : 'uint64', 'downtime-bytes' : 'uint64',
+ 'postcopy-bytes' : 'uint64' } }
##
# @XBZRLECacheStats:
diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 1022aa0184..4bc45d2474 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -344,9 +344,9 @@
#
# @node: the numa node
#
-# @size: the size of epc section
+# @size: the size of EPC section
#
-# Since: 6.2
+# Since: 7.0
##
{ 'struct': 'SGXEPCSection',
'data': { 'node': 'int',
@@ -365,7 +365,13 @@
#
# @flc: true if FLC is supported
#
-# @sections: The EPC sections info for guest
+# @section-size: The EPC section size for guest
+# Redundant with @sections. Just for backward compatibility.
+#
+# @sections: The EPC sections info for guest (Since: 7.0)
+#
+# Features:
+# @deprecated: Member @section-size is deprecated. Use @sections instead.
#
# Since: 6.2
##
@@ -374,6 +380,8 @@
'sgx1': 'bool',
'sgx2': 'bool',
'flc': 'bool',
+ 'section-size': { 'type': 'uint64',
+ 'features': [ 'deprecated' ] },
'sections': ['SGXEPCSection']},
'if': 'TARGET_I386' }
@@ -390,7 +398,9 @@
#
# -> { "execute": "query-sgx" }
# <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true,
-# "flc": true, "section-size" : 0 } }
+# "flc": true, "section-size" : 96468992,
+# "sections": [{"node": 0, "size": 67108864},
+# {"node": 1, "size": 29360128}]} }
#
##
{ 'command': 'query-sgx', 'returns': 'SGXInfo', 'if': 'TARGET_I386' }
@@ -408,7 +418,9 @@
#
# -> { "execute": "query-sgx-capabilities" }
# <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true,
-# "flc": true, "section-size" : 0 } }
+# "flc": true, "section-size" : 96468992,
+# "section" : [{"node": 0, "size": 67108864},
+# {"node": 1, "size": 29360128}]} }
#
##
{ 'command': 'query-sgx-capabilities', 'returns': 'SGXInfo', 'if': 'TARGET_I386' }
diff --git a/qapi/replay.json b/qapi/replay.json
index bfd83d7591..b4d1ba253b 100644
--- a/qapi/replay.json
+++ b/qapi/replay.json
@@ -1,4 +1,5 @@
# -*- Mode: Python -*-
+# vim: filetype=python
#
##
diff --git a/qapi/trace.json b/qapi/trace.json
index eedfded512..119509f565 100644
--- a/qapi/trace.json
+++ b/qapi/trace.json
@@ -1,4 +1,5 @@
# -*- mode: python -*-
+# vim: filetype=python
#
# Copyright (C) 2011-2016 Lluís Vilanova <vilanova@ac.upc.edu>
#
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index 72bcdcfbfa..1b1dab5b17 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -52,9 +52,9 @@ SRST
ERST
DEF("create", img_create,
- "create [--object objectdef] [-q] [-f fmt] [-b backing_file] [-F backing_fmt] [-u] [-o options] filename [size]")
+ "create [--object objectdef] [-q] [-f fmt] [-b backing_file [-F backing_fmt]] [-u] [-o options] filename [size]")
SRST
-.. option:: create [--object OBJECTDEF] [-q] [-f FMT] [-b BACKING_FILE] [-F BACKING_FMT] [-u] [-o OPTIONS] FILENAME [SIZE]
+.. option:: create [--object OBJECTDEF] [-q] [-f FMT] [-b BACKING_FILE [-F BACKING_FMT]] [-u] [-o OPTIONS] FILENAME [SIZE]
ERST
DEF("dd", img_dd,
diff --git a/qga/meson.build b/qga/meson.build
index cfb1fbc085..1ee9dca60b 100644
--- a/qga/meson.build
+++ b/qga/meson.build
@@ -15,10 +15,18 @@ qga_qapi_outputs = [
'qga-qapi-visit.h',
]
+# Problem: to generate trace events, we'd have to add the .trace-events
+# file to qapi_trace_events like we do in qapi/meson.build. Since
+# qapi_trace_events is used by trace/meson.build, we'd have to move
+# subdir('qga') above subdir('trace') in the top-level meson.build.
+# Can't, because it would break the dependency of qga on qemuutil (which
+# depends on trace_ss). Not worth solving now; simply suppress trace
+# event generation instead.
qga_qapi_files = custom_target('QGA QAPI files',
output: qga_qapi_outputs,
input: 'qapi-schema.json',
- command: [ qapi_gen, '-o', 'qga', '-p', 'qga-', '@INPUT0@' ],
+ command: [ qapi_gen, '-o', 'qga', '-p', 'qga-', '@INPUT0@',
+ '--suppress-tracing' ],
depend_files: qapi_gen_depends)
qga_ss = ss.source_set()
@@ -75,7 +83,7 @@ if targetos == 'windows'
endif
qga_msi = custom_target('QGA MSI',
input: files('installer/qemu-ga.wxs'),
- output: 'qemu-ga-@0@.msi'.format(config_host['ARCH']),
+ output: 'qemu-ga-@0@.msi'.format(host_arch),
depends: deps,
command: [
find_program('env'),
diff --git a/roms/seabios-hppa b/roms/seabios-hppa
-Subproject b12acac4be27b6d5d9fbe48c4be1286dcc245fb
+Subproject bf3404006fd2c832857eb57e6f853862f97dace
diff --git a/scripts/mtest2make.py b/scripts/mtest2make.py
index 7067bdadf5..4d542e8aaa 100644
--- a/scripts/mtest2make.py
+++ b/scripts/mtest2make.py
@@ -23,8 +23,9 @@ class Suite(object):
print('''
SPEED = quick
-.speed.quick = $(foreach s,$(sort $(filter-out %-slow, $1)), --suite $s)
-.speed.slow = $(foreach s,$(sort $1), --suite $s)
+.speed.quick = $(foreach s,$(sort $(filter-out %-slow %-thorough, $1)), --suite $s)
+.speed.slow = $(foreach s,$(sort $(filter-out %-thorough, $1)), --suite $s)
+.speed.thorough = $(foreach s,$(sort $1), --suite $s)
.mtestargs = --no-rebuild -t 0
ifneq ($(SPEED), quick)
@@ -52,11 +53,14 @@ def process_tests(test, targets, suites):
for s in test_suites:
# The suite name in the introspection info is "PROJECT:SUITE"
s = s.split(':')[1]
- if s == 'slow':
+ if s == 'slow' or s == 'thorough':
continue
if s.endswith('-slow'):
s = s[:-5]
suites[s].speeds.append('slow')
+ if s.endswith('-thorough'):
+ s = s[:-9]
+ suites[s].speeds.append('thorough')
suites[s].deps.update(deps)
def emit_prolog(suites, prefix):
@@ -75,7 +79,7 @@ def emit_prolog(suites, prefix):
print(f'{prefix}-report.junit.xml $(all-{prefix}-xml): {prefix}-report%.junit.xml: run-ninja')
print(f'\t$(MAKE) {prefix}$* MTESTARGS="$(MTESTARGS) --logbase {prefix}-report$*" && ln -f meson-logs/$@ .')
-def emit_suite(name, suite, prefix):
+def emit_suite_deps(name, suite, prefix):
deps = ' '.join(suite.deps)
targets = f'{prefix}-{name} {prefix}-report-{name}.junit.xml {prefix} {prefix}-report.junit.xml'
print()
@@ -83,6 +87,10 @@ def emit_suite(name, suite, prefix):
print(f'ifneq ($(filter {prefix}-build {targets}, $(MAKECMDGOALS)),)')
print(f'.{prefix}.build-suites += {name}')
print(f'endif')
+
+def emit_suite(name, suite, prefix):
+ emit_suite_deps(name, suite, prefix)
+ targets = f'{prefix}-{name} {prefix}-report-{name}.junit.xml {prefix} {prefix}-report.junit.xml'
print(f'ifneq ($(filter {targets}, $(MAKECMDGOALS)),)')
print(f'.{prefix}.mtest-suites += ' + ' '.join(suite.names(name)))
print(f'endif')
@@ -93,6 +101,10 @@ targets = {t['id']: [os.path.relpath(f) for f in t['filename']]
testsuites = defaultdict(Suite)
for test in introspect['tests']:
process_tests(test, targets, testsuites)
+# HACK: check-block is a separate target so that it runs with --verbose;
+# only write the dependencies
+emit_suite_deps('block', testsuites['block'], 'check')
+del testsuites['block']
emit_prolog(testsuites, 'check')
for name, suite in testsuites.items():
emit_suite(name, suite, 'check')
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 21001bbd6b..869d799ed2 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -53,7 +53,8 @@ def gen_command_decl(name: str,
def gen_call(name: str,
arg_type: Optional[QAPISchemaObjectType],
boxed: bool,
- ret_type: Optional[QAPISchemaType]) -> str:
+ ret_type: Optional[QAPISchemaType],
+ gen_tracing: bool) -> str:
ret = ''
argstr = ''
@@ -71,21 +72,67 @@ def gen_call(name: str,
if ret_type:
lhs = 'retval = '
- ret = mcgen('''
+ name = c_name(name)
+ upper = name.upper()
- %(lhs)sqmp_%(c_name)s(%(args)s&err);
- error_propagate(errp, err);
-''',
- c_name=c_name(name), args=argstr, lhs=lhs)
- if ret_type:
+ if gen_tracing:
ret += mcgen('''
+
+ if (trace_event_get_state_backends(TRACE_QMP_ENTER_%(upper)s)) {
+ g_autoptr(GString) req_json = qobject_to_json(QOBJECT(args));
+
+ trace_qmp_enter_%(name)s(req_json->str);
+ }
+ ''',
+ upper=upper, name=name)
+
+ ret += mcgen('''
+
+ %(lhs)sqmp_%(name)s(%(args)s&err);
+''',
+ name=name, args=argstr, lhs=lhs)
+
+ ret += mcgen('''
if (err) {
+''')
+
+ if gen_tracing:
+ ret += mcgen('''
+ trace_qmp_exit_%(name)s(error_get_pretty(err), false);
+''',
+ name=name)
+
+ ret += mcgen('''
+ error_propagate(errp, err);
goto out;
}
+''')
+
+ if ret_type:
+ ret += mcgen('''
qmp_marshal_output_%(c_name)s(retval, ret, errp);
''',
c_name=ret_type.c_name())
+
+ if gen_tracing:
+ if ret_type:
+ ret += mcgen('''
+
+ if (trace_event_get_state_backends(TRACE_QMP_EXIT_%(upper)s)) {
+ g_autoptr(GString) ret_json = qobject_to_json(*ret);
+
+ trace_qmp_exit_%(name)s(ret_json->str, true);
+ }
+ ''',
+ upper=upper, name=name)
+ else:
+ ret += mcgen('''
+
+ trace_qmp_exit_%(name)s("{}", true);
+ ''',
+ name=name)
+
return ret
@@ -122,10 +169,19 @@ def gen_marshal_decl(name: str) -> str:
proto=build_marshal_proto(name))
+def gen_trace(name: str) -> str:
+ return mcgen('''
+qmp_enter_%(name)s(const char *json) "%%s"
+qmp_exit_%(name)s(const char *result, bool succeeded) "%%s %%d"
+''',
+ name=c_name(name))
+
+
def gen_marshal(name: str,
arg_type: Optional[QAPISchemaObjectType],
boxed: bool,
- ret_type: Optional[QAPISchemaType]) -> str:
+ ret_type: Optional[QAPISchemaType],
+ gen_tracing: bool) -> str:
have_args = boxed or (arg_type and not arg_type.is_empty())
if have_args:
assert arg_type is not None
@@ -180,7 +236,7 @@ def gen_marshal(name: str,
}
''')
- ret += gen_call(name, arg_type, boxed, ret_type)
+ ret += gen_call(name, arg_type, boxed, ret_type, gen_tracing)
ret += mcgen('''
@@ -238,11 +294,13 @@ def gen_register_command(name: str,
class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
- def __init__(self, prefix: str):
+ def __init__(self, prefix: str, gen_tracing: bool):
super().__init__(
prefix, 'qapi-commands',
- ' * Schema-defined QAPI/QMP commands', None, __doc__)
+ ' * Schema-defined QAPI/QMP commands', None, __doc__,
+ gen_tracing=gen_tracing)
self._visited_ret_types: Dict[QAPIGenC, Set[QAPISchemaType]] = {}
+ self._gen_tracing = gen_tracing
def _begin_user_module(self, name: str) -> None:
self._visited_ret_types[self._genc] = set()
@@ -261,6 +319,16 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
''',
commands=commands, visit=visit))
+
+ if self._gen_tracing and commands != 'qapi-commands':
+ self._genc.add(mcgen('''
+#include "qapi/qmp/qjson.h"
+#include "trace/trace-%(nm)s_trace_events.h"
+''',
+ nm=c_name(commands, protect=False)))
+ # We use c_name(commands, protect=False) to turn '-' into '_', to
+ # match .underscorify() in trace/meson.build
+
self._genh.add(mcgen('''
#include "%(types)s.h"
@@ -322,7 +390,10 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
self._genh.add(gen_marshal_decl(name))
- self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
+ self._genc.add(gen_marshal(name, arg_type, boxed, ret_type,
+ self._gen_tracing))
+ if self._gen_tracing:
+ self._gen_trace_events.add(gen_trace(name))
with self._temp_module('./init'):
with ifcontext(ifcond, self._genh, self._genc):
self._genc.add(gen_register_command(
@@ -332,7 +403,8 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
def gen_commands(schema: QAPISchema,
output_dir: str,
- prefix: str) -> None:
- vis = QAPISchemaGenCommandVisitor(prefix)
+ prefix: str,
+ gen_tracing: bool) -> None:
+ vis = QAPISchemaGenCommandVisitor(prefix, gen_tracing)
schema.visit(vis)
vis.write(output_dir)
diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py
index 995a97d2b8..113b49134d 100644
--- a/scripts/qapi/gen.py
+++ b/scripts/qapi/gen.py
@@ -192,6 +192,11 @@ class QAPIGenH(QAPIGenC):
return guardend(self.fname)
+class QAPIGenTrace(QAPIGen):
+ def _top(self) -> str:
+ return super()._top() + '# AUTOMATICALLY GENERATED, DO NOT MODIFY\n\n'
+
+
@contextmanager
def ifcontext(ifcond: QAPISchemaIfCond, *args: QAPIGenCCode) -> Iterator[None]:
"""
@@ -244,15 +249,18 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor):
what: str,
user_blurb: str,
builtin_blurb: Optional[str],
- pydoc: str):
+ pydoc: str,
+ gen_tracing: bool = False):
self._prefix = prefix
self._what = what
self._user_blurb = user_blurb
self._builtin_blurb = builtin_blurb
self._pydoc = pydoc
self._current_module: Optional[str] = None
- self._module: Dict[str, Tuple[QAPIGenC, QAPIGenH]] = {}
+ self._module: Dict[str, Tuple[QAPIGenC, QAPIGenH,
+ Optional[QAPIGenTrace]]] = {}
self._main_module: Optional[str] = None
+ self._gen_tracing = gen_tracing
@property
def _genc(self) -> QAPIGenC:
@@ -264,6 +272,14 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor):
assert self._current_module is not None
return self._module[self._current_module][1]
+ @property
+ def _gen_trace_events(self) -> QAPIGenTrace:
+ assert self._gen_tracing
+ assert self._current_module is not None
+ gent = self._module[self._current_module][2]
+ assert gent is not None
+ return gent
+
@staticmethod
def _module_dirname(name: str) -> str:
if QAPISchemaModule.is_user_module(name):
@@ -293,7 +309,12 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor):
basename = self._module_filename(self._what, name)
genc = QAPIGenC(basename + '.c', blurb, self._pydoc)
genh = QAPIGenH(basename + '.h', blurb, self._pydoc)
- self._module[name] = (genc, genh)
+
+ gent: Optional[QAPIGenTrace] = None
+ if self._gen_tracing:
+ gent = QAPIGenTrace(basename + '.trace-events')
+
+ self._module[name] = (genc, genh, gent)
self._current_module = name
@contextmanager
@@ -304,11 +325,13 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor):
self._current_module = old_module
def write(self, output_dir: str, opt_builtins: bool = False) -> None:
- for name, (genc, genh) in self._module.items():
+ for name, (genc, genh, gent) in self._module.items():
if QAPISchemaModule.is_builtin_module(name) and not opt_builtins:
continue
genc.write(output_dir)
genh.write(output_dir)
+ if gent is not None:
+ gent.write(output_dir)
def _begin_builtin_module(self) -> None:
pass
diff --git a/scripts/qapi/main.py b/scripts/qapi/main.py
index f2ea6e0ce4..fc216a53d3 100644
--- a/scripts/qapi/main.py
+++ b/scripts/qapi/main.py
@@ -32,7 +32,8 @@ def generate(schema_file: str,
output_dir: str,
prefix: str,
unmask: bool = False,
- builtins: bool = False) -> None:
+ builtins: bool = False,
+ gen_tracing: bool = False) -> None:
"""
Generate C code for the given schema into the target directory.
@@ -49,7 +50,7 @@ def generate(schema_file: str,
schema = QAPISchema(schema_file)
gen_types(schema, output_dir, prefix, builtins)
gen_visit(schema, output_dir, prefix, builtins)
- gen_commands(schema, output_dir, prefix)
+ gen_commands(schema, output_dir, prefix, gen_tracing)
gen_events(schema, output_dir, prefix)
gen_introspect(schema, output_dir, prefix, unmask)
@@ -74,6 +75,12 @@ def main() -> int:
parser.add_argument('-u', '--unmask-non-abi-names', action='store_true',
dest='unmask',
help="expose non-ABI names in introspection")
+
+ # Option --suppress-tracing exists so we can avoid solving build system
+ # problems. TODO Drop it when we no longer need it.
+ parser.add_argument('--suppress-tracing', action='store_true',
+ help="suppress adding trace events to qmp marshals")
+
parser.add_argument('schema', action='store')
args = parser.parse_args()
@@ -88,7 +95,8 @@ def main() -> int:
output_dir=args.output_dir,
prefix=args.prefix,
unmask=args.unmask,
- builtins=args.builtins)
+ builtins=args.builtins,
+ gen_tracing=not args.suppress_tracing)
except QAPIError as err:
print(f"{sys.argv[0]}: {str(err)}", file=sys.stderr)
return 1
diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
index fea4d6eb65..fe850763c5 100755
--- a/scripts/update-linux-headers.sh
+++ b/scripts/update-linux-headers.sh
@@ -9,6 +9,22 @@
#
# This work is licensed under the terms of the GNU GPL version 2.
# See the COPYING file in the top-level directory.
+#
+# The script will copy the headers into two target folders:
+#
+# - linux-headers/ for files that are required for compiling for a
+# Linux host. Generally we have these so we can use kernel structs
+# and defines that are more recent than the headers that might be
+# installed on the host system. Usually this script can do simple
+# file copies for these headers.
+#
+# - include/standard-headers/ for files that are used for guest
+# device emulation and are required on all hosts. For instance, we
+# get our definitions of the virtio structures from the Linux
+# kernel headers, but we need those definitions regardless of which
+# host OS we are building for. This script has to be careful to
+# sanitize the headers to remove any use of Linux-specifics such as
+# types like "__u64". This work is done in the cp_portable function.
tmpdir=$(mktemp -d)
linux="$1"
diff --git a/softmmu/rtc.c b/softmmu/rtc.c
index 5632684fc9..7e2956f81e 100644
--- a/softmmu/rtc.c
+++ b/softmmu/rtc.c
@@ -23,7 +23,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
@@ -33,6 +32,7 @@
#include "qom/object.h"
#include "sysemu/replay.h"
#include "sysemu/sysemu.h"
+#include "sysemu/rtc.h"
static enum {
RTC_BASE_UTC,
diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c
index 9d76d1114d..504d33aa91 100644
--- a/storage-daemon/qemu-storage-daemon.c
+++ b/storage-daemon/qemu-storage-daemon.c
@@ -100,7 +100,7 @@ static void help(void)
"\n"
#ifdef CONFIG_FUSE
" --export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file>\n"
-" [,growable=on|off][,writable=on|off]\n"
+" [,growable=on|off][,writable=on|off][,allow-other=on|off|auto]\n"
" export the specified block node over FUSE\n"
"\n"
#endif /* CONFIG_FUSE */
@@ -111,7 +111,7 @@ static void help(void)
" export the specified block node as a\n"
" vhost-user-blk device over UNIX domain socket\n"
" --export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,\n"
-" fd,addr.str=<fd>[,writable=on|off]\n"
+" addr.type=fd,addr.str=<fd>[,writable=on|off]\n"
" [,logical-block-size=<block-size>][,num-queues=<num-queues>]\n"
" export the specified block node as a\n"
" vhost-user-blk device over file descriptor\n"
diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c
index 787f4d2d4f..47d2efc60f 100644
--- a/subprojects/libvhost-user/libvhost-user.c
+++ b/subprojects/libvhost-user/libvhost-user.c
@@ -690,6 +690,29 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
VuDevRegion *dev_region = &dev->regions[dev->nregions];
void *mmap_addr;
+ if (vmsg->fd_num != 1) {
+ vmsg_close_fds(vmsg);
+ vu_panic(dev, "VHOST_USER_ADD_MEM_REG received %d fds - only 1 fd "
+ "should be sent for this message type", vmsg->fd_num);
+ return false;
+ }
+
+ if (vmsg->size < VHOST_USER_MEM_REG_SIZE) {
+ close(vmsg->fds[0]);
+ vu_panic(dev, "VHOST_USER_ADD_MEM_REG requires a message size of at "
+ "least %d bytes and only %d bytes were received",
+ VHOST_USER_MEM_REG_SIZE, vmsg->size);
+ return false;
+ }
+
+ if (dev->nregions == VHOST_USER_MAX_RAM_SLOTS) {
+ close(vmsg->fds[0]);
+ vu_panic(dev, "failing attempt to hot add memory via "
+ "VHOST_USER_ADD_MEM_REG message because the backend has "
+ "no free ram slots available");
+ return false;
+ }
+
/*
* If we are in postcopy mode and we receive a u64 payload with a 0 value
* we know all the postcopy client bases have been received, and we
@@ -728,12 +751,12 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
* accessing it before we userfault.
*/
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
- PROT_NONE, MAP_SHARED,
+ PROT_NONE, MAP_SHARED | MAP_NORESERVE,
vmsg->fds[0], 0);
} else {
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
- PROT_READ | PROT_WRITE, MAP_SHARED, vmsg->fds[0],
- 0);
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE,
+ vmsg->fds[0], 0);
}
if (mmap_addr == MAP_FAILED) {
@@ -796,10 +819,24 @@ static inline bool reg_equal(VuDevRegion *vudev_reg,
static bool
vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
- int i, j;
- bool found = false;
- VuDevRegion shadow_regions[VHOST_USER_MAX_RAM_SLOTS] = {};
VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m;
+ int i;
+ bool found = false;
+
+ if (vmsg->fd_num != 1) {
+ vmsg_close_fds(vmsg);
+ vu_panic(dev, "VHOST_USER_REM_MEM_REG received %d fds - only 1 fd "
+ "should be sent for this message type", vmsg->fd_num);
+ return false;
+ }
+
+ if (vmsg->size < VHOST_USER_MEM_REG_SIZE) {
+ close(vmsg->fds[0]);
+ vu_panic(dev, "VHOST_USER_REM_MEM_REG requires a message size of at "
+ "least %d bytes and only %d bytes were received",
+ VHOST_USER_MEM_REG_SIZE, vmsg->size);
+ return false;
+ }
DPRINT("Removing region:\n");
DPRINT(" guest_phys_addr: 0x%016"PRIx64"\n",
@@ -811,35 +848,40 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
DPRINT(" mmap_offset 0x%016"PRIx64"\n",
msg_region->mmap_offset);
- for (i = 0, j = 0; i < dev->nregions; i++) {
- if (!reg_equal(&dev->regions[i], msg_region)) {
- shadow_regions[j].gpa = dev->regions[i].gpa;
- shadow_regions[j].size = dev->regions[i].size;
- shadow_regions[j].qva = dev->regions[i].qva;
- shadow_regions[j].mmap_addr = dev->regions[i].mmap_addr;
- shadow_regions[j].mmap_offset = dev->regions[i].mmap_offset;
- j++;
- } else {
- found = true;
+ for (i = 0; i < dev->nregions; i++) {
+ if (reg_equal(&dev->regions[i], msg_region)) {
VuDevRegion *r = &dev->regions[i];
void *m = (void *) (uintptr_t) r->mmap_addr;
if (m) {
munmap(m, r->size + r->mmap_offset);
}
+
+ /*
+ * Shift all affected entries by 1 to close the hole at index i and
+ * zero out the last entry.
+ */
+ memmove(dev->regions + i, dev->regions + i + 1,
+ sizeof(VuDevRegion) * (dev->nregions - i - 1));
+ memset(dev->regions + dev->nregions - 1, 0, sizeof(VuDevRegion));
+ DPRINT("Successfully removed a region\n");
+ dev->nregions--;
+ i--;
+
+ found = true;
+
+ /* Continue the search for eventual duplicates. */
}
}
if (found) {
- memcpy(dev->regions, shadow_regions,
- sizeof(VuDevRegion) * VHOST_USER_MAX_RAM_SLOTS);
- DPRINT("Successfully removed a region\n");
- dev->nregions--;
vmsg_set_reply_u64(vmsg, 0);
} else {
vu_panic(dev, "Specified region not found\n");
}
+ close(vmsg->fds[0]);
+
return true;
}
@@ -878,7 +920,7 @@ vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg)
* accessing it before we userfault
*/
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
- PROT_NONE, MAP_SHARED,
+ PROT_NONE, MAP_SHARED | MAP_NORESERVE,
vmsg->fds[i], 0);
if (mmap_addr == MAP_FAILED) {
@@ -965,7 +1007,7 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)
* mapped address has to be page aligned, and we use huge
* pages. */
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
- PROT_READ | PROT_WRITE, MAP_SHARED,
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE,
vmsg->fds[i], 0);
if (mmap_addr == MAP_FAILED) {
diff --git a/subprojects/libvhost-user/libvhost-user.h b/subprojects/libvhost-user/libvhost-user.h
index 3d13dfadde..cde9f07bb3 100644
--- a/subprojects/libvhost-user/libvhost-user.h
+++ b/subprojects/libvhost-user/libvhost-user.h
@@ -129,6 +129,8 @@ typedef struct VhostUserMemoryRegion {
uint64_t mmap_offset;
} VhostUserMemoryRegion;
+#define VHOST_USER_MEM_REG_SIZE (sizeof(VhostUserMemoryRegion))
+
typedef struct VhostUserMemory {
uint32_t nregions;
uint32_t padding;
diff --git a/target/arm/helper.c b/target/arm/helper.c
index cfca0f5ba6..6dd241fbef 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -9317,8 +9317,10 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
return target_el;
}
-void arm_log_exception(int idx)
+void arm_log_exception(CPUState *cs)
{
+ int idx = cs->exception_index;
+
if (qemu_loglevel_mask(CPU_LOG_INT)) {
const char *exc = NULL;
static const char * const excnames[] = {
@@ -9352,7 +9354,8 @@ void arm_log_exception(int idx)
if (!exc) {
exc = "unknown";
}
- qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s]\n", idx, exc);
+ qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s] on CPU %d\n",
+ idx, exc, cs->cpu_index);
}
}
@@ -9655,7 +9658,7 @@ static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs)
* separately here.
*
* The vector table entry used is always the 0x14 Hyp mode entry point,
- * unless this is an UNDEF/HVC/abort taken from Hyp to Hyp.
+ * unless this is an UNDEF/SVC/HVC/abort taken from Hyp to Hyp.
* The offset applied to the preferred return address is always zero
* (see DDI0487C.a section G1.12.3).
* PSTATE A/I/F masks are set based only on the SCR.EA/IRQ/FIQ values.
@@ -9669,7 +9672,7 @@ static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs)
addr = 0x04;
break;
case EXCP_SWI:
- addr = 0x14;
+ addr = 0x08;
break;
case EXCP_BKPT:
/* Fall through to prefetch abort. */
@@ -10185,7 +10188,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
assert(!arm_feature(env, ARM_FEATURE_M));
- arm_log_exception(cs->exception_index);
+ arm_log_exception(cs);
qemu_log_mask(CPU_LOG_INT, "...from EL%d to EL%d\n", arm_current_el(env),
new_el);
if (qemu_loglevel_mask(CPU_LOG_INT)
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 89f7610ebc..3f05748ea4 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1130,7 +1130,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs)
__attribute__((nonnull));
-void arm_log_exception(int idx);
+void arm_log_exception(CPUState *cs);
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c
index 2c9922dc29..b11e927df1 100644
--- a/target/arm/m_helper.c
+++ b/target/arm/m_helper.c
@@ -2206,7 +2206,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
uint32_t lr;
bool ignore_stackfaults;
- arm_log_exception(cs->exception_index);
+ arm_log_exception(cs);
/*
* For exceptions we just mark as pending on the NVIC, and let that
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
index 23eb254228..37b763fca0 100644
--- a/target/hppa/cpu.c
+++ b/target/hppa/cpu.c
@@ -62,7 +62,7 @@ static void hppa_cpu_synchronize_from_tb(CPUState *cs,
static bool hppa_cpu_has_work(CPUState *cs)
{
- return cs->interrupt_request & CPU_INTERRUPT_HARD;
+ return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
}
static void hppa_cpu_disas_set_info(CPUState *cs, disassemble_info *info)
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index 45fd338b02..93c119532a 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -69,6 +69,11 @@
#define EXCP_SYSCALL 30
#define EXCP_SYSCALL_LWS 31
+/* Emulated hardware TOC button */
+#define EXCP_TOC 32 /* TOC = Transfer of control (NMI) */
+
+#define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_3 /* TOC */
+
/* Taken from Linux kernel: arch/parisc/include/asm/psw.h */
#define PSW_I 0x00000001
#define PSW_D 0x00000002
diff --git a/target/hppa/helper.h b/target/hppa/helper.h
index 0a629ffa7c..fe8a9ce493 100644
--- a/target/hppa/helper.h
+++ b/target/hppa/helper.h
@@ -80,6 +80,7 @@ DEF_HELPER_FLAGS_0(read_interval_timer, TCG_CALL_NO_RWG, tr)
#ifndef CONFIG_USER_ONLY
DEF_HELPER_1(halt, noreturn, env)
DEF_HELPER_1(reset, noreturn, env)
+DEF_HELPER_1(getshadowregs, void, env)
DEF_HELPER_1(rfi, void, env)
DEF_HELPER_1(rfi_r, void, env)
DEF_HELPER_FLAGS_2(write_interval_timer, TCG_CALL_NO_RWG, void, env, tr)
diff --git a/target/hppa/insns.decode b/target/hppa/insns.decode
index d4eefc0d48..c7a7e997f9 100644
--- a/target/hppa/insns.decode
+++ b/target/hppa/insns.decode
@@ -111,6 +111,7 @@ rfi_r 000000 ----- ----- --- 01100101 00000
# They are allocated from the unassigned instruction space.
halt 1111 1111 1111 1101 1110 1010 1101 0000
reset 1111 1111 1111 1101 1110 1010 1101 0001
+getshadowregs 1111 1111 1111 1101 1110 1010 1101 0010
####
# Memory Management
diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c
index 13073ae2bd..f599dccfff 100644
--- a/target/hppa/int_helper.c
+++ b/target/hppa/int_helper.c
@@ -23,6 +23,7 @@
#include "cpu.h"
#include "exec/helper-proto.h"
#include "hw/core/cpu.h"
+#include "hw/hppa/hppa_hardware.h"
#ifndef CONFIG_USER_ONLY
static void eval_interrupt(HPPACPU *cpu)
@@ -181,7 +182,14 @@ void hppa_cpu_do_interrupt(CPUState *cs)
}
/* step 7 */
- env->iaoq_f = env->cr[CR_IVA] + 32 * i;
+ if (i == EXCP_TOC) {
+ env->iaoq_f = FIRMWARE_START;
+ /* help SeaBIOS and provide iaoq_b and iasq_back in shadow regs */
+ env->gr[24] = env->cr_back[0];
+ env->gr[25] = env->cr_back[1];
+ } else {
+ env->iaoq_f = env->cr[CR_IVA] + 32 * i;
+ }
env->iaoq_b = env->iaoq_f + 4;
env->iasq_f = 0;
env->iasq_b = 0;
@@ -219,6 +227,7 @@ void hppa_cpu_do_interrupt(CPUState *cs)
[EXCP_PER_INTERRUPT] = "performance monitor interrupt",
[EXCP_SYSCALL] = "syscall",
[EXCP_SYSCALL_LWS] = "syscall-lws",
+ [EXCP_TOC] = "TOC (transfer of control)",
};
static int count;
const char *name = NULL;
@@ -248,6 +257,14 @@ bool hppa_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
HPPACPU *cpu = HPPA_CPU(cs);
CPUHPPAState *env = &cpu->env;
+ if (interrupt_request & CPU_INTERRUPT_NMI) {
+ /* Raise TOC (NMI) interrupt */
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_NMI);
+ cs->exception_index = EXCP_TOC;
+ hppa_cpu_do_interrupt(cs);
+ return true;
+ }
+
/* If interrupts are requested and enabled, raise them. */
if ((env->psw & PSW_I) && (interrupt_request & CPU_INTERRUPT_HARD)) {
cs->exception_index = EXCP_EXT_INTERRUPT;
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
index 1b86557d5d..b0dec4ebf4 100644
--- a/target/hppa/op_helper.c
+++ b/target/hppa/op_helper.c
@@ -694,7 +694,7 @@ void HELPER(rfi)(CPUHPPAState *env)
cpu_hppa_put_psw(env, env->cr[CR_IPSW]);
}
-void HELPER(rfi_r)(CPUHPPAState *env)
+void HELPER(getshadowregs)(CPUHPPAState *env)
{
env->gr[1] = env->shadow[0];
env->gr[8] = env->shadow[1];
@@ -703,6 +703,11 @@ void HELPER(rfi_r)(CPUHPPAState *env)
env->gr[17] = env->shadow[4];
env->gr[24] = env->shadow[5];
env->gr[25] = env->shadow[6];
+}
+
+void HELPER(rfi_r)(CPUHPPAState *env)
+{
+ helper_getshadowregs(env);
helper_rfi(env);
}
#endif
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index c6195590f8..5c0b1eb274 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -2393,6 +2393,16 @@ static bool trans_reset(DisasContext *ctx, arg_reset *a)
#endif
}
+static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
+{
+ CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
+#ifndef CONFIG_USER_ONLY
+ nullify_over(ctx);
+ gen_helper_getshadowregs(cpu_env);
+ return nullify_end(ctx);
+#endif
+}
+
static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
{
if (a->m) {
diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c
index 6239725c4f..b7d7388640 100644
--- a/target/openrisc/machine.c
+++ b/target/openrisc/machine.c
@@ -25,7 +25,6 @@ static const VMStateDescription vmstate_tlb_entry = {
.name = "tlb_entry",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINTTL(mr, OpenRISCTLBEntry),
VMSTATE_UINTTL(tr, OpenRISCTLBEntry),
diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c
index 764afe5a2a..a2c720cc4d 100644
--- a/target/ppc/cpu-models.c
+++ b/target/ppc/cpu-models.c
@@ -428,8 +428,6 @@
"PowerPC 601v1")
POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v,
"PowerPC 601v2")
- POWERPC_DEF("602", CPU_POWERPC_602, 602,
- "PowerPC 602")
POWERPC_DEF("603", CPU_POWERPC_603, 603,
"PowerPC 603")
POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E,
diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h
index bf1dc7e5ca..612978a3fb 100644
--- a/target/ppc/cpu-models.h
+++ b/target/ppc/cpu-models.h
@@ -208,7 +208,6 @@ enum {
CPU_POWERPC_601_v0 = 0x00010001,
CPU_POWERPC_601_v1 = 0x00010001,
CPU_POWERPC_601_v2 = 0x00010002,
- CPU_POWERPC_602 = 0x00050100,
CPU_POWERPC_603 = 0x00030100,
CPU_POWERPC_603E_v11 = 0x00060101,
CPU_POWERPC_603E_v12 = 0x00060102,
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 2560b70c5f..dcd83b503c 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -321,12 +321,11 @@ typedef enum {
#define MSR_UCLE 26 /* User-mode cache lock enable for BookE */
#define MSR_VR 25 /* altivec available x hflags */
#define MSR_SPE 25 /* SPE enable for BookE x hflags */
-#define MSR_AP 23 /* Access privilege state on 602 hflags */
#define MSR_VSX 23 /* Vector Scalar Extension (ISA 2.06 and later) x hflags */
-#define MSR_SA 22 /* Supervisor access mode on 602 hflags */
#define MSR_S 22 /* Secure state */
#define MSR_KEY 19 /* key bit on 603e */
#define MSR_POW 18 /* Power management */
+#define MSR_WE 18 /* Wait State Enable on 405 */
#define MSR_TGPR 17 /* TGPR usage on 602/603 x */
#define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC x */
#define MSR_ILE 16 /* Interrupt little-endian mode */
@@ -476,9 +475,7 @@ typedef enum {
#define msr_ucle ((env->msr >> MSR_UCLE) & 1)
#define msr_vr ((env->msr >> MSR_VR) & 1)
#define msr_spe ((env->msr >> MSR_SPE) & 1)
-#define msr_ap ((env->msr >> MSR_AP) & 1)
#define msr_vsx ((env->msr >> MSR_VSX) & 1)
-#define msr_sa ((env->msr >> MSR_SA) & 1)
#define msr_key ((env->msr >> MSR_KEY) & 1)
#define msr_pow ((env->msr >> MSR_POW) & 1)
#define msr_tgpr ((env->msr >> MSR_TGPR) & 1)
@@ -2141,8 +2138,6 @@ enum {
PPC_MFTB = 0x0000000000000200ULL,
/* Fixed-point unit extensions */
- /* PowerPC 602 specific */
- PPC_602_SPEC = 0x0000000000000400ULL,
/* isel instruction */
PPC_ISEL = 0x0000000000000800ULL,
/* popcntb instruction */
@@ -2244,7 +2239,7 @@ enum {
#define PPC_TCG_INSNS (PPC_INSNS_BASE | PPC_POWER | PPC_POWER2 \
| PPC_POWER_RTC | PPC_POWER_BR | PPC_64B \
| PPC_64BX | PPC_64H | PPC_WAIT | PPC_MFTB \
- | PPC_602_SPEC | PPC_ISEL | PPC_POPCNTB \
+ | PPC_ISEL | PPC_POPCNTB \
| PPC_STRING | PPC_FLOAT | PPC_FLOAT_EXT \
| PPC_FLOAT_FSQRT | PPC_FLOAT_FRES \
| PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES \
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index e30e86fe9d..bf60529d37 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -749,54 +749,6 @@ static void register_G2_sprs(CPUPPCState *env)
0x00000000);
}
-/* SPR specific to PowerPC 602 implementation */
-static void register_602_sprs(CPUPPCState *env)
-{
- /* ESA registers */
- /* XXX : not implemented */
- spr_register(env, SPR_SER, "SER",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_SEBR, "SEBR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_ESASRR, "ESASRR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* Floating point status */
- /* XXX : not implemented */
- spr_register(env, SPR_SP, "SP",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_LT, "LT",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* Watchdog timer */
- /* XXX : not implemented */
- spr_register(env, SPR_TCR, "TCR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* Interrupt base */
- spr_register(env, SPR_IBR, "IBR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_IABR, "IABR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
-}
-
/* SPR specific to PowerPC 601 implementation */
static void register_601_sprs(CPUPPCState *env)
{
@@ -2128,33 +2080,6 @@ static void init_excp_601(CPUPPCState *env)
#endif
}
-static void init_excp_602(CPUPPCState *env)
-{
-#if !defined(CONFIG_USER_ONLY)
- /* XXX: exception prefix has a special behavior on 602 */
- env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100;
- env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200;
- env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300;
- env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400;
- env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
- env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600;
- env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700;
- env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800;
- env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900;
- env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00;
- env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00;
- env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000;
- env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100;
- env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200;
- env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
- env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
- env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001500;
- env->excp_vectors[POWERPC_EXCP_EMUL] = 0x00001600;
- /* Hardware reset vector */
- env->hreset_vector = 0x00000100UL;
-#endif
-}
-
static void init_excp_603(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
@@ -2535,11 +2460,12 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data)
PPC_MEM_SYNC | PPC_MEM_EIEIO |
PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC |
PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP;
- pcc->msr_mask = (1ull << MSR_POW) |
+ pcc->msr_mask = (1ull << MSR_WE) |
(1ull << MSR_CE) |
(1ull << MSR_EE) |
(1ull << MSR_PR) |
(1ull << MSR_FP) |
+ (1ull << MSR_ME) |
(1ull << MSR_DWE) |
(1ull << MSR_DE) |
(1ull << MSR_IR) |
@@ -4080,76 +4006,6 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE;
}
-static void init_proc_602(CPUPPCState *env)
-{
- register_ne_601_sprs(env);
- register_sdr1_sprs(env);
- register_602_sprs(env);
- /* Time base */
- register_tbl(env);
- /* hardware implementation registers */
- /* XXX : not implemented */
- spr_register(env, SPR_HID0, "HID0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_HID1, "HID1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* Memory management */
- register_low_BATs(env);
- register_6xx_7xx_soft_tlb(env, 64, 2);
- init_excp_602(env);
- env->dcache_line_size = 32;
- env->icache_line_size = 32;
- /* Allocate hardware IRQ controller */
- ppc6xx_irq_init(env_archcpu(env));
-}
-
-POWERPC_FAMILY(602)(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-
- dc->desc = "PowerPC 602";
- pcc->init_proc = init_proc_602;
- pcc->check_pow = check_pow_hid0;
- pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
- PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
- PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
- PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
- PPC_MEM_SYNC | PPC_MEM_EIEIO |
- PPC_MEM_TLBIE | PPC_6xx_TLB | PPC_MEM_TLBSYNC |
- PPC_SEGMENT | PPC_602_SPEC;
- pcc->msr_mask = (1ull << MSR_VSX) |
- (1ull << MSR_SA) |
- (1ull << MSR_POW) |
- (1ull << MSR_TGPR) |
- (1ull << MSR_ILE) |
- (1ull << MSR_EE) |
- (1ull << MSR_PR) |
- (1ull << MSR_FP) |
- (1ull << MSR_ME) |
- (1ull << MSR_FE0) |
- (1ull << MSR_SE) |
- (1ull << MSR_DE) |
- (1ull << MSR_FE1) |
- (1ull << MSR_EP) |
- (1ull << MSR_IR) |
- (1ull << MSR_DR) |
- (1ull << MSR_RI) |
- (1ull << MSR_LE);
- /* XXX: 602 MMU is quite specific. Should add a special case */
- pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
- pcc->excp_model = POWERPC_EXCP_602;
- pcc->bus_model = PPC_FLAGS_INPUT_6xx;
- pcc->bfd_mach = bfd_mach_ppc_602;
- pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |
- POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK;
-}
-
static void init_proc_603(CPUPPCState *env)
{
register_ne_601_sprs(env);
@@ -8270,8 +8126,6 @@ static void ppc_cpu_reset(DeviceState *dev)
msr = (target_ulong)0;
msr |= (target_ulong)MSR_HVB;
- msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
- msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
msr |= (target_ulong)1 << MSR_EP;
#if defined(DO_SINGLE_STEP) && 0
/* Single step trace mode */
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index bc646c67a0..c107953dec 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -392,6 +392,660 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu,
check_tlb_flush(env, false);
}
+static void powerpc_excp_40x(PowerPCCPU *cpu, int excp)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+ target_ulong msr, new_msr, vector;
+ int srr0, srr1;
+
+ if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
+ cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
+ }
+
+ qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
+ " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
+ excp, env->error_code);
+
+ /* new srr1 value excluding must-be-zero bits */
+ msr = env->msr & ~0x783f0000ULL;
+
+ /*
+ * new interrupt handler msr preserves existing ME unless
+ * explicitly overriden.
+ */
+ new_msr = env->msr & (((target_ulong)1 << MSR_ME));
+
+ /* target registers */
+ srr0 = SPR_SRR0;
+ srr1 = SPR_SRR1;
+
+ /*
+ * Hypervisor emulation assistance interrupt only exists on server
+ * arch 2.05 server or later.
+ */
+ if (excp == POWERPC_EXCP_HV_EMU) {
+ excp = POWERPC_EXCP_PROGRAM;
+ }
+
+ vector = env->excp_vectors[excp];
+ if (vector == (target_ulong)-1ULL) {
+ cpu_abort(cs, "Raised an exception without defined vector %d\n",
+ excp);
+ }
+
+ vector |= env->excp_prefix;
+
+ switch (excp) {
+ case POWERPC_EXCP_CRITICAL: /* Critical input */
+ srr0 = SPR_40x_SRR2;
+ srr1 = SPR_40x_SRR3;
+ break;
+ case POWERPC_EXCP_MCHECK: /* Machine check exception */
+ if (msr_me == 0) {
+ /*
+ * Machine check exception is not enabled. Enter
+ * checkstop state.
+ */
+ fprintf(stderr, "Machine check while not allowed. "
+ "Entering checkstop state\n");
+ if (qemu_log_separate()) {
+ qemu_log("Machine check while not allowed. "
+ "Entering checkstop state\n");
+ }
+ cs->halted = 1;
+ cpu_interrupt_exittb(cs);
+ }
+
+ /* machine check exceptions don't have ME set */
+ new_msr &= ~((target_ulong)1 << MSR_ME);
+
+ srr0 = SPR_40x_SRR2;
+ srr1 = SPR_40x_SRR3;
+ break;
+ case POWERPC_EXCP_DSI: /* Data storage exception */
+ trace_ppc_excp_dsi(env->spr[SPR_40x_ESR], env->spr[SPR_40x_DEAR]);
+ break;
+ case POWERPC_EXCP_ISI: /* Instruction storage exception */
+ trace_ppc_excp_isi(msr, env->nip);
+ break;
+ case POWERPC_EXCP_EXTERNAL: /* External input */
+ break;
+ case POWERPC_EXCP_ALIGN: /* Alignment exception */
+ break;
+ case POWERPC_EXCP_PROGRAM: /* Program exception */
+ switch (env->error_code & ~0xF) {
+ case POWERPC_EXCP_FP:
+ if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
+ trace_ppc_excp_fp_ignore();
+ cs->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+ return;
+ }
+ env->spr[SPR_40x_ESR] = ESR_FP;
+ break;
+ case POWERPC_EXCP_INVAL:
+ trace_ppc_excp_inval(env->nip);
+ env->spr[SPR_40x_ESR] = ESR_PIL;
+ break;
+ case POWERPC_EXCP_PRIV:
+ env->spr[SPR_40x_ESR] = ESR_PPR;
+ break;
+ case POWERPC_EXCP_TRAP:
+ env->spr[SPR_40x_ESR] = ESR_PTR;
+ break;
+ default:
+ cpu_abort(cs, "Invalid program exception %d. Aborting\n",
+ env->error_code);
+ break;
+ }
+ break;
+ case POWERPC_EXCP_SYSCALL: /* System call exception */
+ dump_syscall(env);
+
+ /*
+ * We need to correct the NIP which in this case is supposed
+ * to point to the next instruction
+ */
+ env->nip += 4;
+ break;
+ case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
+ trace_ppc_excp_print("FIT");
+ break;
+ case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
+ trace_ppc_excp_print("WDT");
+ break;
+ case POWERPC_EXCP_DTLB: /* Data TLB error */
+ case POWERPC_EXCP_ITLB: /* Instruction TLB error */
+ break;
+ case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
+ trace_ppc_excp_print("PIT");
+ break;
+ case POWERPC_EXCP_DEBUG: /* Debug interrupt */
+ cpu_abort(cs, "%s exception not implemented\n",
+ powerpc_excp_name(excp));
+ break;
+ default:
+ cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
+ break;
+ }
+
+ /* Sanity check */
+ if (!(env->msr_mask & MSR_HVB)) {
+ if (new_msr & MSR_HVB) {
+ cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
+ "no HV support\n", excp);
+ }
+ if (srr0 == SPR_HSRR0) {
+ cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
+ "no HV support\n", excp);
+ }
+ }
+
+ /* Save PC */
+ env->spr[srr0] = env->nip;
+
+ /* Save MSR */
+ env->spr[srr1] = msr;
+
+ powerpc_set_excp_state(cpu, vector, new_msr);
+}
+
+static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+ target_ulong msr, new_msr, vector;
+
+ if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
+ cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
+ }
+
+ qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
+ " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
+ excp, env->error_code);
+
+ /* new srr1 value excluding must-be-zero bits */
+ msr = env->msr & ~0x783f0000ULL;
+
+ /*
+ * new interrupt handler msr preserves existing ME unless
+ * explicitly overriden
+ */
+ new_msr = env->msr & ((target_ulong)1 << MSR_ME);
+
+ /*
+ * Hypervisor emulation assistance interrupt only exists on server
+ * arch 2.05 server or later.
+ */
+ if (excp == POWERPC_EXCP_HV_EMU) {
+ excp = POWERPC_EXCP_PROGRAM;
+ }
+
+ vector = env->excp_vectors[excp];
+ if (vector == (target_ulong)-1ULL) {
+ cpu_abort(cs, "Raised an exception without defined vector %d\n",
+ excp);
+ }
+
+ vector |= env->excp_prefix;
+
+ switch (excp) {
+ case POWERPC_EXCP_MCHECK: /* Machine check exception */
+ if (msr_me == 0) {
+ /*
+ * Machine check exception is not enabled. Enter
+ * checkstop state.
+ */
+ fprintf(stderr, "Machine check while not allowed. "
+ "Entering checkstop state\n");
+ if (qemu_log_separate()) {
+ qemu_log("Machine check while not allowed. "
+ "Entering checkstop state\n");
+ }
+ cs->halted = 1;
+ cpu_interrupt_exittb(cs);
+ }
+
+ /* machine check exceptions don't have ME set */
+ new_msr &= ~((target_ulong)1 << MSR_ME);
+
+ break;
+ case POWERPC_EXCP_DSI: /* Data storage exception */
+ trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+ break;
+ case POWERPC_EXCP_ISI: /* Instruction storage exception */
+ trace_ppc_excp_isi(msr, env->nip);
+ msr |= env->error_code;
+ break;
+ case POWERPC_EXCP_EXTERNAL: /* External input */
+ break;
+ case POWERPC_EXCP_ALIGN: /* Alignment exception */
+ /* Get rS/rD and rA from faulting opcode */
+ /*
+ * Note: the opcode fields will not be set properly for a
+ * direct store load/store, but nobody cares as nobody
+ * actually uses direct store segments.
+ */
+ env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
+ break;
+ case POWERPC_EXCP_PROGRAM: /* Program exception */
+ switch (env->error_code & ~0xF) {
+ case POWERPC_EXCP_FP:
+ if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
+ trace_ppc_excp_fp_ignore();
+ cs->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+ return;
+ }
+
+ /*
+ * FP exceptions always have NIP pointing to the faulting
+ * instruction, so always use store_next and claim we are
+ * precise in the MSR.
+ */
+ msr |= 0x00100000;
+ break;
+ case POWERPC_EXCP_INVAL:
+ trace_ppc_excp_inval(env->nip);
+ msr |= 0x00080000;
+ break;
+ case POWERPC_EXCP_PRIV:
+ msr |= 0x00040000;
+ break;
+ case POWERPC_EXCP_TRAP:
+ msr |= 0x00020000;
+ break;
+ default:
+ /* Should never occur */
+ cpu_abort(cs, "Invalid program exception %d. Aborting\n",
+ env->error_code);
+ break;
+ }
+ break;
+ case POWERPC_EXCP_SYSCALL: /* System call exception */
+ {
+ int lev = env->error_code;
+
+ if ((lev == 1) && cpu->vhyp) {
+ dump_hcall(env);
+ } else {
+ dump_syscall(env);
+ }
+
+ /*
+ * We need to correct the NIP which in this case is supposed
+ * to point to the next instruction
+ */
+ env->nip += 4;
+
+ /*
+ * The Virtual Open Firmware (VOF) relies on the 'sc 1'
+ * instruction to communicate with QEMU. The pegasos2 machine
+ * uses VOF and the 74xx CPUs, so although the 74xx don't have
+ * HV mode, we need to keep hypercall support.
+ */
+ if ((lev == 1) && cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ vhc->hypercall(cpu->vhyp, cpu);
+ return;
+ }
+
+ break;
+ }
+ case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
+ case POWERPC_EXCP_DECR: /* Decrementer exception */
+ break;
+ case POWERPC_EXCP_RESET: /* System reset exception */
+ if (msr_pow) {
+ cpu_abort(cs, "Trying to deliver power-saving system reset "
+ "exception %d with no HV support\n", excp);
+ }
+ break;
+ case POWERPC_EXCP_TRACE: /* Trace exception */
+ break;
+ case POWERPC_EXCP_VPU: /* Vector unavailable exception */
+ break;
+ case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
+ case POWERPC_EXCP_SMI: /* System management interrupt */
+ case POWERPC_EXCP_THERM: /* Thermal interrupt */
+ case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
+ case POWERPC_EXCP_VPUA: /* Vector assist exception */
+ cpu_abort(cs, "%s exception not implemented\n",
+ powerpc_excp_name(excp));
+ break;
+ default:
+ cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
+ break;
+ }
+
+ /* Sanity check */
+ if (!(env->msr_mask & MSR_HVB)) {
+ if (new_msr & MSR_HVB) {
+ cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
+ "no HV support\n", excp);
+ }
+ }
+
+ /*
+ * Sort out endianness of interrupt, this differs depending on the
+ * CPU, the HV mode, etc...
+ */
+ if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
+ new_msr |= (target_ulong)1 << MSR_LE;
+ }
+
+ /* Save PC */
+ env->spr[SPR_SRR0] = env->nip;
+
+ /* Save MSR */
+ env->spr[SPR_SRR1] = msr;
+
+ powerpc_set_excp_state(cpu, vector, new_msr);
+}
+
+#ifdef TARGET_PPC64
+static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+ int excp_model = env->excp_model;
+ target_ulong msr, new_msr, vector;
+ int srr0, srr1, lev = -1;
+
+ if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
+ cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
+ }
+
+ qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
+ " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
+ excp, env->error_code);
+
+ /* new srr1 value excluding must-be-zero bits */
+ msr = env->msr & ~0x783f0000ULL;
+
+ /*
+ * new interrupt handler msr preserves existing HV and ME unless
+ * explicitly overriden
+ */
+ new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
+
+ /* target registers */
+ srr0 = SPR_SRR0;
+ srr1 = SPR_SRR1;
+
+ /*
+ * check for special resume at 0x100 from doze/nap/sleep/winkle on
+ * P7/P8/P9
+ */
+ if (env->resume_as_sreset) {
+ excp = powerpc_reset_wakeup(cs, env, excp, &msr);
+ }
+
+ /*
+ * We don't want to generate a Hypervisor Emulation Assistance
+ * Interrupt if we don't have HVB in msr_mask (PAPR mode).
+ */
+ if (excp == POWERPC_EXCP_HV_EMU && !(env->msr_mask & MSR_HVB)) {
+ excp = POWERPC_EXCP_PROGRAM;
+ }
+
+ vector = env->excp_vectors[excp];
+ if (vector == (target_ulong)-1ULL) {
+ cpu_abort(cs, "Raised an exception without defined vector %d\n",
+ excp);
+ }
+
+ vector |= env->excp_prefix;
+
+ switch (excp) {
+ case POWERPC_EXCP_MCHECK: /* Machine check exception */
+ if (msr_me == 0) {
+ /*
+ * Machine check exception is not enabled. Enter
+ * checkstop state.
+ */
+ fprintf(stderr, "Machine check while not allowed. "
+ "Entering checkstop state\n");
+ if (qemu_log_separate()) {
+ qemu_log("Machine check while not allowed. "
+ "Entering checkstop state\n");
+ }
+ cs->halted = 1;
+ cpu_interrupt_exittb(cs);
+ }
+ if (env->msr_mask & MSR_HVB) {
+ /*
+ * ISA specifies HV, but can be delivered to guest with HV
+ * clear (e.g., see FWNMI in PAPR).
+ */
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+
+ /* machine check exceptions don't have ME set */
+ new_msr &= ~((target_ulong)1 << MSR_ME);
+
+ break;
+ case POWERPC_EXCP_DSI: /* Data storage exception */
+ trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+ break;
+ case POWERPC_EXCP_ISI: /* Instruction storage exception */
+ trace_ppc_excp_isi(msr, env->nip);
+ msr |= env->error_code;
+ break;
+ case POWERPC_EXCP_EXTERNAL: /* External input */
+ {
+ bool lpes0;
+
+ /*
+ * LPES0 is only taken into consideration if we support HV
+ * mode for this CPU.
+ */
+ if (!env->has_hv_mode) {
+ break;
+ }
+
+ lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+
+ if (!lpes0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+ srr0 = SPR_HSRR0;
+ srr1 = SPR_HSRR1;
+ }
+
+ break;
+ }
+ case POWERPC_EXCP_ALIGN: /* Alignment exception */
+ /* Get rS/rD and rA from faulting opcode */
+ /*
+ * Note: the opcode fields will not be set properly for a
+ * direct store load/store, but nobody cares as nobody
+ * actually uses direct store segments.
+ */
+ env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
+ break;
+ case POWERPC_EXCP_PROGRAM: /* Program exception */
+ switch (env->error_code & ~0xF) {
+ case POWERPC_EXCP_FP:
+ if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
+ trace_ppc_excp_fp_ignore();
+ cs->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+ return;
+ }
+
+ /*
+ * FP exceptions always have NIP pointing to the faulting
+ * instruction, so always use store_next and claim we are
+ * precise in the MSR.
+ */
+ msr |= 0x00100000;
+ break;
+ case POWERPC_EXCP_INVAL:
+ trace_ppc_excp_inval(env->nip);
+ msr |= 0x00080000;
+ break;
+ case POWERPC_EXCP_PRIV:
+ msr |= 0x00040000;
+ break;
+ case POWERPC_EXCP_TRAP:
+ msr |= 0x00020000;
+ break;
+ default:
+ /* Should never occur */
+ cpu_abort(cs, "Invalid program exception %d. Aborting\n",
+ env->error_code);
+ break;
+ }
+ break;
+ case POWERPC_EXCP_SYSCALL: /* System call exception */
+ lev = env->error_code;
+
+ if ((lev == 1) && cpu->vhyp) {
+ dump_hcall(env);
+ } else {
+ dump_syscall(env);
+ }
+
+ /*
+ * We need to correct the NIP which in this case is supposed
+ * to point to the next instruction
+ */
+ env->nip += 4;
+
+ /* "PAPR mode" built-in hypercall emulation */
+ if ((lev == 1) && cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ vhc->hypercall(cpu->vhyp, cpu);
+ return;
+ }
+ if (lev == 1) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ break;
+ case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception */
+ lev = env->error_code;
+ dump_syscall(env);
+ env->nip += 4;
+ new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
+ new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+
+ vector += lev * 0x20;
+
+ env->lr = env->nip;
+ env->ctr = msr;
+ break;
+ case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
+ case POWERPC_EXCP_DECR: /* Decrementer exception */
+ break;
+ case POWERPC_EXCP_RESET: /* System reset exception */
+ /* A power-saving exception sets ME, otherwise it is unchanged */
+ if (msr_pow) {
+ /* indicate that we resumed from power save mode */
+ msr |= 0x10000;
+ new_msr |= ((target_ulong)1 << MSR_ME);
+ }
+ if (env->msr_mask & MSR_HVB) {
+ /*
+ * ISA specifies HV, but can be delivered to guest with HV
+ * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
+ */
+ new_msr |= (target_ulong)MSR_HVB;
+ } else {
+ if (msr_pow) {
+ cpu_abort(cs, "Trying to deliver power-saving system reset "
+ "exception %d with no HV support\n", excp);
+ }
+ }
+ break;
+ case POWERPC_EXCP_DSEG: /* Data segment exception */
+ case POWERPC_EXCP_ISEG: /* Instruction segment exception */
+ case POWERPC_EXCP_TRACE: /* Trace exception */
+ break;
+ case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
+ msr |= env->error_code;
+ /* fall through */
+ case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
+ case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
+ case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */
+ case POWERPC_EXCP_HV_EMU:
+ case POWERPC_EXCP_HVIRT: /* Hypervisor virtualization */
+ srr0 = SPR_HSRR0;
+ srr1 = SPR_HSRR1;
+ new_msr |= (target_ulong)MSR_HVB;
+ new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+ break;
+ case POWERPC_EXCP_VPU: /* Vector unavailable exception */
+ case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
+ case POWERPC_EXCP_FU: /* Facility unavailable exception */
+ env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
+ break;
+ case POWERPC_EXCP_HV_FU: /* Hypervisor Facility Unavailable Exception */
+ env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
+ srr0 = SPR_HSRR0;
+ srr1 = SPR_HSRR1;
+ new_msr |= (target_ulong)MSR_HVB;
+ new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+ break;
+ case POWERPC_EXCP_THERM: /* Thermal interrupt */
+ case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
+ case POWERPC_EXCP_VPUA: /* Vector assist exception */
+ case POWERPC_EXCP_MAINT: /* Maintenance exception */
+ case POWERPC_EXCP_SDOOR: /* Doorbell interrupt */
+ case POWERPC_EXCP_HV_MAINT: /* Hypervisor Maintenance exception */
+ cpu_abort(cs, "%s exception not implemented\n",
+ powerpc_excp_name(excp));
+ break;
+ default:
+ cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
+ break;
+ }
+
+ /* Sanity check */
+ if (!(env->msr_mask & MSR_HVB)) {
+ if (new_msr & MSR_HVB) {
+ cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
+ "no HV support\n", excp);
+ }
+ if (srr0 == SPR_HSRR0) {
+ cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
+ "no HV support\n", excp);
+ }
+ }
+
+ /*
+ * Sort out endianness of interrupt, this differs depending on the
+ * CPU, the HV mode, etc...
+ */
+ if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
+ new_msr |= (target_ulong)1 << MSR_LE;
+ }
+
+ new_msr |= (target_ulong)1 << MSR_SF;
+
+ if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
+ /* Save PC */
+ env->spr[srr0] = env->nip;
+
+ /* Save MSR */
+ env->spr[srr1] = msr;
+ }
+
+ /* This can update new_msr and vector if AIL applies */
+ ppc_excp_apply_ail(cpu, excp_model, excp, msr, &new_msr, &vector);
+
+ powerpc_set_excp_state(cpu, vector, new_msr);
+}
+#else
+static inline void powerpc_excp_books(PowerPCCPU *cpu, int excp)
+{
+ g_assert_not_reached();
+}
+#endif
+
/*
* Note that this function should be greatly optimized when called
* with a constant excp, from ppc_hw_interrupt
@@ -768,7 +1422,6 @@ static inline void powerpc_excp_legacy(PowerPCCPU *cpu, int excp)
case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
switch (excp_model) {
- case POWERPC_EXCP_602:
case POWERPC_EXCP_603:
case POWERPC_EXCP_G2:
/* Swap temporary saved registers with GPRs */
@@ -872,6 +1525,19 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp)
CPUPPCState *env = &cpu->env;
switch (env->excp_model) {
+ case POWERPC_EXCP_40x:
+ powerpc_excp_40x(cpu, excp);
+ break;
+ case POWERPC_EXCP_74xx:
+ powerpc_excp_74xx(cpu, excp);
+ break;
+ case POWERPC_EXCP_970:
+ case POWERPC_EXCP_POWER7:
+ case POWERPC_EXCP_POWER8:
+ case POWERPC_EXCP_POWER9:
+ case POWERPC_EXCP_POWER10:
+ powerpc_excp_books(cpu, excp);
+ break;
default:
powerpc_excp_legacy(cpu, excp);
}
@@ -1155,7 +1821,6 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
(env->spr[SPR_PSSCR] & PSSCR_EC);
}
#endif /* defined(TARGET_PPC64) */
-#endif /* CONFIG_TCG */
static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
{
@@ -1164,6 +1829,10 @@ static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
/* MSR:POW cannot be set by any form of rfi */
msr &= ~(1ULL << MSR_POW);
+ /* MSR:TGPR cannot be set by any form of rfi */
+ if (env->flags & POWERPC_FLAG_TGPR)
+ msr &= ~(1ULL << MSR_TGPR);
+
#if defined(TARGET_PPC64)
/* Switching to 32-bit ? Crop the nip */
if (!msr_is_64bit(env, msr)) {
@@ -1188,7 +1857,6 @@ static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
check_tlb_flush(env, false);
}
-#ifdef CONFIG_TCG
void helper_rfi(CPUPPCState *env)
{
do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful);
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index d318837ea5..f2e5060910 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -646,7 +646,6 @@ DEF_HELPER_FLAGS_2(slbieg, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_NO_RWG, tl, env, tl)
DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, tl, tl)
-DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_1(msgsnd, void, tl)
DEF_HELPER_2(msgclr, void, env, tl)
DEF_HELPER_1(book3s_msgsnd, void, tl)
@@ -707,6 +706,7 @@ DEF_HELPER_FLAGS_1(load_40x_pit, TCG_CALL_NO_RWG, tl, env)
DEF_HELPER_FLAGS_2(store_40x_pit, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(store_40x_tcr, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(store_40x_tsr, TCG_CALL_NO_RWG, void, env, tl)
+DEF_HELPER_2(store_40x_pid, void, env, tl)
DEF_HELPER_2(store_40x_dbcr0, void, env, tl)
DEF_HELPER_2(store_40x_sler, void, env, tl)
DEF_HELPER_FLAGS_2(store_booke_tcr, TCG_CALL_NO_RWG, void, env, tl)
diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
index 8671b7bb69..5b12cb03c9 100644
--- a/target/ppc/helper_regs.c
+++ b/target/ppc/helper_regs.c
@@ -156,7 +156,8 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
*/
unsigned immu_idx, dmmu_idx;
dmmu_idx = msr & (1 << MSR_PR) ? 0 : 1;
- if (env->mmu_model & POWERPC_MMU_BOOKE) {
+ if (env->mmu_model == POWERPC_MMU_BOOKE ||
+ env->mmu_model == POWERPC_MMU_BOOKE206) {
dmmu_idx |= msr & (1 << MSR_GS) ? 4 : 0;
immu_idx = dmmu_idx;
immu_idx |= msr & (1 << MSR_IS) ? 2 : 0;
@@ -201,7 +202,11 @@ void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
void cpu_interrupt_exittb(CPUState *cs)
{
- if (!kvm_enabled()) {
+ /*
+ * We don't need to worry about translation blocks
+ * when running with KVM.
+ */
+ if (kvm_enabled()) {
return;
}
@@ -233,7 +238,8 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv)
((value >> MSR_DR) & 1) != msr_dr) {
cpu_interrupt_exittb(cs);
}
- if ((env->mmu_model & POWERPC_MMU_BOOKE) &&
+ if ((env->mmu_model == POWERPC_MMU_BOOKE ||
+ env->mmu_model == POWERPC_MMU_BOOKE206) &&
((value >> MSR_GS) & 1) != msr_gs) {
cpu_interrupt_exittb(cs);
}
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index 9bc327bcba..d7765fd3e3 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -489,27 +489,6 @@ target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
}
/*****************************************************************************/
-/* 602 specific instructions */
-/* mfrom is the most crazy instruction ever seen, imho ! */
-/* Real implementation uses a ROM table. Do the same */
-/*
- * Extremely decomposed:
- * -arg / 256
- * return 256 * log10(10 + 1.0) + 0.5
- */
-#if !defined(CONFIG_USER_ONLY)
-target_ulong helper_602_mfrom(target_ulong arg)
-{
- if (likely(arg < 602)) {
-#include "mfrom_table.c.inc"
- return mfrom_ROM_table[arg];
- } else {
- return 0;
- }
-}
-#endif
-
-/*****************************************************************************/
/* Altivec extension helpers */
#if defined(HOST_WORDS_BIGENDIAN)
#define VECTOR_FOR_INORDER_I(index, element) \
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index 733a22d744..a503e00ddc 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -421,7 +421,6 @@ static const VMStateDescription vmstate_tm = {
.name = "cpu/tm",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.needed = tm_needed,
.fields = (VMStateField []) {
VMSTATE_UINTTL_ARRAY(env.tm_gpr, PowerPCCPU, 32),
@@ -672,7 +671,6 @@ const VMStateDescription vmstate_ppc_cpu = {
.name = "cpu",
.version_id = 5,
.minimum_version_id = 5,
- .minimum_version_id_old = 4,
.pre_save = cpu_pre_save,
.post_load = cpu_post_load,
.fields = (VMStateField[]) {
diff --git a/target/ppc/mfrom_table.c.inc b/target/ppc/mfrom_table.c.inc
deleted file mode 100644
index 1653b974a4..0000000000
--- a/target/ppc/mfrom_table.c.inc
+++ /dev/null
@@ -1,78 +0,0 @@
-static const uint8_t mfrom_ROM_table[602] = {
- 77, 77, 76, 76, 75, 75, 74, 74,
- 73, 73, 72, 72, 71, 71, 70, 70,
- 69, 69, 68, 68, 68, 67, 67, 66,
- 66, 65, 65, 64, 64, 64, 63, 63,
- 62, 62, 61, 61, 61, 60, 60, 59,
- 59, 58, 58, 58, 57, 57, 56, 56,
- 56, 55, 55, 54, 54, 54, 53, 53,
- 53, 52, 52, 51, 51, 51, 50, 50,
- 50, 49, 49, 49, 48, 48, 47, 47,
- 47, 46, 46, 46, 45, 45, 45, 44,
- 44, 44, 43, 43, 43, 42, 42, 42,
- 42, 41, 41, 41, 40, 40, 40, 39,
- 39, 39, 39, 38, 38, 38, 37, 37,
- 37, 37, 36, 36, 36, 35, 35, 35,
- 35, 34, 34, 34, 34, 33, 33, 33,
- 33, 32, 32, 32, 32, 31, 31, 31,
- 31, 30, 30, 30, 30, 29, 29, 29,
- 29, 28, 28, 28, 28, 28, 27, 27,
- 27, 27, 26, 26, 26, 26, 26, 25,
- 25, 25, 25, 25, 24, 24, 24, 24,
- 24, 23, 23, 23, 23, 23, 23, 22,
- 22, 22, 22, 22, 21, 21, 21, 21,
- 21, 21, 20, 20, 20, 20, 20, 20,
- 19, 19, 19, 19, 19, 19, 19, 18,
- 18, 18, 18, 18, 18, 17, 17, 17,
- 17, 17, 17, 17, 16, 16, 16, 16,
- 16, 16, 16, 16, 15, 15, 15, 15,
- 15, 15, 15, 15, 14, 14, 14, 14,
- 14, 14, 14, 14, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 11,
- 11, 11, 11, 11, 11, 11, 11, 11,
- 11, 11, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 3,
- 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 0,
-};
diff --git a/target/ppc/mfrom_table_gen.c b/target/ppc/mfrom_table_gen.c
deleted file mode 100644
index f96c4268ba..0000000000
--- a/target/ppc/mfrom_table_gen.c
+++ /dev/null
@@ -1,34 +0,0 @@
-#define _GNU_SOURCE
-#include "qemu/osdep.h"
-#include <math.h>
-
-int main(void)
-{
- double d;
- uint8_t n;
- int i;
-
- printf("static const uint8_t mfrom_ROM_table[602] =\n{\n ");
- for (i = 0; i < 602; i++) {
- /*
- * Extremely decomposed:
- * -T0 / 256
- * T0 = 256 * log10(10 + 1.0) + 0.5
- */
- d = -i;
- d /= 256.0;
- d = exp10(d);
- d += 1.0;
- d = log10(d);
- d *= 256;
- d += 0.5;
- n = d;
- printf("%3d, ", n);
- if ((i & 7) == 7) {
- printf("\n ");
- }
- }
- printf("\n};\n");
-
- return 0;
-}
diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 91270c1f17..6512ee031c 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -1367,22 +1367,34 @@ static bool ppc_jumbo_xlate(PowerPCCPU *cpu, vaddr eaddr,
case -2:
/* Access rights violation */
cs->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x08000000;
+ if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+ (env->mmu_model == POWERPC_MMU_BOOKE206)) {
+ env->error_code = 0;
+ } else {
+ env->error_code = 0x08000000;
+ }
break;
case -3:
/* No execute protection violation */
if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
env->spr[SPR_BOOKE_ESR] = 0x00000000;
+ env->error_code = 0;
+ } else {
+ env->error_code = 0x10000000;
}
cs->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x10000000;
break;
case -4:
/* Direct store exception */
/* No code fetch is allowed in direct-store areas */
cs->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x10000000;
+ if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+ (env->mmu_model == POWERPC_MMU_BOOKE206)) {
+ env->error_code = 0;
+ } else {
+ env->error_code = 0x10000000;
+ }
break;
}
} else {
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index 59df6952ae..a2a52a12c3 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -664,6 +664,14 @@ static inline int booke_page_size_to_tlb(target_ulong page_size)
#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
+void helper_store_40x_pid(CPUPPCState *env, target_ulong val)
+{
+ if (env->spr[SPR_40x_PID] != val) {
+ env->spr[SPR_40x_PID] = val;
+ env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
+ }
+}
+
target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
{
ppcemb_tlb_t *tlb;
@@ -681,7 +689,7 @@ target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
size = PPC4XX_TLBHI_SIZE_DEFAULT;
}
ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
- env->spr[SPR_40x_PID] = tlb->PID;
+ helper_store_40x_pid(env, tlb->PID);
return ret;
}
@@ -794,6 +802,8 @@ void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
tlb->prot & PAGE_WRITE ? 'w' : '-',
tlb->prot & PAGE_EXEC ? 'x' : '-',
tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
+
+ env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
}
target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 9d2adc0cae..c2f436f8d3 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -894,7 +894,7 @@ void spr_write_40x_pid(DisasContext *ctx, int sprn, int gprn)
{
TCGv t0 = tcg_temp_new();
tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xFF);
- gen_store_spr(SPR_40x_PID, t0);
+ gen_helper_store_40x_pid(cpu_env, t0);
tcg_temp_free(t0);
}
@@ -6272,33 +6272,6 @@ static void gen_srq(DisasContext *ctx)
}
}
-/* PowerPC 602 specific instructions */
-
-/* dsa */
-static void gen_dsa(DisasContext *ctx)
-{
- /* XXX: TODO */
- gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
-}
-
-/* esa */
-static void gen_esa(DisasContext *ctx)
-{
- /* XXX: TODO */
- gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
-}
-
-/* mfrom */
-static void gen_mfrom(DisasContext *ctx)
-{
-#if defined(CONFIG_USER_ONLY)
- GEN_PRIV;
-#else
- CHK_SV;
- gen_helper_602_mfrom(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
-#endif /* defined(CONFIG_USER_ONLY) */
-}
-
/* 602 - 603 - G2 TLB management */
/* tlbld */
@@ -7779,9 +7752,6 @@ GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR),
GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR),
GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR),
GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC),
-GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC),
-GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC),
GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB),
GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB),
GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER),
diff --git a/target/sparc/machine.c b/target/sparc/machine.c
index 917375c3a1..44b9e7d75d 100644
--- a/target/sparc/machine.c
+++ b/target/sparc/machine.c
@@ -10,7 +10,6 @@ static const VMStateDescription vmstate_cpu_timer = {
.name = "cpu_timer",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(frequency, CPUTimer),
VMSTATE_UINT32(disabled, CPUTimer),
@@ -30,7 +29,6 @@ static const VMStateDescription vmstate_trap_state = {
.name = "trap_state",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT64(tpc, trap_state),
VMSTATE_UINT64(tnpc, trap_state),
@@ -44,7 +42,6 @@ static const VMStateDescription vmstate_tlb_entry = {
.name = "tlb_entry",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT64(tag, SparcTLBEntry),
VMSTATE_UINT64(tte, SparcTLBEntry),
@@ -113,7 +110,6 @@ const VMStateDescription vmstate_sparc_cpu = {
.name = "cpu",
.version_id = SPARC_VMSTATE_VER,
.minimum_version_id = SPARC_VMSTATE_VER,
- .minimum_version_id_old = SPARC_VMSTATE_VER,
.pre_save = cpu_pre_save,
.fields = (VMStateField[]) {
VMSTATE_UINTTL_ARRAY(env.gregs, SPARCCPU, 8),
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
index 875311f795..4dab09f265 100644
--- a/tcg/i386/tcg-target.c.inc
+++ b/tcg/i386/tcg-target.c.inc
@@ -3747,7 +3747,7 @@ static void tcg_target_init(TCGContext *s)
{
#ifdef CONFIG_CPUID_H
unsigned a, b, c, d, b7 = 0;
- int max = __get_cpuid_max(0, 0);
+ unsigned max = __get_cpuid_max(0, 0);
if (max >= 7) {
/* BMI1 is available on AMD Piledriver and Intel Haswell CPUs. */
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 3aba622400..9157a57b1a 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -156,19 +156,9 @@ check:
ifeq ($(CONFIG_TOOLS)$(CONFIG_POSIX),yy)
check: check-block
-export PYTHON
-
-ifneq ($(filter check check-block check-build, $(MAKECMDGOALS)),)
-ninja-cmd-goals += \
- qemu-img$(EXESUF) \
- qemu-io$(EXESUF) \
- qemu-nbd$(EXESUF) \
- storage-daemon/qemu-storage-daemon$(EXESUF) \
- $(filter qemu-system-%, $(ninja-targets))
-endif
-
-check-block: $(SRC_PATH)/tests/check-block.sh run-ninja
- @$<
+check-block: run-ninja
+ $(if $(MAKE.n),,+)$(MESON) test $(MTESTARGS) $(.mtestargs) --verbose \
+ --logbase iotestslog $(call .speed.$(SPEED), block block-slow block-thorough)
endif
check-build: run-ninja
diff --git a/tests/check-block.sh b/tests/check-block.sh
index f86cb863de..720a46bc36 100755
--- a/tests/check-block.sh
+++ b/tests/check-block.sh
@@ -1,24 +1,25 @@
#!/bin/sh
-# Honor the SPEED environment variable, just like we do it for the qtests.
-if [ "$SPEED" = "slow" ]; then
- format_list="raw qcow2"
- group=
-elif [ "$SPEED" = "thorough" ]; then
- format_list="raw qcow2 qed vmdk vpc"
+if [ "$#" -eq 0 ]; then
+ echo "Usage: $0 fmt..." >&2
+ exit 99
+fi
+
+# Honor the SPEED environment variable, just like we do it for "meson test"
+format_list="$@"
+if [ "$SPEED" = "slow" ] || [ "$SPEED" = "thorough" ]; then
group=
else
- format_list=qcow2
group="-g auto"
fi
-if [ "$#" -ne 0 ]; then
- format_list="$@"
-fi
+skip() {
+ echo "1..0 #SKIP $*"
+ exit 0
+}
if grep -q "CONFIG_GPROF=y" config-host.mak 2>/dev/null ; then
- echo "GPROF is enabled ==> Not running the qemu-iotests."
- exit 0
+ skip "GPROF is enabled ==> Not running the qemu-iotests."
fi
# Disable tests with any sanitizer except for specific ones
@@ -36,36 +37,30 @@ for j in ${ALLOWED_SANITIZE_FLAGS}; do
done
if echo ${SANITIZE_FLAGS} | grep -q "\-fsanitize" 2>/dev/null; then
# Have a sanitize flag that is not allowed, stop
- echo "Sanitizers are enabled ==> Not running the qemu-iotests."
- exit 0
+ skip "Sanitizers are enabled ==> Not running the qemu-iotests."
fi
if [ -z "$(find . -name 'qemu-system-*' -print)" ]; then
- echo "No qemu-system binary available ==> Not running the qemu-iotests."
- exit 0
+ skip "No qemu-system binary available ==> Not running the qemu-iotests."
fi
if ! command -v bash >/dev/null 2>&1 ; then
- echo "bash not available ==> Not running the qemu-iotests."
- exit 0
+ skip "bash not available ==> Not running the qemu-iotests."
fi
if LANG=C bash --version | grep -q 'GNU bash, version [123]' ; then
- echo "bash version too old ==> Not running the qemu-iotests."
- exit 0
+ skip "bash version too old ==> Not running the qemu-iotests."
fi
if ! (sed --version | grep 'GNU sed') > /dev/null 2>&1 ; then
if ! command -v gsed >/dev/null 2>&1; then
- echo "GNU sed not available ==> Not running the qemu-iotests."
- exit 0
+ skip "GNU sed not available ==> Not running the qemu-iotests."
fi
else
# Double-check that we're not using BusyBox' sed which says
# that "This is not GNU sed version 4.0" ...
if sed --version | grep -q 'not GNU sed' ; then
- echo "BusyBox sed not supported ==> Not running the qemu-iotests."
- exit 0
+ skip "BusyBox sed not supported ==> Not running the qemu-iotests."
fi
fi
@@ -74,10 +69,17 @@ cd tests/qemu-iotests
# QEMU_CHECK_BLOCK_AUTO is used to disable some unstable sub-tests
export QEMU_CHECK_BLOCK_AUTO=1
export PYTHONUTF8=1
+# If make was called with -jN we want to call ./check with -j N. Extract the
+# flag from MAKEFLAGS, so that if it absent (or MAKEFLAGS is not defined), JOBS
+# would be an empty line otherwise JOBS is prepared string of flag with value:
+# "-j N"
+# Note, that the following works even if make was called with "-j N" or even
+# "--jobs N", as all these variants becomes simply "-jN" in MAKEFLAGS variable.
+JOBS=$(echo "$MAKEFLAGS" | sed -n 's/\(^\|.* \)-j\([0-9]\+\)\( .*\|$\)/-j \2/p')
ret=0
for fmt in $format_list ; do
- ${PYTHON} ./check -makecheck -$fmt $group || ret=1
+ ${PYTHON} ./check $JOBS -tap -$fmt $group || ret=1
done
exit $ret
diff --git a/tests/data/acpi/microvm/ERST.pcie b/tests/data/acpi/microvm/ERST.pcie
new file mode 100644
index 0000000000..a6d0cb7838
--- /dev/null
+++ b/tests/data/acpi/microvm/ERST.pcie
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.acpierst b/tests/data/acpi/pc/DSDT.acpierst
new file mode 100644
index 0000000000..bb0593eeb8
--- /dev/null
+++ b/tests/data/acpi/pc/DSDT.acpierst
Binary files differ
diff --git a/tests/data/acpi/pc/ERST.acpierst b/tests/data/acpi/pc/ERST.acpierst
new file mode 100644
index 0000000000..7965ac2562
--- /dev/null
+++ b/tests/data/acpi/pc/ERST.acpierst
Binary files differ
diff --git a/tests/data/acpi/pc/SSDT.dimmpxm b/tests/data/acpi/pc/SSDT.dimmpxm
index a50a961fa1..ac55387d57 100644
--- a/tests/data/acpi/pc/SSDT.dimmpxm
+++ b/tests/data/acpi/pc/SSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.acpierst b/tests/data/acpi/q35/DSDT.acpierst
new file mode 100644
index 0000000000..cad26e3f0c
--- /dev/null
+++ b/tests/data/acpi/q35/DSDT.acpierst
Binary files differ
diff --git a/tests/data/acpi/q35/ERST.acpierst b/tests/data/acpi/q35/ERST.acpierst
new file mode 100644
index 0000000000..7965ac2562
--- /dev/null
+++ b/tests/data/acpi/q35/ERST.acpierst
Binary files differ
diff --git a/tests/data/acpi/q35/FACP.slic b/tests/data/acpi/q35/FACP.slic
index 891fd4b784..15986e095c 100644
--- a/tests/data/acpi/q35/FACP.slic
+++ b/tests/data/acpi/q35/FACP.slic
Binary files differ
diff --git a/tests/data/acpi/q35/SSDT.dimmpxm b/tests/data/acpi/q35/SSDT.dimmpxm
index 617a1c911c..98e6f0e3f3 100644
--- a/tests/data/acpi/q35/SSDT.dimmpxm
+++ b/tests/data/acpi/q35/SSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/virt/SSDT.memhp b/tests/data/acpi/virt/SSDT.memhp
index e8b850ae22..375d7b6fc8 100644
--- a/tests/data/acpi/virt/SSDT.memhp
+++ b/tests/data/acpi/virt/SSDT.memhp
Binary files differ
diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker
index aad39dd97f..d80e66c651 100644
--- a/tests/docker/dockerfiles/fedora-win32-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win32-cross.docker
@@ -29,6 +29,7 @@ ENV PACKAGES \
mingw32-pixman \
mingw32-pkg-config \
mingw32-SDL2 \
+ msitools \
perl \
perl-Test-Harness \
python3 \
diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker
index 9a224a619b..2b12b94ccf 100644
--- a/tests/docker/dockerfiles/fedora-win64-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win64-cross.docker
@@ -26,6 +26,7 @@ ENV PACKAGES \
mingw64-libusbx \
mingw64-pixman \
mingw64-pkg-config \
+ msitools \
perl \
perl-Test-Harness \
python3 \
diff --git a/tests/meson.build b/tests/meson.build
index 3f3882748a..079c8f3727 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -1,6 +1,7 @@
py3 = import('python').find_installation()
subdir('bench')
+subdir('qemu-iotests')
test_qapi_outputs = [
'qapi-builtin-types.c',
@@ -31,13 +32,21 @@ test_qapi_outputs = [
'test-qapi-visit.h',
]
+# Problem: to generate trace events, we'd have to add the .trace-events
+# file to qapi_trace_events like we do in qapi/meson.build. Since
+# qapi_trace_events is used by trace/meson.build, we'd have to move
+# subdir('tests') above subdir('trace') in the top-level meson.build.
+# Can't, because it would break the dependency of qga on qemuutil (which
+# depends on trace_ss). Not worth solving now; simply suppress trace
+# event generation instead.
test_qapi_files = custom_target('Test QAPI files',
output: test_qapi_outputs,
input: files('qapi-schema/qapi-schema-test.json',
'qapi-schema/include/sub-module.json',
'qapi-schema/sub-sub-module.json'),
command: [ qapi_gen, '-o', meson.current_build_dir(),
- '-b', '-p', 'test-', '@INPUT0@' ],
+ '-b', '-p', 'test-', '@INPUT0@',
+ '--suppress-tracing' ],
depend_files: qapi_gen_depends)
# meson doesn't like generated output in other directories
diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
index 58b57a0ef2..ee587b1606 100755
--- a/tests/qemu-iotests/031
+++ b/tests/qemu-iotests/031
@@ -42,8 +42,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file fuse
# We want to test compat=0.10, which does not support external data
-# files or refcount widths other than 16
-_unsupported_imgopts data_file 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
+# files or refcount widths other than 16 or compression type
+_unsupported_imgopts data_file compression_type \
+ 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
CLUSTER_SIZE=65536
@@ -58,21 +59,21 @@ for compat in "compat=0.10" "compat=1.1"; do
echo
_make_test_img -o $compat 64M
$PYTHON qcow2.py "$TEST_IMG" add-header-ext 0x12345678 "This is a test header extension"
- $PYTHON qcow2.py "$TEST_IMG" dump-header
+ _qcow2_dump_header
_check_test_img
echo
echo === Rewrite header with no backing file ===
echo
$QEMU_IMG rebase -u -b "" "$TEST_IMG"
- $PYTHON qcow2.py "$TEST_IMG" dump-header
+ _qcow2_dump_header
_check_test_img
echo
echo === Add a backing file and format ===
echo
$QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device "$TEST_IMG"
- $PYTHON qcow2.py "$TEST_IMG" dump-header
+ _qcow2_dump_header
done
# success, all done
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
index 5e567012a8..f703605e44 100755
--- a/tests/qemu-iotests/036
+++ b/tests/qemu-iotests/036
@@ -58,7 +58,7 @@ $PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63
# Without feature table
$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
+_qcow2_dump_header | grep features
$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
_img_info
@@ -107,7 +107,7 @@ echo === Create image with unknown autoclear feature bit ===
echo
_make_test_img 64M
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 63
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
+_qcow2_dump_header | grep features
$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
echo
@@ -115,7 +115,7 @@ echo === Repair image ===
echo
_check_test_img -r all
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
+_qcow2_dump_header | grep features
$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
# success, all done
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
index 12b2c7fa7b..00d379cde2 100755
--- a/tests/qemu-iotests/039
+++ b/tests/qemu-iotests/039
@@ -59,7 +59,7 @@ _make_test_img -o "compat=1.1,lazy_refcounts=on" $size
$QEMU_IO -c "write -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
# The dirty bit must not be set
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
_check_test_img
echo
@@ -73,7 +73,7 @@ $QEMU_IO -c "write -P 0x5a 0 512" \
| _filter_qemu_io
# The dirty bit must be set
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
_check_test_img
echo
@@ -82,7 +82,7 @@ echo "== Read-only access must still work =="
$QEMU_IO -r -c "read -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
# The dirty bit must be set
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
echo
echo "== Repairing the image file must succeed =="
@@ -90,7 +90,7 @@ echo "== Repairing the image file must succeed =="
_check_test_img -r all
# The dirty bit must not be set
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
echo
echo "== Data should still be accessible after repair =="
@@ -108,12 +108,12 @@ $QEMU_IO -c "write -P 0x5a 0 512" \
| _filter_qemu_io
# The dirty bit must be set
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
$QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io
# The dirty bit must not be set
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
echo
echo "== Creating an image file with lazy_refcounts=off =="
@@ -126,7 +126,7 @@ $QEMU_IO -c "write -P 0x5a 0 512" \
| _filter_qemu_io
# The dirty bit must not be set since lazy_refcounts=off
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
_check_test_img
echo
@@ -141,8 +141,8 @@ $QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG commit "$TEST_IMG"
# The dirty bit must not be set
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
-$PYTHON qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
+_qcow2_dump_header "$TEST_IMG".base | grep incompatible_features
_check_test_img
TEST_IMG="$TEST_IMG".base _check_test_img
@@ -159,7 +159,7 @@ $QEMU_IO -c "reopen -o lazy-refcounts=on" \
| _filter_qemu_io
# The dirty bit must be set
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
_check_test_img
_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
@@ -171,7 +171,7 @@ $QEMU_IO -c "reopen -o lazy-refcounts=off" \
| _filter_qemu_io
# The dirty bit must not be set
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
_check_test_img
diff --git a/tests/qemu-iotests/044 b/tests/qemu-iotests/044
index 64b18eb7c8..a5ee9a7ded 100755
--- a/tests/qemu-iotests/044
+++ b/tests/qemu-iotests/044
@@ -24,7 +24,7 @@ import os
import qcow2
from qcow2 import QcowHeader
import iotests
-from iotests import qemu_img, qemu_img_verbose, qemu_io
+from iotests import qemu_img, qemu_img_log, qemu_io
import struct
import subprocess
import sys
@@ -112,9 +112,11 @@ class TestRefcountTableGrowth(iotests.QMPTestCase):
def test_grow_refcount_table(self):
qemu_io('-c', 'write 3800M 1M', test_img)
- qemu_img_verbose('check' , test_img)
+ qemu_img_log('check' , test_img)
pass
if __name__ == '__main__':
+ iotests.activate_logging()
iotests.main(supported_fmts=['qcow2'],
- supported_protocols=['file'])
+ supported_protocols=['file'],
+ unsupported_imgopts=['refcount_bits'])
diff --git a/tests/qemu-iotests/044.out b/tests/qemu-iotests/044.out
index 703cf3dee1..ff663b17d7 100644
--- a/tests/qemu-iotests/044.out
+++ b/tests/qemu-iotests/044.out
@@ -1,6 +1,7 @@
No errors were found on the image.
7292415/33554432 = 21.73% allocated, 0.00% fragmented, 0.00% compressed clusters
Image end offset: 4296217088
+
.
----------------------------------------------------------------------
Ran 1 tests
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 1d2fa93a11..f1a506518b 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -41,10 +41,15 @@ _supported_fmt qcow2
_supported_proto file
# A compat=0.10 image is created in this test which does not support anything
# other than refcount_bits=16;
-# it also will not support an external data file
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
+# it also will not support an external data file and compression type
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file \
+ compression_type
_require_drivers nbd
+if [ "$QEMU_DEFAULT_MACHINE" = "pc" ]; then
+ _require_devices lsi53c895a
+fi
+
do_run_qemu()
{
echo Testing: "$@"
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
index db26c6b246..df87d600f7 100755
--- a/tests/qemu-iotests/060
+++ b/tests/qemu-iotests/060
@@ -80,13 +80,13 @@ poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x03\x00\x00"
_check_test_img
# The corrupt bit should not be set anyway
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
# Try to write something, thereby forcing the corrupt bit to be set
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
# The corrupt bit must now be set
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
# This information should be available through qemu-img info
_img_info --format-specific
@@ -114,19 +114,19 @@ poke_file "$TEST_IMG" "$(($rb_offset+8))" "\x00\x01"
# Redirect new data cluster onto refcount block
poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x02\x00\x00"
_check_test_img
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
# Try to fix it
_check_test_img -r all
# The corrupt bit should be cleared
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
# Look if it's really really fixed
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
echo
echo "=== Testing cluster data reference into inactive L2 table ==="
@@ -139,13 +139,13 @@ $QEMU_IO -c "$OPEN_RW" -c "write -P 2 0 512" | _filter_qemu_io
poke_file "$TEST_IMG" "$l2_offset_after_snapshot" \
"\x80\x00\x00\x00\x00\x04\x00\x00"
_check_test_img
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
$QEMU_IO -c "$OPEN_RW" -c "write -P 3 0 512" | _filter_qemu_io
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
_check_test_img -r all
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
$QEMU_IO -c "$OPEN_RW" -c "write -P 4 0 512" | _filter_qemu_io
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header | grep incompatible_features
# Check data
$QEMU_IO -c "$OPEN_RO" -c "read -P 4 0 512" | _filter_qemu_io
@@ -326,7 +326,7 @@ _make_test_img 64M
# Let the refblock appear unaligned
poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\xff\xff\x2a\x00"
# Mark the image dirty, thus forcing an automatic check when opening it
-poke_file "$TEST_IMG" 72 "\x00\x00\x00\x00\x00\x00\x00\x01"
+$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 0
# Open the image (qemu should refuse to do so)
$QEMU_IO -c close "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
index b74540bafb..329977d9b9 100644
--- a/tests/qemu-iotests/060.out
+++ b/tests/qemu-iotests/060.out
@@ -17,7 +17,7 @@ virtual size: 64 MiB (67108864 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
corrupt: true
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
index 9507c223bd..513fbec14c 100755
--- a/tests/qemu-iotests/061
+++ b/tests/qemu-iotests/061
@@ -48,16 +48,20 @@ _supported_os Linux
# not work with it;
# we have explicit tests for various cluster sizes, the remaining tests
# require the default 64k cluster
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file cluster_size
+# we don't have explicit tests for zstd qcow2 compression type, as zstd may be
+# not compiled in. And we can't create compat images with comression type
+# extension
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file \
+ cluster_size compression_type
echo
echo "=== Testing version downgrade with zero expansion ==="
echo
_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+_qcow2_dump_header
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+_qcow2_dump_header
$QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
_check_test_img
@@ -68,10 +72,10 @@ _make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "write -z 32M 128k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c map "$TEST_IMG" | _filter_qemu_io
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+_qcow2_dump_header
$QEMU_IMG amend -o "compat=0.10" --image-opts \
driver=qcow2,file.filename=$TEST_IMG,l2-cache-entry-size=4096
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+_qcow2_dump_header
$QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "read -P 0 32M 128k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c map "$TEST_IMG" | _filter_qemu_io
@@ -84,9 +88,9 @@ _make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
_NO_VALGRIND \
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+_qcow2_dump_header
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+_qcow2_dump_header
$QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
_check_test_img
@@ -96,9 +100,9 @@ echo
_make_test_img -o "compat=1.1" 64M
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit compatible 42
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 42
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+_qcow2_dump_header
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+_qcow2_dump_header
_check_test_img
echo
@@ -106,9 +110,9 @@ echo "=== Testing version upgrade and resize ==="
echo
_make_test_img -o "compat=0.10" 64M
$QEMU_IO -c "write -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+_qcow2_dump_header
$QEMU_IMG amend -o "compat=1.1,lazy_refcounts=on,size=128M" "$TEST_IMG"
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+_qcow2_dump_header
$QEMU_IO -c "read -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io
_check_test_img
@@ -120,29 +124,29 @@ $QEMU_IO -c "write -P 0x2a 24M 64k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG snapshot -c foo "$TEST_IMG"
$QEMU_IMG resize "$TEST_IMG" 64M &&
echo "unexpected pass"
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)'
+_qcow2_dump_header | grep '^\(version\|size\|nb_snap\)'
$QEMU_IMG amend -o "compat=1.1,size=128M" "$TEST_IMG" ||
echo "unexpected fail"
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)'
+_qcow2_dump_header | grep '^\(version\|size\|nb_snap\)'
$QEMU_IMG snapshot -c bar "$TEST_IMG"
$QEMU_IMG resize --shrink "$TEST_IMG" 64M ||
echo "unexpected fail"
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)'
+_qcow2_dump_header | grep '^\(version\|size\|nb_snap\)'
$QEMU_IMG amend -o "compat=0.10,size=32M" "$TEST_IMG" &&
echo "unexpected pass"
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)'
+_qcow2_dump_header | grep '^\(version\|size\|nb_snap\)'
$QEMU_IMG snapshot -a bar "$TEST_IMG" ||
echo "unexpected fail"
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)'
+_qcow2_dump_header | grep '^\(version\|size\|nb_snap\)'
$QEMU_IMG snapshot -d bar "$TEST_IMG"
$QEMU_IMG amend -o "compat=0.10,size=32M" "$TEST_IMG" ||
echo "unexpected fail"
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)'
+_qcow2_dump_header | grep '^\(version\|size\|nb_snap\)'
_check_test_img
@@ -154,9 +158,9 @@ _make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
_NO_VALGRIND \
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+_qcow2_dump_header
$QEMU_IMG amend -o "lazy_refcounts=off" "$TEST_IMG"
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+_qcow2_dump_header
$QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
_check_test_img
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
index 7ecbd4dea8..139fc68177 100644
--- a/tests/qemu-iotests/061.out
+++ b/tests/qemu-iotests/061.out
@@ -525,7 +525,7 @@ virtual size: 64 MiB (67108864 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
data file: TEST_DIR/t.IMGFMT.data
@@ -552,7 +552,7 @@ virtual size: 64 MiB (67108864 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
data file: foo
@@ -567,7 +567,7 @@ virtual size: 64 MiB (67108864 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
data file raw: false
@@ -583,7 +583,7 @@ virtual size: 64 MiB (67108864 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
data file: TEST_DIR/t.IMGFMT.data
@@ -597,7 +597,7 @@ virtual size: 64 MiB (67108864 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
data file: TEST_DIR/t.IMGFMT.data
@@ -612,7 +612,7 @@ virtual size: 64 MiB (67108864 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
data file: TEST_DIR/t.IMGFMT.data
diff --git a/tests/qemu-iotests/065 b/tests/qemu-iotests/065
index 3c2ca27627..f7c1b68dad 100755
--- a/tests/qemu-iotests/065
+++ b/tests/qemu-iotests/065
@@ -88,7 +88,7 @@ class TestQMP(TestImageInfoSpecific):
class TestQCow2(TestQemuImgInfo):
'''Testing a qcow2 version 2 image'''
- img_options = 'compat=0.10'
+ img_options = 'compat=0.10,compression_type=zlib'
json_compare = { 'compat': '0.10', 'refcount-bits': 16,
'compression-type': 'zlib' }
human_compare = [ 'compat: 0.10', 'compression type: zlib',
@@ -96,17 +96,17 @@ class TestQCow2(TestQemuImgInfo):
class TestQCow3NotLazy(TestQemuImgInfo):
'''Testing a qcow2 version 3 image with lazy refcounts disabled'''
- img_options = 'compat=1.1,lazy_refcounts=off'
+ img_options = 'compat=1.1,lazy_refcounts=off,compression_type=zstd'
json_compare = { 'compat': '1.1', 'lazy-refcounts': False,
'refcount-bits': 16, 'corrupt': False,
- 'compression-type': 'zlib', 'extended-l2': False }
- human_compare = [ 'compat: 1.1', 'compression type: zlib',
+ 'compression-type': 'zstd', 'extended-l2': False }
+ human_compare = [ 'compat: 1.1', 'compression type: zstd',
'lazy refcounts: false', 'refcount bits: 16',
'corrupt: false', 'extended l2: false' ]
class TestQCow3Lazy(TestQemuImgInfo):
'''Testing a qcow2 version 3 image with lazy refcounts enabled'''
- img_options = 'compat=1.1,lazy_refcounts=on'
+ img_options = 'compat=1.1,lazy_refcounts=on,compression_type=zlib'
json_compare = { 'compat': '1.1', 'lazy-refcounts': True,
'refcount-bits': 16, 'corrupt': False,
'compression-type': 'zlib', 'extended-l2': False }
@@ -117,7 +117,7 @@ class TestQCow3Lazy(TestQemuImgInfo):
class TestQCow3NotLazyQMP(TestQMP):
'''Testing a qcow2 version 3 image with lazy refcounts disabled, opening
with lazy refcounts enabled'''
- img_options = 'compat=1.1,lazy_refcounts=off'
+ img_options = 'compat=1.1,lazy_refcounts=off,compression_type=zlib'
qemu_options = 'lazy-refcounts=on'
compare = { 'compat': '1.1', 'lazy-refcounts': False,
'refcount-bits': 16, 'corrupt': False,
@@ -127,11 +127,11 @@ class TestQCow3NotLazyQMP(TestQMP):
class TestQCow3LazyQMP(TestQMP):
'''Testing a qcow2 version 3 image with lazy refcounts enabled, opening
with lazy refcounts disabled'''
- img_options = 'compat=1.1,lazy_refcounts=on'
+ img_options = 'compat=1.1,lazy_refcounts=on,compression_type=zstd'
qemu_options = 'lazy-refcounts=off'
compare = { 'compat': '1.1', 'lazy-refcounts': True,
'refcount-bits': 16, 'corrupt': False,
- 'compression-type': 'zlib', 'extended-l2': False }
+ 'compression-type': 'zstd', 'extended-l2': False }
TestImageInfoSpecific = None
TestQemuImgInfo = None
@@ -139,4 +139,5 @@ TestQMP = None
if __name__ == '__main__':
iotests.main(supported_fmts=['qcow2'],
- supported_protocols=['file'])
+ supported_protocols=['file'],
+ unsupported_imgopts=['refcount_bits'])
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
index 077ed0f2c7..d0dd333117 100644
--- a/tests/qemu-iotests/082.out
+++ b/tests/qemu-iotests/082.out
@@ -17,7 +17,7 @@ virtual size: 128 MiB (134217728 bytes)
cluster_size: 4096
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: true
refcount bits: 16
corrupt: false
@@ -31,7 +31,7 @@ virtual size: 128 MiB (134217728 bytes)
cluster_size: 8192
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: true
refcount bits: 16
corrupt: false
@@ -329,7 +329,7 @@ virtual size: 128 MiB (134217728 bytes)
cluster_size: 4096
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: true
refcount bits: 16
corrupt: false
@@ -342,7 +342,7 @@ virtual size: 128 MiB (134217728 bytes)
cluster_size: 8192
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: true
refcount bits: 16
corrupt: false
@@ -639,7 +639,7 @@ virtual size: 128 MiB (134217728 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: true
refcount bits: 16
corrupt: false
@@ -652,7 +652,7 @@ virtual size: 130 MiB (136314880 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
corrupt: false
@@ -665,7 +665,7 @@ virtual size: 132 MiB (138412032 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: true
refcount bits: 16
corrupt: false
diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
index 07ac74fb2c..5333212993 100755
--- a/tests/qemu-iotests/112
+++ b/tests/qemu-iotests/112
@@ -43,7 +43,8 @@ _supported_proto file fuse
# This test will set refcount_bits on its own which would conflict with the
# manual setting; compat will be overridden as well;
# and external data files do not work well with our refcount testing
-_unsupported_imgopts refcount_bits 'compat=0.10' data_file
+# also, compression type is not supported with compat=0.10 used in test
+_unsupported_imgopts refcount_bits 'compat=0.10' data_file compression_type
print_refcount_bits()
{
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
index 4680d5df3d..52ee135184 100755
--- a/tests/qemu-iotests/137
+++ b/tests/qemu-iotests/137
@@ -140,7 +140,7 @@ $QEMU_IO \
# The dirty bit must not be set
# (Filter the external data file bit)
-if $PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features \
+if _qcow2_dump_header | grep incompatible_features \
| grep -q '\<0\>'
then
echo 'ERROR: Dirty bit set'
diff --git a/tests/qemu-iotests/149.out b/tests/qemu-iotests/149.out
index 6877ab6c4a..ab879596ce 100644
--- a/tests/qemu-iotests/149.out
+++ b/tests/qemu-iotests/149.out
@@ -61,7 +61,6 @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha1.img
# ================= qemu-img aes-256-xts-plain64-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1
@@ -181,7 +180,6 @@ unlink TEST_DIR/luks-twofish-256-xts-plain64-sha1.img
# ================= qemu-img twofish-256-xts-plain64-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=twofish-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-twofish-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1
@@ -301,7 +299,6 @@ unlink TEST_DIR/luks-serpent-256-xts-plain64-sha1.img
# ================= qemu-img serpent-256-xts-plain64-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-serpent-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1
@@ -421,7 +418,6 @@ unlink TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img
# ================= qemu-img cast5-128-cbc-plain64-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=cast5-128,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=cast5-128 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1
@@ -542,7 +538,6 @@ unlink TEST_DIR/luks-aes-256-cbc-plain-sha1.img
# ================= qemu-img aes-256-cbc-plain-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-cbc-plain-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1
@@ -662,7 +657,6 @@ unlink TEST_DIR/luks-aes-256-cbc-plain64-sha1.img
# ================= qemu-img aes-256-cbc-plain64-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1
@@ -782,7 +776,6 @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img
# ================= qemu-img aes-256-cbc-essiv-sha256-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1
@@ -902,7 +895,6 @@ unlink TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img
# ================= qemu-img aes-256-xts-essiv-sha256-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1
@@ -1022,7 +1014,6 @@ unlink TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img
# ================= qemu-img aes-128-xts-plain64-sha256-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1
@@ -1142,7 +1133,6 @@ unlink TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img
# ================= qemu-img aes-192-xts-plain64-sha256-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1
@@ -1262,7 +1252,6 @@ unlink TEST_DIR/luks-twofish-128-xts-plain64-sha1.img
# ================= qemu-img twofish-128-xts-plain64-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=twofish-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-twofish-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1
@@ -1383,7 +1372,6 @@ unlink TEST_DIR/luks-serpent-128-xts-plain64-sha1.img
# ================= qemu-img serpent-128-xts-plain64-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-serpent-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1
@@ -1503,7 +1491,6 @@ unlink TEST_DIR/luks-serpent-192-xts-plain64-sha1.img
# ================= qemu-img serpent-192-xts-plain64-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-serpent-192-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1
@@ -1625,7 +1612,6 @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha224.img
# ================= qemu-img aes-256-xts-plain64-sha224 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha224 TEST_DIR/luks-aes-256-xts-plain64-sha224.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha224.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha224 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224
@@ -1745,7 +1731,6 @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha256.img
# ================= qemu-img aes-256-xts-plain64-sha256 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha256 TEST_DIR/luks-aes-256-xts-plain64-sha256.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha256.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha256 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256
@@ -1865,7 +1850,6 @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha384.img
# ================= qemu-img aes-256-xts-plain64-sha384 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha384 TEST_DIR/luks-aes-256-xts-plain64-sha384.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha384.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha384 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384
@@ -1985,7 +1969,6 @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha512.img
# ================= qemu-img aes-256-xts-plain64-sha512 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha512 TEST_DIR/luks-aes-256-xts-plain64-sha512.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha512.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha512 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512
@@ -2105,7 +2088,6 @@ unlink TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img
# ================= qemu-img aes-256-xts-plain64-ripemd160 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=ripemd160 TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=ripemd160 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160
@@ -2299,7 +2281,6 @@ unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img
# ================= qemu-img aes-256-xts-plain-sha1-pwallslots =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=c2xvdDE=,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots
@@ -2419,7 +2400,6 @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img
# ================= qemu-img aes-256-cbc-essiv-auto-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1
@@ -2539,7 +2519,6 @@ unlink TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img
# ================= qemu-img aes-256-cbc-plain64-sha256-sha1 =================
# Create image
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1
diff --git a/tests/qemu-iotests/163 b/tests/qemu-iotests/163
index dedce8ef43..b8bfc95358 100755
--- a/tests/qemu-iotests/163
+++ b/tests/qemu-iotests/163
@@ -169,4 +169,5 @@ ShrinkBaseClass = None
if __name__ == '__main__':
iotests.main(supported_fmts=['raw', 'qcow2'],
- supported_protocols=['file'])
+ supported_protocols=['file'],
+ unsupported_imgopts=['compat'])
diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165
index ce499946b8..e3ef28e2ee 100755
--- a/tests/qemu-iotests/165
+++ b/tests/qemu-iotests/165
@@ -157,4 +157,5 @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase):
if __name__ == '__main__':
iotests.main(supported_fmts=['qcow2'],
- supported_protocols=['file'])
+ supported_protocols=['file'],
+ unsupported_imgopts=['compat'])
diff --git a/tests/qemu-iotests/196 b/tests/qemu-iotests/196
index 2451515094..76509a5ad1 100755
--- a/tests/qemu-iotests/196
+++ b/tests/qemu-iotests/196
@@ -65,4 +65,5 @@ class TestInvalidateAutoclear(iotests.QMPTestCase):
if __name__ == '__main__':
iotests.main(supported_fmts=['qcow2'],
- supported_protocols=['file'])
+ supported_protocols=['file'],
+ unsupported_imgopts=['compat'])
diff --git a/tests/qemu-iotests/198.out b/tests/qemu-iotests/198.out
index 3952708444..805494916f 100644
--- a/tests/qemu-iotests/198.out
+++ b/tests/qemu-iotests/198.out
@@ -36,7 +36,7 @@ image: json:{ /* filtered */ }
file format: IMGFMT
virtual size: 16 MiB (16777216 bytes)
Format specific information:
- compression type: zlib
+ compression type: COMPRESSION_TYPE
encrypt:
ivgen alg: plain64
hash alg: sha256
@@ -81,7 +81,7 @@ virtual size: 16 MiB (16777216 bytes)
backing file: TEST_DIR/t.IMGFMT.base
backing file format: IMGFMT
Format specific information:
- compression type: zlib
+ compression type: COMPRESSION_TYPE
encrypt:
ivgen alg: plain64
hash alg: sha256
diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out
index 80cd274223..7e95694777 100644
--- a/tests/qemu-iotests/206.out
+++ b/tests/qemu-iotests/206.out
@@ -18,7 +18,7 @@ virtual size: 128 MiB (134217728 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
corrupt: false
@@ -42,7 +42,7 @@ virtual size: 64 MiB (67108864 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
corrupt: false
@@ -66,7 +66,7 @@ virtual size: 32 MiB (33554432 bytes)
cluster_size: 2097152
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: true
refcount bits: 1
corrupt: false
@@ -92,7 +92,7 @@ backing file: TEST_IMG.base
backing file format: IMGFMT
Format specific information:
compat: 0.10
- compression type: zlib
+ compression type: COMPRESSION_TYPE
refcount bits: 16
=== Successful image creation (encrypted) ===
@@ -109,7 +109,7 @@ encrypted: yes
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
encrypt:
diff --git a/tests/qemu-iotests/209 b/tests/qemu-iotests/209
index ff7efea11b..f6ad08ec42 100755
--- a/tests/qemu-iotests/209
+++ b/tests/qemu-iotests/209
@@ -20,8 +20,8 @@
#
import iotests
-from iotests import qemu_img_create, qemu_io, qemu_img_verbose, qemu_nbd, \
- file_path
+from iotests import qemu_img_create, qemu_io, qemu_img_log, qemu_nbd, \
+ file_path, log
iotests.script_initialize(supported_fmts=['qcow2'])
@@ -33,4 +33,5 @@ qemu_img_create('-f', iotests.imgfmt, disk, '1M')
qemu_io('-f', iotests.imgfmt, '-c', 'write 0 512K', disk)
qemu_nbd('-k', nbd_sock, '-x', 'exp', '-f', iotests.imgfmt, disk)
-qemu_img_verbose('map', '-f', 'raw', '--output=json', nbd_uri)
+qemu_img_log('map', '-f', 'raw', '--output=json', nbd_uri)
+log('done.') # avoid new line at the end of output file
diff --git a/tests/qemu-iotests/209.out b/tests/qemu-iotests/209.out
index f27be3fa7b..515906ac7a 100644
--- a/tests/qemu-iotests/209.out
+++ b/tests/qemu-iotests/209.out
@@ -1,2 +1,4 @@
[{ "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}]
+
+done.
diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210
index a4dcc5fe59..10b0a0b87c 100755
--- a/tests/qemu-iotests/210
+++ b/tests/qemu-iotests/210
@@ -62,7 +62,7 @@ with iotests.FilePath('t.luks') as disk_path, \
'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
filter_path=disk_path,
extra_args=['--object', 'secret,id=keysec0,data=foo'],
- imgopts=True)
+ use_image_opts=True)
#
# Successful image creation (with non-default options)
@@ -96,7 +96,7 @@ with iotests.FilePath('t.luks') as disk_path, \
'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
filter_path=disk_path,
extra_args=['--object', 'secret,id=keysec0,data=foo'],
- imgopts=True)
+ use_image_opts=True)
#
# Invalid BlockdevRef
@@ -132,7 +132,7 @@ with iotests.FilePath('t.luks') as disk_path, \
'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
filter_path=disk_path,
extra_args=['--object', 'secret,id=keysec0,data=foo'],
- imgopts=True)
+ use_image_opts=True)
#
# Invalid sizes
@@ -176,4 +176,4 @@ with iotests.FilePath('t.luks') as disk_path, \
'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
filter_path=disk_path,
extra_args=['--object', 'secret,id=keysec0,data=foo'],
- imgopts=True)
+ use_image_opts=True)
diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214
index 0889089d81..c66e246ba2 100755
--- a/tests/qemu-iotests/214
+++ b/tests/qemu-iotests/214
@@ -51,7 +51,7 @@ echo
# The L2 entries of the two compressed clusters are located at
# 0x800000 and 0x800008, their original values are 0x4008000000a00000
# and 0x4008000000a00802 (5 sectors for compressed data each).
-_make_test_img 8M -o cluster_size=2M
+_make_test_img 8M -o cluster_size=2M,compression_type=zlib
$QEMU_IO -c "write -c -P 0x11 0 2M" -c "write -c -P 0x11 2M 2M" "$TEST_IMG" \
2>&1 | _filter_qemu_io | _filter_testdir
diff --git a/tests/qemu-iotests/237.out b/tests/qemu-iotests/237.out
index 2f09ff5512..aeb9724492 100644
--- a/tests/qemu-iotests/237.out
+++ b/tests/qemu-iotests/237.out
@@ -129,11 +129,8 @@ Job failed: Cannot find device='this doesn't exist' nor node-name='this doesn't
=== Other subformats ===
-Formatting 'TEST_DIR/PID-t.vmdk.1', fmt=vmdk size=0 compat6=off hwversion=undefined
-Formatting 'TEST_DIR/PID-t.vmdk.2', fmt=vmdk size=0 compat6=off hwversion=undefined
-Formatting 'TEST_DIR/PID-t.vmdk.3', fmt=vmdk size=0 compat6=off hwversion=undefined
== Missing extent ==
diff --git a/tests/qemu-iotests/242 b/tests/qemu-iotests/242
index a9b27668c2..96a30152b0 100755
--- a/tests/qemu-iotests/242
+++ b/tests/qemu-iotests/242
@@ -26,7 +26,8 @@ from iotests import qemu_img_create, qemu_io, qemu_img_pipe, \
file_path, img_info_log, log, filter_qemu_io
iotests.script_initialize(supported_fmts=['qcow2'],
- supported_protocols=['file'])
+ supported_protocols=['file'],
+ unsupported_imgopts=['refcount_bits', 'compat'])
disk = file_path('disk')
chunk = 256 * 1024
diff --git a/tests/qemu-iotests/242.out b/tests/qemu-iotests/242.out
index 3759c99284..ce231424a7 100644
--- a/tests/qemu-iotests/242.out
+++ b/tests/qemu-iotests/242.out
@@ -12,7 +12,7 @@ virtual size: 1 MiB (1048576 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
corrupt: false
@@ -34,7 +34,7 @@ virtual size: 1 MiB (1048576 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
bitmaps:
[0]:
@@ -68,7 +68,7 @@ virtual size: 1 MiB (1048576 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
bitmaps:
[0]:
@@ -110,7 +110,7 @@ virtual size: 1 MiB (1048576 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
bitmaps:
[0]:
@@ -161,7 +161,7 @@ virtual size: 1 MiB (1048576 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
bitmaps:
[0]:
diff --git a/tests/qemu-iotests/246 b/tests/qemu-iotests/246
index 5932a0e8a9..b009a78397 100755
--- a/tests/qemu-iotests/246
+++ b/tests/qemu-iotests/246
@@ -23,7 +23,8 @@
import iotests
from iotests import log
-iotests.script_initialize(supported_fmts=['qcow2'])
+iotests.script_initialize(supported_fmts=['qcow2'],
+ unsupported_imgopts=['compat'])
size = 64 * 1024 * 1024 * 1024
gran_small = 32 * 1024
gran_large = 128 * 1024
diff --git a/tests/qemu-iotests/254 b/tests/qemu-iotests/254
index 108bf5f894..7ea098818c 100755
--- a/tests/qemu-iotests/254
+++ b/tests/qemu-iotests/254
@@ -22,7 +22,8 @@
import iotests
from iotests import qemu_img_create, file_path, log
-iotests.script_initialize(supported_fmts=['qcow2'])
+iotests.script_initialize(supported_fmts=['qcow2'],
+ unsupported_imgopts=['compat'])
disk, top = file_path('disk', 'top')
size = 1024 * 1024
diff --git a/tests/qemu-iotests/255.out b/tests/qemu-iotests/255.out
index 33b7f22de3..11a05a5213 100644
--- a/tests/qemu-iotests/255.out
+++ b/tests/qemu-iotests/255.out
@@ -3,9 +3,7 @@ Finishing a commit job with background reads
=== Create backing chain and start VM ===
-Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
=== Start background read requests ===
@@ -23,9 +21,7 @@ Closing the VM while a job is being cancelled
=== Create images and start VM ===
-Formatting 'TEST_DIR/PID-src.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/PID-dst.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
wrote 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/260 b/tests/qemu-iotests/260
index 2ec64a9b99..c2133f9980 100755
--- a/tests/qemu-iotests/260
+++ b/tests/qemu-iotests/260
@@ -23,7 +23,8 @@ import iotests
from iotests import qemu_img_create, file_path, log, filter_qmp_event
iotests.script_initialize(
- supported_fmts=['qcow2']
+ supported_fmts=['qcow2'],
+ unsupported_imgopts=['compat']
)
base, top = file_path('base', 'top')
diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274
index caab008e07..080a90f10f 100755
--- a/tests/qemu-iotests/274
+++ b/tests/qemu-iotests/274
@@ -23,7 +23,8 @@
import iotests
iotests.script_initialize(supported_fmts=['qcow2'],
- supported_platforms=['linux'])
+ supported_platforms=['linux'],
+ unsupported_imgopts=['refcount_bits', 'compat'])
size_short = 1 * 1024 * 1024
size_long = 2 * 1024 * 1024
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
index 16a95a4850..1ce40d839a 100644
--- a/tests/qemu-iotests/274.out
+++ b/tests/qemu-iotests/274.out
@@ -1,9 +1,6 @@
== Commit tests ==
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
wrote 2097152/2097152 bytes at offset 0
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -53,7 +50,7 @@ backing file: TEST_DIR/PID-base
backing file format: IMGFMT
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
corrupt: false
@@ -66,11 +63,8 @@ read 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Testing HMP commit (top -> mid) ===
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
wrote 2097152/2097152 bytes at offset 0
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -85,7 +79,7 @@ backing file: TEST_DIR/PID-base
backing file format: IMGFMT
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
corrupt: false
@@ -98,11 +92,8 @@ read 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Testing QMP active commit (top -> mid) ===
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
wrote 2097152/2097152 bytes at offset 0
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -123,7 +114,7 @@ backing file: TEST_DIR/PID-base
backing file format: IMGFMT
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
corrupt: false
@@ -136,11 +127,8 @@ read 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Testing qemu-img commit (top -> base) ===
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
wrote 2097152/2097152 bytes at offset 0
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -153,7 +141,7 @@ virtual size: 2 MiB (2097152 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
corrupt: false
@@ -166,11 +154,8 @@ read 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Testing QMP active commit (top -> base) ===
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
wrote 2097152/2097152 bytes at offset 0
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -191,7 +176,7 @@ backing file: TEST_DIR/PID-base
backing file format: IMGFMT
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
corrupt: false
@@ -205,9 +190,7 @@ read 1048576/1048576 bytes at offset 1048576
== Resize tests ==
=== preallocation=off ===
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=6442450944 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1073741824 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 5368709120
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -224,9 +207,7 @@ read 65536/65536 bytes at offset 5368709120
{ "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
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=32212254720 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 33285996544
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -248,9 +229,7 @@ read 65536/65536 bytes at offset 33285996544
{ "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
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=5242880 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 9437184
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -267,9 +246,7 @@ read 65536/65536 bytes at offset 9437184
{ "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
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=8388608 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 11534336
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -286,9 +263,7 @@ read 65536/65536 bytes at offset 11534336
{ "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
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=259072 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 259072
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -306,9 +281,7 @@ read 65536/65536 bytes at offset 259072
{ "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
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 344064
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -325,9 +298,7 @@ read 65536/65536 bytes at offset 344064
{ "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
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 446464
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/280.out b/tests/qemu-iotests/280.out
index 09a0f1a7cb..e39164c579 100644
--- a/tests/qemu-iotests/280.out
+++ b/tests/qemu-iotests/280.out
@@ -1,4 +1,3 @@
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
=== Launch VM ===
Enabling migration QMP events on VM...
diff --git a/tests/qemu-iotests/281 b/tests/qemu-iotests/281
index 956698083f..318e333939 100755
--- a/tests/qemu-iotests/281
+++ b/tests/qemu-iotests/281
@@ -245,4 +245,5 @@ class TestBlockdevBackupAbort(iotests.QMPTestCase):
if __name__ == '__main__':
iotests.main(supported_fmts=['qcow2'],
- supported_protocols=['file'])
+ supported_protocols=['file'],
+ unsupported_imgopts=['compat'])
diff --git a/tests/qemu-iotests/287 b/tests/qemu-iotests/287
index 2d5334e8bf..6414640b21 100755
--- a/tests/qemu-iotests/287
+++ b/tests/qemu-iotests/287
@@ -61,13 +61,13 @@ echo
echo "=== Testing compression type incompatible bit setting for zlib ==="
echo
_make_test_img -o compression_type=zlib 64M
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header --no-filter-compression | grep incompatible_features
echo
echo "=== Testing compression type incompatible bit setting for zstd ==="
echo
_make_test_img -o compression_type=zstd 64M
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header --no-filter-compression | grep incompatible_features
echo
echo "=== Testing zlib with incompatible bit set ==="
@@ -75,7 +75,7 @@ echo
_make_test_img -o compression_type=zlib 64M
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 3
# to make sure the bit was actually set
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header --no-filter-compression | grep incompatible_features
if $QEMU_IMG info "$TEST_IMG" >/dev/null 2>&1 ; then
echo "Error: The image opened successfully. The image must not be opened."
@@ -87,7 +87,7 @@ echo
_make_test_img -o compression_type=zstd 64M
$PYTHON qcow2.py "$TEST_IMG" set-header incompatible_features 0
# to make sure the bit was actually unset
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_qcow2_dump_header --no-filter-compression | grep incompatible_features
if $QEMU_IMG info "$TEST_IMG" >/dev/null 2>&1 ; then
echo "Error: The image opened successfully. The image must not be opened."
diff --git a/tests/qemu-iotests/290 b/tests/qemu-iotests/290
index ed80da2685..776b59de1b 100755
--- a/tests/qemu-iotests/290
+++ b/tests/qemu-iotests/290
@@ -41,7 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file fuse
_supported_os Linux
-_unsupported_imgopts 'compat=0.10' refcount_bits data_file
+_unsupported_imgopts 'compat=0.10' refcount_bits data_file compression_type
echo
echo "### Test 'qemu-io -c discard' on a QCOW2 image without a backing file"
diff --git a/tests/qemu-iotests/296.out b/tests/qemu-iotests/296.out
index 6c69735604..42205cc981 100644
--- a/tests/qemu-iotests/296.out
+++ b/tests/qemu-iotests/296.out
@@ -1,4 +1,3 @@
-Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@@ -13,8 +12,7 @@ Job failed: Failed to get shared "consistent read" lock
qemu-img: Failed to get shared "consistent read" lock
Is another process using the image [TEST_DIR/test.img]?
-.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
-
+.
Job failed: Block node is read-only
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@@ -26,12 +24,10 @@ Job failed: Failed to get shared "consistent read" lock
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
-.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
-
+.
{"return": {}}
{"error": {"class": "GenericError", "desc": "Failed to get \"write\" lock"}}
-.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
-
+.
{"return": {}}
{"return": {}}
.
diff --git a/tests/qemu-iotests/302 b/tests/qemu-iotests/302
index 5695af4914..a6d79e727b 100755
--- a/tests/qemu-iotests/302
+++ b/tests/qemu-iotests/302
@@ -34,6 +34,7 @@ from iotests import (
qemu_img_measure,
qemu_io,
qemu_nbd_popen,
+ img_info_log,
)
iotests.script_initialize(supported_fmts=["qcow2"])
@@ -88,6 +89,7 @@ with tarfile.open(tar_file, "w") as tar:
tar_file):
iotests.log("=== Target image info ===")
+ # Not img_info_log as it enforces imgfmt, but now we print info on raw
qemu_img_log("info", nbd_uri)
qemu_img(
@@ -99,7 +101,7 @@ with tarfile.open(tar_file, "w") as tar:
nbd_uri)
iotests.log("=== Converted image info ===")
- qemu_img_log("info", nbd_uri)
+ img_info_log(nbd_uri)
iotests.log("=== Converted image check ===")
qemu_img_log("check", nbd_uri)
diff --git a/tests/qemu-iotests/302.out b/tests/qemu-iotests/302.out
index e2f6077e83..3e7c281b91 100644
--- a/tests/qemu-iotests/302.out
+++ b/tests/qemu-iotests/302.out
@@ -6,14 +6,13 @@ virtual size: 448 KiB (458752 bytes)
disk size: unavailable
=== Converted image info ===
-image: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock
-file format: qcow2
+image: TEST_IMG
+file format: IMGFMT
virtual size: 1 GiB (1073741824 bytes)
-disk size: unavailable
cluster_size: 65536
Format specific information:
compat: 1.1
- compression type: zlib
+ compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
corrupt: false
diff --git a/tests/qemu-iotests/303 b/tests/qemu-iotests/303
index 425544c064..16c2e10827 100755
--- a/tests/qemu-iotests/303
+++ b/tests/qemu-iotests/303
@@ -23,7 +23,8 @@ import iotests
import subprocess
from iotests import qemu_img_create, qemu_io, file_path, log, filter_qemu_io
-iotests.script_initialize(supported_fmts=['qcow2'])
+iotests.script_initialize(supported_fmts=['qcow2'],
+ unsupported_imgopts=['refcount_bits', 'compat'])
disk = file_path('disk')
chunk = 1024 * 1024
@@ -53,12 +54,19 @@ def add_bitmap(num, begin, end, disabled):
log('')
-qemu_img_create('-f', iotests.imgfmt, disk, '10M')
+def test(compression_type: str, json_output: bool) -> None:
+ qemu_img_create('-f', iotests.imgfmt,
+ '-o', f'compression_type={compression_type}',
+ disk, '10M')
+ add_bitmap(1, 0, 6, False)
+ add_bitmap(2, 6, 8, True)
-add_bitmap(1, 0, 6, False)
-add_bitmap(2, 6, 8, True)
-dump = ['./qcow2.py', disk, 'dump-header']
-subprocess.run(dump)
-# Dump the metadata in JSON format
-dump.append('-j')
-subprocess.run(dump)
+ cmd = ['./qcow2.py', disk, 'dump-header']
+ if json_output:
+ cmd.append('-j')
+
+ subprocess.run(cmd)
+
+
+test('zlib', False)
+test('zstd', True)
diff --git a/tests/qemu-iotests/303.out b/tests/qemu-iotests/303.out
index 7c16998587..b3c70827b7 100644
--- a/tests/qemu-iotests/303.out
+++ b/tests/qemu-iotests/303.out
@@ -80,6 +80,34 @@ extra_data_size 0
Bitmap table type size offset
0 all-zeroes 0 0
+Add bitmap 1
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+wrote 1048576/1048576 bytes at offset 1048576
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+wrote 1048576/1048576 bytes at offset 2097152
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+wrote 1048576/1048576 bytes at offset 3145728
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+wrote 1048576/1048576 bytes at offset 4194304
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+wrote 1048576/1048576 bytes at offset 5242880
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+
+Add bitmap 2
+wrote 1048576/1048576 bytes at offset 6291456
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+wrote 1048576/1048576 bytes at offset 7340032
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+
{
"magic": 1363560955,
"version": 3,
@@ -94,7 +122,7 @@ Bitmap table type size offset
"refcount_table_clusters": 1,
"nb_snapshots": 0,
"snapshot_offset": 0,
- "incompatible_features": 0,
+ "incompatible_features": 8,
"compatible_features": 0,
"autoclear_features": 1,
"refcount_order": 4,
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index 0c27721a41..75de1b4691 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -32,8 +32,6 @@ def make_argparser() -> argparse.ArgumentParser:
p.add_argument('-n', '--dry-run', action='store_true',
help='show me, do not run tests')
- p.add_argument('-makecheck', action='store_true',
- help='pretty print output for make check')
p.add_argument('-j', dest='jobs', type=int, default=1,
help='run tests in multiple parallel jobs')
@@ -53,6 +51,8 @@ def make_argparser() -> argparse.ArgumentParser:
p.add_argument('--color', choices=['on', 'off', 'auto'],
default='auto', help="use terminal colors. The default "
"'auto' value means use colors if terminal stdout detected")
+ p.add_argument('-tap', action='store_true',
+ help='produce TAP output')
g_env = p.add_argument_group('test environment options')
mg = g_env.add_mutually_exclusive_group()
@@ -164,7 +164,7 @@ if __name__ == '__main__':
if args.dry_run:
print('\n'.join(tests))
else:
- with TestRunner(env, makecheck=args.makecheck,
+ with TestRunner(env, tap=args.tap,
color=args.color) as tr:
paths = [os.path.join(env.source_iotests, t) for t in tests]
ok = tr.run_tests(paths, args.jobs)
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 2b2b53946c..75cc241580 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -247,6 +247,7 @@ _filter_img_info()
-e "/block_state_zero: \\(on\\|off\\)/d" \
-e "/log_size: [0-9]\\+/d" \
-e "s/iters: [0-9]\\+/iters: 1024/" \
+ -e 's/\(compression type: \)\(zlib\|zstd\)/\1COMPRESSION_TYPE/' \
-e "s/uuid: [-a-f0-9]\\+/uuid: 00000000-0000-0000-0000-000000000000/" | \
while IFS='' read -r line; do
if [[ $format_specific == 1 ]]; then
@@ -337,5 +338,12 @@ _filter_authz_check_tls()
$SED -e 's/TLS x509 authz check for .* is denied/TLS x509 authz check for DISTINGUISHED-NAME is denied/'
}
+_filter_qcow2_compression_type_bit()
+{
+ $SED -e 's/\(incompatible_features\s\+\)\[3\(, \)\?/\1[/' \
+ -e 's/\(incompatible_features.*\), 3\]/\1]/' \
+ -e 's/\(incompatible_features.*\), 3\(,.*\)/\1\2/'
+}
+
# make sure this script returns success
true
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index d8582454de..9885030b43 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -699,6 +699,7 @@ _img_info()
-e "s#$TEST_DIR#TEST_DIR#g" \
-e "s#$SOCK_DIR/fuse-#TEST_DIR/#g" \
-e "s#$IMGFMT#IMGFMT#g" \
+ -e 's/\(compression type: \)\(zlib\|zstd\)/\1COMPRESSION_TYPE/' \
-e "/^disk size:/ D" \
-e "/actual-size/ D" | \
while IFS='' read -r line; do
@@ -996,5 +997,26 @@ _require_one_device_of()
_notrun "$* not available"
}
+_qcow2_dump_header()
+{
+ if [[ "$1" == "--no-filter-compression" ]]; then
+ local filter_compression=0
+ shift
+ else
+ local filter_compression=1
+ fi
+
+ img="$1"
+ if [ -z "$img" ]; then
+ img="$TEST_IMG"
+ fi
+
+ if [[ $filter_compression == 0 ]]; then
+ $PYTHON qcow2.py "$img" dump-header
+ else
+ $PYTHON qcow2.py "$img" dump-header | _filter_qcow2_compression_type_bit
+ fi
+}
+
# make sure this script returns success
true
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 1e2f2391d1..8cdb381f2a 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+import argparse
import atexit
import bz2
from collections import OrderedDict
@@ -149,7 +150,9 @@ def qemu_tool_popen(args: Sequence[str],
def qemu_tool_pipe_and_status(tool: str, args: Sequence[str],
- connect_stderr: bool = True) -> Tuple[str, int]:
+ connect_stderr: bool = True,
+ drop_successful_output: bool = False) \
+ -> Tuple[str, int]:
"""
Run a tool and return both its output and its exit code
"""
@@ -159,14 +162,56 @@ def qemu_tool_pipe_and_status(tool: str, args: Sequence[str],
cmd = ' '.join(args)
sys.stderr.write(f'{tool} received signal \
{-subp.returncode}: {cmd}\n')
+ if drop_successful_output and subp.returncode == 0:
+ output = ''
return (output, subp.returncode)
+def qemu_img_create_prepare_args(args: List[str]) -> List[str]:
+ if not args or args[0] != 'create':
+ return list(args)
+ args = args[1:]
+
+ p = argparse.ArgumentParser(allow_abbrev=False)
+ # -o option may be specified several times
+ p.add_argument('-o', action='append', default=[])
+ p.add_argument('-f')
+ parsed, remaining = p.parse_known_args(args)
+
+ opts_list = parsed.o
+
+ result = ['create']
+ if parsed.f is not None:
+ result += ['-f', parsed.f]
+
+ # IMGOPTS most probably contain options specific for the selected format,
+ # like extended_l2 or compression_type for qcow2. Test may want to create
+ # additional images in other formats that doesn't support these options.
+ # So, use IMGOPTS only for images created in imgfmt format.
+ imgopts = os.environ.get('IMGOPTS')
+ if imgopts and parsed.f == imgfmt:
+ opts_list.insert(0, imgopts)
+
+ # default luks support
+ if parsed.f == 'luks' and \
+ all('key-secret' not in opts for opts in opts_list):
+ result += ['--object', luks_default_secret_object]
+ opts_list.append(luks_default_key_secret_opt)
+
+ for opts in opts_list:
+ result += ['-o', opts]
+
+ result += remaining
+
+ return result
+
def qemu_img_pipe_and_status(*args: str) -> Tuple[str, int]:
"""
Run qemu-img and return both its output and its exit code
"""
- full_args = qemu_img_args + list(args)
- return qemu_tool_pipe_and_status('qemu-img', full_args)
+ is_create = bool(args and args[0] == 'create')
+ full_args = qemu_img_args + qemu_img_create_prepare_args(list(args))
+ return qemu_tool_pipe_and_status('qemu-img', full_args,
+ drop_successful_output=is_create)
def qemu_img(*args: str) -> int:
'''Run qemu-img and return the exit code'''
@@ -186,23 +231,7 @@ def ordered_qmp(qmsg, conv_keys=True):
return qmsg
def qemu_img_create(*args):
- args = list(args)
-
- # default luks support
- if '-f' in args and args[args.index('-f') + 1] == 'luks':
- if '-o' in args:
- i = args.index('-o')
- if 'key-secret' not in args[i + 1]:
- args[i + 1].append(luks_default_key_secret_opt)
- args.insert(i + 2, '--object')
- args.insert(i + 3, luks_default_secret_object)
- else:
- args = ['-o', luks_default_key_secret_opt,
- '--object', luks_default_secret_object] + args
-
- args.insert(0, 'create')
-
- return qemu_img(*args)
+ return qemu_img('create', *args)
def qemu_img_measure(*args):
return json.loads(qemu_img_pipe("measure", "--output", "json", *args))
@@ -210,14 +239,6 @@ def qemu_img_measure(*args):
def qemu_img_check(*args):
return json.loads(qemu_img_pipe("check", "--output", "json", *args))
-def qemu_img_verbose(*args):
- '''Run qemu-img without suppressing its output and return the exit code'''
- exitcode = subprocess.call(qemu_img_args + list(args))
- if exitcode < 0:
- sys.stderr.write('qemu-img received signal %i: %s\n'
- % (-exitcode, ' '.join(qemu_img_args + list(args))))
- return exitcode
-
def qemu_img_pipe(*args: str) -> str:
'''Run qemu-img and return its output'''
return qemu_img_pipe_and_status(*args)[0]
@@ -227,9 +248,10 @@ def qemu_img_log(*args):
log(result, filters=[filter_testfiles])
return result
-def img_info_log(filename, filter_path=None, imgopts=False, extra_args=()):
+def img_info_log(filename, filter_path=None, use_image_opts=False,
+ extra_args=()):
args = ['info']
- if imgopts:
+ if use_image_opts:
args.append('--image-opts')
else:
args += ['-f', imgfmt]
@@ -475,6 +497,8 @@ def filter_img_info(output, filename):
'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
line)
line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line)
+ line = re.sub('(compression type: )(zlib|zstd)', r'\1COMPRESSION_TYPE',
+ line)
lines.append(line)
return '\n'.join(lines)
@@ -1225,6 +1249,17 @@ def _verify_virtio_scsi_pci_or_ccw() -> None:
notrun('Missing virtio-scsi-pci or virtio-scsi-ccw in QEMU binary')
+def _verify_imgopts(unsupported: Sequence[str] = ()) -> None:
+ imgopts = os.environ.get('IMGOPTS')
+ # One of usage examples for IMGOPTS is "data_file=$TEST_IMG.ext_data_file"
+ # but it supported only for bash tests. We don't have a concept of global
+ # TEST_IMG in iotests.py, not saying about somehow parsing $variables.
+ # So, for simplicity let's just not support any IMGOPTS with '$' inside.
+ unsup = list(unsupported) + ['$']
+ if imgopts and any(x in imgopts for x in unsup):
+ notrun(f'not suitable for this imgopts: {imgopts}')
+
+
def supports_quorum():
return 'quorum' in qemu_img_pipe('--help')
@@ -1401,7 +1436,8 @@ def execute_setup_common(supported_fmts: Sequence[str] = (),
unsupported_fmts: Sequence[str] = (),
supported_protocols: Sequence[str] = (),
unsupported_protocols: Sequence[str] = (),
- required_fmts: Sequence[str] = ()) -> bool:
+ required_fmts: Sequence[str] = (),
+ unsupported_imgopts: Sequence[str] = ()) -> bool:
"""
Perform necessary setup for either script-style or unittest-style tests.
@@ -1421,6 +1457,7 @@ def execute_setup_common(supported_fmts: Sequence[str] = (),
_verify_aio_mode(supported_aio_modes)
_verify_formats(required_fmts)
_verify_virtio_blk()
+ _verify_imgopts(unsupported_imgopts)
return debug
diff --git a/tests/qemu-iotests/meson.build b/tests/qemu-iotests/meson.build
new file mode 100644
index 0000000000..5be3c74127
--- /dev/null
+++ b/tests/qemu-iotests/meson.build
@@ -0,0 +1,30 @@
+if have_tools and targetos != 'windows'
+ qemu_iotests_binaries = [qemu_img, qemu_io, qemu_nbd, qsd]
+ qemu_iotests_env = {'PYTHON': python.full_path()}
+ qemu_iotests_formats = {
+ 'qcow2': 'quick',
+ 'raw': 'slow',
+ 'qed': 'thorough',
+ 'vmdk': 'thorough',
+ 'vpc': 'thorough'
+ }
+
+ foreach k, v : emulators
+ if k.startswith('qemu-system-')
+ qemu_iotests_binaries += v
+ endif
+ endforeach
+ foreach format, speed: qemu_iotests_formats
+ if speed == 'quick'
+ suites = 'block'
+ else
+ suites = ['block-' + speed, speed]
+ endif
+ test('qemu-iotests ' + format, sh, args: [files('../check-block.sh'), format],
+ depends: qemu_iotests_binaries, env: qemu_iotests_env,
+ protocol: 'tap',
+ suite: suites,
+ timeout: 0,
+ is_parallel: false)
+ endforeach
+endif
diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py
index c33454fa68..0f32897fe8 100644
--- a/tests/qemu-iotests/testenv.py
+++ b/tests/qemu-iotests/testenv.py
@@ -287,21 +287,21 @@ class TestEnv(ContextManager['TestEnv']):
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
self.close()
- def print_env(self) -> None:
+ def print_env(self, prefix: str = '') -> None:
template = """\
-QEMU -- "{QEMU_PROG}" {QEMU_OPTIONS}
-QEMU_IMG -- "{QEMU_IMG_PROG}" {QEMU_IMG_OPTIONS}
-QEMU_IO -- "{QEMU_IO_PROG}" {QEMU_IO_OPTIONS}
-QEMU_NBD -- "{QEMU_NBD_PROG}" {QEMU_NBD_OPTIONS}
-IMGFMT -- {IMGFMT}{imgopts}
-IMGPROTO -- {IMGPROTO}
-PLATFORM -- {platform}
-TEST_DIR -- {TEST_DIR}
-SOCK_DIR -- {SOCK_DIR}
-GDB_OPTIONS -- {GDB_OPTIONS}
-VALGRIND_QEMU -- {VALGRIND_QEMU}
-PRINT_QEMU_OUTPUT -- {PRINT_QEMU}
-"""
+{prefix}QEMU -- "{QEMU_PROG}" {QEMU_OPTIONS}
+{prefix}QEMU_IMG -- "{QEMU_IMG_PROG}" {QEMU_IMG_OPTIONS}
+{prefix}QEMU_IO -- "{QEMU_IO_PROG}" {QEMU_IO_OPTIONS}
+{prefix}QEMU_NBD -- "{QEMU_NBD_PROG}" {QEMU_NBD_OPTIONS}
+{prefix}IMGFMT -- {IMGFMT}{imgopts}
+{prefix}IMGPROTO -- {IMGPROTO}
+{prefix}PLATFORM -- {platform}
+{prefix}TEST_DIR -- {TEST_DIR}
+{prefix}SOCK_DIR -- {SOCK_DIR}
+{prefix}GDB_OPTIONS -- {GDB_OPTIONS}
+{prefix}VALGRIND_QEMU -- {VALGRIND_QEMU}
+{prefix}PRINT_QEMU_OUTPUT -- {PRINT_QEMU}
+{prefix}"""
args = collections.defaultdict(str, self.get_env())
@@ -310,5 +310,5 @@ PRINT_QEMU_OUTPUT -- {PRINT_QEMU}
u = os.uname()
args['platform'] = f'{u.sysname}/{u.machine} {u.nodename} {u.release}'
-
+ args['prefix'] = prefix
print(template.format_map(args))
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
index 15788f919e..0eace147b8 100644
--- a/tests/qemu-iotests/testrunner.py
+++ b/tests/qemu-iotests/testrunner.py
@@ -152,10 +152,10 @@ class TestRunner(ContextManager['TestRunner']):
return results
- def __init__(self, env: TestEnv, makecheck: bool = False,
+ def __init__(self, env: TestEnv, tap: bool = False,
color: str = 'auto') -> None:
self.env = env
- self.makecheck = makecheck
+ self.tap = tap
self.last_elapsed = LastElapsedTime('.last-elapsed-cache', env)
assert color in ('auto', 'on', 'off')
@@ -185,13 +185,16 @@ class TestRunner(ContextManager['TestRunner']):
""" Print short test info before/after test run """
test = os.path.basename(test)
- if self.makecheck and status != '...':
- if status and status != 'pass':
- status = f' [{status}]'
- else:
- status = ''
+ if test_field_width is None:
+ test_field_width = 8
- print(f' TEST iotest-{self.env.imgfmt}: {test}{status}')
+ if self.tap:
+ if status == 'pass':
+ print(f'ok {self.env.imgfmt} {test}')
+ elif status == 'fail':
+ print(f'not ok {self.env.imgfmt} {test}')
+ elif status == 'not run':
+ print(f'ok {self.env.imgfmt} {test} # SKIP')
return
if lasttime:
@@ -343,7 +346,7 @@ class TestRunner(ContextManager['TestRunner']):
last_el = self.last_elapsed.get(test)
start = datetime.datetime.now().strftime('%H:%M:%S')
- if not self.makecheck:
+ if not self.tap:
self.test_print_one_line(test=test,
test_field_width=test_field_width,
status = 'started' if mp else '...',
@@ -372,7 +375,9 @@ class TestRunner(ContextManager['TestRunner']):
notrun = []
casenotrun = []
- if not self.makecheck:
+ if self.tap:
+ self.env.print_env('# ')
+ else:
self.env.print_env()
test_field_width = max(len(os.path.basename(t)) for t in tests) + 2
@@ -398,8 +403,6 @@ class TestRunner(ContextManager['TestRunner']):
if res.status == 'fail':
failed.append(name)
- if self.makecheck:
- self.env.print_env()
if res.diff:
print('\n'.join(res.diff))
elif res.status == 'not run':
@@ -412,16 +415,16 @@ class TestRunner(ContextManager['TestRunner']):
if res.interrupted:
break
- if notrun:
- print('Not run:', ' '.join(notrun))
+ if not self.tap:
+ if notrun:
+ print('Not run:', ' '.join(notrun))
- if casenotrun:
- print('Some cases not run in:', ' '.join(casenotrun))
+ if casenotrun:
+ print('Some cases not run in:', ' '.join(casenotrun))
- if failed:
- print('Failures:', ' '.join(failed))
- print(f'Failed {len(failed)} of {n_run} iotests')
- return False
- else:
- print(f'Passed all {n_run} iotests')
- return True
+ if failed:
+ print('Failures:', ' '.join(failed))
+ print(f'Failed {len(failed)} of {n_run} iotests')
+ else:
+ print(f'Passed all {n_run} iotests')
+ return not failed
diff --git a/tests/qemu-iotests/tests/block-status-cache b/tests/qemu-iotests/tests/block-status-cache
new file mode 100755
index 0000000000..6fa10bb8f8
--- /dev/null
+++ b/tests/qemu-iotests/tests/block-status-cache
@@ -0,0 +1,139 @@
+#!/usr/bin/env python3
+# group: rw quick
+#
+# Test cases for the block-status cache.
+#
+# Copyright (C) 2022 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import signal
+import iotests
+from iotests import qemu_img_create, qemu_img_pipe, qemu_nbd
+
+
+image_size = 1 * 1024 * 1024
+test_img = os.path.join(iotests.test_dir, 'test.img')
+
+nbd_pidfile = os.path.join(iotests.test_dir, 'nbd.pid')
+nbd_sock = os.path.join(iotests.sock_dir, 'nbd.sock')
+
+
+class TestBscWithNbd(iotests.QMPTestCase):
+ def setUp(self) -> None:
+ """Just create an empty image with a read-only NBD server on it"""
+ assert qemu_img_create('-f', iotests.imgfmt, test_img,
+ str(image_size)) == 0
+
+ # Pass --allocation-depth to enable the qemu:allocation-depth context,
+ # which we are going to query to provoke a block-status inquiry with
+ # want_zero=false.
+ assert qemu_nbd(f'--socket={nbd_sock}',
+ f'--format={iotests.imgfmt}',
+ '--persistent',
+ '--allocation-depth',
+ '--read-only',
+ f'--pid-file={nbd_pidfile}',
+ test_img) \
+ == 0
+
+ def tearDown(self) -> None:
+ with open(nbd_pidfile, encoding='utf-8') as f:
+ pid = int(f.read())
+ os.kill(pid, signal.SIGTERM)
+ os.remove(nbd_pidfile)
+ os.remove(test_img)
+
+ def test_with_zero_bug(self) -> None:
+ """
+ Verify that the block-status cache is not corrupted by a
+ want_zero=false call.
+ We can provoke a want_zero=false call with `qemu-img map` over NBD with
+ x-dirty-bitmap=qemu:allocation-depth, so we first run a normal `map`
+ (which results in want_zero=true), then using said
+ qemu:allocation-depth context, and finally another normal `map` to
+ verify that the cache has not been corrupted.
+ """
+
+ nbd_img_opts = f'driver=nbd,server.type=unix,server.path={nbd_sock}'
+ nbd_img_opts_alloc_depth = nbd_img_opts + \
+ ',x-dirty-bitmap=qemu:allocation-depth'
+
+ # Normal map, results in want_zero=true.
+ # This will probably detect an allocated data sector first (qemu likes
+ # to allocate the first sector to facilitate alignment probing), and
+ # then the rest to be zero. The BSC will thus contain (if anything)
+ # one range covering the first sector.
+ map_pre = qemu_img_pipe('map', '--output=json', '--image-opts',
+ nbd_img_opts)
+
+ # qemu:allocation-depth maps for want_zero=false.
+ # want_zero=false should (with the file driver, which the server is
+ # using) report everything as data. While this is sufficient for
+ # want_zero=false, this is nothing that should end up in the
+ # block-status cache.
+ # Due to a bug, this information did end up in the cache, though, and
+ # this would lead to wrong information being returned on subsequent
+ # want_zero=true calls.
+ #
+ # We need to run this map twice: On the first call, we probably still
+ # have the first sector in the cache, and so this will be served from
+ # the cache; and only the subsequent range will be queried from the
+ # block driver. This subsequent range will then be entered into the
+ # cache.
+ # If we did a want_zero=true call at this point, we would thus get
+ # correct information: The first sector is not covered by the cache, so
+ # we would get fresh block-status information from the driver, which
+ # would return a data range, and this would then go into the cache,
+ # evicting the wrong range from the want_zero=false call before.
+ #
+ # Therefore, we need a second want_zero=false map to reproduce:
+ # Since the first sector is not in the cache, the query for its status
+ # will go to the driver, which will return a result that reports the
+ # whole image to be a single data area. This result will then go into
+ # the cache, and so the cache will then report the whole image to
+ # contain data.
+ #
+ # Note that once the cache reports the whole image to contain data, any
+ # subsequent map operation will be served from the cache, and so we can
+ # never loop too many times here.
+ for _ in range(2):
+ # (Ignore the result, this is just to contaminate the cache)
+ qemu_img_pipe('map', '--output=json', '--image-opts',
+ nbd_img_opts_alloc_depth)
+
+ # Now let's see whether the cache reports everything as data, or
+ # whether we get correct information (i.e. the same as we got on our
+ # first attempt).
+ map_post = qemu_img_pipe('map', '--output=json', '--image-opts',
+ nbd_img_opts)
+
+ if map_pre != map_post:
+ print('ERROR: Map information differs before and after querying ' +
+ 'qemu:allocation-depth')
+ print('Before:')
+ print(map_pre)
+ print('After:')
+ print(map_post)
+
+ self.fail("Map information differs")
+
+
+if __name__ == '__main__':
+ # The block-status cache only works on the protocol layer, so to test it,
+ # we can only use the raw format
+ iotests.main(supported_fmts=['raw'],
+ supported_protocols=['file'])
diff --git a/tests/qemu-iotests/tests/block-status-cache.out b/tests/qemu-iotests/tests/block-status-cache.out
new file mode 100644
index 0000000000..ae1213e6f8
--- /dev/null
+++ b/tests/qemu-iotests/tests/block-status-cache.out
@@ -0,0 +1,5 @@
+.
+----------------------------------------------------------------------
+Ran 1 tests
+
+OK
diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test
index 00ebb5c251..fc9c4b4ef4 100755
--- a/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test
+++ b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test
@@ -272,4 +272,5 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase):
if __name__ == '__main__':
- iotests.main(supported_fmts=['qcow2'])
+ iotests.main(supported_fmts=['qcow2'],
+ unsupported_imgopts=['compat'])
diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-test b/tests/qemu-iotests/tests/migrate-bitmaps-test
index c23df3d75c..59f3357580 100755
--- a/tests/qemu-iotests/tests/migrate-bitmaps-test
+++ b/tests/qemu-iotests/tests/migrate-bitmaps-test
@@ -307,7 +307,8 @@ def main() -> None:
iotests.main(
supported_fmts=['qcow2'],
- supported_protocols=['file']
+ supported_protocols=['file'],
+ unsupported_imgopts=['compat']
)
diff --git a/tests/qemu-iotests/tests/migration-permissions b/tests/qemu-iotests/tests/migration-permissions
new file mode 100755
index 0000000000..6be02581c7
--- /dev/null
+++ b/tests/qemu-iotests/tests/migration-permissions
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+# group: migration
+#
+# Copyright (C) 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import iotests
+from iotests import imgfmt, qemu_img_create, qemu_io
+
+
+test_img = os.path.join(iotests.test_dir, 'test.img')
+mig_sock = os.path.join(iotests.sock_dir, 'mig.sock')
+
+
+class TestMigrationPermissions(iotests.QMPTestCase):
+ def setUp(self):
+ qemu_img_create('-f', imgfmt, test_img, '1M')
+
+ # Set up two VMs (source and destination) accessing the same raw
+ # image file with a virtio-blk device; prepare the destination for
+ # migration with .add_incoming() and enable migration events
+ vms = [None, None]
+ for i in range(2):
+ vms[i] = iotests.VM(path_suffix=f'{i}')
+ vms[i].add_blockdev(f'file,node-name=prot,filename={test_img}')
+ vms[i].add_blockdev(f'{imgfmt},node-name=fmt,file=prot')
+ vms[i].add_device('virtio-blk,drive=fmt')
+
+ if i == 1:
+ vms[i].add_incoming(f'unix:{mig_sock}')
+
+ vms[i].launch()
+
+ result = vms[i].qmp('migrate-set-capabilities',
+ capabilities=[
+ {'capability': 'events', 'state': True}
+ ])
+ self.assert_qmp(result, 'return', {})
+
+ self.vm_s = vms[0]
+ self.vm_d = vms[1]
+
+ def tearDown(self):
+ self.vm_s.shutdown()
+ self.vm_d.shutdown()
+ try:
+ os.remove(mig_sock)
+ except FileNotFoundError:
+ pass
+ os.remove(test_img)
+
+ # Migrate an image in use by a virtio-blk device to another VM and
+ # verify that the WRITE permission is unshared both before and after
+ # migration
+ def test_post_migration_permissions(self):
+ # Try to access the image R/W, which should fail because virtio-blk
+ # has not been configured with share-rw=on
+ log = qemu_io('-f', imgfmt, '-c', 'quit', test_img)
+ if not log.strip():
+ print('ERROR (pre-migration): qemu-io should not be able to '
+ 'access this image, but it reported no error')
+ else:
+ # This is the expected output
+ assert 'Is another process using the image' in log
+
+ # Now migrate the VM
+ self.vm_s.qmp('migrate', uri=f'unix:{mig_sock}')
+ assert self.vm_s.wait_migration(None)
+ assert self.vm_d.wait_migration(None)
+
+ # Try the same qemu-io access again, verifying that the WRITE
+ # permission remains unshared
+ log = qemu_io('-f', imgfmt, '-c', 'quit', test_img)
+ if not log.strip():
+ print('ERROR (post-migration): qemu-io should not be able to '
+ 'access this image, but it reported no error')
+ else:
+ # This is the expected output
+ assert 'Is another process using the image' in log
+
+
+if __name__ == '__main__':
+ # Only works with raw images because we are testing the
+ # BlockBackend permissions; image format drivers may additionally
+ # unshare permissions and thus tamper with the result
+ iotests.main(supported_fmts=['raw'],
+ supported_protocols=['file'])
diff --git a/tests/qemu-iotests/tests/migration-permissions.out b/tests/qemu-iotests/tests/migration-permissions.out
new file mode 100644
index 0000000000..ae1213e6f8
--- /dev/null
+++ b/tests/qemu-iotests/tests/migration-permissions.out
@@ -0,0 +1,5 @@
+.
+----------------------------------------------------------------------
+Ran 1 tests
+
+OK
diff --git a/tests/qemu-iotests/tests/mirror-ready-cancel-error b/tests/qemu-iotests/tests/mirror-ready-cancel-error
index f2dc88881f..770ffca379 100755
--- a/tests/qemu-iotests/tests/mirror-ready-cancel-error
+++ b/tests/qemu-iotests/tests/mirror-ready-cancel-error
@@ -36,6 +36,11 @@ class TestMirrorReadyCancelError(iotests.QMPTestCase):
assert iotests.qemu_img_create('-f', iotests.imgfmt, target,
str(image_size)) == 0
+ # Ensure that mirror will copy something before READY so the
+ # target format layer will forward the pre-READY flush to its
+ # file child
+ assert iotests.qemu_io_silent('-c', 'write -P 1 0 64k', source) == 0
+
self.vm = iotests.VM()
self.vm.launch()
@@ -97,7 +102,7 @@ class TestMirrorReadyCancelError(iotests.QMPTestCase):
# Write something so will not leave the job immediately, but
# flush first (which will fail, thanks to blkdebug)
res = self.vm.qmp('human-monitor-command',
- command_line='qemu-io mirror-top "write 0 64k"')
+ command_line='qemu-io mirror-top "write -P 2 0 64k"')
self.assert_qmp(res, 'return', '')
# Drain status change events
diff --git a/tests/qemu-iotests/tests/mirror-top-perms b/tests/qemu-iotests/tests/mirror-top-perms
index 0a51a613f3..b5849978c4 100755
--- a/tests/qemu-iotests/tests/mirror-top-perms
+++ b/tests/qemu-iotests/tests/mirror-top-perms
@@ -21,7 +21,6 @@
import os
-from qemu.aqmp import ConnectError
from qemu.machine import machine
from qemu.qmp import QMPConnectError
@@ -107,7 +106,7 @@ class TestMirrorTopPerms(iotests.QMPTestCase):
self.vm_b.launch()
print('ERROR: VM B launched successfully, '
'this should not have happened')
- except (QMPConnectError, ConnectError):
+ except (QMPConnectError, machine.VMLaunchFailure):
assert 'Is another process using the image' in self.vm_b.get_log()
result = self.vm.qmp('block-job-cancel',
diff --git a/tests/qemu-iotests/tests/remove-bitmap-from-backing b/tests/qemu-iotests/tests/remove-bitmap-from-backing
index 8d48fc0f3c..3c397b08ea 100755
--- a/tests/qemu-iotests/tests/remove-bitmap-from-backing
+++ b/tests/qemu-iotests/tests/remove-bitmap-from-backing
@@ -21,7 +21,8 @@
import iotests
from iotests import log, qemu_img_create, qemu_img, qemu_img_pipe
-iotests.script_initialize(supported_fmts=['qcow2'])
+iotests.script_initialize(supported_fmts=['qcow2'],
+ unsupported_imgopts=['compat'])
top, base = iotests.file_path('top', 'base')
size = '1M'
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index e6b72d9026..c4a2d1e166 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -73,7 +73,8 @@
#define OEM_ID "TEST"
#define OEM_TABLE_ID "OEM"
-#define OEM_TEST_ARGS "-machine x-oem-id="OEM_ID",x-oem-table-id="OEM_TABLE_ID
+#define OEM_TEST_ARGS "-machine x-oem-id=" OEM_ID ",x-oem-table-id=" \
+ OEM_TABLE_ID
typedef struct {
bool tcg_only;
@@ -1446,6 +1447,57 @@ static void test_acpi_piix4_tcg_acpi_hmat(void)
test_acpi_tcg_acpi_hmat(MACHINE_PC);
}
+static void test_acpi_erst(const char *machine)
+{
+ gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XXXXXX", NULL);
+ gchar *params;
+ test_data data;
+
+ memset(&data, 0, sizeof(data));
+ data.machine = machine;
+ data.variant = ".acpierst";
+ params = g_strdup_printf(
+ " -object memory-backend-file,id=erstnvram,"
+ "mem-path=%s,size=0x10000,share=on"
+ " -device acpi-erst,memdev=erstnvram", tmp_path);
+ test_acpi_one(params, &data);
+ free_test_data(&data);
+ g_free(params);
+ g_assert(g_rmdir(tmp_path) == 0);
+ g_free(tmp_path);
+}
+
+static void test_acpi_piix4_acpi_erst(void)
+{
+ test_acpi_erst(MACHINE_PC);
+}
+
+static void test_acpi_q35_acpi_erst(void)
+{
+ test_acpi_erst(MACHINE_Q35);
+}
+
+static void test_acpi_microvm_acpi_erst(void)
+{
+ gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XXXXXX", NULL);
+ gchar *params;
+ test_data data;
+
+ test_acpi_microvm_prepare(&data);
+ data.variant = ".pcie";
+ data.tcg_only = true; /* need constant host-phys-bits */
+ params = g_strdup_printf(" -machine microvm,"
+ "acpi=on,ioapic2=off,rtc=off,pcie=on"
+ " -object memory-backend-file,id=erstnvram,"
+ "mem-path=%s,size=0x10000,share=on"
+ " -device acpi-erst,memdev=erstnvram", tmp_path);
+ test_acpi_one(params, &data);
+ g_free(params);
+ g_assert(g_rmdir(tmp_path) == 0);
+ g_free(tmp_path);
+ free_test_data(&data);
+}
+
static void test_acpi_virt_tcg(void)
{
test_data data = {
@@ -1519,11 +1571,7 @@ static void test_acpi_q35_slic(void)
static void test_oem_fields(test_data *data)
{
int i;
- char oem_id[6];
- char oem_table_id[8];
- strpadcpy(oem_id, sizeof oem_id, OEM_ID, ' ');
- strpadcpy(oem_table_id, sizeof oem_table_id, OEM_TABLE_ID, ' ');
for (i = 0; i < data->tables->len; ++i) {
AcpiSdtTable *sdt;
@@ -1533,8 +1581,8 @@ static void test_oem_fields(test_data *data)
continue;
}
- g_assert(memcmp(sdt->aml + 10, oem_id, 6) == 0);
- g_assert(memcmp(sdt->aml + 16, oem_table_id, 8) == 0);
+ g_assert(strncmp((char *)sdt->aml + 10, OEM_ID, 6) == 0);
+ g_assert(strncmp((char *)sdt->aml + 16, OEM_TABLE_ID, 8) == 0);
}
}
@@ -1675,6 +1723,8 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm);
qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat);
qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat);
+ qtest_add_func("acpi/piix4/acpierst", test_acpi_piix4_acpi_erst);
+ qtest_add_func("acpi/q35/acpierst", test_acpi_q35_acpi_erst);
qtest_add_func("acpi/microvm", test_acpi_microvm_tcg);
qtest_add_func("acpi/microvm/usb", test_acpi_microvm_usb_tcg);
qtest_add_func("acpi/microvm/rtc", test_acpi_microvm_rtc_tcg);
@@ -1684,6 +1734,7 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/q35/ivrs", test_acpi_q35_tcg_ivrs);
if (strcmp(arch, "x86_64") == 0) {
qtest_add_func("acpi/microvm/pcie", test_acpi_microvm_pcie_tcg);
+ qtest_add_func("acpi/microvm/acpierst", test_acpi_microvm_acpi_erst);
}
}
if (has_kvm) {
diff --git a/tests/qtest/cdrom-test.c b/tests/qtest/cdrom-test.c
index cfca24fa94..fdd889a487 100644
--- a/tests/qtest/cdrom-test.c
+++ b/tests/qtest/cdrom-test.c
@@ -138,7 +138,7 @@ static void add_x86_tests(void)
* Unstable CI test under load
* See https://lists.gnu.org/archive/html/qemu-devel/2019-02/msg05509.html
*/
- if (g_test_slow()) {
+ if (g_test_slow() && qtest_has_machine("isapc")) {
qtest_add_data_func("cdrom/boot/isapc", "-M isapc "
"-drive if=ide,media=cdrom,file=", test_cdboot);
}
diff --git a/tests/qtest/erst-test.c b/tests/qtest/erst-test.c
new file mode 100644
index 0000000000..c6a0ae4013
--- /dev/null
+++ b/tests/qtest/erst-test.c
@@ -0,0 +1,164 @@
+/*
+ * QTest testcase for acpi-erst
+ *
+ * Copyright (c) 2021 Oracle
+ *
+ * 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 <glib/gstdio.h>
+#include "libqos/libqos-pc.h"
+#include "libqos/libqtest.h"
+#include "qemu-common.h"
+
+#include "hw/pci/pci.h"
+
+static void save_fn(QPCIDevice *dev, int devfn, void *data)
+{
+ QPCIDevice **pdev = (QPCIDevice **) data;
+
+ *pdev = dev;
+}
+
+static QPCIDevice *get_erst_device(QPCIBus *pcibus)
+{
+ QPCIDevice *dev;
+
+ dev = NULL;
+ qpci_device_foreach(pcibus,
+ PCI_VENDOR_ID_REDHAT,
+ PCI_DEVICE_ID_REDHAT_ACPI_ERST,
+ save_fn, &dev);
+ g_assert(dev != NULL);
+
+ return dev;
+}
+
+typedef struct _ERSTState {
+ QOSState *qs;
+ QPCIBar reg_bar, mem_bar;
+ uint64_t reg_barsize, mem_barsize;
+ QPCIDevice *dev;
+} ERSTState;
+
+#define ACTION 0
+#define VALUE 8
+
+static const char *reg2str(unsigned reg)
+{
+ switch (reg) {
+ case 0:
+ return "ACTION";
+ case 8:
+ return "VALUE";
+ default:
+ return NULL;
+ }
+}
+
+static inline uint32_t in_reg32(ERSTState *s, unsigned reg)
+{
+ const char *name = reg2str(reg);
+ uint32_t res;
+
+ res = qpci_io_readl(s->dev, s->reg_bar, reg);
+ g_test_message("*%s -> %08x", name, res);
+
+ return res;
+}
+
+static inline uint64_t in_reg64(ERSTState *s, unsigned reg)
+{
+ const char *name = reg2str(reg);
+ uint64_t res;
+
+ res = qpci_io_readq(s->dev, s->reg_bar, reg);
+ g_test_message("*%s -> %016llx", name, (unsigned long long)res);
+
+ return res;
+}
+
+static inline void out_reg32(ERSTState *s, unsigned reg, uint32_t v)
+{
+ const char *name = reg2str(reg);
+
+ g_test_message("%08x -> *%s", v, name);
+ qpci_io_writel(s->dev, s->reg_bar, reg, v);
+}
+
+static void cleanup_vm(ERSTState *s)
+{
+ g_free(s->dev);
+ qtest_shutdown(s->qs);
+}
+
+static void setup_vm_cmd(ERSTState *s, const char *cmd)
+{
+ const char *arch = qtest_get_arch();
+
+ if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+ s->qs = qtest_pc_boot(cmd);
+ } else {
+ g_printerr("erst-test tests are only available on x86\n");
+ exit(EXIT_FAILURE);
+ }
+ s->dev = get_erst_device(s->qs->pcibus);
+
+ s->reg_bar = qpci_iomap(s->dev, 0, &s->reg_barsize);
+ g_assert_cmpuint(s->reg_barsize, ==, 16);
+
+ s->mem_bar = qpci_iomap(s->dev, 1, &s->mem_barsize);
+ g_assert_cmpuint(s->mem_barsize, ==, 0x2000);
+
+ qpci_device_enable(s->dev);
+}
+
+static void test_acpi_erst_basic(void)
+{
+ ERSTState state;
+ uint64_t log_address_range;
+ uint64_t log_address_length;
+ uint32_t log_address_attr;
+
+ setup_vm_cmd(&state,
+ "-object memory-backend-file,"
+ "mem-path=acpi-erst.XXXXXX,"
+ "size=64K,"
+ "share=on,"
+ "id=nvram "
+ "-device acpi-erst,"
+ "memdev=nvram");
+
+ out_reg32(&state, ACTION, 0xD);
+ log_address_range = in_reg64(&state, VALUE);
+ out_reg32(&state, ACTION, 0xE);
+ log_address_length = in_reg64(&state, VALUE);
+ out_reg32(&state, ACTION, 0xF);
+ log_address_attr = in_reg32(&state, VALUE);
+
+ /* Check log_address_range is not 0, ~0 or base */
+ g_assert_cmpuint(log_address_range, !=, 0ULL);
+ g_assert_cmpuint(log_address_range, !=, ~0ULL);
+ g_assert_cmpuint(log_address_range, !=, state.reg_bar.addr);
+ g_assert_cmpuint(log_address_range, ==, state.mem_bar.addr);
+
+ /* Check log_address_length is bar1_size */
+ g_assert_cmpuint(log_address_length, ==, state.mem_barsize);
+
+ /* Check log_address_attr is 0 */
+ g_assert_cmpuint(log_address_attr, ==, 0);
+
+ cleanup_vm(&state);
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+ qtest_add_func("/acpi-erst/basic", test_acpi_erst_basic);
+ ret = g_test_run();
+ return ret;
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 26937deb6d..762f6adcd5 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -68,6 +68,7 @@ qtests_i386 = \
(config_all_devices.has_key('CONFIG_RTL8139_PCI') ? ['rtl8139-test'] : []) + \
(config_all_devices.has_key('CONFIG_E1000E_PCI_EXPRESS') ? ['fuzz-e1000e-test'] : []) + \
(config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_ACPI_ERST') ? ['erst-test'] : []) + \
(config_all_devices.has_key('CONFIG_VIRTIO_NET') and \
config_all_devices.has_key('CONFIG_Q35') and \
config_all_devices.has_key('CONFIG_VIRTIO_PCI') and \
@@ -103,7 +104,7 @@ if dbus_daemon.found() and config_host.has_key('GDBUS_CODEGEN')
#qtests_i386 += ['dbus-vmstate-test']
dbus_vmstate1 = custom_target('dbus-vmstate description',
output: ['dbus-vmstate1.h', 'dbus-vmstate1.c'],
- input: meson.source_root() / 'backends/dbus-vmstate1.xml',
+ input: meson.project_source_root() / 'backends/dbus-vmstate1.xml',
command: [config_host['GDBUS_CODEGEN'],
'@INPUT@',
'--interface-prefix', 'org.qemu',
@@ -278,6 +279,7 @@ qtests = {
'bios-tables-test': [io, 'boot-sector.c', 'acpi-utils.c', 'tpm-emu.c'],
'cdrom-test': files('boot-sector.c'),
'dbus-vmstate-test': files('migration-helpers.c') + dbus_vmstate1,
+ 'erst-test': files('erst-test.c'),
'ivshmem-test': [rt, '../../contrib/ivshmem-server/ivshmem-server.c'],
'migration-test': files('migration-helpers.c'),
'pxe-test': files('boot-sector.c'),
diff --git a/trace/meson.build b/trace/meson.build
index 573dd699c6..c4794a1f2a 100644
--- a/trace/meson.build
+++ b/trace/meson.build
@@ -2,10 +2,15 @@
specific_ss.add(files('control-target.c'))
trace_events_files = []
-foreach dir : [ '.' ] + trace_events_subdirs
- trace_events_file = meson.project_source_root() / dir / 'trace-events'
+foreach item : [ '.' ] + trace_events_subdirs + qapi_trace_events
+ if item in qapi_trace_events
+ trace_events_file = item
+ group_name = item.full_path().split('/')[-1].underscorify()
+ else
+ trace_events_file = meson.project_source_root() / item / 'trace-events'
+ group_name = item == '.' ? 'root' : item.underscorify()
+ endif
trace_events_files += [ trace_events_file ]
- group_name = dir == '.' ? 'root' : dir.underscorify()
group = '--group=' + group_name
fmt = '@0@-' + group_name + '.@1@'
diff --git a/util/bufferiszero.c b/util/bufferiszero.c
index 695bb4ce28..ec3cd4ca15 100644
--- a/util/bufferiszero.c
+++ b/util/bufferiszero.c
@@ -272,7 +272,7 @@ static void init_accel(unsigned cache)
static void __attribute__((constructor)) init_cpuid_cache(void)
{
- int max = __get_cpuid_max(0, NULL);
+ unsigned max = __get_cpuid_max(0, NULL);
int a, b, c, d;
unsigned cache = 0;
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index 9efdc74bba..ac0dbc2adc 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -683,6 +683,7 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
ret = sigaction(SIGBUS, &act, &sigbus_oldact);
if (ret) {
+ qemu_mutex_unlock(&sigbus_mutex);
error_setg_errno(errp, errno,
"os_mem_prealloc: failed to install signal handler");
return;
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
index f68287e811..f66fbba710 100644
--- a/util/vhost-user-server.c
+++ b/util/vhost-user-server.c
@@ -74,6 +74,20 @@ static void panic_cb(VuDev *vu_dev, const char *buf)
error_report("vu_panic: %s", buf);
}
+void vhost_user_server_ref(VuServer *server)
+{
+ assert(!server->wait_idle);
+ server->refcount++;
+}
+
+void vhost_user_server_unref(VuServer *server)
+{
+ server->refcount--;
+ if (server->wait_idle && !server->refcount) {
+ aio_co_wake(server->co_trip);
+ }
+}
+
static bool coroutine_fn
vu_message_read(VuDev *vu_dev, int conn_fd, VhostUserMsg *vmsg)
{
@@ -177,6 +191,14 @@ static coroutine_fn void vu_client_trip(void *opaque)
/* Keep running */
}
+ if (server->refcount) {
+ /* Wait for requests to complete before we can unmap the memory */
+ server->wait_idle = true;
+ qemu_coroutine_yield();
+ server->wait_idle = false;
+ }
+ assert(server->refcount == 0);
+
vu_deinit(vu_dev);
/* vu_deinit() should have called remove_watch() */