]> Git Repo - qemu.git/commitdiff
test: Move qtests to a separate directory
authorThomas Huth <[email protected]>
Mon, 9 Sep 2019 10:04:01 +0000 (12:04 +0200)
committerThomas Huth <[email protected]>
Sun, 12 Jan 2020 10:42:41 +0000 (11:42 +0100)
The tests directory itself is pretty overcrowded, and it's hard to
see which test belongs to which test subsystem (unit, qtest, ...).
Let's move the qtests to a separate folder for more clarity.

Message-Id: <20191218103059[email protected]>
Reviewed-by: Paolo Bonzini <[email protected]>
Signed-off-by: Thomas Huth <[email protected]>
214 files changed:
.gitlab-ci.yml
MAINTAINERS
configure
tests/Makefile.include
tests/ac97-test.c [deleted file]
tests/acpi-utils.c [deleted file]
tests/acpi-utils.h [deleted file]
tests/ahci-test.c [deleted file]
tests/arm-cpu-features.c [deleted file]
tests/bios-tables-test-allowed-diff.h [deleted file]
tests/bios-tables-test.c [deleted file]
tests/boot-order-test.c [deleted file]
tests/boot-sector.c [deleted file]
tests/boot-sector.h [deleted file]
tests/boot-serial-test.c [deleted file]
tests/cdrom-test.c [deleted file]
tests/cpu-plug-test.c [deleted file]
tests/dbus-vmstate-test.c [deleted file]
tests/dbus-vmstate1.xml [deleted file]
tests/device-introspect-test.c [deleted file]
tests/device-plug-test.c [deleted file]
tests/display-vga-test.c [deleted file]
tests/drive_del-test.c [deleted file]
tests/ds1338-test.c [deleted file]
tests/e1000-test.c [deleted file]
tests/e1000e-test.c [deleted file]
tests/eepro100-test.c [deleted file]
tests/endianness-test.c [deleted file]
tests/es1370-test.c [deleted file]
tests/fdc-test.c [deleted file]
tests/fw_cfg-test.c [deleted file]
tests/hd-geo-test.c [deleted file]
tests/hexloader-test.c [deleted file]
tests/i440fx-test.c [deleted file]
tests/i82801b11-test.c [deleted file]
tests/ide-test.c [deleted file]
tests/intel-hda-test.c [deleted file]
tests/ioh3420-test.c [deleted file]
tests/ipmi-bt-test.c [deleted file]
tests/ipmi-kcs-test.c [deleted file]
tests/ipoctal232-test.c [deleted file]
tests/ivshmem-test.c [deleted file]
tests/libqtest-single.h [deleted file]
tests/libqtest.c [deleted file]
tests/libqtest.h [deleted file]
tests/m25p80-test.c [deleted file]
tests/m48t59-test.c [deleted file]
tests/machine-none-test.c [deleted file]
tests/megasas-test.c [deleted file]
tests/microbit-test.c [deleted file]
tests/migration-helpers.c [deleted file]
tests/migration-helpers.h [deleted file]
tests/migration-test.c [deleted file]
tests/modules-test.c [deleted file]
tests/ne2000-test.c [deleted file]
tests/numa-test.c [deleted file]
tests/nvme-test.c [deleted file]
tests/pca9552-test.c [deleted file]
tests/pci-test.c [deleted file]
tests/pcnet-test.c [deleted file]
tests/pflash-cfi02-test.c [deleted file]
tests/pnv-xscom-test.c [deleted file]
tests/prom-env-test.c [deleted file]
tests/pvpanic-test.c [deleted file]
tests/pxe-test.c [deleted file]
tests/q35-test.c [deleted file]
tests/qmp-cmd-test.c [deleted file]
tests/qmp-test.c [deleted file]
tests/qom-test.c [deleted file]
tests/qos-test.c [deleted file]
tests/qtest/ac97-test.c [new file with mode: 0644]
tests/qtest/acpi-utils.c [new file with mode: 0644]
tests/qtest/acpi-utils.h [new file with mode: 0644]
tests/qtest/ahci-test.c [new file with mode: 0644]
tests/qtest/arm-cpu-features.c [new file with mode: 0644]
tests/qtest/bios-tables-test-allowed-diff.h [new file with mode: 0644]
tests/qtest/bios-tables-test.c [new file with mode: 0644]
tests/qtest/boot-order-test.c [new file with mode: 0644]
tests/qtest/boot-sector.c [new file with mode: 0644]
tests/qtest/boot-sector.h [new file with mode: 0644]
tests/qtest/boot-serial-test.c [new file with mode: 0644]
tests/qtest/cdrom-test.c [new file with mode: 0644]
tests/qtest/cpu-plug-test.c [new file with mode: 0644]
tests/qtest/dbus-vmstate-test.c [new file with mode: 0644]
tests/qtest/dbus-vmstate1.xml [new file with mode: 0644]
tests/qtest/device-introspect-test.c [new file with mode: 0644]
tests/qtest/device-plug-test.c [new file with mode: 0644]
tests/qtest/display-vga-test.c [new file with mode: 0644]
tests/qtest/drive_del-test.c [new file with mode: 0644]
tests/qtest/ds1338-test.c [new file with mode: 0644]
tests/qtest/e1000-test.c [new file with mode: 0644]
tests/qtest/e1000e-test.c [new file with mode: 0644]
tests/qtest/eepro100-test.c [new file with mode: 0644]
tests/qtest/endianness-test.c [new file with mode: 0644]
tests/qtest/es1370-test.c [new file with mode: 0644]
tests/qtest/fdc-test.c [new file with mode: 0644]
tests/qtest/fw_cfg-test.c [new file with mode: 0644]
tests/qtest/hd-geo-test.c [new file with mode: 0644]
tests/qtest/hexloader-test.c [new file with mode: 0644]
tests/qtest/i440fx-test.c [new file with mode: 0644]
tests/qtest/i82801b11-test.c [new file with mode: 0644]
tests/qtest/ide-test.c [new file with mode: 0644]
tests/qtest/intel-hda-test.c [new file with mode: 0644]
tests/qtest/ioh3420-test.c [new file with mode: 0644]
tests/qtest/ipmi-bt-test.c [new file with mode: 0644]
tests/qtest/ipmi-kcs-test.c [new file with mode: 0644]
tests/qtest/ipoctal232-test.c [new file with mode: 0644]
tests/qtest/ivshmem-test.c [new file with mode: 0644]
tests/qtest/libqtest-single.h [new file with mode: 0644]
tests/qtest/libqtest.c [new file with mode: 0644]
tests/qtest/libqtest.h [new file with mode: 0644]
tests/qtest/m25p80-test.c [new file with mode: 0644]
tests/qtest/m48t59-test.c [new file with mode: 0644]
tests/qtest/machine-none-test.c [new file with mode: 0644]
tests/qtest/megasas-test.c [new file with mode: 0644]
tests/qtest/microbit-test.c [new file with mode: 0644]
tests/qtest/migration-helpers.c [new file with mode: 0644]
tests/qtest/migration-helpers.h [new file with mode: 0644]
tests/qtest/migration-test.c [new file with mode: 0644]
tests/qtest/modules-test.c [new file with mode: 0644]
tests/qtest/ne2000-test.c [new file with mode: 0644]
tests/qtest/numa-test.c [new file with mode: 0644]
tests/qtest/nvme-test.c [new file with mode: 0644]
tests/qtest/pca9552-test.c [new file with mode: 0644]
tests/qtest/pci-test.c [new file with mode: 0644]
tests/qtest/pcnet-test.c [new file with mode: 0644]
tests/qtest/pflash-cfi02-test.c [new file with mode: 0644]
tests/qtest/pnv-xscom-test.c [new file with mode: 0644]
tests/qtest/prom-env-test.c [new file with mode: 0644]
tests/qtest/pvpanic-test.c [new file with mode: 0644]
tests/qtest/pxe-test.c [new file with mode: 0644]
tests/qtest/q35-test.c [new file with mode: 0644]
tests/qtest/qmp-cmd-test.c [new file with mode: 0644]
tests/qtest/qmp-test.c [new file with mode: 0644]
tests/qtest/qom-test.c [new file with mode: 0644]
tests/qtest/qos-test.c [new file with mode: 0644]
tests/qtest/rtas-test.c [new file with mode: 0644]
tests/qtest/rtc-test.c [new file with mode: 0644]
tests/qtest/rtl8139-test.c [new file with mode: 0644]
tests/qtest/sdhci-test.c [new file with mode: 0644]
tests/qtest/spapr-phb-test.c [new file with mode: 0644]
tests/qtest/tco-test.c [new file with mode: 0644]
tests/qtest/test-arm-mptimer.c [new file with mode: 0644]
tests/qtest/test-filter-mirror.c [new file with mode: 0644]
tests/qtest/test-filter-redirector.c [new file with mode: 0644]
tests/qtest/test-hmp.c [new file with mode: 0644]
tests/qtest/test-netfilter.c [new file with mode: 0644]
tests/qtest/test-x86-cpuid-compat.c [new file with mode: 0644]
tests/qtest/tmp105-test.c [new file with mode: 0644]
tests/qtest/tpm-crb-swtpm-test.c [new file with mode: 0644]
tests/qtest/tpm-crb-test.c [new file with mode: 0644]
tests/qtest/tpm-emu.c [new file with mode: 0644]
tests/qtest/tpm-emu.h [new file with mode: 0644]
tests/qtest/tpm-tests.c [new file with mode: 0644]
tests/qtest/tpm-tests.h [new file with mode: 0644]
tests/qtest/tpm-tis-swtpm-test.c [new file with mode: 0644]
tests/qtest/tpm-tis-test.c [new file with mode: 0644]
tests/qtest/tpm-util.c [new file with mode: 0644]
tests/qtest/tpm-util.h [new file with mode: 0644]
tests/qtest/usb-hcd-ehci-test.c [new file with mode: 0644]
tests/qtest/usb-hcd-ohci-test.c [new file with mode: 0644]
tests/qtest/usb-hcd-uhci-test.c [new file with mode: 0644]
tests/qtest/usb-hcd-xhci-test.c [new file with mode: 0644]
tests/qtest/vhost-user-test.c [new file with mode: 0644]
tests/qtest/virtio-9p-test.c [new file with mode: 0644]
tests/qtest/virtio-blk-test.c [new file with mode: 0644]
tests/qtest/virtio-ccw-test.c [new file with mode: 0644]
tests/qtest/virtio-net-test.c [new file with mode: 0644]
tests/qtest/virtio-rng-test.c [new file with mode: 0644]
tests/qtest/virtio-scsi-test.c [new file with mode: 0644]
tests/qtest/virtio-serial-test.c [new file with mode: 0644]
tests/qtest/virtio-test.c [new file with mode: 0644]
tests/qtest/vmgenid-test.c [new file with mode: 0644]
tests/qtest/vmxnet3-test.c [new file with mode: 0644]
tests/qtest/wdt_ib700-test.c [new file with mode: 0644]
tests/rtas-test.c [deleted file]
tests/rtc-test.c [deleted file]
tests/rtl8139-test.c [deleted file]
tests/sdhci-test.c [deleted file]
tests/spapr-phb-test.c [deleted file]
tests/tco-test.c [deleted file]
tests/test-arm-mptimer.c [deleted file]
tests/test-filter-mirror.c [deleted file]
tests/test-filter-redirector.c [deleted file]
tests/test-hmp.c [deleted file]
tests/test-netfilter.c [deleted file]
tests/test-x86-cpuid-compat.c [deleted file]
tests/tmp105-test.c [deleted file]
tests/tpm-crb-swtpm-test.c [deleted file]
tests/tpm-crb-test.c [deleted file]
tests/tpm-emu.c [deleted file]
tests/tpm-emu.h [deleted file]
tests/tpm-tests.c [deleted file]
tests/tpm-tests.h [deleted file]
tests/tpm-tis-swtpm-test.c [deleted file]
tests/tpm-tis-test.c [deleted file]
tests/tpm-util.c [deleted file]
tests/tpm-util.h [deleted file]
tests/usb-hcd-ehci-test.c [deleted file]
tests/usb-hcd-ohci-test.c [deleted file]
tests/usb-hcd-uhci-test.c [deleted file]
tests/usb-hcd-xhci-test.c [deleted file]
tests/vhost-user-test.c [deleted file]
tests/virtio-9p-test.c [deleted file]
tests/virtio-blk-test.c [deleted file]
tests/virtio-ccw-test.c [deleted file]
tests/virtio-net-test.c [deleted file]
tests/virtio-rng-test.c [deleted file]
tests/virtio-scsi-test.c [deleted file]
tests/virtio-serial-test.c [deleted file]
tests/virtio-test.c [deleted file]
tests/vmgenid-test.c [deleted file]
tests/vmxnet3-test.c [deleted file]
tests/wdt_ib700-test.c [deleted file]

index ebcef0ebe9b5c0e15398c3b02f28f1600c496cf9..dce8f2d3f56c6457190a7f926277d4de9162683f 100644 (file)
@@ -87,11 +87,12 @@ build-tci:
  - ../configure --enable-tcg-interpreter
       --target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)"
  - make -j2
- - make tests/boot-serial-test tests/cdrom-test tests/pxe-test
+ - make tests/qtest/boot-serial-test tests/qtest/cdrom-test tests/qtest/pxe-test
  - for tg in $TARGETS ; do
      export QTEST_QEMU_BINARY="${tg}-softmmu/qemu-system-${tg}" ;
-     ./tests/boot-serial-test || exit 1 ;
-     ./tests/cdrom-test || exit 1 ;
+     ./tests/qtest/boot-serial-test || exit 1 ;
+     ./tests/qtest/cdrom-test || exit 1 ;
    done
- - QTEST_QEMU_BINARY="x86_64-softmmu/qemu-system-x86_64" ./tests/pxe-test
- - QTEST_QEMU_BINARY="s390x-softmmu/qemu-system-s390x" ./tests/pxe-test -m slow
+ - QTEST_QEMU_BINARY="x86_64-softmmu/qemu-system-x86_64" ./tests/qtest/pxe-test
+ - QTEST_QEMU_BINARY="s390x-softmmu/qemu-system-s390x"
+   ./tests/qtest/pxe-test -m slow
index cd2dc137a3a916a6d4a561832359635d76d1cfd0..02eab66b02c062c005355c67e0403dba43f9a566 100644 (file)
@@ -533,7 +533,7 @@ F: include/hw/misc/arm11scu.h
 F: include/hw/timer/a9gtimer.h
 F: include/hw/timer/arm_mptimer.h
 F: include/hw/timer/armv7m_systick.h
-F: tests/test-arm-mptimer.c
+F: tests/qtest/test-arm-mptimer.c
 
 Exynos
 M: Igor Mitsyanko <[email protected]>
@@ -864,7 +864,7 @@ F: hw/*/nrf51*.c
 F: hw/*/microbit*.c
 F: include/hw/*/nrf51*.h
 F: include/hw/*/microbit*.h
-F: tests/microbit-test.c
+F: tests/qtest/microbit-test.c
 
 CRIS Machines
 -------------
@@ -1101,9 +1101,9 @@ F: include/hw/*/xics*
 F: pc-bios/slof.bin
 F: docs/specs/ppc-spapr-hcalls.txt
 F: docs/specs/ppc-spapr-hotplug.txt
-F: tests/spapr*
+F: tests/qtest/spapr*
 F: tests/libqos/*spapr*
-F: tests/rtas*
+F: tests/qtest/rtas*
 F: tests/libqos/rtas*
 
 PowerNV (Non-Virtualized)
@@ -1116,7 +1116,7 @@ F: hw/intc/pnv*
 F: hw/intc/xics_pnv.c
 F: include/hw/ppc/pnv*
 F: pc-bios/skiboot.lid
-F: tests/pnv*
+F: tests/qtest/pnv*
 
 virtex_ml507
 M: Edgar E. Iglesias <[email protected]>
@@ -1264,7 +1264,7 @@ F: hw/misc/sga.c
 F: hw/isa/apm.c
 F: include/hw/isa/apm.h
 F: tests/test-x86-cpuid.c
-F: tests/test-x86-cpuid-compat.c
+F: tests/qtest/test-x86-cpuid-compat.c
 
 PC Chipset
 M: Michael S. Tsirkin <[email protected]>
@@ -1360,9 +1360,9 @@ F: hw/ide/
 F: hw/block/block.c
 F: hw/block/cdrom.c
 F: hw/block/hd-geometry.c
-F: tests/ide-test.c
-F: tests/ahci-test.c
-F: tests/cdrom-test.c
+F: tests/qtest/ide-test.c
+F: tests/qtest/ahci-test.c
+F: tests/qtest/cdrom-test.c
 F: tests/libqos/ahci*
 T: git https://github.com/jnsnow/qemu.git ide
 
@@ -1372,7 +1372,7 @@ S: Maintained
 F: include/hw/ipmi/*
 F: hw/ipmi/*
 F: hw/smbios/smbios_type_38.c
-F: tests/ipmi*
+F: tests/qtest/ipmi*
 T: git https://github.com/cminyard/qemu.git master-ipmi-rebase
 
 Floppy
 S: Supported
 F: hw/block/fdc.c
 F: include/hw/block/fdc.h
-F: tests/fdc-test.c
+F: tests/qtest/fdc-test.c
 T: git https://github.com/jnsnow/qemu.git ide
 
 OMAP
@@ -1419,8 +1419,8 @@ F: hw/acpi/*
 F: hw/smbios/*
 F: hw/i386/acpi-build.[hc]
 F: hw/arm/virt-acpi-build.c
-F: tests/bios-tables-test.c
-F: tests/acpi-utils.[hc]
+F: tests/qtest/bios-tables-test.c
+F: tests/qtest/acpi-utils.[hc]
 F: tests/data/acpi/
 
 ppc4xx
@@ -1443,7 +1443,7 @@ M: Jason Wang <[email protected]>
 S: Odd Fixes
 F: hw/net/
 F: include/hw/net/
-F: tests/virtio-net-test.c
+F: tests/qtest/virtio-net-test.c
 F: docs/virtio-net-failover.rst
 T: git https://github.com/jasowang/qemu.git net
 
@@ -1460,7 +1460,7 @@ R: Fam Zheng <[email protected]>
 S: Supported
 F: include/hw/scsi/*
 F: hw/scsi/*
-F: tests/virtio-scsi-test.c
+F: tests/qtest/virtio-scsi-test.c
 T: git https://github.com/bonzini/qemu.git scsi-next
 
 SSI
@@ -1470,7 +1470,7 @@ F: hw/ssi/*
 F: hw/block/m25p80.c
 F: include/hw/ssi/ssi.h
 X: hw/ssi/xilinx_*
-F: tests/m25p80-test.c
+F: tests/qtest/m25p80-test.c
 
 Xilinx SPI
 M: Alistair Francis <[email protected]>
@@ -1484,13 +1484,13 @@ F: include/hw/sd/sd*
 F: hw/sd/core.c
 F: hw/sd/sd*
 F: hw/sd/ssi-sd.c
-F: tests/sd*
+F: tests/qtest/sd*
 
 USB
 M: Gerd Hoffmann <[email protected]>
 S: Maintained
 F: hw/usb/*
-F: tests/usb-*-test.c
+F: tests/qtest/usb-*-test.c
 F: docs/usb2.txt
 F: docs/usb-storage.txt
 F: include/hw/usb.h
@@ -1552,7 +1552,6 @@ F: hw/virtio/Makefile.objs
 F: hw/virtio/trace-events
 F: net/vhost-user.c
 F: include/hw/virtio/
-F: tests/virtio-balloon-test.c
 
 virtio-9p
 M: Greg Kurz <[email protected]>
@@ -1560,7 +1559,7 @@ S: Odd Fixes
 F: hw/9pfs/
 X: hw/9pfs/xen-9p*
 F: fsdev/
-F: tests/virtio-9p-test.c
+F: tests/qtest/virtio-9p-test.c
 T: git https://github.com/gkurz/qemu.git 9p-next
 
 virtio-blk
 S: Supported
 F: hw/block/virtio-blk.c
 F: hw/block/dataplane/*
-F: tests/virtio-blk-test.c
+F: tests/qtest/virtio-blk-test.c
 T: git https://github.com/stefanha/qemu.git block
 
 virtio-ccw
@@ -1597,8 +1596,7 @@ S: Supported
 F: hw/char/virtio-serial-bus.c
 F: hw/char/virtio-console.c
 F: include/hw/virtio/virtio-serial.h
-F: tests/virtio-console-test.c
-F: tests/virtio-serial-test.c
+F: tests/qtest/virtio-serial-test.c
 
 virtio-rng
 M: Laurent Vivier <[email protected]>
@@ -1608,7 +1606,7 @@ F: hw/virtio/virtio-rng.c
 F: include/hw/virtio/virtio-rng.h
 F: include/sysemu/rng*.h
 F: backends/rng*.c
-F: tests/virtio-rng-test.c
+F: tests/qtest/virtio-rng-test.c
 
 virtio-crypto
 M: Gonglei <[email protected]>
@@ -1622,7 +1620,7 @@ M: Keith Busch <[email protected]>
 S: Supported
 F: hw/block/nvme*
-F: tests/nvme-test.c
+F: tests/qtest/nvme-test.c
 
 megasas
 M: Hannes Reinecke <[email protected]>
 S: Supported
 F: hw/scsi/megasas.c
 F: hw/scsi/mfi.h
-F: tests/megasas-test.c
+F: tests/qtest/megasas-test.c
 
 Network packet abstractions
 M: Dmitry Fleytman <[email protected]>
@@ -1645,7 +1643,7 @@ M: Dmitry Fleytman <[email protected]>
 S: Maintained
 F: hw/net/vmxnet*
 F: hw/scsi/vmw_pvscsi*
-F: tests/vmxnet3-test.c
+F: tests/qtest/vmxnet3-test.c
 
 Rocker
 M: Jiri Pirko <[email protected]>
@@ -1693,7 +1691,7 @@ F: docs/generic-loader.txt
 Intel Hexadecimal Object File Loader
 M: Su Hang <[email protected]>
 S: Maintained
-F: tests/hexloader-test.c
+F: tests/qtest/hexloader-test.c
 F: tests/data/hex-loader/test.hex
 
 CHRP NVRAM
@@ -1701,7 +1699,7 @@ M: Thomas Huth <[email protected]>
 S: Maintained
 F: hw/nvram/chrp_nvram.c
 F: include/hw/nvram/chrp_nvram.h
-F: tests/prom-env-test.c
+F: tests/qtest/prom-env-test.c
 
 VM Generation ID
 M: Ben Warren <[email protected]>
@@ -1709,7 +1707,7 @@ S: Maintained
 F: hw/acpi/vmgenid.c
 F: include/hw/acpi/vmgenid.h
 F: docs/specs/vmgenid.txt
-F: tests/vmgenid-test.c
+F: tests/qtest/vmgenid-test.c
 F: stubs/vmgenid.c
 
 Unimplemented device
@@ -1779,7 +1777,7 @@ F: stubs/fw_cfg.c
 F: include/hw/nvram/fw_cfg.h
 F: include/standard-headers/linux/qemu_fw_cfg.h
 F: tests/libqos/fw_cfg.c
-F: tests/fw_cfg-test.c
+F: tests/qtest/fw_cfg-test.c
 T: git https://github.com/philmd/qemu.git fw_cfg-next
 
 XIVE
@@ -1799,9 +1797,9 @@ S: Maintained
 F: audio/
 F: hw/audio/
 F: include/hw/audio/
-F: tests/ac97-test.c
-F: tests/es1370-test.c
-F: tests/intel-hda-test.c
+F: tests/qtest/ac97-test.c
+F: tests/qtest/es1370-test.c
+F: tests/qtest/intel-hda-test.c
 
 Block layer core
 M: Kevin Wolf <[email protected]>
@@ -2002,7 +2000,7 @@ F: monitor/hmp*
 F: hmp.h
 F: hmp-commands*.hx
 F: include/monitor/hmp-target.h
-F: tests/test-hmp.c
+F: tests/qtest/test-hmp.c
 F: include/qemu/qemu-print.h
 F: util/qemu-print.c
 
@@ -2128,8 +2126,8 @@ F: qapi/error.json
 F: docs/devel/*qmp-*
 F: docs/interop/*qmp-*
 F: scripts/qmp/
-F: tests/qmp-test.c
-F: tests/qmp-cmd-test.c
+F: tests/qtest/qmp-test.c
+F: tests/qtest/qmp-cmd-test.c
 T: git https://repo.or.cz/qemu/armbru.git qapi-next
 
 qtest
@@ -2139,9 +2137,8 @@ R: Paolo Bonzini <[email protected]>
 S: Maintained
 F: qtest.c
 F: accel/qtest.c
-F: tests/libqtest*
 F: tests/libqos/
-F: tests/*-test.c
+F: tests/qtest/
 
 Register API
 M: Alistair Francis <[email protected]>
@@ -2185,7 +2182,7 @@ F: include/hw/acpi/tpm.h
 F: include/sysemu/tpm*
 F: qapi/tpm.json
 F: backends/tpm.c
-F: tests/*tpm*
+F: tests/qtest/*tpm*
 T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
 
 Checkpatch
@@ -2202,7 +2199,7 @@ F: include/migration/
 F: migration/
 F: scripts/vmstate-static-checker.py
 F: tests/vmstate-static-checker-data/
-F: tests/migration-test.c
+F: tests/qtest/migration-test.c
 F: docs/devel/migration.rst
 F: qapi/migration.json
 
index 28ee2a254f6dcd713b2b9d8b30324a6c1c75a001..1b8796fc21dbe7cd27a86b2edd121952457ceb0d 100755 (executable)
--- a/configure
+++ b/configure
@@ -7963,8 +7963,8 @@ fi
 # so the build tree will be missing the link back to the new file, and
 # tests might fail. Prefer to keep the relevant files in their own
 # directory and symlink the directory instead.
-DIRS="tests tests/tcg tests/tcg/lm32 tests/libqos tests/qapi-schema tests/qemu-iotests tests/vm"
-DIRS="$DIRS tests/fp tests/qgraph"
+DIRS="tests tests/tcg tests/tcg/lm32 tests/libqos tests/qapi-schema tests/qtest"
+DIRS="$DIRS tests/qemu-iotests tests/vm tests/fp tests/qgraph"
 DIRS="$DIRS docs docs/interop fsdev scsi"
 DIRS="$DIRS pc-bios/optionrom pc-bios/s390-ccw"
 DIRS="$DIRS roms/seabios roms/vgabios"
index 6bacf14d3f9f06e70a22126a8e3cbc2675821f41..bd2bcd6f1ba4960c0d6624bd9e9f14b955d6788e 100644 (file)
@@ -515,7 +515,7 @@ generated-files-y += tests/include/test-qapi-events-sub-module.h
 generated-files-y += tests/test-qapi-events-sub-sub-module.h
 generated-files-y += tests/test-qapi-introspect.h
 
-QEMU_CFLAGS += -I$(SRC_PATH)/tests
+QEMU_CFLAGS += -I$(SRC_PATH)/tests -I$(SRC_PATH)/tests/qtest
 
 
 # Deps that are common to various different sets of tests below
@@ -648,18 +648,18 @@ tests/qapi-schema/doc-good.test.texi: $(SRC_PATH)/tests/qapi-schema/doc-good.jso
        @mv tests/qapi-schema/doc-good-qapi-doc.texi $@
        @rm -f tests/qapi-schema/doc-good-qapi-*.[ch] tests/qapi-schema/doc-good-qmp-*.[ch]
 
-tests/dbus-vmstate1.h tests/dbus-vmstate1.c: tests/dbus-vmstate1-gen-timestamp ;
-tests/dbus-vmstate1-gen-timestamp: $(SRC_PATH)/tests/dbus-vmstate1.xml
+tests/qtest/dbus-vmstate1.h tests/qtest/dbus-vmstate1.c: tests/qtest/dbus-vmstate1-gen-timestamp ;
+tests/qtest/dbus-vmstate1-gen-timestamp: $(SRC_PATH)/tests/qtest/dbus-vmstate1.xml
        $(call quiet-command,$(GDBUS_CODEGEN) $< \
-               --interface-prefix org.qemu --generate-c-code tests/dbus-vmstate1, \
+               --interface-prefix org.qemu --generate-c-code tests/qtest/dbus-vmstate1, \
                "GEN","$(@:%-timestamp=%)")
        @>$@
 
-tests/dbus-vmstate-test.o-cflags := -DSRCDIR="$(SRC_PATH)"
-tests/dbus-vmstate1.o-cflags := $(GIO_CFLAGS)
-tests/dbus-vmstate1.o-libs := $(GIO_LIBS)
+tests/qtest/dbus-vmstate-test.o-cflags := -DSRCDIR="$(SRC_PATH)"
+tests/qtest/dbus-vmstate1.o-cflags := $(GIO_CFLAGS)
+tests/qtest/dbus-vmstate1.o-libs := $(GIO_LIBS)
 
-tests/dbus-vmstate-test.o: tests/dbus-vmstate1.h
+tests/qtest/dbus-vmstate-test.o: tests/qtest/dbus-vmstate1.h
 
 tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y)
 tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y)
@@ -708,12 +708,12 @@ tests/test-authz-pam$(EXESUF): tests/test-authz-pam.o $(test-authz-obj-y)
 tests/test-io-task$(EXESUF): tests/test-io-task.o $(test-io-obj-y)
 tests/test-io-channel-socket$(EXESUF): tests/test-io-channel-socket.o \
         tests/io-channel-helpers.o tests/socket-helpers.o $(test-io-obj-y)
-tests/tpm-crb-swtpm-test$(EXESUF): tests/tpm-crb-swtpm-test.o tests/tpm-emu.o \
-       tests/tpm-util.o tests/tpm-tests.o $(test-io-obj-y)
-tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o tests/tpm-emu.o $(test-io-obj-y)
-tests/tpm-tis-swtpm-test$(EXESUF): tests/tpm-tis-swtpm-test.o tests/tpm-emu.o \
-       tests/tpm-util.o tests/tpm-tests.o $(test-io-obj-y)
-tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-emu.o $(test-io-obj-y)
+tests/qtest/tpm-crb-swtpm-test$(EXESUF): tests/qtest/tpm-crb-swtpm-test.o tests/qtest/tpm-emu.o \
+       tests/qtest/tpm-util.o tests/qtest/tpm-tests.o $(test-io-obj-y)
+tests/qtest/tpm-crb-test$(EXESUF): tests/qtest/tpm-crb-test.o tests/qtest/tpm-emu.o $(test-io-obj-y)
+tests/qtest/tpm-tis-swtpm-test$(EXESUF): tests/qtest/tpm-tis-swtpm-test.o tests/qtest/tpm-emu.o \
+       tests/qtest/tpm-util.o tests/qtest/tpm-tests.o $(test-io-obj-y)
+tests/qtest/tpm-tis-test$(EXESUF): tests/qtest/tpm-tis-test.o tests/qtest/tpm-emu.o $(test-io-obj-y)
 tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \
         tests/io-channel-helpers.o $(test-io-obj-y)
 tests/test-io-channel-tls$(EXESUF): tests/test-io-channel-tls.o \
@@ -743,7 +743,7 @@ libqos-pc-obj-y += tests/libqos/ahci.o
 libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o
 
 # Devices
-qos-test-obj-y = tests/qos-test.o $(libqgraph-obj-y)
+qos-test-obj-y = tests/qtest/qos-test.o $(libqgraph-obj-y)
 qos-test-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
 qos-test-obj-y += tests/libqos/e1000e.o
 qos-test-obj-y += tests/libqos/i2c.o
@@ -776,98 +776,98 @@ qos-test-obj-y += tests/libqos/ppc64_pseries-machine.o
 qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 
 # Tests
-qos-test-obj-y += tests/ac97-test.o
-qos-test-obj-y += tests/ds1338-test.o
-qos-test-obj-y += tests/e1000-test.o
-qos-test-obj-y += tests/e1000e-test.o
-qos-test-obj-y += tests/eepro100-test.o
-qos-test-obj-y += tests/es1370-test.o
-qos-test-obj-y += tests/ipoctal232-test.o
-qos-test-obj-y += tests/megasas-test.o
-qos-test-obj-y += tests/ne2000-test.o
-qos-test-obj-y += tests/nvme-test.o
-qos-test-obj-y += tests/pca9552-test.o
-qos-test-obj-y += tests/pci-test.o
-qos-test-obj-y += tests/pcnet-test.o
-qos-test-obj-y += tests/sdhci-test.o
-qos-test-obj-y += tests/spapr-phb-test.o
-qos-test-obj-y += tests/tmp105-test.o
-qos-test-obj-y += tests/usb-hcd-ohci-test.o $(libqos-usb-obj-y)
-qos-test-obj-$(CONFIG_VHOST_NET_USER) += tests/vhost-user-test.o $(chardev-obj-y) $(test-io-obj-y)
-qos-test-obj-y += tests/virtio-test.o
-qos-test-obj-$(CONFIG_VIRTFS) += tests/virtio-9p-test.o
-qos-test-obj-y += tests/virtio-blk-test.o
-qos-test-obj-y += tests/virtio-net-test.o
-qos-test-obj-y += tests/virtio-rng-test.o
-qos-test-obj-y += tests/virtio-scsi-test.o
-qos-test-obj-y += tests/virtio-serial-test.o
-qos-test-obj-y += tests/vmxnet3-test.o
+qos-test-obj-y += tests/qtest/ac97-test.o
+qos-test-obj-y += tests/qtest/ds1338-test.o
+qos-test-obj-y += tests/qtest/e1000-test.o
+qos-test-obj-y += tests/qtest/e1000e-test.o
+qos-test-obj-y += tests/qtest/eepro100-test.o
+qos-test-obj-y += tests/qtest/es1370-test.o
+qos-test-obj-y += tests/qtest/ipoctal232-test.o
+qos-test-obj-y += tests/qtest/megasas-test.o
+qos-test-obj-y += tests/qtest/ne2000-test.o
+qos-test-obj-y += tests/qtest/nvme-test.o
+qos-test-obj-y += tests/qtest/pca9552-test.o
+qos-test-obj-y += tests/qtest/pci-test.o
+qos-test-obj-y += tests/qtest/pcnet-test.o
+qos-test-obj-y += tests/qtest/sdhci-test.o
+qos-test-obj-y += tests/qtest/spapr-phb-test.o
+qos-test-obj-y += tests/qtest/tmp105-test.o
+qos-test-obj-y += tests/qtest/usb-hcd-ohci-test.o $(libqos-usb-obj-y)
+qos-test-obj-$(CONFIG_VHOST_NET_USER) += tests/qtest/vhost-user-test.o $(chardev-obj-y) $(test-io-obj-y)
+qos-test-obj-y += tests/qtest/virtio-test.o
+qos-test-obj-$(CONFIG_VIRTFS) += tests/qtest/virtio-9p-test.o
+qos-test-obj-y += tests/qtest/virtio-blk-test.o
+qos-test-obj-y += tests/qtest/virtio-net-test.o
+qos-test-obj-y += tests/qtest/virtio-rng-test.o
+qos-test-obj-y += tests/qtest/virtio-scsi-test.o
+qos-test-obj-y += tests/qtest/virtio-serial-test.o
+qos-test-obj-y += tests/qtest/vmxnet3-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
 
 check-qtest-generic-y += qos-test
-tests/qos-test$(EXESUF): $(qos-test-obj-y)
-
-tests/qmp-test$(EXESUF): tests/qmp-test.o
-tests/qmp-cmd-test$(EXESUF): tests/qmp-cmd-test.o
-tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o
-tests/rtc-test$(EXESUF): tests/rtc-test.o
-tests/m48t59-test$(EXESUF): tests/m48t59-test.o
-tests/hexloader-test$(EXESUF): tests/hexloader-test.o
-tests/pflash-cfi02$(EXESUF): tests/pflash-cfi02-test.o
-tests/endianness-test$(EXESUF): tests/endianness-test.o
-tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y)
-tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y)
-tests/fdc-test$(EXESUF): tests/fdc-test.o
-tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
-tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) qemu-img$(EXESUF)
-tests/ipmi-kcs-test$(EXESUF): tests/ipmi-kcs-test.o
-tests/ipmi-bt-test$(EXESUF): tests/ipmi-bt-test.o
-tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o $(libqos-obj-y)
-tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y)
-tests/boot-serial-test$(EXESUF): tests/boot-serial-test.o $(libqos-obj-y)
-tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
-       tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y)
-tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
-tests/microbit-test$(EXESUF): tests/microbit-test.o
-tests/m25p80-test$(EXESUF): tests/m25p80-test.o
-tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
-tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
-tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y)
-tests/rtl8139-test$(EXESUF): tests/rtl8139-test.o $(libqos-pc-obj-y)
-tests/pnv-xscom-test$(EXESUF): tests/pnv-xscom-test.o
-tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
-tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y)
-tests/virtio-ccw-test$(EXESUF): tests/virtio-ccw-test.o
-tests/display-vga-test$(EXESUF): tests/display-vga-test.o
-tests/qom-test$(EXESUF): tests/qom-test.o
-tests/test-hmp$(EXESUF): tests/test-hmp.o
-tests/machine-none-test$(EXESUF): tests/machine-none-test.o
-tests/device-plug-test$(EXESUF): tests/device-plug-test.o
-tests/drive_del-test$(EXESUF): tests/drive_del-test.o
-tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o
-tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
-tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
-tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
-tests/usb-hcd-uhci-test$(EXESUF): tests/usb-hcd-uhci-test.o $(libqos-usb-obj-y)
-tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y)
-tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
-tests/cpu-plug-test$(EXESUF): tests/cpu-plug-test.o
-tests/migration-test$(EXESUF): tests/migration-test.o tests/migration-helpers.o
-tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
-tests/test-netfilter$(EXESUF): tests/test-netfilter.o $(qtest-obj-y)
-tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y)
-tests/test-filter-redirector$(EXESUF): tests/test-filter-redirector.o $(qtest-obj-y)
-tests/test-x86-cpuid-compat$(EXESUF): tests/test-x86-cpuid-compat.o $(qtest-obj-y)
-tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
-tests/dbus-vmstate-test$(EXESUF): tests/dbus-vmstate-test.o tests/migration-helpers.o tests/dbus-vmstate1.o $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
-tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o $(test-util-obj-y) libvhost-user.a
-tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o
-tests/numa-test$(EXESUF): tests/numa-test.o
-tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/boot-sector.o tests/acpi-utils.o
-tests/cdrom-test$(EXESUF): tests/cdrom-test.o tests/boot-sector.o $(libqos-obj-y)
-tests/arm-cpu-features$(EXESUF): tests/arm-cpu-features.o
+tests/qtest/qos-test$(EXESUF): $(qos-test-obj-y)
+
+tests/qtest/qmp-test$(EXESUF): tests/qtest/qmp-test.o
+tests/qtest/qmp-cmd-test$(EXESUF): tests/qtest/qmp-cmd-test.o
+tests/qtest/device-introspect-test$(EXESUF): tests/qtest/device-introspect-test.o
+tests/qtest/rtc-test$(EXESUF): tests/qtest/rtc-test.o
+tests/qtest/m48t59-test$(EXESUF): tests/qtest/m48t59-test.o
+tests/qtest/hexloader-test$(EXESUF): tests/qtest/hexloader-test.o
+tests/qtest/pflash-cfi02$(EXESUF): tests/qtest/pflash-cfi02-test.o
+tests/qtest/endianness-test$(EXESUF): tests/qtest/endianness-test.o
+tests/qtest/prom-env-test$(EXESUF): tests/qtest/prom-env-test.o $(libqos-obj-y)
+tests/qtest/rtas-test$(EXESUF): tests/qtest/rtas-test.o $(libqos-spapr-obj-y)
+tests/qtest/fdc-test$(EXESUF): tests/qtest/fdc-test.o
+tests/qtest/ide-test$(EXESUF): tests/qtest/ide-test.o $(libqos-pc-obj-y)
+tests/qtest/ahci-test$(EXESUF): tests/qtest/ahci-test.o $(libqos-pc-obj-y) qemu-img$(EXESUF)
+tests/qtest/ipmi-kcs-test$(EXESUF): tests/qtest/ipmi-kcs-test.o
+tests/qtest/ipmi-bt-test$(EXESUF): tests/qtest/ipmi-bt-test.o
+tests/qtest/hd-geo-test$(EXESUF): tests/qtest/hd-geo-test.o $(libqos-obj-y)
+tests/qtest/boot-order-test$(EXESUF): tests/qtest/boot-order-test.o $(libqos-obj-y)
+tests/qtest/boot-serial-test$(EXESUF): tests/qtest/boot-serial-test.o $(libqos-obj-y)
+tests/qtest/bios-tables-test$(EXESUF): tests/qtest/bios-tables-test.o \
+       tests/qtest/boot-sector.o tests/qtest/acpi-utils.o $(libqos-obj-y)
+tests/qtest/pxe-test$(EXESUF): tests/qtest/pxe-test.o tests/qtest/boot-sector.o $(libqos-obj-y)
+tests/qtest/microbit-test$(EXESUF): tests/qtest/microbit-test.o
+tests/qtest/m25p80-test$(EXESUF): tests/qtest/m25p80-test.o
+tests/qtest/i440fx-test$(EXESUF): tests/qtest/i440fx-test.o $(libqos-pc-obj-y)
+tests/qtest/q35-test$(EXESUF): tests/qtest/q35-test.o $(libqos-pc-obj-y)
+tests/qtest/fw_cfg-test$(EXESUF): tests/qtest/fw_cfg-test.o $(libqos-pc-obj-y)
+tests/qtest/rtl8139-test$(EXESUF): tests/qtest/rtl8139-test.o $(libqos-pc-obj-y)
+tests/qtest/pnv-xscom-test$(EXESUF): tests/qtest/pnv-xscom-test.o
+tests/qtest/wdt_ib700-test$(EXESUF): tests/qtest/wdt_ib700-test.o
+tests/qtest/tco-test$(EXESUF): tests/qtest/tco-test.o $(libqos-pc-obj-y)
+tests/qtest/virtio-ccw-test$(EXESUF): tests/qtest/virtio-ccw-test.o
+tests/qtest/display-vga-test$(EXESUF): tests/qtest/display-vga-test.o
+tests/qtest/qom-test$(EXESUF): tests/qtest/qom-test.o
+tests/qtest/test-hmp$(EXESUF): tests/qtest/test-hmp.o
+tests/qtest/machine-none-test$(EXESUF): tests/qtest/machine-none-test.o
+tests/qtest/device-plug-test$(EXESUF): tests/qtest/device-plug-test.o
+tests/qtest/drive_del-test$(EXESUF): tests/qtest/drive_del-test.o
+tests/qtest/pvpanic-test$(EXESUF): tests/qtest/pvpanic-test.o
+tests/qtest/i82801b11-test$(EXESUF): tests/qtest/i82801b11-test.o
+tests/qtest/intel-hda-test$(EXESUF): tests/qtest/intel-hda-test.o
+tests/qtest/ioh3420-test$(EXESUF): tests/qtest/ioh3420-test.o
+tests/qtest/usb-hcd-uhci-test$(EXESUF): tests/qtest/usb-hcd-uhci-test.o $(libqos-usb-obj-y)
+tests/qtest/usb-hcd-ehci-test$(EXESUF): tests/qtest/usb-hcd-ehci-test.o $(libqos-usb-obj-y)
+tests/qtest/usb-hcd-xhci-test$(EXESUF): tests/qtest/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
+tests/qtest/cpu-plug-test$(EXESUF): tests/qtest/cpu-plug-test.o
+tests/qtest/migration-test$(EXESUF): tests/qtest/migration-test.o tests/qtest/migration-helpers.o
+tests/qtest/qemu-iotests/qtest/socket_scm_helper$(EXESUF): tests/qtest/qemu-iotests/qtest/socket_scm_helper.o
+tests/qtest/test-netfilter$(EXESUF): tests/qtest/test-netfilter.o $(qtest-obj-y)
+tests/qtest/test-filter-mirror$(EXESUF): tests/qtest/test-filter-mirror.o $(qtest-obj-y)
+tests/qtest/test-filter-redirector$(EXESUF): tests/qtest/test-filter-redirector.o $(qtest-obj-y)
+tests/qtest/test-x86-cpuid-compat$(EXESUF): tests/qtest/test-x86-cpuid-compat.o $(qtest-obj-y)
+tests/qtest/ivshmem-test$(EXESUF): tests/qtest/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
+tests/qtest/dbus-vmstate-test$(EXESUF): tests/qtest/dbus-vmstate-test.o tests/qtest/migration-helpers.o tests/qtest/dbus-vmstate1.o $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
+tests/qtest/vhost-user-bridge$(EXESUF): tests/qtest/vhost-user-bridge.o $(test-util-obj-y) libvhost-user.a
+tests/qtest/test-arm-mptimer$(EXESUF): tests/qtest/test-arm-mptimer.o
+tests/qtest/numa-test$(EXESUF): tests/qtest/numa-test.o
+tests/qtest/vmgenid-test$(EXESUF): tests/qtest/vmgenid-test.o tests/qtest/boot-sector.o tests/qtest/acpi-utils.o
+tests/qtest/cdrom-test$(EXESUF): tests/qtest/cdrom-test.o tests/qtest/boot-sector.o $(libqos-obj-y)
+tests/qtest/arm-cpu-features$(EXESUF): tests/qtest/arm-cpu-features.o
 
 tests/migration/stress$(EXESUF): tests/migration/stress.o
        $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@")
@@ -886,13 +886,13 @@ tests/migration/initrd-stress.img: tests/migration/stress$(EXESUF)
 TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
 ifeq ($(CONFIG_POSIX),y)
 QTEST_TARGETS = $(TARGETS)
-check-qtest-y=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y:%=tests/%$(EXESUF)))
-check-qtest-y += $(check-qtest-generic-y:%=tests/%$(EXESUF))
+check-qtest-y=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y:%=tests/qtest/%$(EXESUF)))
+check-qtest-y += $(check-qtest-generic-y:%=tests/qtest/%$(EXESUF))
 else
 QTEST_TARGETS =
 endif
 
-qtest-obj-y = tests/libqtest.o $(test-util-obj-y)
+qtest-obj-y = tests/qtest/libqtest.o $(test-util-obj-y)
 $(check-qtest-y): $(qtest-obj-y)
 
 tests/test-qga$(EXESUF): qemu-ga$(EXESUF)
@@ -937,7 +937,7 @@ endef
 
 .PHONY: $(patsubst %, check-qtest-%, $(QTEST_TARGETS))
 $(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: %-softmmu/all $(check-qtest-y)
-       $(call do_test_human,$(check-qtest-$*-y:%=tests/%$(EXESUF)) $(check-qtest-generic-y:%=tests/%$(EXESUF)), \
+       $(call do_test_human,$(check-qtest-$*-y:%=tests/qtest/%$(EXESUF)) $(check-qtest-generic-y:%=tests/qtest/%$(EXESUF)), \
          QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
          QTEST_QEMU_IMG=qemu-img$(EXESUF))
 
@@ -950,7 +950,7 @@ check-speed: $(check-speed-y)
 # gtester tests with TAP output
 
 $(patsubst %, check-report-qtest-%.tap, $(QTEST_TARGETS)): check-report-qtest-%.tap: %-softmmu/all $(check-qtest-y)
-       $(call do_test_tap, $(check-qtest-$*-y:%=tests/%$(EXESUF)) $(check-qtest-generic-y:%=tests/%$(EXESUF)), \
+       $(call do_test_tap, $(check-qtest-$*-y:%=tests/qtest/%$(EXESUF)) $(check-qtest-generic-y:%=tests/qtest/%$(EXESUF)), \
          QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
          QTEST_QEMU_IMG=qemu-img$(EXESUF))
 
@@ -1215,10 +1215,10 @@ check-block: $(patsubst %,check-%, $(check-block-y))
 endif
 check: check-block check-qapi-schema check-unit check-softfloat check-qtest check-decodetree
 check-clean:
-       rm -rf $(check-unit-y) tests/*.o $(QEMU_IOTESTS_HELPERS-y)
-       rm -rf $(sort $(foreach target,$(SYSEMU_TARGET_LIST), $(check-qtest-$(target)-y:%=tests/%$(EXESUF))) $(check-qtest-generic-y:%=tests/%$(EXESUF)))
+       rm -rf $(check-unit-y) tests/*.o tests/*/*.o $(QEMU_IOTESTS_HELPERS-y)
+       rm -rf $(sort $(foreach target,$(SYSEMU_TARGET_LIST), $(check-qtest-$(target)-y:%=tests/qtest/%$(EXESUF))) $(check-qtest-generic-y:%=tests/qtest/%$(EXESUF)))
        rm -f tests/test-qapi-gen-timestamp
-       rm -f tests/dbus-vmstate1-gen-timestamp
+       rm -f tests/qtest/dbus-vmstate1-gen-timestamp
        rm -rf $(TESTS_VENV_DIR) $(TESTS_RESULTS_DIR)
 
 clean: check-clean
@@ -1228,6 +1228,7 @@ clean: check-clean
 all: $(QEMU_IOTESTS_HELPERS-y)
 
 -include $(wildcard tests/*.d)
+-include $(wildcard tests/qtest/*.d)
 -include $(wildcard tests/libqos/*.d)
 
 endif
diff --git a/tests/ac97-test.c b/tests/ac97-test.c
deleted file mode 100644 (file)
index b084e31..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * QTest testcase for AC97
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qemu/module.h"
-#include "libqos/qgraph.h"
-#include "libqos/pci.h"
-
-typedef struct QAC97 QAC97;
-
-struct QAC97 {
-    QOSGraphObject obj;
-    QPCIDevice dev;
-};
-
-static void *ac97_get_driver(void *obj, const char *interface)
-{
-    QAC97 *ac97 = obj;
-
-    if (!g_strcmp0(interface, "pci-device")) {
-        return &ac97->dev;
-    }
-
-    fprintf(stderr, "%s not present in e1000e\n", interface);
-    g_assert_not_reached();
-}
-
-static void *ac97_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
-{
-    QAC97 *ac97 = g_new0(QAC97, 1);
-    QPCIBus *bus = pci_bus;
-
-    qpci_device_init(&ac97->dev, bus, addr);
-    ac97->obj.get_driver = ac97_get_driver;
-    return &ac97->obj;
-}
-
-static void ac97_register_nodes(void)
-{
-    QOSGraphEdgeOptions opts = {
-        .extra_device_opts = "addr=04.0",
-    };
-    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
-
-    qos_node_create_driver("AC97", ac97_create);
-    qos_node_produces("AC97", "pci-device");
-    qos_node_consumes("AC97", "pci-bus", &opts);
-}
-
-libqos_init(ac97_register_nodes);
diff --git a/tests/acpi-utils.c b/tests/acpi-utils.c
deleted file mode 100644 (file)
index d2a202e..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * ACPI Utility Functions
- *
- * Copyright (c) 2013 Red Hat Inc.
- * Copyright (c) 2017 Skyport Systems
- *
- * Authors:
- *  Michael S. Tsirkin <[email protected]>,
- *  Ben Warren <[email protected]>
- *
- * 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 "qemu-common.h"
-#include "qemu/bitmap.h"
-#include "acpi-utils.h"
-#include "boot-sector.h"
-
-uint8_t acpi_calc_checksum(const uint8_t *data, int len)
-{
-    int i;
-    uint8_t sum = 0;
-
-    for (i = 0; i < len; i++) {
-        sum += data[i];
-    }
-
-    return sum;
-}
-
-uint32_t acpi_find_rsdp_address(QTestState *qts)
-{
-    uint32_t off;
-
-    /* RSDP location can vary across a narrow range */
-    for (off = 0xf0000; off < 0x100000; off += 0x10) {
-        uint8_t sig[] = "RSD PTR ";
-        int i;
-
-        for (i = 0; i < sizeof sig - 1; ++i) {
-            sig[i] = qtest_readb(qts, off + i);
-        }
-
-        if (!memcmp(sig, "RSD PTR ", sizeof sig)) {
-            break;
-        }
-    }
-    return off;
-}
-
-void acpi_fetch_rsdp_table(QTestState *qts, uint64_t addr, uint8_t *rsdp_table)
-{
-    uint8_t revision;
-
-    /* Read mandatory revision 0 table data (20 bytes) first */
-    qtest_memread(qts, addr, rsdp_table, 20);
-    revision = rsdp_table[15 /* Revision offset */];
-
-    switch (revision) {
-    case 0: /* ACPI 1.0 RSDP */
-        break;
-    case 2: /* ACPI 2.0+ RSDP */
-        /* Read the rest of the RSDP table */
-        qtest_memread(qts, addr + 20, rsdp_table + 20, 16);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    ACPI_ASSERT_CMP64(*((uint64_t *)(rsdp_table)), "RSD PTR ");
-}
-
-/** acpi_fetch_table
- *  load ACPI table at @addr_ptr offset pointer into buffer and return it in
- *  @aml, its length in @aml_len and check that signature/checksum matches
- *  actual one.
- */
-void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
-                      const uint8_t *addr_ptr, int addr_size, const char *sig,
-                      bool verify_checksum)
-{
-    uint32_t len;
-    uint64_t addr = 0;
-
-    g_assert(addr_size == 4 || addr_size == 8);
-    memcpy(&addr, addr_ptr , addr_size);
-    addr = le64_to_cpu(addr);
-    qtest_memread(qts, addr + 4, &len, 4); /* Length of ACPI table */
-    *aml_len = le32_to_cpu(len);
-    *aml = g_malloc0(*aml_len);
-    /* get whole table */
-    qtest_memread(qts, addr, *aml, *aml_len);
-
-    if (sig) {
-        ACPI_ASSERT_CMP(**aml, sig);
-    }
-    if (verify_checksum) {
-        g_assert(!acpi_calc_checksum(*aml, *aml_len));
-    }
-}
-
-#define GUID_SIZE 16
-static const uint8_t AcpiTestSupportGuid[GUID_SIZE] = {
-       0xb1, 0xa6, 0x87, 0xab,
-       0x34, 0x20,
-       0xa0, 0xbd,
-       0x71, 0xbd, 0x37, 0x50, 0x07, 0x75, 0x77, 0x85 };
-
-typedef struct {
-    uint8_t signature_guid[GUID_SIZE];
-    uint64_t rsdp10;
-    uint64_t rsdp20;
-} __attribute__((packed)) UefiTestSupport;
-
-/* Wait at most 600 seconds (test is slow with TCG and --enable-debug) */
-#define TEST_DELAY (1 * G_USEC_PER_SEC / 10)
-#define TEST_CYCLES MAX((600 * G_USEC_PER_SEC / TEST_DELAY), 1)
-#define MB 0x100000ULL
-uint64_t acpi_find_rsdp_address_uefi(QTestState *qts, uint64_t start,
-                                     uint64_t size)
-{
-    int i, j;
-    uint8_t data[GUID_SIZE];
-
-    for (i = 0; i < TEST_CYCLES; ++i) {
-        for (j = 0; j < size / MB; j++) {
-            /* look for GUID at every 1Mb block */
-            uint64_t addr = start + j * MB;
-
-            qtest_memread(qts, addr, data, sizeof(data));
-            if (!memcmp(AcpiTestSupportGuid, data, sizeof(data))) {
-                UefiTestSupport ret;
-
-                qtest_memread(qts, addr, &ret, sizeof(ret));
-                ret.rsdp10 = le64_to_cpu(ret.rsdp10);
-                ret.rsdp20 = le64_to_cpu(ret.rsdp20);
-                return ret.rsdp20 ? ret.rsdp20 : ret.rsdp10;
-            }
-        }
-        g_usleep(TEST_DELAY);
-    }
-    g_assert_not_reached();
-    return 0;
-}
diff --git a/tests/acpi-utils.h b/tests/acpi-utils.h
deleted file mode 100644 (file)
index 0c86780..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Utilities for working with ACPI tables
- *
- * Copyright (c) 2013 Red Hat Inc.
- *
- * Authors:
- *  Michael S. Tsirkin <[email protected]>,
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef TEST_ACPI_UTILS_H
-#define TEST_ACPI_UTILS_H
-
-#include "libqtest.h"
-
-/* DSDT and SSDTs format */
-typedef struct {
-    uint8_t *aml;            /* aml bytecode from guest */
-    uint32_t aml_len;
-    gchar *aml_file;
-    gchar *asl;            /* asl code generated from aml */
-    gsize asl_len;
-    gchar *asl_file;
-    bool tmp_files_retain;   /* do not delete the temp asl/aml */
-} AcpiSdtTable;
-
-#define ACPI_ASSERT_CMP(actual, expected) do { \
-    char ACPI_ASSERT_CMP_str[5] = {}; \
-    memcpy(ACPI_ASSERT_CMP_str, &actual, 4); \
-    g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
-} while (0)
-
-#define ACPI_ASSERT_CMP64(actual, expected) do { \
-    char ACPI_ASSERT_CMP_str[9] = {}; \
-    memcpy(ACPI_ASSERT_CMP_str, &actual, 8); \
-    g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
-} while (0)
-
-
-#define ACPI_FOREACH_RSDT_ENTRY(table, table_len, entry_ptr, entry_size) \
-    for (entry_ptr = table + 36 /* 1st Entry */;                         \
-         entry_ptr < table + table_len;                                  \
-         entry_ptr += entry_size)
-
-uint8_t acpi_calc_checksum(const uint8_t *data, int len);
-uint32_t acpi_find_rsdp_address(QTestState *qts);
-uint64_t acpi_find_rsdp_address_uefi(QTestState *qts, uint64_t start,
-                                     uint64_t size);
-void acpi_fetch_rsdp_table(QTestState *qts, uint64_t addr, uint8_t *rsdp_table);
-void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
-                      const uint8_t *addr_ptr, int addr_size, const char *sig,
-                      bool verify_checksum);
-
-#endif /* TEST_ACPI_UTILS_H */
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
deleted file mode 100644 (file)
index c8d42ce..0000000
+++ /dev/null
@@ -1,1954 +0,0 @@
-/*
- * AHCI test cases
- *
- * Copyright (c) 2014 John Snow <[email protected]>
- *
- * 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 <getopt.h>
-
-#include "libqtest.h"
-#include "libqos/libqos-pc.h"
-#include "libqos/ahci.h"
-#include "libqos/pci-pc.h"
-
-#include "qemu-common.h"
-#include "qapi/qmp/qdict.h"
-#include "qemu/host-utils.h"
-
-#include "hw/pci/pci_ids.h"
-#include "hw/pci/pci_regs.h"
-
-/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(s, ...) qobject_unref(qtest_qmp(s, __VA_ARGS__))
-
-/* Test images sizes in MB */
-#define TEST_IMAGE_SIZE_MB_LARGE (200 * 1024)
-#define TEST_IMAGE_SIZE_MB_SMALL 64
-
-/*** Globals ***/
-static char tmp_path[] = "/tmp/qtest.XXXXXX";
-static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX";
-static char mig_socket[] = "/tmp/qtest-migration.XXXXXX";
-static bool ahci_pedantic;
-static const char *imgfmt;
-static unsigned test_image_size_mb;
-
-/*** Function Declarations ***/
-static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port);
-static void ahci_test_pci_spec(AHCIQState *ahci);
-static void ahci_test_pci_caps(AHCIQState *ahci, uint16_t header,
-                               uint8_t offset);
-static void ahci_test_satacap(AHCIQState *ahci, uint8_t offset);
-static void ahci_test_msicap(AHCIQState *ahci, uint8_t offset);
-static void ahci_test_pmcap(AHCIQState *ahci, uint8_t offset);
-
-/*** Utilities ***/
-
-static uint64_t mb_to_sectors(uint64_t image_size_mb)
-{
-    return (image_size_mb * 1024 * 1024) / AHCI_SECTOR_SIZE;
-}
-
-static void string_bswap16(uint16_t *s, size_t bytes)
-{
-    g_assert_cmphex((bytes & 1), ==, 0);
-    bytes /= 2;
-
-    while (bytes--) {
-        *s = bswap16(*s);
-        s++;
-    }
-}
-
-/**
- * Verify that the transfer did not corrupt our state at all.
- */
-static void verify_state(AHCIQState *ahci, uint64_t hba_old)
-{
-    int i, j;
-    uint32_t ahci_fingerprint;
-    uint64_t hba_base;
-    AHCICommandHeader cmd;
-
-    ahci_fingerprint = qpci_config_readl(ahci->dev, PCI_VENDOR_ID);
-    g_assert_cmphex(ahci_fingerprint, ==, ahci->fingerprint);
-
-    /* If we haven't initialized, this is as much as can be validated. */
-    if (!ahci->enabled) {
-        return;
-    }
-
-    hba_base = (uint64_t)qpci_config_readl(ahci->dev, PCI_BASE_ADDRESS_5);
-    g_assert_cmphex(hba_base, ==, hba_old);
-
-    g_assert_cmphex(ahci_rreg(ahci, AHCI_CAP), ==, ahci->cap);
-    g_assert_cmphex(ahci_rreg(ahci, AHCI_CAP2), ==, ahci->cap2);
-
-    for (i = 0; i < 32; i++) {
-        g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_FB), ==,
-                        ahci->port[i].fb);
-        g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_CLB), ==,
-                        ahci->port[i].clb);
-        for (j = 0; j < 32; j++) {
-            ahci_get_command_header(ahci, i, j, &cmd);
-            g_assert_cmphex(cmd.prdtl, ==, ahci->port[i].prdtl[j]);
-            g_assert_cmphex(cmd.ctba, ==, ahci->port[i].ctba[j]);
-        }
-    }
-}
-
-static void ahci_migrate(AHCIQState *from, AHCIQState *to, const char *uri)
-{
-    QOSState *tmp = to->parent;
-    QPCIDevice *dev = to->dev;
-    char *uri_local = NULL;
-    uint64_t hba_old;
-
-    if (uri == NULL) {
-        uri_local = g_strdup_printf("%s%s", "unix:", mig_socket);
-        uri = uri_local;
-    }
-
-    hba_old = (uint64_t)qpci_config_readl(from->dev, PCI_BASE_ADDRESS_5);
-
-    /* context will be 'to' after completion. */
-    migrate(from->parent, to->parent, uri);
-
-    /* We'd like for the AHCIState objects to still point
-     * to information specific to its specific parent
-     * instance, but otherwise just inherit the new data. */
-    memcpy(to, from, sizeof(AHCIQState));
-    to->parent = tmp;
-    to->dev = dev;
-
-    tmp = from->parent;
-    dev = from->dev;
-    memset(from, 0x00, sizeof(AHCIQState));
-    from->parent = tmp;
-    from->dev = dev;
-
-    verify_state(to, hba_old);
-    g_free(uri_local);
-}
-
-/*** Test Setup & Teardown ***/
-
-/**
- * Start a Q35 machine and bookmark a handle to the AHCI device.
- */
-static AHCIQState *ahci_vboot(const char *cli, va_list ap)
-{
-    AHCIQState *s;
-
-    s = g_new0(AHCIQState, 1);
-    s->parent = qtest_pc_vboot(cli, ap);
-    alloc_set_flags(&s->parent->alloc, ALLOC_LEAK_ASSERT);
-
-    /* Verify that we have an AHCI device present. */
-    s->dev = get_ahci_device(s->parent->qts, &s->fingerprint);
-
-    return s;
-}
-
-/**
- * Start a Q35 machine and bookmark a handle to the AHCI device.
- */
-static AHCIQState *ahci_boot(const char *cli, ...)
-{
-    AHCIQState *s;
-    va_list ap;
-
-    if (cli) {
-        va_start(ap, cli);
-        s = ahci_vboot(cli, ap);
-        va_end(ap);
-    } else {
-        cli = "-drive if=none,id=drive0,file=%s,cache=writeback,format=%s"
-            " -M q35 "
-            "-device ide-hd,drive=drive0 "
-            "-global ide-hd.serial=%s "
-            "-global ide-hd.ver=%s";
-        s = ahci_boot(cli, tmp_path, imgfmt, "testdisk", "version");
-    }
-
-    return s;
-}
-
-/**
- * Clean up the PCI device, then terminate the QEMU instance.
- */
-static void ahci_shutdown(AHCIQState *ahci)
-{
-    QOSState *qs = ahci->parent;
-
-    ahci_clean_mem(ahci);
-    free_ahci_device(ahci->dev);
-    g_free(ahci);
-    qtest_shutdown(qs);
-}
-
-/**
- * Boot and fully enable the HBA device.
- * @see ahci_boot, ahci_pci_enable and ahci_hba_enable.
- */
-static AHCIQState *ahci_boot_and_enable(const char *cli, ...)
-{
-    AHCIQState *ahci;
-    va_list ap;
-    uint16_t buff[256];
-    uint8_t port;
-    uint8_t hello;
-
-    if (cli) {
-        va_start(ap, cli);
-        ahci = ahci_vboot(cli, ap);
-        va_end(ap);
-    } else {
-        ahci = ahci_boot(NULL);
-    }
-
-    ahci_pci_enable(ahci);
-    ahci_hba_enable(ahci);
-    /* Initialize test device */
-    port = ahci_port_select(ahci);
-    ahci_port_clear(ahci, port);
-    if (is_atapi(ahci, port)) {
-        hello = CMD_PACKET_ID;
-    } else {
-        hello = CMD_IDENTIFY;
-    }
-    ahci_io(ahci, port, hello, &buff, sizeof(buff), 0);
-
-    return ahci;
-}
-
-/*** Specification Adherence Tests ***/
-
-/**
- * Implementation for test_pci_spec. Ensures PCI configuration space is sane.
- */
-static void ahci_test_pci_spec(AHCIQState *ahci)
-{
-    uint8_t datab;
-    uint16_t data;
-    uint32_t datal;
-
-    /* Most of these bits should start cleared until we turn them on. */
-    data = qpci_config_readw(ahci->dev, PCI_COMMAND);
-    ASSERT_BIT_CLEAR(data, PCI_COMMAND_MEMORY);
-    ASSERT_BIT_CLEAR(data, PCI_COMMAND_MASTER);
-    ASSERT_BIT_CLEAR(data, PCI_COMMAND_SPECIAL);     /* Reserved */
-    ASSERT_BIT_CLEAR(data, PCI_COMMAND_VGA_PALETTE); /* Reserved */
-    ASSERT_BIT_CLEAR(data, PCI_COMMAND_PARITY);
-    ASSERT_BIT_CLEAR(data, PCI_COMMAND_WAIT);        /* Reserved */
-    ASSERT_BIT_CLEAR(data, PCI_COMMAND_SERR);
-    ASSERT_BIT_CLEAR(data, PCI_COMMAND_FAST_BACK);
-    ASSERT_BIT_CLEAR(data, PCI_COMMAND_INTX_DISABLE);
-    ASSERT_BIT_CLEAR(data, 0xF800);                  /* Reserved */
-
-    data = qpci_config_readw(ahci->dev, PCI_STATUS);
-    ASSERT_BIT_CLEAR(data, 0x01 | 0x02 | 0x04);     /* Reserved */
-    ASSERT_BIT_CLEAR(data, PCI_STATUS_INTERRUPT);
-    ASSERT_BIT_SET(data, PCI_STATUS_CAP_LIST);      /* must be set */
-    ASSERT_BIT_CLEAR(data, PCI_STATUS_UDF);         /* Reserved */
-    ASSERT_BIT_CLEAR(data, PCI_STATUS_PARITY);
-    ASSERT_BIT_CLEAR(data, PCI_STATUS_SIG_TARGET_ABORT);
-    ASSERT_BIT_CLEAR(data, PCI_STATUS_REC_TARGET_ABORT);
-    ASSERT_BIT_CLEAR(data, PCI_STATUS_REC_MASTER_ABORT);
-    ASSERT_BIT_CLEAR(data, PCI_STATUS_SIG_SYSTEM_ERROR);
-    ASSERT_BIT_CLEAR(data, PCI_STATUS_DETECTED_PARITY);
-
-    /* RID occupies the low byte, CCs occupy the high three. */
-    datal = qpci_config_readl(ahci->dev, PCI_CLASS_REVISION);
-    if (ahci_pedantic) {
-        /* AHCI 1.3 specifies that at-boot, the RID should reset to 0x00,
-         * Though in practice this is likely seldom true. */
-        ASSERT_BIT_CLEAR(datal, 0xFF);
-    }
-
-    /* BCC *must* equal 0x01. */
-    g_assert_cmphex(PCI_BCC(datal), ==, 0x01);
-    if (PCI_SCC(datal) == 0x01) {
-        /* IDE */
-        ASSERT_BIT_SET(0x80000000, datal);
-        ASSERT_BIT_CLEAR(0x60000000, datal);
-    } else if (PCI_SCC(datal) == 0x04) {
-        /* RAID */
-        g_assert_cmphex(PCI_PI(datal), ==, 0);
-    } else if (PCI_SCC(datal) == 0x06) {
-        /* AHCI */
-        g_assert_cmphex(PCI_PI(datal), ==, 0x01);
-    } else {
-        g_assert_not_reached();
-    }
-
-    datab = qpci_config_readb(ahci->dev, PCI_CACHE_LINE_SIZE);
-    g_assert_cmphex(datab, ==, 0);
-
-    datab = qpci_config_readb(ahci->dev, PCI_LATENCY_TIMER);
-    g_assert_cmphex(datab, ==, 0);
-
-    /* Only the bottom 7 bits must be off. */
-    datab = qpci_config_readb(ahci->dev, PCI_HEADER_TYPE);
-    ASSERT_BIT_CLEAR(datab, 0x7F);
-
-    /* BIST is optional, but the low 7 bits must always start off regardless. */
-    datab = qpci_config_readb(ahci->dev, PCI_BIST);
-    ASSERT_BIT_CLEAR(datab, 0x7F);
-
-    /* BARS 0-4 do not have a boot spec, but ABAR/BAR5 must be clean. */
-    datal = qpci_config_readl(ahci->dev, PCI_BASE_ADDRESS_5);
-    g_assert_cmphex(datal, ==, 0);
-
-    qpci_config_writel(ahci->dev, PCI_BASE_ADDRESS_5, 0xFFFFFFFF);
-    datal = qpci_config_readl(ahci->dev, PCI_BASE_ADDRESS_5);
-    /* ABAR must be 32-bit, memory mapped, non-prefetchable and
-     * must be >= 512 bytes. To that end, bits 0-8 must be off. */
-    ASSERT_BIT_CLEAR(datal, 0xFF);
-
-    /* Capability list MUST be present, */
-    datal = qpci_config_readl(ahci->dev, PCI_CAPABILITY_LIST);
-    /* But these bits are reserved. */
-    ASSERT_BIT_CLEAR(datal, ~0xFF);
-    g_assert_cmphex(datal, !=, 0);
-
-    /* Check specification adherence for capability extenstions. */
-    data = qpci_config_readw(ahci->dev, datal);
-
-    switch (ahci->fingerprint) {
-    case AHCI_INTEL_ICH9:
-        /* Intel ICH9 Family Datasheet 14.1.19 p.550 */
-        g_assert_cmphex((data & 0xFF), ==, PCI_CAP_ID_MSI);
-        break;
-    default:
-        /* AHCI 1.3, Section 2.1.14 -- CAP must point to PMCAP. */
-        g_assert_cmphex((data & 0xFF), ==, PCI_CAP_ID_PM);
-    }
-
-    ahci_test_pci_caps(ahci, data, (uint8_t)datal);
-
-    /* Reserved. */
-    datal = qpci_config_readl(ahci->dev, PCI_CAPABILITY_LIST + 4);
-    g_assert_cmphex(datal, ==, 0);
-
-    /* IPIN might vary, but ILINE must be off. */
-    datab = qpci_config_readb(ahci->dev, PCI_INTERRUPT_LINE);
-    g_assert_cmphex(datab, ==, 0);
-}
-
-/**
- * Test PCI capabilities for AHCI specification adherence.
- */
-static void ahci_test_pci_caps(AHCIQState *ahci, uint16_t header,
-                               uint8_t offset)
-{
-    uint8_t cid = header & 0xFF;
-    uint8_t next = header >> 8;
-
-    g_test_message("CID: %02x; next: %02x", cid, next);
-
-    switch (cid) {
-    case PCI_CAP_ID_PM:
-        ahci_test_pmcap(ahci, offset);
-        break;
-    case PCI_CAP_ID_MSI:
-        ahci_test_msicap(ahci, offset);
-        break;
-    case PCI_CAP_ID_SATA:
-        ahci_test_satacap(ahci, offset);
-        break;
-
-    default:
-        g_test_message("Unknown CAP 0x%02x", cid);
-    }
-
-    if (next) {
-        ahci_test_pci_caps(ahci, qpci_config_readw(ahci->dev, next), next);
-    }
-}
-
-/**
- * Test SATA PCI capabilitity for AHCI specification adherence.
- */
-static void ahci_test_satacap(AHCIQState *ahci, uint8_t offset)
-{
-    uint16_t dataw;
-    uint32_t datal;
-
-    g_test_message("Verifying SATACAP");
-
-    /* Assert that the SATACAP version is 1.0, And reserved bits are empty. */
-    dataw = qpci_config_readw(ahci->dev, offset + 2);
-    g_assert_cmphex(dataw, ==, 0x10);
-
-    /* Grab the SATACR1 register. */
-    datal = qpci_config_readw(ahci->dev, offset + 4);
-
-    switch (datal & 0x0F) {
-    case 0x04: /* BAR0 */
-    case 0x05: /* BAR1 */
-    case 0x06:
-    case 0x07:
-    case 0x08:
-    case 0x09: /* BAR5 */
-    case 0x0F: /* Immediately following SATACR1 in PCI config space. */
-        break;
-    default:
-        /* Invalid BARLOC for the Index Data Pair. */
-        g_assert_not_reached();
-    }
-
-    /* Reserved. */
-    g_assert_cmphex((datal >> 24), ==, 0x00);
-}
-
-/**
- * Test MSI PCI capability for AHCI specification adherence.
- */
-static void ahci_test_msicap(AHCIQState *ahci, uint8_t offset)
-{
-    uint16_t dataw;
-    uint32_t datal;
-
-    g_test_message("Verifying MSICAP");
-
-    dataw = qpci_config_readw(ahci->dev, offset + PCI_MSI_FLAGS);
-    ASSERT_BIT_CLEAR(dataw, PCI_MSI_FLAGS_ENABLE);
-    ASSERT_BIT_CLEAR(dataw, PCI_MSI_FLAGS_QSIZE);
-    ASSERT_BIT_CLEAR(dataw, PCI_MSI_FLAGS_RESERVED);
-
-    datal = qpci_config_readl(ahci->dev, offset + PCI_MSI_ADDRESS_LO);
-    g_assert_cmphex(datal, ==, 0);
-
-    if (dataw & PCI_MSI_FLAGS_64BIT) {
-        g_test_message("MSICAP is 64bit");
-        datal = qpci_config_readl(ahci->dev, offset + PCI_MSI_ADDRESS_HI);
-        g_assert_cmphex(datal, ==, 0);
-        dataw = qpci_config_readw(ahci->dev, offset + PCI_MSI_DATA_64);
-        g_assert_cmphex(dataw, ==, 0);
-    } else {
-        g_test_message("MSICAP is 32bit");
-        dataw = qpci_config_readw(ahci->dev, offset + PCI_MSI_DATA_32);
-        g_assert_cmphex(dataw, ==, 0);
-    }
-}
-
-/**
- * Test Power Management PCI capability for AHCI specification adherence.
- */
-static void ahci_test_pmcap(AHCIQState *ahci, uint8_t offset)
-{
-    uint16_t dataw;
-
-    g_test_message("Verifying PMCAP");
-
-    dataw = qpci_config_readw(ahci->dev, offset + PCI_PM_PMC);
-    ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_PME_CLOCK);
-    ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_RESERVED);
-    ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_D1);
-    ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_D2);
-
-    dataw = qpci_config_readw(ahci->dev, offset + PCI_PM_CTRL);
-    ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_STATE_MASK);
-    ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_RESERVED);
-    ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_DATA_SEL_MASK);
-    ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_DATA_SCALE_MASK);
-}
-
-static void ahci_test_hba_spec(AHCIQState *ahci)
-{
-    unsigned i;
-    uint32_t reg;
-    uint32_t ports;
-    uint8_t nports_impl;
-    uint8_t maxports;
-
-    g_assert(ahci != NULL);
-
-    /*
-     * Note that the AHCI spec does expect the BIOS to set up a few things:
-     * CAP.SSS    - Support for staggered spin-up            (t/f)
-     * CAP.SMPS   - Support for mechanical presence switches (t/f)
-     * PI         - Ports Implemented                        (1-32)
-     * PxCMD.HPCP - Hot Plug Capable Port
-     * PxCMD.MPSP - Mechanical Presence Switch Present
-     * PxCMD.CPD  - Cold Presence Detection support
-     *
-     * Additional items are touched if CAP.SSS is on, see AHCI 10.1.1 p.97:
-     * Foreach Port Implemented:
-     * -PxCMD.ST, PxCMD.CR, PxCMD.FRE, PxCMD.FR, PxSCTL.DET are 0
-     * -PxCLB/U and PxFB/U are set to valid regions in memory
-     * -PxSUD is set to 1.
-     * -PxSSTS.DET is polled for presence; if detected, we continue:
-     * -PxSERR is cleared with 1's.
-     * -If PxTFD.STS.BSY, PxTFD.STS.DRQ, and PxTFD.STS.ERR are all zero,
-     *  the device is ready.
-     */
-
-    /* 1 CAP - Capabilities Register */
-    ahci->cap = ahci_rreg(ahci, AHCI_CAP);
-    ASSERT_BIT_CLEAR(ahci->cap, AHCI_CAP_RESERVED);
-
-    /* 2 GHC - Global Host Control */
-    reg = ahci_rreg(ahci, AHCI_GHC);
-    ASSERT_BIT_CLEAR(reg, AHCI_GHC_HR);
-    ASSERT_BIT_CLEAR(reg, AHCI_GHC_IE);
-    ASSERT_BIT_CLEAR(reg, AHCI_GHC_MRSM);
-    if (BITSET(ahci->cap, AHCI_CAP_SAM)) {
-        g_test_message("Supports AHCI-Only Mode: GHC_AE is Read-Only.");
-        ASSERT_BIT_SET(reg, AHCI_GHC_AE);
-    } else {
-        g_test_message("Supports AHCI/Legacy mix.");
-        ASSERT_BIT_CLEAR(reg, AHCI_GHC_AE);
-    }
-
-    /* 3 IS - Interrupt Status */
-    reg = ahci_rreg(ahci, AHCI_IS);
-    g_assert_cmphex(reg, ==, 0);
-
-    /* 4 PI - Ports Implemented */
-    ports = ahci_rreg(ahci, AHCI_PI);
-    /* Ports Implemented must be non-zero. */
-    g_assert_cmphex(ports, !=, 0);
-    /* Ports Implemented must be <= Number of Ports. */
-    nports_impl = ctpopl(ports);
-    g_assert_cmpuint(((AHCI_CAP_NP & ahci->cap) + 1), >=, nports_impl);
-
-    /* Ports must be within the proper range. Given a mapping of SIZE,
-     * 256 bytes are used for global HBA control, and the rest is used
-     * for ports data, at 0x80 bytes each. */
-    g_assert_cmphex(ahci->barsize, >, 0);
-    maxports = (ahci->barsize - HBA_DATA_REGION_SIZE) / HBA_PORT_DATA_SIZE;
-    /* e.g, 30 ports for 4K of memory. (4096 - 256) / 128 = 30 */
-    g_assert_cmphex((reg >> maxports), ==, 0);
-
-    /* 5 AHCI Version */
-    reg = ahci_rreg(ahci, AHCI_VS);
-    switch (reg) {
-    case AHCI_VERSION_0_95:
-    case AHCI_VERSION_1_0:
-    case AHCI_VERSION_1_1:
-    case AHCI_VERSION_1_2:
-    case AHCI_VERSION_1_3:
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    /* 6 Command Completion Coalescing Control: depends on CAP.CCCS. */
-    reg = ahci_rreg(ahci, AHCI_CCCCTL);
-    if (BITSET(ahci->cap, AHCI_CAP_CCCS)) {
-        ASSERT_BIT_CLEAR(reg, AHCI_CCCCTL_EN);
-        ASSERT_BIT_CLEAR(reg, AHCI_CCCCTL_RESERVED);
-        ASSERT_BIT_SET(reg, AHCI_CCCCTL_CC);
-        ASSERT_BIT_SET(reg, AHCI_CCCCTL_TV);
-    } else {
-        g_assert_cmphex(reg, ==, 0);
-    }
-
-    /* 7 CCC_PORTS */
-    reg = ahci_rreg(ahci, AHCI_CCCPORTS);
-    /* Must be zeroes initially regardless of CAP.CCCS */
-    g_assert_cmphex(reg, ==, 0);
-
-    /* 8 EM_LOC */
-    reg = ahci_rreg(ahci, AHCI_EMLOC);
-    if (BITCLR(ahci->cap, AHCI_CAP_EMS)) {
-        g_assert_cmphex(reg, ==, 0);
-    }
-
-    /* 9 EM_CTL */
-    reg = ahci_rreg(ahci, AHCI_EMCTL);
-    if (BITSET(ahci->cap, AHCI_CAP_EMS)) {
-        ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_STSMR);
-        ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_CTLTM);
-        ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_CTLRST);
-        ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_RESERVED);
-    } else {
-        g_assert_cmphex(reg, ==, 0);
-    }
-
-    /* 10 CAP2 -- Capabilities Extended */
-    ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2);
-    ASSERT_BIT_CLEAR(ahci->cap2, AHCI_CAP2_RESERVED);
-
-    /* 11 BOHC -- Bios/OS Handoff Control */
-    reg = ahci_rreg(ahci, AHCI_BOHC);
-    g_assert_cmphex(reg, ==, 0);
-
-    /* 12 -- 23: Reserved */
-    g_test_message("Verifying HBA reserved area is empty.");
-    for (i = AHCI_RESERVED; i < AHCI_NVMHCI; ++i) {
-        reg = ahci_rreg(ahci, i);
-        g_assert_cmphex(reg, ==, 0);
-    }
-
-    /* 24 -- 39: NVMHCI */
-    if (BITCLR(ahci->cap2, AHCI_CAP2_NVMP)) {
-        g_test_message("Verifying HBA/NVMHCI area is empty.");
-        for (i = AHCI_NVMHCI; i < AHCI_VENDOR; ++i) {
-            reg = ahci_rreg(ahci, i);
-            g_assert_cmphex(reg, ==, 0);
-        }
-    }
-
-    /* 40 -- 63: Vendor */
-    g_test_message("Verifying HBA/Vendor area is empty.");
-    for (i = AHCI_VENDOR; i < AHCI_PORTS; ++i) {
-        reg = ahci_rreg(ahci, i);
-        g_assert_cmphex(reg, ==, 0);
-    }
-
-    /* 64 -- XX: Port Space */
-    for (i = 0; ports || (i < maxports); ports >>= 1, ++i) {
-        if (BITSET(ports, 0x1)) {
-            g_test_message("Testing port %u for spec", i);
-            ahci_test_port_spec(ahci, i);
-        } else {
-            uint16_t j;
-            uint16_t low = AHCI_PORTS + (32 * i);
-            uint16_t high = AHCI_PORTS + (32 * (i + 1));
-            g_test_message("Asserting unimplemented port %u "
-                           "(reg [%u-%u]) is empty.",
-                           i, low, high - 1);
-            for (j = low; j < high; ++j) {
-                reg = ahci_rreg(ahci, j);
-                g_assert_cmphex(reg, ==, 0);
-            }
-        }
-    }
-}
-
-/**
- * Test the memory space for one port for specification adherence.
- */
-static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port)
-{
-    uint32_t reg;
-    unsigned i;
-
-    /* (0) CLB */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_CLB);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_CLB_RESERVED);
-
-    /* (1) CLBU */
-    if (BITCLR(ahci->cap, AHCI_CAP_S64A)) {
-        reg = ahci_px_rreg(ahci, port, AHCI_PX_CLBU);
-        g_assert_cmphex(reg, ==, 0);
-    }
-
-    /* (2) FB */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_FB);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_FB_RESERVED);
-
-    /* (3) FBU */
-    if (BITCLR(ahci->cap, AHCI_CAP_S64A)) {
-        reg = ahci_px_rreg(ahci, port, AHCI_PX_FBU);
-        g_assert_cmphex(reg, ==, 0);
-    }
-
-    /* (4) IS */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_IS);
-    g_assert_cmphex(reg, ==, 0);
-
-    /* (5) IE */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_IE);
-    g_assert_cmphex(reg, ==, 0);
-
-    /* (6) CMD */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_CMD);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FRE);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_RESERVED);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CCS);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FR);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CR);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_PMA); /* And RW only if CAP.SPM */
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_APSTE); /* RW only if CAP2.APST */
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_ATAPI);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_DLAE);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_ALPE);  /* RW only if CAP.SALP */
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_ASP);   /* RW only if CAP.SALP */
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_ICC);
-    /* If CPDetect support does not exist, CPState must be off. */
-    if (BITCLR(reg, AHCI_PX_CMD_CPD)) {
-        ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CPS);
-    }
-    /* If MPSPresence is not set, MPSState must be off. */
-    if (BITCLR(reg, AHCI_PX_CMD_MPSP)) {
-        ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_MPSS);
-    }
-    /* If we do not support MPS, MPSS and MPSP must be off. */
-    if (BITCLR(ahci->cap, AHCI_CAP_SMPS)) {
-        ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_MPSS);
-        ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_MPSP);
-    }
-    /* If, via CPD or MPSP we detect a drive, HPCP must be on. */
-    if (BITANY(reg, AHCI_PX_CMD_CPD | AHCI_PX_CMD_MPSP)) {
-        ASSERT_BIT_SET(reg, AHCI_PX_CMD_HPCP);
-    }
-    /* HPCP and ESP cannot both be active. */
-    g_assert(!BITSET(reg, AHCI_PX_CMD_HPCP | AHCI_PX_CMD_ESP));
-    /* If CAP.FBSS is not set, FBSCP must not be set. */
-    if (BITCLR(ahci->cap, AHCI_CAP_FBSS)) {
-        ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FBSCP);
-    }
-
-    /* (7) RESERVED */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_RES1);
-    g_assert_cmphex(reg, ==, 0);
-
-    /* (8) TFD */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD);
-    /* At boot, prior to an FIS being received, the TFD register should be 0x7F,
-     * which breaks down as follows, as seen in AHCI 1.3 sec 3.3.8, p. 27. */
-    ASSERT_BIT_SET(reg, AHCI_PX_TFD_STS_ERR);
-    ASSERT_BIT_SET(reg, AHCI_PX_TFD_STS_CS1);
-    ASSERT_BIT_SET(reg, AHCI_PX_TFD_STS_DRQ);
-    ASSERT_BIT_SET(reg, AHCI_PX_TFD_STS_CS2);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_BSY);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_RESERVED);
-
-    /* (9) SIG */
-    /* Though AHCI specifies the boot value should be 0xFFFFFFFF,
-     * Even when GHC.ST is zero, the AHCI HBA may receive the initial
-     * D2H register FIS and update the signature asynchronously,
-     * so we cannot expect a value here. AHCI 1.3, sec 3.3.9, pp 27-28 */
-
-    /* (10) SSTS / SCR0: SStatus */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_SSTS);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_SSTS_RESERVED);
-    /* Even though the register should be 0 at boot, it is asynchronous and
-     * prone to change, so we cannot test any well known value. */
-
-    /* (11) SCTL / SCR2: SControl */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_SCTL);
-    g_assert_cmphex(reg, ==, 0);
-
-    /* (12) SERR / SCR1: SError */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_SERR);
-    g_assert_cmphex(reg, ==, 0);
-
-    /* (13) SACT / SCR3: SActive */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_SACT);
-    g_assert_cmphex(reg, ==, 0);
-
-    /* (14) CI */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_CI);
-    g_assert_cmphex(reg, ==, 0);
-
-    /* (15) SNTF */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_SNTF);
-    g_assert_cmphex(reg, ==, 0);
-
-    /* (16) FBS */
-    reg = ahci_px_rreg(ahci, port, AHCI_PX_FBS);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_EN);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_DEC);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_SDE);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_DEV);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_DWE);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_RESERVED);
-    if (BITSET(ahci->cap, AHCI_CAP_FBSS)) {
-        /* if Port-Multiplier FIS-based switching avail, ADO must >= 2 */
-        g_assert((reg & AHCI_PX_FBS_ADO) >> ctzl(AHCI_PX_FBS_ADO) >= 2);
-    }
-
-    /* [17 -- 27] RESERVED */
-    for (i = AHCI_PX_RES2; i < AHCI_PX_VS; ++i) {
-        reg = ahci_px_rreg(ahci, port, i);
-        g_assert_cmphex(reg, ==, 0);
-    }
-
-    /* [28 -- 31] Vendor-Specific */
-    for (i = AHCI_PX_VS; i < 32; ++i) {
-        reg = ahci_px_rreg(ahci, port, i);
-        if (reg) {
-            g_test_message("INFO: Vendor register %u non-empty", i);
-        }
-    }
-}
-
-/**
- * Utilizing an initialized AHCI HBA, issue an IDENTIFY command to the first
- * device we see, then read and check the response.
- */
-static void ahci_test_identify(AHCIQState *ahci)
-{
-    uint16_t buff[256];
-    unsigned px;
-    int rc;
-    uint16_t sect_size;
-    const size_t buffsize = 512;
-
-    g_assert(ahci != NULL);
-
-    /**
-     * This serves as a bit of a tutorial on AHCI device programming:
-     *
-     * (1) Create a data buffer for the IDENTIFY response to be sent to
-     * (2) Create a Command Table buffer, where we will store the
-     *     command and PRDT (Physical Region Descriptor Table)
-     * (3) Construct an FIS host-to-device command structure, and write it to
-     *     the top of the Command Table buffer.
-     * (4) Create one or more Physical Region Descriptors (PRDs) that describe
-     *     a location in memory where data may be stored/retrieved.
-     * (5) Write these PRDTs to the bottom (offset 0x80) of the Command Table.
-     * (6) Each AHCI port has up to 32 command slots. Each slot contains a
-     *     header that points to a Command Table buffer. Pick an unused slot
-     *     and update it to point to the Command Table we have built.
-     * (7) Now: Command #n points to our Command Table, and our Command Table
-     *     contains the FIS (that describes our command) and the PRDTL, which
-     *     describes our buffer.
-     * (8) We inform the HBA via PxCI (Command Issue) that the command in slot
-     *     #n is ready for processing.
-     */
-
-    /* Pick the first implemented and running port */
-    px = ahci_port_select(ahci);
-    g_test_message("Selected port %u for test", px);
-
-    /* Clear out the FIS Receive area and any pending interrupts. */
-    ahci_port_clear(ahci, px);
-
-    /* "Read" 512 bytes using CMD_IDENTIFY into the host buffer. */
-    ahci_io(ahci, px, CMD_IDENTIFY, &buff, buffsize, 0);
-
-    /* Check serial number/version in the buffer */
-    /* NB: IDENTIFY strings are packed in 16bit little endian chunks.
-     * Since we copy byte-for-byte in ahci-test, on both LE and BE, we need to
-     * unchunk this data. By contrast, ide-test copies 2 bytes at a time, and
-     * as a consequence, only needs to unchunk the data on LE machines. */
-    string_bswap16(&buff[10], 20);
-    rc = memcmp(&buff[10], "testdisk            ", 20);
-    g_assert_cmphex(rc, ==, 0);
-
-    string_bswap16(&buff[23], 8);
-    rc = memcmp(&buff[23], "version ", 8);
-    g_assert_cmphex(rc, ==, 0);
-
-    sect_size = le16_to_cpu(*((uint16_t *)(&buff[5])));
-    g_assert_cmphex(sect_size, ==, AHCI_SECTOR_SIZE);
-}
-
-static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize,
-                                   uint64_t sector, uint8_t read_cmd,
-                                   uint8_t write_cmd)
-{
-    uint64_t ptr;
-    uint8_t port;
-    unsigned char *tx = g_malloc(bufsize);
-    unsigned char *rx = g_malloc0(bufsize);
-
-    g_assert(ahci != NULL);
-
-    /* Pick the first running port and clear it. */
-    port = ahci_port_select(ahci);
-    ahci_port_clear(ahci, port);
-
-    /*** Create pattern and transfer to guest ***/
-    /* Data buffer in the guest */
-    ptr = ahci_alloc(ahci, bufsize);
-    g_assert(ptr);
-
-    /* Write some indicative pattern to our buffer. */
-    generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
-    qtest_bufwrite(ahci->parent->qts, ptr, tx, bufsize);
-
-    /* Write this buffer to disk, then read it back to the DMA buffer. */
-    ahci_guest_io(ahci, port, write_cmd, ptr, bufsize, sector);
-    qtest_memset(ahci->parent->qts, ptr, 0x00, bufsize);
-    ahci_guest_io(ahci, port, read_cmd, ptr, bufsize, sector);
-
-    /*** Read back the Data ***/
-    qtest_bufread(ahci->parent->qts, ptr, rx, bufsize);
-    g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
-
-    ahci_free(ahci, ptr);
-    g_free(tx);
-    g_free(rx);
-}
-
-static uint8_t ahci_test_nondata(AHCIQState *ahci, uint8_t ide_cmd)
-{
-    uint8_t port;
-
-    /* Sanitize */
-    port = ahci_port_select(ahci);
-    ahci_port_clear(ahci, port);
-
-    ahci_io(ahci, port, ide_cmd, NULL, 0, 0);
-
-    return port;
-}
-
-static void ahci_test_flush(AHCIQState *ahci)
-{
-    ahci_test_nondata(ahci, CMD_FLUSH_CACHE);
-}
-
-static void ahci_test_max(AHCIQState *ahci)
-{
-    RegD2HFIS *d2h = g_malloc0(0x20);
-    uint64_t nsect;
-    uint8_t port;
-    uint8_t cmd;
-    uint64_t config_sect = mb_to_sectors(test_image_size_mb) - 1;
-
-    if (config_sect > 0xFFFFFF) {
-        cmd = CMD_READ_MAX_EXT;
-    } else {
-        cmd = CMD_READ_MAX;
-    }
-
-    port = ahci_test_nondata(ahci, cmd);
-    qtest_memread(ahci->parent->qts, ahci->port[port].fb + 0x40, d2h, 0x20);
-    nsect = (uint64_t)d2h->lba_hi[2] << 40 |
-        (uint64_t)d2h->lba_hi[1] << 32 |
-        (uint64_t)d2h->lba_hi[0] << 24 |
-        (uint64_t)d2h->lba_lo[2] << 16 |
-        (uint64_t)d2h->lba_lo[1] << 8 |
-        (uint64_t)d2h->lba_lo[0];
-
-    g_assert_cmphex(nsect, ==, config_sect);
-    g_free(d2h);
-}
-
-
-/******************************************************************************/
-/* Test Interfaces                                                            */
-/******************************************************************************/
-
-/**
- * Basic sanity test to boot a machine, find an AHCI device, and shutdown.
- */
-static void test_sanity(void)
-{
-    AHCIQState *ahci;
-    ahci = ahci_boot(NULL);
-    ahci_shutdown(ahci);
-}
-
-/**
- * Ensure that the PCI configuration space for the AHCI device is in-line with
- * the AHCI 1.3 specification for initial values.
- */
-static void test_pci_spec(void)
-{
-    AHCIQState *ahci;
-    ahci = ahci_boot(NULL);
-    ahci_test_pci_spec(ahci);
-    ahci_shutdown(ahci);
-}
-
-/**
- * Engage the PCI AHCI device and sanity check the response.
- * Perform additional PCI config space bringup for the HBA.
- */
-static void test_pci_enable(void)
-{
-    AHCIQState *ahci;
-    ahci = ahci_boot(NULL);
-    ahci_pci_enable(ahci);
-    ahci_shutdown(ahci);
-}
-
-/**
- * Investigate the memory mapped regions of the HBA,
- * and test them for AHCI specification adherence.
- */
-static void test_hba_spec(void)
-{
-    AHCIQState *ahci;
-
-    ahci = ahci_boot(NULL);
-    ahci_pci_enable(ahci);
-    ahci_test_hba_spec(ahci);
-    ahci_shutdown(ahci);
-}
-
-/**
- * Engage the HBA functionality of the AHCI PCI device,
- * and bring it into a functional idle state.
- */
-static void test_hba_enable(void)
-{
-    AHCIQState *ahci;
-
-    ahci = ahci_boot(NULL);
-    ahci_pci_enable(ahci);
-    ahci_hba_enable(ahci);
-    ahci_shutdown(ahci);
-}
-
-/**
- * Bring up the device and issue an IDENTIFY command.
- * Inspect the state of the HBA device and the data returned.
- */
-static void test_identify(void)
-{
-    AHCIQState *ahci;
-
-    ahci = ahci_boot_and_enable(NULL);
-    ahci_test_identify(ahci);
-    ahci_shutdown(ahci);
-}
-
-/**
- * Fragmented DMA test: Perform a standard 4K DMA read/write
- * test, but make sure the physical regions are fragmented to
- * be very small, each just 32 bytes, to see how AHCI performs
- * with chunks defined to be much less than a sector.
- */
-static void test_dma_fragmented(void)
-{
-    AHCIQState *ahci;
-    AHCICommand *cmd;
-    uint8_t px;
-    size_t bufsize = 4096;
-    unsigned char *tx = g_malloc(bufsize);
-    unsigned char *rx = g_malloc0(bufsize);
-    uint64_t ptr;
-
-    ahci = ahci_boot_and_enable(NULL);
-    px = ahci_port_select(ahci);
-    ahci_port_clear(ahci, px);
-
-    /* create pattern */
-    generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
-
-    /* Create a DMA buffer in guest memory, and write our pattern to it. */
-    ptr = guest_alloc(&ahci->parent->alloc, bufsize);
-    g_assert(ptr);
-    qtest_bufwrite(ahci->parent->qts, ptr, tx, bufsize);
-
-    cmd = ahci_command_create(CMD_WRITE_DMA);
-    ahci_command_adjust(cmd, 0, ptr, bufsize, 32);
-    ahci_command_commit(ahci, cmd, px);
-    ahci_command_issue(ahci, cmd);
-    ahci_command_verify(ahci, cmd);
-    ahci_command_free(cmd);
-
-    cmd = ahci_command_create(CMD_READ_DMA);
-    ahci_command_adjust(cmd, 0, ptr, bufsize, 32);
-    ahci_command_commit(ahci, cmd, px);
-    ahci_command_issue(ahci, cmd);
-    ahci_command_verify(ahci, cmd);
-    ahci_command_free(cmd);
-
-    /* Read back the guest's receive buffer into local memory */
-    qtest_bufread(ahci->parent->qts, ptr, rx, bufsize);
-    guest_free(&ahci->parent->alloc, ptr);
-
-    g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
-
-    ahci_shutdown(ahci);
-
-    g_free(rx);
-    g_free(tx);
-}
-
-/*
- * Write sector 1 with random data to make AHCI storage dirty
- * Needed for flush tests so that flushes actually go though the block layer
- */
-static void make_dirty(AHCIQState* ahci, uint8_t port)
-{
-    uint64_t ptr;
-    unsigned bufsize = 512;
-
-    ptr = ahci_alloc(ahci, bufsize);
-    g_assert(ptr);
-
-    ahci_guest_io(ahci, port, CMD_WRITE_DMA, ptr, bufsize, 1);
-    ahci_free(ahci, ptr);
-}
-
-static void test_flush(void)
-{
-    AHCIQState *ahci;
-    uint8_t port;
-
-    ahci = ahci_boot_and_enable(NULL);
-
-    port = ahci_port_select(ahci);
-    ahci_port_clear(ahci, port);
-
-    make_dirty(ahci, port);
-
-    ahci_test_flush(ahci);
-    ahci_shutdown(ahci);
-}
-
-static void test_flush_retry(void)
-{
-    AHCIQState *ahci;
-    AHCICommand *cmd;
-    uint8_t port;
-
-    prepare_blkdebug_script(debug_path, "flush_to_disk");
-    ahci = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0,"
-                                "format=%s,cache=writeback,"
-                                "rerror=stop,werror=stop "
-                                "-M q35 "
-                                "-device ide-hd,drive=drive0 ",
-                                debug_path,
-                                tmp_path, imgfmt);
-
-    port = ahci_port_select(ahci);
-    ahci_port_clear(ahci, port);
-
-    /* Issue write so that flush actually goes to disk */
-    make_dirty(ahci, port);
-
-    /* Issue Flush Command and wait for error */
-    cmd = ahci_guest_io_halt(ahci, port, CMD_FLUSH_CACHE, 0, 0, 0);
-    ahci_guest_io_resume(ahci, cmd);
-
-    ahci_shutdown(ahci);
-}
-
-/**
- * Basic sanity test to boot a machine, find an AHCI device, and shutdown.
- */
-static void test_migrate_sanity(void)
-{
-    AHCIQState *src, *dst;
-    char *uri = g_strdup_printf("unix:%s", mig_socket);
-
-    src = ahci_boot("-m 384 -M q35 "
-                    "-drive if=ide,file=%s,format=%s ", tmp_path, imgfmt);
-    dst = ahci_boot("-m 384 -M q35 "
-                    "-drive if=ide,file=%s,format=%s "
-                    "-incoming %s", tmp_path, imgfmt, uri);
-
-    ahci_migrate(src, dst, uri);
-
-    ahci_shutdown(src);
-    ahci_shutdown(dst);
-    g_free(uri);
-}
-
-/**
- * Simple migration test: Write a pattern, migrate, then read.
- */
-static void ahci_migrate_simple(uint8_t cmd_read, uint8_t cmd_write)
-{
-    AHCIQState *src, *dst;
-    uint8_t px;
-    size_t bufsize = 4096;
-    unsigned char *tx = g_malloc(bufsize);
-    unsigned char *rx = g_malloc0(bufsize);
-    char *uri = g_strdup_printf("unix:%s", mig_socket);
-
-    src = ahci_boot_and_enable("-m 384 -M q35 "
-                               "-drive if=ide,format=%s,file=%s ",
-                               imgfmt, tmp_path);
-    dst = ahci_boot("-m 384 -M q35 "
-                    "-drive if=ide,format=%s,file=%s "
-                    "-incoming %s", imgfmt, tmp_path, uri);
-
-    /* initialize */
-    px = ahci_port_select(src);
-    ahci_port_clear(src, px);
-
-    /* create pattern */
-    generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
-
-    /* Write, migrate, then read. */
-    ahci_io(src, px, cmd_write, tx, bufsize, 0);
-    ahci_migrate(src, dst, uri);
-    ahci_io(dst, px, cmd_read, rx, bufsize, 0);
-
-    /* Verify pattern */
-    g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
-
-    ahci_shutdown(src);
-    ahci_shutdown(dst);
-    g_free(rx);
-    g_free(tx);
-    g_free(uri);
-}
-
-static void test_migrate_dma(void)
-{
-    ahci_migrate_simple(CMD_READ_DMA, CMD_WRITE_DMA);
-}
-
-static void test_migrate_ncq(void)
-{
-    ahci_migrate_simple(READ_FPDMA_QUEUED, WRITE_FPDMA_QUEUED);
-}
-
-/**
- * Halted IO Error Test
- *
- * Simulate an error on first write, Try to write a pattern,
- * Confirm the VM has stopped, resume the VM, verify command
- * has completed, then read back the data and verify.
- */
-static void ahci_halted_io_test(uint8_t cmd_read, uint8_t cmd_write)
-{
-    AHCIQState *ahci;
-    uint8_t port;
-    size_t bufsize = 4096;
-    unsigned char *tx = g_malloc(bufsize);
-    unsigned char *rx = g_malloc0(bufsize);
-    uint64_t ptr;
-    AHCICommand *cmd;
-
-    prepare_blkdebug_script(debug_path, "write_aio");
-
-    ahci = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0,"
-                                "format=%s,cache=writeback,"
-                                "rerror=stop,werror=stop "
-                                "-M q35 "
-                                "-device ide-hd,drive=drive0 ",
-                                debug_path,
-                                tmp_path, imgfmt);
-
-    /* Initialize and prepare */
-    port = ahci_port_select(ahci);
-    ahci_port_clear(ahci, port);
-
-    /* create DMA source buffer and write pattern */
-    generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
-    ptr = ahci_alloc(ahci, bufsize);
-    g_assert(ptr);
-    qtest_memwrite(ahci->parent->qts, ptr, tx, bufsize);
-
-    /* Attempt to write (and fail) */
-    cmd = ahci_guest_io_halt(ahci, port, cmd_write,
-                             ptr, bufsize, 0);
-
-    /* Attempt to resume the command */
-    ahci_guest_io_resume(ahci, cmd);
-    ahci_free(ahci, ptr);
-
-    /* Read back and verify */
-    ahci_io(ahci, port, cmd_read, rx, bufsize, 0);
-    g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
-
-    /* Cleanup and go home */
-    ahci_shutdown(ahci);
-    g_free(rx);
-    g_free(tx);
-}
-
-static void test_halted_dma(void)
-{
-    ahci_halted_io_test(CMD_READ_DMA, CMD_WRITE_DMA);
-}
-
-static void test_halted_ncq(void)
-{
-    ahci_halted_io_test(READ_FPDMA_QUEUED, WRITE_FPDMA_QUEUED);
-}
-
-/**
- * IO Error Migration Test
- *
- * Simulate an error on first write, Try to write a pattern,
- * Confirm the VM has stopped, migrate, resume the VM,
- * verify command has completed, then read back the data and verify.
- */
-static void ahci_migrate_halted_io(uint8_t cmd_read, uint8_t cmd_write)
-{
-    AHCIQState *src, *dst;
-    uint8_t port;
-    size_t bufsize = 4096;
-    unsigned char *tx = g_malloc(bufsize);
-    unsigned char *rx = g_malloc0(bufsize);
-    uint64_t ptr;
-    AHCICommand *cmd;
-    char *uri = g_strdup_printf("unix:%s", mig_socket);
-
-    prepare_blkdebug_script(debug_path, "write_aio");
-
-    src = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0,"
-                               "format=%s,cache=writeback,"
-                               "rerror=stop,werror=stop "
-                               "-M q35 "
-                               "-device ide-hd,drive=drive0 ",
-                               debug_path,
-                               tmp_path, imgfmt);
-
-    dst = ahci_boot("-drive file=%s,if=none,id=drive0,"
-                    "format=%s,cache=writeback,"
-                    "rerror=stop,werror=stop "
-                    "-M q35 "
-                    "-device ide-hd,drive=drive0 "
-                    "-incoming %s",
-                    tmp_path, imgfmt, uri);
-
-    /* Initialize and prepare */
-    port = ahci_port_select(src);
-    ahci_port_clear(src, port);
-    generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
-
-    /* create DMA source buffer and write pattern */
-    ptr = ahci_alloc(src, bufsize);
-    g_assert(ptr);
-    qtest_memwrite(src->parent->qts, ptr, tx, bufsize);
-
-    /* Write, trigger the VM to stop, migrate, then resume. */
-    cmd = ahci_guest_io_halt(src, port, cmd_write,
-                             ptr, bufsize, 0);
-    ahci_migrate(src, dst, uri);
-    ahci_guest_io_resume(dst, cmd);
-    ahci_free(dst, ptr);
-
-    /* Read back */
-    ahci_io(dst, port, cmd_read, rx, bufsize, 0);
-
-    /* Verify TX and RX are identical */
-    g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
-
-    /* Cleanup and go home. */
-    ahci_shutdown(src);
-    ahci_shutdown(dst);
-    g_free(rx);
-    g_free(tx);
-    g_free(uri);
-}
-
-static void test_migrate_halted_dma(void)
-{
-    ahci_migrate_halted_io(CMD_READ_DMA, CMD_WRITE_DMA);
-}
-
-static void test_migrate_halted_ncq(void)
-{
-    ahci_migrate_halted_io(READ_FPDMA_QUEUED, WRITE_FPDMA_QUEUED);
-}
-
-/**
- * Migration test: Try to flush, migrate, then resume.
- */
-static void test_flush_migrate(void)
-{
-    AHCIQState *src, *dst;
-    AHCICommand *cmd;
-    uint8_t px;
-    char *uri = g_strdup_printf("unix:%s", mig_socket);
-
-    prepare_blkdebug_script(debug_path, "flush_to_disk");
-
-    src = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0,"
-                               "cache=writeback,rerror=stop,werror=stop,"
-                               "format=%s "
-                               "-M q35 "
-                               "-device ide-hd,drive=drive0 ",
-                               debug_path, tmp_path, imgfmt);
-    dst = ahci_boot("-drive file=%s,if=none,id=drive0,"
-                    "cache=writeback,rerror=stop,werror=stop,"
-                    "format=%s "
-                    "-M q35 "
-                    "-device ide-hd,drive=drive0 "
-                    "-incoming %s", tmp_path, imgfmt, uri);
-
-    px = ahci_port_select(src);
-    ahci_port_clear(src, px);
-
-    /* Dirty device so that flush reaches disk */
-    make_dirty(src, px);
-
-    /* Issue Flush Command */
-    cmd = ahci_command_create(CMD_FLUSH_CACHE);
-    ahci_command_commit(src, cmd, px);
-    ahci_command_issue_async(src, cmd);
-    qtest_qmp_eventwait(src->parent->qts, "STOP");
-
-    /* Migrate over */
-    ahci_migrate(src, dst, uri);
-
-    /* Complete the command */
-    qtest_qmp_send(dst->parent->qts, "{'execute':'cont' }");
-    qtest_qmp_eventwait(dst->parent->qts, "RESUME");
-    ahci_command_wait(dst, cmd);
-    ahci_command_verify(dst, cmd);
-
-    ahci_command_free(cmd);
-    ahci_shutdown(src);
-    ahci_shutdown(dst);
-    g_free(uri);
-}
-
-static void test_max(void)
-{
-    AHCIQState *ahci;
-
-    ahci = ahci_boot_and_enable(NULL);
-    ahci_test_max(ahci);
-    ahci_shutdown(ahci);
-}
-
-static void test_reset(void)
-{
-    AHCIQState *ahci;
-    int i;
-
-    ahci = ahci_boot(NULL);
-    ahci_test_pci_spec(ahci);
-    ahci_pci_enable(ahci);
-
-    for (i = 0; i < 2; i++) {
-        ahci_test_hba_spec(ahci);
-        ahci_hba_enable(ahci);
-        ahci_test_identify(ahci);
-        ahci_test_io_rw_simple(ahci, 4096, 0,
-                               CMD_READ_DMA_EXT,
-                               CMD_WRITE_DMA_EXT);
-        ahci_set(ahci, AHCI_GHC, AHCI_GHC_HR);
-        ahci_clean_mem(ahci);
-    }
-
-    ahci_shutdown(ahci);
-}
-
-static void test_ncq_simple(void)
-{
-    AHCIQState *ahci;
-
-    ahci = ahci_boot_and_enable(NULL);
-    ahci_test_io_rw_simple(ahci, 4096, 0,
-                           READ_FPDMA_QUEUED,
-                           WRITE_FPDMA_QUEUED);
-    ahci_shutdown(ahci);
-}
-
-static int prepare_iso(size_t size, unsigned char **buf, char **name)
-{
-    char cdrom_path[] = "/tmp/qtest.iso.XXXXXX";
-    unsigned char *patt;
-    ssize_t ret;
-    int fd = mkstemp(cdrom_path);
-
-    g_assert(buf);
-    g_assert(name);
-    patt = g_malloc(size);
-
-    /* Generate a pattern and build a CDROM image to read from */
-    generate_pattern(patt, size, ATAPI_SECTOR_SIZE);
-    ret = write(fd, patt, size);
-    g_assert(ret == size);
-
-    *name = g_strdup(cdrom_path);
-    *buf = patt;
-    return fd;
-}
-
-static void remove_iso(int fd, char *name)
-{
-    unlink(name);
-    g_free(name);
-    close(fd);
-}
-
-static int ahci_cb_cmp_buff(AHCIQState *ahci, AHCICommand *cmd,
-                            const AHCIOpts *opts)
-{
-    unsigned char *tx = opts->opaque;
-    unsigned char *rx;
-
-    if (!opts->size) {
-        return 0;
-    }
-
-    rx = g_malloc0(opts->size);
-    qtest_bufread(ahci->parent->qts, opts->buffer, rx, opts->size);
-    g_assert_cmphex(memcmp(tx, rx, opts->size), ==, 0);
-    g_free(rx);
-
-    return 0;
-}
-
-static void ahci_test_cdrom(int nsectors, bool dma, uint8_t cmd,
-                            bool override_bcl, uint16_t bcl)
-{
-    AHCIQState *ahci;
-    unsigned char *tx;
-    char *iso;
-    int fd;
-    AHCIOpts opts = {
-        .size = (ATAPI_SECTOR_SIZE * nsectors),
-        .atapi = true,
-        .atapi_dma = dma,
-        .post_cb = ahci_cb_cmp_buff,
-        .set_bcl = override_bcl,
-        .bcl = bcl,
-    };
-    uint64_t iso_size = ATAPI_SECTOR_SIZE * (nsectors + 1);
-
-    /* Prepare ISO and fill 'tx' buffer */
-    fd = prepare_iso(iso_size, &tx, &iso);
-    opts.opaque = tx;
-
-    /* Standard startup wonkery, but use ide-cd and our special iso file */
-    ahci = ahci_boot_and_enable("-drive if=none,id=drive0,file=%s,format=raw "
-                                "-M q35 "
-                                "-device ide-cd,drive=drive0 ", iso);
-
-    /* Build & Send AHCI command */
-    ahci_exec(ahci, ahci_port_select(ahci), cmd, &opts);
-
-    /* Cleanup */
-    g_free(tx);
-    ahci_shutdown(ahci);
-    remove_iso(fd, iso);
-}
-
-static void ahci_test_cdrom_read10(int nsectors, bool dma)
-{
-    ahci_test_cdrom(nsectors, dma, CMD_ATAPI_READ_10, false, 0);
-}
-
-static void test_cdrom_dma(void)
-{
-    ahci_test_cdrom_read10(1, true);
-}
-
-static void test_cdrom_dma_multi(void)
-{
-    ahci_test_cdrom_read10(3, true);
-}
-
-static void test_cdrom_pio(void)
-{
-    ahci_test_cdrom_read10(1, false);
-}
-
-static void test_cdrom_pio_multi(void)
-{
-    ahci_test_cdrom_read10(3, false);
-}
-
-/* Regression test: Test that a READ_CD command with a BCL of 0 but a size of 0
- * completes as a NOP instead of erroring out. */
-static void test_atapi_bcl(void)
-{
-    ahci_test_cdrom(0, false, CMD_ATAPI_READ_CD, true, 0);
-}
-
-
-static void atapi_wait_tray(AHCIQState *ahci, bool open)
-{
-    QDict *rsp = qtest_qmp_eventwait_ref(ahci->parent->qts,
-                                         "DEVICE_TRAY_MOVED");
-    QDict *data = qdict_get_qdict(rsp, "data");
-    if (open) {
-        g_assert(qdict_get_bool(data, "tray-open"));
-    } else {
-        g_assert(!qdict_get_bool(data, "tray-open"));
-    }
-    qobject_unref(rsp);
-}
-
-static void test_atapi_tray(void)
-{
-    AHCIQState *ahci;
-    unsigned char *tx;
-    char *iso;
-    int fd;
-    uint8_t port, sense, asc;
-    uint64_t iso_size = ATAPI_SECTOR_SIZE;
-    QDict *rsp;
-
-    fd = prepare_iso(iso_size, &tx, &iso);
-    ahci = ahci_boot_and_enable("-blockdev node-name=drive0,driver=file,filename=%s "
-                                "-M q35 "
-                                "-device ide-cd,id=cd0,drive=drive0 ", iso);
-    port = ahci_port_select(ahci);
-
-    ahci_atapi_eject(ahci, port);
-    atapi_wait_tray(ahci, true);
-
-    ahci_atapi_load(ahci, port);
-    atapi_wait_tray(ahci, false);
-
-    /* Remove media */
-    qtest_qmp_send(ahci->parent->qts, "{'execute': 'blockdev-open-tray', "
-                    "'arguments': {'id': 'cd0'}}");
-    atapi_wait_tray(ahci, true);
-    rsp = qtest_qmp_receive(ahci->parent->qts);
-    qobject_unref(rsp);
-
-    qmp_discard_response(ahci->parent->qts,
-                         "{'execute': 'blockdev-remove-medium', "
-                         "'arguments': {'id': 'cd0'}}");
-
-    /* Test the tray without a medium */
-    ahci_atapi_load(ahci, port);
-    atapi_wait_tray(ahci, false);
-
-    ahci_atapi_eject(ahci, port);
-    atapi_wait_tray(ahci, true);
-
-    /* Re-insert media */
-    qmp_discard_response(ahci->parent->qts,
-                         "{'execute': 'blockdev-add', "
-                         "'arguments': {'node-name': 'node0', "
-                                        "'driver': 'raw', "
-                                        "'file': { 'driver': 'file', "
-                                                  "'filename': %s }}}", iso);
-    qmp_discard_response(ahci->parent->qts,
-                         "{'execute': 'blockdev-insert-medium',"
-                         "'arguments': { 'id': 'cd0', "
-                                         "'node-name': 'node0' }}");
-
-    /* Again, the event shows up first */
-    qtest_qmp_send(ahci->parent->qts, "{'execute': 'blockdev-close-tray', "
-                   "'arguments': {'id': 'cd0'}}");
-    atapi_wait_tray(ahci, false);
-    rsp = qtest_qmp_receive(ahci->parent->qts);
-    qobject_unref(rsp);
-
-    /* Now, to convince ATAPI we understand the media has changed... */
-    ahci_atapi_test_ready(ahci, port, false, SENSE_NOT_READY);
-    ahci_atapi_get_sense(ahci, port, &sense, &asc);
-    g_assert_cmpuint(sense, ==, SENSE_NOT_READY);
-    g_assert_cmpuint(asc, ==, ASC_MEDIUM_NOT_PRESENT);
-
-    ahci_atapi_test_ready(ahci, port, false, SENSE_UNIT_ATTENTION);
-    ahci_atapi_get_sense(ahci, port, &sense, &asc);
-    g_assert_cmpuint(sense, ==, SENSE_UNIT_ATTENTION);
-    g_assert_cmpuint(asc, ==, ASC_MEDIUM_MAY_HAVE_CHANGED);
-
-    ahci_atapi_test_ready(ahci, port, true, SENSE_NO_SENSE);
-    ahci_atapi_get_sense(ahci, port, &sense, &asc);
-    g_assert_cmpuint(sense, ==, SENSE_NO_SENSE);
-
-    /* Final tray test. */
-    ahci_atapi_eject(ahci, port);
-    atapi_wait_tray(ahci, true);
-
-    ahci_atapi_load(ahci, port);
-    atapi_wait_tray(ahci, false);
-
-    /* Cleanup */
-    g_free(tx);
-    ahci_shutdown(ahci);
-    remove_iso(fd, iso);
-}
-
-/******************************************************************************/
-/* AHCI I/O Test Matrix Definitions                                           */
-
-enum BuffLen {
-    LEN_BEGIN = 0,
-    LEN_SIMPLE = LEN_BEGIN,
-    LEN_DOUBLE,
-    LEN_LONG,
-    LEN_SHORT,
-    NUM_LENGTHS
-};
-
-static const char *buff_len_str[NUM_LENGTHS] = { "simple", "double",
-                                                 "long", "short" };
-
-enum AddrMode {
-    ADDR_MODE_BEGIN = 0,
-    ADDR_MODE_LBA28 = ADDR_MODE_BEGIN,
-    ADDR_MODE_LBA48,
-    NUM_ADDR_MODES
-};
-
-static const char *addr_mode_str[NUM_ADDR_MODES] = { "lba28", "lba48" };
-
-enum IOMode {
-    MODE_BEGIN = 0,
-    MODE_PIO = MODE_BEGIN,
-    MODE_DMA,
-    NUM_MODES
-};
-
-static const char *io_mode_str[NUM_MODES] = { "pio", "dma" };
-
-enum IOOps {
-    IO_BEGIN = 0,
-    IO_READ = IO_BEGIN,
-    IO_WRITE,
-    NUM_IO_OPS
-};
-
-enum OffsetType {
-    OFFSET_BEGIN = 0,
-    OFFSET_ZERO = OFFSET_BEGIN,
-    OFFSET_LOW,
-    OFFSET_HIGH,
-    NUM_OFFSETS
-};
-
-static const char *offset_str[NUM_OFFSETS] = { "zero", "low", "high" };
-
-typedef struct AHCIIOTestOptions {
-    enum BuffLen length;
-    enum AddrMode address_type;
-    enum IOMode io_type;
-    enum OffsetType offset;
-} AHCIIOTestOptions;
-
-static uint64_t offset_sector(enum OffsetType ofst,
-                              enum AddrMode addr_type,
-                              uint64_t buffsize)
-{
-    uint64_t ceil;
-    uint64_t nsectors;
-
-    switch (ofst) {
-    case OFFSET_ZERO:
-        return 0;
-    case OFFSET_LOW:
-        return 1;
-    case OFFSET_HIGH:
-        ceil = (addr_type == ADDR_MODE_LBA28) ? 0xfffffff : 0xffffffffffff;
-        ceil = MIN(ceil, mb_to_sectors(test_image_size_mb) - 1);
-        nsectors = buffsize / AHCI_SECTOR_SIZE;
-        return ceil - nsectors + 1;
-    default:
-        g_assert_not_reached();
-    }
-}
-
-/**
- * Table of possible I/O ATA commands given a set of enumerations.
- */
-static const uint8_t io_cmds[NUM_MODES][NUM_ADDR_MODES][NUM_IO_OPS] = {
-    [MODE_PIO] = {
-        [ADDR_MODE_LBA28] = {
-            [IO_READ] = CMD_READ_PIO,
-            [IO_WRITE] = CMD_WRITE_PIO },
-        [ADDR_MODE_LBA48] = {
-            [IO_READ] = CMD_READ_PIO_EXT,
-            [IO_WRITE] = CMD_WRITE_PIO_EXT }
-    },
-    [MODE_DMA] = {
-        [ADDR_MODE_LBA28] = {
-            [IO_READ] = CMD_READ_DMA,
-            [IO_WRITE] = CMD_WRITE_DMA },
-        [ADDR_MODE_LBA48] = {
-            [IO_READ] = CMD_READ_DMA_EXT,
-            [IO_WRITE] = CMD_WRITE_DMA_EXT }
-    }
-};
-
-/**
- * Test a Read/Write pattern using various commands, addressing modes,
- * transfer modes, and buffer sizes.
- */
-static void test_io_rw_interface(enum AddrMode lba48, enum IOMode dma,
-                                 unsigned bufsize, uint64_t sector)
-{
-    AHCIQState *ahci;
-
-    ahci = ahci_boot_and_enable(NULL);
-    ahci_test_io_rw_simple(ahci, bufsize, sector,
-                           io_cmds[dma][lba48][IO_READ],
-                           io_cmds[dma][lba48][IO_WRITE]);
-    ahci_shutdown(ahci);
-}
-
-/**
- * Demultiplex the test data and invoke the actual test routine.
- */
-static void test_io_interface(gconstpointer opaque)
-{
-    AHCIIOTestOptions *opts = (AHCIIOTestOptions *)opaque;
-    unsigned bufsize;
-    uint64_t sector;
-
-    switch (opts->length) {
-    case LEN_SIMPLE:
-        bufsize = 4096;
-        break;
-    case LEN_DOUBLE:
-        bufsize = 8192;
-        break;
-    case LEN_LONG:
-        bufsize = 4096 * 64;
-        break;
-    case LEN_SHORT:
-        bufsize = 512;
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    sector = offset_sector(opts->offset, opts->address_type, bufsize);
-    test_io_rw_interface(opts->address_type, opts->io_type, bufsize, sector);
-    g_free(opts);
-    return;
-}
-
-static void create_ahci_io_test(enum IOMode type, enum AddrMode addr,
-                                enum BuffLen len, enum OffsetType offset)
-{
-    char *name;
-    AHCIIOTestOptions *opts;
-
-    opts = g_new(AHCIIOTestOptions, 1);
-    opts->length = len;
-    opts->address_type = addr;
-    opts->io_type = type;
-    opts->offset = offset;
-
-    name = g_strdup_printf("ahci/io/%s/%s/%s/%s",
-                           io_mode_str[type],
-                           addr_mode_str[addr],
-                           buff_len_str[len],
-                           offset_str[offset]);
-
-    if ((addr == ADDR_MODE_LBA48) && (offset == OFFSET_HIGH) &&
-        (mb_to_sectors(test_image_size_mb) <= 0xFFFFFFF)) {
-        g_test_message("%s: skipped; test image too small", name);
-        g_free(opts);
-        g_free(name);
-        return;
-    }
-
-    qtest_add_data_func(name, opts, test_io_interface);
-    g_free(name);
-}
-
-/******************************************************************************/
-
-int main(int argc, char **argv)
-{
-    const char *arch;
-    int ret;
-    int fd;
-    int c;
-    int i, j, k, m;
-
-    static struct option long_options[] = {
-        {"pedantic", no_argument, 0, 'p' },
-        {0, 0, 0, 0},
-    };
-
-    /* Should be first to utilize g_test functionality, So we can see errors. */
-    g_test_init(&argc, &argv, NULL);
-
-    while (1) {
-        c = getopt_long(argc, argv, "", long_options, NULL);
-        if (c == -1) {
-            break;
-        }
-        switch (c) {
-        case -1:
-            break;
-        case 'p':
-            ahci_pedantic = 1;
-            break;
-        default:
-            fprintf(stderr, "Unrecognized ahci_test option.\n");
-            g_assert_not_reached();
-        }
-    }
-
-    /* Check architecture */
-    arch = qtest_get_arch();
-    if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) {
-        g_test_message("Skipping test for non-x86");
-        return 0;
-    }
-
-    /* Create a temporary image */
-    fd = mkstemp(tmp_path);
-    g_assert(fd >= 0);
-    if (have_qemu_img()) {
-        imgfmt = "qcow2";
-        test_image_size_mb = TEST_IMAGE_SIZE_MB_LARGE;
-        mkqcow2(tmp_path, TEST_IMAGE_SIZE_MB_LARGE);
-    } else {
-        g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
-                       "skipping LBA48 high-sector tests");
-        imgfmt = "raw";
-        test_image_size_mb = TEST_IMAGE_SIZE_MB_SMALL;
-        ret = ftruncate(fd, test_image_size_mb * 1024 * 1024);
-        g_assert(ret == 0);
-    }
-    close(fd);
-
-    /* Create temporary blkdebug instructions */
-    fd = mkstemp(debug_path);
-    g_assert(fd >= 0);
-    close(fd);
-
-    /* Reserve a hollow file to use as a socket for migration tests */
-    fd = mkstemp(mig_socket);
-    g_assert(fd >= 0);
-    close(fd);
-
-    /* Run the tests */
-    qtest_add_func("/ahci/sanity",     test_sanity);
-    qtest_add_func("/ahci/pci_spec",   test_pci_spec);
-    qtest_add_func("/ahci/pci_enable", test_pci_enable);
-    qtest_add_func("/ahci/hba_spec",   test_hba_spec);
-    qtest_add_func("/ahci/hba_enable", test_hba_enable);
-    qtest_add_func("/ahci/identify",   test_identify);
-
-    for (i = MODE_BEGIN; i < NUM_MODES; i++) {
-        for (j = ADDR_MODE_BEGIN; j < NUM_ADDR_MODES; j++) {
-            for (k = LEN_BEGIN; k < NUM_LENGTHS; k++) {
-                for (m = OFFSET_BEGIN; m < NUM_OFFSETS; m++) {
-                    create_ahci_io_test(i, j, k, m);
-                }
-            }
-        }
-    }
-
-    qtest_add_func("/ahci/io/dma/lba28/fragmented", test_dma_fragmented);
-
-    qtest_add_func("/ahci/flush/simple", test_flush);
-    qtest_add_func("/ahci/flush/retry", test_flush_retry);
-    qtest_add_func("/ahci/flush/migrate", test_flush_migrate);
-
-    qtest_add_func("/ahci/migrate/sanity", test_migrate_sanity);
-    qtest_add_func("/ahci/migrate/dma/simple", test_migrate_dma);
-    qtest_add_func("/ahci/io/dma/lba28/retry", test_halted_dma);
-    qtest_add_func("/ahci/migrate/dma/halted", test_migrate_halted_dma);
-
-    qtest_add_func("/ahci/max", test_max);
-    qtest_add_func("/ahci/reset", test_reset);
-
-    qtest_add_func("/ahci/io/ncq/simple", test_ncq_simple);
-    qtest_add_func("/ahci/migrate/ncq/simple", test_migrate_ncq);
-    qtest_add_func("/ahci/io/ncq/retry", test_halted_ncq);
-    qtest_add_func("/ahci/migrate/ncq/halted", test_migrate_halted_ncq);
-
-    qtest_add_func("/ahci/cdrom/dma/single", test_cdrom_dma);
-    qtest_add_func("/ahci/cdrom/dma/multi", test_cdrom_dma_multi);
-    qtest_add_func("/ahci/cdrom/pio/single", test_cdrom_pio);
-    qtest_add_func("/ahci/cdrom/pio/multi", test_cdrom_pio_multi);
-
-    qtest_add_func("/ahci/cdrom/pio/bcl", test_atapi_bcl);
-    qtest_add_func("/ahci/cdrom/eject", test_atapi_tray);
-
-    ret = g_test_run();
-
-    /* Cleanup */
-    unlink(tmp_path);
-    unlink(debug_path);
-    unlink(mig_socket);
-
-    return ret;
-}
diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
deleted file mode 100644 (file)
index bef3ed2..0000000
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * Arm CPU feature test cases
- *
- * Copyright (c) 2019 Red Hat Inc.
- * Authors:
- *  Andrew Jones <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "qemu/bitops.h"
-#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qjson.h"
-
-/*
- * We expect the SVE max-vq to be 16. Also it must be <= 64
- * for our test code, otherwise 'vls' can't just be a uint64_t.
- */
-#define SVE_MAX_VQ 16
-
-#define MACHINE     "-machine virt,gic-version=max -accel tcg "
-#define MACHINE_KVM "-machine virt,gic-version=max -accel kvm -accel tcg "
-#define QUERY_HEAD  "{ 'execute': 'query-cpu-model-expansion', " \
-                    "  'arguments': { 'type': 'full', "
-#define QUERY_TAIL  "}}"
-
-static bool kvm_enabled(QTestState *qts)
-{
-    QDict *resp, *qdict;
-    bool enabled;
-
-    resp = qtest_qmp(qts, "{ 'execute': 'query-kvm' }");
-    g_assert(qdict_haskey(resp, "return"));
-    qdict = qdict_get_qdict(resp, "return");
-    g_assert(qdict_haskey(qdict, "enabled"));
-    enabled = qdict_get_bool(qdict, "enabled");
-    qobject_unref(resp);
-
-    return enabled;
-}
-
-static QDict *do_query_no_props(QTestState *qts, const char *cpu_type)
-{
-    return qtest_qmp(qts, QUERY_HEAD "'model': { 'name': %s }"
-                          QUERY_TAIL, cpu_type);
-}
-
-static QDict *do_query(QTestState *qts, const char *cpu_type,
-                       const char *fmt, ...)
-{
-    QDict *resp;
-
-    if (fmt) {
-        QDict *args;
-        va_list ap;
-
-        va_start(ap, fmt);
-        args = qdict_from_vjsonf_nofail(fmt, ap);
-        va_end(ap);
-
-        resp = qtest_qmp(qts, QUERY_HEAD "'model': { 'name': %s, "
-                                                    "'props': %p }"
-                              QUERY_TAIL, cpu_type, args);
-    } else {
-        resp = do_query_no_props(qts, cpu_type);
-    }
-
-    return resp;
-}
-
-static const char *resp_get_error(QDict *resp)
-{
-    QDict *qdict;
-
-    g_assert(resp);
-
-    qdict = qdict_get_qdict(resp, "error");
-    if (qdict) {
-        return qdict_get_str(qdict, "desc");
-    }
-
-    return NULL;
-}
-
-#define assert_error(qts, cpu_type, expected_error, fmt, ...)          \
-({                                                                     \
-    QDict *_resp;                                                      \
-    const char *_error;                                                \
-                                                                       \
-    _resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);               \
-    g_assert(_resp);                                                   \
-    _error = resp_get_error(_resp);                                    \
-    g_assert(_error);                                                  \
-    g_assert(g_str_equal(_error, expected_error));                     \
-    qobject_unref(_resp);                                              \
-})
-
-static bool resp_has_props(QDict *resp)
-{
-    QDict *qdict;
-
-    g_assert(resp);
-
-    if (!qdict_haskey(resp, "return")) {
-        return false;
-    }
-    qdict = qdict_get_qdict(resp, "return");
-
-    if (!qdict_haskey(qdict, "model")) {
-        return false;
-    }
-    qdict = qdict_get_qdict(qdict, "model");
-
-    return qdict_haskey(qdict, "props");
-}
-
-static QDict *resp_get_props(QDict *resp)
-{
-    QDict *qdict;
-
-    g_assert(resp);
-    g_assert(resp_has_props(resp));
-
-    qdict = qdict_get_qdict(resp, "return");
-    qdict = qdict_get_qdict(qdict, "model");
-    qdict = qdict_get_qdict(qdict, "props");
-
-    return qdict;
-}
-
-static bool resp_get_feature(QDict *resp, const char *feature)
-{
-    QDict *props;
-
-    g_assert(resp);
-    g_assert(resp_has_props(resp));
-    props = resp_get_props(resp);
-    g_assert(qdict_get(props, feature));
-    return qdict_get_bool(props, feature);
-}
-
-#define assert_has_feature(qts, cpu_type, feature)                     \
-({                                                                     \
-    QDict *_resp = do_query_no_props(qts, cpu_type);                   \
-    g_assert(_resp);                                                   \
-    g_assert(resp_has_props(_resp));                                   \
-    g_assert(qdict_get(resp_get_props(_resp), feature));               \
-    qobject_unref(_resp);                                              \
-})
-
-#define assert_has_not_feature(qts, cpu_type, feature)                 \
-({                                                                     \
-    QDict *_resp = do_query_no_props(qts, cpu_type);                   \
-    g_assert(_resp);                                                   \
-    g_assert(!resp_has_props(_resp) ||                                 \
-             !qdict_get(resp_get_props(_resp), feature));              \
-    qobject_unref(_resp);                                              \
-})
-
-static void assert_type_full(QTestState *qts)
-{
-    const char *error;
-    QDict *resp;
-
-    resp = qtest_qmp(qts, "{ 'execute': 'query-cpu-model-expansion', "
-                            "'arguments': { 'type': 'static', "
-                                           "'model': { 'name': 'foo' }}}");
-    g_assert(resp);
-    error = resp_get_error(resp);
-    g_assert(error);
-    g_assert(g_str_equal(error,
-                         "The requested expansion type is not supported"));
-    qobject_unref(resp);
-}
-
-static void assert_bad_props(QTestState *qts, const char *cpu_type)
-{
-    const char *error;
-    QDict *resp;
-
-    resp = qtest_qmp(qts, "{ 'execute': 'query-cpu-model-expansion', "
-                            "'arguments': { 'type': 'full', "
-                                           "'model': { 'name': %s, "
-                                                      "'props': false }}}",
-                     cpu_type);
-    g_assert(resp);
-    error = resp_get_error(resp);
-    g_assert(error);
-    g_assert(g_str_equal(error,
-                         "Invalid parameter type for 'props', expected: dict"));
-    qobject_unref(resp);
-}
-
-static uint64_t resp_get_sve_vls(QDict *resp)
-{
-    QDict *props;
-    const QDictEntry *e;
-    uint64_t vls = 0;
-    int n = 0;
-
-    g_assert(resp);
-    g_assert(resp_has_props(resp));
-
-    props = resp_get_props(resp);
-
-    for (e = qdict_first(props); e; e = qdict_next(props, e)) {
-        if (strlen(e->key) > 3 && !strncmp(e->key, "sve", 3) &&
-            g_ascii_isdigit(e->key[3])) {
-            char *endptr;
-            int bits;
-
-            bits = g_ascii_strtoll(&e->key[3], &endptr, 10);
-            if (!bits || *endptr != '\0') {
-                continue;
-            }
-
-            if (qdict_get_bool(props, e->key)) {
-                vls |= BIT_ULL((bits / 128) - 1);
-            }
-            ++n;
-        }
-    }
-
-    g_assert(n == SVE_MAX_VQ);
-
-    return vls;
-}
-
-#define assert_sve_vls(qts, cpu_type, expected_vls, fmt, ...)          \
-({                                                                     \
-    QDict *_resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);        \
-    g_assert(_resp);                                                   \
-    g_assert(resp_has_props(_resp));                                   \
-    g_assert(resp_get_sve_vls(_resp) == expected_vls);                 \
-    qobject_unref(_resp);                                              \
-})
-
-static void sve_tests_default(QTestState *qts, const char *cpu_type)
-{
-    /*
-     * With no sve-max-vq or sve<N> properties on the command line
-     * the default is to have all vector lengths enabled. This also
-     * tests that 'sve' is 'on' by default.
-     */
-    assert_sve_vls(qts, cpu_type, BIT_ULL(SVE_MAX_VQ) - 1, NULL);
-
-    /* With SVE off, all vector lengths should also be off. */
-    assert_sve_vls(qts, cpu_type, 0, "{ 'sve': false }");
-
-    /* With SVE on, we must have at least one vector length enabled. */
-    assert_error(qts, cpu_type, "cannot disable sve128", "{ 'sve128': false }");
-
-    /* Basic enable/disable tests. */
-    assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve384': true }");
-    assert_sve_vls(qts, cpu_type, ((BIT_ULL(SVE_MAX_VQ) - 1) & ~BIT_ULL(2)),
-                   "{ 'sve384': false }");
-
-    /*
-     * ---------------------------------------------------------------------
-     *               power-of-two(vq)   all-power-            can      can
-     *                                  of-two(< vq)        enable   disable
-     * ---------------------------------------------------------------------
-     * vq < max_vq      no                MUST*              yes      yes
-     * vq < max_vq      yes               MUST*              yes      no
-     * ---------------------------------------------------------------------
-     * vq == max_vq     n/a               MUST*              yes**    yes**
-     * ---------------------------------------------------------------------
-     * vq > max_vq      n/a               no                 no       yes
-     * vq > max_vq      n/a               yes                yes      yes
-     * ---------------------------------------------------------------------
-     *
-     * [*] "MUST" means this requirement must already be satisfied,
-     *     otherwise 'max_vq' couldn't itself be enabled.
-     *
-     * [**] Not testable with the QMP interface, only with the command line.
-     */
-
-    /* max_vq := 8 */
-    assert_sve_vls(qts, cpu_type, 0x8b, "{ 'sve1024': true }");
-
-    /* max_vq := 8, vq < max_vq, !power-of-two(vq) */
-    assert_sve_vls(qts, cpu_type, 0x8f,
-                   "{ 'sve1024': true, 'sve384': true }");
-    assert_sve_vls(qts, cpu_type, 0x8b,
-                   "{ 'sve1024': true, 'sve384': false }");
-
-    /* max_vq := 8, vq < max_vq, power-of-two(vq) */
-    assert_sve_vls(qts, cpu_type, 0x8b,
-                   "{ 'sve1024': true, 'sve256': true }");
-    assert_error(qts, cpu_type, "cannot disable sve256",
-                 "{ 'sve1024': true, 'sve256': false }");
-
-    /* max_vq := 3, vq > max_vq, !all-power-of-two(< vq) */
-    assert_error(qts, cpu_type, "cannot disable sve512",
-                 "{ 'sve384': true, 'sve512': false, 'sve640': true }");
-
-    /*
-     * We can disable power-of-two vector lengths when all larger lengths
-     * are also disabled. We only need to disable the power-of-two length,
-     * as all non-enabled larger lengths will then be auto-disabled.
-     */
-    assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve512': false }");
-
-    /* max_vq := 3, vq > max_vq, all-power-of-two(< vq) */
-    assert_sve_vls(qts, cpu_type, 0x1f,
-                   "{ 'sve384': true, 'sve512': true, 'sve640': true }");
-    assert_sve_vls(qts, cpu_type, 0xf,
-                   "{ 'sve384': true, 'sve512': true, 'sve640': false }");
-}
-
-static void sve_tests_sve_max_vq_8(const void *data)
-{
-    QTestState *qts;
-
-    qts = qtest_init(MACHINE "-cpu max,sve-max-vq=8");
-
-    assert_sve_vls(qts, "max", BIT_ULL(8) - 1, NULL);
-
-    /*
-     * Disabling the max-vq set by sve-max-vq is not allowed, but
-     * of course enabling it is OK.
-     */
-    assert_error(qts, "max", "cannot disable sve1024", "{ 'sve1024': false }");
-    assert_sve_vls(qts, "max", 0xff, "{ 'sve1024': true }");
-
-    /*
-     * Enabling anything larger than max-vq set by sve-max-vq is not
-     * allowed, but of course disabling everything larger is OK.
-     */
-    assert_error(qts, "max", "cannot enable sve1152", "{ 'sve1152': true }");
-    assert_sve_vls(qts, "max", 0xff, "{ 'sve1152': false }");
-
-    /*
-     * We can enable/disable non power-of-two lengths smaller than the
-     * max-vq set by sve-max-vq, but, while we can enable power-of-two
-     * lengths, we can't disable them.
-     */
-    assert_sve_vls(qts, "max", 0xff, "{ 'sve384': true }");
-    assert_sve_vls(qts, "max", 0xfb, "{ 'sve384': false }");
-    assert_sve_vls(qts, "max", 0xff, "{ 'sve256': true }");
-    assert_error(qts, "max", "cannot disable sve256", "{ 'sve256': false }");
-
-    qtest_quit(qts);
-}
-
-static void sve_tests_sve_off(const void *data)
-{
-    QTestState *qts;
-
-    qts = qtest_init(MACHINE "-cpu max,sve=off");
-
-    /* SVE is off, so the map should be empty. */
-    assert_sve_vls(qts, "max", 0, NULL);
-
-    /* The map stays empty even if we turn lengths off. */
-    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
-
-    /* It's an error to enable lengths when SVE is off. */
-    assert_error(qts, "max", "cannot enable sve128", "{ 'sve128': true }");
-
-    /* With SVE re-enabled we should get all vector lengths enabled. */
-    assert_sve_vls(qts, "max", BIT_ULL(SVE_MAX_VQ) - 1, "{ 'sve': true }");
-
-    /* Or enable SVE with just specific vector lengths. */
-    assert_sve_vls(qts, "max", 0x3,
-                   "{ 'sve': true, 'sve128': true, 'sve256': true }");
-
-    qtest_quit(qts);
-}
-
-static void sve_tests_sve_off_kvm(const void *data)
-{
-    QTestState *qts;
-
-    qts = qtest_init(MACHINE_KVM "-cpu max,sve=off");
-
-    /*
-     * We don't know if this host supports SVE so we don't
-     * attempt to test enabling anything. We only test that
-     * everything is disabled (as it should be with sve=off)
-     * and that using sve<N>=off to explicitly disable vector
-     * lengths is OK too.
-     */
-    assert_sve_vls(qts, "max", 0, NULL);
-    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
-
-    qtest_quit(qts);
-}
-
-static void test_query_cpu_model_expansion(const void *data)
-{
-    QTestState *qts;
-
-    qts = qtest_init(MACHINE "-cpu max");
-
-    /* Test common query-cpu-model-expansion input validation */
-    assert_type_full(qts);
-    assert_bad_props(qts, "max");
-    assert_error(qts, "foo", "The CPU type 'foo' is not a recognized "
-                 "ARM CPU type", NULL);
-    assert_error(qts, "max", "Parameter 'not-a-prop' is unexpected",
-                 "{ 'not-a-prop': false }");
-    assert_error(qts, "host", "The CPU type 'host' requires KVM", NULL);
-
-    /* Test expected feature presence/absence for some cpu types */
-    assert_has_feature(qts, "max", "pmu");
-    assert_has_feature(qts, "cortex-a15", "pmu");
-    assert_has_not_feature(qts, "cortex-a15", "aarch64");
-
-    if (g_str_equal(qtest_get_arch(), "aarch64")) {
-        assert_has_feature(qts, "max", "aarch64");
-        assert_has_feature(qts, "max", "sve");
-        assert_has_feature(qts, "max", "sve128");
-        assert_has_feature(qts, "cortex-a57", "pmu");
-        assert_has_feature(qts, "cortex-a57", "aarch64");
-
-        sve_tests_default(qts, "max");
-
-        /* Test that features that depend on KVM generate errors without. */
-        assert_error(qts, "max",
-                     "'aarch64' feature cannot be disabled "
-                     "unless KVM is enabled and 32-bit EL1 "
-                     "is supported",
-                     "{ 'aarch64': false }");
-    }
-
-    qtest_quit(qts);
-}
-
-static void test_query_cpu_model_expansion_kvm(const void *data)
-{
-    QTestState *qts;
-
-    qts = qtest_init(MACHINE_KVM "-cpu max");
-
-    /*
-     * These tests target the 'host' CPU type, so KVM must be enabled.
-     */
-    if (!kvm_enabled(qts)) {
-        qtest_quit(qts);
-        return;
-    }
-
-    if (g_str_equal(qtest_get_arch(), "aarch64")) {
-        bool kvm_supports_sve;
-        char max_name[8], name[8];
-        uint32_t max_vq, vq;
-        uint64_t vls;
-        QDict *resp;
-        char *error;
-
-        assert_has_feature(qts, "host", "aarch64");
-        assert_has_feature(qts, "host", "pmu");
-
-        assert_error(qts, "cortex-a15",
-            "We cannot guarantee the CPU type 'cortex-a15' works "
-            "with KVM on this host", NULL);
-
-        assert_has_feature(qts, "host", "sve");
-        resp = do_query_no_props(qts, "host");
-        kvm_supports_sve = resp_get_feature(resp, "sve");
-        vls = resp_get_sve_vls(resp);
-        qobject_unref(resp);
-
-        if (kvm_supports_sve) {
-            g_assert(vls != 0);
-            max_vq = 64 - __builtin_clzll(vls);
-            sprintf(max_name, "sve%d", max_vq * 128);
-
-            /* Enabling a supported length is of course fine. */
-            assert_sve_vls(qts, "host", vls, "{ %s: true }", max_name);
-
-            /* Get the next supported length smaller than max-vq. */
-            vq = 64 - __builtin_clzll(vls & ~BIT_ULL(max_vq - 1));
-            if (vq) {
-                /*
-                 * We have at least one length smaller than max-vq,
-                 * so we can disable max-vq.
-                 */
-                assert_sve_vls(qts, "host", (vls & ~BIT_ULL(max_vq - 1)),
-                               "{ %s: false }", max_name);
-
-                /*
-                 * Smaller, supported vector lengths cannot be disabled
-                 * unless all larger, supported vector lengths are also
-                 * disabled.
-                 */
-                sprintf(name, "sve%d", vq * 128);
-                error = g_strdup_printf("cannot disable %s", name);
-                assert_error(qts, "host", error,
-                             "{ %s: true, %s: false }",
-                             max_name, name);
-                g_free(error);
-            }
-
-            /*
-             * The smallest, supported vector length is required, because
-             * we need at least one vector length enabled.
-             */
-            vq = __builtin_ffsll(vls);
-            sprintf(name, "sve%d", vq * 128);
-            error = g_strdup_printf("cannot disable %s", name);
-            assert_error(qts, "host", error, "{ %s: false }", name);
-            g_free(error);
-
-            /* Get an unsupported length. */
-            for (vq = 1; vq <= max_vq; ++vq) {
-                if (!(vls & BIT_ULL(vq - 1))) {
-                    break;
-                }
-            }
-            if (vq <= SVE_MAX_VQ) {
-                sprintf(name, "sve%d", vq * 128);
-                error = g_strdup_printf("cannot enable %s", name);
-                assert_error(qts, "host", error, "{ %s: true }", name);
-                g_free(error);
-            }
-        } else {
-            g_assert(vls == 0);
-        }
-    } else {
-        assert_has_not_feature(qts, "host", "aarch64");
-        assert_has_not_feature(qts, "host", "pmu");
-        assert_has_not_feature(qts, "host", "sve");
-    }
-
-    qtest_quit(qts);
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_data_func("/arm/query-cpu-model-expansion",
-                        NULL, test_query_cpu_model_expansion);
-
-    /*
-     * For now we only run KVM specific tests with AArch64 QEMU in
-     * order avoid attempting to run an AArch32 QEMU with KVM on
-     * AArch64 hosts. That won't work and isn't easy to detect.
-     */
-    if (g_str_equal(qtest_get_arch(), "aarch64")) {
-        qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
-                            NULL, test_query_cpu_model_expansion_kvm);
-    }
-
-    if (g_str_equal(qtest_get_arch(), "aarch64")) {
-        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-max-vq-8",
-                            NULL, sve_tests_sve_max_vq_8);
-        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-off",
-                            NULL, sve_tests_sve_off);
-        qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off",
-                            NULL, sve_tests_sve_off_kvm);
-    }
-
-    return g_test_run();
-}
diff --git a/tests/bios-tables-test-allowed-diff.h b/tests/bios-tables-test-allowed-diff.h
deleted file mode 100644 (file)
index dfb8523..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/* List of comma-separated changed AML files to ignore */
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
deleted file mode 100644 (file)
index f1ac2d7..0000000
+++ /dev/null
@@ -1,1046 +0,0 @@
-/*
- * Boot order test cases.
- *
- * Copyright (c) 2013 Red Hat Inc.
- *
- * Authors:
- *  Michael S. Tsirkin <[email protected]>,
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-/*
- * How to add or update the tests:
- * Contributor:
- * 1. add empty files for new tables, if any, under tests/data/acpi
- * 2. list any changed files in tests/bios-tables-test-allowed-diff.h
- * 3. commit the above *before* making changes that affect the tables
- * Maintainer:
- * After 1-3 above tests will pass but ignore differences with the expected files.
- * You will also notice that tests/bios-tables-test-allowed-diff.h lists
- * a bunch of files. This is your hint that you need to do the below:
- * 4. Run
- *      make check V=1
- * this will produce a bunch of warnings about differences
- * beween actual and expected ACPI tables. If you have IASL installed,
- * they will also be disassembled so you can look at the disassembled
- * output. If not - disassemble them yourself in any way you like.
- * Look at the differences - make sure they make sense and match what the
- * changes you are merging are supposed to do.
- *
- * 5. From build directory, run:
- *      $(SRC_PATH)/tests/data/acpi/rebuild-expected-aml.sh
- * 6. Now commit any changes.
- * 7. Before doing a pull request, make sure tests/bios-tables-test-allowed-diff.h
- *    is empty - this will ensure following changes to ACPI tables will
- *    be noticed.
- */
-
-#include "qemu/osdep.h"
-#include <glib/gstdio.h>
-#include "qemu-common.h"
-#include "hw/firmware/smbios.h"
-#include "qemu/bitmap.h"
-#include "acpi-utils.h"
-#include "boot-sector.h"
-
-#define MACHINE_PC "pc"
-#define MACHINE_Q35 "q35"
-
-#define ACPI_REBUILD_EXPECTED_AML "TEST_ACPI_REBUILD_AML"
-
-typedef struct {
-    bool tcg_only;
-    const char *machine;
-    const char *variant;
-    const char *uefi_fl1;
-    const char *uefi_fl2;
-    const char *cd;
-    const uint64_t ram_start;
-    const uint64_t scan_len;
-    uint64_t rsdp_addr;
-    uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
-    GArray *tables;
-    uint32_t smbios_ep_addr;
-    struct smbios_21_entry_point smbios_ep_table;
-    uint8_t *required_struct_types;
-    int required_struct_types_len;
-    QTestState *qts;
-} test_data;
-
-static char disk[] = "tests/acpi-test-disk-XXXXXX";
-static const char *data_dir = "tests/data/acpi";
-#ifdef CONFIG_IASL
-static const char *iasl = stringify(CONFIG_IASL);
-#else
-static const char *iasl;
-#endif
-
-static bool compare_signature(const AcpiSdtTable *sdt, const char *signature)
-{
-   return !memcmp(sdt->aml, signature, 4);
-}
-
-static void cleanup_table_descriptor(AcpiSdtTable *table)
-{
-    g_free(table->aml);
-    if (table->aml_file &&
-        !table->tmp_files_retain &&
-        g_strstr_len(table->aml_file, -1, "aml-")) {
-        unlink(table->aml_file);
-    }
-    g_free(table->aml_file);
-    g_free(table->asl);
-    if (table->asl_file &&
-        !table->tmp_files_retain) {
-        unlink(table->asl_file);
-    }
-    g_free(table->asl_file);
-}
-
-static void free_test_data(test_data *data)
-{
-    int i;
-
-    for (i = 0; i < data->tables->len; ++i) {
-        cleanup_table_descriptor(&g_array_index(data->tables, AcpiSdtTable, i));
-    }
-
-    g_array_free(data->tables, true);
-}
-
-static void test_acpi_rsdp_table(test_data *data)
-{
-    uint8_t *rsdp_table = data->rsdp_table;
-
-    acpi_fetch_rsdp_table(data->qts, data->rsdp_addr, rsdp_table);
-
-    switch (rsdp_table[15 /* Revision offset */]) {
-    case 0: /* ACPI 1.0 RSDP */
-        /* With rev 1, checksum is only for the first 20 bytes */
-        g_assert(!acpi_calc_checksum(rsdp_table,  20));
-        break;
-    case 2: /* ACPI 2.0+ RSDP */
-        /* With revision 2, we have 2 checksums */
-        g_assert(!acpi_calc_checksum(rsdp_table, 20));
-        g_assert(!acpi_calc_checksum(rsdp_table, 36));
-        break;
-    default:
-        g_assert_not_reached();
-    }
-}
-
-static void test_acpi_rxsdt_table(test_data *data)
-{
-    const char *sig = "RSDT";
-    AcpiSdtTable rsdt = {};
-    int entry_size = 4;
-    int addr_off = 16 /* RsdtAddress */;
-    uint8_t *ent;
-
-    if (data->rsdp_table[15 /* Revision offset */] != 0) {
-        addr_off = 24 /* XsdtAddress */;
-        entry_size = 8;
-        sig = "XSDT";
-    }
-    /* read [RX]SDT table */
-    acpi_fetch_table(data->qts, &rsdt.aml, &rsdt.aml_len,
-                     &data->rsdp_table[addr_off], entry_size, sig, true);
-
-    /* Load all tables and add to test list directly RSDT referenced tables */
-    ACPI_FOREACH_RSDT_ENTRY(rsdt.aml, rsdt.aml_len, ent, entry_size) {
-        AcpiSdtTable ssdt_table = {};
-
-        acpi_fetch_table(data->qts, &ssdt_table.aml, &ssdt_table.aml_len, ent,
-                         entry_size, NULL, true);
-        /* Add table to ASL test tables list */
-        g_array_append_val(data->tables, ssdt_table);
-    }
-    cleanup_table_descriptor(&rsdt);
-}
-
-static void test_acpi_fadt_table(test_data *data)
-{
-    /* FADT table is 1st */
-    AcpiSdtTable table = g_array_index(data->tables, typeof(table), 0);
-    uint8_t *fadt_aml = table.aml;
-    uint32_t fadt_len = table.aml_len;
-    uint32_t val;
-    int dsdt_offset = 40 /* DSDT */;
-    int dsdt_entry_size = 4;
-
-    g_assert(compare_signature(&table, "FACP"));
-
-    /* Since DSDT/FACS isn't in RSDT, add them to ASL test list manually */
-    memcpy(&val, fadt_aml + 112 /* Flags */, 4);
-    val = le32_to_cpu(val);
-    if (!(val & 1UL << 20 /* HW_REDUCED_ACPI */)) {
-        acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
-                         fadt_aml + 36 /* FIRMWARE_CTRL */, 4, "FACS", false);
-        g_array_append_val(data->tables, table);
-    }
-
-    memcpy(&val, fadt_aml + dsdt_offset, 4);
-    val = le32_to_cpu(val);
-    if (!val) {
-        dsdt_offset = 140 /* X_DSDT */;
-        dsdt_entry_size = 8;
-    }
-    acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
-                     fadt_aml + dsdt_offset, dsdt_entry_size, "DSDT", true);
-    g_array_append_val(data->tables, table);
-
-    memset(fadt_aml + 36, 0, 4); /* sanitize FIRMWARE_CTRL ptr */
-    memset(fadt_aml + 40, 0, 4); /* sanitize DSDT ptr */
-    if (fadt_aml[8 /* FADT Major Version */] >= 3) {
-        memset(fadt_aml + 132, 0, 8); /* sanitize X_FIRMWARE_CTRL ptr */
-        memset(fadt_aml + 140, 0, 8); /* sanitize X_DSDT ptr */
-    }
-
-    /* update checksum */
-    fadt_aml[9 /* Checksum */] = 0;
-    fadt_aml[9 /* Checksum */] -= acpi_calc_checksum(fadt_aml, fadt_len);
-}
-
-static void dump_aml_files(test_data *data, bool rebuild)
-{
-    AcpiSdtTable *sdt;
-    GError *error = NULL;
-    gchar *aml_file = NULL;
-    gint fd;
-    ssize_t ret;
-    int i;
-
-    for (i = 0; i < data->tables->len; ++i) {
-        const char *ext = data->variant ? data->variant : "";
-        sdt = &g_array_index(data->tables, AcpiSdtTable, i);
-        g_assert(sdt->aml);
-
-        if (rebuild) {
-            aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
-                                       sdt->aml, ext);
-            fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT,
-                        S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
-            if (fd < 0) {
-                perror(aml_file);
-            }
-            g_assert(fd >= 0);
-        } else {
-            fd = g_file_open_tmp("aml-XXXXXX", &sdt->aml_file, &error);
-            g_assert_no_error(error);
-        }
-
-        ret = qemu_write_full(fd, sdt->aml, sdt->aml_len);
-        g_assert(ret == sdt->aml_len);
-
-        close(fd);
-
-        g_free(aml_file);
-    }
-}
-
-static bool load_asl(GArray *sdts, AcpiSdtTable *sdt)
-{
-    AcpiSdtTable *temp;
-    GError *error = NULL;
-    GString *command_line = g_string_new(iasl);
-    gint fd;
-    gchar *out, *out_err;
-    gboolean ret;
-    int i;
-
-    fd = g_file_open_tmp("asl-XXXXXX.dsl", &sdt->asl_file, &error);
-    g_assert_no_error(error);
-    close(fd);
-
-    /* build command line */
-    g_string_append_printf(command_line, " -p %s ", sdt->asl_file);
-    if (compare_signature(sdt, "DSDT") ||
-        compare_signature(sdt, "SSDT")) {
-        for (i = 0; i < sdts->len; ++i) {
-            temp = &g_array_index(sdts, AcpiSdtTable, i);
-            if (compare_signature(temp, "DSDT") ||
-                compare_signature(temp, "SSDT")) {
-                g_string_append_printf(command_line, "-e %s ", temp->aml_file);
-            }
-        }
-    }
-    g_string_append_printf(command_line, "-d %s", sdt->aml_file);
-
-    /* pass 'out' and 'out_err' in order to be redirected */
-    ret = g_spawn_command_line_sync(command_line->str, &out, &out_err, NULL, &error);
-    g_assert_no_error(error);
-    if (ret) {
-        ret = g_file_get_contents(sdt->asl_file, &sdt->asl,
-                                  &sdt->asl_len, &error);
-        g_assert(ret);
-        g_assert_no_error(error);
-        ret = (sdt->asl_len > 0);
-    }
-
-    g_free(out);
-    g_free(out_err);
-    g_string_free(command_line, true);
-
-    return !ret;
-}
-
-#define COMMENT_END "*/"
-#define DEF_BLOCK "DefinitionBlock ("
-#define BLOCK_NAME_END ","
-
-static GString *normalize_asl(gchar *asl_code)
-{
-    GString *asl = g_string_new(asl_code);
-    gchar *comment, *block_name;
-
-    /* strip comments (different generation days) */
-    comment = g_strstr_len(asl->str, asl->len, COMMENT_END);
-    if (comment) {
-        comment += strlen(COMMENT_END);
-        while (*comment == '\n') {
-            comment++;
-        }
-        asl = g_string_erase(asl, 0, comment - asl->str);
-    }
-
-    /* strip def block name (it has file path in it) */
-    if (g_str_has_prefix(asl->str, DEF_BLOCK)) {
-        block_name = g_strstr_len(asl->str, asl->len, BLOCK_NAME_END);
-        g_assert(block_name);
-        asl = g_string_erase(asl, 0,
-                             block_name + sizeof(BLOCK_NAME_END) - asl->str);
-    }
-
-    return asl;
-}
-
-static GArray *load_expected_aml(test_data *data)
-{
-    int i;
-    AcpiSdtTable *sdt;
-    GError *error = NULL;
-    gboolean ret;
-    gsize aml_len;
-
-    GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable));
-    if (getenv("V")) {
-        fputc('\n', stderr);
-    }
-    for (i = 0; i < data->tables->len; ++i) {
-        AcpiSdtTable exp_sdt;
-        gchar *aml_file = NULL;
-        const char *ext = data->variant ? data->variant : "";
-
-        sdt = &g_array_index(data->tables, AcpiSdtTable, i);
-
-        memset(&exp_sdt, 0, sizeof(exp_sdt));
-
-try_again:
-        aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
-                                   sdt->aml, ext);
-        if (getenv("V")) {
-            fprintf(stderr, "Looking for expected file '%s'\n", aml_file);
-        }
-        if (g_file_test(aml_file, G_FILE_TEST_EXISTS)) {
-            exp_sdt.aml_file = aml_file;
-        } else if (*ext != '\0') {
-            /* try fallback to generic (extension less) expected file */
-            ext = "";
-            g_free(aml_file);
-            goto try_again;
-        }
-        g_assert(exp_sdt.aml_file);
-        if (getenv("V")) {
-            fprintf(stderr, "Using expected file '%s'\n", aml_file);
-        }
-        ret = g_file_get_contents(aml_file, (gchar **)&exp_sdt.aml,
-                                  &aml_len, &error);
-        exp_sdt.aml_len = aml_len;
-        g_assert(ret);
-        g_assert_no_error(error);
-        g_assert(exp_sdt.aml);
-        if (!exp_sdt.aml_len) {
-            fprintf(stderr, "Warning! zero length expected file '%s'\n",
-                    aml_file);
-        }
-
-        g_array_append_val(exp_tables, exp_sdt);
-    }
-
-    return exp_tables;
-}
-
-static bool test_acpi_find_diff_allowed(AcpiSdtTable *sdt)
-{
-    const gchar *allowed_diff_file[] = {
-#include "bios-tables-test-allowed-diff.h"
-        NULL
-    };
-    const gchar **f;
-
-    for (f = allowed_diff_file; *f; ++f) {
-        if (!g_strcmp0(sdt->aml_file, *f)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-/* test the list of tables in @data->tables against reference tables */
-static void test_acpi_asl(test_data *data)
-{
-    int i;
-    AcpiSdtTable *sdt, *exp_sdt;
-    test_data exp_data;
-    gboolean exp_err, err, all_tables_match = true;
-
-    memset(&exp_data, 0, sizeof(exp_data));
-    exp_data.tables = load_expected_aml(data);
-    dump_aml_files(data, false);
-    for (i = 0; i < data->tables->len; ++i) {
-        GString *asl, *exp_asl;
-
-        sdt = &g_array_index(data->tables, AcpiSdtTable, i);
-        exp_sdt = &g_array_index(exp_data.tables, AcpiSdtTable, i);
-
-        if (sdt->aml_len == exp_sdt->aml_len &&
-            !memcmp(sdt->aml, exp_sdt->aml, sdt->aml_len)) {
-            /* Identical table binaries: no need to disassemble. */
-            continue;
-        }
-
-        fprintf(stderr,
-                "acpi-test: Warning! %.4s binary file mismatch. "
-                "Actual [aml:%s], Expected [aml:%s].\n",
-                exp_sdt->aml, sdt->aml_file, exp_sdt->aml_file);
-
-        all_tables_match = all_tables_match &&
-            test_acpi_find_diff_allowed(exp_sdt);
-
-        /*
-         *  don't try to decompile if IASL isn't present, in this case user
-         * will just 'get binary file mismatch' warnings and test failure
-         */
-        if (!iasl) {
-            continue;
-        }
-
-        err = load_asl(data->tables, sdt);
-        asl = normalize_asl(sdt->asl);
-
-        exp_err = load_asl(exp_data.tables, exp_sdt);
-        exp_asl = normalize_asl(exp_sdt->asl);
-
-        /* TODO: check for warnings */
-        g_assert(!err || exp_err);
-
-        if (g_strcmp0(asl->str, exp_asl->str)) {
-            sdt->tmp_files_retain = true;
-            if (exp_err) {
-                fprintf(stderr,
-                        "Warning! iasl couldn't parse the expected aml\n");
-            } else {
-                exp_sdt->tmp_files_retain = true;
-                fprintf(stderr,
-                        "acpi-test: Warning! %.4s mismatch. "
-                        "Actual [asl:%s, aml:%s], Expected [asl:%s, aml:%s].\n",
-                        exp_sdt->aml, sdt->asl_file, sdt->aml_file,
-                        exp_sdt->asl_file, exp_sdt->aml_file);
-                if (getenv("V")) {
-                    const char *diff_cmd = getenv("DIFF");
-                    if (diff_cmd) {
-                        int ret G_GNUC_UNUSED;
-                        char *diff = g_strdup_printf("%s %s %s", diff_cmd,
-                            exp_sdt->asl_file, sdt->asl_file);
-                        ret = system(diff) ;
-                        g_free(diff);
-                    } else {
-                        fprintf(stderr, "acpi-test: Warning. not showing "
-                            "difference since no diff utility is specified. "
-                            "Set 'DIFF' environment variable to a preferred "
-                            "diff utility and run 'make V=1 check' again to "
-                            "see ASL difference.");
-                    }
-                }
-            }
-        }
-        g_string_free(asl, true);
-        g_string_free(exp_asl, true);
-    }
-    if (!iasl && !all_tables_match) {
-        fprintf(stderr, "to see ASL diff between mismatched files install IASL,"
-                " rebuild QEMU from scratch and re-run tests with V=1"
-                " environment variable set");
-    }
-    g_assert(all_tables_match);
-
-    free_test_data(&exp_data);
-}
-
-static bool smbios_ep_table_ok(test_data *data)
-{
-    struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
-    uint32_t addr = data->smbios_ep_addr;
-
-    qtest_memread(data->qts, addr, ep_table, sizeof(*ep_table));
-    if (memcmp(ep_table->anchor_string, "_SM_", 4)) {
-        return false;
-    }
-    if (memcmp(ep_table->intermediate_anchor_string, "_DMI_", 5)) {
-        return false;
-    }
-    if (ep_table->structure_table_length == 0) {
-        return false;
-    }
-    if (ep_table->number_of_structures == 0) {
-        return false;
-    }
-    if (acpi_calc_checksum((uint8_t *)ep_table, sizeof *ep_table) ||
-        acpi_calc_checksum((uint8_t *)ep_table + 0x10,
-                           sizeof *ep_table - 0x10)) {
-        return false;
-    }
-    return true;
-}
-
-static void test_smbios_entry_point(test_data *data)
-{
-    uint32_t off;
-
-    /* find smbios entry point structure */
-    for (off = 0xf0000; off < 0x100000; off += 0x10) {
-        uint8_t sig[] = "_SM_";
-        int i;
-
-        for (i = 0; i < sizeof sig - 1; ++i) {
-            sig[i] = qtest_readb(data->qts, off + i);
-        }
-
-        if (!memcmp(sig, "_SM_", sizeof sig)) {
-            /* signature match, but is this a valid entry point? */
-            data->smbios_ep_addr = off;
-            if (smbios_ep_table_ok(data)) {
-                break;
-            }
-        }
-    }
-
-    g_assert_cmphex(off, <, 0x100000);
-}
-
-static inline bool smbios_single_instance(uint8_t type)
-{
-    switch (type) {
-    case 0:
-    case 1:
-    case 2:
-    case 3:
-    case 16:
-    case 32:
-    case 127:
-        return true;
-    default:
-        return false;
-    }
-}
-
-static void test_smbios_structs(test_data *data)
-{
-    DECLARE_BITMAP(struct_bitmap, SMBIOS_MAX_TYPE+1) = { 0 };
-    struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
-    uint32_t addr = le32_to_cpu(ep_table->structure_table_address);
-    int i, len, max_len = 0;
-    uint8_t type, prv, crt;
-
-    /* walk the smbios tables */
-    for (i = 0; i < le16_to_cpu(ep_table->number_of_structures); i++) {
-
-        /* grab type and formatted area length from struct header */
-        type = qtest_readb(data->qts, addr);
-        g_assert_cmpuint(type, <=, SMBIOS_MAX_TYPE);
-        len = qtest_readb(data->qts, addr + 1);
-
-        /* single-instance structs must not have been encountered before */
-        if (smbios_single_instance(type)) {
-            g_assert(!test_bit(type, struct_bitmap));
-        }
-        set_bit(type, struct_bitmap);
-
-        /* seek to end of unformatted string area of this struct ("\0\0") */
-        prv = crt = 1;
-        while (prv || crt) {
-            prv = crt;
-            crt = qtest_readb(data->qts, addr + len);
-            len++;
-        }
-
-        /* keep track of max. struct size */
-        if (max_len < len) {
-            max_len = len;
-            g_assert_cmpuint(max_len, <=, ep_table->max_structure_size);
-        }
-
-        /* start of next structure */
-        addr += len;
-    }
-
-    /* total table length and max struct size must match entry point values */
-    g_assert_cmpuint(le16_to_cpu(ep_table->structure_table_length), ==,
-                     addr - le32_to_cpu(ep_table->structure_table_address));
-    g_assert_cmpuint(le16_to_cpu(ep_table->max_structure_size), ==, max_len);
-
-    /* required struct types must all be present */
-    for (i = 0; i < data->required_struct_types_len; i++) {
-        g_assert(test_bit(data->required_struct_types[i], struct_bitmap));
-    }
-}
-
-static void test_acpi_one(const char *params, test_data *data)
-{
-    char *args;
-    bool use_uefi = data->uefi_fl1 && data->uefi_fl2;
-
-    if (use_uefi) {
-        /*
-         * TODO: convert '-drive if=pflash' to new syntax (see e33763be7cd3)
-         * when arm/virt boad starts to support it.
-         */
-        args = g_strdup_printf("-machine %s %s -accel tcg -nodefaults -nographic "
-            "-drive if=pflash,format=raw,file=%s,readonly "
-            "-drive if=pflash,format=raw,file=%s,snapshot=on -cdrom %s %s",
-            data->machine, data->tcg_only ? "" : "-accel kvm",
-            data->uefi_fl1, data->uefi_fl2, data->cd, params ? params : "");
-
-    } else {
-        /* Disable kernel irqchip to be able to override apic irq0. */
-        args = g_strdup_printf("-machine %s,kernel-irqchip=off %s -accel tcg "
-            "-net none -display none %s "
-            "-drive id=hd0,if=none,file=%s,format=raw "
-            "-device ide-hd,drive=hd0 ",
-             data->machine, data->tcg_only ? "" : "-accel kvm",
-             params ? params : "", disk);
-    }
-
-    data->qts = qtest_init(args);
-
-    if (use_uefi) {
-        g_assert(data->scan_len);
-        data->rsdp_addr = acpi_find_rsdp_address_uefi(data->qts,
-            data->ram_start, data->scan_len);
-    } else {
-        boot_sector_test(data->qts);
-        data->rsdp_addr = acpi_find_rsdp_address(data->qts);
-        g_assert_cmphex(data->rsdp_addr, <, 0x100000);
-    }
-
-    data->tables = g_array_new(false, true, sizeof(AcpiSdtTable));
-    test_acpi_rsdp_table(data);
-    test_acpi_rxsdt_table(data);
-    test_acpi_fadt_table(data);
-
-    if (getenv(ACPI_REBUILD_EXPECTED_AML)) {
-        dump_aml_files(data, true);
-    } else {
-        test_acpi_asl(data);
-    }
-
-    /*
-     * TODO: make SMBIOS tests work with UEFI firmware,
-     * Bug on uefi-test-tools to provide entry point:
-     * https://bugs.launchpad.net/qemu/+bug/1821884
-     */
-    if (!use_uefi) {
-        test_smbios_entry_point(data);
-        test_smbios_structs(data);
-    }
-
-    qtest_quit(data->qts);
-    g_free(args);
-}
-
-static uint8_t base_required_struct_types[] = {
-    0, 1, 3, 4, 16, 17, 19, 32, 127
-};
-
-static void test_acpi_piix4_tcg(void)
-{
-    test_data data;
-
-    /* Supplying -machine accel argument overrides the default (qtest).
-     * This is to make guest actually run.
-     */
-    memset(&data, 0, sizeof(data));
-    data.machine = MACHINE_PC;
-    data.required_struct_types = base_required_struct_types;
-    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
-    test_acpi_one(NULL, &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_piix4_tcg_bridge(void)
-{
-    test_data data;
-
-    memset(&data, 0, sizeof(data));
-    data.machine = MACHINE_PC;
-    data.variant = ".bridge";
-    data.required_struct_types = base_required_struct_types;
-    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
-    test_acpi_one("-device pci-bridge,chassis_nr=1", &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_q35_tcg(void)
-{
-    test_data data;
-
-    memset(&data, 0, sizeof(data));
-    data.machine = MACHINE_Q35;
-    data.required_struct_types = base_required_struct_types;
-    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
-    test_acpi_one(NULL, &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_q35_tcg_bridge(void)
-{
-    test_data data;
-
-    memset(&data, 0, sizeof(data));
-    data.machine = MACHINE_Q35;
-    data.variant = ".bridge";
-    data.required_struct_types = base_required_struct_types;
-    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
-    test_acpi_one("-device pci-bridge,chassis_nr=1",
-                  &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_q35_tcg_mmio64(void)
-{
-    test_data data = {
-        .machine = MACHINE_Q35,
-        .variant = ".mmio64",
-        .required_struct_types = base_required_struct_types,
-        .required_struct_types_len = ARRAY_SIZE(base_required_struct_types)
-    };
-
-    test_acpi_one("-m 128M,slots=1,maxmem=2G "
-                  "-object memory-backend-ram,id=ram0,size=128M "
-                  "-numa node,memdev=ram0 "
-                  "-device pci-testdev,membar=2G",
-                  &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_piix4_tcg_cphp(void)
-{
-    test_data data;
-
-    memset(&data, 0, sizeof(data));
-    data.machine = MACHINE_PC;
-    data.variant = ".cphp";
-    test_acpi_one("-smp 2,cores=3,sockets=2,maxcpus=6"
-                  " -object memory-backend-ram,id=ram0,size=64M"
-                  " -object memory-backend-ram,id=ram1,size=64M"
-                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
-                  " -numa dist,src=0,dst=1,val=21",
-                  &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_q35_tcg_cphp(void)
-{
-    test_data data;
-
-    memset(&data, 0, sizeof(data));
-    data.machine = MACHINE_Q35;
-    data.variant = ".cphp";
-    test_acpi_one(" -smp 2,cores=3,sockets=2,maxcpus=6"
-                  " -object memory-backend-ram,id=ram0,size=64M"
-                  " -object memory-backend-ram,id=ram1,size=64M"
-                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
-                  " -numa dist,src=0,dst=1,val=21",
-                  &data);
-    free_test_data(&data);
-}
-
-static uint8_t ipmi_required_struct_types[] = {
-    0, 1, 3, 4, 16, 17, 19, 32, 38, 127
-};
-
-static void test_acpi_q35_tcg_ipmi(void)
-{
-    test_data data;
-
-    memset(&data, 0, sizeof(data));
-    data.machine = MACHINE_Q35;
-    data.variant = ".ipmibt";
-    data.required_struct_types = ipmi_required_struct_types;
-    data.required_struct_types_len = ARRAY_SIZE(ipmi_required_struct_types);
-    test_acpi_one("-device ipmi-bmc-sim,id=bmc0"
-                  " -device isa-ipmi-bt,bmc=bmc0",
-                  &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_piix4_tcg_ipmi(void)
-{
-    test_data data;
-
-    /* Supplying -machine accel argument overrides the default (qtest).
-     * This is to make guest actually run.
-     */
-    memset(&data, 0, sizeof(data));
-    data.machine = MACHINE_PC;
-    data.variant = ".ipmikcs";
-    data.required_struct_types = ipmi_required_struct_types;
-    data.required_struct_types_len = ARRAY_SIZE(ipmi_required_struct_types);
-    test_acpi_one("-device ipmi-bmc-sim,id=bmc0"
-                  " -device isa-ipmi-kcs,irq=0,bmc=bmc0",
-                  &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_q35_tcg_memhp(void)
-{
-    test_data data;
-
-    memset(&data, 0, sizeof(data));
-    data.machine = MACHINE_Q35;
-    data.variant = ".memhp";
-    test_acpi_one(" -m 128,slots=3,maxmem=1G"
-                  " -object memory-backend-ram,id=ram0,size=64M"
-                  " -object memory-backend-ram,id=ram1,size=64M"
-                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
-                  " -numa dist,src=0,dst=1,val=21",
-                  &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_piix4_tcg_memhp(void)
-{
-    test_data data;
-
-    memset(&data, 0, sizeof(data));
-    data.machine = MACHINE_PC;
-    data.variant = ".memhp";
-    test_acpi_one(" -m 128,slots=3,maxmem=1G"
-                  " -object memory-backend-ram,id=ram0,size=64M"
-                  " -object memory-backend-ram,id=ram1,size=64M"
-                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
-                  " -numa dist,src=0,dst=1,val=21",
-                  &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_q35_tcg_numamem(void)
-{
-    test_data data;
-
-    memset(&data, 0, sizeof(data));
-    data.machine = MACHINE_Q35;
-    data.variant = ".numamem";
-    test_acpi_one(" -object memory-backend-ram,id=ram0,size=128M"
-                  " -numa node -numa node,memdev=ram0", &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_piix4_tcg_numamem(void)
-{
-    test_data data;
-
-    memset(&data, 0, sizeof(data));
-    data.machine = MACHINE_PC;
-    data.variant = ".numamem";
-    test_acpi_one(" -object memory-backend-ram,id=ram0,size=128M"
-                  " -numa node -numa node,memdev=ram0", &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_tcg_dimm_pxm(const char *machine)
-{
-    test_data data;
-
-    memset(&data, 0, sizeof(data));
-    data.machine = machine;
-    data.variant = ".dimmpxm";
-    test_acpi_one(" -machine nvdimm=on,nvdimm-persistence=cpu"
-                  " -smp 4,sockets=4"
-                  " -m 128M,slots=3,maxmem=1G"
-                  " -object memory-backend-ram,id=ram0,size=32M"
-                  " -object memory-backend-ram,id=ram1,size=32M"
-                  " -object memory-backend-ram,id=ram2,size=32M"
-                  " -object memory-backend-ram,id=ram3,size=32M"
-                  " -numa node,memdev=ram0,nodeid=0"
-                  " -numa node,memdev=ram1,nodeid=1"
-                  " -numa node,memdev=ram2,nodeid=2"
-                  " -numa node,memdev=ram3,nodeid=3"
-                  " -numa cpu,node-id=0,socket-id=0"
-                  " -numa cpu,node-id=1,socket-id=1"
-                  " -numa cpu,node-id=2,socket-id=2"
-                  " -numa cpu,node-id=3,socket-id=3"
-                  " -object memory-backend-ram,id=ram4,size=128M"
-                  " -object memory-backend-ram,id=nvm0,size=128M"
-                  " -device pc-dimm,id=dimm0,memdev=ram4,node=1"
-                  " -device nvdimm,id=dimm1,memdev=nvm0,node=2",
-                  &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_q35_tcg_dimm_pxm(void)
-{
-    test_acpi_tcg_dimm_pxm(MACHINE_Q35);
-}
-
-static void test_acpi_piix4_tcg_dimm_pxm(void)
-{
-    test_acpi_tcg_dimm_pxm(MACHINE_PC);
-}
-
-static void test_acpi_virt_tcg_memhp(void)
-{
-    test_data data = {
-        .machine = "virt",
-        .tcg_only = true,
-        .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
-        .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
-        .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
-        .ram_start = 0x40000000ULL,
-        .scan_len = 256ULL * 1024 * 1024,
-    };
-
-    data.variant = ".memhp";
-    test_acpi_one(" -cpu cortex-a57"
-                  " -m 256M,slots=3,maxmem=1G"
-                  " -object memory-backend-ram,id=ram0,size=128M"
-                  " -object memory-backend-ram,id=ram1,size=128M"
-                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
-                  " -numa dist,src=0,dst=1,val=21",
-                  &data);
-
-    free_test_data(&data);
-
-}
-
-static void test_acpi_virt_tcg_numamem(void)
-{
-    test_data data = {
-        .machine = "virt",
-        .tcg_only = true,
-        .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
-        .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
-        .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
-        .ram_start = 0x40000000ULL,
-        .scan_len = 128ULL * 1024 * 1024,
-    };
-
-    data.variant = ".numamem";
-    test_acpi_one(" -cpu cortex-a57"
-                  " -object memory-backend-ram,id=ram0,size=128M"
-                  " -numa node,memdev=ram0",
-                  &data);
-
-    free_test_data(&data);
-
-}
-
-static void test_acpi_tcg_acpi_hmat(const char *machine)
-{
-    test_data data;
-
-    memset(&data, 0, sizeof(data));
-    data.machine = machine;
-    data.variant = ".acpihmat";
-    test_acpi_one(" -machine hmat=on"
-                  " -smp 2,sockets=2"
-                  " -m 128M,slots=2,maxmem=1G"
-                  " -object memory-backend-ram,size=64M,id=m0"
-                  " -object memory-backend-ram,size=64M,id=m1"
-                  " -numa node,nodeid=0,memdev=m0"
-                  " -numa node,nodeid=1,memdev=m1,initiator=0"
-                  " -numa cpu,node-id=0,socket-id=0"
-                  " -numa cpu,node-id=0,socket-id=1"
-                  " -numa hmat-lb,initiator=0,target=0,hierarchy=memory,"
-                  "data-type=access-latency,latency=1"
-                  " -numa hmat-lb,initiator=0,target=0,hierarchy=memory,"
-                  "data-type=access-bandwidth,bandwidth=65534M"
-                  " -numa hmat-lb,initiator=0,target=1,hierarchy=memory,"
-                  "data-type=access-latency,latency=65534"
-                  " -numa hmat-lb,initiator=0,target=1,hierarchy=memory,"
-                  "data-type=access-bandwidth,bandwidth=32767M"
-                  " -numa hmat-cache,node-id=0,size=10K,level=1,"
-                  "associativity=direct,policy=write-back,line=8"
-                  " -numa hmat-cache,node-id=1,size=10K,level=1,"
-                  "associativity=direct,policy=write-back,line=8",
-                  &data);
-    free_test_data(&data);
-}
-
-static void test_acpi_q35_tcg_acpi_hmat(void)
-{
-    test_acpi_tcg_acpi_hmat(MACHINE_Q35);
-}
-
-static void test_acpi_piix4_tcg_acpi_hmat(void)
-{
-    test_acpi_tcg_acpi_hmat(MACHINE_PC);
-}
-
-static void test_acpi_virt_tcg(void)
-{
-    test_data data = {
-        .machine = "virt",
-        .tcg_only = true,
-        .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
-        .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
-        .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
-        .ram_start = 0x40000000ULL,
-        .scan_len = 128ULL * 1024 * 1024,
-    };
-
-    test_acpi_one("-cpu cortex-a57", &data);
-    free_test_data(&data);
-}
-
-int main(int argc, char *argv[])
-{
-    const char *arch = qtest_get_arch();
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        ret = boot_sector_init(disk);
-        if (ret) {
-            return ret;
-        }
-
-        qtest_add_func("acpi/piix4", test_acpi_piix4_tcg);
-        qtest_add_func("acpi/piix4/bridge", test_acpi_piix4_tcg_bridge);
-        qtest_add_func("acpi/q35", test_acpi_q35_tcg);
-        qtest_add_func("acpi/q35/bridge", test_acpi_q35_tcg_bridge);
-        qtest_add_func("acpi/q35/mmio64", test_acpi_q35_tcg_mmio64);
-        qtest_add_func("acpi/piix4/ipmi", test_acpi_piix4_tcg_ipmi);
-        qtest_add_func("acpi/q35/ipmi", test_acpi_q35_tcg_ipmi);
-        qtest_add_func("acpi/piix4/cpuhp", test_acpi_piix4_tcg_cphp);
-        qtest_add_func("acpi/q35/cpuhp", test_acpi_q35_tcg_cphp);
-        qtest_add_func("acpi/piix4/memhp", test_acpi_piix4_tcg_memhp);
-        qtest_add_func("acpi/q35/memhp", test_acpi_q35_tcg_memhp);
-        qtest_add_func("acpi/piix4/numamem", test_acpi_piix4_tcg_numamem);
-        qtest_add_func("acpi/q35/numamem", test_acpi_q35_tcg_numamem);
-        qtest_add_func("acpi/piix4/dimmpxm", test_acpi_piix4_tcg_dimm_pxm);
-        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);
-    } else if (strcmp(arch, "aarch64") == 0) {
-        qtest_add_func("acpi/virt", test_acpi_virt_tcg);
-        qtest_add_func("acpi/virt/numamem", test_acpi_virt_tcg_numamem);
-        qtest_add_func("acpi/virt/memhp", test_acpi_virt_tcg_memhp);
-    }
-    ret = g_test_run();
-    boot_sector_cleanup(disk);
-    return ret;
-}
diff --git a/tests/boot-order-test.c b/tests/boot-order-test.c
deleted file mode 100644 (file)
index a725bce..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Boot order test cases.
- *
- * Copyright (c) 2013 Red Hat Inc.
- *
- * Authors:
- *  Markus Armbruster <[email protected]>,
- *
- * 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 "libqos/fw_cfg.h"
-#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "standard-headers/linux/qemu_fw_cfg.h"
-
-/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(qs, ...) qobject_unref(qtest_qmp(qs, __VA_ARGS__))
-
-typedef struct {
-    const char *args;
-    uint64_t expected_boot;
-    uint64_t expected_reboot;
-} boot_order_test;
-
-static void test_a_boot_order(const char *machine,
-                              const char *test_args,
-                              uint64_t (*read_boot_order)(QTestState *),
-                              uint64_t expected_boot,
-                              uint64_t expected_reboot)
-{
-    uint64_t actual;
-    QTestState *qts;
-
-    qts = qtest_initf("-nodefaults%s%s %s", machine ? " -M " : "",
-                      machine ?: "", test_args);
-    actual = read_boot_order(qts);
-    g_assert_cmphex(actual, ==, expected_boot);
-    qmp_discard_response(qts, "{ 'execute': 'system_reset' }");
-    /*
-     * system_reset only requests reset.  We get a RESET event after
-     * the actual reset completes.  Need to wait for that.
-     */
-    qtest_qmp_eventwait(qts, "RESET");
-    actual = read_boot_order(qts);
-    g_assert_cmphex(actual, ==, expected_reboot);
-    qtest_quit(qts);
-}
-
-static void test_boot_orders(const char *machine,
-                             uint64_t (*read_boot_order)(QTestState *),
-                             const boot_order_test *tests)
-{
-    int i;
-
-    for (i = 0; tests[i].args; i++) {
-        test_a_boot_order(machine, tests[i].args,
-                          read_boot_order,
-                          tests[i].expected_boot,
-                          tests[i].expected_reboot);
-    }
-}
-
-static uint8_t read_mc146818(QTestState *qts, uint16_t port, uint8_t reg)
-{
-    qtest_outb(qts, port, reg);
-    return qtest_inb(qts, port + 1);
-}
-
-static uint64_t read_boot_order_pc(QTestState *qts)
-{
-    uint8_t b1 = read_mc146818(qts, 0x70, 0x38);
-    uint8_t b2 = read_mc146818(qts, 0x70, 0x3d);
-
-    return b1 | (b2 << 8);
-}
-
-static const boot_order_test test_cases_pc[] = {
-    { "",
-      0x1230, 0x1230 },
-    { "-no-fd-bootchk",
-      0x1231, 0x1231 },
-    { "-boot c",
-      0x0200, 0x0200 },
-    { "-boot nda",
-      0x3410, 0x3410 },
-    { "-boot order=",
-      0, 0 },
-    { "-boot order= -boot order=c",
-      0x0200, 0x0200 },
-    { "-boot once=a",
-      0x0100, 0x1230 },
-    { "-boot once=a -no-fd-bootchk",
-      0x0101, 0x1231 },
-    { "-boot once=a,order=c",
-      0x0100, 0x0200 },
-    { "-boot once=d -boot order=nda",
-      0x0300, 0x3410 },
-    { "-boot once=a -boot once=b -boot once=c",
-      0x0200, 0x1230 },
-    {}
-};
-
-static void test_pc_boot_order(void)
-{
-    test_boot_orders(NULL, read_boot_order_pc, test_cases_pc);
-}
-
-static uint8_t read_m48t59(QTestState *qts, uint64_t addr, uint16_t reg)
-{
-    qtest_writeb(qts, addr, reg & 0xff);
-    qtest_writeb(qts, addr + 1, reg >> 8);
-    return qtest_readb(qts, addr + 3);
-}
-
-static uint64_t read_boot_order_prep(QTestState *qts)
-{
-    return read_m48t59(qts, 0x80000000 + 0x74, 0x34);
-}
-
-static const boot_order_test test_cases_prep[] = {
-    { "", 'c', 'c' },
-    { "-boot c", 'c', 'c' },
-    { "-boot d", 'd', 'd' },
-    {}
-};
-
-static void test_prep_boot_order(void)
-{
-    test_boot_orders("prep", read_boot_order_prep, test_cases_prep);
-}
-
-static uint64_t read_boot_order_pmac(QTestState *qts)
-{
-    QFWCFG *fw_cfg = mm_fw_cfg_init(qts, 0xf0000510);
-
-    return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
-}
-
-static const boot_order_test test_cases_fw_cfg[] = {
-    { "", 'c', 'c' },
-    { "-boot c", 'c', 'c' },
-    { "-boot d", 'd', 'd' },
-    { "-boot once=d,order=c", 'd', 'c' },
-    {}
-};
-
-static void test_pmac_oldworld_boot_order(void)
-{
-    test_boot_orders("g3beige", read_boot_order_pmac, test_cases_fw_cfg);
-}
-
-static void test_pmac_newworld_boot_order(void)
-{
-    test_boot_orders("mac99", read_boot_order_pmac, test_cases_fw_cfg);
-}
-
-static uint64_t read_boot_order_sun4m(QTestState *qts)
-{
-    QFWCFG *fw_cfg = mm_fw_cfg_init(qts, 0xd00000510ULL);
-
-    return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
-}
-
-static void test_sun4m_boot_order(void)
-{
-    test_boot_orders("SS-5", read_boot_order_sun4m, test_cases_fw_cfg);
-}
-
-static uint64_t read_boot_order_sun4u(QTestState *qts)
-{
-    QFWCFG *fw_cfg = io_fw_cfg_init(qts, 0x510);
-
-    return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
-}
-
-static void test_sun4u_boot_order(void)
-{
-    test_boot_orders("sun4u", read_boot_order_sun4u, test_cases_fw_cfg);
-}
-
-int main(int argc, char *argv[])
-{
-    const char *arch = qtest_get_arch();
-
-    g_test_init(&argc, &argv, NULL);
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        qtest_add_func("boot-order/pc", test_pc_boot_order);
-    } else if (strcmp(arch, "ppc") == 0 || strcmp(arch, "ppc64") == 0) {
-        qtest_add_func("boot-order/prep", test_prep_boot_order);
-        qtest_add_func("boot-order/pmac_oldworld",
-                       test_pmac_oldworld_boot_order);
-        qtest_add_func("boot-order/pmac_newworld",
-                       test_pmac_newworld_boot_order);
-    } else if (strcmp(arch, "sparc") == 0) {
-        qtest_add_func("boot-order/sun4m", test_sun4m_boot_order);
-    } else if (strcmp(arch, "sparc64") == 0) {
-        qtest_add_func("boot-order/sun4u", test_sun4u_boot_order);
-    }
-
-    return g_test_run();
-}
diff --git a/tests/boot-sector.c b/tests/boot-sector.c
deleted file mode 100644 (file)
index 9e66c6d..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * QEMU boot sector testing helpers.
- *
- * Copyright (c) 2016 Red Hat Inc.
- *
- * Authors:
- *  Michael S. Tsirkin <[email protected]>
- *  Victor Kaplansky <[email protected]>
- *
- * 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 "boot-sector.h"
-#include "qemu-common.h"
-#include "libqtest.h"
-
-#define LOW(x) ((x) & 0xff)
-#define HIGH(x) ((x) >> 8)
-
-#define SIGNATURE 0xdead
-#define SIGNATURE_OFFSET 0x10
-#define BOOT_SECTOR_ADDRESS 0x7c00
-#define SIGNATURE_ADDR (BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET)
-
-/* x86 boot sector code: write SIGNATURE into memory,
- * then halt.
- */
-static uint8_t x86_boot_sector[512] = {
-    /* The first sector will be placed at RAM address 00007C00, and
-     * the BIOS transfers control to 00007C00
-     */
-
-    /* Data Segment register should be initialized, since pxe
-     * boot loader can leave it dirty.
-     */
-
-    /* 7c00: move $0000,%ax */
-    [0x00] = 0xb8,
-    [0x01] = 0x00,
-    [0x02] = 0x00,
-    /* 7c03: move %ax,%ds */
-    [0x03] = 0x8e,
-    [0x04] = 0xd8,
-
-    /* 7c05: mov $0xdead,%ax */
-    [0x05] = 0xb8,
-    [0x06] = LOW(SIGNATURE),
-    [0x07] = HIGH(SIGNATURE),
-    /* 7c08:  mov %ax,0x7c10 */
-    [0x08] = 0xa3,
-    [0x09] = LOW(SIGNATURE_ADDR),
-    [0x0a] = HIGH(SIGNATURE_ADDR),
-
-    /* 7c0b cli */
-    [0x0b] = 0xfa,
-    /* 7c0c: hlt */
-    [0x0c] = 0xf4,
-    /* 7c0e: jmp 0x7c07=0x7c0f-3 */
-    [0x0d] = 0xeb,
-    [0x0e] = LOW(-3),
-    /* We mov 0xdead here: set value to make debugging easier */
-    [SIGNATURE_OFFSET] = LOW(0xface),
-    [SIGNATURE_OFFSET + 1] = HIGH(0xface),
-    /* End of boot sector marker */
-    [0x1FE] = 0x55,
-    [0x1FF] = 0xAA,
-};
-
-/* For s390x, use a mini "kernel" with the appropriate signature */
-static const uint8_t s390x_psw_and_magic[] = {
-    0x00, 0x08, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,  /* Program status word  */
-    0x02, 0x00, 0x00, 0x18, 0x60, 0x00, 0x00, 0x50,  /* Magic:               */
-    0x02, 0x00, 0x00, 0x68, 0x60, 0x00, 0x00, 0x50,  /* see linux_s390_magic */
-    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* in the s390-ccw bios */
-};
-static const uint8_t s390x_code[] = {
-    0xa7, 0xf4, 0x00, 0x08,                                /* j 0x10010 */
-    0x00, 0x00, 0x00, 0x00,
-    'S', '3', '9', '0',
-    'E', 'P', 0x00, 0x01,
-    0xa7, 0x39, HIGH(SIGNATURE_ADDR), LOW(SIGNATURE_ADDR), /* lghi r3,0x7c10 */
-    0xa7, 0x48, LOW(SIGNATURE), HIGH(SIGNATURE),           /* lhi r4,0xadde */
-    0x40, 0x40, 0x30, 0x00,                                /* sth r4,0(r3) */
-    0xa7, 0xf4, 0xff, 0xfa                                 /* j 0x10010 */
-};
-
-/* Create boot disk file.  */
-int boot_sector_init(char *fname)
-{
-    int fd, ret;
-    size_t len;
-    char *boot_code;
-    const char *arch = qtest_get_arch();
-
-    fd = mkstemp(fname);
-    if (fd < 0) {
-        fprintf(stderr, "Couldn't open \"%s\": %s", fname, strerror(errno));
-        return 1;
-    }
-
-    if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64")) {
-        /* Q35 requires a minimum 0x7e000 bytes disk (bug or feature?) */
-        len = MAX(0x7e000, sizeof(x86_boot_sector));
-        boot_code = g_malloc0(len);
-        memcpy(boot_code, x86_boot_sector, sizeof(x86_boot_sector));
-    } else if (g_str_equal(arch, "ppc64")) {
-        /* For Open Firmware based system, use a Forth script */
-        boot_code = g_strdup_printf("\\ Bootscript\n%x %x c! %x %x c!\n",
-                                    LOW(SIGNATURE), SIGNATURE_ADDR,
-                                    HIGH(SIGNATURE), SIGNATURE_ADDR + 1);
-        len = strlen(boot_code);
-    } else if (g_str_equal(arch, "s390x")) {
-        len = 0x10000 + sizeof(s390x_code);
-        boot_code = g_malloc0(len);
-        memcpy(boot_code, s390x_psw_and_magic, sizeof(s390x_psw_and_magic));
-        memcpy(&boot_code[0x10000], s390x_code, sizeof(s390x_code));
-    } else {
-        g_assert_not_reached();
-    }
-
-    ret = write(fd, boot_code, len);
-    close(fd);
-
-    g_free(boot_code);
-
-    if (ret != len) {
-        fprintf(stderr, "Could not write \"%s\"", fname);
-        return 1;
-    }
-
-    return 0;
-}
-
-/* Loop until signature in memory is OK.  */
-void boot_sector_test(QTestState *qts)
-{
-    uint8_t signature_low;
-    uint8_t signature_high;
-    uint16_t signature;
-    int i;
-
-    /* Wait at most 600 seconds (test is slow with TCI and --enable-debug) */
-#define TEST_DELAY (1 * G_USEC_PER_SEC / 10)
-#define TEST_CYCLES MAX((600 * G_USEC_PER_SEC / TEST_DELAY), 1)
-
-    /* Poll until code has run and modified memory.  Once it has we know BIOS
-     * initialization is done.  TODO: check that IP reached the halt
-     * instruction.
-     */
-    for (i = 0; i < TEST_CYCLES; ++i) {
-        signature_low = qtest_readb(qts, SIGNATURE_ADDR);
-        signature_high = qtest_readb(qts, SIGNATURE_ADDR + 1);
-        signature = (signature_high << 8) | signature_low;
-        if (signature == SIGNATURE) {
-            break;
-        }
-        g_usleep(TEST_DELAY);
-    }
-
-    g_assert_cmphex(signature, ==, SIGNATURE);
-}
-
-/* unlink boot disk file.  */
-void boot_sector_cleanup(const char *fname)
-{
-    unlink(fname);
-}
diff --git a/tests/boot-sector.h b/tests/boot-sector.h
deleted file mode 100644 (file)
index 6ee6bb4..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * QEMU boot sector testing helpers.
- *
- * Copyright (c) 2016 Red Hat Inc.
- *
- * Authors:
- *  Michael S. Tsirkin <[email protected]>
- *  Victor Kaplansky <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef TEST_BOOT_SECTOR_H
-#define TEST_BOOT_SECTOR_H
-
-#include "libqtest.h"
-
-/* Create boot disk file. fname must be a suitable string for mkstemp() */
-int boot_sector_init(char *fname);
-
-/* Loop until signature in memory is OK.  */
-void boot_sector_test(QTestState *qts);
-
-/* unlink boot disk file.  */
-void boot_sector_cleanup(const char *fname);
-
-#endif /* TEST_BOOT_SECTOR_H */
diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c
deleted file mode 100644 (file)
index 05c7f44..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Test serial output of some machines.
- *
- * Copyright 2016 Thomas Huth, Red Hat Inc.
- *
- * This work is licensed under the terms of the GNU GPL, version 2
- * or later. See the COPYING file in the top-level directory.
- *
- * This test is used to check that the serial output of the firmware
- * (that we provide for some machines) or some small mini-kernels that
- * we provide here contains an expected string. Thus we check that the
- * firmware/kernel still boots at least to a certain point and so we
- * know that the machine is not completely broken.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-
-static const uint8_t kernel_mcf5208[] = {
-    0x41, 0xf9, 0xfc, 0x06, 0x00, 0x00,     /* lea 0xfc060000,%a0 */
-    0x10, 0x3c, 0x00, 0x54,                 /* move.b #'T',%d0 */
-    0x11, 0x7c, 0x00, 0x04, 0x00, 0x08,     /* move.b #4,8(%a0)     Enable TX */
-    0x11, 0x40, 0x00, 0x0c,                 /* move.b %d0,12(%a0)   Print 'T' */
-    0x60, 0xfa                              /* bra.s  loop */
-};
-
-static const uint8_t bios_nextcube[] = {
-    0x06, 0x00, 0x00, 0x00,                 /* Initial SP */
-    0x01, 0x00, 0x00, 0x08,                 /* Initial PC */
-    0x41, 0xf9, 0x02, 0x11, 0x80, 0x00,     /* lea 0x02118000,%a0 */
-    0x10, 0x3c, 0x00, 0x54,                 /* move.b #'T',%d0 */
-    0x11, 0x7c, 0x00, 0x05, 0x00, 0x01,     /* move.b #5,1(%a0)    Sel TXCTRL */
-    0x11, 0x7c, 0x00, 0x68, 0x00, 0x01,     /* move.b #0x68,1(%a0) Enable TX */
-    0x11, 0x40, 0x00, 0x03,                 /* move.b %d0,3(%a0)   Print 'T' */
-    0x60, 0xfa                              /* bra.s  loop */
-};
-
-static const uint8_t kernel_pls3adsp1800[] = {
-    0xb0, 0x00, 0x84, 0x00,                 /* imm   0x8400 */
-    0x30, 0x60, 0x00, 0x04,                 /* addik r3,r0,4 */
-    0x30, 0x80, 0x00, 0x54,                 /* addik r4,r0,'T' */
-    0xf0, 0x83, 0x00, 0x00,                 /* sbi   r4,r3,0 */
-    0xb8, 0x00, 0xff, 0xfc                  /* bri   -4  loop */
-};
-
-static const uint8_t kernel_plml605[] = {
-    0xe0, 0x83, 0x00, 0xb0,                 /* imm   0x83e0 */
-    0x00, 0x10, 0x60, 0x30,                 /* addik r3,r0,0x1000 */
-    0x54, 0x00, 0x80, 0x30,                 /* addik r4,r0,'T' */
-    0x00, 0x00, 0x83, 0xf0,                 /* sbi   r4,r3,0 */
-    0xfc, 0xff, 0x00, 0xb8                  /* bri   -4  loop */
-};
-
-static const uint8_t bios_moxiesim[] = {
-    0x20, 0x10, 0x00, 0x00, 0x03, 0xf8,     /* ldi.s r1,0x3f8 */
-    0x1b, 0x20, 0x00, 0x00, 0x00, 0x54,     /* ldi.b r2,'T' */
-    0x1e, 0x12,                             /* st.b  r1,r2 */
-    0x1a, 0x00, 0x00, 0x00, 0x10, 0x00      /* jmpa  0x1000 */
-};
-
-static const uint8_t bios_raspi2[] = {
-    0x08, 0x30, 0x9f, 0xe5,                 /* ldr   r3,[pc,#8]    Get base */
-    0x54, 0x20, 0xa0, 0xe3,                 /* mov     r2,#'T' */
-    0x00, 0x20, 0xc3, 0xe5,                 /* strb    r2,[r3] */
-    0xfb, 0xff, 0xff, 0xea,                 /* b       loop */
-    0x00, 0x10, 0x20, 0x3f,                 /* 0x3f201000 = UART0 base addr */
-};
-
-static const uint8_t kernel_aarch64[] = {
-    0x81, 0x0a, 0x80, 0x52,                 /* mov     w1, #0x54 */
-    0x02, 0x20, 0xa1, 0xd2,                 /* mov     x2, #0x9000000 */
-    0x41, 0x00, 0x00, 0x39,                 /* strb    w1, [x2] */
-    0xfd, 0xff, 0xff, 0x17,                 /* b       -12 (loop) */
-};
-
-static const uint8_t kernel_nrf51[] = {
-    0x00, 0x00, 0x00, 0x00,                 /* Stack top address */
-    0x09, 0x00, 0x00, 0x00,                 /* Reset handler address */
-    0x04, 0x4a,                             /* ldr  r2, [pc, #16] Get ENABLE */
-    0x04, 0x21,                             /* movs r1, #4 */
-    0x11, 0x60,                             /* str  r1, [r2] */
-    0x04, 0x4a,                             /* ldr  r2, [pc, #16] Get STARTTX */
-    0x01, 0x21,                             /* movs r1, #1 */
-    0x11, 0x60,                             /* str  r1, [r2] */
-    0x03, 0x4a,                             /* ldr  r2, [pc, #12] Get TXD */
-    0x54, 0x21,                             /* movs r1, 'T' */
-    0x11, 0x60,                             /* str  r1, [r2] */
-    0xfe, 0xe7,                             /* b    . */
-    0x00, 0x25, 0x00, 0x40,                 /* 0x40002500 = UART ENABLE */
-    0x08, 0x20, 0x00, 0x40,                 /* 0x40002008 = UART STARTTX */
-    0x1c, 0x25, 0x00, 0x40                  /* 0x4000251c = UART TXD */
-};
-
-typedef struct testdef {
-    const char *arch;       /* Target architecture */
-    const char *machine;    /* Name of the machine */
-    const char *extra;      /* Additional parameters */
-    const char *expect;     /* Expected string in the serial output */
-    size_t codesize;        /* Size of the kernel or bios data */
-    const uint8_t *kernel;  /* Set in case we use our own mini kernel */
-    const uint8_t *bios;    /* Set in case we use our own mini bios */
-} testdef_t;
-
-static testdef_t tests[] = {
-    { "alpha", "clipper", "", "PCI:" },
-    { "ppc", "ppce500", "", "U-Boot" },
-    { "ppc", "40p", "-vga none -boot d", "Trying cd:," },
-    { "ppc", "g3beige", "", "PowerPC,750" },
-    { "ppc", "mac99", "", "PowerPC,G4" },
-    { "ppc", "sam460ex", "-m 256", "DRAM:  256 MiB" },
-    { "ppc64", "ppce500", "", "U-Boot" },
-    { "ppc64", "40p", "-m 192", "Memory: 192M" },
-    { "ppc64", "mac99", "", "PowerPC,970FX" },
-    { "ppc64", "pseries",
-      "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken",
-      "Open Firmware" },
-    { "ppc64", "powernv8", "", "OPAL" },
-    { "ppc64", "powernv9", "", "OPAL" },
-    { "ppc64", "sam460ex", "-device e1000", "8086  100e" },
-    { "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
-    { "i386", "pc", "-device sga", "SGABIOS" },
-    { "i386", "q35", "-device sga", "SGABIOS" },
-    { "x86_64", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
-    { "x86_64", "q35", "-device sga", "SGABIOS" },
-    { "sparc", "LX", "", "TMS390S10" },
-    { "sparc", "SS-4", "", "MB86904" },
-    { "sparc", "SS-600MP", "", "TMS390Z55" },
-    { "sparc64", "sun4u", "", "UltraSPARC" },
-    { "s390x", "s390-ccw-virtio", "", "device" },
-    { "m68k", "mcf5208evb", "", "TT", sizeof(kernel_mcf5208), kernel_mcf5208 },
-    { "m68k", "next-cube", "", "TT", sizeof(bios_nextcube), 0, bios_nextcube },
-    { "microblaze", "petalogix-s3adsp1800", "", "TT",
-      sizeof(kernel_pls3adsp1800), kernel_pls3adsp1800 },
-    { "microblazeel", "petalogix-ml605", "", "TT",
-      sizeof(kernel_plml605), kernel_plml605 },
-    { "moxie", "moxiesim", "", "TT", sizeof(bios_moxiesim), 0, bios_moxiesim },
-    { "arm", "raspi2", "", "TT", sizeof(bios_raspi2), 0, bios_raspi2 },
-    { "hppa", "hppa", "", "SeaBIOS wants SYSTEM HALT" },
-    { "aarch64", "virt", "-cpu cortex-a57", "TT", sizeof(kernel_aarch64),
-      kernel_aarch64 },
-    { "arm", "microbit", "", "T", sizeof(kernel_nrf51), kernel_nrf51 },
-
-    { NULL }
-};
-
-static bool check_guest_output(QTestState *qts, const testdef_t *test, int fd)
-{
-    int nbr = 0, pos = 0, ccnt;
-    time_t now, start = time(NULL);
-    char ch;
-
-    /* Poll serial output... */
-    while (1) {
-        ccnt = 0;
-        while (ccnt++ < 512 && (nbr = read(fd, &ch, 1)) == 1) {
-            if (ch == test->expect[pos]) {
-                pos += 1;
-                if (test->expect[pos] == '\0') {
-                    /* We've reached the end of the expected string! */
-                    return true;
-                }
-            } else {
-                pos = 0;
-            }
-        }
-        g_assert(nbr >= 0);
-        /* Wait only if the child is still alive.  */
-        if (!qtest_probe_child(qts)) {
-            break;
-        }
-        /* Wait at most 360 seconds.  */
-        now = time(NULL);
-        if (now - start >= 360) {
-            break;
-        }
-        g_usleep(10000);
-    }
-
-    return false;
-}
-
-static void test_machine(const void *data)
-{
-    const testdef_t *test = data;
-    char serialtmp[] = "/tmp/qtest-boot-serial-sXXXXXX";
-    char codetmp[] = "/tmp/qtest-boot-serial-cXXXXXX";
-    const char *codeparam = "";
-    const uint8_t *code = NULL;
-    QTestState *qts;
-    int ser_fd;
-
-    ser_fd = mkstemp(serialtmp);
-    g_assert(ser_fd != -1);
-
-    if (test->kernel) {
-        code = test->kernel;
-        codeparam = "-kernel";
-    } else if (test->bios) {
-        code = test->bios;
-        codeparam = "-bios";
-    }
-
-    if (code) {
-        ssize_t wlen;
-        int code_fd;
-
-        code_fd = mkstemp(codetmp);
-        g_assert(code_fd != -1);
-        wlen = write(code_fd, code, test->codesize);
-        g_assert(wlen == test->codesize);
-        close(code_fd);
-    }
-
-    /*
-     * Make sure that this test uses tcg if available: It is used as a
-     * fast-enough smoketest for that.
-     */
-    qts = qtest_initf("%s %s -M %s -no-shutdown "
-                      "-chardev file,id=serial0,path=%s "
-                      "-serial chardev:serial0 -accel tcg -accel kvm %s",
-                      codeparam, code ? codetmp : "", test->machine,
-                      serialtmp, test->extra);
-    if (code) {
-        unlink(codetmp);
-    }
-
-    if (!check_guest_output(qts, test, ser_fd)) {
-        g_error("Failed to find expected string. Please check '%s'",
-                serialtmp);
-    }
-    unlink(serialtmp);
-
-    qtest_quit(qts);
-
-    close(ser_fd);
-}
-
-int main(int argc, char *argv[])
-{
-    const char *arch = qtest_get_arch();
-    int i;
-
-    g_test_init(&argc, &argv, NULL);
-
-    for (i = 0; tests[i].arch != NULL; i++) {
-        if (strcmp(arch, tests[i].arch) == 0) {
-            char *name = g_strdup_printf("boot-serial/%s", tests[i].machine);
-            qtest_add_data_func(name, &tests[i], test_machine);
-            g_free(name);
-        }
-    }
-
-    return g_test_run();
-}
diff --git a/tests/cdrom-test.c b/tests/cdrom-test.c
deleted file mode 100644 (file)
index 67635e3..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Various tests for emulated CD-ROM drives.
- *
- * Copyright (c) 2018 Red Hat Inc.
- *
- * Author:
- *    Thomas Huth <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2
- * or later. See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "boot-sector.h"
-#include "qapi/qmp/qdict.h"
-
-static char isoimage[] = "cdrom-boot-iso-XXXXXX";
-
-static int exec_genisoimg(const char **args)
-{
-    gchar *out_err = NULL;
-    gint exit_status = -1;
-    bool success;
-
-    success = g_spawn_sync(NULL, (gchar **)args, NULL,
-                           G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL,
-                           NULL, NULL, NULL, &out_err, &exit_status, NULL);
-    if (!success) {
-        return -ENOENT;
-    }
-    if (out_err) {
-        fputs(out_err, stderr);
-        g_free(out_err);
-    }
-
-    return exit_status;
-}
-
-static int prepare_image(const char *arch, char *isoimage)
-{
-    char srcdir[] = "cdrom-test-dir-XXXXXX";
-    char *codefile = NULL;
-    int ifh, ret = -1;
-    const char *args[] = {
-        "genisoimage", "-quiet", "-l", "-no-emul-boot",
-        "-b", NULL, "-o", isoimage, srcdir, NULL
-    };
-
-    ifh = mkstemp(isoimage);
-    if (ifh < 0) {
-        perror("Error creating temporary iso image file");
-        return -1;
-    }
-    if (!mkdtemp(srcdir)) {
-        perror("Error creating temporary directory");
-        goto cleanup;
-    }
-
-    if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64") ||
-        g_str_equal(arch, "s390x")) {
-        codefile = g_strdup_printf("%s/bootcode-XXXXXX", srcdir);
-        ret = boot_sector_init(codefile);
-        if (ret) {
-            goto cleanup;
-        }
-    } else {
-        /* Just create a dummy file */
-        char txt[] = "empty disc";
-        codefile = g_strdup_printf("%s/readme.txt", srcdir);
-        if (!g_file_set_contents(codefile, txt, sizeof(txt) - 1, NULL)) {
-            fprintf(stderr, "Failed to create '%s'\n", codefile);
-            goto cleanup;
-        }
-    }
-
-    args[5] = strchr(codefile, '/') + 1;
-    ret = exec_genisoimg(args);
-    if (ret) {
-        fprintf(stderr, "genisoimage failed: %i\n", ret);
-    }
-
-    unlink(codefile);
-
-cleanup:
-    g_free(codefile);
-    rmdir(srcdir);
-    close(ifh);
-
-    return ret;
-}
-
-/**
- * Check that at least the -cdrom parameter is basically working, i.e. we can
- * see the filename of the ISO image in the output of "info block" afterwards
- */
-static void test_cdrom_param(gconstpointer data)
-{
-    QTestState *qts;
-    char *resp;
-
-    qts = qtest_initf("-M %s -cdrom %s", (const char *)data, isoimage);
-    resp = qtest_hmp(qts, "info block");
-    g_assert(strstr(resp, isoimage) != 0);
-    g_free(resp);
-    qtest_quit(qts);
-}
-
-static void add_cdrom_param_tests(const char **machines)
-{
-    while (*machines) {
-        char *testname = g_strdup_printf("cdrom/param/%s", *machines);
-        qtest_add_data_func(testname, *machines, test_cdrom_param);
-        g_free(testname);
-        machines++;
-    }
-}
-
-static void test_cdboot(gconstpointer data)
-{
-    QTestState *qts;
-
-    qts = qtest_initf("-accel kvm -accel tcg -no-shutdown %s%s", (const char *)data,
-                      isoimage);
-    boot_sector_test(qts);
-    qtest_quit(qts);
-}
-
-static void add_x86_tests(void)
-{
-    qtest_add_data_func("cdrom/boot/default", "-cdrom ", test_cdboot);
-    qtest_add_data_func("cdrom/boot/virtio-scsi",
-                        "-device virtio-scsi -device scsi-cd,drive=cdr "
-                        "-blockdev file,node-name=cdr,filename=", test_cdboot);
-    /*
-     * Unstable CI test under load
-     * See https://lists.gnu.org/archive/html/qemu-devel/2019-02/msg05509.html
-     */
-    if (g_test_slow()) {
-        qtest_add_data_func("cdrom/boot/isapc", "-M isapc "
-                            "-drive if=ide,media=cdrom,file=", test_cdboot);
-    }
-    qtest_add_data_func("cdrom/boot/am53c974",
-                        "-device am53c974 -device scsi-cd,drive=cd1 "
-                        "-drive if=none,id=cd1,format=raw,file=", test_cdboot);
-    qtest_add_data_func("cdrom/boot/dc390",
-                        "-device dc390 -device scsi-cd,drive=cd1 "
-                        "-blockdev file,node-name=cd1,filename=", test_cdboot);
-    qtest_add_data_func("cdrom/boot/lsi53c895a",
-                        "-device lsi53c895a -device scsi-cd,drive=cd1 "
-                        "-blockdev file,node-name=cd1,filename=", test_cdboot);
-    qtest_add_data_func("cdrom/boot/megasas", "-M q35 "
-                        "-device megasas -device scsi-cd,drive=cd1 "
-                        "-blockdev file,node-name=cd1,filename=", test_cdboot);
-    qtest_add_data_func("cdrom/boot/megasas-gen2", "-M q35 "
-                        "-device megasas-gen2 -device scsi-cd,drive=cd1 "
-                        "-blockdev file,node-name=cd1,filename=", test_cdboot);
-}
-
-static void add_s390x_tests(void)
-{
-    qtest_add_data_func("cdrom/boot/default", "-cdrom ", test_cdboot);
-    qtest_add_data_func("cdrom/boot/virtio-scsi",
-                        "-device virtio-scsi -device scsi-cd,drive=cdr "
-                        "-blockdev file,node-name=cdr,filename=", test_cdboot);
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-    const char *arch = qtest_get_arch();
-    const char *genisocheck[] = { "genisoimage", "-version", NULL };
-
-    g_test_init(&argc, &argv, NULL);
-
-    if (exec_genisoimg(genisocheck)) {
-        /* genisoimage not available - so can't run tests */
-        return g_test_run();
-    }
-
-    ret = prepare_image(arch, isoimage);
-    if (ret) {
-        return ret;
-    }
-
-    if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64")) {
-        add_x86_tests();
-    } else if (g_str_equal(arch, "s390x")) {
-        add_s390x_tests();
-    } else if (g_str_equal(arch, "ppc64")) {
-        const char *ppcmachines[] = {
-            "pseries", "mac99", "g3beige", "40p", "prep", NULL
-        };
-        add_cdrom_param_tests(ppcmachines);
-    } else if (g_str_equal(arch, "sparc")) {
-        const char *sparcmachines[] = {
-            "LX", "SPARCClassic", "SPARCbook", "SS-10", "SS-20", "SS-4",
-            "SS-5", "SS-600MP", "Voyager", "leon3_generic", NULL
-        };
-        add_cdrom_param_tests(sparcmachines);
-    } else if (g_str_equal(arch, "sparc64")) {
-        const char *sparc64machines[] = {
-            "niagara", "sun4u", "sun4v", NULL
-        };
-        add_cdrom_param_tests(sparc64machines);
-    } else if (!strncmp(arch, "mips64", 6)) {
-        const char *mips64machines[] = {
-            "magnum", "malta", "mips", "pica61", NULL
-        };
-        add_cdrom_param_tests(mips64machines);
-    } else if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) {
-        const char *armmachines[] = {
-            "realview-eb", "realview-eb-mpcore", "realview-pb-a8",
-            "realview-pbx-a9", "versatileab", "versatilepb", "vexpress-a15",
-            "vexpress-a9", "virt", NULL
-        };
-        add_cdrom_param_tests(armmachines);
-    } else {
-        const char *nonemachine[] = { "none", NULL };
-        add_cdrom_param_tests(nonemachine);
-    }
-
-    ret = g_test_run();
-
-    unlink(isoimage);
-
-    return ret;
-}
diff --git a/tests/cpu-plug-test.c b/tests/cpu-plug-test.c
deleted file mode 100644 (file)
index e8ffbbc..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * QTest testcase for CPU plugging
- *
- * Copyright (c) 2015 SUSE Linux GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-
-#include "qemu-common.h"
-#include "libqtest-single.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
-
-struct PlugTestData {
-    char *machine;
-    const char *cpu_model;
-    char *device_model;
-    unsigned sockets;
-    unsigned cores;
-    unsigned threads;
-    unsigned maxcpus;
-};
-typedef struct PlugTestData PlugTestData;
-
-static void test_plug_with_cpu_add(gconstpointer data)
-{
-    const PlugTestData *s = data;
-    char *args;
-    QDict *response;
-    unsigned int i;
-
-    args = g_strdup_printf("-machine %s -cpu %s "
-                           "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u",
-                           s->machine, s->cpu_model,
-                           s->sockets, s->cores, s->threads, s->maxcpus);
-    qtest_start(args);
-
-    for (i = 1; i < s->maxcpus; i++) {
-        response = qmp("{ 'execute': 'cpu-add',"
-                       "  'arguments': { 'id': %d } }", i);
-        g_assert(response);
-        g_assert(!qdict_haskey(response, "error"));
-        qobject_unref(response);
-    }
-
-    qtest_end();
-    g_free(args);
-}
-
-static void test_plug_without_cpu_add(gconstpointer data)
-{
-    const PlugTestData *s = data;
-    char *args;
-    QDict *response;
-
-    args = g_strdup_printf("-machine %s -cpu %s "
-                           "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u",
-                           s->machine, s->cpu_model,
-                           s->sockets, s->cores, s->threads, s->maxcpus);
-    qtest_start(args);
-
-    response = qmp("{ 'execute': 'cpu-add',"
-                   "  'arguments': { 'id': %d } }",
-                   s->sockets * s->cores * s->threads);
-    g_assert(response);
-    g_assert(qdict_haskey(response, "error"));
-    qobject_unref(response);
-
-    qtest_end();
-    g_free(args);
-}
-
-static void test_plug_with_device_add(gconstpointer data)
-{
-    const PlugTestData *td = data;
-    char *args;
-    QTestState *qts;
-    QDict *resp;
-    QList *cpus;
-    QObject *e;
-    int hotplugged = 0;
-
-    args = g_strdup_printf("-machine %s -cpu %s "
-                           "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u",
-                           td->machine, td->cpu_model,
-                           td->sockets, td->cores, td->threads, td->maxcpus);
-    qts = qtest_init(args);
-
-    resp = qtest_qmp(qts, "{ 'execute': 'query-hotpluggable-cpus'}");
-    g_assert(qdict_haskey(resp, "return"));
-    cpus = qdict_get_qlist(resp, "return");
-    g_assert(cpus);
-
-    while ((e = qlist_pop(cpus))) {
-        const QDict *cpu, *props;
-
-        cpu = qobject_to(QDict, e);
-        if (qdict_haskey(cpu, "qom-path")) {
-            qobject_unref(e);
-            continue;
-        }
-
-        g_assert(qdict_haskey(cpu, "props"));
-        props = qdict_get_qdict(cpu, "props");
-
-        qtest_qmp_device_add_qdict(qts, td->device_model, props);
-        hotplugged++;
-        qobject_unref(e);
-    }
-
-    /* make sure that there were hotplugged CPUs */
-    g_assert(hotplugged);
-    qobject_unref(resp);
-    qtest_quit(qts);
-    g_free(args);
-}
-
-static void test_data_free(gpointer data)
-{
-    PlugTestData *pc = data;
-
-    g_free(pc->machine);
-    g_free(pc->device_model);
-    g_free(pc);
-}
-
-static void add_pc_test_case(const char *mname)
-{
-    char *path;
-    PlugTestData *data;
-
-    if (!g_str_has_prefix(mname, "pc-")) {
-        return;
-    }
-    data = g_new(PlugTestData, 1);
-    data->machine = g_strdup(mname);
-    data->cpu_model = "Haswell"; /* 1.3+ theoretically */
-    data->device_model = g_strdup_printf("%s-%s-cpu", data->cpu_model,
-                                         qtest_get_arch());
-    data->sockets = 1;
-    data->cores = 3;
-    data->threads = 2;
-    data->maxcpus = data->sockets * data->cores * data->threads;
-    if (g_str_has_suffix(mname, "-1.4") ||
-        (strcmp(mname, "pc-1.3") == 0) ||
-        (strcmp(mname, "pc-1.2") == 0) ||
-        (strcmp(mname, "pc-1.1") == 0) ||
-        (strcmp(mname, "pc-1.0") == 0)) {
-        path = g_strdup_printf("cpu-plug/%s/init/%ux%ux%u&maxcpus=%u",
-                               mname, data->sockets, data->cores,
-                               data->threads, data->maxcpus);
-        qtest_add_data_func_full(path, data, test_plug_without_cpu_add,
-                                 test_data_free);
-        g_free(path);
-    } else {
-        PlugTestData *data2 = g_memdup(data, sizeof(PlugTestData));
-
-        data2->machine = g_strdup(data->machine);
-        data2->device_model = g_strdup(data->device_model);
-
-        path = g_strdup_printf("cpu-plug/%s/cpu-add/%ux%ux%u&maxcpus=%u",
-                               mname, data->sockets, data->cores,
-                               data->threads, data->maxcpus);
-        qtest_add_data_func_full(path, data, test_plug_with_cpu_add,
-                                 test_data_free);
-        g_free(path);
-        path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u",
-                               mname, data2->sockets, data2->cores,
-                               data2->threads, data2->maxcpus);
-        qtest_add_data_func_full(path, data2, test_plug_with_device_add,
-                                 test_data_free);
-        g_free(path);
-    }
-}
-
-static void add_pseries_test_case(const char *mname)
-{
-    char *path;
-    PlugTestData *data;
-
-    if (!g_str_has_prefix(mname, "pseries-") ||
-        (g_str_has_prefix(mname, "pseries-2.") && atoi(&mname[10]) < 7)) {
-        return;
-    }
-    data = g_new(PlugTestData, 1);
-    data->machine = g_strdup(mname);
-    data->cpu_model = "power8_v2.0";
-    data->device_model = g_strdup("power8_v2.0-spapr-cpu-core");
-    data->sockets = 2;
-    data->cores = 3;
-    data->threads = 1;
-    data->maxcpus = data->sockets * data->cores * data->threads;
-
-    path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u",
-                           mname, data->sockets, data->cores,
-                           data->threads, data->maxcpus);
-    qtest_add_data_func_full(path, data, test_plug_with_device_add,
-                             test_data_free);
-    g_free(path);
-}
-
-static void add_s390x_test_case(const char *mname)
-{
-    char *path;
-    PlugTestData *data, *data2;
-
-    if (!g_str_has_prefix(mname, "s390-ccw-virtio-")) {
-        return;
-    }
-
-    data = g_new(PlugTestData, 1);
-    data->machine = g_strdup(mname);
-    data->cpu_model = "qemu";
-    data->device_model = g_strdup("qemu-s390x-cpu");
-    data->sockets = 1;
-    data->cores = 3;
-    data->threads = 1;
-    data->maxcpus = data->sockets * data->cores * data->threads;
-
-    data2 = g_memdup(data, sizeof(PlugTestData));
-    data2->machine = g_strdup(data->machine);
-    data2->device_model = g_strdup(data->device_model);
-
-    path = g_strdup_printf("cpu-plug/%s/cpu-add/%ux%ux%u&maxcpus=%u",
-                           mname, data->sockets, data->cores,
-                           data->threads, data->maxcpus);
-    qtest_add_data_func_full(path, data, test_plug_with_cpu_add,
-                             test_data_free);
-    g_free(path);
-
-    path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u",
-                           mname, data2->sockets, data2->cores,
-                           data2->threads, data2->maxcpus);
-    qtest_add_data_func_full(path, data2, test_plug_with_device_add,
-                             test_data_free);
-    g_free(path);
-}
-
-int main(int argc, char **argv)
-{
-    const char *arch = qtest_get_arch();
-
-    g_test_init(&argc, &argv, NULL);
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        qtest_cb_for_every_machine(add_pc_test_case, g_test_quick());
-    } else if (g_str_equal(arch, "ppc64")) {
-        qtest_cb_for_every_machine(add_pseries_test_case, g_test_quick());
-    } else if (g_str_equal(arch, "s390x")) {
-        qtest_cb_for_every_machine(add_s390x_test_case, g_test_quick());
-    }
-
-    return g_test_run();
-}
diff --git a/tests/dbus-vmstate-test.c b/tests/dbus-vmstate-test.c
deleted file mode 100644 (file)
index 2e5e47d..0000000
+++ /dev/null
@@ -1,382 +0,0 @@
-#include "qemu/osdep.h"
-#include <glib/gstdio.h>
-#include <gio/gio.h>
-#include "libqtest.h"
-#include "qemu-common.h"
-#include "dbus-vmstate1.h"
-#include "migration-helpers.h"
-
-static char *workdir;
-
-typedef struct TestServerId {
-    const char *name;
-    const char *data;
-    size_t size;
-} TestServerId;
-
-static const TestServerId idA = {
-    "idA", "I'am\0idA!", sizeof("I'am\0idA!")
-};
-
-static const TestServerId idB = {
-    "idB", "I'am\0idB!", sizeof("I'am\0idB!")
-};
-
-typedef struct TestServer {
-    const TestServerId *id;
-    bool save_called;
-    bool load_called;
-} TestServer;
-
-typedef struct Test {
-    const char *id_list;
-    bool migrate_fail;
-    bool without_dst_b;
-    TestServer srcA;
-    TestServer dstA;
-    TestServer srcB;
-    TestServer dstB;
-    GMainLoop *loop;
-    QTestState *src_qemu;
-} Test;
-
-static gboolean
-vmstate_load(VMState1 *object, GDBusMethodInvocation *invocation,
-             const gchar *arg_data, gpointer user_data)
-{
-    TestServer *h = user_data;
-    g_autoptr(GVariant) var = NULL;
-    GVariant *args;
-    const uint8_t *data;
-    size_t size;
-
-    args = g_dbus_method_invocation_get_parameters(invocation);
-    var = g_variant_get_child_value(args, 0);
-    data = g_variant_get_fixed_array(var, &size, sizeof(char));
-    g_assert_cmpuint(size, ==, h->id->size);
-    g_assert(!memcmp(data, h->id->data, h->id->size));
-    h->load_called = true;
-
-    g_dbus_method_invocation_return_value(invocation, g_variant_new("()"));
-    return TRUE;
-}
-
-static gboolean
-vmstate_save(VMState1 *object, GDBusMethodInvocation *invocation,
-             gpointer user_data)
-{
-    TestServer *h = user_data;
-    GVariant *var;
-
-    var = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
-                                    h->id->data, h->id->size, sizeof(char));
-    g_dbus_method_invocation_return_value(invocation,
-                                          g_variant_new("(@ay)", var));
-    h->save_called = true;
-
-    return TRUE;
-}
-
-typedef struct WaitNamed {
-    GMainLoop *loop;
-    bool named;
-} WaitNamed;
-
-static void
-named_cb(GDBusConnection *connection,
-         const gchar *name,
-         gpointer user_data)
-{
-    WaitNamed *t = user_data;
-
-    t->named = true;
-    g_main_loop_quit(t->loop);
-}
-
-static GDBusConnection *
-get_connection(Test *test, guint *ownid)
-{
-    g_autofree gchar *addr = NULL;
-    WaitNamed *wait;
-    GError *err = NULL;
-    GDBusConnection *c;
-
-    wait = g_new0(WaitNamed, 1);
-    wait->loop = test->loop;
-    addr = g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SESSION, NULL, &err);
-    g_assert_no_error(err);
-
-    c = g_dbus_connection_new_for_address_sync(
-        addr,
-        G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION |
-        G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
-        NULL, NULL, &err);
-    g_assert_no_error(err);
-    *ownid = g_bus_own_name_on_connection(c, "org.qemu.VMState1",
-                                          G_BUS_NAME_OWNER_FLAGS_NONE,
-                                          named_cb, named_cb, wait, g_free);
-    if (!wait->named) {
-        g_main_loop_run(wait->loop);
-    }
-
-    return c;
-}
-
-static GDBusObjectManagerServer *
-get_server(GDBusConnection *conn, TestServer *s, const TestServerId *id)
-{
-    g_autoptr(GDBusObjectSkeleton) sk = NULL;
-    g_autoptr(VMState1Skeleton) v = NULL;
-    GDBusObjectManagerServer *os;
-
-    s->id = id;
-    os = g_dbus_object_manager_server_new("/org/qemu");
-    sk = g_dbus_object_skeleton_new("/org/qemu/VMState1");
-
-    v = VMSTATE1_SKELETON(vmstate1_skeleton_new());
-    g_object_set(v, "id", id->name, NULL);
-
-    g_signal_connect(v, "handle-load", G_CALLBACK(vmstate_load), s);
-    g_signal_connect(v, "handle-save", G_CALLBACK(vmstate_save), s);
-
-    g_dbus_object_skeleton_add_interface(sk, G_DBUS_INTERFACE_SKELETON(v));
-    g_dbus_object_manager_server_export(os, sk);
-    g_dbus_object_manager_server_set_connection(os, conn);
-
-    return os;
-}
-
-static void
-set_id_list(Test *test, QTestState *s)
-{
-    if (!test->id_list) {
-        return;
-    }
-
-    g_assert(!qmp_rsp_is_err(qtest_qmp(s,
-        "{ 'execute': 'qom-set', 'arguments': "
-        "{ 'path': '/objects/dv', 'property': 'id-list', 'value': %s } }",
-        test->id_list)));
-}
-
-static gpointer
-dbus_vmstate_thread(gpointer data)
-{
-    GMainLoop *loop = data;
-
-    g_main_loop_run(loop);
-
-    return NULL;
-}
-
-static void
-test_dbus_vmstate(Test *test)
-{
-    g_autofree char *src_qemu_args = NULL;
-    g_autofree char *dst_qemu_args = NULL;
-    g_autoptr(GTestDBus) srcbus = NULL;
-    g_autoptr(GTestDBus) dstbus = NULL;
-    g_autoptr(GDBusConnection) srcconnA = NULL;
-    g_autoptr(GDBusConnection) srcconnB = NULL;
-    g_autoptr(GDBusConnection) dstconnA = NULL;
-    g_autoptr(GDBusConnection) dstconnB = NULL;
-    g_autoptr(GDBusObjectManagerServer) srcserverA = NULL;
-    g_autoptr(GDBusObjectManagerServer) srcserverB = NULL;
-    g_autoptr(GDBusObjectManagerServer) dstserverA = NULL;
-    g_autoptr(GDBusObjectManagerServer) dstserverB = NULL;
-    g_auto(GStrv) srcaddr = NULL;
-    g_auto(GStrv) dstaddr = NULL;
-    g_autoptr(GThread) thread = NULL;
-    g_autoptr(GMainLoop) loop = NULL;
-    g_autofree char *uri = NULL;
-    QTestState *src_qemu = NULL, *dst_qemu = NULL;
-    guint ownsrcA, ownsrcB, owndstA, owndstB;
-
-    uri = g_strdup_printf("unix:%s/migsocket", workdir);
-
-    loop = g_main_loop_new(NULL, FALSE);
-    test->loop = loop;
-
-    srcbus = g_test_dbus_new(G_TEST_DBUS_NONE);
-    g_test_dbus_up(srcbus);
-    srcconnA = get_connection(test, &ownsrcA);
-    srcserverA = get_server(srcconnA, &test->srcA, &idA);
-    srcconnB = get_connection(test, &ownsrcB);
-    srcserverB = get_server(srcconnB, &test->srcB, &idB);
-
-    /* remove ,guid=foo part */
-    srcaddr = g_strsplit(g_test_dbus_get_bus_address(srcbus), ",", 2);
-    src_qemu_args =
-        g_strdup_printf("-object dbus-vmstate,id=dv,addr=%s", srcaddr[0]);
-
-    dstbus = g_test_dbus_new(G_TEST_DBUS_NONE);
-    g_test_dbus_up(dstbus);
-    dstconnA = get_connection(test, &owndstA);
-    dstserverA = get_server(dstconnA, &test->dstA, &idA);
-    if (!test->without_dst_b) {
-        dstconnB = get_connection(test, &owndstB);
-        dstserverB = get_server(dstconnB, &test->dstB, &idB);
-    }
-
-    dstaddr = g_strsplit(g_test_dbus_get_bus_address(dstbus), ",", 2);
-    dst_qemu_args =
-        g_strdup_printf("-object dbus-vmstate,id=dv,addr=%s -incoming %s",
-                        dstaddr[0], uri);
-
-    src_qemu = qtest_init(src_qemu_args);
-    dst_qemu = qtest_init(dst_qemu_args);
-    set_id_list(test, src_qemu);
-    set_id_list(test, dst_qemu);
-
-    thread = g_thread_new("dbus-vmstate-thread", dbus_vmstate_thread, loop);
-
-    migrate_qmp(src_qemu, uri, "{}");
-    test->src_qemu = src_qemu;
-    if (test->migrate_fail) {
-        wait_for_migration_fail(src_qemu, true);
-        qtest_set_expected_status(dst_qemu, 1);
-    } else {
-        wait_for_migration_complete(src_qemu);
-    }
-
-    qtest_quit(dst_qemu);
-    qtest_quit(src_qemu);
-    g_bus_unown_name(ownsrcA);
-    g_bus_unown_name(ownsrcB);
-    g_bus_unown_name(owndstA);
-    if (!test->without_dst_b) {
-        g_bus_unown_name(owndstB);
-    }
-
-    g_main_loop_quit(test->loop);
-}
-
-static void
-check_not_migrated(TestServer *s, TestServer *d)
-{
-    assert(!s->save_called);
-    assert(!s->load_called);
-    assert(!d->save_called);
-    assert(!d->load_called);
-}
-
-static void
-check_migrated(TestServer *s, TestServer *d)
-{
-    assert(s->save_called);
-    assert(!s->load_called);
-    assert(!d->save_called);
-    assert(d->load_called);
-}
-
-static void
-test_dbus_vmstate_without_list(void)
-{
-    Test test = { 0, };
-
-    test_dbus_vmstate(&test);
-
-    check_migrated(&test.srcA, &test.dstA);
-    check_migrated(&test.srcB, &test.dstB);
-}
-
-static void
-test_dbus_vmstate_with_list(void)
-{
-    Test test = { .id_list = "idA,idB" };
-
-    test_dbus_vmstate(&test);
-
-    check_migrated(&test.srcA, &test.dstA);
-    check_migrated(&test.srcB, &test.dstB);
-}
-
-static void
-test_dbus_vmstate_only_a(void)
-{
-    Test test = { .id_list = "idA" };
-
-    test_dbus_vmstate(&test);
-
-    check_migrated(&test.srcA, &test.dstA);
-    check_not_migrated(&test.srcB, &test.dstB);
-}
-
-static void
-test_dbus_vmstate_missing_src(void)
-{
-    Test test = { .id_list = "idA,idC", .migrate_fail = true };
-
-    /* run in subprocess to silence QEMU error reporting */
-    if (g_test_subprocess()) {
-        test_dbus_vmstate(&test);
-        check_not_migrated(&test.srcA, &test.dstA);
-        check_not_migrated(&test.srcB, &test.dstB);
-        return;
-    }
-
-    g_test_trap_subprocess(NULL, 0, 0);
-    g_test_trap_assert_passed();
-}
-
-static void
-test_dbus_vmstate_missing_dst(void)
-{
-    Test test = { .id_list = "idA,idB",
-                  .without_dst_b = true,
-                  .migrate_fail = true };
-
-    /* run in subprocess to silence QEMU error reporting */
-    if (g_test_subprocess()) {
-        test_dbus_vmstate(&test);
-        assert(test.srcA.save_called);
-        assert(test.srcB.save_called);
-        assert(!test.dstB.save_called);
-        return;
-    }
-
-    g_test_trap_subprocess(NULL, 0, 0);
-    g_test_trap_assert_passed();
-}
-
-int
-main(int argc, char **argv)
-{
-    GError *err = NULL;
-    g_autofree char *dbus_daemon = NULL;
-    int ret;
-
-    dbus_daemon = g_build_filename(G_STRINGIFY(SRCDIR),
-                                   "tests",
-                                   "dbus-vmstate-daemon.sh",
-                                   NULL);
-    g_setenv("G_TEST_DBUS_DAEMON", dbus_daemon, true);
-
-    g_test_init(&argc, &argv, NULL);
-
-    workdir = g_dir_make_tmp("dbus-vmstate-test-XXXXXX", &err);
-    if (!workdir) {
-        g_error("Unable to create temporary dir: %s\n", err->message);
-        exit(1);
-    }
-
-    g_setenv("DBUS_VMSTATE_TEST_TMPDIR", workdir, true);
-
-    qtest_add_func("/dbus-vmstate/without-list",
-                   test_dbus_vmstate_without_list);
-    qtest_add_func("/dbus-vmstate/with-list",
-                   test_dbus_vmstate_with_list);
-    qtest_add_func("/dbus-vmstate/only-a",
-                   test_dbus_vmstate_only_a);
-    qtest_add_func("/dbus-vmstate/missing-src",
-                   test_dbus_vmstate_missing_src);
-    qtest_add_func("/dbus-vmstate/missing-dst",
-                   test_dbus_vmstate_missing_dst);
-
-    ret = g_test_run();
-
-    rmdir(workdir);
-    g_free(workdir);
-
-    return ret;
-}
diff --git a/tests/dbus-vmstate1.xml b/tests/dbus-vmstate1.xml
deleted file mode 100644 (file)
index cc8563b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0"?>
-<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
-  <interface name="org.qemu.VMState1">
-    <property name="Id" type="s" access="read"/>
-    <method name="Load">
-      <arg type="ay" name="data" direction="in"/>
-    </method>
-    <method name="Save">
-      <arg type="ay" name="data" direction="out"/>
-    </method>
-  </interface>
-</node>
diff --git a/tests/device-introspect-test.c b/tests/device-introspect-test.c
deleted file mode 100644 (file)
index 04f2290..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Device introspection test cases
- *
- * Copyright (c) 2015 Red Hat Inc.
- *
- * Authors:
- *  Markus Armbruster <[email protected]>,
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-/*
- * Covers QMP device-list-properties and HMP device_add help.  We
- * currently don't check that their output makes sense, only that QEMU
- * survives.  Useful since we've had an astounding number of crash
- * bugs around here.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qapi/qmp/qstring.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
-#include "libqtest.h"
-
-const char common_args[] = "-nodefaults -machine none";
-
-static QList *qom_list_types(QTestState * qts, const char *implements,
-                             bool abstract)
-{
-    QDict *resp;
-    QList *ret;
-    QDict *args = qdict_new();
-
-    qdict_put_bool(args, "abstract", abstract);
-    if (implements) {
-        qdict_put_str(args, "implements", implements);
-    }
-    resp = qtest_qmp(qts, "{'execute': 'qom-list-types', 'arguments': %p }",
-                     args);
-    g_assert(qdict_haskey(resp, "return"));
-    ret = qdict_get_qlist(resp, "return");
-    qobject_ref(ret);
-    qobject_unref(resp);
-    return ret;
-}
-
-/* Build a name -> ObjectTypeInfo index from a ObjectTypeInfo list */
-static QDict *qom_type_index(QList *types)
-{
-    QDict *index = qdict_new();
-    QListEntry *e;
-
-    QLIST_FOREACH_ENTRY(types, e) {
-        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
-        const char *name = qdict_get_str(d, "name");
-        qobject_ref(d);
-        qdict_put(index, name, d);
-    }
-    return index;
-}
-
-/* Check if @parent is present in the parent chain of @type */
-static bool qom_has_parent(QDict *index, const char *type, const char *parent)
-{
-    while (type) {
-        QDict *d = qdict_get_qdict(index, type);
-        const char *p = d && qdict_haskey(d, "parent") ?
-                        qdict_get_str(d, "parent") :
-                        NULL;
-
-        if (!strcmp(type, parent)) {
-            return true;
-        }
-
-        type = p;
-    }
-
-    return false;
-}
-
-/* Find an entry on a list returned by qom-list-types */
-static QDict *type_list_find(QList *types, const char *name)
-{
-    QListEntry *e;
-
-    QLIST_FOREACH_ENTRY(types, e) {
-        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
-        const char *ename = qdict_get_str(d, "name");
-        if (!strcmp(ename, name)) {
-            return d;
-        }
-    }
-
-    return NULL;
-}
-
-static QList *device_type_list(QTestState *qts, bool abstract)
-{
-    return qom_list_types(qts, "device", abstract);
-}
-
-static void test_one_device(QTestState *qts, const char *type)
-{
-    QDict *resp;
-    char *help;
-    char *qom_tree_start, *qom_tree_end;
-    char *qtree_start, *qtree_end;
-
-    g_test_message("Testing device '%s'", type);
-
-    qom_tree_start = qtest_hmp(qts, "info qom-tree");
-    qtree_start = qtest_hmp(qts, "info qtree");
-
-    resp = qtest_qmp(qts, "{'execute': 'device-list-properties',"
-                          " 'arguments': {'typename': %s}}",
-               type);
-    qobject_unref(resp);
-
-    help = qtest_hmp(qts, "device_add \"%s,help\"", type);
-    g_free(help);
-
-    /*
-     * Some devices leave dangling pointers in QOM behind.
-     * "info qom-tree" or "info qtree" have a good chance at crashing then.
-     * Also make sure that the tree did not change.
-     */
-    qom_tree_end = qtest_hmp(qts, "info qom-tree");
-    g_assert_cmpstr(qom_tree_start, ==, qom_tree_end);
-    g_free(qom_tree_start);
-    g_free(qom_tree_end);
-
-    qtree_end = qtest_hmp(qts, "info qtree");
-    g_assert_cmpstr(qtree_start, ==, qtree_end);
-    g_free(qtree_start);
-    g_free(qtree_end);
-}
-
-static void test_device_intro_list(void)
-{
-    QList *types;
-    char *help;
-    QTestState *qts;
-
-    qts = qtest_init(common_args);
-
-    types = device_type_list(qts, true);
-    qobject_unref(types);
-
-    help = qtest_hmp(qts, "device_add help");
-    g_free(help);
-
-    qtest_quit(qts);
-}
-
-/*
- * Ensure all entries returned by qom-list-types implements=<parent>
- * have <parent> as a parent.
- */
-static void test_qom_list_parents(QTestState *qts, const char *parent)
-{
-    QList *types;
-    QListEntry *e;
-    QDict *index;
-
-    types = qom_list_types(qts, parent, true);
-    index = qom_type_index(types);
-
-    QLIST_FOREACH_ENTRY(types, e) {
-        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
-        const char *name = qdict_get_str(d, "name");
-
-        g_assert(qom_has_parent(index, name, parent));
-    }
-
-    qobject_unref(types);
-    qobject_unref(index);
-}
-
-static void test_qom_list_fields(void)
-{
-    QList *all_types;
-    QList *non_abstract;
-    QListEntry *e;
-    QTestState *qts;
-
-    qts = qtest_init(common_args);
-
-    all_types = qom_list_types(qts, NULL, true);
-    non_abstract = qom_list_types(qts, NULL, false);
-
-    QLIST_FOREACH_ENTRY(all_types, e) {
-        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
-        const char *name = qdict_get_str(d, "name");
-        bool abstract = qdict_haskey(d, "abstract") ?
-                        qdict_get_bool(d, "abstract") :
-                        false;
-        bool expected_abstract = !type_list_find(non_abstract, name);
-
-        g_assert(abstract == expected_abstract);
-    }
-
-    test_qom_list_parents(qts, "object");
-    test_qom_list_parents(qts, "device");
-    test_qom_list_parents(qts, "sys-bus-device");
-
-    qobject_unref(all_types);
-    qobject_unref(non_abstract);
-    qtest_quit(qts);
-}
-
-static void test_device_intro_none(void)
-{
-    QTestState *qts = qtest_init(common_args);
-
-    test_one_device(qts, "nonexistent");
-    qtest_quit(qts);
-}
-
-static void test_device_intro_abstract(void)
-{
-    QTestState *qts = qtest_init(common_args);
-
-    test_one_device(qts, "device");
-    qtest_quit(qts);
-}
-
-static void test_device_intro_concrete(const void *args)
-{
-    QList *types;
-    QListEntry *entry;
-    const char *type;
-    QTestState *qts;
-
-    qts = qtest_init(args);
-    types = device_type_list(qts, false);
-
-    QLIST_FOREACH_ENTRY(types, entry) {
-        type = qdict_get_try_str(qobject_to(QDict, qlist_entry_obj(entry)),
-                                 "name");
-        g_assert(type);
-        test_one_device(qts, type);
-    }
-
-    qobject_unref(types);
-    qtest_quit(qts);
-    g_free((void *)args);
-}
-
-static void test_abstract_interfaces(void)
-{
-    QList *all_types;
-    QListEntry *e;
-    QDict *index;
-    QTestState *qts;
-
-    qts = qtest_init(common_args);
-
-    all_types = qom_list_types(qts, "interface", true);
-    index = qom_type_index(all_types);
-
-    QLIST_FOREACH_ENTRY(all_types, e) {
-        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
-        const char *name = qdict_get_str(d, "name");
-
-        /*
-         * qom-list-types implements=interface returns all types
-         * that implement _any_ interface (not just interface
-         * types), so skip the ones that don't have "interface"
-         * on the parent type chain.
-         */
-        if (!qom_has_parent(index, name, "interface")) {
-            /* Not an interface type */
-            continue;
-        }
-
-        g_assert(qdict_haskey(d, "abstract") && qdict_get_bool(d, "abstract"));
-    }
-
-    qobject_unref(all_types);
-    qobject_unref(index);
-    qtest_quit(qts);
-}
-
-static void add_machine_test_case(const char *mname)
-{
-    char *path, *args;
-
-    /* Ignore blacklisted machines */
-    if (g_str_equal("xenfv", mname) || g_str_equal("xenpv", mname)) {
-        return;
-    }
-
-    path = g_strdup_printf("device/introspect/concrete/defaults/%s", mname);
-    args = g_strdup_printf("-M %s", mname);
-    qtest_add_data_func(path, args, test_device_intro_concrete);
-    g_free(path);
-
-    path = g_strdup_printf("device/introspect/concrete/nodefaults/%s", mname);
-    args = g_strdup_printf("-nodefaults -M %s", mname);
-    qtest_add_data_func(path, args, test_device_intro_concrete);
-    g_free(path);
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("device/introspect/list", test_device_intro_list);
-    qtest_add_func("device/introspect/list-fields", test_qom_list_fields);
-    qtest_add_func("device/introspect/none", test_device_intro_none);
-    qtest_add_func("device/introspect/abstract", test_device_intro_abstract);
-    qtest_add_func("device/introspect/abstract-interfaces", test_abstract_interfaces);
-    if (g_test_quick()) {
-        qtest_add_data_func("device/introspect/concrete/defaults/none",
-                            g_strdup(common_args), test_device_intro_concrete);
-    } else {
-        qtest_cb_for_every_machine(add_machine_test_case, true);
-    }
-
-    return g_test_run();
-}
diff --git a/tests/device-plug-test.c b/tests/device-plug-test.c
deleted file mode 100644 (file)
index 318e422..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * QEMU device plug/unplug handling
- *
- * Copyright (C) 2019 Red Hat Inc.
- *
- * Authors:
- *  David Hildenbrand <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qstring.h"
-
-static void device_del_start(QTestState *qtest, const char *id)
-{
-    qtest_qmp_send(qtest,
-                   "{'execute': 'device_del', 'arguments': { 'id': %s } }", id);
-}
-
-static void device_del_finish(QTestState *qtest)
-{
-    QDict *resp = qtest_qmp_receive(qtest);
-
-    g_assert(qdict_haskey(resp, "return"));
-    qobject_unref(resp);
-}
-
-static void device_del_request(QTestState *qtest, const char *id)
-{
-    device_del_start(qtest, id);
-    device_del_finish(qtest);
-}
-
-static void system_reset(QTestState *qtest)
-{
-    QDict *resp;
-
-    resp = qtest_qmp(qtest, "{'execute': 'system_reset'}");
-    g_assert(qdict_haskey(resp, "return"));
-    qobject_unref(resp);
-}
-
-static void wait_device_deleted_event(QTestState *qtest, const char *id)
-{
-    QDict *resp, *data;
-    QString *qstr;
-
-    /*
-     * Other devices might get removed along with the removed device. Skip
-     * these. The device of interest will be the last one.
-     */
-    for (;;) {
-        resp = qtest_qmp_eventwait_ref(qtest, "DEVICE_DELETED");
-        data = qdict_get_qdict(resp, "data");
-        if (!data || !qdict_get(data, "device")) {
-            qobject_unref(resp);
-            continue;
-        }
-        qstr = qobject_to(QString, qdict_get(data, "device"));
-        g_assert(qstr);
-        if (!strcmp(qstring_get_str(qstr), id)) {
-            qobject_unref(resp);
-            break;
-        }
-        qobject_unref(resp);
-    }
-}
-
-static void test_pci_unplug_request(void)
-{
-    QTestState *qtest = qtest_initf("-device virtio-mouse-pci,id=dev0");
-
-    /*
-     * Request device removal. As the guest is not running, the request won't
-     * be processed. However during system reset, the removal will be
-     * handled, removing the device.
-     */
-    device_del_request(qtest, "dev0");
-    system_reset(qtest);
-    wait_device_deleted_event(qtest, "dev0");
-
-    qtest_quit(qtest);
-}
-
-static void test_ccw_unplug(void)
-{
-    QTestState *qtest = qtest_initf("-device virtio-balloon-ccw,id=dev0");
-
-    /*
-     * The DEVICE_DELETED events will be sent before the command
-     * completes.
-     */
-    device_del_start(qtest, "dev0");
-    wait_device_deleted_event(qtest, "dev0");
-    device_del_finish(qtest);
-
-    qtest_quit(qtest);
-}
-
-static void test_spapr_cpu_unplug_request(void)
-{
-    QTestState *qtest;
-
-    qtest = qtest_initf("-cpu power9_v2.0 -smp 1,maxcpus=2 "
-                        "-device power9_v2.0-spapr-cpu-core,core-id=1,id=dev0");
-
-    /* similar to test_pci_unplug_request */
-    device_del_request(qtest, "dev0");
-    system_reset(qtest);
-    wait_device_deleted_event(qtest, "dev0");
-
-    qtest_quit(qtest);
-}
-
-static void test_spapr_memory_unplug_request(void)
-{
-    QTestState *qtest;
-
-    qtest = qtest_initf("-m 256M,slots=1,maxmem=768M "
-                        "-object memory-backend-ram,id=mem0,size=512M "
-                        "-device pc-dimm,id=dev0,memdev=mem0");
-
-    /* similar to test_pci_unplug_request */
-    device_del_request(qtest, "dev0");
-    system_reset(qtest);
-    wait_device_deleted_event(qtest, "dev0");
-
-    qtest_quit(qtest);
-}
-
-static void test_spapr_phb_unplug_request(void)
-{
-    QTestState *qtest;
-
-    qtest = qtest_initf("-device spapr-pci-host-bridge,index=1,id=dev0");
-
-    /* similar to test_pci_unplug_request */
-    device_del_request(qtest, "dev0");
-    system_reset(qtest);
-    wait_device_deleted_event(qtest, "dev0");
-
-    qtest_quit(qtest);
-}
-
-int main(int argc, char **argv)
-{
-    const char *arch = qtest_get_arch();
-
-    g_test_init(&argc, &argv, NULL);
-
-    /*
-     * We need a system that will process unplug requests during system resets
-     * and does not do PCI surprise removal. This holds for x86 ACPI,
-     * s390x and spapr.
-     */
-    qtest_add_func("/device-plug/pci-unplug-request",
-                   test_pci_unplug_request);
-
-    if (!strcmp(arch, "s390x")) {
-        qtest_add_func("/device-plug/ccw-unplug",
-                       test_ccw_unplug);
-    }
-
-    if (!strcmp(arch, "ppc64")) {
-        qtest_add_func("/device-plug/spapr-cpu-unplug-request",
-                       test_spapr_cpu_unplug_request);
-        qtest_add_func("/device-plug/spapr-memory-unplug-request",
-                       test_spapr_memory_unplug_request);
-        qtest_add_func("/device-plug/spapr-phb-unplug-request",
-                       test_spapr_phb_unplug_request);
-    }
-
-    return g_test_run();
-}
diff --git a/tests/display-vga-test.c b/tests/display-vga-test.c
deleted file mode 100644 (file)
index ace3bb2..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * QTest testcase for vga cards
- *
- * Copyright (c) 2014 Red Hat, Inc
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-
-static void pci_cirrus(void)
-{
-    qtest_start("-vga none -device cirrus-vga");
-    qtest_end();
-}
-
-static void pci_stdvga(void)
-{
-    qtest_start("-vga none -device VGA");
-    qtest_end();
-}
-
-static void pci_secondary(void)
-{
-    qtest_start("-vga none -device secondary-vga");
-    qtest_end();
-}
-
-static void pci_multihead(void)
-{
-    qtest_start("-vga none -device VGA -device secondary-vga");
-    qtest_end();
-}
-
-static void pci_virtio_gpu(void)
-{
-    qtest_start("-vga none -device virtio-gpu-pci");
-    qtest_end();
-}
-
-static void pci_virtio_vga(void)
-{
-    qtest_start("-vga none -device virtio-vga");
-    qtest_end();
-}
-
-int main(int argc, char **argv)
-{
-    const char *arch = qtest_get_arch();
-
-    g_test_init(&argc, &argv, NULL);
-
-    if (strcmp(arch, "alpha") == 0 || strcmp(arch, "i386") == 0 ||
-        strcmp(arch, "mips") == 0 || strcmp(arch, "x86_64") == 0) {
-        qtest_add_func("/display/pci/cirrus", pci_cirrus);
-    }
-    qtest_add_func("/display/pci/stdvga", pci_stdvga);
-    qtest_add_func("/display/pci/secondary", pci_secondary);
-    qtest_add_func("/display/pci/multihead", pci_multihead);
-    qtest_add_func("/display/pci/virtio-gpu", pci_virtio_gpu);
-    if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64") ||
-        g_str_equal(arch, "hppa") || g_str_equal(arch, "ppc64")) {
-        qtest_add_func("/display/pci/virtio-vga", pci_virtio_vga);
-    }
-
-    return g_test_run();
-}
diff --git a/tests/drive_del-test.c b/tests/drive_del-test.c
deleted file mode 100644 (file)
index 5f8839b..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * blockdev.c test cases
- *
- * Copyright (C) 2013-2014 Red Hat Inc.
- *
- * Authors:
- *  Stefan Hajnoczi <[email protected]>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "libqos/virtio.h"
-#include "qapi/qmp/qdict.h"
-
-/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(q, ...) qobject_unref(qtest_qmp(q, __VA_ARGS__))
-
-static void drive_add(QTestState *qts)
-{
-    char *resp = qtest_hmp(qts, "drive_add 0 if=none,id=drive0");
-
-    g_assert_cmpstr(resp, ==, "OK\r\n");
-    g_free(resp);
-}
-
-static void drive_del(QTestState *qts)
-{
-    char *resp = qtest_hmp(qts, "drive_del drive0");
-
-    g_assert_cmpstr(resp, ==, "");
-    g_free(resp);
-}
-
-static void device_del(QTestState *qts)
-{
-    QDict *response;
-
-    /* Complication: ignore DEVICE_DELETED event */
-    qmp_discard_response(qts, "{'execute': 'device_del',"
-                         " 'arguments': { 'id': 'dev0' } }");
-    response = qtest_qmp_receive(qts);
-    g_assert(response);
-    g_assert(qdict_haskey(response, "return"));
-    qobject_unref(response);
-}
-
-static void test_drive_without_dev(void)
-{
-    QTestState *qts;
-
-    /* Start with an empty drive */
-    qts = qtest_init("-drive if=none,id=drive0");
-
-    /* Delete the drive */
-    drive_del(qts);
-
-    /* Ensure re-adding the drive works - there should be no duplicate ID error
-     * because the old drive must be gone.
-     */
-    drive_add(qts);
-
-    qtest_quit(qts);
-}
-
-/*
- * qvirtio_get_dev_type:
- * Returns: the preferred virtio bus/device type for the current architecture.
- * TODO: delete this
- */
-static const char *qvirtio_get_dev_type(void)
-{
-    const char *arch = qtest_get_arch();
-
-    if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) {
-        return "device";  /* for virtio-mmio */
-    } else if (g_str_equal(arch, "s390x")) {
-        return "ccw";
-    } else {
-        return "pci";
-    }
-}
-
-static void test_after_failed_device_add(void)
-{
-    char driver[32];
-    QDict *response;
-    QTestState *qts;
-
-    snprintf(driver, sizeof(driver), "virtio-blk-%s",
-             qvirtio_get_dev_type());
-
-    qts = qtest_init("-drive if=none,id=drive0");
-
-    /* Make device_add fail. If this leaks the virtio-blk device then a
-     * reference to drive0 will also be held (via qdev properties).
-     */
-    response = qtest_qmp(qts, "{'execute': 'device_add',"
-                              " 'arguments': {"
-                              "   'driver': %s,"
-                              "   'drive': 'drive0'"
-                              "}}", driver);
-    g_assert(response);
-    qmp_assert_error_class(response, "GenericError");
-
-    /* Delete the drive */
-    drive_del(qts);
-
-    /* Try to re-add the drive.  This fails with duplicate IDs if a leaked
-     * virtio-blk device exists that holds a reference to the old drive0.
-     */
-    drive_add(qts);
-
-    qtest_quit(qts);
-}
-
-static void test_drive_del_device_del(void)
-{
-    QTestState *qts;
-
-    /* Start with a drive used by a device that unplugs instantaneously */
-    qts = qtest_initf("-drive if=none,id=drive0,file=null-co://,"
-                      "file.read-zeroes=on,format=raw"
-                      " -device virtio-scsi-%s"
-                      " -device scsi-hd,drive=drive0,id=dev0",
-                      qvirtio_get_dev_type());
-
-    /*
-     * Delete the drive, and then the device
-     * Doing it in this order takes notoriously tricky special paths
-     */
-    drive_del(qts);
-    device_del(qts);
-
-    qtest_quit(qts);
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("/drive_del/without-dev", test_drive_without_dev);
-
-    if (qvirtio_get_dev_type() != NULL) {
-        qtest_add_func("/drive_del/after_failed_device_add",
-                       test_after_failed_device_add);
-        qtest_add_func("/blockdev/drive_del_device_del",
-                       test_drive_del_device_del);
-    }
-
-    return g_test_run();
-}
diff --git a/tests/ds1338-test.c b/tests/ds1338-test.c
deleted file mode 100644 (file)
index f6ade9a..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * QTest testcase for the DS1338 RTC
- *
- * Copyright (c) 2013 Jean-Christophe Dubois
- *
- *  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/>.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "libqos/i2c.h"
-
-#define DS1338_ADDR 0x68
-
-static inline uint8_t bcd2bin(uint8_t x)
-{
-    return ((x) & 0x0f) + ((x) >> 4) * 10;
-}
-
-static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc)
-{
-    QI2CDevice *i2cdev = (QI2CDevice *)obj;
-
-    uint8_t resp[7];
-    time_t now = time(NULL);
-    struct tm *tm_ptr = gmtime(&now);
-
-    i2c_read_block(i2cdev, 0, resp, sizeof(resp));
-
-    /* check retrieved time againt local time */
-    g_assert_cmpuint(bcd2bin(resp[4]), == , tm_ptr->tm_mday);
-    g_assert_cmpuint(bcd2bin(resp[5]), == , 1 + tm_ptr->tm_mon);
-    g_assert_cmpuint(2000 + bcd2bin(resp[6]), == , 1900 + tm_ptr->tm_year);
-}
-
-static void ds1338_register_nodes(void)
-{
-    QOSGraphEdgeOptions opts = {
-        .extra_device_opts = "address=0x68"
-    };
-    add_qi2c_address(&opts, &(QI2CAddress) { DS1338_ADDR });
-
-    qos_node_create_driver("ds1338", i2c_device_create);
-    qos_node_consumes("ds1338", "i2c-bus", &opts);
-    qos_add_test("tx-rx", "ds1338", send_and_receive, NULL);
-}
-libqos_init(ds1338_register_nodes);
diff --git a/tests/e1000-test.c b/tests/e1000-test.c
deleted file mode 100644 (file)
index c387984..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * QTest testcase for e1000 NIC
- *
- * Copyright (c) 2013-2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qemu/module.h"
-#include "libqos/qgraph.h"
-#include "libqos/pci.h"
-
-typedef struct QE1000 QE1000;
-
-struct QE1000 {
-    QOSGraphObject obj;
-    QPCIDevice dev;
-};
-
-static const char *models[] = {
-    "e1000",
-    "e1000-82540em",
-    "e1000-82544gc",
-    "e1000-82545em",
-};
-
-static void *e1000_get_driver(void *obj, const char *interface)
-{
-    QE1000 *e1000 = obj;
-
-    if (!g_strcmp0(interface, "pci-device")) {
-        return &e1000->dev;
-    }
-
-    fprintf(stderr, "%s not present in e1000e\n", interface);
-    g_assert_not_reached();
-}
-
-static void *e1000_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
-{
-    QE1000 *e1000 = g_new0(QE1000, 1);
-    QPCIBus *bus = pci_bus;
-
-    qpci_device_init(&e1000->dev, bus, addr);
-    e1000->obj.get_driver = e1000_get_driver;
-
-    return &e1000->obj;
-}
-
-static void e1000_register_nodes(void)
-{
-    int i;
-    QOSGraphEdgeOptions opts = {
-        .extra_device_opts = "addr=04.0",
-    };
-    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
-
-    for (i = 0; i < ARRAY_SIZE(models); i++) {
-        qos_node_create_driver(models[i], e1000_create);
-        qos_node_consumes(models[i], "pci-bus", &opts);
-        qos_node_produces(models[i], "pci-device");
-    }
-}
-
-libqos_init(e1000_register_nodes);
diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c
deleted file mode 100644 (file)
index 1a232a6..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
- /*
- * QTest testcase for e1000e NIC
- *
- * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <[email protected]>
- * Leonid Bloch <[email protected]>
- * Yan Vugenfirer <[email protected]>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "libqtest-single.h"
-#include "qemu-common.h"
-#include "libqos/pci-pc.h"
-#include "qemu/sockets.h"
-#include "qemu/iov.h"
-#include "qemu/module.h"
-#include "qemu/bitops.h"
-#include "libqos/malloc.h"
-#include "libqos/e1000e.h"
-
-static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
-{
-    struct {
-        uint64_t buffer_addr;
-        union {
-            uint32_t data;
-            struct {
-                uint16_t length;
-                uint8_t cso;
-                uint8_t cmd;
-            } flags;
-        } lower;
-        union {
-            uint32_t data;
-            struct {
-                uint8_t status;
-                uint8_t css;
-                uint16_t special;
-            } fields;
-        } upper;
-    } descr;
-
-    static const uint32_t dtyp_data = BIT(20);
-    static const uint32_t dtyp_ext  = BIT(29);
-    static const uint32_t dcmd_rs   = BIT(27);
-    static const uint32_t dcmd_eop  = BIT(24);
-    static const uint32_t dsta_dd   = BIT(0);
-    static const int data_len = 64;
-    char buffer[64];
-    int ret;
-    uint32_t recv_len;
-
-    /* Prepare test data buffer */
-    uint64_t data = guest_alloc(alloc, data_len);
-    memwrite(data, "TEST", 5);
-
-    /* Prepare TX descriptor */
-    memset(&descr, 0, sizeof(descr));
-    descr.buffer_addr = cpu_to_le64(data);
-    descr.lower.data = cpu_to_le32(dcmd_rs   |
-                                   dcmd_eop  |
-                                   dtyp_ext  |
-                                   dtyp_data |
-                                   data_len);
-
-    /* Put descriptor to the ring */
-    e1000e_tx_ring_push(d, &descr);
-
-    /* Wait for TX WB interrupt */
-    e1000e_wait_isr(d, E1000E_TX0_MSG_ID);
-
-    /* Check DD bit */
-    g_assert_cmphex(le32_to_cpu(descr.upper.data) & dsta_dd, ==, dsta_dd);
-
-    /* Check data sent to the backend */
-    ret = qemu_recv(test_sockets[0], &recv_len, sizeof(recv_len), 0);
-    g_assert_cmpint(ret, == , sizeof(recv_len));
-    qemu_recv(test_sockets[0], buffer, 64, 0);
-    g_assert_cmpstr(buffer, == , "TEST");
-
-    /* Free test data buffer */
-    guest_free(alloc, data);
-}
-
-static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
-{
-    union {
-        struct {
-            uint64_t buffer_addr;
-            uint64_t reserved;
-        } read;
-        struct {
-            struct {
-                uint32_t mrq;
-                union {
-                    uint32_t rss;
-                    struct {
-                        uint16_t ip_id;
-                        uint16_t csum;
-                    } csum_ip;
-                } hi_dword;
-            } lower;
-            struct {
-                uint32_t status_error;
-                uint16_t length;
-                uint16_t vlan;
-            } upper;
-        } wb;
-    } descr;
-
-    static const uint32_t esta_dd = BIT(0);
-
-    char test[] = "TEST";
-    int len = htonl(sizeof(test));
-    struct iovec iov[] = {
-        {
-            .iov_base = &len,
-            .iov_len = sizeof(len),
-        },{
-            .iov_base = test,
-            .iov_len = sizeof(test),
-        },
-    };
-
-    static const int data_len = 64;
-    char buffer[64];
-    int ret;
-
-    /* Send a dummy packet to device's socket*/
-    ret = iov_send(test_sockets[0], iov, 2, 0, sizeof(len) + sizeof(test));
-    g_assert_cmpint(ret, == , sizeof(test) + sizeof(len));
-
-    /* Prepare test data buffer */
-    uint64_t data = guest_alloc(alloc, data_len);
-
-    /* Prepare RX descriptor */
-    memset(&descr, 0, sizeof(descr));
-    descr.read.buffer_addr = cpu_to_le64(data);
-
-    /* Put descriptor to the ring */
-    e1000e_rx_ring_push(d, &descr);
-
-    /* Wait for TX WB interrupt */
-    e1000e_wait_isr(d, E1000E_RX0_MSG_ID);
-
-    /* Check DD bit */
-    g_assert_cmphex(le32_to_cpu(descr.wb.upper.status_error) &
-        esta_dd, ==, esta_dd);
-
-    /* Check data sent to the backend */
-    memread(data, buffer, sizeof(buffer));
-    g_assert_cmpstr(buffer, == , "TEST");
-
-    /* Free test data buffer */
-    guest_free(alloc, data);
-}
-
-static void test_e1000e_init(void *obj, void *data, QGuestAllocator * alloc)
-{
-    /* init does nothing */
-}
-
-static void test_e1000e_tx(void *obj, void *data, QGuestAllocator * alloc)
-{
-    QE1000E_PCI *e1000e = obj;
-    QE1000E *d = &e1000e->e1000e;
-    QOSGraphObject *e_object = obj;
-    QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
-
-    /* FIXME: add spapr support */
-    if (qpci_check_buggy_msi(dev)) {
-        return;
-    }
-
-    e1000e_send_verify(d, data, alloc);
-}
-
-static void test_e1000e_rx(void *obj, void *data, QGuestAllocator * alloc)
-{
-    QE1000E_PCI *e1000e = obj;
-    QE1000E *d = &e1000e->e1000e;
-    QOSGraphObject *e_object = obj;
-    QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
-
-    /* FIXME: add spapr support */
-    if (qpci_check_buggy_msi(dev)) {
-        return;
-    }
-
-    e1000e_receive_verify(d, data, alloc);
-}
-
-static void test_e1000e_multiple_transfers(void *obj, void *data,
-                                           QGuestAllocator *alloc)
-{
-    static const long iterations = 4 * 1024;
-    long i;
-
-    QE1000E_PCI *e1000e = obj;
-    QE1000E *d = &e1000e->e1000e;
-    QOSGraphObject *e_object = obj;
-    QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
-
-    /* FIXME: add spapr support */
-    if (qpci_check_buggy_msi(dev)) {
-        return;
-    }
-
-    for (i = 0; i < iterations; i++) {
-        e1000e_send_verify(d, data, alloc);
-        e1000e_receive_verify(d, data, alloc);
-    }
-
-}
-
-static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
-{
-    QTestState *qts = global_qtest;  /* TODO: get rid of global_qtest here */
-
-    qtest_qmp_device_add(qts, "e1000e", "e1000e_net", "{'addr': '0x06'}");
-    qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06);
-}
-
-static void data_test_clear(void *sockets)
-{
-    int *test_sockets = sockets;
-
-    close(test_sockets[0]);
-    qos_invalidate_command_line();
-    close(test_sockets[1]);
-    g_free(test_sockets);
-}
-
-static void *data_test_init(GString *cmd_line, void *arg)
-{
-    int *test_sockets = g_new(int, 2);
-    int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, test_sockets);
-    g_assert_cmpint(ret, != , -1);
-
-    g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ",
-                           test_sockets[1]);
-
-    g_test_queue_destroy(data_test_clear, test_sockets);
-    return test_sockets;
-}
-
-static void register_e1000e_test(void)
-{
-    QOSGraphTestOptions opts = {
-        .before = data_test_init,
-    };
-
-    qos_add_test("init", "e1000e", test_e1000e_init, &opts);
-    qos_add_test("tx", "e1000e", test_e1000e_tx, &opts);
-    qos_add_test("rx", "e1000e", test_e1000e_rx, &opts);
-    qos_add_test("multiple_transfers", "e1000e",
-                      test_e1000e_multiple_transfers, &opts);
-    qos_add_test("hotplug", "e1000e", test_e1000e_hotplug, &opts);
-}
-
-libqos_init(register_e1000e_test);
diff --git a/tests/eepro100-test.c b/tests/eepro100-test.c
deleted file mode 100644 (file)
index 8dbffff..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * QTest testcase for eepro100 NIC
- *
- * Copyright (c) 2013-2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qemu/module.h"
-#include "libqos/qgraph.h"
-#include "libqos/pci.h"
-
-typedef struct QEEPRO100 QEEPRO100;
-
-struct QEEPRO100 {
-    QOSGraphObject obj;
-    QPCIDevice dev;
-};
-
-static const char *models[] = {
-    "i82550",
-    "i82551",
-    "i82557a",
-    "i82557b",
-    "i82557c",
-    "i82558a",
-    "i82558b",
-    "i82559a",
-    "i82559b",
-    "i82559c",
-    "i82559er",
-    "i82562",
-    "i82801",
-};
-
-static void *eepro100_get_driver(void *obj, const char *interface)
-{
-    QEEPRO100 *eepro100 = obj;
-
-    if (!g_strcmp0(interface, "pci-device")) {
-        return &eepro100->dev;
-    }
-
-    fprintf(stderr, "%s not present in eepro100\n", interface);
-    g_assert_not_reached();
-}
-
-static void *eepro100_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
-{
-    QEEPRO100 *eepro100 = g_new0(QEEPRO100, 1);
-    QPCIBus *bus = pci_bus;
-
-    qpci_device_init(&eepro100->dev, bus, addr);
-    eepro100->obj.get_driver = eepro100_get_driver;
-
-    return &eepro100->obj;
-}
-
-static void eepro100_register_nodes(void)
-{
-    int i;
-    QOSGraphEdgeOptions opts = {
-        .extra_device_opts = "addr=04.0",
-    };
-
-    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
-    for (i = 0; i < ARRAY_SIZE(models); i++) {
-        qos_node_create_driver(models[i], eepro100_create);
-        qos_node_consumes(models[i], "pci-bus", &opts);
-        qos_node_produces(models[i], "pci-device");
-    }
-}
-
-libqos_init(eepro100_register_nodes);
diff --git a/tests/endianness-test.c b/tests/endianness-test.c
deleted file mode 100644 (file)
index 5852795..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * QTest testcase for ISA endianness
- *
- * Copyright Red Hat, Inc. 2012
- *
- * Authors:
- *  Paolo Bonzini <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-
-#include "libqtest.h"
-#include "qemu/bswap.h"
-
-typedef struct TestCase TestCase;
-struct TestCase {
-    const char *arch;
-    const char *machine;
-    uint64_t isa_base;
-    bool bswap;
-    const char *superio;
-};
-
-static const TestCase test_cases[] = {
-    { "i386", "pc", -1 },
-    { "mips", "mips", 0x14000000, .bswap = true },
-    { "mips", "malta", 0x10000000, .bswap = true },
-    { "mips64", "magnum", 0x90000000, .bswap = true },
-    { "mips64", "pica61", 0x90000000, .bswap = true },
-    { "mips64", "mips", 0x14000000, .bswap = true },
-    { "mips64", "malta", 0x10000000, .bswap = true },
-    { "mips64el", "fulong2e", 0x1fd00000 },
-    { "ppc", "g3beige", 0xfe000000, .bswap = true, .superio = "i82378" },
-    { "ppc", "prep", 0x80000000, .bswap = true },
-    { "ppc", "bamboo", 0xe8000000, .bswap = true, .superio = "i82378" },
-    { "ppc64", "mac99", 0xf2000000, .bswap = true, .superio = "i82378" },
-    { "ppc64", "pseries", (1ULL << 45), .bswap = true, .superio = "i82378" },
-    { "ppc64", "pseries-2.7", 0x10080000000ULL,
-      .bswap = true, .superio = "i82378" },
-    { "sh4", "r2d", 0xfe240000, .superio = "i82378" },
-    { "sh4eb", "r2d", 0xfe240000, .bswap = true, .superio = "i82378" },
-    { "sparc64", "sun4u", 0x1fe02000000LL, .bswap = true },
-    { "x86_64", "pc", -1 },
-    {}
-};
-
-static uint8_t isa_inb(QTestState *qts, const TestCase *test, uint16_t addr)
-{
-    uint8_t value;
-    if (test->isa_base == -1) {
-        value = qtest_inb(qts, addr);
-    } else {
-        value = qtest_readb(qts, test->isa_base + addr);
-    }
-    return value;
-}
-
-static uint16_t isa_inw(QTestState *qts, const TestCase *test, uint16_t addr)
-{
-    uint16_t value;
-    if (test->isa_base == -1) {
-        value = qtest_inw(qts, addr);
-    } else {
-        value = qtest_readw(qts, test->isa_base + addr);
-    }
-    return test->bswap ? bswap16(value) : value;
-}
-
-static uint32_t isa_inl(QTestState *qts, const TestCase *test, uint16_t addr)
-{
-    uint32_t value;
-    if (test->isa_base == -1) {
-        value = qtest_inl(qts, addr);
-    } else {
-        value = qtest_readl(qts, test->isa_base + addr);
-    }
-    return test->bswap ? bswap32(value) : value;
-}
-
-static void isa_outb(QTestState *qts, const TestCase *test, uint16_t addr,
-                     uint8_t value)
-{
-    if (test->isa_base == -1) {
-        qtest_outb(qts, addr, value);
-    } else {
-        qtest_writeb(qts, test->isa_base + addr, value);
-    }
-}
-
-static void isa_outw(QTestState *qts, const TestCase *test, uint16_t addr,
-                     uint16_t value)
-{
-    value = test->bswap ? bswap16(value) : value;
-    if (test->isa_base == -1) {
-        qtest_outw(qts, addr, value);
-    } else {
-        qtest_writew(qts, test->isa_base + addr, value);
-    }
-}
-
-static void isa_outl(QTestState *qts, const TestCase *test, uint16_t addr,
-                     uint32_t value)
-{
-    value = test->bswap ? bswap32(value) : value;
-    if (test->isa_base == -1) {
-        qtest_outl(qts, addr, value);
-    } else {
-        qtest_writel(qts, test->isa_base + addr, value);
-    }
-}
-
-
-static void test_endianness(gconstpointer data)
-{
-    const TestCase *test = data;
-    QTestState *qts;
-
-    qts = qtest_initf("-M %s%s%s -device pc-testdev", test->machine,
-                      test->superio ? " -device " : "",
-                      test->superio ?: "");
-    isa_outl(qts, test, 0xe0, 0x87654321);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
-    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
-    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
-    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65);
-    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43);
-    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x21);
-
-    isa_outw(qts, test, 0xe2, 0x8866);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664321);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866);
-    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
-    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x88);
-    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x66);
-    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43);
-    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x21);
-
-    isa_outw(qts, test, 0xe0, 0x4422);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664422);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866);
-    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422);
-    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x88);
-    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x66);
-    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x44);
-    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22);
-
-    isa_outb(qts, test, 0xe3, 0x87);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87664422);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8766);
-    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
-    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x66);
-    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x44);
-    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22);
-
-    isa_outb(qts, test, 0xe2, 0x65);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654422);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
-    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422);
-    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
-    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65);
-    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x44);
-    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22);
-
-    isa_outb(qts, test, 0xe1, 0x43);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654322);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
-    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4322);
-    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
-    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65);
-    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43);
-    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22);
-
-    isa_outb(qts, test, 0xe0, 0x21);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
-    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
-    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
-    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65);
-    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43);
-    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x21);
-    qtest_quit(qts);
-}
-
-static void test_endianness_split(gconstpointer data)
-{
-    const TestCase *test = data;
-    QTestState *qts;
-
-    qts = qtest_initf("-M %s%s%s -device pc-testdev", test->machine,
-                      test->superio ? " -device " : "",
-                      test->superio ?: "");
-    isa_outl(qts, test, 0xe8, 0x87654321);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
-    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
-
-    isa_outw(qts, test, 0xea, 0x8866);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664321);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866);
-    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
-
-    isa_outw(qts, test, 0xe8, 0x4422);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664422);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866);
-    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422);
-
-    isa_outb(qts, test, 0xeb, 0x87);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87664422);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8766);
-
-    isa_outb(qts, test, 0xea, 0x65);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654422);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
-    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422);
-
-    isa_outb(qts, test, 0xe9, 0x43);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654322);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
-    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4322);
-
-    isa_outb(qts, test, 0xe8, 0x21);
-    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321);
-    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
-    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
-    qtest_quit(qts);
-}
-
-static void test_endianness_combine(gconstpointer data)
-{
-    const TestCase *test = data;
-    QTestState *qts;
-
-    qts = qtest_initf("-M %s%s%s -device pc-testdev", test->machine,
-                      test->superio ? " -device " : "",
-                      test->superio ?: "");
-    isa_outl(qts, test, 0xe0, 0x87654321);
-    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654321);
-    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765);
-    g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4321);
-
-    isa_outw(qts, test, 0xe2, 0x8866);
-    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x88664321);
-    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8866);
-    g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4321);
-
-    isa_outw(qts, test, 0xe0, 0x4422);
-    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x88664422);
-    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8866);
-    g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4422);
-
-    isa_outb(qts, test, 0xe3, 0x87);
-    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87664422);
-    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8766);
-
-    isa_outb(qts, test, 0xe2, 0x65);
-    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654422);
-    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765);
-    g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4422);
-
-    isa_outb(qts, test, 0xe1, 0x43);
-    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654322);
-    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765);
-    g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4322);
-
-    isa_outb(qts, test, 0xe0, 0x21);
-    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654321);
-    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765);
-    g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4321);
-    qtest_quit(qts);
-}
-
-int main(int argc, char **argv)
-{
-    const char *arch = qtest_get_arch();
-    int i;
-
-    g_test_init(&argc, &argv, NULL);
-
-    for (i = 0; test_cases[i].arch; i++) {
-        gchar *path;
-        if (strcmp(test_cases[i].arch, arch) != 0) {
-            continue;
-        }
-        path = g_strdup_printf("endianness/%s",
-                               test_cases[i].machine);
-        qtest_add_data_func(path, &test_cases[i], test_endianness);
-        g_free(path);
-
-        path = g_strdup_printf("endianness/split/%s",
-                               test_cases[i].machine);
-        qtest_add_data_func(path, &test_cases[i], test_endianness_split);
-        g_free(path);
-
-        path = g_strdup_printf("endianness/combine/%s",
-                               test_cases[i].machine);
-        qtest_add_data_func(path, &test_cases[i], test_endianness_combine);
-        g_free(path);
-    }
-
-    return g_test_run();
-}
diff --git a/tests/es1370-test.c b/tests/es1370-test.c
deleted file mode 100644 (file)
index adccdac..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * QTest testcase for ES1370
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qemu/module.h"
-#include "libqos/qgraph.h"
-#include "libqos/pci.h"
-
-typedef struct QES1370 QES1370;
-
-struct QES1370 {
-    QOSGraphObject obj;
-    QPCIDevice dev;
-};
-
-static void *es1370_get_driver(void *obj, const char *interface)
-{
-    QES1370 *es1370 = obj;
-
-    if (!g_strcmp0(interface, "pci-device")) {
-        return &es1370->dev;
-    }
-
-    fprintf(stderr, "%s not present in e1000e\n", interface);
-    g_assert_not_reached();
-}
-
-static void *es1370_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
-{
-    QES1370 *es1370 = g_new0(QES1370, 1);
-    QPCIBus *bus = pci_bus;
-
-    qpci_device_init(&es1370->dev, bus, addr);
-    es1370->obj.get_driver = es1370_get_driver;
-
-    return &es1370->obj;
-}
-
-static void es1370_register_nodes(void)
-{
-    QOSGraphEdgeOptions opts = {
-        .extra_device_opts = "addr=04.0",
-    };
-    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
-
-    qos_node_create_driver("ES1370", es1370_create);
-    qos_node_consumes("ES1370", "pci-bus", &opts);
-    qos_node_produces("ES1370", "pci-device");
-}
-
-libqos_init(es1370_register_nodes);
diff --git a/tests/fdc-test.c b/tests/fdc-test.c
deleted file mode 100644 (file)
index 26b69f7..0000000
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * Floppy test cases.
- *
- * Copyright (c) 2012 Kevin Wolf <[email protected]>
- *
- * 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 "libqtest-single.h"
-#include "qapi/qmp/qdict.h"
-#include "qemu-common.h"
-
-/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
-
-#define TEST_IMAGE_SIZE 1440 * 1024
-
-#define FLOPPY_BASE 0x3f0
-#define FLOPPY_IRQ 6
-
-enum {
-    reg_sra         = 0x0,
-    reg_srb         = 0x1,
-    reg_dor         = 0x2,
-    reg_msr         = 0x4,
-    reg_dsr         = 0x4,
-    reg_fifo        = 0x5,
-    reg_dir         = 0x7,
-};
-
-enum {
-    CMD_SENSE_INT           = 0x08,
-    CMD_READ_ID             = 0x0a,
-    CMD_SEEK                = 0x0f,
-    CMD_VERIFY              = 0x16,
-    CMD_READ                = 0xe6,
-    CMD_RELATIVE_SEEK_OUT   = 0x8f,
-    CMD_RELATIVE_SEEK_IN    = 0xcf,
-};
-
-enum {
-    BUSY    = 0x10,
-    NONDMA  = 0x20,
-    RQM     = 0x80,
-    DIO     = 0x40,
-
-    DSKCHG  = 0x80,
-};
-
-static char test_image[] = "/tmp/qtest.XXXXXX";
-
-#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
-#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
-
-static uint8_t base = 0x70;
-
-enum {
-    CMOS_FLOPPY     = 0x10,
-};
-
-static void floppy_send(uint8_t byte)
-{
-    uint8_t msr;
-
-    msr = inb(FLOPPY_BASE + reg_msr);
-    assert_bit_set(msr, RQM);
-    assert_bit_clear(msr, DIO);
-
-    outb(FLOPPY_BASE + reg_fifo, byte);
-}
-
-static uint8_t floppy_recv(void)
-{
-    uint8_t msr;
-
-    msr = inb(FLOPPY_BASE + reg_msr);
-    assert_bit_set(msr, RQM | DIO);
-
-    return inb(FLOPPY_BASE + reg_fifo);
-}
-
-/* pcn: Present Cylinder Number */
-static void ack_irq(uint8_t *pcn)
-{
-    uint8_t ret;
-
-    g_assert(get_irq(FLOPPY_IRQ));
-    floppy_send(CMD_SENSE_INT);
-    floppy_recv();
-
-    ret = floppy_recv();
-    if (pcn != NULL) {
-        *pcn = ret;
-    }
-
-    g_assert(!get_irq(FLOPPY_IRQ));
-}
-
-static uint8_t send_read_command(uint8_t cmd)
-{
-    uint8_t drive = 0;
-    uint8_t head = 0;
-    uint8_t cyl = 0;
-    uint8_t sect_addr = 1;
-    uint8_t sect_size = 2;
-    uint8_t eot = 1;
-    uint8_t gap = 0x1b;
-    uint8_t gpl = 0xff;
-
-    uint8_t msr = 0;
-    uint8_t st0;
-
-    uint8_t ret = 0;
-
-    floppy_send(cmd);
-    floppy_send(head << 2 | drive);
-    g_assert(!get_irq(FLOPPY_IRQ));
-    floppy_send(cyl);
-    floppy_send(head);
-    floppy_send(sect_addr);
-    floppy_send(sect_size);
-    floppy_send(eot);
-    floppy_send(gap);
-    floppy_send(gpl);
-
-    uint8_t i = 0;
-    uint8_t n = 2;
-    for (; i < n; i++) {
-        msr = inb(FLOPPY_BASE + reg_msr);
-        if (msr == 0xd0) {
-            break;
-        }
-        sleep(1);
-    }
-
-    if (i >= n) {
-        return 1;
-    }
-
-    st0 = floppy_recv();
-    if (st0 != 0x40) {
-        ret = 1;
-    }
-
-    floppy_recv();
-    floppy_recv();
-    floppy_recv();
-    floppy_recv();
-    floppy_recv();
-    floppy_recv();
-
-    return ret;
-}
-
-static uint8_t send_read_no_dma_command(int nb_sect, uint8_t expected_st0)
-{
-    uint8_t drive = 0;
-    uint8_t head = 0;
-    uint8_t cyl = 0;
-    uint8_t sect_addr = 1;
-    uint8_t sect_size = 2;
-    uint8_t eot = nb_sect;
-    uint8_t gap = 0x1b;
-    uint8_t gpl = 0xff;
-
-    uint8_t msr = 0;
-    uint8_t st0;
-
-    uint8_t ret = 0;
-
-    floppy_send(CMD_READ);
-    floppy_send(head << 2 | drive);
-    g_assert(!get_irq(FLOPPY_IRQ));
-    floppy_send(cyl);
-    floppy_send(head);
-    floppy_send(sect_addr);
-    floppy_send(sect_size);
-    floppy_send(eot);
-    floppy_send(gap);
-    floppy_send(gpl);
-
-    uint16_t i = 0;
-    uint8_t n = 2;
-    for (; i < n; i++) {
-        msr = inb(FLOPPY_BASE + reg_msr);
-        if (msr == (BUSY | NONDMA | DIO | RQM)) {
-            break;
-        }
-        sleep(1);
-    }
-
-    if (i >= n) {
-        return 1;
-    }
-
-    /* Non-DMA mode */
-    for (i = 0; i < 512 * 2 * nb_sect; i++) {
-        msr = inb(FLOPPY_BASE + reg_msr);
-        assert_bit_set(msr, BUSY | RQM | DIO);
-        inb(FLOPPY_BASE + reg_fifo);
-    }
-
-    msr = inb(FLOPPY_BASE + reg_msr);
-    assert_bit_set(msr, BUSY | RQM | DIO);
-    g_assert(get_irq(FLOPPY_IRQ));
-
-    st0 = floppy_recv();
-    if (st0 != expected_st0) {
-        ret = 1;
-    }
-
-    floppy_recv();
-    floppy_recv();
-    floppy_recv();
-    floppy_recv();
-    floppy_recv();
-    g_assert(get_irq(FLOPPY_IRQ));
-    floppy_recv();
-
-    /* Check that we're back in command phase */
-    msr = inb(FLOPPY_BASE + reg_msr);
-    assert_bit_clear(msr, BUSY | DIO);
-    assert_bit_set(msr, RQM);
-    g_assert(!get_irq(FLOPPY_IRQ));
-
-    return ret;
-}
-
-static void send_seek(int cyl)
-{
-    int drive = 0;
-    int head = 0;
-
-    floppy_send(CMD_SEEK);
-    floppy_send(head << 2 | drive);
-    g_assert(!get_irq(FLOPPY_IRQ));
-    floppy_send(cyl);
-    ack_irq(NULL);
-}
-
-static uint8_t cmos_read(uint8_t reg)
-{
-    outb(base + 0, reg);
-    return inb(base + 1);
-}
-
-static void test_cmos(void)
-{
-    uint8_t cmos;
-
-    cmos = cmos_read(CMOS_FLOPPY);
-    g_assert(cmos == 0x40 || cmos == 0x50);
-}
-
-static void test_no_media_on_start(void)
-{
-    uint8_t dir;
-
-    /* Media changed bit must be set all time after start if there is
-     * no media in drive. */
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-    send_seek(1);
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-}
-
-static void test_read_without_media(void)
-{
-    uint8_t ret;
-
-    ret = send_read_command(CMD_READ);
-    g_assert(ret == 0);
-}
-
-static void test_media_insert(void)
-{
-    uint8_t dir;
-
-    /* Insert media in drive. DSKCHK should not be reset until a step pulse
-     * is sent. */
-    qmp_discard_response("{'execute':'blockdev-change-medium', 'arguments':{"
-                         " 'id':'floppy0', 'filename': %s, 'format': 'raw' }}",
-                         test_image);
-
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-
-    send_seek(0);
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-
-    /* Step to next track should clear DSKCHG bit. */
-    send_seek(1);
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_clear(dir, DSKCHG);
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_clear(dir, DSKCHG);
-}
-
-static void test_media_change(void)
-{
-    uint8_t dir;
-
-    test_media_insert();
-
-    /* Eject the floppy and check that DSKCHG is set. Reading it out doesn't
-     * reset the bit. */
-    qmp_discard_response("{'execute':'eject', 'arguments':{"
-                         " 'id':'floppy0' }}");
-
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-
-    send_seek(0);
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-
-    send_seek(1);
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-    dir = inb(FLOPPY_BASE + reg_dir);
-    assert_bit_set(dir, DSKCHG);
-}
-
-static void test_sense_interrupt(void)
-{
-    int drive = 0;
-    int head = 0;
-    int cyl = 0;
-    int ret = 0;
-
-    floppy_send(CMD_SENSE_INT);
-    ret = floppy_recv();
-    g_assert(ret == 0x80);
-
-    floppy_send(CMD_SEEK);
-    floppy_send(head << 2 | drive);
-    g_assert(!get_irq(FLOPPY_IRQ));
-    floppy_send(cyl);
-
-    floppy_send(CMD_SENSE_INT);
-    ret = floppy_recv();
-    g_assert(ret == 0x20);
-    floppy_recv();
-}
-
-static void test_relative_seek(void)
-{
-    uint8_t drive = 0;
-    uint8_t head = 0;
-    uint8_t cyl = 1;
-    uint8_t pcn;
-
-    /* Send seek to track 0 */
-    send_seek(0);
-
-    /* Send relative seek to increase track by 1 */
-    floppy_send(CMD_RELATIVE_SEEK_IN);
-    floppy_send(head << 2 | drive);
-    g_assert(!get_irq(FLOPPY_IRQ));
-    floppy_send(cyl);
-
-    ack_irq(&pcn);
-    g_assert(pcn == 1);
-
-    /* Send relative seek to decrease track by 1 */
-    floppy_send(CMD_RELATIVE_SEEK_OUT);
-    floppy_send(head << 2 | drive);
-    g_assert(!get_irq(FLOPPY_IRQ));
-    floppy_send(cyl);
-
-    ack_irq(&pcn);
-    g_assert(pcn == 0);
-}
-
-static void test_read_id(void)
-{
-    uint8_t drive = 0;
-    uint8_t head = 0;
-    uint8_t cyl;
-    uint8_t st0;
-    uint8_t msr;
-
-    /* Seek to track 0 and check with READ ID */
-    send_seek(0);
-
-    floppy_send(CMD_READ_ID);
-    g_assert(!get_irq(FLOPPY_IRQ));
-    floppy_send(head << 2 | drive);
-
-    msr = inb(FLOPPY_BASE + reg_msr);
-    if (!get_irq(FLOPPY_IRQ)) {
-        assert_bit_set(msr, BUSY);
-        assert_bit_clear(msr, RQM);
-    }
-
-    while (!get_irq(FLOPPY_IRQ)) {
-        /* qemu involves a timer with READ ID... */
-        clock_step(1000000000LL / 50);
-    }
-
-    msr = inb(FLOPPY_BASE + reg_msr);
-    assert_bit_set(msr, BUSY | RQM | DIO);
-
-    st0 = floppy_recv();
-    floppy_recv();
-    floppy_recv();
-    cyl = floppy_recv();
-    head = floppy_recv();
-    floppy_recv();
-    g_assert(get_irq(FLOPPY_IRQ));
-    floppy_recv();
-    g_assert(!get_irq(FLOPPY_IRQ));
-
-    g_assert_cmpint(cyl, ==, 0);
-    g_assert_cmpint(head, ==, 0);
-    g_assert_cmpint(st0, ==, head << 2);
-
-    /* Seek to track 8 on head 1 and check with READ ID */
-    head = 1;
-    cyl = 8;
-
-    floppy_send(CMD_SEEK);
-    floppy_send(head << 2 | drive);
-    g_assert(!get_irq(FLOPPY_IRQ));
-    floppy_send(cyl);
-    g_assert(get_irq(FLOPPY_IRQ));
-    ack_irq(NULL);
-
-    floppy_send(CMD_READ_ID);
-    g_assert(!get_irq(FLOPPY_IRQ));
-    floppy_send(head << 2 | drive);
-
-    msr = inb(FLOPPY_BASE + reg_msr);
-    if (!get_irq(FLOPPY_IRQ)) {
-        assert_bit_set(msr, BUSY);
-        assert_bit_clear(msr, RQM);
-    }
-
-    while (!get_irq(FLOPPY_IRQ)) {
-        /* qemu involves a timer with READ ID... */
-        clock_step(1000000000LL / 50);
-    }
-
-    msr = inb(FLOPPY_BASE + reg_msr);
-    assert_bit_set(msr, BUSY | RQM | DIO);
-
-    st0 = floppy_recv();
-    floppy_recv();
-    floppy_recv();
-    cyl = floppy_recv();
-    head = floppy_recv();
-    floppy_recv();
-    g_assert(get_irq(FLOPPY_IRQ));
-    floppy_recv();
-    g_assert(!get_irq(FLOPPY_IRQ));
-
-    g_assert_cmpint(cyl, ==, 8);
-    g_assert_cmpint(head, ==, 1);
-    g_assert_cmpint(st0, ==, head << 2);
-}
-
-static void test_read_no_dma_1(void)
-{
-    uint8_t ret;
-
-    outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08);
-    send_seek(0);
-    ret = send_read_no_dma_command(1, 0x04);
-    g_assert(ret == 0);
-}
-
-static void test_read_no_dma_18(void)
-{
-    uint8_t ret;
-
-    outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08);
-    send_seek(0);
-    ret = send_read_no_dma_command(18, 0x04);
-    g_assert(ret == 0);
-}
-
-static void test_read_no_dma_19(void)
-{
-    uint8_t ret;
-
-    outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08);
-    send_seek(0);
-    ret = send_read_no_dma_command(19, 0x20);
-    g_assert(ret == 0);
-}
-
-static void test_verify(void)
-{
-    uint8_t ret;
-
-    ret = send_read_command(CMD_VERIFY);
-    g_assert(ret == 0);
-}
-
-/* success if no crash or abort */
-static void fuzz_registers(void)
-{
-    unsigned int i;
-
-    for (i = 0; i < 1000; i++) {
-        uint8_t reg, val;
-
-        reg = (uint8_t)g_test_rand_int_range(0, 8);
-        val = (uint8_t)g_test_rand_int_range(0, 256);
-
-        outb(FLOPPY_BASE + reg, val);
-        inb(FLOPPY_BASE + reg);
-    }
-}
-
-int main(int argc, char **argv)
-{
-    int fd;
-    int ret;
-
-    /* Create a temporary raw image */
-    fd = mkstemp(test_image);
-    g_assert(fd >= 0);
-    ret = ftruncate(fd, TEST_IMAGE_SIZE);
-    g_assert(ret == 0);
-    close(fd);
-
-    /* Run the tests */
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_start("-device floppy,id=floppy0");
-    qtest_irq_intercept_in(global_qtest, "ioapic");
-    qtest_add_func("/fdc/cmos", test_cmos);
-    qtest_add_func("/fdc/no_media_on_start", test_no_media_on_start);
-    qtest_add_func("/fdc/read_without_media", test_read_without_media);
-    qtest_add_func("/fdc/media_change", test_media_change);
-    qtest_add_func("/fdc/sense_interrupt", test_sense_interrupt);
-    qtest_add_func("/fdc/relative_seek", test_relative_seek);
-    qtest_add_func("/fdc/read_id", test_read_id);
-    qtest_add_func("/fdc/verify", test_verify);
-    qtest_add_func("/fdc/media_insert", test_media_insert);
-    qtest_add_func("/fdc/read_no_dma_1", test_read_no_dma_1);
-    qtest_add_func("/fdc/read_no_dma_18", test_read_no_dma_18);
-    qtest_add_func("/fdc/read_no_dma_19", test_read_no_dma_19);
-    qtest_add_func("/fdc/fuzz-registers", fuzz_registers);
-
-    ret = g_test_run();
-
-    /* Cleanup */
-    qtest_end();
-    unlink(test_image);
-
-    return ret;
-}
diff --git a/tests/fw_cfg-test.c b/tests/fw_cfg-test.c
deleted file mode 100644 (file)
index 5dc807b..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * qtest fw_cfg test case
- *
- * Copyright IBM, Corp. 2012-2013
- *
- * Authors:
- *  Anthony Liguori   <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-
-#include "libqtest.h"
-#include "standard-headers/linux/qemu_fw_cfg.h"
-#include "libqos/fw_cfg.h"
-#include "qemu/bswap.h"
-
-static uint64_t ram_size = 128 << 20;
-static uint16_t nb_cpus = 1;
-static uint16_t max_cpus = 1;
-static uint64_t nb_nodes = 0;
-static uint16_t boot_menu = 0;
-
-static void test_fw_cfg_signature(void)
-{
-    QFWCFG *fw_cfg;
-    QTestState *s;
-    char buf[5];
-
-    s = qtest_init("");
-    fw_cfg = pc_fw_cfg_init(s);
-
-    qfw_cfg_get(fw_cfg, FW_CFG_SIGNATURE, buf, 4);
-    buf[4] = 0;
-
-    g_assert_cmpstr(buf, ==, "QEMU");
-    pc_fw_cfg_uninit(fw_cfg);
-    qtest_quit(s);
-}
-
-static void test_fw_cfg_id(void)
-{
-    QFWCFG *fw_cfg;
-    QTestState *s;
-    uint32_t id;
-
-    s = qtest_init("");
-    fw_cfg = pc_fw_cfg_init(s);
-
-    id = qfw_cfg_get_u32(fw_cfg, FW_CFG_ID);
-    g_assert((id == 1) ||
-             (id == 3));
-    pc_fw_cfg_uninit(fw_cfg);
-    qtest_quit(s);
-}
-
-static void test_fw_cfg_uuid(void)
-{
-    QFWCFG *fw_cfg;
-    QTestState *s;
-
-    uint8_t buf[16];
-    static const uint8_t uuid[16] = {
-        0x46, 0x00, 0xcb, 0x32, 0x38, 0xec, 0x4b, 0x2f,
-        0x8a, 0xcb, 0x81, 0xc6, 0xea, 0x54, 0xf2, 0xd8,
-    };
-
-    s = qtest_init("-uuid 4600cb32-38ec-4b2f-8acb-81c6ea54f2d8");
-    fw_cfg = pc_fw_cfg_init(s);
-
-    qfw_cfg_get(fw_cfg, FW_CFG_UUID, buf, 16);
-    g_assert(memcmp(buf, uuid, sizeof(buf)) == 0);
-
-    pc_fw_cfg_uninit(fw_cfg);
-    qtest_quit(s);
-
-}
-
-static void test_fw_cfg_ram_size(void)
-{
-    QFWCFG *fw_cfg;
-    QTestState *s;
-
-    s = qtest_init("");
-    fw_cfg = pc_fw_cfg_init(s);
-
-    g_assert_cmpint(qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE), ==, ram_size);
-
-    pc_fw_cfg_uninit(fw_cfg);
-    qtest_quit(s);
-}
-
-static void test_fw_cfg_nographic(void)
-{
-    QFWCFG *fw_cfg;
-    QTestState *s;
-
-    s = qtest_init("");
-    fw_cfg = pc_fw_cfg_init(s);
-
-    g_assert_cmpint(qfw_cfg_get_u16(fw_cfg, FW_CFG_NOGRAPHIC), ==, 0);
-
-    pc_fw_cfg_uninit(fw_cfg);
-    qtest_quit(s);
-}
-
-static void test_fw_cfg_nb_cpus(void)
-{
-    QFWCFG *fw_cfg;
-    QTestState *s;
-
-    s = qtest_init("");
-    fw_cfg = pc_fw_cfg_init(s);
-
-    g_assert_cmpint(qfw_cfg_get_u16(fw_cfg, FW_CFG_NB_CPUS), ==, nb_cpus);
-
-    pc_fw_cfg_uninit(fw_cfg);
-    qtest_quit(s);
-}
-
-static void test_fw_cfg_max_cpus(void)
-{
-    QFWCFG *fw_cfg;
-    QTestState *s;
-
-    s = qtest_init("");
-    fw_cfg = pc_fw_cfg_init(s);
-
-    g_assert_cmpint(qfw_cfg_get_u16(fw_cfg, FW_CFG_MAX_CPUS), ==, max_cpus);
-    pc_fw_cfg_uninit(fw_cfg);
-    qtest_quit(s);
-}
-
-static void test_fw_cfg_numa(void)
-{
-    QFWCFG *fw_cfg;
-    QTestState *s;
-    uint64_t *cpu_mask;
-    uint64_t *node_mask;
-
-    s = qtest_init("");
-    fw_cfg = pc_fw_cfg_init(s);
-
-    g_assert_cmpint(qfw_cfg_get_u64(fw_cfg, FW_CFG_NUMA), ==, nb_nodes);
-
-    cpu_mask = g_new0(uint64_t, max_cpus);
-    node_mask = g_new0(uint64_t, nb_nodes);
-
-    qfw_cfg_read_data(fw_cfg, cpu_mask, sizeof(uint64_t) * max_cpus);
-    qfw_cfg_read_data(fw_cfg, node_mask, sizeof(uint64_t) * nb_nodes);
-
-    if (nb_nodes) {
-        g_assert(cpu_mask[0] & 0x01);
-        g_assert_cmpint(node_mask[0], ==, ram_size);
-    }
-
-    g_free(node_mask);
-    g_free(cpu_mask);
-    pc_fw_cfg_uninit(fw_cfg);
-    qtest_quit(s);
-}
-
-static void test_fw_cfg_boot_menu(void)
-{
-    QFWCFG *fw_cfg;
-    QTestState *s;
-
-    s = qtest_init("");
-    fw_cfg = pc_fw_cfg_init(s);
-
-    g_assert_cmpint(qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_MENU), ==, boot_menu);
-    pc_fw_cfg_uninit(fw_cfg);
-    qtest_quit(s);
-}
-
-static void test_fw_cfg_reboot_timeout(void)
-{
-    QFWCFG *fw_cfg;
-    QTestState *s;
-    uint32_t reboot_timeout = 0;
-    size_t filesize;
-
-    s = qtest_init("-boot reboot-timeout=15");
-    fw_cfg = pc_fw_cfg_init(s);
-
-    filesize = qfw_cfg_get_file(fw_cfg, "etc/boot-fail-wait",
-                                &reboot_timeout, sizeof(reboot_timeout));
-    g_assert_cmpint(filesize, ==, sizeof(reboot_timeout));
-    reboot_timeout = le32_to_cpu(reboot_timeout);
-    g_assert_cmpint(reboot_timeout, ==, 15);
-    pc_fw_cfg_uninit(fw_cfg);
-    qtest_quit(s);
-}
-
-static void test_fw_cfg_no_reboot_timeout(void)
-{
-    QFWCFG *fw_cfg;
-    QTestState *s;
-    uint32_t reboot_timeout = 0;
-    size_t filesize;
-
-    /* Special value -1 means "don't reboot" */
-    s = qtest_init("-boot reboot-timeout=-1");
-    fw_cfg = pc_fw_cfg_init(s);
-
-    filesize = qfw_cfg_get_file(fw_cfg, "etc/boot-fail-wait",
-                                &reboot_timeout, sizeof(reboot_timeout));
-    g_assert_cmpint(filesize, ==, sizeof(reboot_timeout));
-    reboot_timeout = le32_to_cpu(reboot_timeout);
-    g_assert_cmpint(reboot_timeout, ==, UINT32_MAX);
-    pc_fw_cfg_uninit(fw_cfg);
-    qtest_quit(s);
-}
-
-static void test_fw_cfg_splash_time(void)
-{
-    QFWCFG *fw_cfg;
-    QTestState *s;
-    uint16_t splash_time = 0;
-    size_t filesize;
-
-    s = qtest_init("-boot splash-time=12");
-    fw_cfg = pc_fw_cfg_init(s);
-
-    filesize = qfw_cfg_get_file(fw_cfg, "etc/boot-menu-wait",
-                                &splash_time, sizeof(splash_time));
-    g_assert_cmpint(filesize, ==, sizeof(splash_time));
-    splash_time = le16_to_cpu(splash_time);
-    g_assert_cmpint(splash_time, ==, 12);
-    pc_fw_cfg_uninit(fw_cfg);
-    qtest_quit(s);
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("fw_cfg/signature", test_fw_cfg_signature);
-    qtest_add_func("fw_cfg/id", test_fw_cfg_id);
-    qtest_add_func("fw_cfg/uuid", test_fw_cfg_uuid);
-    qtest_add_func("fw_cfg/ram_size", test_fw_cfg_ram_size);
-    qtest_add_func("fw_cfg/nographic", test_fw_cfg_nographic);
-    qtest_add_func("fw_cfg/nb_cpus", test_fw_cfg_nb_cpus);
-#if 0
-    qtest_add_func("fw_cfg/machine_id", test_fw_cfg_machine_id);
-    qtest_add_func("fw_cfg/kernel", test_fw_cfg_kernel);
-    qtest_add_func("fw_cfg/initrd", test_fw_cfg_initrd);
-    qtest_add_func("fw_cfg/boot_device", test_fw_cfg_boot_device);
-#endif
-    qtest_add_func("fw_cfg/max_cpus", test_fw_cfg_max_cpus);
-    qtest_add_func("fw_cfg/numa", test_fw_cfg_numa);
-    qtest_add_func("fw_cfg/boot_menu", test_fw_cfg_boot_menu);
-    qtest_add_func("fw_cfg/reboot_timeout", test_fw_cfg_reboot_timeout);
-    qtest_add_func("fw_cfg/no_reboot_timeout", test_fw_cfg_no_reboot_timeout);
-    qtest_add_func("fw_cfg/splash_time", test_fw_cfg_splash_time);
-
-    return g_test_run();
-}
diff --git a/tests/hd-geo-test.c b/tests/hd-geo-test.c
deleted file mode 100644 (file)
index a249800..0000000
+++ /dev/null
@@ -1,988 +0,0 @@
-/*
- * Hard disk geometry test cases.
- *
- * Copyright (c) 2012 Red Hat Inc.
- *
- * Authors:
- *  Markus Armbruster <[email protected]>,
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-/*
- * Covers only IDE and tests only CMOS contents.  Better than nothing.
- * Improvements welcome.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/bswap.h"
-#include "qapi/qmp/qlist.h"
-#include "libqtest.h"
-#include "libqos/fw_cfg.h"
-#include "libqos/libqos.h"
-#include "standard-headers/linux/qemu_fw_cfg.h"
-
-#define ARGV_SIZE 256
-
-static char *create_test_img(int secs)
-{
-    char *template = strdup("/tmp/qtest.XXXXXX");
-    int fd, ret;
-
-    fd = mkstemp(template);
-    g_assert(fd >= 0);
-    ret = ftruncate(fd, (off_t)secs * 512);
-    close(fd);
-
-    if (ret) {
-        free(template);
-        template = NULL;
-    }
-
-    return template;
-}
-
-typedef struct {
-    int cyls, heads, secs, trans;
-} CHST;
-
-typedef enum {
-    mbr_blank, mbr_lba, mbr_chs,
-    mbr_last
-} MBRcontents;
-
-typedef enum {
-    /* order is relevant */
-    backend_small, backend_large, backend_empty,
-    backend_last
-} Backend;
-
-static const int img_secs[backend_last] = {
-    [backend_small] = 61440,
-    [backend_large] = 8388608,
-    [backend_empty] = -1,
-};
-
-static const CHST hd_chst[backend_last][mbr_last] = {
-    [backend_small] = {
-        [mbr_blank] = { 60, 16, 63, 0 },
-        [mbr_lba]   = { 60, 16, 63, 2 },
-        [mbr_chs]   = { 60, 16, 63, 0 }
-    },
-    [backend_large] = {
-        [mbr_blank] = { 8322, 16, 63, 1 },
-        [mbr_lba]   = { 8322, 16, 63, 1 },
-        [mbr_chs]   = { 8322, 16, 63, 0 }
-    },
-};
-
-static char *img_file_name[backend_last];
-
-static const CHST *cur_ide[4];
-
-static bool is_hd(const CHST *expected_chst)
-{
-    return expected_chst && expected_chst->cyls;
-}
-
-static void test_cmos_byte(QTestState *qts, int reg, int expected)
-{
-    enum { cmos_base = 0x70 };
-    int actual;
-
-    qtest_outb(qts, cmos_base + 0, reg);
-    actual = qtest_inb(qts, cmos_base + 1);
-    g_assert(actual == expected);
-}
-
-static void test_cmos_bytes(QTestState *qts, int reg0, int n,
-                            uint8_t expected[])
-{
-    int i;
-
-    for (i = 0; i < 9; i++) {
-        test_cmos_byte(qts, reg0 + i, expected[i]);
-    }
-}
-
-static void test_cmos_disk_data(QTestState *qts)
-{
-    test_cmos_byte(qts, 0x12,
-                   (is_hd(cur_ide[0]) ? 0xf0 : 0) |
-                   (is_hd(cur_ide[1]) ? 0x0f : 0));
-}
-
-static void test_cmos_drive_cyl(QTestState *qts, int reg0,
-                                const CHST *expected_chst)
-{
-    if (is_hd(expected_chst)) {
-        int c = expected_chst->cyls;
-        int h = expected_chst->heads;
-        int s = expected_chst->secs;
-        uint8_t expected_bytes[9] = {
-            c & 0xff, c >> 8, h, 0xff, 0xff, 0xc0 | ((h > 8) << 3),
-            c & 0xff, c >> 8, s
-        };
-        test_cmos_bytes(qts, reg0, 9, expected_bytes);
-    } else {
-        int i;
-
-        for (i = 0; i < 9; i++) {
-            test_cmos_byte(qts, reg0 + i, 0);
-        }
-    }
-}
-
-static void test_cmos_drive1(QTestState *qts)
-{
-    test_cmos_byte(qts, 0x19, is_hd(cur_ide[0]) ? 47 : 0);
-    test_cmos_drive_cyl(qts, 0x1b, cur_ide[0]);
-}
-
-static void test_cmos_drive2(QTestState *qts)
-{
-    test_cmos_byte(qts, 0x1a, is_hd(cur_ide[1]) ? 47 : 0);
-    test_cmos_drive_cyl(qts, 0x24, cur_ide[1]);
-}
-
-static void test_cmos_disktransflag(QTestState *qts)
-{
-    int val, i;
-
-    val = 0;
-    for (i = 0; i < ARRAY_SIZE(cur_ide); i++) {
-        if (is_hd(cur_ide[i])) {
-            val |= cur_ide[i]->trans << (2 * i);
-        }
-    }
-    test_cmos_byte(qts, 0x39, val);
-}
-
-static void test_cmos(QTestState *qts)
-{
-    test_cmos_disk_data(qts);
-    test_cmos_drive1(qts);
-    test_cmos_drive2(qts);
-    test_cmos_disktransflag(qts);
-}
-
-static int append_arg(int argc, char *argv[], int argv_sz, char *arg)
-{
-    g_assert(argc + 1 < argv_sz);
-    argv[argc++] = arg;
-    argv[argc] = NULL;
-    return argc;
-}
-
-static int setup_common(char *argv[], int argv_sz)
-{
-    memset(cur_ide, 0, sizeof(cur_ide));
-    return append_arg(0, argv, argv_sz,
-                      g_strdup("-nodefaults"));
-}
-
-static void setup_mbr(int img_idx, MBRcontents mbr)
-{
-    static const uint8_t part_lba[16] = {
-        /* chs 0,1,1 (lba 63) to chs 0,127,63 (8001 sectors) */
-        0x80, 1, 1, 0, 6, 127, 63, 0, 63, 0, 0, 0, 0x41, 0x1F, 0, 0,
-    };
-    static const uint8_t part_chs[16] = {
-        /* chs 0,1,1 (lba 63) to chs 7,15,63 (8001 sectors) */
-        0x80, 1, 1, 0, 6,  15, 63, 7, 63, 0, 0, 0, 0x41, 0x1F, 0, 0,
-    };
-    uint8_t buf[512];
-    int fd, ret;
-
-    memset(buf, 0, sizeof(buf));
-
-    if (mbr != mbr_blank) {
-        buf[0x1fe] = 0x55;
-        buf[0x1ff] = 0xAA;
-        memcpy(buf + 0x1BE, mbr == mbr_lba ? part_lba : part_chs, 16);
-    }
-
-    fd = open(img_file_name[img_idx], O_WRONLY);
-    g_assert(fd >= 0);
-    ret = write(fd, buf, sizeof(buf));
-    g_assert(ret == sizeof(buf));
-    close(fd);
-}
-
-static int setup_ide(int argc, char *argv[], int argv_sz,
-                     int ide_idx, const char *dev, int img_idx,
-                     MBRcontents mbr)
-{
-    char *s1, *s2, *s3;
-
-    s1 = g_strdup_printf("-drive id=drive%d,if=%s",
-                         ide_idx, dev ? "none" : "ide");
-    s2 = dev ? g_strdup("") : g_strdup_printf(",index=%d", ide_idx);
-
-    if (img_secs[img_idx] >= 0) {
-        setup_mbr(img_idx, mbr);
-        s3 = g_strdup_printf(",format=raw,file=%s", img_file_name[img_idx]);
-    } else {
-        s3 = g_strdup(",media=cdrom");
-    }
-    argc = append_arg(argc, argv, argv_sz,
-                      g_strdup_printf("%s%s%s", s1, s2, s3));
-    g_free(s1);
-    g_free(s2);
-    g_free(s3);
-
-    if (dev) {
-        argc = append_arg(argc, argv, argv_sz,
-                          g_strdup_printf("-device %s,drive=drive%d,"
-                                          "bus=ide.%d,unit=%d",
-                                          dev, ide_idx,
-                                          ide_idx / 2, ide_idx % 2));
-    }
-    return argc;
-}
-
-/*
- * Test case: no IDE devices
- */
-static void test_ide_none(void)
-{
-    char **argv = g_new0(char *, ARGV_SIZE);
-    char *args;
-    QTestState *qts;
-
-    setup_common(argv, ARGV_SIZE);
-    args = g_strjoinv(" ", argv);
-    qts = qtest_init(args);
-    g_strfreev(argv);
-    g_free(args);
-    test_cmos(qts);
-    qtest_quit(qts);
-}
-
-static void test_ide_mbr(bool use_device, MBRcontents mbr)
-{
-    char **argv = g_new0(char *, ARGV_SIZE);
-    char *args;
-    int argc;
-    Backend i;
-    const char *dev;
-    QTestState *qts;
-
-    argc = setup_common(argv, ARGV_SIZE);
-    for (i = 0; i < backend_last; i++) {
-        cur_ide[i] = &hd_chst[i][mbr];
-        dev = use_device ? (is_hd(cur_ide[i]) ? "ide-hd" : "ide-cd") : NULL;
-        argc = setup_ide(argc, argv, ARGV_SIZE, i, dev, i, mbr);
-    }
-    args = g_strjoinv(" ", argv);
-    qts = qtest_init(args);
-    g_strfreev(argv);
-    g_free(args);
-    test_cmos(qts);
-    qtest_quit(qts);
-}
-
-/*
- * Test case: IDE devices (if=ide) with blank MBRs
- */
-static void test_ide_drive_mbr_blank(void)
-{
-    test_ide_mbr(false, mbr_blank);
-}
-
-/*
- * Test case: IDE devices (if=ide) with MBRs indicating LBA is in use
- */
-static void test_ide_drive_mbr_lba(void)
-{
-    test_ide_mbr(false, mbr_lba);
-}
-
-/*
- * Test case: IDE devices (if=ide) with MBRs indicating CHS is in use
- */
-static void test_ide_drive_mbr_chs(void)
-{
-    test_ide_mbr(false, mbr_chs);
-}
-
-/*
- * Test case: IDE devices (if=none) with blank MBRs
- */
-static void test_ide_device_mbr_blank(void)
-{
-    test_ide_mbr(true, mbr_blank);
-}
-
-/*
- * Test case: IDE devices (if=none) with MBRs indicating LBA is in use
- */
-static void test_ide_device_mbr_lba(void)
-{
-    test_ide_mbr(true, mbr_lba);
-}
-
-/*
- * Test case: IDE devices (if=none) with MBRs indicating CHS is in use
- */
-static void test_ide_device_mbr_chs(void)
-{
-    test_ide_mbr(true, mbr_chs);
-}
-
-static void test_ide_drive_user(const char *dev, bool trans)
-{
-    char **argv = g_new0(char *, ARGV_SIZE);
-    char *args, *opts;
-    int argc;
-    int secs = img_secs[backend_small];
-    const CHST expected_chst = { secs / (4 * 32) , 4, 32, trans };
-    QTestState *qts;
-
-    argc = setup_common(argv, ARGV_SIZE);
-    opts = g_strdup_printf("%s,%scyls=%d,heads=%d,secs=%d",
-                           dev, trans ? "bios-chs-trans=lba," : "",
-                           expected_chst.cyls, expected_chst.heads,
-                           expected_chst.secs);
-    cur_ide[0] = &expected_chst;
-    argc = setup_ide(argc, argv, ARGV_SIZE, 0, opts, backend_small, mbr_chs);
-    g_free(opts);
-    args = g_strjoinv(" ", argv);
-    qts = qtest_init(args);
-    g_strfreev(argv);
-    g_free(args);
-    test_cmos(qts);
-    qtest_quit(qts);
-}
-
-/*
- * Test case: IDE device (if=none) with explicit CHS
- */
-static void test_ide_device_user_chs(void)
-{
-    test_ide_drive_user("ide-hd", false);
-}
-
-/*
- * Test case: IDE device (if=none) with explicit CHS and translation
- */
-static void test_ide_device_user_chst(void)
-{
-    test_ide_drive_user("ide-hd", true);
-}
-
-/*
- * Test case: IDE devices (if=ide), but use index=0 for CD-ROM
- */
-static void test_ide_drive_cd_0(void)
-{
-    char **argv = g_new0(char *, ARGV_SIZE);
-    char *args;
-    int argc, ide_idx;
-    Backend i;
-    QTestState *qts;
-
-    argc = setup_common(argv, ARGV_SIZE);
-    for (i = 0; i <= backend_empty; i++) {
-        ide_idx = backend_empty - i;
-        cur_ide[ide_idx] = &hd_chst[i][mbr_blank];
-        argc = setup_ide(argc, argv, ARGV_SIZE, ide_idx, NULL, i, mbr_blank);
-    }
-    args = g_strjoinv(" ", argv);
-    qts = qtest_init(args);
-    g_strfreev(argv);
-    g_free(args);
-    test_cmos(qts);
-    qtest_quit(qts);
-}
-
-typedef struct {
-    bool active;
-    uint32_t head;
-    uint32_t sector;
-    uint32_t cyl;
-    uint32_t end_head;
-    uint32_t end_sector;
-    uint32_t end_cyl;
-    uint32_t start_sect;
-    uint32_t nr_sects;
-} MBRpartitions[4];
-
-static MBRpartitions empty_mbr = { {false, 0, 0, 0, 0, 0, 0, 0, 0},
-                                   {false, 0, 0, 0, 0, 0, 0, 0, 0},
-                                   {false, 0, 0, 0, 0, 0, 0, 0, 0},
-                                   {false, 0, 0, 0, 0, 0, 0, 0, 0} };
-
-static char *create_qcow2_with_mbr(MBRpartitions mbr, uint64_t sectors)
-{
-    const char *template = "/tmp/qtest.XXXXXX";
-    char *raw_path = strdup(template);
-    char *qcow2_path = strdup(template);
-    char cmd[100 + 2 * PATH_MAX];
-    uint8_t buf[512];
-    int i, ret, fd, offset;
-    uint64_t qcow2_size = sectors * 512;
-    uint8_t status, parttype, head, sector, cyl;
-    char *qemu_img_path;
-    char *qemu_img_abs_path;
-
-    offset = 0xbe;
-
-    for (i = 0; i < 4; i++) {
-        status = mbr[i].active ? 0x80 : 0x00;
-        g_assert(mbr[i].head < 256);
-        g_assert(mbr[i].sector < 64);
-        g_assert(mbr[i].cyl < 1024);
-        head = mbr[i].head;
-        sector = mbr[i].sector + ((mbr[i].cyl & 0x300) >> 2);
-        cyl = mbr[i].cyl & 0xff;
-
-        buf[offset + 0x0] = status;
-        buf[offset + 0x1] = head;
-        buf[offset + 0x2] = sector;
-        buf[offset + 0x3] = cyl;
-
-        parttype = 0;
-        g_assert(mbr[i].end_head < 256);
-        g_assert(mbr[i].end_sector < 64);
-        g_assert(mbr[i].end_cyl < 1024);
-        head = mbr[i].end_head;
-        sector = mbr[i].end_sector + ((mbr[i].end_cyl & 0x300) >> 2);
-        cyl = mbr[i].end_cyl & 0xff;
-
-        buf[offset + 0x4] = parttype;
-        buf[offset + 0x5] = head;
-        buf[offset + 0x6] = sector;
-        buf[offset + 0x7] = cyl;
-
-        (*(uint32_t *)&buf[offset + 0x8]) = cpu_to_le32(mbr[i].start_sect);
-        (*(uint32_t *)&buf[offset + 0xc]) = cpu_to_le32(mbr[i].nr_sects);
-
-        offset += 0x10;
-    }
-
-    fd = mkstemp(raw_path);
-    g_assert(fd);
-    close(fd);
-
-    fd = open(raw_path, O_WRONLY);
-    g_assert(fd >= 0);
-    ret = write(fd, buf, sizeof(buf));
-    g_assert(ret == sizeof(buf));
-    close(fd);
-
-    fd = mkstemp(qcow2_path);
-    g_assert(fd);
-    close(fd);
-
-    qemu_img_path = getenv("QTEST_QEMU_IMG");
-    g_assert(qemu_img_path);
-    qemu_img_abs_path = realpath(qemu_img_path, NULL);
-    g_assert(qemu_img_abs_path);
-
-    ret = snprintf(cmd, sizeof(cmd),
-                   "%s convert -f raw -O qcow2 %s %s > /dev/null",
-                   qemu_img_abs_path,
-                   raw_path, qcow2_path);
-    g_assert((0 < ret) && (ret <= sizeof(cmd)));
-    ret = system(cmd);
-    g_assert(ret == 0);
-
-    ret = snprintf(cmd, sizeof(cmd),
-                   "%s resize %s %" PRIu64 " > /dev/null",
-                   qemu_img_abs_path,
-                   qcow2_path, qcow2_size);
-    g_assert((0 < ret) && (ret <= sizeof(cmd)));
-    ret = system(cmd);
-    g_assert(ret == 0);
-
-    free(qemu_img_abs_path);
-
-    unlink(raw_path);
-    free(raw_path);
-
-    return qcow2_path;
-}
-
-#define BIOS_GEOMETRY_MAX_SIZE 10000
-
-typedef struct {
-    uint32_t c;
-    uint32_t h;
-    uint32_t s;
-} CHS;
-
-typedef struct {
-    const char *dev_path;
-    CHS chs;
-} CHSResult;
-
-static void read_bootdevices(QFWCFG *fw_cfg, CHSResult expected[])
-{
-    char *buf = g_malloc0(BIOS_GEOMETRY_MAX_SIZE);
-    char *cur;
-    GList *results = NULL, *cur_result;
-    CHSResult *r;
-    int i;
-    int res;
-    bool found;
-
-    qfw_cfg_get_file(fw_cfg, "bios-geometry", buf, BIOS_GEOMETRY_MAX_SIZE);
-
-    for (cur = buf; *cur; cur++) {
-        if (*cur == '\n') {
-            *cur = '\0';
-        }
-    }
-    cur = buf;
-
-    while (strlen(cur)) {
-
-        r = g_malloc0(sizeof(*r));
-        r->dev_path = g_malloc0(strlen(cur) + 1);
-        res = sscanf(cur, "%s %" PRIu32 " %" PRIu32 " %" PRIu32,
-                     (char *)r->dev_path,
-                     &(r->chs.c), &(r->chs.h), &(r->chs.s));
-
-        g_assert(res == 4);
-
-        results = g_list_prepend(results, r);
-
-        cur += strlen(cur) + 1;
-    }
-
-    i = 0;
-
-    while (expected[i].dev_path) {
-        found = false;
-        cur_result = results;
-        while (cur_result) {
-            r = cur_result->data;
-            if (!strcmp(r->dev_path, expected[i].dev_path) &&
-                !memcmp(&(r->chs), &(expected[i].chs), sizeof(r->chs))) {
-                found = true;
-                break;
-            }
-            cur_result = g_list_next(cur_result);
-        }
-        g_assert(found);
-        g_free((char *)((CHSResult *)cur_result->data)->dev_path);
-        g_free(cur_result->data);
-        results = g_list_delete_link(results, cur_result);
-        i++;
-    }
-
-    g_assert(results == NULL);
-
-    g_free(buf);
-}
-
-#define MAX_DRIVES 30
-
-typedef struct {
-    char **argv;
-    int argc;
-    char **drives;
-    int n_drives;
-    int n_scsi_disks;
-    int n_scsi_controllers;
-    int n_virtio_disks;
-} TestArgs;
-
-static TestArgs *create_args(void)
-{
-    TestArgs *args = g_malloc0(sizeof(*args));
-    args->argv = g_new0(char *, ARGV_SIZE);
-    args->argc = append_arg(args->argc, args->argv,
-                            ARGV_SIZE, g_strdup("-nodefaults"));
-    args->drives = g_new0(char *, MAX_DRIVES);
-    return args;
-}
-
-static void add_drive_with_mbr(TestArgs *args,
-                               MBRpartitions mbr, uint64_t sectors)
-{
-    char *img_file_name;
-    char part[300];
-    int ret;
-
-    g_assert(args->n_drives < MAX_DRIVES);
-
-    img_file_name = create_qcow2_with_mbr(mbr, sectors);
-
-    args->drives[args->n_drives] = img_file_name;
-    ret = snprintf(part, sizeof(part),
-                   "-drive file=%s,if=none,format=qcow2,id=disk%d",
-                   img_file_name, args->n_drives);
-    g_assert((0 < ret) && (ret <= sizeof(part)));
-    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
-    args->n_drives++;
-}
-
-static void add_ide_disk(TestArgs *args,
-                         int drive_idx, int bus, int unit, int c, int h, int s)
-{
-    char part[300];
-    int ret;
-
-    ret = snprintf(part, sizeof(part),
-                   "-device ide-hd,drive=disk%d,bus=ide.%d,unit=%d,"
-                   "lcyls=%d,lheads=%d,lsecs=%d",
-                   drive_idx, bus, unit, c, h, s);
-    g_assert((0 < ret) && (ret <= sizeof(part)));
-    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
-}
-
-static void add_scsi_controller(TestArgs *args,
-                                const char *type,
-                                const char *bus,
-                                int addr)
-{
-    char part[300];
-    int ret;
-
-    ret = snprintf(part, sizeof(part),
-                   "-device %s,id=scsi%d,bus=%s,addr=%d",
-                   type, args->n_scsi_controllers, bus, addr);
-    g_assert((0 < ret) && (ret <= sizeof(part)));
-    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
-    args->n_scsi_controllers++;
-}
-
-static void add_scsi_disk(TestArgs *args,
-                          int drive_idx, int bus,
-                          int channel, int scsi_id, int lun,
-                          int c, int h, int s)
-{
-    char part[300];
-    int ret;
-
-    ret = snprintf(part, sizeof(part),
-                   "-device scsi-hd,id=scsi-disk%d,drive=disk%d,"
-                   "bus=scsi%d.0,"
-                   "channel=%d,scsi-id=%d,lun=%d,"
-                   "lcyls=%d,lheads=%d,lsecs=%d",
-                   args->n_scsi_disks, drive_idx, bus, channel, scsi_id, lun,
-                   c, h, s);
-    g_assert((0 < ret) && (ret <= sizeof(part)));
-    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
-    args->n_scsi_disks++;
-}
-
-static void add_virtio_disk(TestArgs *args,
-                            int drive_idx, const char *bus, int addr,
-                            int c, int h, int s)
-{
-    char part[300];
-    int ret;
-
-    ret = snprintf(part, sizeof(part),
-                   "-device virtio-blk-pci,id=virtio-disk%d,"
-                   "drive=disk%d,bus=%s,addr=%d,"
-                   "lcyls=%d,lheads=%d,lsecs=%d",
-                   args->n_virtio_disks, drive_idx, bus, addr, c, h, s);
-    g_assert((0 < ret) && (ret <= sizeof(part)));
-    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
-    args->n_virtio_disks++;
-}
-
-static void test_override(TestArgs *args, CHSResult expected[])
-{
-    QTestState *qts;
-    char *joined_args;
-    QFWCFG *fw_cfg;
-    int i;
-
-    joined_args = g_strjoinv(" ", args->argv);
-
-    qts = qtest_init(joined_args);
-    fw_cfg = pc_fw_cfg_init(qts);
-
-    read_bootdevices(fw_cfg, expected);
-
-    g_free(joined_args);
-    qtest_quit(qts);
-
-    g_free(fw_cfg);
-
-    for (i = 0; i < args->n_drives; i++) {
-        unlink(args->drives[i]);
-        free(args->drives[i]);
-    }
-    g_free(args->drives);
-    g_strfreev(args->argv);
-    g_free(args);
-}
-
-static void test_override_ide(void)
-{
-    TestArgs *args = create_args();
-    CHSResult expected[] = {
-        {"/pci@i0cf8/ide@1,1/drive@0/disk@0", {10000, 120, 30} },
-        {"/pci@i0cf8/ide@1,1/drive@0/disk@1", {9000, 120, 30} },
-        {"/pci@i0cf8/ide@1,1/drive@1/disk@0", {0, 1, 1} },
-        {"/pci@i0cf8/ide@1,1/drive@1/disk@1", {1, 0, 0} },
-        {NULL, {0, 0, 0} }
-    };
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_ide_disk(args, 0, 0, 0, 10000, 120, 30);
-    add_ide_disk(args, 1, 0, 1, 9000, 120, 30);
-    add_ide_disk(args, 2, 1, 0, 0, 1, 1);
-    add_ide_disk(args, 3, 1, 1, 1, 0, 0);
-    test_override(args, expected);
-}
-
-static void test_override_scsi(void)
-{
-    TestArgs *args = create_args();
-    CHSResult expected[] = {
-        {"/pci@i0cf8/scsi@3/channel@0/disk@0,0", {10000, 120, 30} },
-        {"/pci@i0cf8/scsi@3/channel@0/disk@1,0", {9000, 120, 30} },
-        {"/pci@i0cf8/scsi@3/channel@0/disk@2,0", {1, 0, 0} },
-        {"/pci@i0cf8/scsi@3/channel@0/disk@3,0", {0, 1, 0} },
-        {NULL, {0, 0, 0} }
-    };
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_scsi_controller(args, "lsi53c895a", "pci.0", 3);
-    add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
-    add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30);
-    add_scsi_disk(args, 2, 0, 0, 2, 0, 1, 0, 0);
-    add_scsi_disk(args, 3, 0, 0, 3, 0, 0, 1, 0);
-    test_override(args, expected);
-}
-
-static void test_override_scsi_2_controllers(void)
-{
-    TestArgs *args = create_args();
-    CHSResult expected[] = {
-        {"/pci@i0cf8/scsi@3/channel@0/disk@0,0", {10000, 120, 30} },
-        {"/pci@i0cf8/scsi@3/channel@0/disk@1,0", {9000, 120, 30} },
-        {"/pci@i0cf8/scsi@4/channel@0/disk@0,1", {1, 0, 0} },
-        {"/pci@i0cf8/scsi@4/channel@0/disk@1,2", {0, 1, 0} },
-        {NULL, {0, 0, 0} }
-    };
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_scsi_controller(args, "lsi53c895a", "pci.0", 3);
-    add_scsi_controller(args, "virtio-scsi-pci", "pci.0", 4);
-    add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
-    add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30);
-    add_scsi_disk(args, 2, 1, 0, 0, 1, 1, 0, 0);
-    add_scsi_disk(args, 3, 1, 0, 1, 2, 0, 1, 0);
-    test_override(args, expected);
-}
-
-static void test_override_virtio_blk(void)
-{
-    TestArgs *args = create_args();
-    CHSResult expected[] = {
-        {"/pci@i0cf8/scsi@3/disk@0,0", {10000, 120, 30} },
-        {"/pci@i0cf8/scsi@4/disk@0,0", {9000, 120, 30} },
-        {NULL, {0, 0, 0} }
-    };
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_virtio_disk(args, 0, "pci.0", 3, 10000, 120, 30);
-    add_virtio_disk(args, 1, "pci.0", 4, 9000, 120, 30);
-    test_override(args, expected);
-}
-
-static void test_override_zero_chs(void)
-{
-    TestArgs *args = create_args();
-    CHSResult expected[] = {
-        {NULL, {0, 0, 0} }
-    };
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_ide_disk(args, 0, 1, 1, 0, 0, 0);
-    test_override(args, expected);
-}
-
-static void test_override_scsi_hot_unplug(void)
-{
-    QTestState *qts;
-    char *joined_args;
-    QFWCFG *fw_cfg;
-    QDict *response;
-    int i;
-    TestArgs *args = create_args();
-    CHSResult expected[] = {
-        {"/pci@i0cf8/scsi@2/channel@0/disk@0,0", {10000, 120, 30} },
-        {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} },
-        {NULL, {0, 0, 0} }
-    };
-    CHSResult expected2[] = {
-        {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} },
-        {NULL, {0, 0, 0} }
-    };
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_scsi_controller(args, "virtio-scsi-pci", "pci.0", 2);
-    add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
-    add_scsi_disk(args, 1, 0, 0, 1, 0, 20, 20, 20);
-
-    joined_args = g_strjoinv(" ", args->argv);
-
-    qts = qtest_init(joined_args);
-    fw_cfg = pc_fw_cfg_init(qts);
-
-    read_bootdevices(fw_cfg, expected);
-
-    /* unplug device an restart */
-    response = qtest_qmp(qts,
-                         "{ 'execute': 'device_del',"
-                         "  'arguments': {'id': 'scsi-disk0' }}");
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-    response = qtest_qmp(qts,
-                         "{ 'execute': 'system_reset', 'arguments': { }}");
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-
-    qtest_qmp_eventwait(qts, "RESET");
-
-    read_bootdevices(fw_cfg, expected2);
-
-    g_free(joined_args);
-    qtest_quit(qts);
-
-    g_free(fw_cfg);
-
-    for (i = 0; i < args->n_drives; i++) {
-        unlink(args->drives[i]);
-        free(args->drives[i]);
-    }
-    g_free(args->drives);
-    g_strfreev(args->argv);
-    g_free(args);
-}
-
-static void test_override_virtio_hot_unplug(void)
-{
-    QTestState *qts;
-    char *joined_args;
-    QFWCFG *fw_cfg;
-    QDict *response;
-    int i;
-    TestArgs *args = create_args();
-    CHSResult expected[] = {
-        {"/pci@i0cf8/scsi@2/disk@0,0", {10000, 120, 30} },
-        {"/pci@i0cf8/scsi@3/disk@0,0", {20, 20, 20} },
-        {NULL, {0, 0, 0} }
-    };
-    CHSResult expected2[] = {
-        {"/pci@i0cf8/scsi@3/disk@0,0", {20, 20, 20} },
-        {NULL, {0, 0, 0} }
-    };
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_drive_with_mbr(args, empty_mbr, 1);
-    add_virtio_disk(args, 0, "pci.0", 2, 10000, 120, 30);
-    add_virtio_disk(args, 1, "pci.0", 3, 20, 20, 20);
-
-    joined_args = g_strjoinv(" ", args->argv);
-
-    qts = qtest_init(joined_args);
-    fw_cfg = pc_fw_cfg_init(qts);
-
-    read_bootdevices(fw_cfg, expected);
-
-    /* unplug device an restart */
-    response = qtest_qmp(qts,
-                         "{ 'execute': 'device_del',"
-                         "  'arguments': {'id': 'virtio-disk0' }}");
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-    response = qtest_qmp(qts,
-                         "{ 'execute': 'system_reset', 'arguments': { }}");
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-
-    qtest_qmp_eventwait(qts, "RESET");
-
-    read_bootdevices(fw_cfg, expected2);
-
-    g_free(joined_args);
-    qtest_quit(qts);
-
-    g_free(fw_cfg);
-
-    for (i = 0; i < args->n_drives; i++) {
-        unlink(args->drives[i]);
-        free(args->drives[i]);
-    }
-    g_free(args->drives);
-    g_strfreev(args->argv);
-    g_free(args);
-}
-
-int main(int argc, char **argv)
-{
-    Backend i;
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-
-    for (i = 0; i < backend_last; i++) {
-        if (img_secs[i] >= 0) {
-            img_file_name[i] = create_test_img(img_secs[i]);
-            if (!img_file_name[i]) {
-                g_test_message("Could not create test images.");
-                goto test_add_done;
-            }
-        } else {
-            img_file_name[i] = NULL;
-        }
-    }
-
-    qtest_add_func("hd-geo/ide/none", test_ide_none);
-    qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank);
-    qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba);
-    qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs);
-    qtest_add_func("hd-geo/ide/drive/cd_0", test_ide_drive_cd_0);
-    qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank);
-    qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba);
-    qtest_add_func("hd-geo/ide/device/mbr/chs", test_ide_device_mbr_chs);
-    qtest_add_func("hd-geo/ide/device/user/chs", test_ide_device_user_chs);
-    qtest_add_func("hd-geo/ide/device/user/chst", test_ide_device_user_chst);
-    if (have_qemu_img()) {
-        qtest_add_func("hd-geo/override/ide", test_override_ide);
-        qtest_add_func("hd-geo/override/scsi", test_override_scsi);
-        qtest_add_func("hd-geo/override/scsi_2_controllers",
-                       test_override_scsi_2_controllers);
-        qtest_add_func("hd-geo/override/virtio_blk", test_override_virtio_blk);
-        qtest_add_func("hd-geo/override/zero_chs", test_override_zero_chs);
-        qtest_add_func("hd-geo/override/scsi_hot_unplug",
-                       test_override_scsi_hot_unplug);
-        qtest_add_func("hd-geo/override/virtio_hot_unplug",
-                       test_override_virtio_hot_unplug);
-    } else {
-        g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
-                       "skipping hd-geo/override/* tests");
-    }
-
-test_add_done:
-    ret = g_test_run();
-
-    for (i = 0; i < backend_last; i++) {
-        if (img_file_name[i]) {
-            unlink(img_file_name[i]);
-            free(img_file_name[i]);
-        }
-    }
-
-    return ret;
-}
diff --git a/tests/hexloader-test.c b/tests/hexloader-test.c
deleted file mode 100644 (file)
index 8b7aa2d..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * QTest testcase for the Intel Hexadecimal Object File Loader
- *
- * Authors:
- *  Su Hang <[email protected]> 2018
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-
-/* Load 'test.hex' and verify that the in-memory contents are as expected.
- * 'test.hex' is a memory test pattern stored in Hexadecimal Object
- * format.  It loads at 0x10000 in RAM and contains values from 0 through
- * 255.
- */
-static void hex_loader_test(void)
-{
-    unsigned int i;
-    const unsigned int base_addr = 0x00010000;
-
-    QTestState *s = qtest_initf(
-        "-M vexpress-a9 -device loader,file=tests/data/hex-loader/test.hex");
-
-    for (i = 0; i < 256; ++i) {
-        uint8_t val = qtest_readb(s, base_addr + i);
-        g_assert_cmpuint(i, ==, val);
-    }
-    qtest_quit(s);
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("/tmp/hex_loader", hex_loader_test);
-    ret = g_test_run();
-
-    return ret;
-}
diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c
deleted file mode 100644 (file)
index 1f57d96..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * qtest I440FX test case
- *
- * Copyright IBM, Corp. 2012-2013
- * Copyright Red Hat, Inc. 2013
- *
- * Authors:
- *  Anthony Liguori   <[email protected]>
- *  Laszlo Ersek      <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-
-#include "libqtest-single.h"
-#include "libqos/pci.h"
-#include "libqos/pci-pc.h"
-#include "hw/pci/pci_regs.h"
-
-#define BROKEN 1
-
-typedef struct TestData
-{
-    int num_cpus;
-} TestData;
-
-typedef struct FirmwareTestFixture {
-    /* decides whether we're testing -bios or -pflash */
-    bool is_bios;
-} FirmwareTestFixture;
-
-static QPCIBus *test_start_get_bus(const TestData *s)
-{
-    char *cmdline;
-
-    cmdline = g_strdup_printf("-smp %d", s->num_cpus);
-    qtest_start(cmdline);
-    g_free(cmdline);
-    return qpci_new_pc(global_qtest, NULL);
-}
-
-static void test_i440fx_defaults(gconstpointer opaque)
-{
-    const TestData *s = opaque;
-    QPCIBus *bus;
-    QPCIDevice *dev;
-    uint32_t value;
-
-    bus = test_start_get_bus(s);
-    dev = qpci_device_find(bus, QPCI_DEVFN(0, 0));
-    g_assert(dev != NULL);
-
-    /* 3.2.2 */
-    g_assert_cmpint(qpci_config_readw(dev, PCI_VENDOR_ID), ==, 0x8086);
-    /* 3.2.3 */
-    g_assert_cmpint(qpci_config_readw(dev, PCI_DEVICE_ID), ==, 0x1237);
-#ifndef BROKEN
-    /* 3.2.4 */
-    g_assert_cmpint(qpci_config_readw(dev, PCI_COMMAND), ==, 0x0006);
-    /* 3.2.5 */
-    g_assert_cmpint(qpci_config_readw(dev, PCI_STATUS), ==, 0x0280);
-#endif
-    /* 3.2.7 */
-    g_assert_cmpint(qpci_config_readb(dev, PCI_CLASS_PROG), ==, 0x00);
-    g_assert_cmpint(qpci_config_readw(dev, PCI_CLASS_DEVICE), ==, 0x0600);
-    /* 3.2.8 */
-    g_assert_cmpint(qpci_config_readb(dev, PCI_LATENCY_TIMER), ==, 0x00);
-    /* 3.2.9 */
-    g_assert_cmpint(qpci_config_readb(dev, PCI_HEADER_TYPE), ==, 0x00);
-    /* 3.2.10 */
-    g_assert_cmpint(qpci_config_readb(dev, PCI_BIST), ==, 0x00);
-
-    /* 3.2.11 */
-    value = qpci_config_readw(dev, 0x50); /* PMCCFG */
-    if (s->num_cpus == 1) { /* WPE */
-        g_assert(!(value & (1 << 15)));
-    } else {
-        g_assert((value & (1 << 15)));
-    }
-
-    g_assert(!(value & (1 << 6))); /* EPTE */
-
-    /* 3.2.12 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x52), ==, 0x00); /* DETURBO */
-    /* 3.2.13 */
-#ifndef BROKEN
-    g_assert_cmpint(qpci_config_readb(dev, 0x53), ==, 0x80); /* DBC */
-#endif
-    /* 3.2.14 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x54), ==, 0x00); /* AXC */
-    /* 3.2.15 */
-    g_assert_cmpint(qpci_config_readw(dev, 0x55), ==, 0x0000); /* DRT */
-#ifndef BROKEN
-    /* 3.2.16 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x57), ==, 0x01); /* DRAMC */
-    /* 3.2.17 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x58), ==, 0x10); /* DRAMT */
-#endif
-    /* 3.2.18 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x59), ==, 0x00); /* PAM0 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x5A), ==, 0x00); /* PAM1 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x5B), ==, 0x00); /* PAM2 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x5C), ==, 0x00); /* PAM3 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x5D), ==, 0x00); /* PAM4 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x5E), ==, 0x00); /* PAM5 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x5F), ==, 0x00); /* PAM6 */
-#ifndef BROKEN
-    /* 3.2.19 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x60), ==, 0x01); /* DRB0 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x61), ==, 0x01); /* DRB1 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x62), ==, 0x01); /* DRB2 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x63), ==, 0x01); /* DRB3 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x64), ==, 0x01); /* DRB4 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x65), ==, 0x01); /* DRB5 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x66), ==, 0x01); /* DRB6 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x67), ==, 0x01); /* DRB7 */
-#endif
-    /* 3.2.20 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x68), ==, 0x00); /* FDHC */
-    /* 3.2.21 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x70), ==, 0x00); /* MTT */
-#ifndef BROKEN
-    /* 3.2.22 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x71), ==, 0x10); /* CLT */
-#endif
-    /* 3.2.23 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x72), ==, 0x02); /* SMRAM */
-    /* 3.2.24 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x90), ==, 0x00); /* ERRCMD */
-    /* 3.2.25 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x91), ==, 0x00); /* ERRSTS */
-    /* 3.2.26 */
-    g_assert_cmpint(qpci_config_readb(dev, 0x93), ==, 0x00); /* TRC */
-
-    g_free(dev);
-    qpci_free_pc(bus);
-    qtest_end();
-}
-
-#define PAM_RE 1
-#define PAM_WE 2
-
-static void pam_set(QPCIDevice *dev, int index, int flags)
-{
-    int regno = 0x59 + (index / 2);
-    uint8_t reg;
-
-    reg = qpci_config_readb(dev, regno);
-    if (index & 1) {
-        reg = (reg & 0x0F) | (flags << 4);
-    } else {
-        reg = (reg & 0xF0) | flags;
-    }
-    qpci_config_writeb(dev, regno, reg);
-}
-
-static gboolean verify_area(uint32_t start, uint32_t end, uint8_t value)
-{
-    uint32_t size = end - start + 1;
-    gboolean ret = TRUE;
-    uint8_t *data;
-    int i;
-
-    data = g_malloc0(size);
-    memread(start, data, size);
-
-    g_test_message("verify_area: data[0] = 0x%x", data[0]);
-
-    for (i = 0; i < size; i++) {
-        if (data[i] != value) {
-            ret = FALSE;
-            break;
-        }
-    }
-
-    g_free(data);
-
-    return ret;
-}
-
-static void write_area(uint32_t start, uint32_t end, uint8_t value)
-{
-    uint32_t size = end - start + 1;
-    uint8_t *data;
-
-    data = g_malloc(size);
-    memset(data, value, size);
-    memwrite(start, data, size);
-
-    g_free(data);
-}
-
-static void test_i440fx_pam(gconstpointer opaque)
-{
-    const TestData *s = opaque;
-    QPCIBus *bus;
-    QPCIDevice *dev;
-    int i;
-    static struct {
-        uint32_t start;
-        uint32_t end;
-    } pam_area[] = {
-        { 0, 0 },             /* Reserved */
-        { 0xF0000, 0xFFFFF }, /* BIOS Area */
-        { 0xC0000, 0xC3FFF }, /* Option ROM */
-        { 0xC4000, 0xC7FFF }, /* Option ROM */
-        { 0xC8000, 0xCBFFF }, /* Option ROM */
-        { 0xCC000, 0xCFFFF }, /* Option ROM */
-        { 0xD0000, 0xD3FFF }, /* Option ROM */
-        { 0xD4000, 0xD7FFF }, /* Option ROM */
-        { 0xD8000, 0xDBFFF }, /* Option ROM */
-        { 0xDC000, 0xDFFFF }, /* Option ROM */
-        { 0xE0000, 0xE3FFF }, /* BIOS Extension */
-        { 0xE4000, 0xE7FFF }, /* BIOS Extension */
-        { 0xE8000, 0xEBFFF }, /* BIOS Extension */
-        { 0xEC000, 0xEFFFF }, /* BIOS Extension */
-    };
-
-    bus = test_start_get_bus(s);
-    dev = qpci_device_find(bus, QPCI_DEVFN(0, 0));
-    g_assert(dev != NULL);
-
-    for (i = 0; i < ARRAY_SIZE(pam_area); i++) {
-        if (pam_area[i].start == pam_area[i].end) {
-            continue;
-        }
-
-        g_test_message("Checking area 0x%05x..0x%05x",
-                       pam_area[i].start, pam_area[i].end);
-        /* Switch to RE for the area */
-        pam_set(dev, i, PAM_RE);
-        /* Verify the RAM is all zeros */
-        g_assert(verify_area(pam_area[i].start, pam_area[i].end, 0));
-
-        /* Switch to WE for the area */
-        pam_set(dev, i, PAM_RE | PAM_WE);
-        /* Write out a non-zero mask to the full area */
-        write_area(pam_area[i].start, pam_area[i].end, 0x42);
-
-#ifndef BROKEN
-        /* QEMU only supports a limited form of PAM */
-
-        /* Switch to !RE for the area */
-        pam_set(dev, i, PAM_WE);
-        /* Verify the area is not our mask */
-        g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x42));
-#endif
-
-        /* Verify the area is our new mask */
-        g_assert(verify_area(pam_area[i].start, pam_area[i].end, 0x42));
-
-        /* Write out a new mask */
-        write_area(pam_area[i].start, pam_area[i].end, 0x82);
-
-#ifndef BROKEN
-        /* QEMU only supports a limited form of PAM */
-
-        /* Verify the area is not our mask */
-        g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x82));
-
-        /* Switch to RE for the area */
-        pam_set(dev, i, PAM_RE | PAM_WE);
-#endif
-        /* Verify the area is our new mask */
-        g_assert(verify_area(pam_area[i].start, pam_area[i].end, 0x82));
-
-        /* Reset area */
-        pam_set(dev, i, 0);
-
-        /* Verify the area is not our new mask */
-        g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x82));
-    }
-
-    g_free(dev);
-    qpci_free_pc(bus);
-    qtest_end();
-}
-
-#define BLOB_SIZE ((size_t)65536)
-#define ISA_BIOS_MAXSZ ((size_t)(128 * 1024))
-
-/* Create a blob file, and return its absolute pathname as a dynamically
- * allocated string.
- * The file is closed before the function returns.
- * In case of error, NULL is returned. The function prints the error message.
- */
-static char *create_blob_file(void)
-{
-    int ret, fd;
-    char *pathname;
-    GError *error = NULL;
-
-    ret = -1;
-    fd = g_file_open_tmp("blob_XXXXXX", &pathname, &error);
-    if (fd == -1) {
-        fprintf(stderr, "unable to create blob file: %s\n", error->message);
-        g_error_free(error);
-    } else {
-        if (ftruncate(fd, BLOB_SIZE) == -1) {
-            fprintf(stderr, "ftruncate(\"%s\", %zu): %s\n", pathname,
-                    BLOB_SIZE, strerror(errno));
-        } else {
-            void *buf;
-
-            buf = mmap(NULL, BLOB_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
-            if (buf == MAP_FAILED) {
-                fprintf(stderr, "mmap(\"%s\", %zu): %s\n", pathname, BLOB_SIZE,
-                        strerror(errno));
-            } else {
-                size_t i;
-
-                for (i = 0; i < BLOB_SIZE; ++i) {
-                    ((uint8_t *)buf)[i] = i;
-                }
-                munmap(buf, BLOB_SIZE);
-                ret = 0;
-            }
-        }
-        close(fd);
-        if (ret == -1) {
-            unlink(pathname);
-            g_free(pathname);
-        }
-    }
-
-    return ret == -1 ? NULL : pathname;
-}
-
-static void test_i440fx_firmware(FirmwareTestFixture *fixture,
-                                 gconstpointer user_data)
-{
-    char *fw_pathname, *cmdline;
-    uint8_t *buf;
-    size_t i, isa_bios_size;
-
-    fw_pathname = create_blob_file();
-    g_assert(fw_pathname != NULL);
-
-    /* Better hope the user didn't put metacharacters in TMPDIR and co. */
-    cmdline = g_strdup_printf("-S %s%s", fixture->is_bios
-                                         ? "-bios "
-                                         : "-drive if=pflash,format=raw,file=",
-                              fw_pathname);
-    g_test_message("qemu cmdline: %s", cmdline);
-    qtest_start(cmdline);
-    g_free(cmdline);
-
-    /* QEMU has loaded the firmware (because qtest_start() only returns after
-     * the QMP handshake completes). We must unlink the firmware blob right
-     * here, because any assertion firing below would leak it in the
-     * filesystem. This is also the reason why we recreate the blob every time
-     * this function is invoked.
-     */
-    unlink(fw_pathname);
-    g_free(fw_pathname);
-
-    /* check below 4G */
-    buf = g_malloc0(BLOB_SIZE);
-    memread(0x100000000ULL - BLOB_SIZE, buf, BLOB_SIZE);
-    for (i = 0; i < BLOB_SIZE; ++i) {
-        g_assert_cmphex(buf[i], ==, (uint8_t)i);
-    }
-
-    /* check in ISA space too */
-    memset(buf, 0, BLOB_SIZE);
-    isa_bios_size = ISA_BIOS_MAXSZ < BLOB_SIZE ? ISA_BIOS_MAXSZ : BLOB_SIZE;
-    memread(0x100000 - isa_bios_size, buf, isa_bios_size);
-    for (i = 0; i < isa_bios_size; ++i) {
-        g_assert_cmphex(buf[i], ==,
-                        (uint8_t)((BLOB_SIZE - isa_bios_size) + i));
-    }
-
-    g_free(buf);
-    qtest_end();
-}
-
-static void add_firmware_test(const char *testpath,
-                              void (*setup_fixture)(FirmwareTestFixture *f,
-                                                    gconstpointer test_data))
-{
-    qtest_add(testpath, FirmwareTestFixture, NULL, setup_fixture,
-              test_i440fx_firmware, NULL);
-}
-
-static void request_bios(FirmwareTestFixture *fixture,
-                         gconstpointer user_data)
-{
-    fixture->is_bios = true;
-}
-
-static void request_pflash(FirmwareTestFixture *fixture,
-                           gconstpointer user_data)
-{
-    fixture->is_bios = false;
-}
-
-int main(int argc, char **argv)
-{
-    TestData data;
-
-    g_test_init(&argc, &argv, NULL);
-
-    data.num_cpus = 1;
-
-    qtest_add_data_func("i440fx/defaults", &data, test_i440fx_defaults);
-    qtest_add_data_func("i440fx/pam", &data, test_i440fx_pam);
-    add_firmware_test("i440fx/firmware/bios", request_bios);
-    add_firmware_test("i440fx/firmware/pflash", request_pflash);
-
-    return g_test_run();
-}
diff --git a/tests/i82801b11-test.c b/tests/i82801b11-test.c
deleted file mode 100644 (file)
index 4345da3..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * QTest testcase for i82801b11
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void nop(void)
-{
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/i82801b11/nop", nop);
-
-    qtest_start("-machine q35 -device i82801b11-bridge,bus=pcie.0,addr=1e.0");
-    ret = g_test_run();
-
-    qtest_end();
-
-    return ret;
-}
diff --git a/tests/ide-test.c b/tests/ide-test.c
deleted file mode 100644 (file)
index 0277e7d..0000000
+++ /dev/null
@@ -1,1092 +0,0 @@
-/*
- * IDE test cases
- *
- * Copyright (c) 2013 Kevin Wolf <[email protected]>
- *
- * 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 "libqtest.h"
-#include "libqos/libqos.h"
-#include "libqos/pci-pc.h"
-#include "libqos/malloc-pc.h"
-#include "qapi/qmp/qdict.h"
-#include "qemu-common.h"
-#include "qemu/bswap.h"
-#include "hw/pci/pci_ids.h"
-#include "hw/pci/pci_regs.h"
-
-/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(q, ...) qobject_unref(qtest_qmp(q, __VA_ARGS__))
-
-#define TEST_IMAGE_SIZE 64 * 1024 * 1024
-
-#define IDE_PCI_DEV     1
-#define IDE_PCI_FUNC    1
-
-#define IDE_BASE 0x1f0
-#define IDE_PRIMARY_IRQ 14
-
-#define ATAPI_BLOCK_SIZE 2048
-
-/* How many bytes to receive via ATAPI PIO at one time.
- * Must be less than 0xFFFF. */
-#define BYTE_COUNT_LIMIT 5120
-
-enum {
-    reg_data        = 0x0,
-    reg_feature     = 0x1,
-    reg_error       = 0x1,
-    reg_nsectors    = 0x2,
-    reg_lba_low     = 0x3,
-    reg_lba_middle  = 0x4,
-    reg_lba_high    = 0x5,
-    reg_device      = 0x6,
-    reg_status      = 0x7,
-    reg_command     = 0x7,
-};
-
-enum {
-    BSY     = 0x80,
-    DRDY    = 0x40,
-    DF      = 0x20,
-    DRQ     = 0x08,
-    ERR     = 0x01,
-};
-
-/* Error field */
-enum {
-    ABRT    = 0x04,
-};
-
-enum {
-    DEV     = 0x10,
-    LBA     = 0x40,
-};
-
-enum {
-    bmreg_cmd       = 0x0,
-    bmreg_status    = 0x2,
-    bmreg_prdt      = 0x4,
-};
-
-enum {
-    CMD_DSM         = 0x06,
-    CMD_READ_DMA    = 0xc8,
-    CMD_WRITE_DMA   = 0xca,
-    CMD_FLUSH_CACHE = 0xe7,
-    CMD_IDENTIFY    = 0xec,
-    CMD_PACKET      = 0xa0,
-
-    CMDF_ABORT      = 0x100,
-    CMDF_NO_BM      = 0x200,
-};
-
-enum {
-    BM_CMD_START    =  0x1,
-    BM_CMD_WRITE    =  0x8, /* write = from device to memory */
-};
-
-enum {
-    BM_STS_ACTIVE   =  0x1,
-    BM_STS_ERROR    =  0x2,
-    BM_STS_INTR     =  0x4,
-};
-
-enum {
-    PRDT_EOT        = 0x80000000,
-};
-
-#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
-#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
-
-static QPCIBus *pcibus = NULL;
-static QGuestAllocator guest_malloc;
-
-static char tmp_path[] = "/tmp/qtest.XXXXXX";
-static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX";
-
-static QTestState *ide_test_start(const char *cmdline_fmt, ...)
-{
-    QTestState *qts;
-    va_list ap;
-
-    va_start(ap, cmdline_fmt);
-    qts = qtest_vinitf(cmdline_fmt, ap);
-    va_end(ap);
-
-    pc_alloc_init(&guest_malloc, qts, 0);
-
-    return qts;
-}
-
-static void ide_test_quit(QTestState *qts)
-{
-    if (pcibus) {
-        qpci_free_pc(pcibus);
-        pcibus = NULL;
-    }
-    alloc_destroy(&guest_malloc);
-    qtest_quit(qts);
-}
-
-static QPCIDevice *get_pci_device(QTestState *qts, QPCIBar *bmdma_bar,
-                                  QPCIBar *ide_bar)
-{
-    QPCIDevice *dev;
-    uint16_t vendor_id, device_id;
-
-    if (!pcibus) {
-        pcibus = qpci_new_pc(qts, NULL);
-    }
-
-    /* Find PCI device and verify it's the right one */
-    dev = qpci_device_find(pcibus, QPCI_DEVFN(IDE_PCI_DEV, IDE_PCI_FUNC));
-    g_assert(dev != NULL);
-
-    vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);
-    device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
-    g_assert(vendor_id == PCI_VENDOR_ID_INTEL);
-    g_assert(device_id == PCI_DEVICE_ID_INTEL_82371SB_1);
-
-    /* Map bmdma BAR */
-    *bmdma_bar = qpci_iomap(dev, 4, NULL);
-
-    *ide_bar = qpci_legacy_iomap(dev, IDE_BASE);
-
-    qpci_device_enable(dev);
-
-    return dev;
-}
-
-static void free_pci_device(QPCIDevice *dev)
-{
-    /* libqos doesn't have a function for this, so free it manually */
-    g_free(dev);
-}
-
-typedef struct PrdtEntry {
-    uint32_t addr;
-    uint32_t size;
-} QEMU_PACKED PrdtEntry;
-
-#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
-#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
-
-static uint64_t trim_range_le(uint64_t sector, uint16_t count)
-{
-    /* 2-byte range, 6-byte LBA */
-    return cpu_to_le64(((uint64_t)count << 48) + sector);
-}
-
-static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
-                            int nb_sectors, PrdtEntry *prdt, int prdt_entries,
-                            void(*post_exec)(QPCIDevice *dev, QPCIBar ide_bar,
-                                             uint64_t sector, int nb_sectors))
-{
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-    uintptr_t guest_prdt;
-    size_t len;
-    bool from_dev;
-    uint8_t status;
-    int flags;
-
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    flags = cmd & ~0xff;
-    cmd &= 0xff;
-
-    switch (cmd) {
-    case CMD_READ_DMA:
-    case CMD_PACKET:
-        /* Assuming we only test data reads w/ ATAPI, otherwise we need to know
-         * the SCSI command being sent in the packet, too. */
-        from_dev = true;
-        break;
-    case CMD_DSM:
-    case CMD_WRITE_DMA:
-        from_dev = false;
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    if (flags & CMDF_NO_BM) {
-        qpci_config_writew(dev, PCI_COMMAND,
-                           PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-    }
-
-    /* Select device 0 */
-    qpci_io_writeb(dev, ide_bar, reg_device, 0 | LBA);
-
-    /* Stop any running transfer, clear any pending interrupt */
-    qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
-    qpci_io_writeb(dev, bmdma_bar, bmreg_status, BM_STS_INTR);
-
-    /* Setup PRDT */
-    len = sizeof(*prdt) * prdt_entries;
-    guest_prdt = guest_alloc(&guest_malloc, len);
-    qtest_memwrite(qts, guest_prdt, prdt, len);
-    qpci_io_writel(dev, bmdma_bar, bmreg_prdt, guest_prdt);
-
-    /* ATA DMA command */
-    if (cmd == CMD_PACKET) {
-        /* Enables ATAPI DMA; otherwise PIO is attempted */
-        qpci_io_writeb(dev, ide_bar, reg_feature, 0x01);
-    } else {
-        if (cmd == CMD_DSM) {
-            /* trim bit */
-            qpci_io_writeb(dev, ide_bar, reg_feature, 0x01);
-        }
-        qpci_io_writeb(dev, ide_bar, reg_nsectors, nb_sectors);
-        qpci_io_writeb(dev, ide_bar, reg_lba_low,    sector & 0xff);
-        qpci_io_writeb(dev, ide_bar, reg_lba_middle, (sector >> 8) & 0xff);
-        qpci_io_writeb(dev, ide_bar, reg_lba_high,   (sector >> 16) & 0xff);
-    }
-
-    qpci_io_writeb(dev, ide_bar, reg_command, cmd);
-
-    if (post_exec) {
-        post_exec(dev, ide_bar, sector, nb_sectors);
-    }
-
-    /* Start DMA transfer */
-    qpci_io_writeb(dev, bmdma_bar, bmreg_cmd,
-                   BM_CMD_START | (from_dev ? BM_CMD_WRITE : 0));
-
-    if (flags & CMDF_ABORT) {
-        qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
-    }
-
-    /* Wait for the DMA transfer to complete */
-    do {
-        status = qpci_io_readb(dev, bmdma_bar, bmreg_status);
-    } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
-
-    g_assert_cmpint(qtest_get_irq(qts, IDE_PRIMARY_IRQ), ==,
-                    !!(status & BM_STS_INTR));
-
-    /* Check IDE status code */
-    assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), DRDY);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), BSY | DRQ);
-
-    /* Reading the status register clears the IRQ */
-    g_assert(!qtest_get_irq(qts, IDE_PRIMARY_IRQ));
-
-    /* Stop DMA transfer if still active */
-    if (status & BM_STS_ACTIVE) {
-        qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
-    }
-
-    free_pci_device(dev);
-
-    return status;
-}
-
-static QTestState *test_bmdma_setup(void)
-{
-    QTestState *qts;
-
-    qts = ide_test_start(
-        "-drive file=%s,if=ide,cache=writeback,format=raw "
-        "-global ide-hd.serial=%s -global ide-hd.ver=%s",
-        tmp_path, "testdisk", "version");
-    qtest_irq_intercept_in(qts, "ioapic");
-
-    return qts;
-}
-
-static void test_bmdma_teardown(QTestState *qts)
-{
-    ide_test_quit(qts);
-}
-
-static void test_bmdma_simple_rw(void)
-{
-    QTestState *qts;
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-    uint8_t status;
-    uint8_t *buf;
-    uint8_t *cmpbuf;
-    size_t len = 512;
-    uintptr_t guest_buf;
-    PrdtEntry prdt[1];
-
-    qts = test_bmdma_setup();
-
-    guest_buf  = guest_alloc(&guest_malloc, len);
-    prdt[0].addr = cpu_to_le32(guest_buf);
-    prdt[0].size = cpu_to_le32(len | PRDT_EOT);
-
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    buf = g_malloc(len);
-    cmpbuf = g_malloc(len);
-
-    /* Write 0x55 pattern to sector 0 */
-    memset(buf, 0x55, len);
-    qtest_memwrite(qts, guest_buf, buf, len);
-
-    status = send_dma_request(qts, CMD_WRITE_DMA, 0, 1, prdt,
-                              ARRAY_SIZE(prdt), NULL);
-    g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
-
-    /* Write 0xaa pattern to sector 1 */
-    memset(buf, 0xaa, len);
-    qtest_memwrite(qts, guest_buf, buf, len);
-
-    status = send_dma_request(qts, CMD_WRITE_DMA, 1, 1, prdt,
-                              ARRAY_SIZE(prdt), NULL);
-    g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
-
-    /* Read and verify 0x55 pattern in sector 0 */
-    memset(cmpbuf, 0x55, len);
-
-    status = send_dma_request(qts, CMD_READ_DMA, 0, 1, prdt, ARRAY_SIZE(prdt),
-                              NULL);
-    g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
-
-    qtest_memread(qts, guest_buf, buf, len);
-    g_assert(memcmp(buf, cmpbuf, len) == 0);
-
-    /* Read and verify 0xaa pattern in sector 1 */
-    memset(cmpbuf, 0xaa, len);
-
-    status = send_dma_request(qts, CMD_READ_DMA, 1, 1, prdt, ARRAY_SIZE(prdt),
-                              NULL);
-    g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
-
-    qtest_memread(qts, guest_buf, buf, len);
-    g_assert(memcmp(buf, cmpbuf, len) == 0);
-
-    free_pci_device(dev);
-    g_free(buf);
-    g_free(cmpbuf);
-
-    test_bmdma_teardown(qts);
-}
-
-static void test_bmdma_trim(void)
-{
-    QTestState *qts;
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-    uint8_t status;
-    const uint64_t trim_range[] = { trim_range_le(0, 2),
-                                    trim_range_le(6, 8),
-                                    trim_range_le(10, 1),
-                                  };
-    const uint64_t bad_range = trim_range_le(TEST_IMAGE_SIZE / 512 - 1, 2);
-    size_t len = 512;
-    uint8_t *buf;
-    uintptr_t guest_buf;
-    PrdtEntry prdt[1];
-
-    qts = test_bmdma_setup();
-
-    guest_buf = guest_alloc(&guest_malloc, len);
-    prdt[0].addr = cpu_to_le32(guest_buf),
-    prdt[0].size = cpu_to_le32(len | PRDT_EOT),
-
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    buf = g_malloc(len);
-
-    /* Normal request */
-    *((uint64_t *)buf) = trim_range[0];
-    *((uint64_t *)buf + 1) = trim_range[1];
-
-    qtest_memwrite(qts, guest_buf, buf, 2 * sizeof(uint64_t));
-
-    status = send_dma_request(qts, CMD_DSM, 0, 1, prdt,
-                              ARRAY_SIZE(prdt), NULL);
-    g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
-
-    /* Request contains invalid range */
-    *((uint64_t *)buf) = trim_range[2];
-    *((uint64_t *)buf + 1) = bad_range;
-
-    qtest_memwrite(qts, guest_buf, buf, 2 * sizeof(uint64_t));
-
-    status = send_dma_request(qts, CMD_DSM, 0, 1, prdt,
-                              ARRAY_SIZE(prdt), NULL);
-    g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), ERR);
-    assert_bit_set(qpci_io_readb(dev, ide_bar, reg_error), ABRT);
-
-    free_pci_device(dev);
-    g_free(buf);
-    test_bmdma_teardown(qts);
-}
-
-static void test_bmdma_short_prdt(void)
-{
-    QTestState *qts;
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-    uint8_t status;
-
-    PrdtEntry prdt[] = {
-        {
-            .addr = 0,
-            .size = cpu_to_le32(0x10 | PRDT_EOT),
-        },
-    };
-
-    qts = test_bmdma_setup();
-
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    /* Normal request */
-    status = send_dma_request(qts, CMD_READ_DMA, 0, 1,
-                              prdt, ARRAY_SIZE(prdt), NULL);
-    g_assert_cmphex(status, ==, 0);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
-
-    /* Abort the request before it completes */
-    status = send_dma_request(qts, CMD_READ_DMA | CMDF_ABORT, 0, 1,
-                              prdt, ARRAY_SIZE(prdt), NULL);
-    g_assert_cmphex(status, ==, 0);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
-    free_pci_device(dev);
-    test_bmdma_teardown(qts);
-}
-
-static void test_bmdma_one_sector_short_prdt(void)
-{
-    QTestState *qts;
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-    uint8_t status;
-
-    /* Read 2 sectors but only give 1 sector in PRDT */
-    PrdtEntry prdt[] = {
-        {
-            .addr = 0,
-            .size = cpu_to_le32(0x200 | PRDT_EOT),
-        },
-    };
-
-    qts = test_bmdma_setup();
-
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    /* Normal request */
-    status = send_dma_request(qts, CMD_READ_DMA, 0, 2,
-                              prdt, ARRAY_SIZE(prdt), NULL);
-    g_assert_cmphex(status, ==, 0);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
-
-    /* Abort the request before it completes */
-    status = send_dma_request(qts, CMD_READ_DMA | CMDF_ABORT, 0, 2,
-                              prdt, ARRAY_SIZE(prdt), NULL);
-    g_assert_cmphex(status, ==, 0);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
-    free_pci_device(dev);
-    test_bmdma_teardown(qts);
-}
-
-static void test_bmdma_long_prdt(void)
-{
-    QTestState *qts;
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-    uint8_t status;
-
-    PrdtEntry prdt[] = {
-        {
-            .addr = 0,
-            .size = cpu_to_le32(0x1000 | PRDT_EOT),
-        },
-    };
-
-    qts = test_bmdma_setup();
-
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    /* Normal request */
-    status = send_dma_request(qts, CMD_READ_DMA, 0, 1,
-                              prdt, ARRAY_SIZE(prdt), NULL);
-    g_assert_cmphex(status, ==, BM_STS_ACTIVE | BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
-
-    /* Abort the request before it completes */
-    status = send_dma_request(qts, CMD_READ_DMA | CMDF_ABORT, 0, 1,
-                              prdt, ARRAY_SIZE(prdt), NULL);
-    g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
-    free_pci_device(dev);
-    test_bmdma_teardown(qts);
-}
-
-static void test_bmdma_no_busmaster(void)
-{
-    QTestState *qts;
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-    uint8_t status;
-
-    qts = test_bmdma_setup();
-
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    /* No PRDT_EOT, each entry addr 0/size 64k, and in theory qemu shouldn't be
-     * able to access it anyway because the Bus Master bit in the PCI command
-     * register isn't set. This is complete nonsense, but it used to be pretty
-     * good at confusing and occasionally crashing qemu. */
-    PrdtEntry prdt[4096] = { };
-
-    status = send_dma_request(qts, CMD_READ_DMA | CMDF_NO_BM, 0, 512,
-                              prdt, ARRAY_SIZE(prdt), NULL);
-
-    /* Not entirely clear what the expected result is, but this is what we get
-     * in practice. At least we want to be aware of any changes. */
-    g_assert_cmphex(status, ==, BM_STS_ACTIVE | BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
-    free_pci_device(dev);
-    test_bmdma_teardown(qts);
-}
-
-static void string_cpu_to_be16(uint16_t *s, size_t bytes)
-{
-    g_assert((bytes & 1) == 0);
-    bytes /= 2;
-
-    while (bytes--) {
-        *s = cpu_to_be16(*s);
-        s++;
-    }
-}
-
-static void test_identify(void)
-{
-    QTestState *qts;
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-    uint8_t data;
-    uint16_t buf[256];
-    int i;
-    int ret;
-
-    qts = ide_test_start(
-        "-drive file=%s,if=ide,cache=writeback,format=raw "
-        "-global ide-hd.serial=%s -global ide-hd.ver=%s",
-        tmp_path, "testdisk", "version");
-
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    /* IDENTIFY command on device 0*/
-    qpci_io_writeb(dev, ide_bar, reg_device, 0);
-    qpci_io_writeb(dev, ide_bar, reg_command, CMD_IDENTIFY);
-
-    /* Read in the IDENTIFY buffer and check registers */
-    data = qpci_io_readb(dev, ide_bar, reg_device);
-    g_assert_cmpint(data & DEV, ==, 0);
-
-    for (i = 0; i < 256; i++) {
-        data = qpci_io_readb(dev, ide_bar, reg_status);
-        assert_bit_set(data, DRDY | DRQ);
-        assert_bit_clear(data, BSY | DF | ERR);
-
-        buf[i] = qpci_io_readw(dev, ide_bar, reg_data);
-    }
-
-    data = qpci_io_readb(dev, ide_bar, reg_status);
-    assert_bit_set(data, DRDY);
-    assert_bit_clear(data, BSY | DF | ERR | DRQ);
-
-    /* Check serial number/version in the buffer */
-    string_cpu_to_be16(&buf[10], 20);
-    ret = memcmp(&buf[10], "testdisk            ", 20);
-    g_assert(ret == 0);
-
-    string_cpu_to_be16(&buf[23], 8);
-    ret = memcmp(&buf[23], "version ", 8);
-    g_assert(ret == 0);
-
-    /* Write cache enabled bit */
-    assert_bit_set(buf[85], 0x20);
-
-    ide_test_quit(qts);
-    free_pci_device(dev);
-}
-
-/*
- * Write sector 1 with random data to make IDE storage dirty
- * Needed for flush tests so that flushes actually go though the block layer
- */
-static void make_dirty(QTestState *qts, uint8_t device)
-{
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-    uint8_t status;
-    size_t len = 512;
-    uintptr_t guest_buf;
-    void* buf;
-
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    guest_buf = guest_alloc(&guest_malloc, len);
-    buf = g_malloc(len);
-    memset(buf, rand() % 255 + 1, len);
-    g_assert(guest_buf);
-    g_assert(buf);
-
-    qtest_memwrite(qts, guest_buf, buf, len);
-
-    PrdtEntry prdt[] = {
-        {
-            .addr = cpu_to_le32(guest_buf),
-            .size = cpu_to_le32(len | PRDT_EOT),
-        },
-    };
-
-    status = send_dma_request(qts, CMD_WRITE_DMA, 1, 1, prdt,
-                              ARRAY_SIZE(prdt), NULL);
-    g_assert_cmphex(status, ==, BM_STS_INTR);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
-
-    g_free(buf);
-    free_pci_device(dev);
-}
-
-static void test_flush(void)
-{
-    QTestState *qts;
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-    uint8_t data;
-
-    qts = ide_test_start(
-        "-drive file=blkdebug::%s,if=ide,cache=writeback,format=raw",
-        tmp_path);
-
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    qtest_irq_intercept_in(qts, "ioapic");
-
-    /* Dirty media so that CMD_FLUSH_CACHE will actually go to disk */
-    make_dirty(qts, 0);
-
-    /* Delay the completion of the flush request until we explicitly do it */
-    g_free(qtest_hmp(qts, "qemu-io ide0-hd0 \"break flush_to_os A\""));
-
-    /* FLUSH CACHE command on device 0*/
-    qpci_io_writeb(dev, ide_bar, reg_device, 0);
-    qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE);
-
-    /* Check status while request is in flight*/
-    data = qpci_io_readb(dev, ide_bar, reg_status);
-    assert_bit_set(data, BSY | DRDY);
-    assert_bit_clear(data, DF | ERR | DRQ);
-
-    /* Complete the command */
-    g_free(qtest_hmp(qts, "qemu-io ide0-hd0 \"resume A\""));
-
-    /* Check registers */
-    data = qpci_io_readb(dev, ide_bar, reg_device);
-    g_assert_cmpint(data & DEV, ==, 0);
-
-    do {
-        data = qpci_io_readb(dev, ide_bar, reg_status);
-    } while (data & BSY);
-
-    assert_bit_set(data, DRDY);
-    assert_bit_clear(data, BSY | DF | ERR | DRQ);
-
-    ide_test_quit(qts);
-    free_pci_device(dev);
-}
-
-static void test_retry_flush(const char *machine)
-{
-    QTestState *qts;
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-    uint8_t data;
-
-    prepare_blkdebug_script(debug_path, "flush_to_disk");
-
-    qts = ide_test_start(
-        "-drive file=blkdebug:%s:%s,if=ide,cache=writeback,format=raw,"
-        "rerror=stop,werror=stop",
-        debug_path, tmp_path);
-
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    qtest_irq_intercept_in(qts, "ioapic");
-
-    /* Dirty media so that CMD_FLUSH_CACHE will actually go to disk */
-    make_dirty(qts, 0);
-
-    /* FLUSH CACHE command on device 0*/
-    qpci_io_writeb(dev, ide_bar, reg_device, 0);
-    qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE);
-
-    /* Check status while request is in flight*/
-    data = qpci_io_readb(dev, ide_bar, reg_status);
-    assert_bit_set(data, BSY | DRDY);
-    assert_bit_clear(data, DF | ERR | DRQ);
-
-    qtest_qmp_eventwait(qts, "STOP");
-
-    /* Complete the command */
-    qmp_discard_response(qts, "{'execute':'cont' }");
-
-    /* Check registers */
-    data = qpci_io_readb(dev, ide_bar, reg_device);
-    g_assert_cmpint(data & DEV, ==, 0);
-
-    do {
-        data = qpci_io_readb(dev, ide_bar, reg_status);
-    } while (data & BSY);
-
-    assert_bit_set(data, DRDY);
-    assert_bit_clear(data, BSY | DF | ERR | DRQ);
-
-    ide_test_quit(qts);
-    free_pci_device(dev);
-}
-
-static void test_flush_nodev(void)
-{
-    QTestState *qts;
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-
-    qts = ide_test_start("");
-
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    /* FLUSH CACHE command on device 0*/
-    qpci_io_writeb(dev, ide_bar, reg_device, 0);
-    qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE);
-
-    /* Just testing that qemu doesn't crash... */
-
-    free_pci_device(dev);
-    ide_test_quit(qts);
-}
-
-static void test_flush_empty_drive(void)
-{
-    QTestState *qts;
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-
-    qts = ide_test_start("-device ide-cd,bus=ide.0");
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    /* FLUSH CACHE command on device 0 */
-    qpci_io_writeb(dev, ide_bar, reg_device, 0);
-    qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE);
-
-    /* Just testing that qemu doesn't crash... */
-
-    free_pci_device(dev);
-    ide_test_quit(qts);
-}
-
-static void test_pci_retry_flush(void)
-{
-    test_retry_flush("pc");
-}
-
-static void test_isa_retry_flush(void)
-{
-    test_retry_flush("isapc");
-}
-
-typedef struct Read10CDB {
-    uint8_t opcode;
-    uint8_t flags;
-    uint32_t lba;
-    uint8_t reserved;
-    uint16_t nblocks;
-    uint8_t control;
-    uint16_t padding;
-} __attribute__((__packed__)) Read10CDB;
-
-static void send_scsi_cdb_read10(QPCIDevice *dev, QPCIBar ide_bar,
-                                 uint64_t lba, int nblocks)
-{
-    Read10CDB pkt = { .padding = 0 };
-    int i;
-
-    g_assert_cmpint(lba, <=, UINT32_MAX);
-    g_assert_cmpint(nblocks, <=, UINT16_MAX);
-    g_assert_cmpint(nblocks, >=, 0);
-
-    /* Construct SCSI CDB packet */
-    pkt.opcode = 0x28;
-    pkt.lba = cpu_to_be32(lba);
-    pkt.nblocks = cpu_to_be16(nblocks);
-
-    /* Send Packet */
-    for (i = 0; i < sizeof(Read10CDB)/2; i++) {
-        qpci_io_writew(dev, ide_bar, reg_data,
-                       le16_to_cpu(((uint16_t *)&pkt)[i]));
-    }
-}
-
-static void nsleep(QTestState *qts, int64_t nsecs)
-{
-    const struct timespec val = { .tv_nsec = nsecs };
-    nanosleep(&val, NULL);
-    qtest_clock_set(qts, nsecs);
-}
-
-static uint8_t ide_wait_clear(QTestState *qts, uint8_t flag)
-{
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-    uint8_t data;
-    time_t st;
-
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
-    /* Wait with a 5 second timeout */
-    time(&st);
-    while (true) {
-        data = qpci_io_readb(dev, ide_bar, reg_status);
-        if (!(data & flag)) {
-            free_pci_device(dev);
-            return data;
-        }
-        if (difftime(time(NULL), st) > 5.0) {
-            break;
-        }
-        nsleep(qts, 400);
-    }
-    g_assert_not_reached();
-}
-
-static void ide_wait_intr(QTestState *qts, int irq)
-{
-    time_t st;
-    bool intr;
-
-    time(&st);
-    while (true) {
-        intr = qtest_get_irq(qts, irq);
-        if (intr) {
-            return;
-        }
-        if (difftime(time(NULL), st) > 5.0) {
-            break;
-        }
-        nsleep(qts, 400);
-    }
-
-    g_assert_not_reached();
-}
-
-static void cdrom_pio_impl(int nblocks)
-{
-    QTestState *qts;
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
-    FILE *fh;
-    int patt_blocks = MAX(16, nblocks);
-    size_t patt_len = ATAPI_BLOCK_SIZE * patt_blocks;
-    char *pattern = g_malloc(patt_len);
-    size_t rxsize = ATAPI_BLOCK_SIZE * nblocks;
-    uint16_t *rx = g_malloc0(rxsize);
-    int i, j;
-    uint8_t data;
-    uint16_t limit;
-    size_t ret;
-
-    /* Prepopulate the CDROM with an interesting pattern */
-    generate_pattern(pattern, patt_len, ATAPI_BLOCK_SIZE);
-    fh = fopen(tmp_path, "w+");
-    ret = fwrite(pattern, ATAPI_BLOCK_SIZE, patt_blocks, fh);
-    g_assert_cmpint(ret, ==, patt_blocks);
-    fclose(fh);
-
-    qts = ide_test_start(
-            "-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 "
-            "-device ide-cd,drive=sr0,bus=ide.0", tmp_path);
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-    qtest_irq_intercept_in(qts, "ioapic");
-
-    /* PACKET command on device 0 */
-    qpci_io_writeb(dev, ide_bar, reg_device, 0);
-    qpci_io_writeb(dev, ide_bar, reg_lba_middle, BYTE_COUNT_LIMIT & 0xFF);
-    qpci_io_writeb(dev, ide_bar, reg_lba_high, (BYTE_COUNT_LIMIT >> 8 & 0xFF));
-    qpci_io_writeb(dev, ide_bar, reg_command, CMD_PACKET);
-    /* HP0: Check_Status_A State */
-    nsleep(qts, 400);
-    data = ide_wait_clear(qts, BSY);
-    /* HP1: Send_Packet State */
-    assert_bit_set(data, DRQ | DRDY);
-    assert_bit_clear(data, ERR | DF | BSY);
-
-    /* SCSI CDB (READ10) -- read n*2048 bytes from block 0 */
-    send_scsi_cdb_read10(dev, ide_bar, 0, nblocks);
-
-    /* Read data back: occurs in bursts of 'BYTE_COUNT_LIMIT' bytes.
-     * If BYTE_COUNT_LIMIT is odd, we transfer BYTE_COUNT_LIMIT - 1 bytes.
-     * We allow an odd limit only when the remaining transfer size is
-     * less than BYTE_COUNT_LIMIT. However, SCSI's read10 command can only
-     * request n blocks, so our request size is always even.
-     * For this reason, we assume there is never a hanging byte to fetch. */
-    g_assert(!(rxsize & 1));
-    limit = BYTE_COUNT_LIMIT & ~1;
-    for (i = 0; i < DIV_ROUND_UP(rxsize, limit); i++) {
-        size_t offset = i * (limit / 2);
-        size_t rem = (rxsize / 2) - offset;
-
-        /* HP3: INTRQ_Wait */
-        ide_wait_intr(qts, IDE_PRIMARY_IRQ);
-
-        /* HP2: Check_Status_B (and clear IRQ) */
-        data = ide_wait_clear(qts, BSY);
-        assert_bit_set(data, DRQ | DRDY);
-        assert_bit_clear(data, ERR | DF | BSY);
-
-        /* HP4: Transfer_Data */
-        for (j = 0; j < MIN((limit / 2), rem); j++) {
-            rx[offset + j] = cpu_to_le16(qpci_io_readw(dev, ide_bar,
-                                                       reg_data));
-        }
-    }
-
-    /* Check for final completion IRQ */
-    ide_wait_intr(qts, IDE_PRIMARY_IRQ);
-
-    /* Sanity check final state */
-    data = ide_wait_clear(qts, DRQ);
-    assert_bit_set(data, DRDY);
-    assert_bit_clear(data, DRQ | ERR | DF | BSY);
-
-    g_assert_cmpint(memcmp(pattern, rx, rxsize), ==, 0);
-    g_free(pattern);
-    g_free(rx);
-    test_bmdma_teardown(qts);
-    free_pci_device(dev);
-}
-
-static void test_cdrom_pio(void)
-{
-    cdrom_pio_impl(1);
-}
-
-static void test_cdrom_pio_large(void)
-{
-    /* Test a few loops of the PIO DRQ mechanism. */
-    cdrom_pio_impl(BYTE_COUNT_LIMIT * 4 / ATAPI_BLOCK_SIZE);
-}
-
-
-static void test_cdrom_dma(void)
-{
-    QTestState *qts;
-    static const size_t len = ATAPI_BLOCK_SIZE;
-    size_t ret;
-    char *pattern = g_malloc(ATAPI_BLOCK_SIZE * 16);
-    char *rx = g_malloc0(len);
-    uintptr_t guest_buf;
-    PrdtEntry prdt[1];
-    FILE *fh;
-
-    qts = ide_test_start(
-            "-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 "
-            "-device ide-cd,drive=sr0,bus=ide.0", tmp_path);
-    qtest_irq_intercept_in(qts, "ioapic");
-
-    guest_buf = guest_alloc(&guest_malloc, len);
-    prdt[0].addr = cpu_to_le32(guest_buf);
-    prdt[0].size = cpu_to_le32(len | PRDT_EOT);
-
-    generate_pattern(pattern, ATAPI_BLOCK_SIZE * 16, ATAPI_BLOCK_SIZE);
-    fh = fopen(tmp_path, "w+");
-    ret = fwrite(pattern, ATAPI_BLOCK_SIZE, 16, fh);
-    g_assert_cmpint(ret, ==, 16);
-    fclose(fh);
-
-    send_dma_request(qts, CMD_PACKET, 0, 1, prdt, 1, send_scsi_cdb_read10);
-
-    /* Read back data from guest memory into local qtest memory */
-    qtest_memread(qts, guest_buf, rx, len);
-    g_assert_cmpint(memcmp(pattern, rx, len), ==, 0);
-
-    g_free(pattern);
-    g_free(rx);
-    test_bmdma_teardown(qts);
-}
-
-int main(int argc, char **argv)
-{
-    int fd;
-    int ret;
-
-    /* Create temporary blkdebug instructions */
-    fd = mkstemp(debug_path);
-    g_assert(fd >= 0);
-    close(fd);
-
-    /* Create a temporary raw image */
-    fd = mkstemp(tmp_path);
-    g_assert(fd >= 0);
-    ret = ftruncate(fd, TEST_IMAGE_SIZE);
-    g_assert(ret == 0);
-    close(fd);
-
-    /* Run the tests */
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("/ide/identify", test_identify);
-
-    qtest_add_func("/ide/bmdma/simple_rw", test_bmdma_simple_rw);
-    qtest_add_func("/ide/bmdma/trim", test_bmdma_trim);
-    qtest_add_func("/ide/bmdma/short_prdt", test_bmdma_short_prdt);
-    qtest_add_func("/ide/bmdma/one_sector_short_prdt",
-                   test_bmdma_one_sector_short_prdt);
-    qtest_add_func("/ide/bmdma/long_prdt", test_bmdma_long_prdt);
-    qtest_add_func("/ide/bmdma/no_busmaster", test_bmdma_no_busmaster);
-
-    qtest_add_func("/ide/flush", test_flush);
-    qtest_add_func("/ide/flush/nodev", test_flush_nodev);
-    qtest_add_func("/ide/flush/empty_drive", test_flush_empty_drive);
-    qtest_add_func("/ide/flush/retry_pci", test_pci_retry_flush);
-    qtest_add_func("/ide/flush/retry_isa", test_isa_retry_flush);
-
-    qtest_add_func("/ide/cdrom/pio", test_cdrom_pio);
-    qtest_add_func("/ide/cdrom/pio_large", test_cdrom_pio_large);
-    qtest_add_func("/ide/cdrom/dma", test_cdrom_dma);
-
-    ret = g_test_run();
-
-    /* Cleanup */
-    unlink(tmp_path);
-    unlink(debug_path);
-
-    return ret;
-}
diff --git a/tests/intel-hda-test.c b/tests/intel-hda-test.c
deleted file mode 100644 (file)
index fc25ccc..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * QTest testcase for Intel HDA
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-
-#define HDA_ID "hda0"
-#define CODEC_DEVICES " -device hda-output,bus=" HDA_ID ".0" \
-                      " -device hda-micro,bus=" HDA_ID ".0" \
-                      " -device hda-duplex,bus=" HDA_ID ".0"
-
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void ich6_test(void)
-{
-    qtest_start("-device intel-hda,id=" HDA_ID CODEC_DEVICES);
-    qtest_end();
-}
-
-static void ich9_test(void)
-{
-    qtest_start("-machine q35 -device ich9-intel-hda,bus=pcie.0,addr=1b.0,id="
-                HDA_ID CODEC_DEVICES);
-    qtest_end();
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/intel-hda/ich6", ich6_test);
-    qtest_add_func("/intel-hda/ich9", ich9_test);
-
-    return g_test_run();
-}
diff --git a/tests/ioh3420-test.c b/tests/ioh3420-test.c
deleted file mode 100644 (file)
index f6ca43c..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * QTest testcase for Intel X58 north bridge IOH
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void nop(void)
-{
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/ioh3420/nop", nop);
-
-    qtest_start("-machine q35 -device ioh3420,bus=pcie.0,addr=1c.0,port=1,"
-                "chassis=1,multifunction=on");
-    ret = g_test_run();
-
-    qtest_end();
-
-    return ret;
-}
diff --git a/tests/ipmi-bt-test.c b/tests/ipmi-bt-test.c
deleted file mode 100644 (file)
index a42207d..0000000
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * IPMI BT test cases, using the external interface for checking
- *
- * Copyright (c) 2012 Corey Minyard <[email protected]>
- *
- * 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 <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/tcp.h>
-
-
-#include "libqtest-single.h"
-#include "qemu-common.h"
-
-#define IPMI_IRQ        5
-
-#define IPMI_BT_BASE    0xe4
-
-#define IPMI_BT_CTLREG_CLR_WR_PTR  0
-#define IPMI_BT_CTLREG_CLR_RD_PTR  1
-#define IPMI_BT_CTLREG_H2B_ATN     2
-#define IPMI_BT_CTLREG_B2H_ATN     3
-#define IPMI_BT_CTLREG_SMS_ATN     4
-#define IPMI_BT_CTLREG_H_BUSY      6
-#define IPMI_BT_CTLREG_B_BUSY      7
-
-#define IPMI_BT_CTLREG_GET(b) ((bt_get_ctrlreg() >> (b)) & 1)
-#define IPMI_BT_CTLREG_GET_H2B_ATN() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_H2B_ATN)
-#define IPMI_BT_CTLREG_GET_B2H_ATN() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_B2H_ATN)
-#define IPMI_BT_CTLREG_GET_SMS_ATN() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_SMS_ATN)
-#define IPMI_BT_CTLREG_GET_H_BUSY()  IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_H_BUSY)
-#define IPMI_BT_CTLREG_GET_B_BUSY()  IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_B_BUSY)
-
-#define IPMI_BT_CTLREG_SET(b) bt_write_ctrlreg(1 << (b))
-#define IPMI_BT_CTLREG_SET_CLR_WR_PTR() IPMI_BT_CTLREG_SET( \
-                                                IPMI_BT_CTLREG_CLR_WR_PTR)
-#define IPMI_BT_CTLREG_SET_CLR_RD_PTR() IPMI_BT_CTLREG_SET( \
-                                                IPMI_BT_CTLREG_CLR_RD_PTR)
-#define IPMI_BT_CTLREG_SET_H2B_ATN()  IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_H2B_ATN)
-#define IPMI_BT_CTLREG_SET_B2H_ATN()  IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_B2H_ATN)
-#define IPMI_BT_CTLREG_SET_SMS_ATN()  IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_SMS_ATN)
-#define IPMI_BT_CTLREG_SET_H_BUSY()   IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_H_BUSY)
-
-static int bt_ints_enabled;
-
-static uint8_t bt_get_ctrlreg(void)
-{
-    return inb(IPMI_BT_BASE);
-}
-
-static void bt_write_ctrlreg(uint8_t val)
-{
-    outb(IPMI_BT_BASE, val);
-}
-
-static uint8_t bt_get_buf(void)
-{
-    return inb(IPMI_BT_BASE + 1);
-}
-
-static void bt_write_buf(uint8_t val)
-{
-    outb(IPMI_BT_BASE + 1, val);
-}
-
-static uint8_t bt_get_irqreg(void)
-{
-    return inb(IPMI_BT_BASE + 2);
-}
-
-static void bt_write_irqreg(uint8_t val)
-{
-    outb(IPMI_BT_BASE + 2, val);
-}
-
-static void bt_wait_b_busy(void)
-{
-    unsigned int count = 1000;
-    while (IPMI_BT_CTLREG_GET_B_BUSY() != 0) {
-        g_assert(--count != 0);
-        usleep(100);
-    }
-}
-
-static void bt_wait_b2h_atn(void)
-{
-    unsigned int count = 1000;
-    while (IPMI_BT_CTLREG_GET_B2H_ATN() == 0) {
-        g_assert(--count != 0);
-        usleep(100);
-    }
-}
-
-
-static int emu_lfd;
-static int emu_fd;
-static in_port_t emu_port;
-static uint8_t inbuf[100];
-static unsigned int inbuf_len;
-static unsigned int inbuf_pos;
-static int last_was_aa;
-
-static void read_emu_data(void)
-{
-    fd_set readfds;
-    int rv;
-    struct timeval tv;
-
-    FD_ZERO(&readfds);
-    FD_SET(emu_fd, &readfds);
-    tv.tv_sec = 10;
-    tv.tv_usec = 0;
-    rv = select(emu_fd + 1, &readfds, NULL, NULL, &tv);
-    if (rv == -1) {
-        perror("select");
-    }
-    g_assert(rv == 1);
-    rv = read(emu_fd, inbuf, sizeof(inbuf));
-    if (rv == -1) {
-        perror("read");
-    }
-    g_assert(rv > 0);
-    inbuf_len = rv;
-    inbuf_pos = 0;
-}
-
-static void write_emu_msg(uint8_t *msg, unsigned int len)
-{
-    int rv;
-
-#ifdef DEBUG_TEST
-    {
-        unsigned int i;
-        printf("sending:");
-        for (i = 0; i < len; i++) {
-            printf(" %2.2x", msg[i]);
-        }
-        printf("\n");
-    }
-#endif
-    rv = write(emu_fd, msg, len);
-    g_assert(rv == len);
-}
-
-static void get_emu_msg(uint8_t *msg, unsigned int *len)
-{
-    unsigned int outpos = 0;
-
-    for (;;) {
-        while (inbuf_pos < inbuf_len) {
-            uint8_t ch = inbuf[inbuf_pos++];
-
-            g_assert(outpos < *len);
-            if (last_was_aa) {
-                assert(ch & 0x10);
-                msg[outpos++] = ch & ~0x10;
-                last_was_aa = 0;
-            } else if (ch == 0xaa) {
-                last_was_aa = 1;
-            } else {
-                msg[outpos++] = ch;
-                if ((ch == 0xa0) || (ch == 0xa1)) {
-                    /* Message complete */
-                    *len = outpos;
-                    goto done;
-                }
-            }
-        }
-        read_emu_data();
-    }
- done:
-#ifdef DEBUG_TEST
-    {
-        unsigned int i;
-        printf("Msg:");
-        for (i = 0; i < outpos; i++) {
-            printf(" %2.2x", msg[i]);
-        }
-        printf("\n");
-    }
-#endif
-    return;
-}
-
-static uint8_t
-ipmb_checksum(const unsigned char *data, int size, unsigned char start)
-{
-        unsigned char csum = start;
-
-        for (; size > 0; size--, data++) {
-                csum += *data;
-        }
-        return csum;
-}
-
-static uint8_t get_dev_id_cmd[] = { 0x18, 0x01 };
-static uint8_t get_dev_id_rsp[] = { 0x1c, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
-                                    0x02, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-static uint8_t set_bmc_globals_cmd[] = { 0x18, 0x2e, 0x0f };
-static uint8_t set_bmc_globals_rsp[] = { 0x1c, 0x2e, 0x00 };
-static uint8_t enable_irq_cmd[] = { 0x05, 0xa1 };
-
-static void emu_msg_handler(void)
-{
-    uint8_t msg[100];
-    unsigned int msg_len = sizeof(msg);
-
-    get_emu_msg(msg, &msg_len);
-    g_assert(msg_len >= 5);
-    g_assert(msg[msg_len - 1] == 0xa0);
-    msg_len--;
-    g_assert(ipmb_checksum(msg, msg_len, 0) == 0);
-    msg_len--;
-    if ((msg[1] == get_dev_id_cmd[0]) && (msg[2] == get_dev_id_cmd[1])) {
-        memcpy(msg + 1, get_dev_id_rsp, sizeof(get_dev_id_rsp));
-        msg_len = sizeof(get_dev_id_rsp) + 1;
-        msg[msg_len] = -ipmb_checksum(msg, msg_len, 0);
-        msg_len++;
-        msg[msg_len++] = 0xa0;
-        write_emu_msg(msg, msg_len);
-    } else if ((msg[1] == set_bmc_globals_cmd[0]) &&
-               (msg[2] == set_bmc_globals_cmd[1])) {
-        write_emu_msg(enable_irq_cmd, sizeof(enable_irq_cmd));
-        memcpy(msg + 1, set_bmc_globals_rsp, sizeof(set_bmc_globals_rsp));
-        msg_len = sizeof(set_bmc_globals_rsp) + 1;
-        msg[msg_len] = -ipmb_checksum(msg, msg_len, 0);
-        msg_len++;
-        msg[msg_len++] = 0xa0;
-        write_emu_msg(msg, msg_len);
-    } else {
-        g_assert(0);
-    }
-}
-
-static void bt_cmd(uint8_t *cmd, unsigned int cmd_len,
-                    uint8_t *rsp, unsigned int *rsp_len)
-{
-    unsigned int i, len, j = 0;
-    uint8_t seq = 5;
-
-    /* Should be idle */
-    g_assert(bt_get_ctrlreg() == 0);
-
-    bt_wait_b_busy();
-    IPMI_BT_CTLREG_SET_CLR_WR_PTR();
-    bt_write_buf(cmd_len + 1);
-    bt_write_buf(cmd[0]);
-    bt_write_buf(seq);
-    for (i = 1; i < cmd_len; i++) {
-        bt_write_buf(cmd[i]);
-    }
-    IPMI_BT_CTLREG_SET_H2B_ATN();
-
-    emu_msg_handler(); /* We should get a message on the socket here. */
-
-    bt_wait_b2h_atn();
-    if (bt_ints_enabled) {
-        g_assert((bt_get_irqreg() & 0x02) == 0x02);
-        g_assert(get_irq(IPMI_IRQ));
-        bt_write_irqreg(0x03);
-    } else {
-        g_assert(!get_irq(IPMI_IRQ));
-    }
-    IPMI_BT_CTLREG_SET_H_BUSY();
-    IPMI_BT_CTLREG_SET_B2H_ATN();
-    IPMI_BT_CTLREG_SET_CLR_RD_PTR();
-    len = bt_get_buf();
-    g_assert(len >= 4);
-    rsp[0] = bt_get_buf();
-    assert(bt_get_buf() == seq);
-    len--;
-    for (j = 1; j < len; j++) {
-        rsp[j] = bt_get_buf();
-    }
-    IPMI_BT_CTLREG_SET_H_BUSY();
-    *rsp_len = j;
-}
-
-
-/*
- * We should get a connect request and a short message with capabilities.
- */
-static void test_connect(void)
-{
-    fd_set readfds;
-    int rv;
-    int val;
-    struct timeval tv;
-    uint8_t msg[100];
-    unsigned int msglen;
-    static uint8_t exp1[] = { 0xff, 0x01, 0xa1 }; /* A protocol version */
-    static uint8_t exp2[] = { 0x08, 0x3f, 0xa1 }; /* A capabilities cmd */
-
-    FD_ZERO(&readfds);
-    FD_SET(emu_lfd, &readfds);
-    tv.tv_sec = 10;
-    tv.tv_usec = 0;
-    rv = select(emu_lfd + 1, &readfds, NULL, NULL, &tv);
-    g_assert(rv == 1);
-    emu_fd = accept(emu_lfd, NULL, 0);
-    if (emu_fd < 0) {
-        perror("accept");
-    }
-    g_assert(emu_fd >= 0);
-
-    val = 1;
-    rv = setsockopt(emu_fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
-    g_assert(rv != -1);
-
-    /* Report our version */
-    write_emu_msg(exp1, sizeof(exp1));
-
-    /* Validate that we get the info we expect. */
-    msglen = sizeof(msg);
-    get_emu_msg(msg, &msglen);
-    g_assert(msglen == sizeof(exp1));
-    g_assert(memcmp(msg, exp1, msglen) == 0);
-    msglen = sizeof(msg);
-    get_emu_msg(msg, &msglen);
-    g_assert(msglen == sizeof(exp2));
-    g_assert(memcmp(msg, exp2, msglen) == 0);
-}
-
-/*
- * Send a get_device_id to do a basic test.
- */
-static void test_bt_base(void)
-{
-    uint8_t rsp[20];
-    unsigned int rsplen = sizeof(rsp);
-
-    bt_cmd(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen);
-    g_assert(rsplen == sizeof(get_dev_id_rsp));
-    g_assert(memcmp(get_dev_id_rsp, rsp, rsplen) == 0);
-}
-
-/*
- * Enable IRQs for the interface.
- */
-static void test_enable_irq(void)
-{
-    uint8_t rsp[20];
-    unsigned int rsplen = sizeof(rsp);
-
-    bt_cmd(set_bmc_globals_cmd, sizeof(set_bmc_globals_cmd), rsp, &rsplen);
-    g_assert(rsplen == sizeof(set_bmc_globals_rsp));
-    g_assert(memcmp(set_bmc_globals_rsp, rsp, rsplen) == 0);
-    bt_write_irqreg(0x01);
-    bt_ints_enabled = 1;
-}
-
-/*
- * Create a local TCP socket with any port, then save off the port we got.
- */
-static void open_socket(void)
-{
-    struct sockaddr_in myaddr;
-    socklen_t addrlen;
-
-    myaddr.sin_family = AF_INET;
-    myaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-    myaddr.sin_port = 0;
-    emu_lfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-    if (emu_lfd == -1) {
-        perror("socket");
-        exit(1);
-    }
-    if (bind(emu_lfd, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) {
-        perror("bind");
-        exit(1);
-    }
-    addrlen = sizeof(myaddr);
-    if (getsockname(emu_lfd, (struct sockaddr *) &myaddr , &addrlen) == -1) {
-        perror("getsockname");
-        exit(1);
-    }
-    emu_port = ntohs(myaddr.sin_port);
-    assert(listen(emu_lfd, 1) != -1);
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-
-    open_socket();
-
-    /* Run the tests */
-    g_test_init(&argc, &argv, NULL);
-
-    global_qtest = qtest_initf(
-        " -chardev socket,id=ipmi0,host=localhost,port=%d,reconnect=10"
-        " -device ipmi-bmc-extern,chardev=ipmi0,id=bmc0"
-        " -device isa-ipmi-bt,bmc=bmc0", emu_port);
-    qtest_irq_intercept_in(global_qtest, "ioapic");
-    qtest_add_func("/ipmi/extern/connect", test_connect);
-    qtest_add_func("/ipmi/extern/bt_base", test_bt_base);
-    qtest_add_func("/ipmi/extern/bt_enable_irq", test_enable_irq);
-    qtest_add_func("/ipmi/extern/bt_base_irq", test_bt_base);
-    ret = g_test_run();
-    qtest_quit(global_qtest);
-
-    return ret;
-}
diff --git a/tests/ipmi-kcs-test.c b/tests/ipmi-kcs-test.c
deleted file mode 100644 (file)
index 693a6aa..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * IPMI KCS test cases, using the local interface.
- *
- * Copyright (c) 2012 Corey Minyard <[email protected]>
- *
- * 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 "libqtest-single.h"
-
-#define IPMI_IRQ        5
-
-#define IPMI_KCS_BASE   0xca2
-
-#define IPMI_KCS_STATUS_ABORT           0x60
-#define IPMI_KCS_CMD_WRITE_START        0x61
-#define IPMI_KCS_CMD_WRITE_END          0x62
-#define IPMI_KCS_CMD_READ               0x68
-
-#define IPMI_KCS_ABORTED_BY_CMD         0x01
-
-#define IPMI_KCS_CMDREG_GET_STATE() ((kcs_get_cmdreg() >> 6) & 3)
-#define IPMI_KCS_STATE_IDLE     0
-#define IPMI_KCS_STATE_READ     1
-#define IPMI_KCS_STATE_WRITE    2
-#define IPMI_KCS_STATE_ERROR    3
-#define IPMI_KCS_CMDREG_GET_CD()    ((kcs_get_cmdreg() >> 3) & 1)
-#define IPMI_KCS_CMDREG_GET_ATN()   ((kcs_get_cmdreg() >> 2) & 1)
-#define IPMI_KCS_CMDREG_GET_IBF()   ((kcs_get_cmdreg() >> 1) & 1)
-#define IPMI_KCS_CMDREG_GET_OBF()   ((kcs_get_cmdreg() >> 0) & 1)
-
-static int kcs_ints_enabled;
-
-static uint8_t kcs_get_cmdreg(void)
-{
-    return inb(IPMI_KCS_BASE + 1);
-}
-
-static void kcs_write_cmdreg(uint8_t val)
-{
-    outb(IPMI_KCS_BASE + 1, val);
-}
-
-static uint8_t kcs_get_datareg(void)
-{
-    return inb(IPMI_KCS_BASE);
-}
-
-static void kcs_write_datareg(uint8_t val)
-{
-    outb(IPMI_KCS_BASE, val);
-}
-
-static void kcs_wait_ibf(void)
-{
-    unsigned int count = 1000;
-    while (IPMI_KCS_CMDREG_GET_IBF() != 0) {
-        g_assert(--count != 0);
-    }
-}
-
-static void kcs_wait_obf(void)
-{
-    unsigned int count = 1000;
-    while (IPMI_KCS_CMDREG_GET_OBF() == 0) {
-        g_assert(--count != 0);
-    }
-}
-
-static void kcs_clear_obf(void)
-{
-    if (kcs_ints_enabled) {
-        g_assert(get_irq(IPMI_IRQ));
-    } else {
-        g_assert(!get_irq(IPMI_IRQ));
-    }
-    g_assert(IPMI_KCS_CMDREG_GET_OBF() == 1);
-    kcs_get_datareg();
-    g_assert(IPMI_KCS_CMDREG_GET_OBF() == 0);
-    g_assert(!get_irq(IPMI_IRQ));
-}
-
-static void kcs_check_state(uint8_t state)
-{
-    g_assert(IPMI_KCS_CMDREG_GET_STATE() == state);
-}
-
-static void kcs_cmd(uint8_t *cmd, unsigned int cmd_len,
-                    uint8_t *rsp, unsigned int *rsp_len)
-{
-    unsigned int i, j = 0;
-
-    /* Should be idle */
-    g_assert(kcs_get_cmdreg() == 0);
-
-    kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_START);
-    kcs_wait_ibf();
-    kcs_check_state(IPMI_KCS_STATE_WRITE);
-    kcs_clear_obf();
-    for (i = 0; i < cmd_len; i++) {
-        kcs_write_datareg(cmd[i]);
-        kcs_wait_ibf();
-        kcs_check_state(IPMI_KCS_STATE_WRITE);
-        kcs_clear_obf();
-    }
-    kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_END);
-    kcs_wait_ibf();
-    kcs_check_state(IPMI_KCS_STATE_WRITE);
-    kcs_clear_obf();
-    kcs_write_datareg(0);
- next_read_byte:
-    kcs_wait_ibf();
-    switch (IPMI_KCS_CMDREG_GET_STATE()) {
-    case IPMI_KCS_STATE_READ:
-        kcs_wait_obf();
-        g_assert(j < *rsp_len);
-        rsp[j++] = kcs_get_datareg();
-        kcs_write_datareg(IPMI_KCS_CMD_READ);
-        goto next_read_byte;
-        break;
-
-    case IPMI_KCS_STATE_IDLE:
-        kcs_wait_obf();
-        kcs_get_datareg();
-        break;
-
-    default:
-        g_assert(0);
-    }
-    *rsp_len = j;
-}
-
-static void kcs_abort(uint8_t *cmd, unsigned int cmd_len,
-                      uint8_t *rsp, unsigned int *rsp_len)
-{
-    unsigned int i, j = 0;
-    unsigned int retries = 4;
-
-    /* Should be idle */
-    g_assert(kcs_get_cmdreg() == 0);
-
-    kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_START);
-    kcs_wait_ibf();
-    kcs_check_state(IPMI_KCS_STATE_WRITE);
-    kcs_clear_obf();
-    for (i = 0; i < cmd_len; i++) {
-        kcs_write_datareg(cmd[i]);
-        kcs_wait_ibf();
-        kcs_check_state(IPMI_KCS_STATE_WRITE);
-        kcs_clear_obf();
-    }
-    kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_END);
-    kcs_wait_ibf();
-    kcs_check_state(IPMI_KCS_STATE_WRITE);
-    kcs_clear_obf();
-    kcs_write_datareg(0);
-    kcs_wait_ibf();
-    switch (IPMI_KCS_CMDREG_GET_STATE()) {
-    case IPMI_KCS_STATE_READ:
-        kcs_wait_obf();
-        g_assert(j < *rsp_len);
-        rsp[j++] = kcs_get_datareg();
-        kcs_write_datareg(IPMI_KCS_CMD_READ);
-        break;
-
-    default:
-        g_assert(0);
-    }
-
-    /* Start the abort here */
- retry_abort:
-    g_assert(retries > 0);
-
-    kcs_wait_ibf();
-    kcs_write_cmdreg(IPMI_KCS_STATUS_ABORT);
-    kcs_wait_ibf();
-    kcs_clear_obf();
-    kcs_write_datareg(0);
-    kcs_wait_ibf();
-    if (IPMI_KCS_CMDREG_GET_STATE() != IPMI_KCS_STATE_READ) {
-        retries--;
-        goto retry_abort;
-    }
-    kcs_wait_obf();
-    rsp[0] = kcs_get_datareg();
-    kcs_write_datareg(IPMI_KCS_CMD_READ);
-    kcs_wait_ibf();
-    if (IPMI_KCS_CMDREG_GET_STATE() != IPMI_KCS_STATE_IDLE) {
-        retries--;
-        goto retry_abort;
-    }
-    kcs_wait_obf();
-    kcs_clear_obf();
-
-    *rsp_len = j;
-}
-
-
-static uint8_t get_dev_id_cmd[] = { 0x18, 0x01 };
-static uint8_t get_dev_id_rsp[] = { 0x1c, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
-                                    0x02, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-/*
- * Send a get_device_id to do a basic test.
- */
-static void test_kcs_base(void)
-{
-    uint8_t rsp[20];
-    unsigned int rsplen = sizeof(rsp);
-
-    kcs_cmd(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen);
-    g_assert(rsplen == sizeof(get_dev_id_rsp));
-    g_assert(memcmp(get_dev_id_rsp, rsp, rsplen) == 0);
-}
-
-/*
- * Abort a kcs operation while reading
- */
-static void test_kcs_abort(void)
-{
-    uint8_t rsp[20];
-    unsigned int rsplen = sizeof(rsp);
-
-    kcs_abort(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen);
-    g_assert(rsp[0] == IPMI_KCS_ABORTED_BY_CMD);
-}
-
-static uint8_t set_bmc_globals_cmd[] = { 0x18, 0x2e, 0x0f };
-static uint8_t set_bmc_globals_rsp[] = { 0x1c, 0x2e, 0x00 };
-
-/*
- * Enable interrupts
- */
-static void test_enable_irq(void)
-{
-    uint8_t rsp[20];
-    unsigned int rsplen = sizeof(rsp);
-
-    kcs_cmd(set_bmc_globals_cmd, sizeof(set_bmc_globals_cmd), rsp, &rsplen);
-    g_assert(rsplen == sizeof(set_bmc_globals_rsp));
-    g_assert(memcmp(set_bmc_globals_rsp, rsp, rsplen) == 0);
-    kcs_ints_enabled = 1;
-}
-
-int main(int argc, char **argv)
-{
-    char *cmdline;
-    int ret;
-
-    /* Run the tests */
-    g_test_init(&argc, &argv, NULL);
-
-    cmdline = g_strdup_printf("-device ipmi-bmc-sim,id=bmc0"
-                              " -device isa-ipmi-kcs,bmc=bmc0");
-    qtest_start(cmdline);
-    g_free(cmdline);
-    qtest_irq_intercept_in(global_qtest, "ioapic");
-    qtest_add_func("/ipmi/local/kcs_base", test_kcs_base);
-    qtest_add_func("/ipmi/local/kcs_abort", test_kcs_abort);
-    qtest_add_func("/ipmi/local/kcs_enable_irq", test_enable_irq);
-    qtest_add_func("/ipmi/local/kcs_base_irq", test_kcs_base);
-    qtest_add_func("/ipmi/local/kcs_abort_irq", test_kcs_abort);
-    ret = g_test_run();
-    qtest_quit(global_qtest);
-
-    return ret;
-}
diff --git a/tests/ipoctal232-test.c b/tests/ipoctal232-test.c
deleted file mode 100644 (file)
index 53a8c9b..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * QTest testcase for IndustryPack Octal-RS232
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qemu/module.h"
-#include "libqos/qgraph.h"
-
-typedef struct QIpoctal232 QIpoctal232;
-
-struct QIpoctal232 {
-    QOSGraphObject obj;
-};
-
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void nop(void *obj, void *data, QGuestAllocator *alloc)
-{
-}
-
-static void *ipoctal232_create(void *pci_bus, QGuestAllocator *alloc,
-                               void *addr)
-{
-    QIpoctal232 *ipoctal232 = g_new0(QIpoctal232, 1);
-
-    return &ipoctal232->obj;
-}
-
-static void ipoctal232_register_nodes(void)
-{
-    qos_node_create_driver("ipoctal232", ipoctal232_create);
-    qos_node_consumes("ipoctal232", "ipack", &(QOSGraphEdgeOptions) {
-        .extra_device_opts = "bus=ipack0.0",
-    });
-}
-
-libqos_init(ipoctal232_register_nodes);
-
-static void register_ipoctal232_test(void)
-{
-    qos_add_test("nop", "ipoctal232", nop, NULL);
-}
-
-libqos_init(register_ipoctal232_test);
diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
deleted file mode 100644 (file)
index ecda256..0000000
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * QTest testcase for ivshmem
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- * Copyright (c) 2015 Red Hat, Inc.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include <glib/gstdio.h>
-#include "contrib/ivshmem-server/ivshmem-server.h"
-#include "libqos/libqos-pc.h"
-#include "libqos/libqos-spapr.h"
-#include "libqtest.h"
-#include "qemu-common.h"
-
-#define TMPSHMSIZE (1 << 20)
-static char *tmpshm;
-static void *tmpshmem;
-static char *tmpdir;
-static char *tmpserver;
-
-static void save_fn(QPCIDevice *dev, int devfn, void *data)
-{
-    QPCIDevice **pdev = (QPCIDevice **) data;
-
-    *pdev = dev;
-}
-
-static QPCIDevice *get_device(QPCIBus *pcibus)
-{
-    QPCIDevice *dev;
-
-    dev = NULL;
-    qpci_device_foreach(pcibus, 0x1af4, 0x1110, save_fn, &dev);
-    g_assert(dev != NULL);
-
-    return dev;
-}
-
-typedef struct _IVState {
-    QOSState *qs;
-    QPCIBar reg_bar, mem_bar;
-    QPCIDevice *dev;
-} IVState;
-
-enum Reg {
-    INTRMASK = 0,
-    INTRSTATUS = 4,
-    IVPOSITION = 8,
-    DOORBELL = 12,
-};
-
-static const char* reg2str(enum Reg reg) {
-    switch (reg) {
-    case INTRMASK:
-        return "IntrMask";
-    case INTRSTATUS:
-        return "IntrStatus";
-    case IVPOSITION:
-        return "IVPosition";
-    case DOORBELL:
-        return "DoorBell";
-    default:
-        return NULL;
-    }
-}
-
-static inline unsigned in_reg(IVState *s, enum Reg reg)
-{
-    const char *name = reg2str(reg);
-    unsigned res;
-
-    res = qpci_io_readl(s->dev, s->reg_bar, reg);
-    g_test_message("*%s -> %x", name, res);
-
-    return res;
-}
-
-static inline void out_reg(IVState *s, enum Reg reg, unsigned v)
-{
-    const char *name = reg2str(reg);
-
-    g_test_message("%x -> *%s", v, name);
-    qpci_io_writel(s->dev, s->reg_bar, reg, v);
-}
-
-static inline void read_mem(IVState *s, uint64_t off, void *buf, size_t len)
-{
-    qpci_memread(s->dev, s->mem_bar, off, buf, len);
-}
-
-static inline void write_mem(IVState *s, uint64_t off,
-                             const void *buf, size_t len)
-{
-    qpci_memwrite(s->dev, s->mem_bar, off, buf, len);
-}
-
-static void cleanup_vm(IVState *s)
-{
-    g_free(s->dev);
-    qtest_shutdown(s->qs);
-}
-
-static void setup_vm_cmd(IVState *s, const char *cmd, bool msix)
-{
-    uint64_t barsize;
-    const char *arch = qtest_get_arch();
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        s->qs = qtest_pc_boot(cmd);
-    } else if (strcmp(arch, "ppc64") == 0) {
-        s->qs = qtest_spapr_boot(cmd);
-    } else {
-        g_printerr("ivshmem-test tests are only available on x86 or ppc64\n");
-        exit(EXIT_FAILURE);
-    }
-    s->dev = get_device(s->qs->pcibus);
-
-    s->reg_bar = qpci_iomap(s->dev, 0, &barsize);
-    g_assert_cmpuint(barsize, ==, 256);
-
-    if (msix) {
-        qpci_msix_enable(s->dev);
-    }
-
-    s->mem_bar = qpci_iomap(s->dev, 2, &barsize);
-    g_assert_cmpuint(barsize, ==, TMPSHMSIZE);
-
-    qpci_device_enable(s->dev);
-}
-
-static void setup_vm(IVState *s)
-{
-    char *cmd = g_strdup_printf("-object memory-backend-file"
-                                ",id=mb1,size=1M,share,mem-path=/dev/shm%s"
-                                " -device ivshmem-plain,memdev=mb1", tmpshm);
-
-    setup_vm_cmd(s, cmd, false);
-
-    g_free(cmd);
-}
-
-static void test_ivshmem_single(void)
-{
-    IVState state, *s;
-    uint32_t data[1024];
-    int i;
-
-    setup_vm(&state);
-    s = &state;
-
-    /* initial state of readable registers */
-    g_assert_cmpuint(in_reg(s, INTRMASK), ==, 0);
-    g_assert_cmpuint(in_reg(s, INTRSTATUS), ==, 0);
-    g_assert_cmpuint(in_reg(s, IVPOSITION), ==, 0);
-
-    /* trigger interrupt via registers */
-    out_reg(s, INTRMASK, 0xffffffff);
-    g_assert_cmpuint(in_reg(s, INTRMASK), ==, 0xffffffff);
-    out_reg(s, INTRSTATUS, 1);
-    /* check interrupt status */
-    g_assert_cmpuint(in_reg(s, INTRSTATUS), ==, 1);
-    /* reading clears */
-    g_assert_cmpuint(in_reg(s, INTRSTATUS), ==, 0);
-    /* TODO intercept actual interrupt (needs qtest work) */
-
-    /* invalid register access */
-    out_reg(s, IVPOSITION, 1);
-    in_reg(s, DOORBELL);
-
-    /* ring the (non-functional) doorbell */
-    out_reg(s, DOORBELL, 8 << 16);
-
-    /* write shared memory */
-    for (i = 0; i < G_N_ELEMENTS(data); i++) {
-        data[i] = i;
-    }
-    write_mem(s, 0, data, sizeof(data));
-
-    /* verify write */
-    for (i = 0; i < G_N_ELEMENTS(data); i++) {
-        g_assert_cmpuint(((uint32_t *)tmpshmem)[i], ==, i);
-    }
-
-    /* read it back and verify read */
-    memset(data, 0, sizeof(data));
-    read_mem(s, 0, data, sizeof(data));
-    for (i = 0; i < G_N_ELEMENTS(data); i++) {
-        g_assert_cmpuint(data[i], ==, i);
-    }
-
-    cleanup_vm(s);
-}
-
-static void test_ivshmem_pair(void)
-{
-    IVState state1, state2, *s1, *s2;
-    char *data;
-    int i;
-
-    setup_vm(&state1);
-    s1 = &state1;
-    setup_vm(&state2);
-    s2 = &state2;
-
-    data = g_malloc0(TMPSHMSIZE);
-
-    /* host write, guest 1 & 2 read */
-    memset(tmpshmem, 0x42, TMPSHMSIZE);
-    read_mem(s1, 0, data, TMPSHMSIZE);
-    for (i = 0; i < TMPSHMSIZE; i++) {
-        g_assert_cmpuint(data[i], ==, 0x42);
-    }
-    read_mem(s2, 0, data, TMPSHMSIZE);
-    for (i = 0; i < TMPSHMSIZE; i++) {
-        g_assert_cmpuint(data[i], ==, 0x42);
-    }
-
-    /* guest 1 write, guest 2 read */
-    memset(data, 0x43, TMPSHMSIZE);
-    write_mem(s1, 0, data, TMPSHMSIZE);
-    memset(data, 0, TMPSHMSIZE);
-    read_mem(s2, 0, data, TMPSHMSIZE);
-    for (i = 0; i < TMPSHMSIZE; i++) {
-        g_assert_cmpuint(data[i], ==, 0x43);
-    }
-
-    /* guest 2 write, guest 1 read */
-    memset(data, 0x44, TMPSHMSIZE);
-    write_mem(s2, 0, data, TMPSHMSIZE);
-    memset(data, 0, TMPSHMSIZE);
-    read_mem(s1, 0, data, TMPSHMSIZE);
-    for (i = 0; i < TMPSHMSIZE; i++) {
-        g_assert_cmpuint(data[i], ==, 0x44);
-    }
-
-    cleanup_vm(s1);
-    cleanup_vm(s2);
-    g_free(data);
-}
-
-typedef struct ServerThread {
-    GThread *thread;
-    IvshmemServer *server;
-    int pipe[2]; /* to handle quit */
-} ServerThread;
-
-static void *server_thread(void *data)
-{
-    ServerThread *t = data;
-    IvshmemServer *server = t->server;
-
-    while (true) {
-        fd_set fds;
-        int maxfd, ret;
-
-        FD_ZERO(&fds);
-        FD_SET(t->pipe[0], &fds);
-        maxfd = t->pipe[0] + 1;
-
-        ivshmem_server_get_fds(server, &fds, &maxfd);
-
-        ret = select(maxfd, &fds, NULL, NULL, NULL);
-
-        if (ret < 0) {
-            if (errno == EINTR) {
-                continue;
-            }
-
-            g_critical("select error: %s\n", strerror(errno));
-            break;
-        }
-        if (ret == 0) {
-            continue;
-        }
-
-        if (FD_ISSET(t->pipe[0], &fds)) {
-            break;
-        }
-
-        if (ivshmem_server_handle_fds(server, &fds, maxfd) < 0) {
-            g_critical("ivshmem_server_handle_fds() failed\n");
-            break;
-        }
-    }
-
-    return NULL;
-}
-
-static void setup_vm_with_server(IVState *s, int nvectors)
-{
-    char *cmd;
-
-    cmd = g_strdup_printf("-chardev socket,id=chr0,path=%s "
-                          "-device ivshmem-doorbell,chardev=chr0,vectors=%d",
-                          tmpserver, nvectors);
-
-    setup_vm_cmd(s, cmd, true);
-
-    g_free(cmd);
-}
-
-static void test_ivshmem_server(void)
-{
-    IVState state1, state2, *s1, *s2;
-    ServerThread thread;
-    IvshmemServer server;
-    int ret, vm1, vm2;
-    int nvectors = 2;
-    guint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
-
-    ret = ivshmem_server_init(&server, tmpserver, tmpshm, true,
-                              TMPSHMSIZE, nvectors,
-                              g_test_verbose());
-    g_assert_cmpint(ret, ==, 0);
-
-    ret = ivshmem_server_start(&server);
-    g_assert_cmpint(ret, ==, 0);
-
-    thread.server = &server;
-    ret = pipe(thread.pipe);
-    g_assert_cmpint(ret, ==, 0);
-    thread.thread = g_thread_new("ivshmem-server", server_thread, &thread);
-    g_assert(thread.thread != NULL);
-
-    setup_vm_with_server(&state1, nvectors);
-    s1 = &state1;
-    setup_vm_with_server(&state2, nvectors);
-    s2 = &state2;
-
-    /* check got different VM ids */
-    vm1 = in_reg(s1, IVPOSITION);
-    vm2 = in_reg(s2, IVPOSITION);
-    g_assert_cmpint(vm1, >=, 0);
-    g_assert_cmpint(vm2, >=, 0);
-    g_assert_cmpint(vm1, !=, vm2);
-
-    /* check number of MSI-X vectors */
-    ret = qpci_msix_table_size(s1->dev);
-    g_assert_cmpuint(ret, ==, nvectors);
-
-    /* TODO test behavior before MSI-X is enabled */
-
-    /* ping vm2 -> vm1 on vector 0 */
-    ret = qpci_msix_pending(s1->dev, 0);
-    g_assert_cmpuint(ret, ==, 0);
-    out_reg(s2, DOORBELL, vm1 << 16);
-    do {
-        g_usleep(10000);
-        ret = qpci_msix_pending(s1->dev, 0);
-    } while (ret == 0 && g_get_monotonic_time() < end_time);
-    g_assert_cmpuint(ret, !=, 0);
-
-    /* ping vm1 -> vm2 on vector 1 */
-    ret = qpci_msix_pending(s2->dev, 1);
-    g_assert_cmpuint(ret, ==, 0);
-    out_reg(s1, DOORBELL, vm2 << 16 | 1);
-    do {
-        g_usleep(10000);
-        ret = qpci_msix_pending(s2->dev, 1);
-    } while (ret == 0 && g_get_monotonic_time() < end_time);
-    g_assert_cmpuint(ret, !=, 0);
-
-    cleanup_vm(s2);
-    cleanup_vm(s1);
-
-    if (qemu_write_full(thread.pipe[1], "q", 1) != 1) {
-        g_error("qemu_write_full: %s", g_strerror(errno));
-    }
-
-    g_thread_join(thread.thread);
-
-    ivshmem_server_close(&server);
-    close(thread.pipe[1]);
-    close(thread.pipe[0]);
-}
-
-#define PCI_SLOT_HP             0x06
-
-static void test_ivshmem_hotplug(void)
-{
-    QTestState *qts;
-    const char *arch = qtest_get_arch();
-
-    qts = qtest_init("-object memory-backend-ram,size=1M,id=mb1");
-
-    qtest_qmp_device_add(qts, "ivshmem-plain", "iv1",
-                         "{'addr': %s, 'memdev': 'mb1'}",
-                         stringify(PCI_SLOT_HP));
-    if (strcmp(arch, "ppc64") != 0) {
-        qpci_unplug_acpi_device_test(qts, "iv1", PCI_SLOT_HP);
-    }
-
-    qtest_quit(qts);
-}
-
-static void test_ivshmem_memdev(void)
-{
-    IVState state;
-
-    /* just for the sake of checking memory-backend property */
-    setup_vm_cmd(&state, "-object memory-backend-ram,size=1M,id=mb1"
-                 " -device ivshmem-plain,memdev=mb1", false);
-
-    cleanup_vm(&state);
-}
-
-static void cleanup(void)
-{
-    if (tmpshmem) {
-        munmap(tmpshmem, TMPSHMSIZE);
-        tmpshmem = NULL;
-    }
-
-    if (tmpshm) {
-        shm_unlink(tmpshm);
-        g_free(tmpshm);
-        tmpshm = NULL;
-    }
-
-    if (tmpserver) {
-        g_unlink(tmpserver);
-        g_free(tmpserver);
-        tmpserver = NULL;
-    }
-
-    if (tmpdir) {
-        g_rmdir(tmpdir);
-        tmpdir = NULL;
-    }
-}
-
-static void abrt_handler(void *data)
-{
-    cleanup();
-}
-
-static gchar *mktempshm(int size, int *fd)
-{
-    while (true) {
-        gchar *name;
-
-        name = g_strdup_printf("/qtest-%u-%u", getpid(), g_test_rand_int());
-        *fd = shm_open(name, O_CREAT|O_RDWR|O_EXCL,
-                       S_IRWXU|S_IRWXG|S_IRWXO);
-        if (*fd > 0) {
-            g_assert(ftruncate(*fd, size) == 0);
-            return name;
-        }
-
-        g_free(name);
-
-        if (errno != EEXIST) {
-            perror("shm_open");
-            return NULL;
-        }
-    }
-}
-
-int main(int argc, char **argv)
-{
-    int ret, fd;
-    const char *arch = qtest_get_arch();
-    gchar dir[] = "/tmp/ivshmem-test.XXXXXX";
-
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_abrt_handler(abrt_handler, NULL);
-    /* shm */
-    tmpshm = mktempshm(TMPSHMSIZE, &fd);
-    if (!tmpshm) {
-        goto out;
-    }
-    tmpshmem = mmap(0, TMPSHMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
-    g_assert(tmpshmem != MAP_FAILED);
-    /* server */
-    if (mkdtemp(dir) == NULL) {
-        g_error("mkdtemp: %s", g_strerror(errno));
-    }
-    tmpdir = dir;
-    tmpserver = g_strconcat(tmpdir, "/server", NULL);
-
-    qtest_add_func("/ivshmem/single", test_ivshmem_single);
-    qtest_add_func("/ivshmem/hotplug", test_ivshmem_hotplug);
-    qtest_add_func("/ivshmem/memdev", test_ivshmem_memdev);
-    if (g_test_slow()) {
-        qtest_add_func("/ivshmem/pair", test_ivshmem_pair);
-        if (strcmp(arch, "ppc64") != 0) {
-            qtest_add_func("/ivshmem/server", test_ivshmem_server);
-        }
-    }
-
-out:
-    ret = g_test_run();
-    cleanup();
-    return ret;
-}
diff --git a/tests/libqtest-single.h b/tests/libqtest-single.h
deleted file mode 100644 (file)
index 6f1bb13..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * QTest - wrappers for test with single QEMU instances
- *
- * Copyright IBM, Corp. 2012
- * Copyright Red Hat, Inc. 2012
- * Copyright SUSE LINUX Products GmbH 2013
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#ifndef LIBQTEST_SINGLE_H
-#define LIBQTEST_SINGLE_H
-
-#include "libqtest.h"
-
-QTestState *global_qtest __attribute__((common, weak));
-
-/**
- * qtest_start:
- * @args: other arguments to pass to QEMU
- *
- * Start QEMU and assign the resulting #QTestState to a global variable.
- * The global variable is used by "shortcut" functions documented below.
- *
- * Returns: #QTestState instance.
- */
-static inline QTestState *qtest_start(const char *args)
-{
-    global_qtest = qtest_init(args);
-    return global_qtest;
-}
-
-/**
- * qtest_end:
- *
- * Shut down the QEMU process started by qtest_start().
- */
-static inline void qtest_end(void)
-{
-    if (!global_qtest) {
-        return;
-    }
-    qtest_quit(global_qtest);
-    global_qtest = NULL;
-}
-
-/**
- * qmp:
- * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail().  See parse_escape() for what's
- * supported after '%'.
- *
- * Sends a QMP message to QEMU and returns the response.
- */
-GCC_FMT_ATTR(1, 2)
-static inline QDict *qmp(const char *fmt, ...)
-{
-    va_list ap;
-    QDict *response;
-
-    va_start(ap, fmt);
-    response = qtest_vqmp(global_qtest, fmt, ap);
-    va_end(ap);
-    return response;
-}
-
-/**
- * qmp_eventwait:
- * @s: #event event to wait for.
- *
- * Continuously polls for QMP responses until it receives the desired event.
- */
-static inline void qmp_eventwait(const char *event)
-{
-    return qtest_qmp_eventwait(global_qtest, event);
-}
-
-/**
- * get_irq:
- * @num: Interrupt to observe.
- *
- * Returns: The level of the @num interrupt.
- */
-static inline bool get_irq(int num)
-{
-    return qtest_get_irq(global_qtest, num);
-}
-
-/**
- * outb:
- * @addr: I/O port to write to.
- * @value: Value being written.
- *
- * Write an 8-bit value to an I/O port.
- */
-static inline void outb(uint16_t addr, uint8_t value)
-{
-    qtest_outb(global_qtest, addr, value);
-}
-
-/**
- * outw:
- * @addr: I/O port to write to.
- * @value: Value being written.
- *
- * Write a 16-bit value to an I/O port.
- */
-static inline void outw(uint16_t addr, uint16_t value)
-{
-    qtest_outw(global_qtest, addr, value);
-}
-
-/**
- * outl:
- * @addr: I/O port to write to.
- * @value: Value being written.
- *
- * Write a 32-bit value to an I/O port.
- */
-static inline void outl(uint16_t addr, uint32_t value)
-{
-    qtest_outl(global_qtest, addr, value);
-}
-
-/**
- * inb:
- * @addr: I/O port to read from.
- *
- * Reads an 8-bit value from an I/O port.
- *
- * Returns: Value read.
- */
-static inline uint8_t inb(uint16_t addr)
-{
-    return qtest_inb(global_qtest, addr);
-}
-
-/**
- * inw:
- * @addr: I/O port to read from.
- *
- * Reads a 16-bit value from an I/O port.
- *
- * Returns: Value read.
- */
-static inline uint16_t inw(uint16_t addr)
-{
-    return qtest_inw(global_qtest, addr);
-}
-
-/**
- * inl:
- * @addr: I/O port to read from.
- *
- * Reads a 32-bit value from an I/O port.
- *
- * Returns: Value read.
- */
-static inline uint32_t inl(uint16_t addr)
-{
-    return qtest_inl(global_qtest, addr);
-}
-
-/**
- * writeb:
- * @addr: Guest address to write to.
- * @value: Value being written.
- *
- * Writes an 8-bit value to guest memory.
- */
-static inline void writeb(uint64_t addr, uint8_t value)
-{
-    qtest_writeb(global_qtest, addr, value);
-}
-
-/**
- * writew:
- * @addr: Guest address to write to.
- * @value: Value being written.
- *
- * Writes a 16-bit value to guest memory.
- */
-static inline void writew(uint64_t addr, uint16_t value)
-{
-    qtest_writew(global_qtest, addr, value);
-}
-
-/**
- * writel:
- * @addr: Guest address to write to.
- * @value: Value being written.
- *
- * Writes a 32-bit value to guest memory.
- */
-static inline void writel(uint64_t addr, uint32_t value)
-{
-    qtest_writel(global_qtest, addr, value);
-}
-
-/**
- * writeq:
- * @addr: Guest address to write to.
- * @value: Value being written.
- *
- * Writes a 64-bit value to guest memory.
- */
-static inline void writeq(uint64_t addr, uint64_t value)
-{
-    qtest_writeq(global_qtest, addr, value);
-}
-
-/**
- * readb:
- * @addr: Guest address to read from.
- *
- * Reads an 8-bit value from guest memory.
- *
- * Returns: Value read.
- */
-static inline uint8_t readb(uint64_t addr)
-{
-    return qtest_readb(global_qtest, addr);
-}
-
-/**
- * readw:
- * @addr: Guest address to read from.
- *
- * Reads a 16-bit value from guest memory.
- *
- * Returns: Value read.
- */
-static inline uint16_t readw(uint64_t addr)
-{
-    return qtest_readw(global_qtest, addr);
-}
-
-/**
- * readl:
- * @addr: Guest address to read from.
- *
- * Reads a 32-bit value from guest memory.
- *
- * Returns: Value read.
- */
-static inline uint32_t readl(uint64_t addr)
-{
-    return qtest_readl(global_qtest, addr);
-}
-
-/**
- * readq:
- * @addr: Guest address to read from.
- *
- * Reads a 64-bit value from guest memory.
- *
- * Returns: Value read.
- */
-static inline uint64_t readq(uint64_t addr)
-{
-    return qtest_readq(global_qtest, addr);
-}
-
-/**
- * memread:
- * @addr: Guest address to read from.
- * @data: Pointer to where memory contents will be stored.
- * @size: Number of bytes to read.
- *
- * Read guest memory into a buffer.
- */
-static inline void memread(uint64_t addr, void *data, size_t size)
-{
-    qtest_memread(global_qtest, addr, data, size);
-}
-
-/**
- * memwrite:
- * @addr: Guest address to write to.
- * @data: Pointer to the bytes that will be written to guest memory.
- * @size: Number of bytes to write.
- *
- * Write a buffer to guest memory.
- */
-static inline void memwrite(uint64_t addr, const void *data, size_t size)
-{
-    qtest_memwrite(global_qtest, addr, data, size);
-}
-
-/**
- * clock_step_next:
- *
- * Advance the QEMU_CLOCK_VIRTUAL to the next deadline.
- *
- * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
- */
-static inline int64_t clock_step_next(void)
-{
-    return qtest_clock_step_next(global_qtest);
-}
-
-/**
- * clock_step:
- * @step: Number of nanoseconds to advance the clock by.
- *
- * Advance the QEMU_CLOCK_VIRTUAL by @step nanoseconds.
- *
- * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
- */
-static inline int64_t clock_step(int64_t step)
-{
-    return qtest_clock_step(global_qtest, step);
-}
-
-#endif
diff --git a/tests/libqtest.c b/tests/libqtest.c
deleted file mode 100644 (file)
index 76c9f8e..0000000
+++ /dev/null
@@ -1,1339 +0,0 @@
-/*
- * QTest
- *
- * Copyright IBM, Corp. 2012
- * Copyright Red Hat, Inc. 2012
- * Copyright SUSE LINUX Products GmbH 2013
- *
- * Authors:
- *  Anthony Liguori   <[email protected]>
- *  Paolo Bonzini     <[email protected]>
- *  Andreas Färber    <[email protected]>
- *
- * 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 <sys/socket.h>
-#include <sys/wait.h>
-#include <sys/un.h>
-
-#include "libqtest.h"
-#include "qemu-common.h"
-#include "qemu/ctype.h"
-#include "qemu/cutils.h"
-#include "qapi/error.h"
-#include "qapi/qmp/json-parser.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qjson.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qstring.h"
-
-#define MAX_IRQ 256
-#define SOCKET_TIMEOUT 50
-#define SOCKET_MAX_FDS 16
-
-struct QTestState
-{
-    int fd;
-    int qmp_fd;
-    pid_t qemu_pid;  /* our child QEMU process */
-    int wstatus;
-    int expected_status;
-    bool big_endian;
-    bool irq_level[MAX_IRQ];
-    GString *rx;
-};
-
-static GHookList abrt_hooks;
-static struct sigaction sigact_old;
-
-static int qtest_query_target_endianness(QTestState *s);
-
-static int init_socket(const char *socket_path)
-{
-    struct sockaddr_un addr;
-    int sock;
-    int ret;
-
-    sock = socket(PF_UNIX, SOCK_STREAM, 0);
-    g_assert_cmpint(sock, !=, -1);
-
-    addr.sun_family = AF_UNIX;
-    snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path);
-    qemu_set_cloexec(sock);
-
-    do {
-        ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
-    } while (ret == -1 && errno == EINTR);
-    g_assert_cmpint(ret, !=, -1);
-    ret = listen(sock, 1);
-    g_assert_cmpint(ret, !=, -1);
-
-    return sock;
-}
-
-static int socket_accept(int sock)
-{
-    struct sockaddr_un addr;
-    socklen_t addrlen;
-    int ret;
-    struct timeval timeout = { .tv_sec = SOCKET_TIMEOUT,
-                               .tv_usec = 0 };
-
-    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout,
-               sizeof(timeout));
-
-    do {
-        addrlen = sizeof(addr);
-        ret = accept(sock, (struct sockaddr *)&addr, &addrlen);
-    } while (ret == -1 && errno == EINTR);
-    if (ret == -1) {
-        fprintf(stderr, "%s failed: %s\n", __func__, strerror(errno));
-    }
-    close(sock);
-
-    return ret;
-}
-
-bool qtest_probe_child(QTestState *s)
-{
-    pid_t pid = s->qemu_pid;
-
-    if (pid != -1) {
-        pid = waitpid(pid, &s->wstatus, WNOHANG);
-        if (pid == 0) {
-            return true;
-        }
-        s->qemu_pid = -1;
-    }
-    return false;
-}
-
-void qtest_set_expected_status(QTestState *s, int status)
-{
-    s->expected_status = status;
-}
-
-static void kill_qemu(QTestState *s)
-{
-    pid_t pid = s->qemu_pid;
-    int wstatus;
-
-    /* Skip wait if qtest_probe_child already reaped.  */
-    if (pid != -1) {
-        kill(pid, SIGTERM);
-        TFR(pid = waitpid(s->qemu_pid, &s->wstatus, 0));
-        assert(pid == s->qemu_pid);
-    }
-
-    /*
-     * Check whether qemu exited with expected exit status; anything else is
-     * fishy and should be logged with as much detail as possible.
-     */
-    wstatus = s->wstatus;
-    if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != s->expected_status) {
-        fprintf(stderr, "%s:%d: kill_qemu() tried to terminate QEMU "
-                "process but encountered exit status %d (expected %d)\n",
-                __FILE__, __LINE__, WEXITSTATUS(wstatus), s->expected_status);
-        abort();
-    } else if (WIFSIGNALED(wstatus)) {
-        int sig = WTERMSIG(wstatus);
-        const char *signame = strsignal(sig) ?: "unknown ???";
-        const char *dump = WCOREDUMP(wstatus) ? " (core dumped)" : "";
-
-        fprintf(stderr, "%s:%d: kill_qemu() detected QEMU death "
-                "from signal %d (%s)%s\n",
-                __FILE__, __LINE__, sig, signame, dump);
-        abort();
-    }
-}
-
-static void kill_qemu_hook_func(void *s)
-{
-    kill_qemu(s);
-}
-
-static void sigabrt_handler(int signo)
-{
-    g_hook_list_invoke(&abrt_hooks, FALSE);
-}
-
-static void setup_sigabrt_handler(void)
-{
-    struct sigaction sigact;
-
-    /* Catch SIGABRT to clean up on g_assert() failure */
-    sigact = (struct sigaction){
-        .sa_handler = sigabrt_handler,
-        .sa_flags = SA_RESETHAND,
-    };
-    sigemptyset(&sigact.sa_mask);
-    sigaction(SIGABRT, &sigact, &sigact_old);
-}
-
-static void cleanup_sigabrt_handler(void)
-{
-    sigaction(SIGABRT, &sigact_old, NULL);
-}
-
-void qtest_add_abrt_handler(GHookFunc fn, const void *data)
-{
-    GHook *hook;
-
-    /* Only install SIGABRT handler once */
-    if (!abrt_hooks.is_setup) {
-        g_hook_list_init(&abrt_hooks, sizeof(GHook));
-    }
-    setup_sigabrt_handler();
-
-    hook = g_hook_alloc(&abrt_hooks);
-    hook->func = fn;
-    hook->data = (void *)data;
-
-    g_hook_prepend(&abrt_hooks, hook);
-}
-
-static const char *qtest_qemu_binary(void)
-{
-    const char *qemu_bin;
-
-    qemu_bin = getenv("QTEST_QEMU_BINARY");
-    if (!qemu_bin) {
-        fprintf(stderr, "Environment variable QTEST_QEMU_BINARY required\n");
-        exit(1);
-    }
-
-    return qemu_bin;
-}
-
-QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
-{
-    QTestState *s;
-    int sock, qmpsock, i;
-    gchar *socket_path;
-    gchar *qmp_socket_path;
-    gchar *command;
-    const char *qemu_binary = qtest_qemu_binary();
-
-    s = g_new(QTestState, 1);
-
-    socket_path = g_strdup_printf("/tmp/qtest-%d.sock", getpid());
-    qmp_socket_path = g_strdup_printf("/tmp/qtest-%d.qmp", getpid());
-
-    /* It's possible that if an earlier test run crashed it might
-     * have left a stale unix socket lying around. Delete any
-     * stale old socket to avoid spurious test failures with
-     * tests/libqtest.c:70:init_socket: assertion failed (ret != -1): (-1 != -1)
-     */
-    unlink(socket_path);
-    unlink(qmp_socket_path);
-
-    sock = init_socket(socket_path);
-    qmpsock = init_socket(qmp_socket_path);
-
-    qtest_add_abrt_handler(kill_qemu_hook_func, s);
-
-    command = g_strdup_printf("exec %s "
-                              "-qtest unix:%s "
-                              "-qtest-log %s "
-                              "-chardev socket,path=%s,id=char0 "
-                              "-mon chardev=char0,mode=control "
-                              "-display none "
-                              "%s"
-                              " -accel qtest", qemu_binary, socket_path,
-                              getenv("QTEST_LOG") ? "/dev/fd/2" : "/dev/null",
-                              qmp_socket_path,
-                              extra_args ?: "");
-
-    g_test_message("starting QEMU: %s", command);
-
-    s->wstatus = 0;
-    s->expected_status = 0;
-    s->qemu_pid = fork();
-    if (s->qemu_pid == 0) {
-        g_setenv("QEMU_AUDIO_DRV", "none", true);
-        execlp("/bin/sh", "sh", "-c", command, NULL);
-        exit(1);
-    }
-
-    g_free(command);
-    s->fd = socket_accept(sock);
-    if (s->fd >= 0) {
-        s->qmp_fd = socket_accept(qmpsock);
-    }
-    unlink(socket_path);
-    unlink(qmp_socket_path);
-    g_free(socket_path);
-    g_free(qmp_socket_path);
-
-    g_assert(s->fd >= 0 && s->qmp_fd >= 0);
-
-    s->rx = g_string_new("");
-    for (i = 0; i < MAX_IRQ; i++) {
-        s->irq_level[i] = false;
-    }
-
-    if (getenv("QTEST_STOP")) {
-        kill(s->qemu_pid, SIGSTOP);
-    }
-
-    /* ask endianness of the target */
-
-    s->big_endian = qtest_query_target_endianness(s);
-
-    return s;
-}
-
-QTestState *qtest_init(const char *extra_args)
-{
-    QTestState *s = qtest_init_without_qmp_handshake(extra_args);
-    QDict *greeting;
-
-    /* Read the QMP greeting and then do the handshake */
-    greeting = qtest_qmp_receive(s);
-    qobject_unref(greeting);
-    qobject_unref(qtest_qmp(s, "{ 'execute': 'qmp_capabilities' }"));
-
-    return s;
-}
-
-QTestState *qtest_vinitf(const char *fmt, va_list ap)
-{
-    char *args = g_strdup_vprintf(fmt, ap);
-    QTestState *s;
-
-    s = qtest_init(args);
-    g_free(args);
-    return s;
-}
-
-QTestState *qtest_initf(const char *fmt, ...)
-{
-    va_list ap;
-    QTestState *s;
-
-    va_start(ap, fmt);
-    s = qtest_vinitf(fmt, ap);
-    va_end(ap);
-    return s;
-}
-
-QTestState *qtest_init_with_serial(const char *extra_args, int *sock_fd)
-{
-    int sock_fd_init;
-    char *sock_path, sock_dir[] = "/tmp/qtest-serial-XXXXXX";
-    QTestState *qts;
-
-    g_assert_true(mkdtemp(sock_dir) != NULL);
-    sock_path = g_strdup_printf("%s/sock", sock_dir);
-
-    sock_fd_init = init_socket(sock_path);
-
-    qts = qtest_initf("-chardev socket,id=s0,path=%s -serial chardev:s0 %s",
-                      sock_path, extra_args);
-
-    *sock_fd = socket_accept(sock_fd_init);
-
-    unlink(sock_path);
-    g_free(sock_path);
-    rmdir(sock_dir);
-
-    g_assert_true(*sock_fd >= 0);
-
-    return qts;
-}
-
-void qtest_quit(QTestState *s)
-{
-    g_hook_destroy_link(&abrt_hooks, g_hook_find_data(&abrt_hooks, TRUE, s));
-
-    /* Uninstall SIGABRT handler on last instance */
-    cleanup_sigabrt_handler();
-
-    kill_qemu(s);
-    close(s->fd);
-    close(s->qmp_fd);
-    g_string_free(s->rx, true);
-    g_free(s);
-}
-
-static void socket_send(int fd, const char *buf, size_t size)
-{
-    size_t offset;
-
-    offset = 0;
-    while (offset < size) {
-        ssize_t len;
-
-        len = write(fd, buf + offset, size - offset);
-        if (len == -1 && errno == EINTR) {
-            continue;
-        }
-
-        g_assert_cmpint(len, >, 0);
-
-        offset += len;
-    }
-}
-
-static void socket_sendf(int fd, const char *fmt, va_list ap)
-{
-    gchar *str = g_strdup_vprintf(fmt, ap);
-    size_t size = strlen(str);
-
-    socket_send(fd, str, size);
-    g_free(str);
-}
-
-static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    socket_sendf(s->fd, fmt, ap);
-    va_end(ap);
-}
-
-/* Sends a message and file descriptors to the socket.
- * It's needed for qmp-commands like getfd/add-fd */
-static void socket_send_fds(int socket_fd, int *fds, size_t fds_num,
-                            const char *buf, size_t buf_size)
-{
-    ssize_t ret;
-    struct msghdr msg = { 0 };
-    char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)] = { 0 };
-    size_t fdsize = sizeof(int) * fds_num;
-    struct cmsghdr *cmsg;
-    struct iovec iov = { .iov_base = (char *)buf, .iov_len = buf_size };
-
-    msg.msg_iov = &iov;
-    msg.msg_iovlen = 1;
-
-    if (fds && fds_num > 0) {
-        g_assert_cmpuint(fds_num, <, SOCKET_MAX_FDS);
-
-        msg.msg_control = control;
-        msg.msg_controllen = CMSG_SPACE(fdsize);
-
-        cmsg = CMSG_FIRSTHDR(&msg);
-        cmsg->cmsg_len = CMSG_LEN(fdsize);
-        cmsg->cmsg_level = SOL_SOCKET;
-        cmsg->cmsg_type = SCM_RIGHTS;
-        memcpy(CMSG_DATA(cmsg), fds, fdsize);
-    }
-
-    do {
-        ret = sendmsg(socket_fd, &msg, 0);
-    } while (ret < 0 && errno == EINTR);
-    g_assert_cmpint(ret, >, 0);
-}
-
-static GString *qtest_recv_line(QTestState *s)
-{
-    GString *line;
-    size_t offset;
-    char *eol;
-
-    while ((eol = strchr(s->rx->str, '\n')) == NULL) {
-        ssize_t len;
-        char buffer[1024];
-
-        len = read(s->fd, buffer, sizeof(buffer));
-        if (len == -1 && errno == EINTR) {
-            continue;
-        }
-
-        if (len == -1 || len == 0) {
-            fprintf(stderr, "Broken pipe\n");
-            abort();
-        }
-
-        g_string_append_len(s->rx, buffer, len);
-    }
-
-    offset = eol - s->rx->str;
-    line = g_string_new_len(s->rx->str, offset);
-    g_string_erase(s->rx, 0, offset + 1);
-
-    return line;
-}
-
-static gchar **qtest_rsp(QTestState *s, int expected_args)
-{
-    GString *line;
-    gchar **words;
-    int i;
-
-redo:
-    line = qtest_recv_line(s);
-    words = g_strsplit(line->str, " ", 0);
-    g_string_free(line, TRUE);
-
-    if (strcmp(words[0], "IRQ") == 0) {
-        long irq;
-        int ret;
-
-        g_assert(words[1] != NULL);
-        g_assert(words[2] != NULL);
-
-        ret = qemu_strtol(words[2], NULL, 0, &irq);
-        g_assert(!ret);
-        g_assert_cmpint(irq, >=, 0);
-        g_assert_cmpint(irq, <, MAX_IRQ);
-
-        if (strcmp(words[1], "raise") == 0) {
-            s->irq_level[irq] = true;
-        } else {
-            s->irq_level[irq] = false;
-        }
-
-        g_strfreev(words);
-        goto redo;
-    }
-
-    g_assert(words[0] != NULL);
-    g_assert_cmpstr(words[0], ==, "OK");
-
-    if (expected_args) {
-        for (i = 0; i < expected_args; i++) {
-            g_assert(words[i] != NULL);
-        }
-    } else {
-        g_strfreev(words);
-    }
-
-    return words;
-}
-
-static int qtest_query_target_endianness(QTestState *s)
-{
-    gchar **args;
-    int big_endian;
-
-    qtest_sendf(s, "endianness\n");
-    args = qtest_rsp(s, 1);
-    g_assert(strcmp(args[1], "big") == 0 || strcmp(args[1], "little") == 0);
-    big_endian = strcmp(args[1], "big") == 0;
-    g_strfreev(args);
-
-    return big_endian;
-}
-
-typedef struct {
-    JSONMessageParser parser;
-    QDict *response;
-} QMPResponseParser;
-
-static void qmp_response(void *opaque, QObject *obj, Error *err)
-{
-    QMPResponseParser *qmp = opaque;
-
-    assert(!obj != !err);
-
-    if (err) {
-        error_prepend(&err, "QMP JSON response parsing failed: ");
-        error_report_err(err);
-        abort();
-    }
-
-    g_assert(!qmp->response);
-    qmp->response = qobject_to(QDict, obj);
-    g_assert(qmp->response);
-}
-
-QDict *qmp_fd_receive(int fd)
-{
-    QMPResponseParser qmp;
-    bool log = getenv("QTEST_LOG") != NULL;
-
-    qmp.response = NULL;
-    json_message_parser_init(&qmp.parser, qmp_response, &qmp, NULL);
-    while (!qmp.response) {
-        ssize_t len;
-        char c;
-
-        len = read(fd, &c, 1);
-        if (len == -1 && errno == EINTR) {
-            continue;
-        }
-
-        if (len == -1 || len == 0) {
-            fprintf(stderr, "Broken pipe\n");
-            abort();
-        }
-
-        if (log) {
-            len = write(2, &c, 1);
-        }
-        json_message_parser_feed(&qmp.parser, &c, 1);
-    }
-    json_message_parser_destroy(&qmp.parser);
-
-    return qmp.response;
-}
-
-QDict *qtest_qmp_receive(QTestState *s)
-{
-    return qmp_fd_receive(s->qmp_fd);
-}
-
-/**
- * Allow users to send a message without waiting for the reply,
- * in the case that they choose to discard all replies up until
- * a particular EVENT is received.
- */
-void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
-                      const char *fmt, va_list ap)
-{
-    QObject *qobj;
-
-    /* Going through qobject ensures we escape strings properly */
-    qobj = qobject_from_vjsonf_nofail(fmt, ap);
-
-    /* No need to send anything for an empty QObject.  */
-    if (qobj) {
-        int log = getenv("QTEST_LOG") != NULL;
-        QString *qstr = qobject_to_json(qobj);
-        const char *str;
-
-        /*
-         * BUG: QMP doesn't react to input until it sees a newline, an
-         * object, or an array.  Work-around: give it a newline.
-         */
-        qstring_append_chr(qstr, '\n');
-        str = qstring_get_str(qstr);
-
-        if (log) {
-            fprintf(stderr, "%s", str);
-        }
-        /* Send QMP request */
-        if (fds && fds_num > 0) {
-            socket_send_fds(fd, fds, fds_num, str, qstring_get_length(qstr));
-        } else {
-            socket_send(fd, str, qstring_get_length(qstr));
-        }
-
-        qobject_unref(qstr);
-        qobject_unref(qobj);
-    }
-}
-
-void qmp_fd_vsend(int fd, const char *fmt, va_list ap)
-{
-    qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap);
-}
-
-void qtest_qmp_vsend_fds(QTestState *s, int *fds, size_t fds_num,
-                         const char *fmt, va_list ap)
-{
-    qmp_fd_vsend_fds(s->qmp_fd, fds, fds_num, fmt, ap);
-}
-
-void qtest_qmp_vsend(QTestState *s, const char *fmt, va_list ap)
-{
-    qmp_fd_vsend_fds(s->qmp_fd, NULL, 0, fmt, ap);
-}
-
-QDict *qmp_fdv(int fd, const char *fmt, va_list ap)
-{
-    qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap);
-
-    return qmp_fd_receive(fd);
-}
-
-QDict *qtest_vqmp_fds(QTestState *s, int *fds, size_t fds_num,
-                      const char *fmt, va_list ap)
-{
-    qtest_qmp_vsend_fds(s, fds, fds_num, fmt, ap);
-
-    /* Receive reply */
-    return qtest_qmp_receive(s);
-}
-
-QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap)
-{
-    qtest_qmp_vsend(s, fmt, ap);
-
-    /* Receive reply */
-    return qtest_qmp_receive(s);
-}
-
-QDict *qmp_fd(int fd, const char *fmt, ...)
-{
-    va_list ap;
-    QDict *response;
-
-    va_start(ap, fmt);
-    response = qmp_fdv(fd, fmt, ap);
-    va_end(ap);
-    return response;
-}
-
-void qmp_fd_send(int fd, const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    qmp_fd_vsend(fd, fmt, ap);
-    va_end(ap);
-}
-
-QDict *qtest_qmp_fds(QTestState *s, int *fds, size_t fds_num,
-                     const char *fmt, ...)
-{
-    va_list ap;
-    QDict *response;
-
-    va_start(ap, fmt);
-    response = qtest_vqmp_fds(s, fds, fds_num, fmt, ap);
-    va_end(ap);
-    return response;
-}
-
-QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
-{
-    va_list ap;
-    QDict *response;
-
-    va_start(ap, fmt);
-    response = qtest_vqmp(s, fmt, ap);
-    va_end(ap);
-    return response;
-}
-
-void qtest_qmp_send(QTestState *s, const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    qtest_qmp_vsend(s, fmt, ap);
-    va_end(ap);
-}
-
-void qmp_fd_vsend_raw(int fd, const char *fmt, va_list ap)
-{
-    bool log = getenv("QTEST_LOG") != NULL;
-    char *str = g_strdup_vprintf(fmt, ap);
-
-    if (log) {
-        fprintf(stderr, "%s", str);
-    }
-    socket_send(fd, str, strlen(str));
-    g_free(str);
-}
-
-void qmp_fd_send_raw(int fd, const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    qmp_fd_vsend_raw(fd, fmt, ap);
-    va_end(ap);
-}
-
-void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    qmp_fd_vsend_raw(s->qmp_fd, fmt, ap);
-    va_end(ap);
-}
-
-QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event)
-{
-    QDict *response;
-
-    for (;;) {
-        response = qtest_qmp_receive(s);
-        if ((qdict_haskey(response, "event")) &&
-            (strcmp(qdict_get_str(response, "event"), event) == 0)) {
-            return response;
-        }
-        qobject_unref(response);
-    }
-}
-
-void qtest_qmp_eventwait(QTestState *s, const char *event)
-{
-    QDict *response;
-
-    response = qtest_qmp_eventwait_ref(s, event);
-    qobject_unref(response);
-}
-
-char *qtest_vhmp(QTestState *s, const char *fmt, va_list ap)
-{
-    char *cmd;
-    QDict *resp;
-    char *ret;
-
-    cmd = g_strdup_vprintf(fmt, ap);
-    resp = qtest_qmp(s, "{'execute': 'human-monitor-command',"
-                     " 'arguments': {'command-line': %s}}",
-                     cmd);
-    ret = g_strdup(qdict_get_try_str(resp, "return"));
-    while (ret == NULL && qdict_get_try_str(resp, "event")) {
-        /* Ignore asynchronous QMP events */
-        qobject_unref(resp);
-        resp = qtest_qmp_receive(s);
-        ret = g_strdup(qdict_get_try_str(resp, "return"));
-    }
-    g_assert(ret);
-    qobject_unref(resp);
-    g_free(cmd);
-    return ret;
-}
-
-char *qtest_hmp(QTestState *s, const char *fmt, ...)
-{
-    va_list ap;
-    char *ret;
-
-    va_start(ap, fmt);
-    ret = qtest_vhmp(s, fmt, ap);
-    va_end(ap);
-    return ret;
-}
-
-const char *qtest_get_arch(void)
-{
-    const char *qemu = qtest_qemu_binary();
-    const char *end = strrchr(qemu, '/');
-
-    return end + strlen("/qemu-system-");
-}
-
-bool qtest_get_irq(QTestState *s, int num)
-{
-    /* dummy operation in order to make sure irq is up to date */
-    qtest_inb(s, 0);
-
-    return s->irq_level[num];
-}
-
-void qtest_module_load(QTestState *s, const char *prefix, const char *libname)
-{
-    qtest_sendf(s, "module_load %s %s\n", prefix, libname);
-    qtest_rsp(s, 0);
-}
-
-static int64_t qtest_clock_rsp(QTestState *s)
-{
-    gchar **words;
-    int64_t clock;
-    words = qtest_rsp(s, 2);
-    clock = g_ascii_strtoll(words[1], NULL, 0);
-    g_strfreev(words);
-    return clock;
-}
-
-int64_t qtest_clock_step_next(QTestState *s)
-{
-    qtest_sendf(s, "clock_step\n");
-    return qtest_clock_rsp(s);
-}
-
-int64_t qtest_clock_step(QTestState *s, int64_t step)
-{
-    qtest_sendf(s, "clock_step %"PRIi64"\n", step);
-    return qtest_clock_rsp(s);
-}
-
-int64_t qtest_clock_set(QTestState *s, int64_t val)
-{
-    qtest_sendf(s, "clock_set %"PRIi64"\n", val);
-    return qtest_clock_rsp(s);
-}
-
-void qtest_irq_intercept_out(QTestState *s, const char *qom_path)
-{
-    qtest_sendf(s, "irq_intercept_out %s\n", qom_path);
-    qtest_rsp(s, 0);
-}
-
-void qtest_irq_intercept_in(QTestState *s, const char *qom_path)
-{
-    qtest_sendf(s, "irq_intercept_in %s\n", qom_path);
-    qtest_rsp(s, 0);
-}
-
-void qtest_set_irq_in(QTestState *s, const char *qom_path, const char *name,
-                      int num, int level)
-{
-    if (!name) {
-        name = "unnamed-gpio-in";
-    }
-    qtest_sendf(s, "set_irq_in %s %s %d %d\n", qom_path, name, num, level);
-    qtest_rsp(s, 0);
-}
-
-static void qtest_out(QTestState *s, const char *cmd, uint16_t addr, uint32_t value)
-{
-    qtest_sendf(s, "%s 0x%x 0x%x\n", cmd, addr, value);
-    qtest_rsp(s, 0);
-}
-
-void qtest_outb(QTestState *s, uint16_t addr, uint8_t value)
-{
-    qtest_out(s, "outb", addr, value);
-}
-
-void qtest_outw(QTestState *s, uint16_t addr, uint16_t value)
-{
-    qtest_out(s, "outw", addr, value);
-}
-
-void qtest_outl(QTestState *s, uint16_t addr, uint32_t value)
-{
-    qtest_out(s, "outl", addr, value);
-}
-
-static uint32_t qtest_in(QTestState *s, const char *cmd, uint16_t addr)
-{
-    gchar **args;
-    int ret;
-    unsigned long value;
-
-    qtest_sendf(s, "%s 0x%x\n", cmd, addr);
-    args = qtest_rsp(s, 2);
-    ret = qemu_strtoul(args[1], NULL, 0, &value);
-    g_assert(!ret && value <= UINT32_MAX);
-    g_strfreev(args);
-
-    return value;
-}
-
-uint8_t qtest_inb(QTestState *s, uint16_t addr)
-{
-    return qtest_in(s, "inb", addr);
-}
-
-uint16_t qtest_inw(QTestState *s, uint16_t addr)
-{
-    return qtest_in(s, "inw", addr);
-}
-
-uint32_t qtest_inl(QTestState *s, uint16_t addr)
-{
-    return qtest_in(s, "inl", addr);
-}
-
-static void qtest_write(QTestState *s, const char *cmd, uint64_t addr,
-                        uint64_t value)
-{
-    qtest_sendf(s, "%s 0x%" PRIx64 " 0x%" PRIx64 "\n", cmd, addr, value);
-    qtest_rsp(s, 0);
-}
-
-void qtest_writeb(QTestState *s, uint64_t addr, uint8_t value)
-{
-    qtest_write(s, "writeb", addr, value);
-}
-
-void qtest_writew(QTestState *s, uint64_t addr, uint16_t value)
-{
-    qtest_write(s, "writew", addr, value);
-}
-
-void qtest_writel(QTestState *s, uint64_t addr, uint32_t value)
-{
-    qtest_write(s, "writel", addr, value);
-}
-
-void qtest_writeq(QTestState *s, uint64_t addr, uint64_t value)
-{
-    qtest_write(s, "writeq", addr, value);
-}
-
-static uint64_t qtest_read(QTestState *s, const char *cmd, uint64_t addr)
-{
-    gchar **args;
-    int ret;
-    uint64_t value;
-
-    qtest_sendf(s, "%s 0x%" PRIx64 "\n", cmd, addr);
-    args = qtest_rsp(s, 2);
-    ret = qemu_strtou64(args[1], NULL, 0, &value);
-    g_assert(!ret);
-    g_strfreev(args);
-
-    return value;
-}
-
-uint8_t qtest_readb(QTestState *s, uint64_t addr)
-{
-    return qtest_read(s, "readb", addr);
-}
-
-uint16_t qtest_readw(QTestState *s, uint64_t addr)
-{
-    return qtest_read(s, "readw", addr);
-}
-
-uint32_t qtest_readl(QTestState *s, uint64_t addr)
-{
-    return qtest_read(s, "readl", addr);
-}
-
-uint64_t qtest_readq(QTestState *s, uint64_t addr)
-{
-    return qtest_read(s, "readq", addr);
-}
-
-static int hex2nib(char ch)
-{
-    if (ch >= '0' && ch <= '9') {
-        return ch - '0';
-    } else if (ch >= 'a' && ch <= 'f') {
-        return 10 + (ch - 'a');
-    } else if (ch >= 'A' && ch <= 'F') {
-        return 10 + (ch - 'a');
-    } else {
-        return -1;
-    }
-}
-
-void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size)
-{
-    uint8_t *ptr = data;
-    gchar **args;
-    size_t i;
-
-    if (!size) {
-        return;
-    }
-
-    qtest_sendf(s, "read 0x%" PRIx64 " 0x%zx\n", addr, size);
-    args = qtest_rsp(s, 2);
-
-    for (i = 0; i < size; i++) {
-        ptr[i] = hex2nib(args[1][2 + (i * 2)]) << 4;
-        ptr[i] |= hex2nib(args[1][2 + (i * 2) + 1]);
-    }
-
-    g_strfreev(args);
-}
-
-uint64_t qtest_rtas_call(QTestState *s, const char *name,
-                         uint32_t nargs, uint64_t args,
-                         uint32_t nret, uint64_t ret)
-{
-    qtest_sendf(s, "rtas %s %u 0x%"PRIx64" %u 0x%"PRIx64"\n",
-                name, nargs, args, nret, ret);
-    qtest_rsp(s, 0);
-    return 0;
-}
-
-void qtest_add_func(const char *str, void (*fn)(void))
-{
-    gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
-    g_test_add_func(path, fn);
-    g_free(path);
-}
-
-void qtest_add_data_func_full(const char *str, void *data,
-                              void (*fn)(const void *),
-                              GDestroyNotify data_free_func)
-{
-    gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
-    g_test_add_data_func_full(path, data, fn, data_free_func);
-    g_free(path);
-}
-
-void qtest_add_data_func(const char *str, const void *data,
-                         void (*fn)(const void *))
-{
-    gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
-    g_test_add_data_func(path, data, fn);
-    g_free(path);
-}
-
-void qtest_bufwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
-{
-    gchar *bdata;
-
-    bdata = g_base64_encode(data, size);
-    qtest_sendf(s, "b64write 0x%" PRIx64 " 0x%zx ", addr, size);
-    socket_send(s->fd, bdata, strlen(bdata));
-    socket_send(s->fd, "\n", 1);
-    qtest_rsp(s, 0);
-    g_free(bdata);
-}
-
-void qtest_bufread(QTestState *s, uint64_t addr, void *data, size_t size)
-{
-    gchar **args;
-    size_t len;
-
-    qtest_sendf(s, "b64read 0x%" PRIx64 " 0x%zx\n", addr, size);
-    args = qtest_rsp(s, 2);
-
-    g_base64_decode_inplace(args[1], &len);
-    if (size != len) {
-        fprintf(stderr, "bufread: asked for %zu bytes but decoded %zu\n",
-                size, len);
-        len = MIN(len, size);
-    }
-
-    memcpy(data, args[1], len);
-    g_strfreev(args);
-}
-
-void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
-{
-    const uint8_t *ptr = data;
-    size_t i;
-    char *enc;
-
-    if (!size) {
-        return;
-    }
-
-    enc = g_malloc(2 * size + 1);
-
-    for (i = 0; i < size; i++) {
-        sprintf(&enc[i * 2], "%02x", ptr[i]);
-    }
-
-    qtest_sendf(s, "write 0x%" PRIx64 " 0x%zx 0x%s\n", addr, size, enc);
-    qtest_rsp(s, 0);
-    g_free(enc);
-}
-
-void qtest_memset(QTestState *s, uint64_t addr, uint8_t pattern, size_t size)
-{
-    qtest_sendf(s, "memset 0x%" PRIx64 " 0x%zx 0x%02x\n", addr, size, pattern);
-    qtest_rsp(s, 0);
-}
-
-void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
-{
-    va_list ap;
-    QDict *response;
-
-    va_start(ap, fmt);
-    response = qtest_vqmp(qts, fmt, ap);
-    va_end(ap);
-
-    g_assert(response);
-    if (!qdict_haskey(response, "return")) {
-        QString *s = qobject_to_json_pretty(QOBJECT(response));
-        g_test_message("%s", qstring_get_str(s));
-        qobject_unref(s);
-    }
-    g_assert(qdict_haskey(response, "return"));
-    qobject_unref(response);
-}
-
-bool qtest_big_endian(QTestState *s)
-{
-    return s->big_endian;
-}
-
-static bool qtest_check_machine_version(const char *mname, const char *basename,
-                                        int major, int minor)
-{
-    char *newname;
-    bool is_equal;
-
-    newname = g_strdup_printf("%s-%i.%i", basename, major, minor);
-    is_equal = g_str_equal(mname, newname);
-    g_free(newname);
-
-    return is_equal;
-}
-
-static bool qtest_is_old_versioned_machine(const char *mname)
-{
-    const char *dash = strrchr(mname, '-');
-    const char *dot = strrchr(mname, '.');
-    const char *chr;
-    char *bname;
-    const int major = QEMU_VERSION_MAJOR;
-    const int minor = QEMU_VERSION_MINOR;
-    bool res = false;
-
-    if (dash && dot && dot > dash) {
-        for (chr = dash + 1; *chr; chr++) {
-            if (!qemu_isdigit(*chr) && *chr != '.') {
-                return false;
-            }
-        }
-        /*
-         * Now check if it is one of the latest versions. Check major + 1
-         * and minor + 1 versions as well, since they might already exist
-         * in the development branch.
-         */
-        bname = g_strdup(mname);
-        bname[dash - mname] = 0;
-        res = !qtest_check_machine_version(mname, bname, major + 1, 0) &&
-              !qtest_check_machine_version(mname, bname, major, minor + 1) &&
-              !qtest_check_machine_version(mname, bname, major, minor);
-        g_free(bname);
-    }
-
-    return res;
-}
-
-void qtest_cb_for_every_machine(void (*cb)(const char *machine),
-                                bool skip_old_versioned)
-{
-    QDict *response, *minfo;
-    QList *list;
-    const QListEntry *p;
-    QObject *qobj;
-    QString *qstr;
-    const char *mname;
-    QTestState *qts;
-
-    qts = qtest_init("-machine none");
-    response = qtest_qmp(qts, "{ 'execute': 'query-machines' }");
-    g_assert(response);
-    list = qdict_get_qlist(response, "return");
-    g_assert(list);
-
-    for (p = qlist_first(list); p; p = qlist_next(p)) {
-        minfo = qobject_to(QDict, qlist_entry_obj(p));
-        g_assert(minfo);
-        qobj = qdict_get(minfo, "name");
-        g_assert(qobj);
-        qstr = qobject_to(QString, qobj);
-        g_assert(qstr);
-        mname = qstring_get_str(qstr);
-        if (!skip_old_versioned || !qtest_is_old_versioned_machine(mname)) {
-            cb(mname);
-        }
-    }
-
-    qtest_quit(qts);
-    qobject_unref(response);
-}
-
-QDict *qtest_qmp_receive_success(QTestState *s,
-                                 void (*event_cb)(void *opaque,
-                                                  const char *event,
-                                                  QDict *data),
-                                 void *opaque)
-{
-    QDict *response, *ret, *data;
-    const char *event;
-
-    for (;;) {
-        response = qtest_qmp_receive(s);
-        g_assert(!qdict_haskey(response, "error"));
-        ret = qdict_get_qdict(response, "return");
-        if (ret) {
-            break;
-        }
-        event = qdict_get_str(response, "event");
-        data = qdict_get_qdict(response, "data");
-        if (event_cb) {
-            event_cb(opaque, event, data);
-        }
-        qobject_unref(response);
-    }
-
-    qobject_ref(ret);
-    qobject_unref(response);
-    return ret;
-}
-
-/*
- * Generic hot-plugging test via the device_add QMP commands.
- */
-void qtest_qmp_device_add_qdict(QTestState *qts, const char *drv,
-                                const QDict *arguments)
-{
-    QDict *resp;
-    QDict *args = arguments ? qdict_clone_shallow(arguments) : qdict_new();
-
-    g_assert(!qdict_haskey(args, "driver"));
-    qdict_put_str(args, "driver", drv);
-    resp = qtest_qmp(qts, "{'execute': 'device_add', 'arguments': %p}", args);
-    g_assert(resp);
-    g_assert(!qdict_haskey(resp, "event")); /* We don't expect any events */
-    g_assert(!qdict_haskey(resp, "error"));
-    qobject_unref(resp);
-}
-
-void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id,
-                          const char *fmt, ...)
-{
-    QDict *args;
-    va_list ap;
-
-    va_start(ap, fmt);
-    args = qdict_from_vjsonf_nofail(fmt, ap);
-    va_end(ap);
-
-    g_assert(!qdict_haskey(args, "id"));
-    qdict_put_str(args, "id", id);
-
-    qtest_qmp_device_add_qdict(qts, driver, args);
-    qobject_unref(args);
-}
-
-static void device_deleted_cb(void *opaque, const char *name, QDict *data)
-{
-    bool *got_event = opaque;
-
-    g_assert_cmpstr(name, ==, "DEVICE_DELETED");
-    *got_event = true;
-}
-
-/*
- * Generic hot-unplugging test via the device_del QMP command.
- * Device deletion will get one response and one event. For example:
- *
- * {'execute': 'device_del','arguments': { 'id': 'scsi-hd'}}
- *
- * will get this one:
- *
- * {"timestamp": {"seconds": 1505289667, "microseconds": 569862},
- *  "event": "DEVICE_DELETED", "data": {"device": "scsi-hd",
- *  "path": "/machine/peripheral/scsi-hd"}}
- *
- * and this one:
- *
- * {"return": {}}
- *
- * But the order of arrival may vary - so we've got to detect both.
- */
-void qtest_qmp_device_del(QTestState *qts, const char *id)
-{
-    bool got_event = false;
-    QDict *rsp;
-
-    qtest_qmp_send(qts, "{'execute': 'device_del', 'arguments': {'id': %s}}",
-                   id);
-    rsp = qtest_qmp_receive_success(qts, device_deleted_cb, &got_event);
-    qobject_unref(rsp);
-    if (!got_event) {
-        rsp = qtest_qmp_receive(qts);
-        g_assert_cmpstr(qdict_get_try_str(rsp, "event"),
-                        ==, "DEVICE_DELETED");
-        qobject_unref(rsp);
-    }
-}
-
-bool qmp_rsp_is_err(QDict *rsp)
-{
-    QDict *error = qdict_get_qdict(rsp, "error");
-    qobject_unref(rsp);
-    return !!error;
-}
-
-void qmp_assert_error_class(QDict *rsp, const char *class)
-{
-    QDict *error = qdict_get_qdict(rsp, "error");
-
-    g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, class);
-    g_assert_nonnull(qdict_get_try_str(error, "desc"));
-    g_assert(!qdict_haskey(rsp, "return"));
-
-    qobject_unref(rsp);
-}
diff --git a/tests/libqtest.h b/tests/libqtest.h
deleted file mode 100644 (file)
index c9e21e0..0000000
+++ /dev/null
@@ -1,732 +0,0 @@
-/*
- * QTest
- *
- * Copyright IBM, Corp. 2012
- * Copyright Red Hat, Inc. 2012
- * Copyright SUSE LINUX Products GmbH 2013
- *
- * Authors:
- *  Anthony Liguori   <[email protected]>
- *  Paolo Bonzini     <[email protected]>
- *  Andreas Färber    <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-#ifndef LIBQTEST_H
-#define LIBQTEST_H
-
-#include "qapi/qmp/qobject.h"
-#include "qapi/qmp/qdict.h"
-
-typedef struct QTestState QTestState;
-
-/**
- * qtest_initf:
- * @fmt...: Format for creating other arguments to pass to QEMU, formatted
- * like sprintf().
- *
- * Convenience wrapper around qtest_init().
- *
- * Returns: #QTestState instance.
- */
-QTestState *qtest_initf(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
-
-/**
- * qtest_vinitf:
- * @fmt: Format for creating other arguments to pass to QEMU, formatted
- * like vsprintf().
- * @ap: Format arguments.
- *
- * Convenience wrapper around qtest_init().
- *
- * Returns: #QTestState instance.
- */
-QTestState *qtest_vinitf(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0);
-
-/**
- * qtest_init:
- * @extra_args: other arguments to pass to QEMU.  CAUTION: these
- * arguments are subject to word splitting and shell evaluation.
- *
- * Returns: #QTestState instance.
- */
-QTestState *qtest_init(const char *extra_args);
-
-/**
- * qtest_init_without_qmp_handshake:
- * @extra_args: other arguments to pass to QEMU.  CAUTION: these
- * arguments are subject to word splitting and shell evaluation.
- *
- * Returns: #QTestState instance.
- */
-QTestState *qtest_init_without_qmp_handshake(const char *extra_args);
-
-/**
- * qtest_init_with_serial:
- * @extra_args: other arguments to pass to QEMU.  CAUTION: these
- * arguments are subject to word splitting and shell evaluation.
- * @sock_fd: pointer to store the socket file descriptor for
- * connection with serial.
- *
- * Returns: #QTestState instance.
- */
-QTestState *qtest_init_with_serial(const char *extra_args, int *sock_fd);
-
-/**
- * qtest_quit:
- * @s: #QTestState instance to operate on.
- *
- * Shut down the QEMU process associated to @s.
- */
-void qtest_quit(QTestState *s);
-
-/**
- * qtest_qmp_fds:
- * @s: #QTestState instance to operate on.
- * @fds: array of file descriptors
- * @fds_num: number of elements in @fds
- * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail().  See parse_escape() for what's
- * supported after '%'.
- *
- * Sends a QMP message to QEMU with fds and returns the response.
- */
-QDict *qtest_qmp_fds(QTestState *s, int *fds, size_t fds_num,
-                     const char *fmt, ...)
-    GCC_FMT_ATTR(4, 5);
-
-/**
- * qtest_qmp:
- * @s: #QTestState instance to operate on.
- * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail().  See parse_escape() for what's
- * supported after '%'.
- *
- * Sends a QMP message to QEMU and returns the response.
- */
-QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
-    GCC_FMT_ATTR(2, 3);
-
-/**
- * qtest_qmp_send:
- * @s: #QTestState instance to operate on.
- * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail().  See parse_escape() for what's
- * supported after '%'.
- *
- * Sends a QMP message to QEMU and leaves the response in the stream.
- */
-void qtest_qmp_send(QTestState *s, const char *fmt, ...)
-    GCC_FMT_ATTR(2, 3);
-
-/**
- * qtest_qmp_send_raw:
- * @s: #QTestState instance to operate on.
- * @fmt...: text to send, formatted like sprintf()
- *
- * Sends text to the QMP monitor verbatim.  Need not be valid JSON;
- * this is useful for negative tests.
- */
-void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...)
-    GCC_FMT_ATTR(2, 3);
-
-/**
- * qtest_vqmp_fds:
- * @s: #QTestState instance to operate on.
- * @fds: array of file descriptors
- * @fds_num: number of elements in @fds
- * @fmt: QMP message to send to QEMU, formatted like
- * qobject_from_jsonf_nofail().  See parse_escape() for what's
- * supported after '%'.
- * @ap: QMP message arguments
- *
- * Sends a QMP message to QEMU with fds and returns the response.
- */
-QDict *qtest_vqmp_fds(QTestState *s, int *fds, size_t fds_num,
-                      const char *fmt, va_list ap)
-    GCC_FMT_ATTR(4, 0);
-
-/**
- * qtest_vqmp:
- * @s: #QTestState instance to operate on.
- * @fmt: QMP message to send to QEMU, formatted like
- * qobject_from_jsonf_nofail().  See parse_escape() for what's
- * supported after '%'.
- * @ap: QMP message arguments
- *
- * Sends a QMP message to QEMU and returns the response.
- */
-QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap)
-    GCC_FMT_ATTR(2, 0);
-
-/**
- * qtest_qmp_vsend_fds:
- * @s: #QTestState instance to operate on.
- * @fds: array of file descriptors
- * @fds_num: number of elements in @fds
- * @fmt: QMP message to send to QEMU, formatted like
- * qobject_from_jsonf_nofail().  See parse_escape() for what's
- * supported after '%'.
- * @ap: QMP message arguments
- *
- * Sends a QMP message to QEMU and leaves the response in the stream.
- */
-void qtest_qmp_vsend_fds(QTestState *s, int *fds, size_t fds_num,
-                         const char *fmt, va_list ap)
-    GCC_FMT_ATTR(4, 0);
-
-/**
- * qtest_qmp_vsend:
- * @s: #QTestState instance to operate on.
- * @fmt: QMP message to send to QEMU, formatted like
- * qobject_from_jsonf_nofail().  See parse_escape() for what's
- * supported after '%'.
- * @ap: QMP message arguments
- *
- * Sends a QMP message to QEMU and leaves the response in the stream.
- */
-void qtest_qmp_vsend(QTestState *s, const char *fmt, va_list ap)
-    GCC_FMT_ATTR(2, 0);
-
-/**
- * qtest_receive:
- * @s: #QTestState instance to operate on.
- *
- * Reads a QMP message from QEMU and returns the response.
- */
-QDict *qtest_qmp_receive(QTestState *s);
-
-/**
- * qtest_qmp_eventwait:
- * @s: #QTestState instance to operate on.
- * @s: #event event to wait for.
- *
- * Continuously polls for QMP responses until it receives the desired event.
- */
-void qtest_qmp_eventwait(QTestState *s, const char *event);
-
-/**
- * qtest_qmp_eventwait_ref:
- * @s: #QTestState instance to operate on.
- * @s: #event event to wait for.
- *
- * Continuously polls for QMP responses until it receives the desired event.
- * Returns a copy of the event for further investigation.
- */
-QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event);
-
-/**
- * qtest_qmp_receive_success:
- * @s: #QTestState instance to operate on
- * @event_cb: Event callback
- * @opaque: Argument for @event_cb
- *
- * Poll QMP messages until a command success response is received.
- * If @event_cb, call it for each event received, passing @opaque,
- * the event's name and data.
- * Return the success response's "return" member.
- */
-QDict *qtest_qmp_receive_success(QTestState *s,
-                                 void (*event_cb)(void *opaque,
-                                                  const char *name,
-                                                  QDict *data),
-                                 void *opaque);
-
-/**
- * qtest_hmp:
- * @s: #QTestState instance to operate on.
- * @fmt...: HMP command to send to QEMU, formats arguments like sprintf().
- *
- * Send HMP command to QEMU via QMP's human-monitor-command.
- * QMP events are discarded.
- *
- * Returns: the command's output.  The caller should g_free() it.
- */
-char *qtest_hmp(QTestState *s, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
-
-/**
- * qtest_hmpv:
- * @s: #QTestState instance to operate on.
- * @fmt: HMP command to send to QEMU, formats arguments like vsprintf().
- * @ap: HMP command arguments
- *
- * Send HMP command to QEMU via QMP's human-monitor-command.
- * QMP events are discarded.
- *
- * Returns: the command's output.  The caller should g_free() it.
- */
-char *qtest_vhmp(QTestState *s, const char *fmt, va_list ap)
-    GCC_FMT_ATTR(2, 0);
-
-void qtest_module_load(QTestState *s, const char *prefix, const char *libname);
-
-/**
- * qtest_get_irq:
- * @s: #QTestState instance to operate on.
- * @num: Interrupt to observe.
- *
- * Returns: The level of the @num interrupt.
- */
-bool qtest_get_irq(QTestState *s, int num);
-
-/**
- * qtest_irq_intercept_in:
- * @s: #QTestState instance to operate on.
- * @string: QOM path of a device.
- *
- * Associate qtest irqs with the GPIO-in pins of the device
- * whose path is specified by @string.
- */
-void qtest_irq_intercept_in(QTestState *s, const char *string);
-
-/**
- * qtest_irq_intercept_out:
- * @s: #QTestState instance to operate on.
- * @string: QOM path of a device.
- *
- * Associate qtest irqs with the GPIO-out pins of the device
- * whose path is specified by @string.
- */
-void qtest_irq_intercept_out(QTestState *s, const char *string);
-
-/**
- * qtest_set_irq_in:
- * @s: QTestState instance to operate on.
- * @string: QOM path of a device
- * @name: IRQ name
- * @irq: IRQ number
- * @level: IRQ level
- *
- * Force given device/irq GPIO-in pin to the given level.
- */
-void qtest_set_irq_in(QTestState *s, const char *string, const char *name,
-                      int irq, int level);
-
-/**
- * qtest_outb:
- * @s: #QTestState instance to operate on.
- * @addr: I/O port to write to.
- * @value: Value being written.
- *
- * Write an 8-bit value to an I/O port.
- */
-void qtest_outb(QTestState *s, uint16_t addr, uint8_t value);
-
-/**
- * qtest_outw:
- * @s: #QTestState instance to operate on.
- * @addr: I/O port to write to.
- * @value: Value being written.
- *
- * Write a 16-bit value to an I/O port.
- */
-void qtest_outw(QTestState *s, uint16_t addr, uint16_t value);
-
-/**
- * qtest_outl:
- * @s: #QTestState instance to operate on.
- * @addr: I/O port to write to.
- * @value: Value being written.
- *
- * Write a 32-bit value to an I/O port.
- */
-void qtest_outl(QTestState *s, uint16_t addr, uint32_t value);
-
-/**
- * qtest_inb:
- * @s: #QTestState instance to operate on.
- * @addr: I/O port to read from.
- *
- * Returns an 8-bit value from an I/O port.
- */
-uint8_t qtest_inb(QTestState *s, uint16_t addr);
-
-/**
- * qtest_inw:
- * @s: #QTestState instance to operate on.
- * @addr: I/O port to read from.
- *
- * Returns a 16-bit value from an I/O port.
- */
-uint16_t qtest_inw(QTestState *s, uint16_t addr);
-
-/**
- * qtest_inl:
- * @s: #QTestState instance to operate on.
- * @addr: I/O port to read from.
- *
- * Returns a 32-bit value from an I/O port.
- */
-uint32_t qtest_inl(QTestState *s, uint16_t addr);
-
-/**
- * qtest_writeb:
- * @s: #QTestState instance to operate on.
- * @addr: Guest address to write to.
- * @value: Value being written.
- *
- * Writes an 8-bit value to memory.
- */
-void qtest_writeb(QTestState *s, uint64_t addr, uint8_t value);
-
-/**
- * qtest_writew:
- * @s: #QTestState instance to operate on.
- * @addr: Guest address to write to.
- * @value: Value being written.
- *
- * Writes a 16-bit value to memory.
- */
-void qtest_writew(QTestState *s, uint64_t addr, uint16_t value);
-
-/**
- * qtest_writel:
- * @s: #QTestState instance to operate on.
- * @addr: Guest address to write to.
- * @value: Value being written.
- *
- * Writes a 32-bit value to memory.
- */
-void qtest_writel(QTestState *s, uint64_t addr, uint32_t value);
-
-/**
- * qtest_writeq:
- * @s: #QTestState instance to operate on.
- * @addr: Guest address to write to.
- * @value: Value being written.
- *
- * Writes a 64-bit value to memory.
- */
-void qtest_writeq(QTestState *s, uint64_t addr, uint64_t value);
-
-/**
- * qtest_readb:
- * @s: #QTestState instance to operate on.
- * @addr: Guest address to read from.
- *
- * Reads an 8-bit value from memory.
- *
- * Returns: Value read.
- */
-uint8_t qtest_readb(QTestState *s, uint64_t addr);
-
-/**
- * qtest_readw:
- * @s: #QTestState instance to operate on.
- * @addr: Guest address to read from.
- *
- * Reads a 16-bit value from memory.
- *
- * Returns: Value read.
- */
-uint16_t qtest_readw(QTestState *s, uint64_t addr);
-
-/**
- * qtest_readl:
- * @s: #QTestState instance to operate on.
- * @addr: Guest address to read from.
- *
- * Reads a 32-bit value from memory.
- *
- * Returns: Value read.
- */
-uint32_t qtest_readl(QTestState *s, uint64_t addr);
-
-/**
- * qtest_readq:
- * @s: #QTestState instance to operate on.
- * @addr: Guest address to read from.
- *
- * Reads a 64-bit value from memory.
- *
- * Returns: Value read.
- */
-uint64_t qtest_readq(QTestState *s, uint64_t addr);
-
-/**
- * qtest_memread:
- * @s: #QTestState instance to operate on.
- * @addr: Guest address to read from.
- * @data: Pointer to where memory contents will be stored.
- * @size: Number of bytes to read.
- *
- * Read guest memory into a buffer.
- */
-void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
-
-/**
- * qtest_rtas_call:
- * @s: #QTestState instance to operate on.
- * @name: name of the command to call.
- * @nargs: Number of args.
- * @args: Guest address to read args from.
- * @nret: Number of return value.
- * @ret: Guest address to write return values to.
- *
- * Call an RTAS function
- */
-uint64_t qtest_rtas_call(QTestState *s, const char *name,
-                         uint32_t nargs, uint64_t args,
-                         uint32_t nret, uint64_t ret);
-
-/**
- * qtest_bufread:
- * @s: #QTestState instance to operate on.
- * @addr: Guest address to read from.
- * @data: Pointer to where memory contents will be stored.
- * @size: Number of bytes to read.
- *
- * Read guest memory into a buffer and receive using a base64 encoding.
- */
-void qtest_bufread(QTestState *s, uint64_t addr, void *data, size_t size);
-
-/**
- * qtest_memwrite:
- * @s: #QTestState instance to operate on.
- * @addr: Guest address to write to.
- * @data: Pointer to the bytes that will be written to guest memory.
- * @size: Number of bytes to write.
- *
- * Write a buffer to guest memory.
- */
-void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size);
-
-/**
- * qtest_bufwrite:
- * @s: #QTestState instance to operate on.
- * @addr: Guest address to write to.
- * @data: Pointer to the bytes that will be written to guest memory.
- * @size: Number of bytes to write.
- *
- * Write a buffer to guest memory and transmit using a base64 encoding.
- */
-void qtest_bufwrite(QTestState *s, uint64_t addr,
-                    const void *data, size_t size);
-
-/**
- * qtest_memset:
- * @s: #QTestState instance to operate on.
- * @addr: Guest address to write to.
- * @patt: Byte pattern to fill the guest memory region with.
- * @size: Number of bytes to write.
- *
- * Write a pattern to guest memory.
- */
-void qtest_memset(QTestState *s, uint64_t addr, uint8_t patt, size_t size);
-
-/**
- * qtest_clock_step_next:
- * @s: #QTestState instance to operate on.
- *
- * Advance the QEMU_CLOCK_VIRTUAL to the next deadline.
- *
- * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
- */
-int64_t qtest_clock_step_next(QTestState *s);
-
-/**
- * qtest_clock_step:
- * @s: QTestState instance to operate on.
- * @step: Number of nanoseconds to advance the clock by.
- *
- * Advance the QEMU_CLOCK_VIRTUAL by @step nanoseconds.
- *
- * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
- */
-int64_t qtest_clock_step(QTestState *s, int64_t step);
-
-/**
- * qtest_clock_set:
- * @s: QTestState instance to operate on.
- * @val: Nanoseconds value to advance the clock to.
- *
- * Advance the QEMU_CLOCK_VIRTUAL to @val nanoseconds since the VM was launched.
- *
- * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
- */
-int64_t qtest_clock_set(QTestState *s, int64_t val);
-
-/**
- * qtest_big_endian:
- * @s: QTestState instance to operate on.
- *
- * Returns: True if the architecture under test has a big endian configuration.
- */
-bool qtest_big_endian(QTestState *s);
-
-/**
- * qtest_get_arch:
- *
- * Returns: The architecture for the QEMU executable under test.
- */
-const char *qtest_get_arch(void);
-
-/**
- * qtest_add_func:
- * @str: Test case path.
- * @fn: Test case function
- *
- * Add a GTester testcase with the given name and function.
- * The path is prefixed with the architecture under test, as
- * returned by qtest_get_arch().
- */
-void qtest_add_func(const char *str, void (*fn)(void));
-
-/**
- * qtest_add_data_func:
- * @str: Test case path.
- * @data: Test case data
- * @fn: Test case function
- *
- * Add a GTester testcase with the given name, data and function.
- * The path is prefixed with the architecture under test, as
- * returned by qtest_get_arch().
- */
-void qtest_add_data_func(const char *str, const void *data,
-                         void (*fn)(const void *));
-
-/**
- * qtest_add_data_func_full:
- * @str: Test case path.
- * @data: Test case data
- * @fn: Test case function
- * @data_free_func: GDestroyNotify for data
- *
- * Add a GTester testcase with the given name, data and function.
- * The path is prefixed with the architecture under test, as
- * returned by qtest_get_arch().
- *
- * @data is passed to @data_free_func() on test completion.
- */
-void qtest_add_data_func_full(const char *str, void *data,
-                              void (*fn)(const void *),
-                              GDestroyNotify data_free_func);
-
-/**
- * qtest_add:
- * @testpath: Test case path
- * @Fixture: Fixture type
- * @tdata: Test case data
- * @fsetup: Test case setup function
- * @ftest: Test case function
- * @fteardown: Test case teardown function
- *
- * Add a GTester testcase with the given name, data and functions.
- * The path is prefixed with the architecture under test, as
- * returned by qtest_get_arch().
- */
-#define qtest_add(testpath, Fixture, tdata, fsetup, ftest, fteardown) \
-    do { \
-        char *path = g_strdup_printf("/%s/%s", qtest_get_arch(), testpath); \
-        g_test_add(path, Fixture, tdata, fsetup, ftest, fteardown); \
-        g_free(path); \
-    } while (0)
-
-void qtest_add_abrt_handler(GHookFunc fn, const void *data);
-
-/**
- * qtest_qmp_assert_success:
- * @qts: QTestState instance to operate on
- * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail().  See parse_escape() for what's
- * supported after '%'.
- *
- * Sends a QMP message to QEMU and asserts that a 'return' key is present in
- * the response.
- */
-void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
-    GCC_FMT_ATTR(2, 3);
-
-QDict *qmp_fd_receive(int fd);
-void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
-                      const char *fmt, va_list ap) GCC_FMT_ATTR(4, 0);
-void qmp_fd_vsend(int fd, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
-void qmp_fd_send(int fd, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
-void qmp_fd_send_raw(int fd, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
-void qmp_fd_vsend_raw(int fd, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
-QDict *qmp_fdv(int fd, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
-QDict *qmp_fd(int fd, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
-
-/**
- * qtest_cb_for_every_machine:
- * @cb: Pointer to the callback function
- * @skip_old_versioned: true if versioned old machine types should be skipped
- *
- *  Call a callback function for every name of all available machines.
- */
-void qtest_cb_for_every_machine(void (*cb)(const char *machine),
-                                bool skip_old_versioned);
-
-/**
- * qtest_qmp_device_add_qdict:
- * @qts: QTestState instance to operate on
- * @drv: Name of the device that should be added
- * @arguments: QDict with properties for the device to intialize
- *
- * Generic hot-plugging test via the device_add QMP command with properties
- * supplied in form of QDict. Use NULL for empty properties list.
- */
-void qtest_qmp_device_add_qdict(QTestState *qts, const char *drv,
-                                const QDict *arguments);
-
-/**
- * qtest_qmp_device_add:
- * @qts: QTestState instance to operate on
- * @driver: Name of the device that should be added
- * @id: Identification string
- * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail().  See parse_escape() for what's
- * supported after '%'.
- *
- * Generic hot-plugging test via the device_add QMP command.
- */
-void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id,
-                          const char *fmt, ...) GCC_FMT_ATTR(4, 5);
-
-/**
- * qtest_qmp_device_del:
- * @qts: QTestState instance to operate on
- * @id: Identification string
- *
- * Generic hot-unplugging test via the device_del QMP command.
- */
-void qtest_qmp_device_del(QTestState *qts, const char *id);
-
-/**
- * qmp_rsp_is_err:
- * @rsp: QMP response to check for error
- *
- * Test @rsp for error and discard @rsp.
- * Returns 'true' if there is error in @rsp and 'false' otherwise.
- */
-bool qmp_rsp_is_err(QDict *rsp);
-
-/**
- * qmp_assert_error_class:
- * @rsp: QMP response to check for error
- * @class: an error class
- *
- * Assert the response has the given error class and discard @rsp.
- */
-void qmp_assert_error_class(QDict *rsp, const char *class);
-
-/**
- * qtest_probe_child:
- * @s: QTestState instance to operate on.
- *
- * Returns: true if the child is still alive.
- */
-bool qtest_probe_child(QTestState *s);
-
-/**
- * qtest_set_expected_status:
- * @s: QTestState instance to operate on.
- * @status: an expected exit status.
- *
- * Set expected exit status of the child.
- */
-void qtest_set_expected_status(QTestState *s, int status);
-
-#endif
diff --git a/tests/m25p80-test.c b/tests/m25p80-test.c
deleted file mode 100644 (file)
index 50c6b79..0000000
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * QTest testcase for the M25P80 Flash (Using the Aspeed SPI
- * Controller)
- *
- * Copyright (C) 2016 IBM Corp.
- *
- * 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 "qemu/bswap.h"
-#include "libqtest-single.h"
-
-/*
- * ASPEED SPI Controller registers
- */
-#define R_CONF              0x00
-#define   CONF_ENABLE_W0       (1 << 16)
-#define R_CE_CTRL           0x04
-#define   CRTL_EXTENDED0       0  /* 32 bit addressing for SPI */
-#define R_CTRL0             0x10
-#define   CTRL_CE_STOP_ACTIVE  (1 << 2)
-#define   CTRL_READMODE        0x0
-#define   CTRL_FREADMODE       0x1
-#define   CTRL_WRITEMODE       0x2
-#define   CTRL_USERMODE        0x3
-
-#define ASPEED_FMC_BASE    0x1E620000
-#define ASPEED_FLASH_BASE  0x20000000
-
-/*
- * Flash commands
- */
-enum {
-    JEDEC_READ = 0x9f,
-    BULK_ERASE = 0xc7,
-    READ = 0x03,
-    PP = 0x02,
-    WREN = 0x6,
-    RESET_ENABLE = 0x66,
-    RESET_MEMORY = 0x99,
-    EN_4BYTE_ADDR = 0xB7,
-    ERASE_SECTOR = 0xd8,
-};
-
-#define FLASH_JEDEC         0x20ba19  /* n25q256a */
-#define FLASH_SIZE          (32 * 1024 * 1024)
-
-#define PAGE_SIZE           256
-
-/*
- * Use an explicit bswap for the values read/wrote to the flash region
- * as they are BE and the Aspeed CPU is LE.
- */
-static inline uint32_t make_be32(uint32_t data)
-{
-    return bswap32(data);
-}
-
-static void spi_conf(uint32_t value)
-{
-    uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
-
-    conf |= value;
-    writel(ASPEED_FMC_BASE + R_CONF, conf);
-}
-
-static void spi_conf_remove(uint32_t value)
-{
-    uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
-
-    conf &= ~value;
-    writel(ASPEED_FMC_BASE + R_CONF, conf);
-}
-
-static void spi_ce_ctrl(uint32_t value)
-{
-    uint32_t conf = readl(ASPEED_FMC_BASE + R_CE_CTRL);
-
-    conf |= value;
-    writel(ASPEED_FMC_BASE + R_CE_CTRL, conf);
-}
-
-static void spi_ctrl_setmode(uint8_t mode, uint8_t cmd)
-{
-    uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
-    ctrl &= ~(CTRL_USERMODE | 0xff << 16);
-    ctrl |= mode | (cmd << 16);
-    writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
-}
-
-static void spi_ctrl_start_user(void)
-{
-    uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
-
-    ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
-    writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
-
-    ctrl &= ~CTRL_CE_STOP_ACTIVE;
-    writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
-}
-
-static void spi_ctrl_stop_user(void)
-{
-    uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
-
-    ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
-    writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
-}
-
-static void flash_reset(void)
-{
-    spi_conf(CONF_ENABLE_W0);
-
-    spi_ctrl_start_user();
-    writeb(ASPEED_FLASH_BASE, RESET_ENABLE);
-    writeb(ASPEED_FLASH_BASE, RESET_MEMORY);
-    spi_ctrl_stop_user();
-
-    spi_conf_remove(CONF_ENABLE_W0);
-}
-
-static void test_read_jedec(void)
-{
-    uint32_t jedec = 0x0;
-
-    spi_conf(CONF_ENABLE_W0);
-
-    spi_ctrl_start_user();
-    writeb(ASPEED_FLASH_BASE, JEDEC_READ);
-    jedec |= readb(ASPEED_FLASH_BASE) << 16;
-    jedec |= readb(ASPEED_FLASH_BASE) << 8;
-    jedec |= readb(ASPEED_FLASH_BASE);
-    spi_ctrl_stop_user();
-
-    flash_reset();
-
-    g_assert_cmphex(jedec, ==, FLASH_JEDEC);
-}
-
-static void read_page(uint32_t addr, uint32_t *page)
-{
-    int i;
-
-    spi_ctrl_start_user();
-
-    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
-    writeb(ASPEED_FLASH_BASE, READ);
-    writel(ASPEED_FLASH_BASE, make_be32(addr));
-
-    /* Continuous read are supported */
-    for (i = 0; i < PAGE_SIZE / 4; i++) {
-        page[i] = make_be32(readl(ASPEED_FLASH_BASE));
-    }
-    spi_ctrl_stop_user();
-}
-
-static void read_page_mem(uint32_t addr, uint32_t *page)
-{
-    int i;
-
-    /* move out USER mode to use direct reads from the AHB bus */
-    spi_ctrl_setmode(CTRL_READMODE, READ);
-
-    for (i = 0; i < PAGE_SIZE / 4; i++) {
-        page[i] = make_be32(readl(ASPEED_FLASH_BASE + addr + i * 4));
-    }
-}
-
-static void test_erase_sector(void)
-{
-    uint32_t some_page_addr = 0x600 * PAGE_SIZE;
-    uint32_t page[PAGE_SIZE / 4];
-    int i;
-
-    spi_conf(CONF_ENABLE_W0);
-
-    spi_ctrl_start_user();
-    writeb(ASPEED_FLASH_BASE, WREN);
-    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
-    writeb(ASPEED_FLASH_BASE, ERASE_SECTOR);
-    writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
-    spi_ctrl_stop_user();
-
-    /* Previous page should be full of zeroes as backend is not
-     * initialized */
-    read_page(some_page_addr - PAGE_SIZE, page);
-    for (i = 0; i < PAGE_SIZE / 4; i++) {
-        g_assert_cmphex(page[i], ==, 0x0);
-    }
-
-    /* But this one was erased */
-    read_page(some_page_addr, page);
-    for (i = 0; i < PAGE_SIZE / 4; i++) {
-        g_assert_cmphex(page[i], ==, 0xffffffff);
-    }
-
-    flash_reset();
-}
-
-static void test_erase_all(void)
-{
-    uint32_t some_page_addr = 0x15000 * PAGE_SIZE;
-    uint32_t page[PAGE_SIZE / 4];
-    int i;
-
-    spi_conf(CONF_ENABLE_W0);
-
-    /* Check some random page. Should be full of zeroes as backend is
-     * not initialized */
-    read_page(some_page_addr, page);
-    for (i = 0; i < PAGE_SIZE / 4; i++) {
-        g_assert_cmphex(page[i], ==, 0x0);
-    }
-
-    spi_ctrl_start_user();
-    writeb(ASPEED_FLASH_BASE, WREN);
-    writeb(ASPEED_FLASH_BASE, BULK_ERASE);
-    spi_ctrl_stop_user();
-
-    /* Recheck that some random page */
-    read_page(some_page_addr, page);
-    for (i = 0; i < PAGE_SIZE / 4; i++) {
-        g_assert_cmphex(page[i], ==, 0xffffffff);
-    }
-
-    flash_reset();
-}
-
-static void test_write_page(void)
-{
-    uint32_t my_page_addr = 0x14000 * PAGE_SIZE; /* beyond 16MB */
-    uint32_t some_page_addr = 0x15000 * PAGE_SIZE;
-    uint32_t page[PAGE_SIZE / 4];
-    int i;
-
-    spi_conf(CONF_ENABLE_W0);
-
-    spi_ctrl_start_user();
-    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
-    writeb(ASPEED_FLASH_BASE, WREN);
-    writeb(ASPEED_FLASH_BASE, PP);
-    writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
-
-    /* Fill the page with its own addresses */
-    for (i = 0; i < PAGE_SIZE / 4; i++) {
-        writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
-    }
-    spi_ctrl_stop_user();
-
-    /* Check what was written */
-    read_page(my_page_addr, page);
-    for (i = 0; i < PAGE_SIZE / 4; i++) {
-        g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
-    }
-
-    /* Check some other page. It should be full of 0xff */
-    read_page(some_page_addr, page);
-    for (i = 0; i < PAGE_SIZE / 4; i++) {
-        g_assert_cmphex(page[i], ==, 0xffffffff);
-    }
-
-    flash_reset();
-}
-
-static void test_read_page_mem(void)
-{
-    uint32_t my_page_addr = 0x14000 * PAGE_SIZE; /* beyond 16MB */
-    uint32_t some_page_addr = 0x15000 * PAGE_SIZE;
-    uint32_t page[PAGE_SIZE / 4];
-    int i;
-
-    /* Enable 4BYTE mode for controller. This is should be strapped by
-     * HW for CE0 anyhow.
-     */
-    spi_ce_ctrl(1 << CRTL_EXTENDED0);
-
-    /* Enable 4BYTE mode for flash. */
-    spi_conf(CONF_ENABLE_W0);
-    spi_ctrl_start_user();
-    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
-    spi_ctrl_stop_user();
-    spi_conf_remove(CONF_ENABLE_W0);
-
-    /* Check what was written */
-    read_page_mem(my_page_addr, page);
-    for (i = 0; i < PAGE_SIZE / 4; i++) {
-        g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
-    }
-
-    /* Check some other page. It should be full of 0xff */
-    read_page_mem(some_page_addr, page);
-    for (i = 0; i < PAGE_SIZE / 4; i++) {
-        g_assert_cmphex(page[i], ==, 0xffffffff);
-    }
-
-    flash_reset();
-}
-
-static void test_write_page_mem(void)
-{
-    uint32_t my_page_addr = 0x15000 * PAGE_SIZE;
-    uint32_t page[PAGE_SIZE / 4];
-    int i;
-
-    /* Enable 4BYTE mode for controller. This is should be strapped by
-     * HW for CE0 anyhow.
-     */
-    spi_ce_ctrl(1 << CRTL_EXTENDED0);
-
-    /* Enable 4BYTE mode for flash. */
-    spi_conf(CONF_ENABLE_W0);
-    spi_ctrl_start_user();
-    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
-    writeb(ASPEED_FLASH_BASE, WREN);
-    spi_ctrl_stop_user();
-
-    /* move out USER mode to use direct writes to the AHB bus */
-    spi_ctrl_setmode(CTRL_WRITEMODE, PP);
-
-    for (i = 0; i < PAGE_SIZE / 4; i++) {
-        writel(ASPEED_FLASH_BASE + my_page_addr + i * 4,
-               make_be32(my_page_addr + i * 4));
-    }
-
-    /* Check what was written */
-    read_page_mem(my_page_addr, page);
-    for (i = 0; i < PAGE_SIZE / 4; i++) {
-        g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
-    }
-
-    flash_reset();
-}
-
-static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX";
-
-int main(int argc, char **argv)
-{
-    int ret;
-    int fd;
-
-    g_test_init(&argc, &argv, NULL);
-
-    fd = mkstemp(tmp_path);
-    g_assert(fd >= 0);
-    ret = ftruncate(fd, FLASH_SIZE);
-    g_assert(ret == 0);
-    close(fd);
-
-    global_qtest = qtest_initf("-m 256 -machine palmetto-bmc "
-                               "-drive file=%s,format=raw,if=mtd",
-                               tmp_path);
-
-    qtest_add_func("/m25p80/read_jedec", test_read_jedec);
-    qtest_add_func("/m25p80/erase_sector", test_erase_sector);
-    qtest_add_func("/m25p80/erase_all",  test_erase_all);
-    qtest_add_func("/m25p80/write_page", test_write_page);
-    qtest_add_func("/m25p80/read_page_mem", test_read_page_mem);
-    qtest_add_func("/m25p80/write_page_mem", test_write_page_mem);
-
-    ret = g_test_run();
-
-    qtest_quit(global_qtest);
-    unlink(tmp_path);
-    return ret;
-}
diff --git a/tests/m48t59-test.c b/tests/m48t59-test.c
deleted file mode 100644 (file)
index b94a123..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * QTest testcase for the M48T59 and M48T08 real-time clocks
- *
- * Based on MC146818 RTC test:
- * Copyright IBM, Corp. 2012
- *
- * Authors:
- *  Anthony Liguori   <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-
-#include "libqtest.h"
-
-#define RTC_SECONDS             0x9
-#define RTC_MINUTES             0xa
-#define RTC_HOURS               0xb
-
-#define RTC_DAY_OF_WEEK         0xc
-#define RTC_DAY_OF_MONTH        0xd
-#define RTC_MONTH               0xe
-#define RTC_YEAR                0xf
-
-static uint32_t base;
-static uint16_t reg_base = 0x1ff0; /* 0x7f0 for m48t02 */
-static int base_year;
-static const char *base_machine;
-static bool use_mmio;
-
-static uint8_t cmos_read_mmio(QTestState *s, uint8_t reg)
-{
-    return qtest_readb(s, base + (uint32_t)reg_base + (uint32_t)reg);
-}
-
-static void cmos_write_mmio(QTestState *s, uint8_t reg, uint8_t val)
-{
-    uint8_t data = val;
-
-    qtest_writeb(s, base + (uint32_t)reg_base + (uint32_t)reg, data);
-}
-
-static uint8_t cmos_read_ioio(QTestState *s, uint8_t reg)
-{
-    qtest_outw(s, base + 0, reg_base + (uint16_t)reg);
-    return qtest_inb(s, base + 3);
-}
-
-static void cmos_write_ioio(QTestState *s, uint8_t reg, uint8_t val)
-{
-    qtest_outw(s, base + 0, reg_base + (uint16_t)reg);
-    qtest_outb(s, base + 3, val);
-}
-
-static uint8_t cmos_read(QTestState *s, uint8_t reg)
-{
-    if (use_mmio) {
-        return cmos_read_mmio(s, reg);
-    } else {
-        return cmos_read_ioio(s, reg);
-    }
-}
-
-static void cmos_write(QTestState *s, uint8_t reg, uint8_t val)
-{
-    if (use_mmio) {
-        cmos_write_mmio(s, reg, val);
-    } else {
-        cmos_write_ioio(s, reg, val);
-    }
-}
-
-static int bcd2dec(int value)
-{
-    return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
-}
-
-static int tm_cmp(struct tm *lhs, struct tm *rhs)
-{
-    time_t a, b;
-    struct tm d1, d2;
-
-    memcpy(&d1, lhs, sizeof(d1));
-    memcpy(&d2, rhs, sizeof(d2));
-
-    a = mktime(&d1);
-    b = mktime(&d2);
-
-    if (a < b) {
-        return -1;
-    } else if (a > b) {
-        return 1;
-    }
-
-    return 0;
-}
-
-#if 0
-static void print_tm(struct tm *tm)
-{
-    printf("%04d-%02d-%02d %02d:%02d:%02d %+02ld\n",
-           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
-           tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
-}
-#endif
-
-static void cmos_get_date_time(QTestState *s, struct tm *date)
-{
-    int sec, min, hour, mday, mon, year;
-    time_t ts;
-    struct tm dummy;
-
-    sec = cmos_read(s, RTC_SECONDS);
-    min = cmos_read(s, RTC_MINUTES);
-    hour = cmos_read(s, RTC_HOURS);
-    mday = cmos_read(s, RTC_DAY_OF_MONTH);
-    mon = cmos_read(s, RTC_MONTH);
-    year = cmos_read(s, RTC_YEAR);
-
-    sec = bcd2dec(sec);
-    min = bcd2dec(min);
-    hour = bcd2dec(hour);
-    mday = bcd2dec(mday);
-    mon = bcd2dec(mon);
-    year = bcd2dec(year);
-
-    ts = time(NULL);
-    localtime_r(&ts, &dummy);
-
-    date->tm_isdst = dummy.tm_isdst;
-    date->tm_sec = sec;
-    date->tm_min = min;
-    date->tm_hour = hour;
-    date->tm_mday = mday;
-    date->tm_mon = mon - 1;
-    date->tm_year = base_year + year - 1900;
-#ifndef __sun__
-    date->tm_gmtoff = 0;
-#endif
-
-    ts = mktime(date);
-}
-
-static QTestState *m48t59_qtest_start(void)
-{
-    return qtest_initf("-M %s -rtc clock=vm", base_machine);
-}
-
-static void bcd_check_time(void)
-{
-    struct tm start, date[4], end;
-    struct tm *datep;
-    time_t ts;
-    const int wiggle = 2;
-    QTestState *s = m48t59_qtest_start();
-
-    /*
-     * This check assumes a few things.  First, we cannot guarantee that we get
-     * a consistent reading from the wall clock because we may hit an edge of
-     * the clock while reading.  To work around this, we read four clock readings
-     * such that at least two of them should match.  We need to assume that one
-     * reading is corrupt so we need four readings to ensure that we have at
-     * least two consecutive identical readings
-     *
-     * It's also possible that we'll cross an edge reading the host clock so
-     * simply check to make sure that the clock reading is within the period of
-     * when we expect it to be.
-     */
-
-    ts = time(NULL);
-    gmtime_r(&ts, &start);
-
-    cmos_get_date_time(s, &date[0]);
-    cmos_get_date_time(s, &date[1]);
-    cmos_get_date_time(s, &date[2]);
-    cmos_get_date_time(s, &date[3]);
-
-    ts = time(NULL);
-    gmtime_r(&ts, &end);
-
-    if (tm_cmp(&date[0], &date[1]) == 0) {
-        datep = &date[0];
-    } else if (tm_cmp(&date[1], &date[2]) == 0) {
-        datep = &date[1];
-    } else if (tm_cmp(&date[2], &date[3]) == 0) {
-        datep = &date[2];
-    } else {
-        g_assert_not_reached();
-    }
-
-    if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
-        long t, s;
-
-        start.tm_isdst = datep->tm_isdst;
-
-        t = (long)mktime(datep);
-        s = (long)mktime(&start);
-        if (t < s) {
-            g_test_message("RTC is %ld second(s) behind wall-clock", (s - t));
-        } else {
-            g_test_message("RTC is %ld second(s) ahead of wall-clock", (t - s));
-        }
-
-        g_assert_cmpint(ABS(t - s), <=, wiggle);
-    }
-
-    qtest_quit(s);
-}
-
-/* success if no crash or abort */
-static void fuzz_registers(void)
-{
-    unsigned int i;
-    QTestState *s = m48t59_qtest_start();
-
-    for (i = 0; i < 1000; i++) {
-        uint8_t reg, val;
-
-        reg = (uint8_t)g_test_rand_int_range(0, 16);
-        val = (uint8_t)g_test_rand_int_range(0, 256);
-
-        if (reg == 7) {
-            /* watchdog setup register, may trigger system reset, skip */
-            continue;
-        }
-
-        cmos_write(s, reg, val);
-        cmos_read(s, reg);
-    }
-
-    qtest_quit(s);
-}
-
-static void base_setup(void)
-{
-    const char *arch = qtest_get_arch();
-
-    if (g_str_equal(arch, "sparc")) {
-        /* Note: For sparc64, we'd need to map-in the PCI bridge memory first */
-        base = 0x71200000;
-        base_year = 1968;
-        base_machine = "SS-5";
-        use_mmio = true;
-    } else if (g_str_equal(arch, "ppc") || g_str_equal(arch, "ppc64")) {
-        base = 0xF0000000;
-        base_year = 1968;
-        base_machine = "ref405ep";
-        use_mmio = true;
-    } else {
-        g_assert_not_reached();
-    }
-}
-
-int main(int argc, char **argv)
-{
-    base_setup();
-
-    g_test_init(&argc, &argv, NULL);
-
-    if (g_test_slow()) {
-        /* Do not run this in timing-sensitive environments */
-        qtest_add_func("/rtc/bcd-check-time", bcd_check_time);
-    }
-    qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
-    return g_test_run();
-}
diff --git a/tests/machine-none-test.c b/tests/machine-none-test.c
deleted file mode 100644 (file)
index 5953d31..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Machine 'none' tests.
- *
- * Copyright (c) 2018 Red Hat Inc.
- *
- * Authors:
- *  Igor Mammedov <[email protected]>,
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-
-#include "qemu-common.h"
-#include "qemu/cutils.h"
-#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-
-
-struct arch2cpu {
-    const char *arch;
-    const char *cpu_model;
-};
-
-static struct arch2cpu cpus_map[] = {
-    /* tested targets list */
-    { "arm", "cortex-a15" },
-    { "aarch64", "cortex-a57" },
-    { "x86_64", "qemu64,apic-id=0" },
-    { "i386", "qemu32,apic-id=0" },
-    { "alpha", "ev67" },
-    { "cris", "crisv32" },
-    { "lm32", "lm32-full" },
-    { "m68k", "m5206" },
-    /* FIXME: { "microblaze", "any" }, doesn't work with -M none -cpu any */
-    /* FIXME: { "microblazeel", "any" }, doesn't work with -M none -cpu any */
-    { "mips", "4Kc" },
-    { "mipsel", "I7200" },
-    { "mips64", "20Kc" },
-    { "mips64el", "I6500" },
-    { "moxie", "MoxieLite" },
-    { "nios2", "FIXME" },
-    { "or1k", "or1200" },
-    { "ppc", "604" },
-    { "ppc64", "power8e_v2.1" },
-    { "s390x", "qemu" },
-    { "sh4", "sh7750r" },
-    { "sh4eb", "sh7751r" },
-    { "sparc", "LEON2" },
-    { "sparc64", "Fujitsu Sparc64" },
-    { "tricore", "tc1796" },
-    { "unicore32", "UniCore-II" },
-    { "xtensa", "dc233c" },
-    { "xtensaeb", "fsf" },
-    { "hppa", "hppa" },
-    { "riscv64", "rv64gcsu-v1.10.0" },
-    { "riscv32", "rv32gcsu-v1.9.1" },
-};
-
-static const char *get_cpu_model_by_arch(const char *arch)
-{
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(cpus_map); i++) {
-        if (!strcmp(arch, cpus_map[i].arch)) {
-            return cpus_map[i].cpu_model;
-        }
-    }
-    return NULL;
-}
-
-static void test_machine_cpu_cli(void)
-{
-    QDict *response;
-    const char *arch = qtest_get_arch();
-    const char *cpu_model = get_cpu_model_by_arch(arch);
-    QTestState *qts;
-
-    if (!cpu_model) {
-        if (!(!strcmp(arch, "microblaze") || !strcmp(arch, "microblazeel"))) {
-            fprintf(stderr, "WARNING: cpu name for target '%s' isn't defined,"
-                    " add it to cpus_map\n", arch);
-        }
-        return; /* TODO: die here to force all targets have a test */
-    }
-    qts = qtest_initf("-machine none -cpu '%s'", cpu_model);
-
-    response = qtest_qmp(qts, "{ 'execute': 'quit' }");
-    g_assert(qdict_haskey(response, "return"));
-    qobject_unref(response);
-
-    qtest_quit(qts);
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("machine/none/cpu_option", test_machine_cpu_cli);
-
-    return g_test_run();
-}
diff --git a/tests/megasas-test.c b/tests/megasas-test.c
deleted file mode 100644 (file)
index d6796b9..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * QTest testcase for LSI MegaRAID
- *
- * Copyright (c) 2017 Red Hat Inc.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qemu/bswap.h"
-#include "qemu/module.h"
-#include "libqos/qgraph.h"
-#include "libqos/pci.h"
-
-typedef struct QMegasas QMegasas;
-
-struct QMegasas {
-    QOSGraphObject obj;
-    QPCIDevice dev;
-};
-
-static void *megasas_get_driver(void *obj, const char *interface)
-{
-    QMegasas *megasas = obj;
-
-    if (!g_strcmp0(interface, "pci-device")) {
-        return &megasas->dev;
-    }
-
-    fprintf(stderr, "%s not present in megasas\n", interface);
-    g_assert_not_reached();
-}
-
-static void *megasas_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
-{
-    QMegasas *megasas = g_new0(QMegasas, 1);
-    QPCIBus *bus = pci_bus;
-
-    qpci_device_init(&megasas->dev, bus, addr);
-    megasas->obj.get_driver = megasas_get_driver;
-
-    return &megasas->obj;
-}
-
-/* This used to cause a NULL pointer dereference.  */
-static void megasas_pd_get_info_fuzz(void *obj, void *data, QGuestAllocator *alloc)
-{
-    QMegasas *megasas = obj;
-    QPCIDevice *dev = &megasas->dev;
-    QPCIBar bar;
-    uint32_t context[256];
-    uint64_t context_pa;
-    int i;
-
-    qpci_device_enable(dev);
-    bar = qpci_iomap(dev, 0, NULL);
-
-    memset(context, 0, sizeof(context));
-    context[0] = cpu_to_le32(0x05050505);
-    context[1] = cpu_to_le32(0x01010101);
-    for (i = 2; i < ARRAY_SIZE(context); i++) {
-        context[i] = cpu_to_le32(0x41414141);
-    }
-    context[6] = cpu_to_le32(0x02020000);
-    context[7] = cpu_to_le32(0);
-
-    context_pa = guest_alloc(alloc, sizeof(context));
-    qtest_memwrite(dev->bus->qts, context_pa, context, sizeof(context));
-    qpci_io_writel(dev, bar, 0x40, context_pa);
-}
-
-static void megasas_register_nodes(void)
-{
-    QOSGraphEdgeOptions opts = {
-        .extra_device_opts = "addr=04.0,id=scsi0",
-        .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,"
-                           "file.read-zeroes=on,format=raw",
-        .after_cmd_line = "-device scsi-hd,bus=scsi0.0,drive=drv0",
-    };
-
-    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
-
-    qos_node_create_driver("megasas", megasas_create);
-    qos_node_consumes("megasas", "pci-bus", &opts);
-    qos_node_produces("megasas", "pci-device");
-
-    qos_add_test("dcmd/pd-get-info/fuzz", "megasas", megasas_pd_get_info_fuzz, NULL);
-}
-libqos_init(megasas_register_nodes);
diff --git a/tests/microbit-test.c b/tests/microbit-test.c
deleted file mode 100644 (file)
index 04e199e..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * QTest testcase for Microbit board using the Nordic Semiconductor nRF51 SoC.
- *
- * nRF51:
- * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
- * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
- *
- * Microbit Board: http://microbit.org/
- *
- * Copyright 2018 Steffen Görtz <[email protected]>
- *
- * This code is licensed under the GPL version 2 or later.  See
- * the COPYING file in the top-level directory.
- */
-
-
-#include "qemu/osdep.h"
-#include "exec/hwaddr.h"
-#include "libqtest.h"
-
-#include "hw/arm/nrf51.h"
-#include "hw/char/nrf51_uart.h"
-#include "hw/gpio/nrf51_gpio.h"
-#include "hw/nvram/nrf51_nvm.h"
-#include "hw/timer/nrf51_timer.h"
-#include "hw/i2c/microbit_i2c.h"
-
-static bool uart_wait_for_event(QTestState *qts, uint32_t event_addr)
-{
-    time_t now, start = time(NULL);
-
-    while (true) {
-        if (qtest_readl(qts, event_addr) == 1) {
-            qtest_writel(qts, event_addr, 0x00);
-            return true;
-        }
-
-        /* Wait at most 10 minutes */
-        now = time(NULL);
-        if (now - start > 600) {
-            break;
-        }
-        g_usleep(10000);
-    }
-
-    return false;
-}
-
-static void uart_rw_to_rxd(QTestState *qts, int sock_fd, const char *in,
-                           char *out)
-{
-    int i, in_len = strlen(in);
-
-    g_assert_true(write(sock_fd, in, in_len) == in_len);
-    for (i = 0; i < in_len; i++) {
-        g_assert_true(uart_wait_for_event(qts, NRF51_UART_BASE +
-                                               A_UART_RXDRDY));
-        out[i] = qtest_readl(qts, NRF51_UART_BASE + A_UART_RXD);
-    }
-    out[i] = '\0';
-}
-
-static void uart_w_to_txd(QTestState *qts, const char *in)
-{
-    int i, in_len = strlen(in);
-
-    for (i = 0; i < in_len; i++) {
-        qtest_writel(qts, NRF51_UART_BASE + A_UART_TXD, in[i]);
-        g_assert_true(uart_wait_for_event(qts, NRF51_UART_BASE +
-                                               A_UART_TXDRDY));
-    }
-}
-
-static void test_nrf51_uart(void)
-{
-    int sock_fd;
-    char s[10];
-    QTestState *qts = qtest_init_with_serial("-M microbit", &sock_fd);
-
-    g_assert_true(write(sock_fd, "c", 1) == 1);
-    g_assert_cmphex(qtest_readl(qts, NRF51_UART_BASE + A_UART_RXD), ==, 0x00);
-
-    qtest_writel(qts, NRF51_UART_BASE + A_UART_ENABLE, 0x04);
-    qtest_writel(qts, NRF51_UART_BASE + A_UART_STARTRX, 0x01);
-
-    g_assert_true(uart_wait_for_event(qts, NRF51_UART_BASE + A_UART_RXDRDY));
-    qtest_writel(qts, NRF51_UART_BASE + A_UART_RXDRDY, 0x00);
-    g_assert_cmphex(qtest_readl(qts, NRF51_UART_BASE + A_UART_RXD), ==, 'c');
-
-    qtest_writel(qts, NRF51_UART_BASE + A_UART_INTENSET, 0x04);
-    g_assert_cmphex(qtest_readl(qts, NRF51_UART_BASE + A_UART_INTEN), ==, 0x04);
-    qtest_writel(qts, NRF51_UART_BASE + A_UART_INTENCLR, 0x04);
-    g_assert_cmphex(qtest_readl(qts, NRF51_UART_BASE + A_UART_INTEN), ==, 0x00);
-
-    uart_rw_to_rxd(qts, sock_fd, "hello", s);
-    g_assert_true(memcmp(s, "hello", 5) == 0);
-
-    qtest_writel(qts, NRF51_UART_BASE + A_UART_STARTTX, 0x01);
-    uart_w_to_txd(qts, "d");
-    g_assert_true(read(sock_fd, s, 10) == 1);
-    g_assert_cmphex(s[0], ==, 'd');
-
-    qtest_writel(qts, NRF51_UART_BASE + A_UART_SUSPEND, 0x01);
-    qtest_writel(qts, NRF51_UART_BASE + A_UART_TXD, 'h');
-    qtest_writel(qts, NRF51_UART_BASE + A_UART_STARTTX, 0x01);
-    uart_w_to_txd(qts, "world");
-    g_assert_true(read(sock_fd, s, 10) == 5);
-    g_assert_true(memcmp(s, "world", 5) == 0);
-
-    close(sock_fd);
-
-    qtest_quit(qts);
-}
-
-/* Read a byte from I2C device at @addr from register @reg */
-static uint32_t i2c_read_byte(QTestState *qts, uint32_t addr, uint32_t reg)
-{
-    uint32_t val;
-
-    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_REG_ADDRESS, addr);
-    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_TASK_STARTTX, 1);
-    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_REG_TXD, reg);
-    val = qtest_readl(qts, NRF51_TWI_BASE + NRF51_TWI_EVENT_TXDSENT);
-    g_assert_cmpuint(val, ==, 1);
-    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_TASK_STOP, 1);
-
-    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_TASK_STARTRX, 1);
-    val = qtest_readl(qts, NRF51_TWI_BASE + NRF51_TWI_EVENT_RXDREADY);
-    g_assert_cmpuint(val, ==, 1);
-    val = qtest_readl(qts, NRF51_TWI_BASE + NRF51_TWI_REG_RXD);
-    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_TASK_STOP, 1);
-
-    return val;
-}
-
-static void test_microbit_i2c(void)
-{
-    uint32_t val;
-    QTestState *qts = qtest_init("-M microbit");
-
-    /* We don't program pins/irqs but at least enable the device */
-    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_REG_ENABLE, 5);
-
-    /* MMA8653 magnetometer detection */
-    val = i2c_read_byte(qts, 0x3A, 0x0D);
-    g_assert_cmpuint(val, ==, 0x5A);
-
-    val = i2c_read_byte(qts, 0x3A, 0x0D);
-    g_assert_cmpuint(val, ==, 0x5A);
-
-    /* LSM303 accelerometer detection */
-    val = i2c_read_byte(qts, 0x3C, 0x4F);
-    g_assert_cmpuint(val, ==, 0x40);
-
-    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_REG_ENABLE, 0);
-
-    qtest_quit(qts);
-}
-
-#define FLASH_SIZE          (256 * NRF51_PAGE_SIZE)
-
-static void fill_and_erase(QTestState *qts, hwaddr base, hwaddr size,
-                           uint32_t address_reg)
-{
-    hwaddr i;
-
-    /* Erase Page */
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02);
-    qtest_writel(qts, NRF51_NVMC_BASE + address_reg, base);
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
-
-    /* Check memory */
-    for (i = 0; i < size / 4; i++) {
-        g_assert_cmpuint(qtest_readl(qts, base + i * 4), ==, 0xFFFFFFFF);
-    }
-
-    /* Fill memory */
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x01);
-    for (i = 0; i < size / 4; i++) {
-        qtest_writel(qts, base + i * 4, i);
-        g_assert_cmpuint(qtest_readl(qts, base + i * 4), ==, i);
-    }
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
-}
-
-static void test_nrf51_nvmc(void)
-{
-    uint32_t value;
-    hwaddr i;
-    QTestState *qts = qtest_init("-M microbit");
-
-    /* Test always ready */
-    value = qtest_readl(qts, NRF51_NVMC_BASE + NRF51_NVMC_READY);
-    g_assert_cmpuint(value & 0x01, ==, 0x01);
-
-    /* Test write-read config register */
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x03);
-    g_assert_cmpuint(qtest_readl(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG),
-                     ==, 0x03);
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
-    g_assert_cmpuint(qtest_readl(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG),
-                     ==, 0x00);
-
-    /* Test PCR0 */
-    fill_and_erase(qts, NRF51_FLASH_BASE, NRF51_PAGE_SIZE,
-                   NRF51_NVMC_ERASEPCR0);
-    fill_and_erase(qts, NRF51_FLASH_BASE + NRF51_PAGE_SIZE,
-                   NRF51_PAGE_SIZE, NRF51_NVMC_ERASEPCR0);
-
-    /* Test PCR1 */
-    fill_and_erase(qts, NRF51_FLASH_BASE, NRF51_PAGE_SIZE,
-                   NRF51_NVMC_ERASEPCR1);
-    fill_and_erase(qts, NRF51_FLASH_BASE + NRF51_PAGE_SIZE,
-                   NRF51_PAGE_SIZE, NRF51_NVMC_ERASEPCR1);
-
-    /* Erase all */
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02);
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_ERASEALL, 0x01);
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
-
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x01);
-    for (i = 0; i < FLASH_SIZE / 4; i++) {
-        qtest_writel(qts, NRF51_FLASH_BASE + i * 4, i);
-        g_assert_cmpuint(qtest_readl(qts, NRF51_FLASH_BASE + i * 4), ==, i);
-    }
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
-
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02);
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_ERASEALL, 0x01);
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
-
-    for (i = 0; i < FLASH_SIZE / 4; i++) {
-        g_assert_cmpuint(qtest_readl(qts, NRF51_FLASH_BASE + i * 4),
-                         ==, 0xFFFFFFFF);
-    }
-
-    /* Erase UICR */
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02);
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_ERASEUICR, 0x01);
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
-
-    for (i = 0; i < NRF51_UICR_SIZE / 4; i++) {
-        g_assert_cmpuint(qtest_readl(qts, NRF51_UICR_BASE + i * 4),
-                         ==, 0xFFFFFFFF);
-    }
-
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x01);
-    for (i = 0; i < NRF51_UICR_SIZE / 4; i++) {
-        qtest_writel(qts, NRF51_UICR_BASE + i * 4, i);
-        g_assert_cmpuint(qtest_readl(qts, NRF51_UICR_BASE + i * 4), ==, i);
-    }
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
-
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02);
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_ERASEUICR, 0x01);
-    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
-
-    for (i = 0; i < NRF51_UICR_SIZE / 4; i++) {
-        g_assert_cmpuint(qtest_readl(qts, NRF51_UICR_BASE + i * 4),
-                         ==, 0xFFFFFFFF);
-    }
-
-    qtest_quit(qts);
-}
-
-static void test_nrf51_gpio(void)
-{
-    size_t i;
-    uint32_t actual, expected;
-
-    struct {
-        hwaddr addr;
-        uint32_t expected;
-    } const reset_state[] = {
-        {NRF51_GPIO_REG_OUT, 0x00000000}, {NRF51_GPIO_REG_OUTSET, 0x00000000},
-        {NRF51_GPIO_REG_OUTCLR, 0x00000000}, {NRF51_GPIO_REG_IN, 0x00000000},
-        {NRF51_GPIO_REG_DIR, 0x00000000}, {NRF51_GPIO_REG_DIRSET, 0x00000000},
-        {NRF51_GPIO_REG_DIRCLR, 0x00000000}
-    };
-
-    QTestState *qts = qtest_init("-M microbit");
-
-    /* Check reset state */
-    for (i = 0; i < ARRAY_SIZE(reset_state); i++) {
-        expected = reset_state[i].expected;
-        actual = qtest_readl(qts, NRF51_GPIO_BASE + reset_state[i].addr);
-        g_assert_cmpuint(actual, ==, expected);
-    }
-
-    for (i = 0; i < NRF51_GPIO_PINS; i++) {
-        expected = 0x00000002;
-        actual = qtest_readl(qts, NRF51_GPIO_BASE +
-                                  NRF51_GPIO_REG_CNF_START + i * 4);
-        g_assert_cmpuint(actual, ==, expected);
-    }
-
-    /* Check dir bit consistency between dir and cnf */
-    /* Check set via DIRSET */
-    expected = 0x80000001;
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRSET, expected);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
-    g_assert_cmpuint(actual, ==, expected);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START)
-             & 0x01;
-    g_assert_cmpuint(actual, ==, 0x01);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
-    g_assert_cmpuint(actual, ==, 0x01);
-
-    /* Check clear via DIRCLR */
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRCLR, 0x80000001);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
-    g_assert_cmpuint(actual, ==, 0x00000000);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START)
-             & 0x01;
-    g_assert_cmpuint(actual, ==, 0x00);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
-    g_assert_cmpuint(actual, ==, 0x00);
-
-    /* Check set via DIR */
-    expected = 0x80000001;
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, expected);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
-    g_assert_cmpuint(actual, ==, expected);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START)
-             & 0x01;
-    g_assert_cmpuint(actual, ==, 0x01);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
-    g_assert_cmpuint(actual, ==, 0x01);
-
-    /* Reset DIR */
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, 0x00000000);
-
-    /* Check Input propagates */
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x00);
-    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
-    g_assert_cmpuint(actual, ==, 0x00);
-    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 1);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
-    g_assert_cmpuint(actual, ==, 0x01);
-    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, -1);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
-    g_assert_cmpuint(actual, ==, 0x01);
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
-
-    /* Check pull-up working */
-    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
-    g_assert_cmpuint(actual, ==, 0x00);
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b1110);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
-    g_assert_cmpuint(actual, ==, 0x01);
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
-
-    /* Check pull-down working */
-    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 1);
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
-    g_assert_cmpuint(actual, ==, 0x01);
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0110);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
-    g_assert_cmpuint(actual, ==, 0x00);
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
-    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, -1);
-
-    /* Check Output propagates */
-    qtest_irq_intercept_out(qts, "/machine/nrf51");
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0011);
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
-    g_assert_true(qtest_get_irq(qts, 0));
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01);
-    g_assert_false(qtest_get_irq(qts, 0));
-
-    /* Check self-stimulation */
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01);
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
-    g_assert_cmpuint(actual, ==, 0x01);
-
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01);
-    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
-    g_assert_cmpuint(actual, ==, 0x00);
-
-    /*
-     * Check short-circuit - generates an guest_error which must be checked
-     * manually as long as qtest can not scan qemu_log messages
-     */
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01);
-    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
-    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
-
-    qtest_quit(qts);
-}
-
-static void timer_task(QTestState *qts, hwaddr task)
-{
-    qtest_writel(qts, NRF51_TIMER_BASE + task, NRF51_TRIGGER_TASK);
-}
-
-static void timer_clear_event(QTestState *qts, hwaddr event)
-{
-    qtest_writel(qts, NRF51_TIMER_BASE + event, NRF51_EVENT_CLEAR);
-}
-
-static void timer_set_bitmode(QTestState *qts, uint8_t mode)
-{
-    qtest_writel(qts, NRF51_TIMER_BASE + NRF51_TIMER_REG_BITMODE, mode);
-}
-
-static void timer_set_prescaler(QTestState *qts, uint8_t prescaler)
-{
-    qtest_writel(qts, NRF51_TIMER_BASE + NRF51_TIMER_REG_PRESCALER, prescaler);
-}
-
-static void timer_set_cc(QTestState *qts, size_t idx, uint32_t value)
-{
-    qtest_writel(qts, NRF51_TIMER_BASE + NRF51_TIMER_REG_CC0 + idx * 4, value);
-}
-
-static void timer_assert_events(QTestState *qts, uint32_t ev0, uint32_t ev1,
-                                uint32_t ev2, uint32_t ev3)
-{
-    g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_0)
-             == ev0);
-    g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_1)
-             == ev1);
-    g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_2)
-             == ev2);
-    g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_3)
-             == ev3);
-}
-
-static void test_nrf51_timer(void)
-{
-    uint32_t steps_to_overflow = 408;
-    QTestState *qts = qtest_init("-M microbit");
-
-    /* Compare Match */
-    timer_task(qts, NRF51_TIMER_TASK_STOP);
-    timer_task(qts, NRF51_TIMER_TASK_CLEAR);
-
-    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_0);
-    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_1);
-    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_2);
-    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_3);
-
-    timer_set_bitmode(qts, NRF51_TIMER_WIDTH_16); /* 16 MHz Timer */
-    timer_set_prescaler(qts, 0);
-    /* Swept over in first step */
-    timer_set_cc(qts, 0, 2);
-    /* Barely miss on first step */
-    timer_set_cc(qts, 1, 162);
-    /* Spot on on third step */
-    timer_set_cc(qts, 2, 480);
-
-    timer_assert_events(qts, 0, 0, 0, 0);
-
-    timer_task(qts, NRF51_TIMER_TASK_START);
-    qtest_clock_step(qts, 10000);
-    timer_assert_events(qts, 1, 0, 0, 0);
-
-    /* Swept over on first overflow */
-    timer_set_cc(qts, 3, 114);
-
-    qtest_clock_step(qts, 10000);
-    timer_assert_events(qts, 1, 1, 0, 0);
-
-    qtest_clock_step(qts, 10000);
-    timer_assert_events(qts, 1, 1, 1, 0);
-
-    /* Wrap time until internal counter overflows */
-    while (steps_to_overflow--) {
-        timer_assert_events(qts, 1, 1, 1, 0);
-        qtest_clock_step(qts, 10000);
-    }
-
-    timer_assert_events(qts, 1, 1, 1, 1);
-
-    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_0);
-    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_1);
-    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_2);
-    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_3);
-    timer_assert_events(qts, 0, 0, 0, 0);
-
-    timer_task(qts, NRF51_TIMER_TASK_STOP);
-
-    /* Test Proposal: Stop/Shutdown */
-    /* Test Proposal: Shortcut Compare -> Clear */
-    /* Test Proposal: Shortcut Compare -> Stop */
-    /* Test Proposal: Counter Mode */
-
-    qtest_quit(qts);
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("/microbit/nrf51/uart", test_nrf51_uart);
-    qtest_add_func("/microbit/nrf51/gpio", test_nrf51_gpio);
-    qtest_add_func("/microbit/nrf51/nvmc", test_nrf51_nvmc);
-    qtest_add_func("/microbit/nrf51/timer", test_nrf51_timer);
-    qtest_add_func("/microbit/microbit/i2c", test_microbit_i2c);
-
-    return g_test_run();
-}
diff --git a/tests/migration-helpers.c b/tests/migration-helpers.c
deleted file mode 100644 (file)
index 516093b..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * QTest migration helpers
- *
- * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
- *   based on the vhost-user-test.c that is:
- *      Copyright (c) 2014 Virtual Open Systems Sarl.
- *
- * 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 "qapi/qmp/qjson.h"
-
-#include "migration-helpers.h"
-
-bool got_stop;
-
-static void stop_cb(void *opaque, const char *name, QDict *data)
-{
-    if (!strcmp(name, "STOP")) {
-        got_stop = true;
-    }
-}
-
-/*
- * Events can get in the way of responses we are actually waiting for.
- */
-QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...)
-{
-    va_list ap;
-
-    va_start(ap, command);
-    qtest_qmp_vsend_fds(who, &fd, 1, command, ap);
-    va_end(ap);
-
-    return qtest_qmp_receive_success(who, stop_cb, NULL);
-}
-
-/*
- * Events can get in the way of responses we are actually waiting for.
- */
-QDict *wait_command(QTestState *who, const char *command, ...)
-{
-    va_list ap;
-
-    va_start(ap, command);
-    qtest_qmp_vsend(who, command, ap);
-    va_end(ap);
-
-    return qtest_qmp_receive_success(who, stop_cb, NULL);
-}
-
-/*
- * Send QMP command "migrate".
- * Arguments are built from @fmt... (formatted like
- * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
- */
-void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...)
-{
-    va_list ap;
-    QDict *args, *rsp;
-
-    va_start(ap, fmt);
-    args = qdict_from_vjsonf_nofail(fmt, ap);
-    va_end(ap);
-
-    g_assert(!qdict_haskey(args, "uri"));
-    qdict_put_str(args, "uri", uri);
-
-    rsp = qtest_qmp(who, "{ 'execute': 'migrate', 'arguments': %p}", args);
-
-    g_assert(qdict_haskey(rsp, "return"));
-    qobject_unref(rsp);
-}
-
-/*
- * Note: caller is responsible to free the returned object via
- * qobject_unref() after use
- */
-QDict *migrate_query(QTestState *who)
-{
-    return wait_command(who, "{ 'execute': 'query-migrate' }");
-}
-
-/*
- * Note: caller is responsible to free the returned object via
- * g_free() after use
- */
-static gchar *migrate_query_status(QTestState *who)
-{
-    QDict *rsp_return = migrate_query(who);
-    gchar *status = g_strdup(qdict_get_str(rsp_return, "status"));
-
-    g_assert(status);
-    qobject_unref(rsp_return);
-
-    return status;
-}
-
-static bool check_migration_status(QTestState *who, const char *goal,
-                                   const char **ungoals)
-{
-    bool ready;
-    char *current_status;
-    const char **ungoal;
-
-    current_status = migrate_query_status(who);
-    ready = strcmp(current_status, goal) == 0;
-    if (!ungoals) {
-        g_assert_cmpstr(current_status, !=, "failed");
-        /*
-         * If looking for a state other than completed,
-         * completion of migration would cause the test to
-         * hang.
-         */
-        if (strcmp(goal, "completed") != 0) {
-            g_assert_cmpstr(current_status, !=, "completed");
-        }
-    } else {
-        for (ungoal = ungoals; *ungoal; ungoal++) {
-            g_assert_cmpstr(current_status, !=,  *ungoal);
-        }
-    }
-    g_free(current_status);
-    return ready;
-}
-
-void wait_for_migration_status(QTestState *who,
-                               const char *goal, const char **ungoals)
-{
-    while (!check_migration_status(who, goal, ungoals)) {
-        usleep(1000);
-    }
-}
-
-void wait_for_migration_complete(QTestState *who)
-{
-    wait_for_migration_status(who, "completed", NULL);
-}
-
-void wait_for_migration_fail(QTestState *from, bool allow_active)
-{
-    QDict *rsp_return;
-    char *status;
-    bool failed;
-
-    do {
-        status = migrate_query_status(from);
-        bool result = !strcmp(status, "setup") || !strcmp(status, "failed") ||
-            (allow_active && !strcmp(status, "active"));
-        if (!result) {
-            fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n",
-                    __func__, status, allow_active);
-        }
-        g_assert(result);
-        failed = !strcmp(status, "failed");
-        g_free(status);
-    } while (!failed);
-
-    /* Is the machine currently running? */
-    rsp_return = wait_command(from, "{ 'execute': 'query-status' }");
-    g_assert(qdict_haskey(rsp_return, "running"));
-    g_assert(qdict_get_bool(rsp_return, "running"));
-    qobject_unref(rsp_return);
-}
diff --git a/tests/migration-helpers.h b/tests/migration-helpers.h
deleted file mode 100644 (file)
index a11808b..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * QTest migration helpers
- *
- * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
- *   based on the vhost-user-test.c that is:
- *      Copyright (c) 2014 Virtual Open Systems Sarl.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-#ifndef MIGRATION_HELPERS_H_
-#define MIGRATION_HELPERS_H_
-
-#include "libqtest.h"
-
-extern bool got_stop;
-
-GCC_FMT_ATTR(3, 4)
-QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...);
-
-GCC_FMT_ATTR(2, 3)
-QDict *wait_command(QTestState *who, const char *command, ...);
-
-GCC_FMT_ATTR(3, 4)
-void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...);
-
-QDict *migrate_query(QTestState *who);
-
-void wait_for_migration_status(QTestState *who,
-                               const char *goal, const char **ungoals);
-
-void wait_for_migration_complete(QTestState *who);
-
-void wait_for_migration_fail(QTestState *from, bool allow_active);
-
-#endif /* MIGRATION_HELPERS_H_ */
diff --git a/tests/migration-test.c b/tests/migration-test.c
deleted file mode 100644 (file)
index 53afec4..0000000
+++ /dev/null
@@ -1,1281 +0,0 @@
-/*
- * QTest testcase for migration
- *
- * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
- *   based on the vhost-user-test.c that is:
- *      Copyright (c) 2014 Virtual Open Systems Sarl.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-
-#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "qemu/module.h"
-#include "qemu/option.h"
-#include "qemu/range.h"
-#include "qemu/sockets.h"
-#include "chardev/char.h"
-#include "qapi/qapi-visit-sockets.h"
-#include "qapi/qobject-input-visitor.h"
-#include "qapi/qobject-output-visitor.h"
-
-#include "migration-helpers.h"
-#include "migration/migration-test.h"
-
-/* TODO actually test the results and get rid of this */
-#define qtest_qmp_discard_response(...) qobject_unref(qtest_qmp(__VA_ARGS__))
-
-unsigned start_address;
-unsigned end_address;
-static bool uffd_feature_thread_id;
-
-#if defined(__linux__)
-#include <sys/syscall.h>
-#include <sys/vfs.h>
-#endif
-
-#if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD)
-#include <sys/eventfd.h>
-#include <sys/ioctl.h>
-#include <linux/userfaultfd.h>
-
-static bool ufd_version_check(void)
-{
-    struct uffdio_api api_struct;
-    uint64_t ioctl_mask;
-
-    int ufd = syscall(__NR_userfaultfd, O_CLOEXEC);
-
-    if (ufd == -1) {
-        g_test_message("Skipping test: userfaultfd not available");
-        return false;
-    }
-
-    api_struct.api = UFFD_API;
-    api_struct.features = 0;
-    if (ioctl(ufd, UFFDIO_API, &api_struct)) {
-        g_test_message("Skipping test: UFFDIO_API failed");
-        return false;
-    }
-    uffd_feature_thread_id = api_struct.features & UFFD_FEATURE_THREAD_ID;
-
-    ioctl_mask = (__u64)1 << _UFFDIO_REGISTER |
-                 (__u64)1 << _UFFDIO_UNREGISTER;
-    if ((api_struct.ioctls & ioctl_mask) != ioctl_mask) {
-        g_test_message("Skipping test: Missing userfault feature");
-        return false;
-    }
-
-    return true;
-}
-
-#else
-static bool ufd_version_check(void)
-{
-    g_test_message("Skipping test: Userfault not available (builtdtime)");
-    return false;
-}
-
-#endif
-
-static const char *tmpfs;
-
-/* The boot file modifies memory area in [start_address, end_address)
- * repeatedly. It outputs a 'B' at a fixed rate while it's still running.
- */
-#include "tests/migration/i386/a-b-bootblock.h"
-#include "tests/migration/aarch64/a-b-kernel.h"
-#include "tests/migration/s390x/a-b-bios.h"
-
-static void init_bootfile(const char *bootpath, void *content, size_t len)
-{
-    FILE *bootfile = fopen(bootpath, "wb");
-
-    g_assert_cmpint(fwrite(content, len, 1, bootfile), ==, 1);
-    fclose(bootfile);
-}
-
-/*
- * Wait for some output in the serial output file,
- * we get an 'A' followed by an endless string of 'B's
- * but on the destination we won't have the A.
- */
-static void wait_for_serial(const char *side)
-{
-    char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
-    FILE *serialfile = fopen(serialpath, "r");
-    const char *arch = qtest_get_arch();
-    int started = (strcmp(side, "src_serial") == 0 &&
-                   strcmp(arch, "ppc64") == 0) ? 0 : 1;
-
-    g_free(serialpath);
-    do {
-        int readvalue = fgetc(serialfile);
-
-        if (!started) {
-            /* SLOF prints its banner before starting test,
-             * to ignore it, mark the start of the test with '_',
-             * ignore all characters until this marker
-             */
-            switch (readvalue) {
-            case '_':
-                started = 1;
-                break;
-            case EOF:
-                fseek(serialfile, 0, SEEK_SET);
-                usleep(1000);
-                break;
-            }
-            continue;
-        }
-        switch (readvalue) {
-        case 'A':
-            /* Fine */
-            break;
-
-        case 'B':
-            /* It's alive! */
-            fclose(serialfile);
-            return;
-
-        case EOF:
-            started = (strcmp(side, "src_serial") == 0 &&
-                       strcmp(arch, "ppc64") == 0) ? 0 : 1;
-            fseek(serialfile, 0, SEEK_SET);
-            usleep(1000);
-            break;
-
-        default:
-            fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, side);
-            g_assert_not_reached();
-        }
-    } while (true);
-}
-
-/*
- * It's tricky to use qemu's migration event capability with qtest,
- * events suddenly appearing confuse the qmp()/hmp() responses.
- */
-
-static int64_t read_ram_property_int(QTestState *who, const char *property)
-{
-    QDict *rsp_return, *rsp_ram;
-    int64_t result;
-
-    rsp_return = migrate_query(who);
-    if (!qdict_haskey(rsp_return, "ram")) {
-        /* Still in setup */
-        result = 0;
-    } else {
-        rsp_ram = qdict_get_qdict(rsp_return, "ram");
-        result = qdict_get_try_int(rsp_ram, property, 0);
-    }
-    qobject_unref(rsp_return);
-    return result;
-}
-
-static int64_t read_migrate_property_int(QTestState *who, const char *property)
-{
-    QDict *rsp_return;
-    int64_t result;
-
-    rsp_return = migrate_query(who);
-    result = qdict_get_try_int(rsp_return, property, 0);
-    qobject_unref(rsp_return);
-    return result;
-}
-
-static uint64_t get_migration_pass(QTestState *who)
-{
-    return read_ram_property_int(who, "dirty-sync-count");
-}
-
-static void read_blocktime(QTestState *who)
-{
-    QDict *rsp_return;
-
-    rsp_return = migrate_query(who);
-    g_assert(qdict_haskey(rsp_return, "postcopy-blocktime"));
-    qobject_unref(rsp_return);
-}
-
-static void wait_for_migration_pass(QTestState *who)
-{
-    uint64_t initial_pass = get_migration_pass(who);
-    uint64_t pass;
-
-    /* Wait for the 1st sync */
-    while (!got_stop && !initial_pass) {
-        usleep(1000);
-        initial_pass = get_migration_pass(who);
-    }
-
-    do {
-        usleep(1000);
-        pass = get_migration_pass(who);
-    } while (pass == initial_pass && !got_stop);
-}
-
-static void check_guests_ram(QTestState *who)
-{
-    /* Our ASM test will have been incrementing one byte from each page from
-     * start_address to < end_address in order. This gives us a constraint
-     * that any page's byte should be equal or less than the previous pages
-     * byte (mod 256); and they should all be equal except for one transition
-     * at the point where we meet the incrementer. (We're running this with
-     * the guest stopped).
-     */
-    unsigned address;
-    uint8_t first_byte;
-    uint8_t last_byte;
-    bool hit_edge = false;
-    int bad = 0;
-
-    qtest_memread(who, start_address, &first_byte, 1);
-    last_byte = first_byte;
-
-    for (address = start_address + TEST_MEM_PAGE_SIZE; address < end_address;
-         address += TEST_MEM_PAGE_SIZE)
-    {
-        uint8_t b;
-        qtest_memread(who, address, &b, 1);
-        if (b != last_byte) {
-            if (((b + 1) % 256) == last_byte && !hit_edge) {
-                /* This is OK, the guest stopped at the point of
-                 * incrementing the previous page but didn't get
-                 * to us yet.
-                 */
-                hit_edge = true;
-                last_byte = b;
-            } else {
-                bad++;
-                if (bad <= 10) {
-                    fprintf(stderr, "Memory content inconsistency at %x"
-                            " first_byte = %x last_byte = %x current = %x"
-                            " hit_edge = %x\n",
-                            address, first_byte, last_byte, b, hit_edge);
-                }
-            }
-        }
-    }
-    if (bad >= 10) {
-        fprintf(stderr, "and in another %d pages", bad - 10);
-    }
-    g_assert(bad == 0);
-}
-
-static void cleanup(const char *filename)
-{
-    char *path = g_strdup_printf("%s/%s", tmpfs, filename);
-
-    unlink(path);
-    g_free(path);
-}
-
-static char *SocketAddress_to_str(SocketAddress *addr)
-{
-    switch (addr->type) {
-    case SOCKET_ADDRESS_TYPE_INET:
-        return g_strdup_printf("tcp:%s:%s",
-                               addr->u.inet.host,
-                               addr->u.inet.port);
-    case SOCKET_ADDRESS_TYPE_UNIX:
-        return g_strdup_printf("unix:%s",
-                               addr->u.q_unix.path);
-    case SOCKET_ADDRESS_TYPE_FD:
-        return g_strdup_printf("fd:%s", addr->u.fd.str);
-    case SOCKET_ADDRESS_TYPE_VSOCK:
-        return g_strdup_printf("tcp:%s:%s",
-                               addr->u.vsock.cid,
-                               addr->u.vsock.port);
-    default:
-        return g_strdup("unknown address type");
-    }
-}
-
-static char *migrate_get_socket_address(QTestState *who, const char *parameter)
-{
-    QDict *rsp;
-    char *result;
-    Error *local_err = NULL;
-    SocketAddressList *addrs;
-    Visitor *iv = NULL;
-    QObject *object;
-
-    rsp = migrate_query(who);
-    object = qdict_get(rsp, parameter);
-
-    iv = qobject_input_visitor_new(object);
-    visit_type_SocketAddressList(iv, NULL, &addrs, &local_err);
-    visit_free(iv);
-
-    /* we are only using a single address */
-    result = SocketAddress_to_str(addrs->value);
-
-    qapi_free_SocketAddressList(addrs);
-    qobject_unref(rsp);
-    return result;
-}
-
-static long long migrate_get_parameter_int(QTestState *who,
-                                           const char *parameter)
-{
-    QDict *rsp;
-    long long result;
-
-    rsp = wait_command(who, "{ 'execute': 'query-migrate-parameters' }");
-    result = qdict_get_int(rsp, parameter);
-    qobject_unref(rsp);
-    return result;
-}
-
-static void migrate_check_parameter_int(QTestState *who, const char *parameter,
-                                        long long value)
-{
-    long long result;
-
-    result = migrate_get_parameter_int(who, parameter);
-    g_assert_cmpint(result, ==, value);
-}
-
-static void migrate_set_parameter_int(QTestState *who, const char *parameter,
-                                      long long value)
-{
-    QDict *rsp;
-
-    rsp = qtest_qmp(who,
-                    "{ 'execute': 'migrate-set-parameters',"
-                    "'arguments': { %s: %lld } }",
-                    parameter, value);
-    g_assert(qdict_haskey(rsp, "return"));
-    qobject_unref(rsp);
-    migrate_check_parameter_int(who, parameter, value);
-}
-
-static void migrate_pause(QTestState *who)
-{
-    QDict *rsp;
-
-    rsp = wait_command(who, "{ 'execute': 'migrate-pause' }");
-    qobject_unref(rsp);
-}
-
-static void migrate_continue(QTestState *who, const char *state)
-{
-    QDict *rsp;
-
-    rsp = wait_command(who,
-                       "{ 'execute': 'migrate-continue',"
-                       "  'arguments': { 'state': %s } }",
-                       state);
-    qobject_unref(rsp);
-}
-
-static void migrate_recover(QTestState *who, const char *uri)
-{
-    QDict *rsp;
-
-    rsp = wait_command(who,
-                       "{ 'execute': 'migrate-recover', "
-                       "  'id': 'recover-cmd', "
-                       "  'arguments': { 'uri': %s } }",
-                       uri);
-    qobject_unref(rsp);
-}
-
-static void migrate_set_capability(QTestState *who, const char *capability,
-                                   bool value)
-{
-    QDict *rsp;
-
-    rsp = qtest_qmp(who,
-                    "{ 'execute': 'migrate-set-capabilities',"
-                    "'arguments': { "
-                    "'capabilities': [ { "
-                    "'capability': %s, 'state': %i } ] } }",
-                    capability, value);
-    g_assert(qdict_haskey(rsp, "return"));
-    qobject_unref(rsp);
-}
-
-static void migrate_postcopy_start(QTestState *from, QTestState *to)
-{
-    QDict *rsp;
-
-    rsp = wait_command(from, "{ 'execute': 'migrate-start-postcopy' }");
-    qobject_unref(rsp);
-
-    if (!got_stop) {
-        qtest_qmp_eventwait(from, "STOP");
-    }
-
-    qtest_qmp_eventwait(to, "RESUME");
-}
-
-typedef struct {
-    bool hide_stderr;
-    bool use_shmem;
-    char *opts_source;
-    char *opts_target;
-} MigrateStart;
-
-static MigrateStart *migrate_start_new(void)
-{
-    MigrateStart *args = g_new0(MigrateStart, 1);
-
-    args->opts_source = g_strdup("");
-    args->opts_target = g_strdup("");
-    return args;
-}
-
-static void migrate_start_destroy(MigrateStart *args)
-{
-    g_free(args->opts_source);
-    g_free(args->opts_target);
-    g_free(args);
-}
-
-static int test_migrate_start(QTestState **from, QTestState **to,
-                              const char *uri, MigrateStart *args)
-{
-    gchar *arch_source, *arch_target;
-    gchar *cmd_source, *cmd_target;
-    const gchar *ignore_stderr;
-    char *bootpath = NULL;
-    char *shmem_opts;
-    char *shmem_path;
-    const char *arch = qtest_get_arch();
-    const char *machine_opts = NULL;
-    const char *memory_size;
-
-    if (args->use_shmem) {
-        if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) {
-            g_test_skip("/dev/shm is not supported");
-            return -1;
-        }
-    }
-
-    got_stop = false;
-    bootpath = g_strdup_printf("%s/bootsect", tmpfs);
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        /* the assembled x86 boot sector should be exactly one sector large */
-        assert(sizeof(x86_bootsect) == 512);
-        init_bootfile(bootpath, x86_bootsect, sizeof(x86_bootsect));
-        memory_size = "150M";
-        arch_source = g_strdup_printf("-drive file=%s,format=raw", bootpath);
-        arch_target = g_strdup(arch_source);
-        start_address = X86_TEST_MEM_START;
-        end_address = X86_TEST_MEM_END;
-    } else if (g_str_equal(arch, "s390x")) {
-        init_bootfile(bootpath, s390x_elf, sizeof(s390x_elf));
-        memory_size = "128M";
-        arch_source = g_strdup_printf("-bios %s", bootpath);
-        arch_target = g_strdup(arch_source);
-        start_address = S390_TEST_MEM_START;
-        end_address = S390_TEST_MEM_END;
-    } else if (strcmp(arch, "ppc64") == 0) {
-        machine_opts = "vsmt=8";
-        memory_size = "256M";
-        arch_source = g_strdup_printf("-nodefaults "
-                                      "-prom-env 'use-nvramrc?=true' -prom-env "
-                                      "'nvramrc=hex .\" _\" begin %x %x "
-                                      "do i c@ 1 + i c! 1000 +loop .\" B\" 0 "
-                                      "until'", end_address, start_address);
-        arch_target = g_strdup("");
-        start_address = PPC_TEST_MEM_START;
-        end_address = PPC_TEST_MEM_END;
-    } else if (strcmp(arch, "aarch64") == 0) {
-        init_bootfile(bootpath, aarch64_kernel, sizeof(aarch64_kernel));
-        machine_opts = "virt,gic-version=max";
-        memory_size = "150M";
-        arch_source = g_strdup_printf("-cpu max "
-                                      "-kernel %s",
-                                      bootpath);
-        arch_target = g_strdup(arch_source);
-        start_address = ARM_TEST_MEM_START;
-        end_address = ARM_TEST_MEM_END;
-
-        g_assert(sizeof(aarch64_kernel) <= ARM_TEST_MAX_KERNEL_SIZE);
-    } else {
-        g_assert_not_reached();
-    }
-
-    g_free(bootpath);
-
-    if (args->hide_stderr) {
-        ignore_stderr = "2>/dev/null";
-    } else {
-        ignore_stderr = "";
-    }
-
-    if (args->use_shmem) {
-        shmem_path = g_strdup_printf("/dev/shm/qemu-%d", getpid());
-        shmem_opts = g_strdup_printf(
-            "-object memory-backend-file,id=mem0,size=%s"
-            ",mem-path=%s,share=on -numa node,memdev=mem0",
-            memory_size, shmem_path);
-    } else {
-        shmem_path = NULL;
-        shmem_opts = g_strdup("");
-    }
-
-    cmd_source = g_strdup_printf("-accel kvm -accel tcg%s%s "
-                                 "-name source,debug-threads=on "
-                                 "-m %s "
-                                 "-serial file:%s/src_serial "
-                                 "%s %s %s %s",
-                                 machine_opts ? " -machine " : "",
-                                 machine_opts ? machine_opts : "",
-                                 memory_size, tmpfs,
-                                 arch_source, shmem_opts, args->opts_source,
-                                 ignore_stderr);
-    g_free(arch_source);
-    *from = qtest_init(cmd_source);
-    g_free(cmd_source);
-
-    cmd_target = g_strdup_printf("-accel kvm -accel tcg%s%s "
-                                 "-name target,debug-threads=on "
-                                 "-m %s "
-                                 "-serial file:%s/dest_serial "
-                                 "-incoming %s "
-                                 "%s %s %s %s",
-                                 machine_opts ? " -machine " : "",
-                                 machine_opts ? machine_opts : "",
-                                 memory_size, tmpfs, uri,
-                                 arch_target, shmem_opts,
-                                 args->opts_target, ignore_stderr);
-    g_free(arch_target);
-    *to = qtest_init(cmd_target);
-    g_free(cmd_target);
-
-    g_free(shmem_opts);
-    /*
-     * Remove shmem file immediately to avoid memory leak in test failed case.
-     * It's valid becase QEMU has already opened this file
-     */
-    if (args->use_shmem) {
-        unlink(shmem_path);
-        g_free(shmem_path);
-    }
-
-    migrate_start_destroy(args);
-    return 0;
-}
-
-static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest)
-{
-    unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
-
-    qtest_quit(from);
-
-    if (test_dest) {
-        qtest_memread(to, start_address, &dest_byte_a, 1);
-
-        /* Destination still running, wait for a byte to change */
-        do {
-            qtest_memread(to, start_address, &dest_byte_b, 1);
-            usleep(1000 * 10);
-        } while (dest_byte_a == dest_byte_b);
-
-        qtest_qmp_discard_response(to, "{ 'execute' : 'stop'}");
-
-        /* With it stopped, check nothing changes */
-        qtest_memread(to, start_address, &dest_byte_c, 1);
-        usleep(1000 * 200);
-        qtest_memread(to, start_address, &dest_byte_d, 1);
-        g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
-
-        check_guests_ram(to);
-    }
-
-    qtest_quit(to);
-
-    cleanup("bootsect");
-    cleanup("migsocket");
-    cleanup("src_serial");
-    cleanup("dest_serial");
-}
-
-static void deprecated_set_downtime(QTestState *who, const double value)
-{
-    QDict *rsp;
-
-    rsp = qtest_qmp(who,
-                    "{ 'execute': 'migrate_set_downtime',"
-                    " 'arguments': { 'value': %f } }", value);
-    g_assert(qdict_haskey(rsp, "return"));
-    qobject_unref(rsp);
-    migrate_check_parameter_int(who, "downtime-limit", value * 1000);
-}
-
-static void deprecated_set_speed(QTestState *who, long long value)
-{
-    QDict *rsp;
-
-    rsp = qtest_qmp(who, "{ 'execute': 'migrate_set_speed',"
-                          "'arguments': { 'value': %lld } }", value);
-    g_assert(qdict_haskey(rsp, "return"));
-    qobject_unref(rsp);
-    migrate_check_parameter_int(who, "max-bandwidth", value);
-}
-
-static void deprecated_set_cache_size(QTestState *who, long long value)
-{
-    QDict *rsp;
-
-    rsp = qtest_qmp(who, "{ 'execute': 'migrate-set-cache-size',"
-                         "'arguments': { 'value': %lld } }", value);
-    g_assert(qdict_haskey(rsp, "return"));
-    qobject_unref(rsp);
-    migrate_check_parameter_int(who, "xbzrle-cache-size", value);
-}
-
-static void test_deprecated(void)
-{
-    QTestState *from;
-
-    from = qtest_init("-machine none");
-
-    deprecated_set_downtime(from, 0.12345);
-    deprecated_set_speed(from, 12345);
-    deprecated_set_cache_size(from, 4096);
-
-    qtest_quit(from);
-}
-
-static int migrate_postcopy_prepare(QTestState **from_ptr,
-                                    QTestState **to_ptr,
-                                    MigrateStart *args)
-{
-    char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    QTestState *from, *to;
-
-    if (test_migrate_start(&from, &to, uri, args)) {
-        return -1;
-    }
-
-    migrate_set_capability(from, "postcopy-ram", true);
-    migrate_set_capability(to, "postcopy-ram", true);
-    migrate_set_capability(to, "postcopy-blocktime", true);
-
-    /* We want to pick a speed slow enough that the test completes
-     * quickly, but that it doesn't complete precopy even on a slow
-     * machine, so also set the downtime.
-     */
-    migrate_set_parameter_int(from, "max-bandwidth", 30000000);
-    migrate_set_parameter_int(from, "downtime-limit", 1);
-
-    /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
-
-    migrate_qmp(from, uri, "{}");
-    g_free(uri);
-
-    wait_for_migration_pass(from);
-
-    *from_ptr = from;
-    *to_ptr = to;
-
-    return 0;
-}
-
-static void migrate_postcopy_complete(QTestState *from, QTestState *to)
-{
-    wait_for_migration_complete(from);
-
-    /* Make sure we get at least one "B" on destination */
-    wait_for_serial("dest_serial");
-
-    if (uffd_feature_thread_id) {
-        read_blocktime(to);
-    }
-
-    test_migrate_end(from, to, true);
-}
-
-static void test_postcopy(void)
-{
-    MigrateStart *args = migrate_start_new();
-    QTestState *from, *to;
-
-    if (migrate_postcopy_prepare(&from, &to, args)) {
-        return;
-    }
-    migrate_postcopy_start(from, to);
-    migrate_postcopy_complete(from, to);
-}
-
-static void test_postcopy_recovery(void)
-{
-    MigrateStart *args = migrate_start_new();
-    QTestState *from, *to;
-    char *uri;
-
-    args->hide_stderr = true;
-
-    if (migrate_postcopy_prepare(&from, &to, args)) {
-        return;
-    }
-
-    /* Turn postcopy speed down, 4K/s is slow enough on any machines */
-    migrate_set_parameter_int(from, "max-postcopy-bandwidth", 4096);
-
-    /* Now we start the postcopy */
-    migrate_postcopy_start(from, to);
-
-    /*
-     * Wait until postcopy is really started; we can only run the
-     * migrate-pause command during a postcopy
-     */
-    wait_for_migration_status(from, "postcopy-active", NULL);
-
-    /*
-     * Manually stop the postcopy migration. This emulates a network
-     * failure with the migration socket
-     */
-    migrate_pause(from);
-
-    /*
-     * Wait for destination side to reach postcopy-paused state.  The
-     * migrate-recover command can only succeed if destination machine
-     * is in the paused state
-     */
-    wait_for_migration_status(to, "postcopy-paused",
-                              (const char * []) { "failed", "active",
-                                                  "completed", NULL });
-
-    /*
-     * Create a new socket to emulate a new channel that is different
-     * from the broken migration channel; tell the destination to
-     * listen to the new port
-     */
-    uri = g_strdup_printf("unix:%s/migsocket-recover", tmpfs);
-    migrate_recover(to, uri);
-
-    /*
-     * Try to rebuild the migration channel using the resume flag and
-     * the newly created channel
-     */
-    wait_for_migration_status(from, "postcopy-paused",
-                              (const char * []) { "failed", "active",
-                                                  "completed", NULL });
-    migrate_qmp(from, uri, "{'resume': true}");
-    g_free(uri);
-
-    /* Restore the postcopy bandwidth to unlimited */
-    migrate_set_parameter_int(from, "max-postcopy-bandwidth", 0);
-
-    migrate_postcopy_complete(from, to);
-}
-
-static void test_baddest(void)
-{
-    MigrateStart *args = migrate_start_new();
-    QTestState *from, *to;
-
-    args->hide_stderr = true;
-
-    if (test_migrate_start(&from, &to, "tcp:0:0", args)) {
-        return;
-    }
-    migrate_qmp(from, "tcp:0:0", "{}");
-    wait_for_migration_fail(from, false);
-    test_migrate_end(from, to, false);
-}
-
-static void test_precopy_unix(void)
-{
-    char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    MigrateStart *args = migrate_start_new();
-    QTestState *from, *to;
-
-    if (test_migrate_start(&from, &to, uri, args)) {
-        return;
-    }
-
-    /* We want to pick a speed slow enough that the test completes
-     * quickly, but that it doesn't complete precopy even on a slow
-     * machine, so also set the downtime.
-     */
-    /* 1 ms should make it not converge*/
-    migrate_set_parameter_int(from, "downtime-limit", 1);
-    /* 1GB/s */
-    migrate_set_parameter_int(from, "max-bandwidth", 1000000000);
-
-    /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
-
-    migrate_qmp(from, uri, "{}");
-
-    wait_for_migration_pass(from);
-
-    /* 300 ms should converge */
-    migrate_set_parameter_int(from, "downtime-limit", 300);
-
-    if (!got_stop) {
-        qtest_qmp_eventwait(from, "STOP");
-    }
-
-    qtest_qmp_eventwait(to, "RESUME");
-
-    wait_for_serial("dest_serial");
-    wait_for_migration_complete(from);
-
-    test_migrate_end(from, to, true);
-    g_free(uri);
-}
-
-#if 0
-/* Currently upset on aarch64 TCG */
-static void test_ignore_shared(void)
-{
-    char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    QTestState *from, *to;
-
-    if (test_migrate_start(&from, &to, uri, false, true, NULL, NULL)) {
-        return;
-    }
-
-    migrate_set_capability(from, "x-ignore-shared", true);
-    migrate_set_capability(to, "x-ignore-shared", true);
-
-    /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
-
-    migrate_qmp(from, uri, "{}");
-
-    wait_for_migration_pass(from);
-
-    if (!got_stop) {
-        qtest_qmp_eventwait(from, "STOP");
-    }
-
-    qtest_qmp_eventwait(to, "RESUME");
-
-    wait_for_serial("dest_serial");
-    wait_for_migration_complete(from);
-
-    /* Check whether shared RAM has been really skipped */
-    g_assert_cmpint(read_ram_property_int(from, "transferred"), <, 1024 * 1024);
-
-    test_migrate_end(from, to, true);
-    g_free(uri);
-}
-#endif
-
-static void test_xbzrle(const char *uri)
-{
-    MigrateStart *args = migrate_start_new();
-    QTestState *from, *to;
-
-    if (test_migrate_start(&from, &to, uri, args)) {
-        return;
-    }
-
-    /*
-     * We want to pick a speed slow enough that the test completes
-     * quickly, but that it doesn't complete precopy even on a slow
-     * machine, so also set the downtime.
-     */
-    /* 1 ms should make it not converge*/
-    migrate_set_parameter_int(from, "downtime-limit", 1);
-    /* 1GB/s */
-    migrate_set_parameter_int(from, "max-bandwidth", 1000000000);
-
-    migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432);
-
-    migrate_set_capability(from, "xbzrle", "true");
-    migrate_set_capability(to, "xbzrle", "true");
-    /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
-
-    migrate_qmp(from, uri, "{}");
-
-    wait_for_migration_pass(from);
-
-    /* 300ms should converge */
-    migrate_set_parameter_int(from, "downtime-limit", 300);
-
-    if (!got_stop) {
-        qtest_qmp_eventwait(from, "STOP");
-    }
-    qtest_qmp_eventwait(to, "RESUME");
-
-    wait_for_serial("dest_serial");
-    wait_for_migration_complete(from);
-
-    test_migrate_end(from, to, true);
-}
-
-static void test_xbzrle_unix(void)
-{
-    char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-
-    test_xbzrle(uri);
-    g_free(uri);
-}
-
-static void test_precopy_tcp(void)
-{
-    MigrateStart *args = migrate_start_new();
-    char *uri;
-    QTestState *from, *to;
-
-    if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", args)) {
-        return;
-    }
-
-    /*
-     * We want to pick a speed slow enough that the test completes
-     * quickly, but that it doesn't complete precopy even on a slow
-     * machine, so also set the downtime.
-     */
-    /* 1 ms should make it not converge*/
-    migrate_set_parameter_int(from, "downtime-limit", 1);
-    /* 1GB/s */
-    migrate_set_parameter_int(from, "max-bandwidth", 1000000000);
-
-    /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
-
-    uri = migrate_get_socket_address(to, "socket-address");
-
-    migrate_qmp(from, uri, "{}");
-
-    wait_for_migration_pass(from);
-
-    /* 300ms should converge */
-    migrate_set_parameter_int(from, "downtime-limit", 300);
-
-    if (!got_stop) {
-        qtest_qmp_eventwait(from, "STOP");
-    }
-    qtest_qmp_eventwait(to, "RESUME");
-
-    wait_for_serial("dest_serial");
-    wait_for_migration_complete(from);
-
-    test_migrate_end(from, to, true);
-    g_free(uri);
-}
-
-static void test_migrate_fd_proto(void)
-{
-    MigrateStart *args = migrate_start_new();
-    QTestState *from, *to;
-    int ret;
-    int pair[2];
-    QDict *rsp;
-    const char *error_desc;
-
-    if (test_migrate_start(&from, &to, "defer", args)) {
-        return;
-    }
-
-    /*
-     * We want to pick a speed slow enough that the test completes
-     * quickly, but that it doesn't complete precopy even on a slow
-     * machine, so also set the downtime.
-     */
-    /* 1 ms should make it not converge */
-    migrate_set_parameter_int(from, "downtime-limit", 1);
-    /* 1GB/s */
-    migrate_set_parameter_int(from, "max-bandwidth", 1000000000);
-
-    /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
-
-    /* Create two connected sockets for migration */
-    ret = socketpair(PF_LOCAL, SOCK_STREAM, 0, pair);
-    g_assert_cmpint(ret, ==, 0);
-
-    /* Send the 1st socket to the target */
-    rsp = wait_command_fd(to, pair[0],
-                          "{ 'execute': 'getfd',"
-                          "  'arguments': { 'fdname': 'fd-mig' }}");
-    qobject_unref(rsp);
-    close(pair[0]);
-
-    /* Start incoming migration from the 1st socket */
-    rsp = wait_command(to, "{ 'execute': 'migrate-incoming',"
-                           "  'arguments': { 'uri': 'fd:fd-mig' }}");
-    qobject_unref(rsp);
-
-    /* Send the 2nd socket to the target */
-    rsp = wait_command_fd(from, pair[1],
-                          "{ 'execute': 'getfd',"
-                          "  'arguments': { 'fdname': 'fd-mig' }}");
-    qobject_unref(rsp);
-    close(pair[1]);
-
-    /* Start migration to the 2nd socket*/
-    migrate_qmp(from, "fd:fd-mig", "{}");
-
-    wait_for_migration_pass(from);
-
-    /* 300ms should converge */
-    migrate_set_parameter_int(from, "downtime-limit", 300);
-
-    if (!got_stop) {
-        qtest_qmp_eventwait(from, "STOP");
-    }
-    qtest_qmp_eventwait(to, "RESUME");
-
-    /* Test closing fds */
-    /* We assume, that QEMU removes named fd from its list,
-     * so this should fail */
-    rsp = qtest_qmp(from, "{ 'execute': 'closefd',"
-                          "  'arguments': { 'fdname': 'fd-mig' }}");
-    g_assert_true(qdict_haskey(rsp, "error"));
-    error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc");
-    g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found");
-    qobject_unref(rsp);
-
-    rsp = qtest_qmp(to, "{ 'execute': 'closefd',"
-                        "  'arguments': { 'fdname': 'fd-mig' }}");
-    g_assert_true(qdict_haskey(rsp, "error"));
-    error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc");
-    g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found");
-    qobject_unref(rsp);
-
-    /* Complete migration */
-    wait_for_serial("dest_serial");
-    wait_for_migration_complete(from);
-    test_migrate_end(from, to, true);
-}
-
-static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
-{
-    char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    QTestState *from, *to;
-
-    if (test_migrate_start(&from, &to, uri, args)) {
-        return;
-    }
-
-    /*
-     * UUID validation is at the begin of migration. So, the main process of
-     * migration is not interesting for us here. Thus, set huge downtime for
-     * very fast migration.
-     */
-    migrate_set_parameter_int(from, "downtime-limit", 1000000);
-    migrate_set_capability(from, "validate-uuid", true);
-
-    /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
-
-    migrate_qmp(from, uri, "{}");
-
-    if (should_fail) {
-        qtest_set_expected_status(to, 1);
-        wait_for_migration_fail(from, true);
-    } else {
-        wait_for_migration_complete(from);
-    }
-
-    test_migrate_end(from, to, false);
-    g_free(uri);
-}
-
-static void test_validate_uuid(void)
-{
-    MigrateStart *args = migrate_start_new();
-
-    args->opts_source = g_strdup("-uuid 11111111-1111-1111-1111-111111111111");
-    args->opts_target = g_strdup("-uuid 11111111-1111-1111-1111-111111111111");
-    do_test_validate_uuid(args, false);
-}
-
-static void test_validate_uuid_error(void)
-{
-    MigrateStart *args = migrate_start_new();
-
-    args->opts_source = g_strdup("-uuid 11111111-1111-1111-1111-111111111111");
-    args->opts_target = g_strdup("-uuid 22222222-2222-2222-2222-222222222222");
-    args->hide_stderr = true;
-    do_test_validate_uuid(args, true);
-}
-
-static void test_validate_uuid_src_not_set(void)
-{
-    MigrateStart *args = migrate_start_new();
-
-    args->opts_target = g_strdup("-uuid 22222222-2222-2222-2222-222222222222");
-    args->hide_stderr = true;
-    do_test_validate_uuid(args, false);
-}
-
-static void test_validate_uuid_dst_not_set(void)
-{
-    MigrateStart *args = migrate_start_new();
-
-    args->opts_source = g_strdup("-uuid 11111111-1111-1111-1111-111111111111");
-    args->hide_stderr = true;
-    do_test_validate_uuid(args, false);
-}
-
-static void test_migrate_auto_converge(void)
-{
-    char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    MigrateStart *args = migrate_start_new();
-    QTestState *from, *to;
-    int64_t remaining, percentage;
-
-    /*
-     * We want the test to be stable and as fast as possible.
-     * E.g., with 1Gb/s bandwith migration may pass without throttling,
-     * so we need to decrease a bandwidth.
-     */
-    const int64_t init_pct = 5, inc_pct = 50, max_pct = 95;
-    const int64_t max_bandwidth = 400000000; /* ~400Mb/s */
-    const int64_t downtime_limit = 250; /* 250ms */
-    /*
-     * We migrate through unix-socket (> 500Mb/s).
-     * Thus, expected migration speed ~= bandwidth limit (< 500Mb/s).
-     * So, we can predict expected_threshold
-     */
-    const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000;
-
-    if (test_migrate_start(&from, &to, uri, args)) {
-        return;
-    }
-
-    migrate_set_capability(from, "auto-converge", true);
-    migrate_set_parameter_int(from, "cpu-throttle-initial", init_pct);
-    migrate_set_parameter_int(from, "cpu-throttle-increment", inc_pct);
-    migrate_set_parameter_int(from, "max-cpu-throttle", max_pct);
-
-    /*
-     * Set the initial parameters so that the migration could not converge
-     * without throttling.
-     */
-    migrate_set_parameter_int(from, "downtime-limit", 1);
-    migrate_set_parameter_int(from, "max-bandwidth", 100000000); /* ~100Mb/s */
-
-    /* To check remaining size after precopy */
-    migrate_set_capability(from, "pause-before-switchover", true);
-
-    /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
-
-    migrate_qmp(from, uri, "{}");
-
-    /* Wait for throttling begins */
-    percentage = 0;
-    while (percentage == 0) {
-        percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
-        usleep(100);
-        g_assert_false(got_stop);
-    }
-    /* The first percentage of throttling should be equal to init_pct */
-    g_assert_cmpint(percentage, ==, init_pct);
-    /* Now, when we tested that throttling works, let it converge */
-    migrate_set_parameter_int(from, "downtime-limit", downtime_limit);
-    migrate_set_parameter_int(from, "max-bandwidth", max_bandwidth);
-
-    /*
-     * Wait for pre-switchover status to check last throttle percentage
-     * and remaining. These values will be zeroed later
-     */
-    wait_for_migration_status(from, "pre-switchover", NULL);
-
-    /* The final percentage of throttling shouldn't be greater than max_pct */
-    percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
-    g_assert_cmpint(percentage, <=, max_pct);
-
-    remaining = read_ram_property_int(from, "remaining");
-    g_assert_cmpint(remaining, <, expected_threshold);
-
-    migrate_continue(from, "pre-switchover");
-
-    qtest_qmp_eventwait(to, "RESUME");
-
-    wait_for_serial("dest_serial");
-    wait_for_migration_complete(from);
-
-    g_free(uri);
-
-    test_migrate_end(from, to, true);
-}
-
-int main(int argc, char **argv)
-{
-    char template[] = "/tmp/migration-test-XXXXXX";
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-
-    if (!ufd_version_check()) {
-        return g_test_run();
-    }
-
-    /*
-     * On ppc64, the test only works with kvm-hv, but not with kvm-pr and TCG
-     * is touchy due to race conditions on dirty bits (especially on PPC for
-     * some reason)
-     */
-    if (g_str_equal(qtest_get_arch(), "ppc64") &&
-        (access("/sys/module/kvm_hv", F_OK) ||
-         access("/dev/kvm", R_OK | W_OK))) {
-        g_test_message("Skipping test: kvm_hv not available");
-        return g_test_run();
-    }
-
-    /*
-     * Similar to ppc64, s390x seems to be touchy with TCG, so disable it
-     * there until the problems are resolved
-     */
-    if (g_str_equal(qtest_get_arch(), "s390x")) {
-#if defined(HOST_S390X)
-        if (access("/dev/kvm", R_OK | W_OK)) {
-            g_test_message("Skipping test: kvm not available");
-            return g_test_run();
-        }
-#else
-        g_test_message("Skipping test: Need s390x host to work properly");
-        return g_test_run();
-#endif
-    }
-
-    tmpfs = mkdtemp(template);
-    if (!tmpfs) {
-        g_test_message("mkdtemp on path (%s): %s", template, strerror(errno));
-    }
-    g_assert(tmpfs);
-
-    module_call_init(MODULE_INIT_QOM);
-
-    qtest_add_func("/migration/postcopy/unix", test_postcopy);
-    qtest_add_func("/migration/postcopy/recovery", test_postcopy_recovery);
-    qtest_add_func("/migration/deprecated", test_deprecated);
-    qtest_add_func("/migration/bad_dest", test_baddest);
-    qtest_add_func("/migration/precopy/unix", test_precopy_unix);
-    qtest_add_func("/migration/precopy/tcp", test_precopy_tcp);
-    /* qtest_add_func("/migration/ignore_shared", test_ignore_shared); */
-    qtest_add_func("/migration/xbzrle/unix", test_xbzrle_unix);
-    qtest_add_func("/migration/fd_proto", test_migrate_fd_proto);
-    qtest_add_func("/migration/validate_uuid", test_validate_uuid);
-    qtest_add_func("/migration/validate_uuid_error", test_validate_uuid_error);
-    qtest_add_func("/migration/validate_uuid_src_not_set",
-                   test_validate_uuid_src_not_set);
-    qtest_add_func("/migration/validate_uuid_dst_not_set",
-                   test_validate_uuid_dst_not_set);
-
-    qtest_add_func("/migration/auto_converge", test_migrate_auto_converge);
-
-    ret = g_test_run();
-
-    g_assert_cmpint(ret, ==, 0);
-
-    ret = rmdir(tmpfs);
-    if (ret != 0) {
-        g_test_message("unable to rmdir: path (%s): %s",
-                       tmpfs, strerror(errno));
-    }
-
-    return ret;
-}
diff --git a/tests/modules-test.c b/tests/modules-test.c
deleted file mode 100644 (file)
index 8821768..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-#include "qemu/osdep.h"
-#include "libqtest.h"
-
-const char common_args[] = "-nodefaults -machine none";
-
-static void test_modules_load(const void *data)
-{
-    QTestState *qts;
-    const char **args = (const char **)data;
-
-    qts = qtest_init(common_args);
-    qtest_module_load(qts, args[0], args[1]);
-    qtest_quit(qts);
-}
-
-int main(int argc, char *argv[])
-{
-    const char *modules[] = {
-#ifdef CONFIG_CURL
-        "block-", "curl",
-#endif
-#ifdef CONFIG_GLUSTERFS
-        "block-", "gluster",
-#endif
-#ifdef CONFIG_LIBISCSI
-        "block-", "iscsi",
-#endif
-#ifdef CONFIG_LIBNFS
-        "block-", "nfs",
-#endif
-#ifdef CONFIG_LIBSSH
-        "block-", "ssh",
-#endif
-#ifdef CONFIG_RBD
-        "block-", "rbd",
-#endif
-#ifdef CONFIG_AUDIO_ALSA
-        "audio-", "alsa",
-#endif
-#ifdef CONFIG_AUDIO_OSS
-        "audio-", "oss",
-#endif
-#ifdef CONFIG_AUDIO_PA
-        "audio-", "pa",
-#endif
-#ifdef CONFIG_AUDIO_SDL
-        "audio-", "sdl",
-#endif
-#ifdef CONFIG_CURSES
-        "ui-", "curses",
-#endif
-#if defined(CONFIG_GTK) && defined(CONFIG_VTE)
-        "ui-", "gtk",
-#endif
-#ifdef CONFIG_SDL
-        "ui-", "sdl",
-#endif
-#if defined(CONFIG_SPICE) && defined(CONFIG_GIO)
-        "ui-", "spice-app",
-#endif
-    };
-    int i;
-
-    g_test_init(&argc, &argv, NULL);
-
-    for (i = 0; i < G_N_ELEMENTS(modules); i += 2) {
-        char *testname = g_strdup_printf("/module/load/%s%s",
-                                         modules[i], modules[i + 1]);
-        qtest_add_data_func(testname, modules + i, test_modules_load);
-        g_free(testname);
-    }
-
-    return g_test_run();
-}
diff --git a/tests/ne2000-test.c b/tests/ne2000-test.c
deleted file mode 100644 (file)
index 3fc0e55..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * QTest testcase for ne2000 NIC
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qemu/module.h"
-#include "libqos/qgraph.h"
-#include "libqos/pci.h"
-
-typedef struct QNe2k_pci QNe2k_pci;
-
-struct QNe2k_pci {
-    QOSGraphObject obj;
-    QPCIDevice dev;
-};
-
-static void *ne2k_pci_get_driver(void *obj, const char *interface)
-{
-    QNe2k_pci *ne2k_pci = obj;
-
-    if (!g_strcmp0(interface, "pci-device")) {
-        return &ne2k_pci->dev;
-    }
-
-    fprintf(stderr, "%s not present in ne2k_pci\n", interface);
-    g_assert_not_reached();
-}
-
-static void *ne2k_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
-{
-    QNe2k_pci *ne2k_pci = g_new0(QNe2k_pci, 1);
-    QPCIBus *bus = pci_bus;
-
-    qpci_device_init(&ne2k_pci->dev, bus, addr);
-    ne2k_pci->obj.get_driver = ne2k_pci_get_driver;
-
-    return &ne2k_pci->obj;
-}
-
-static void ne2000_register_nodes(void)
-{
-    QOSGraphEdgeOptions opts = {
-        .extra_device_opts = "addr=04.0",
-    };
-    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
-
-    qos_node_create_driver("ne2k_pci", ne2k_pci_create);
-    qos_node_consumes("ne2k_pci", "pci-bus", &opts);
-    qos_node_produces("ne2k_pci", "pci-device");
-}
-
-libqos_init(ne2000_register_nodes);
diff --git a/tests/numa-test.c b/tests/numa-test.c
deleted file mode 100644 (file)
index 17dd807..0000000
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * NUMA configuration test cases
- *
- * Copyright (c) 2017 Red Hat Inc.
- * Authors:
- *  Igor Mammedov <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
-
-static char *make_cli(const char *generic_cli, const char *test_cli)
-{
-    return g_strdup_printf("%s %s", generic_cli ? generic_cli : "", test_cli);
-}
-
-static void test_mon_explicit(const void *data)
-{
-    char *s;
-    char *cli;
-    QTestState *qts;
-
-    cli = make_cli(data, "-smp 8 "
-                   "-numa node,nodeid=0,cpus=0-3 "
-                   "-numa node,nodeid=1,cpus=4-7 ");
-    qts = qtest_init(cli);
-
-    s = qtest_hmp(qts, "info numa");
-    g_assert(strstr(s, "node 0 cpus: 0 1 2 3"));
-    g_assert(strstr(s, "node 1 cpus: 4 5 6 7"));
-    g_free(s);
-
-    qtest_quit(qts);
-    g_free(cli);
-}
-
-static void test_mon_default(const void *data)
-{
-    char *s;
-    char *cli;
-    QTestState *qts;
-
-    cli = make_cli(data, "-smp 8 -numa node -numa node");
-    qts = qtest_init(cli);
-
-    s = qtest_hmp(qts, "info numa");
-    g_assert(strstr(s, "node 0 cpus: 0 2 4 6"));
-    g_assert(strstr(s, "node 1 cpus: 1 3 5 7"));
-    g_free(s);
-
-    qtest_quit(qts);
-    g_free(cli);
-}
-
-static void test_mon_partial(const void *data)
-{
-    char *s;
-    char *cli;
-    QTestState *qts;
-
-    cli = make_cli(data, "-smp 8 "
-                   "-numa node,nodeid=0,cpus=0-1 "
-                   "-numa node,nodeid=1,cpus=4-5 ");
-    qts = qtest_init(cli);
-
-    s = qtest_hmp(qts, "info numa");
-    g_assert(strstr(s, "node 0 cpus: 0 1 2 3 6 7"));
-    g_assert(strstr(s, "node 1 cpus: 4 5"));
-    g_free(s);
-
-    qtest_quit(qts);
-    g_free(cli);
-}
-
-static QList *get_cpus(QTestState *qts, QDict **resp)
-{
-    *resp = qtest_qmp(qts, "{ 'execute': 'query-cpus' }");
-    g_assert(*resp);
-    g_assert(qdict_haskey(*resp, "return"));
-    return qdict_get_qlist(*resp, "return");
-}
-
-static void test_query_cpus(const void *data)
-{
-    char *cli;
-    QDict *resp;
-    QList *cpus;
-    QObject *e;
-    QTestState *qts;
-
-    cli = make_cli(data, "-smp 8 -numa node,cpus=0-3 -numa node,cpus=4-7");
-    qts = qtest_init(cli);
-    cpus = get_cpus(qts, &resp);
-    g_assert(cpus);
-
-    while ((e = qlist_pop(cpus))) {
-        QDict *cpu, *props;
-        int64_t cpu_idx, node;
-
-        cpu = qobject_to(QDict, e);
-        g_assert(qdict_haskey(cpu, "CPU"));
-        g_assert(qdict_haskey(cpu, "props"));
-
-        cpu_idx = qdict_get_int(cpu, "CPU");
-        props = qdict_get_qdict(cpu, "props");
-        g_assert(qdict_haskey(props, "node-id"));
-        node = qdict_get_int(props, "node-id");
-        if (cpu_idx >= 0 && cpu_idx < 4) {
-            g_assert_cmpint(node, ==, 0);
-        } else {
-            g_assert_cmpint(node, ==, 1);
-        }
-        qobject_unref(e);
-    }
-
-    qobject_unref(resp);
-    qtest_quit(qts);
-    g_free(cli);
-}
-
-static void pc_numa_cpu(const void *data)
-{
-    char *cli;
-    QDict *resp;
-    QList *cpus;
-    QObject *e;
-    QTestState *qts;
-
-    cli = make_cli(data, "-cpu pentium -smp 8,sockets=2,cores=2,threads=2 "
-        "-numa node,nodeid=0 -numa node,nodeid=1 "
-        "-numa cpu,node-id=1,socket-id=0 "
-        "-numa cpu,node-id=0,socket-id=1,core-id=0 "
-        "-numa cpu,node-id=0,socket-id=1,core-id=1,thread-id=0 "
-        "-numa cpu,node-id=1,socket-id=1,core-id=1,thread-id=1");
-    qts = qtest_init(cli);
-    cpus = get_cpus(qts, &resp);
-    g_assert(cpus);
-
-    while ((e = qlist_pop(cpus))) {
-        QDict *cpu, *props;
-        int64_t socket, core, thread, node;
-
-        cpu = qobject_to(QDict, e);
-        g_assert(qdict_haskey(cpu, "props"));
-        props = qdict_get_qdict(cpu, "props");
-
-        g_assert(qdict_haskey(props, "node-id"));
-        node = qdict_get_int(props, "node-id");
-        g_assert(qdict_haskey(props, "socket-id"));
-        socket = qdict_get_int(props, "socket-id");
-        g_assert(qdict_haskey(props, "core-id"));
-        core = qdict_get_int(props, "core-id");
-        g_assert(qdict_haskey(props, "thread-id"));
-        thread = qdict_get_int(props, "thread-id");
-
-        if (socket == 0) {
-            g_assert_cmpint(node, ==, 1);
-        } else if (socket == 1 && core == 0) {
-            g_assert_cmpint(node, ==, 0);
-        } else if (socket == 1 && core == 1 && thread == 0) {
-            g_assert_cmpint(node, ==, 0);
-        } else if (socket == 1 && core == 1 && thread == 1) {
-            g_assert_cmpint(node, ==, 1);
-        } else {
-            g_assert(false);
-        }
-        qobject_unref(e);
-    }
-
-    qobject_unref(resp);
-    qtest_quit(qts);
-    g_free(cli);
-}
-
-static void spapr_numa_cpu(const void *data)
-{
-    char *cli;
-    QDict *resp;
-    QList *cpus;
-    QObject *e;
-    QTestState *qts;
-
-    cli = make_cli(data, "-smp 4,cores=4 "
-        "-numa node,nodeid=0 -numa node,nodeid=1 "
-        "-numa cpu,node-id=0,core-id=0 "
-        "-numa cpu,node-id=0,core-id=1 "
-        "-numa cpu,node-id=0,core-id=2 "
-        "-numa cpu,node-id=1,core-id=3");
-    qts = qtest_init(cli);
-    cpus = get_cpus(qts, &resp);
-    g_assert(cpus);
-
-    while ((e = qlist_pop(cpus))) {
-        QDict *cpu, *props;
-        int64_t core, node;
-
-        cpu = qobject_to(QDict, e);
-        g_assert(qdict_haskey(cpu, "props"));
-        props = qdict_get_qdict(cpu, "props");
-
-        g_assert(qdict_haskey(props, "node-id"));
-        node = qdict_get_int(props, "node-id");
-        g_assert(qdict_haskey(props, "core-id"));
-        core = qdict_get_int(props, "core-id");
-
-        if (core >= 0 && core < 3) {
-            g_assert_cmpint(node, ==, 0);
-        } else if (core == 3) {
-            g_assert_cmpint(node, ==, 1);
-        } else {
-            g_assert(false);
-        }
-        qobject_unref(e);
-    }
-
-    qobject_unref(resp);
-    qtest_quit(qts);
-    g_free(cli);
-}
-
-static void aarch64_numa_cpu(const void *data)
-{
-    char *cli;
-    QDict *resp;
-    QList *cpus;
-    QObject *e;
-    QTestState *qts;
-
-    cli = make_cli(data, "-smp 2 "
-        "-numa node,nodeid=0 -numa node,nodeid=1 "
-        "-numa cpu,node-id=1,thread-id=0 "
-        "-numa cpu,node-id=0,thread-id=1");
-    qts = qtest_init(cli);
-    cpus = get_cpus(qts, &resp);
-    g_assert(cpus);
-
-    while ((e = qlist_pop(cpus))) {
-        QDict *cpu, *props;
-        int64_t thread, node;
-
-        cpu = qobject_to(QDict, e);
-        g_assert(qdict_haskey(cpu, "props"));
-        props = qdict_get_qdict(cpu, "props");
-
-        g_assert(qdict_haskey(props, "node-id"));
-        node = qdict_get_int(props, "node-id");
-        g_assert(qdict_haskey(props, "thread-id"));
-        thread = qdict_get_int(props, "thread-id");
-
-        if (thread == 0) {
-            g_assert_cmpint(node, ==, 1);
-        } else if (thread == 1) {
-            g_assert_cmpint(node, ==, 0);
-        } else {
-            g_assert(false);
-        }
-        qobject_unref(e);
-    }
-
-    qobject_unref(resp);
-    qtest_quit(qts);
-    g_free(cli);
-}
-
-static void pc_dynamic_cpu_cfg(const void *data)
-{
-    QObject *e;
-    QDict *resp;
-    QList *cpus;
-    QTestState *qs;
-
-    qs = qtest_initf("%s -nodefaults --preconfig -smp 2",
-                     data ? (char *)data : "");
-
-    /* create 2 numa nodes */
-    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'node', 'nodeid': 0 } }")));
-    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'node', 'nodeid': 1 } }")));
-
-    /* map 2 cpus in non default reverse order
-     * i.e socket1->node0, socket0->node1
-     */
-    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'cpu', 'node-id': 0, 'socket-id': 1 } }")));
-    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'cpu', 'node-id': 1, 'socket-id': 0 } }")));
-
-    /* let machine initialization to complete and run */
-    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
-    qtest_qmp_eventwait(qs, "RESUME");
-
-    /* check that CPUs are mapped as expected */
-    resp = qtest_qmp(qs, "{ 'execute': 'query-hotpluggable-cpus'}");
-    g_assert(qdict_haskey(resp, "return"));
-    cpus = qdict_get_qlist(resp, "return");
-    g_assert(cpus);
-    while ((e = qlist_pop(cpus))) {
-        const QDict *cpu, *props;
-        int64_t socket, node;
-
-        cpu = qobject_to(QDict, e);
-        g_assert(qdict_haskey(cpu, "props"));
-        props = qdict_get_qdict(cpu, "props");
-
-        g_assert(qdict_haskey(props, "node-id"));
-        node = qdict_get_int(props, "node-id");
-        g_assert(qdict_haskey(props, "socket-id"));
-        socket = qdict_get_int(props, "socket-id");
-
-        if (socket == 0) {
-            g_assert_cmpint(node, ==, 1);
-        } else if (socket == 1) {
-            g_assert_cmpint(node, ==, 0);
-        } else {
-            g_assert(false);
-        }
-        qobject_unref(e);
-    }
-    qobject_unref(resp);
-
-    qtest_quit(qs);
-}
-
-static void pc_hmat_build_cfg(const void *data)
-{
-    QTestState *qs = qtest_initf("%s -nodefaults --preconfig -machine hmat=on "
-                     "-smp 2,sockets=2 "
-                     "-m 128M,slots=2,maxmem=1G "
-                     "-object memory-backend-ram,size=64M,id=m0 "
-                     "-object memory-backend-ram,size=64M,id=m1 "
-                     "-numa node,nodeid=0,memdev=m0 "
-                     "-numa node,nodeid=1,memdev=m1,initiator=0 "
-                     "-numa cpu,node-id=0,socket-id=0 "
-                     "-numa cpu,node-id=0,socket-id=1",
-                     data ? (char *)data : "");
-
-    /* Fail: Initiator should be less than the number of nodes */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 2, 'target': 0,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-latency\" } }")));
-
-    /* Fail: Target should be less than the number of nodes */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 2,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-latency\" } }")));
-
-    /* Fail: Initiator should contain cpu */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 1, 'target': 0,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-latency\" } }")));
-
-    /* Fail: Data-type mismatch */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
-        " 'hierarchy': \"memory\", 'data-type': \"write-latency\","
-        " 'bandwidth': 524288000 } }")));
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
-        " 'hierarchy': \"memory\", 'data-type': \"read-bandwidth\","
-        " 'latency': 5 } }")));
-
-    /* Fail: Bandwidth should be 1MB (1048576) aligned */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-bandwidth\","
-        " 'bandwidth': 1048575 } }")));
-
-    /* Configuring HMAT bandwidth and latency details */
-    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-latency\","
-        " 'latency': 1 } }")));    /* 1 ns */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-latency\","
-        " 'latency': 5 } }")));    /* Fail: Duplicate configuration */
-    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-bandwidth\","
-        " 'bandwidth': 68717379584 } }")));    /* 65534 MB/s */
-    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 1,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-latency\","
-        " 'latency': 65534 } }")));    /* 65534 ns */
-    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 1,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-bandwidth\","
-        " 'bandwidth': 34358689792 } }")));    /* 32767 MB/s */
-
-    /* Fail: node_id should be less than the number of nodes */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-cache', 'node-id': 2, 'size': 10240,"
-        " 'level': 1, 'associativity': \"direct\", 'policy': \"write-back\","
-        " 'line': 8 } }")));
-
-    /* Fail: level should be less than HMAT_LB_LEVELS (4) */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
-        " 'level': 4, 'associativity': \"direct\", 'policy': \"write-back\","
-        " 'line': 8 } }")));
-
-    /* Fail: associativity option should be 'none', if level is 0 */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
-        " 'level': 0, 'associativity': \"direct\", 'policy': \"none\","
-        " 'line': 0 } }")));
-    /* Fail: policy option should be 'none', if level is 0 */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
-        " 'level': 0, 'associativity': \"none\", 'policy': \"write-back\","
-        " 'line': 0 } }")));
-    /* Fail: line option should be 0, if level is 0 */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
-        " 'level': 0, 'associativity': \"none\", 'policy': \"none\","
-        " 'line': 8 } }")));
-
-    /* Configuring HMAT memory side cache attributes */
-    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
-        " 'level': 1, 'associativity': \"direct\", 'policy': \"write-back\","
-        " 'line': 8 } }")));
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
-        " 'level': 1, 'associativity': \"direct\", 'policy': \"write-back\","
-        " 'line': 8 } }")));    /* Fail: Duplicate configuration */
-    /* Fail: The size of level 2 size should be small than level 1 */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
-        " 'level': 2, 'associativity': \"direct\", 'policy': \"write-back\","
-        " 'line': 8 } }")));
-    /* Fail: The size of level 0 size should be larger than level 1 */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
-        " 'level': 0, 'associativity': \"direct\", 'policy': \"write-back\","
-        " 'line': 8 } }")));
-    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-cache', 'node-id': 1, 'size': 10240,"
-        " 'level': 1, 'associativity': \"direct\", 'policy': \"write-back\","
-        " 'line': 8 } }")));
-
-    /* let machine initialization to complete and run */
-    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs,
-        "{ 'execute': 'x-exit-preconfig' }")));
-    qtest_qmp_eventwait(qs, "RESUME");
-
-    qtest_quit(qs);
-}
-
-static void pc_hmat_off_cfg(const void *data)
-{
-    QTestState *qs = qtest_initf("%s -nodefaults --preconfig "
-                     "-smp 2,sockets=2 "
-                     "-m 128M,slots=2,maxmem=1G "
-                     "-object memory-backend-ram,size=64M,id=m0 "
-                     "-object memory-backend-ram,size=64M,id=m1 "
-                     "-numa node,nodeid=0,memdev=m0",
-                     data ? (char *)data : "");
-
-    /*
-     * Fail: Enable HMAT with -machine hmat=on
-     * before using any of hmat specific options
-     */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'node', 'nodeid': 1, 'memdev': \"m1\","
-        " 'initiator': 0 } }")));
-    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'node', 'nodeid': 1, 'memdev': \"m1\" } }")));
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-latency\","
-        " 'latency': 1 } }")));
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
-        " 'level': 1, 'associativity': \"direct\", 'policy': \"write-back\","
-        " 'line': 8 } }")));
-
-    /* let machine initialization to complete and run */
-    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs,
-        "{ 'execute': 'x-exit-preconfig' }")));
-    qtest_qmp_eventwait(qs, "RESUME");
-
-    qtest_quit(qs);
-}
-
-static void pc_hmat_erange_cfg(const void *data)
-{
-    QTestState *qs = qtest_initf("%s -nodefaults --preconfig -machine hmat=on "
-                     "-smp 2,sockets=2 "
-                     "-m 128M,slots=2,maxmem=1G "
-                     "-object memory-backend-ram,size=64M,id=m0 "
-                     "-object memory-backend-ram,size=64M,id=m1 "
-                     "-numa node,nodeid=0,memdev=m0 "
-                     "-numa node,nodeid=1,memdev=m1,initiator=0 "
-                     "-numa cpu,node-id=0,socket-id=0 "
-                     "-numa cpu,node-id=0,socket-id=1",
-                     data ? (char *)data : "");
-
-    /* Can't store the compressed latency */
-    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-latency\","
-        " 'latency': 1 } }")));    /* 1 ns */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 1,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-latency\","
-        " 'latency': 65535 } }")));    /* 65535 ns */
-
-    /* Test the 0 input (bandwidth not provided) */
-    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-bandwidth\","
-        " 'bandwidth': 0 } }")));    /* 0 MB/s */
-    /* Fail: bandwidth should be provided before memory side cache attributes */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
-        " 'level': 1, 'associativity': \"direct\", 'policy': \"write-back\","
-        " 'line': 8 } }")));
-
-    /* Can't store the compressed bandwidth */
-    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
-        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 1,"
-        " 'hierarchy': \"memory\", 'data-type': \"access-bandwidth\","
-        " 'bandwidth': 68718428160 } }")));    /* 65535 MB/s */
-
-    /* let machine initialization to complete and run */
-    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs,
-        "{ 'execute': 'x-exit-preconfig' }")));
-    qtest_qmp_eventwait(qs, "RESUME");
-
-    qtest_quit(qs);
-}
-
-int main(int argc, char **argv)
-{
-    const char *args = NULL;
-    const char *arch = qtest_get_arch();
-
-    if (strcmp(arch, "aarch64") == 0) {
-        args = "-machine virt";
-    }
-
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_data_func("/numa/mon/default", args, test_mon_default);
-    qtest_add_data_func("/numa/mon/cpus/explicit", args, test_mon_explicit);
-    qtest_add_data_func("/numa/mon/cpus/partial", args, test_mon_partial);
-    qtest_add_data_func("/numa/qmp/cpus/query-cpus", args, test_query_cpus);
-
-    if (!strcmp(arch, "i386") || !strcmp(arch, "x86_64")) {
-        qtest_add_data_func("/numa/pc/cpu/explicit", args, pc_numa_cpu);
-        qtest_add_data_func("/numa/pc/dynamic/cpu", args, pc_dynamic_cpu_cfg);
-        qtest_add_data_func("/numa/pc/hmat/build", args, pc_hmat_build_cfg);
-        qtest_add_data_func("/numa/pc/hmat/off", args, pc_hmat_off_cfg);
-        qtest_add_data_func("/numa/pc/hmat/erange", args, pc_hmat_erange_cfg);
-    }
-
-    if (!strcmp(arch, "ppc64")) {
-        qtest_add_data_func("/numa/spapr/cpu/explicit", args, spapr_numa_cpu);
-    }
-
-    if (!strcmp(arch, "aarch64")) {
-        qtest_add_data_func("/numa/aarch64/cpu/explicit", args,
-                            aarch64_numa_cpu);
-    }
-
-    return g_test_run();
-}
diff --git a/tests/nvme-test.c b/tests/nvme-test.c
deleted file mode 100644 (file)
index ff04421..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * QTest testcase for NVMe
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/module.h"
-#include "qemu/units.h"
-#include "libqtest.h"
-#include "libqos/qgraph.h"
-#include "libqos/pci.h"
-
-typedef struct QNvme QNvme;
-
-struct QNvme {
-    QOSGraphObject obj;
-    QPCIDevice dev;
-};
-
-static void *nvme_get_driver(void *obj, const char *interface)
-{
-    QNvme *nvme = obj;
-
-    if (!g_strcmp0(interface, "pci-device")) {
-        return &nvme->dev;
-    }
-
-    fprintf(stderr, "%s not present in nvme\n", interface);
-    g_assert_not_reached();
-}
-
-static void *nvme_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
-{
-    QNvme *nvme = g_new0(QNvme, 1);
-    QPCIBus *bus = pci_bus;
-
-    qpci_device_init(&nvme->dev, bus, addr);
-    nvme->obj.get_driver = nvme_get_driver;
-
-    return &nvme->obj;
-}
-
-/* This used to cause a NULL pointer dereference.  */
-static void nvmetest_oob_cmb_test(void *obj, void *data, QGuestAllocator *alloc)
-{
-    const int cmb_bar_size = 2 * MiB;
-    QNvme *nvme = obj;
-    QPCIDevice *pdev = &nvme->dev;
-    QPCIBar bar;
-
-    qpci_device_enable(pdev);
-    bar = qpci_iomap(pdev, 2, NULL);
-
-    qpci_io_writel(pdev, bar, 0, 0xccbbaa99);
-    g_assert_cmpint(qpci_io_readb(pdev, bar, 0), ==, 0x99);
-    g_assert_cmpint(qpci_io_readw(pdev, bar, 0), ==, 0xaa99);
-
-    /* Test partially out-of-bounds accesses.  */
-    qpci_io_writel(pdev, bar, cmb_bar_size - 1, 0x44332211);
-    g_assert_cmpint(qpci_io_readb(pdev, bar, cmb_bar_size - 1), ==, 0x11);
-    g_assert_cmpint(qpci_io_readw(pdev, bar, cmb_bar_size - 1), !=, 0x2211);
-    g_assert_cmpint(qpci_io_readl(pdev, bar, cmb_bar_size - 1), !=, 0x44332211);
-}
-
-static void nvme_register_nodes(void)
-{
-    QOSGraphEdgeOptions opts = {
-        .extra_device_opts = "addr=04.0,drive=drv0,serial=foo",
-        .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,"
-                           "file.read-zeroes=on,format=raw",
-    };
-
-    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
-
-    qos_node_create_driver("nvme", nvme_create);
-    qos_node_consumes("nvme", "pci-bus", &opts);
-    qos_node_produces("nvme", "pci-device");
-
-    qos_add_test("oob-cmb-access", "nvme", nvmetest_oob_cmb_test, &(QOSGraphTestOptions) {
-        .edge.extra_device_opts = "cmb_size_mb=2"
-    });
-}
-
-libqos_init(nvme_register_nodes);
diff --git a/tests/pca9552-test.c b/tests/pca9552-test.c
deleted file mode 100644 (file)
index 4b800d3..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * QTest testcase for the PCA9552 LED blinker
- *
- * Copyright (c) 2017-2018, IBM Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-
-#include "libqtest.h"
-#include "libqos/qgraph.h"
-#include "libqos/i2c.h"
-#include "hw/misc/pca9552_regs.h"
-
-#define PCA9552_TEST_ID   "pca9552-test"
-#define PCA9552_TEST_ADDR 0x60
-
-static void pca9552_init(QI2CDevice *i2cdev)
-{
-    /* Switch on LEDs 0 and 12 */
-    i2c_set8(i2cdev, PCA9552_LS0, 0x54);
-    i2c_set8(i2cdev, PCA9552_LS3, 0x54);
-}
-
-static void receive_autoinc(void *obj, void *data, QGuestAllocator *alloc)
-{
-    QI2CDevice *i2cdev = (QI2CDevice *)obj;
-    uint8_t resp;
-    uint8_t reg = PCA9552_LS0 | PCA9552_AUTOINC;
-
-    pca9552_init(i2cdev);
-
-    i2c_send(i2cdev, &reg, 1);
-
-    /* PCA9552_LS0 */
-    i2c_recv(i2cdev, &resp, 1);
-    g_assert_cmphex(resp, ==, 0x54);
-
-    /* PCA9552_LS1 */
-    i2c_recv(i2cdev, &resp, 1);
-    g_assert_cmphex(resp, ==, 0x55);
-
-    /* PCA9552_LS2 */
-    i2c_recv(i2cdev, &resp, 1);
-    g_assert_cmphex(resp, ==, 0x55);
-
-    /* PCA9552_LS3 */
-    i2c_recv(i2cdev, &resp, 1);
-    g_assert_cmphex(resp, ==, 0x54);
-}
-
-static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc)
-{
-    QI2CDevice *i2cdev = (QI2CDevice *)obj;
-    uint8_t value;
-
-    value = i2c_get8(i2cdev, PCA9552_LS0);
-    g_assert_cmphex(value, ==, 0x55);
-
-    value = i2c_get8(i2cdev, PCA9552_INPUT0);
-    g_assert_cmphex(value, ==, 0x0);
-
-    pca9552_init(i2cdev);
-
-    value = i2c_get8(i2cdev, PCA9552_LS0);
-    g_assert_cmphex(value, ==, 0x54);
-
-    value = i2c_get8(i2cdev, PCA9552_INPUT0);
-    g_assert_cmphex(value, ==, 0x01);
-
-    value = i2c_get8(i2cdev, PCA9552_LS3);
-    g_assert_cmphex(value, ==, 0x54);
-
-    value = i2c_get8(i2cdev, PCA9552_INPUT1);
-    g_assert_cmphex(value, ==, 0x10);
-}
-
-static void pca9552_register_nodes(void)
-{
-    QOSGraphEdgeOptions opts = {
-        .extra_device_opts = "address=0x60"
-    };
-    add_qi2c_address(&opts, &(QI2CAddress) { 0x60 });
-
-    qos_node_create_driver("pca9552", i2c_device_create);
-    qos_node_consumes("pca9552", "i2c-bus", &opts);
-
-    qos_add_test("tx-rx", "pca9552", send_and_receive, NULL);
-    qos_add_test("rx-autoinc", "pca9552", receive_autoinc, NULL);
-}
-libqos_init(pca9552_register_nodes);
diff --git a/tests/pci-test.c b/tests/pci-test.c
deleted file mode 100644 (file)
index 4b2092b..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * QTest testcase for PCI
- *
- * Copyright (c) 2018 Red Hat, Inc.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qemu/module.h"
-#include "libqos/qgraph.h"
-#include "libqos/pci.h"
-
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void nop(void *obj, void *data, QGuestAllocator *alloc)
-{
-}
-
-static void register_pci_test(void)
-{
-    qos_add_test("nop", "pci-device", nop, NULL);
-}
-
-libqos_init(register_pci_test);
diff --git a/tests/pcnet-test.c b/tests/pcnet-test.c
deleted file mode 100644 (file)
index 900944f..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * QTest testcase for PC-Net NIC
- *
- * Copyright (c) 2013-2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qemu/module.h"
-#include "libqos/qgraph.h"
-#include "libqos/pci.h"
-
-typedef struct QPCNet QPCNet;
-
-struct QPCNet {
-    QOSGraphObject obj;
-    QPCIDevice dev;
-};
-
-static void *pcnet_get_driver(void *obj, const char *interface)
-{
-    QPCNet *pcnet = obj;
-
-    if (!g_strcmp0(interface, "pci-device")) {
-        return &pcnet->dev;
-    }
-
-    fprintf(stderr, "%s not present in pcnet\n", interface);
-    g_assert_not_reached();
-}
-
-static void *pcnet_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
-{
-    QPCNet *pcnet = g_new0(QPCNet, 1);
-    QPCIBus *bus = pci_bus;
-
-    qpci_device_init(&pcnet->dev, bus, addr);
-    pcnet->obj.get_driver = pcnet_get_driver;
-
-    return &pcnet->obj;
-}
-
-static void pcnet_register_nodes(void)
-{
-    QOSGraphEdgeOptions opts = {
-        .extra_device_opts = "addr=04.0",
-    };
-    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
-
-    qos_node_create_driver("pcnet", pcnet_create);
-    qos_node_consumes("pcnet", "pci-bus", &opts);
-    qos_node_produces("pcnet", "pci-device");
-}
-
-libqos_init(pcnet_register_nodes);
diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c
deleted file mode 100644 (file)
index 17aa669..0000000
+++ /dev/null
@@ -1,681 +0,0 @@
-/*
- * QTest testcase for parallel flash with AMD command set
- *
- * Copyright (c) 2019 Stephen Checkoway
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-
-/*
- * To test the pflash_cfi02 device, we run QEMU with the musicpal machine with
- * a pflash drive. This enables us to test some flash configurations, but not
- * all. In particular, we're limited to a 16-bit wide flash device.
- */
-
-#define MP_FLASH_SIZE_MAX (32 * 1024 * 1024)
-#define BASE_ADDR (0x100000000ULL - MP_FLASH_SIZE_MAX)
-
-#define UNIFORM_FLASH_SIZE (8 * 1024 * 1024)
-#define UNIFORM_FLASH_SECTOR_SIZE (64 * 1024)
-
-/* Use a newtype to keep flash addresses separate from byte addresses. */
-typedef struct {
-    uint64_t addr;
-} faddr;
-#define FLASH_ADDR(x) ((faddr) { .addr = (x) })
-
-#define CFI_ADDR FLASH_ADDR(0x55)
-#define UNLOCK0_ADDR FLASH_ADDR(0x555)
-#define UNLOCK1_ADDR FLASH_ADDR(0x2AA)
-
-#define CFI_CMD 0x98
-#define UNLOCK0_CMD 0xAA
-#define UNLOCK1_CMD 0x55
-#define SECOND_UNLOCK_CMD 0x80
-#define AUTOSELECT_CMD 0x90
-#define RESET_CMD 0xF0
-#define PROGRAM_CMD 0xA0
-#define SECTOR_ERASE_CMD 0x30
-#define CHIP_ERASE_CMD 0x10
-#define UNLOCK_BYPASS_CMD 0x20
-#define UNLOCK_BYPASS_RESET_CMD 0x00
-#define ERASE_SUSPEND_CMD 0xB0
-#define ERASE_RESUME_CMD SECTOR_ERASE_CMD
-
-typedef struct {
-    int bank_width;
-
-    /* Nonuniform block size. */
-    int nb_blocs[4];
-    int sector_len[4];
-
-    QTestState *qtest;
-} FlashConfig;
-
-static char image_path[] = "/tmp/qtest.XXXXXX";
-
-/*
- * The pflash implementation allows some parameters to be unspecified. We want
- * to test those configurations but we also need to know the real values in
- * our testing code. So after we launch qemu, we'll need a new FlashConfig
- * with the correct values filled in.
- */
-static FlashConfig expand_config_defaults(const FlashConfig *c)
-{
-    FlashConfig ret = *c;
-
-    if (ret.bank_width == 0) {
-        ret.bank_width = 2;
-    }
-    if (ret.nb_blocs[0] == 0 && ret.sector_len[0] == 0) {
-        ret.sector_len[0] = UNIFORM_FLASH_SECTOR_SIZE;
-        ret.nb_blocs[0] = UNIFORM_FLASH_SIZE / UNIFORM_FLASH_SECTOR_SIZE;
-    }
-
-    /* XXX: Limitations of test harness. */
-    assert(ret.bank_width == 2);
-    return ret;
-}
-
-/*
- * Return a bit mask suitable for extracting the least significant
- * status/query response from an interleaved response.
- */
-static inline uint64_t device_mask(const FlashConfig *c)
-{
-    return (uint64_t)-1;
-}
-
-/*
- * Return a bit mask exactly as long as the bank_width.
- */
-static inline uint64_t bank_mask(const FlashConfig *c)
-{
-    if (c->bank_width == 8) {
-        return (uint64_t)-1;
-    }
-    return (1ULL << (c->bank_width * 8)) - 1ULL;
-}
-
-static inline void flash_write(const FlashConfig *c, uint64_t byte_addr,
-                               uint64_t data)
-{
-    /* Sanity check our tests. */
-    assert((data & ~bank_mask(c)) == 0);
-    uint64_t addr = BASE_ADDR + byte_addr;
-    switch (c->bank_width) {
-    case 1:
-        qtest_writeb(c->qtest, addr, data);
-        break;
-    case 2:
-        qtest_writew(c->qtest, addr, data);
-        break;
-    case 4:
-        qtest_writel(c->qtest, addr, data);
-        break;
-    case 8:
-        qtest_writeq(c->qtest, addr, data);
-        break;
-    default:
-        abort();
-    }
-}
-
-static inline uint64_t flash_read(const FlashConfig *c, uint64_t byte_addr)
-{
-    uint64_t addr = BASE_ADDR + byte_addr;
-    switch (c->bank_width) {
-    case 1:
-        return qtest_readb(c->qtest, addr);
-    case 2:
-        return qtest_readw(c->qtest, addr);
-    case 4:
-        return qtest_readl(c->qtest, addr);
-    case 8:
-        return qtest_readq(c->qtest, addr);
-    default:
-        abort();
-    }
-}
-
-/*
- * Convert a flash address expressed in the maximum width of the device as a
- * byte address.
- */
-static inline uint64_t as_byte_addr(const FlashConfig *c, faddr flash_addr)
-{
-    /*
-     * Command addresses are always given as addresses in the maximum
-     * supported bus size for the flash chip. So an x8/x16 chip in x8 mode
-     * uses addresses 0xAAA and 0x555 to unlock because the least significant
-     * bit is ignored. (0x555 rather than 0x554 is traditional.)
-     *
-     * In general we need to multiply by the maximum device width.
-     */
-    return flash_addr.addr * c->bank_width;
-}
-
-/*
- * Return the command value or expected status replicated across all devices.
- */
-static inline uint64_t replicate(const FlashConfig *c, uint64_t data)
-{
-    /* Sanity check our tests. */
-    assert((data & ~device_mask(c)) == 0);
-    return data;
-}
-
-static inline void flash_cmd(const FlashConfig *c, faddr cmd_addr,
-                             uint8_t cmd)
-{
-    flash_write(c, as_byte_addr(c, cmd_addr), replicate(c, cmd));
-}
-
-static inline uint64_t flash_query(const FlashConfig *c, faddr query_addr)
-{
-    return flash_read(c, as_byte_addr(c, query_addr));
-}
-
-static inline uint64_t flash_query_1(const FlashConfig *c, faddr query_addr)
-{
-    return flash_query(c, query_addr) & device_mask(c);
-}
-
-static void unlock(const FlashConfig *c)
-{
-    flash_cmd(c, UNLOCK0_ADDR, UNLOCK0_CMD);
-    flash_cmd(c, UNLOCK1_ADDR, UNLOCK1_CMD);
-}
-
-static void reset(const FlashConfig *c)
-{
-    flash_cmd(c, FLASH_ADDR(0), RESET_CMD);
-}
-
-static void sector_erase(const FlashConfig *c, uint64_t byte_addr)
-{
-    unlock(c);
-    flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
-    unlock(c);
-    flash_write(c, byte_addr, replicate(c, SECTOR_ERASE_CMD));
-}
-
-static void wait_for_completion(const FlashConfig *c, uint64_t byte_addr)
-{
-    /* If DQ6 is toggling, step the clock and ensure the toggle stops. */
-    const uint64_t dq6 = replicate(c, 0x40);
-    if ((flash_read(c, byte_addr) & dq6) ^ (flash_read(c, byte_addr) & dq6)) {
-        /* Wait for erase or program to finish. */
-        qtest_clock_step_next(c->qtest);
-        /* Ensure that DQ6 has stopped toggling. */
-        g_assert_cmphex(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
-    }
-}
-
-static void bypass_program(const FlashConfig *c, uint64_t byte_addr,
-                           uint16_t data)
-{
-    flash_cmd(c, UNLOCK0_ADDR, PROGRAM_CMD);
-    flash_write(c, byte_addr, data);
-    /*
-     * Data isn't valid until DQ6 stops toggling. We don't model this as
-     * writes are immediate, but if this changes in the future, we can wait
-     * until the program is complete.
-     */
-    wait_for_completion(c, byte_addr);
-}
-
-static void program(const FlashConfig *c, uint64_t byte_addr, uint16_t data)
-{
-    unlock(c);
-    bypass_program(c, byte_addr, data);
-}
-
-static void chip_erase(const FlashConfig *c)
-{
-    unlock(c);
-    flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
-    unlock(c);
-    flash_cmd(c, UNLOCK0_ADDR, CHIP_ERASE_CMD);
-}
-
-static void erase_suspend(const FlashConfig *c)
-{
-    flash_cmd(c, FLASH_ADDR(0), ERASE_SUSPEND_CMD);
-}
-
-static void erase_resume(const FlashConfig *c)
-{
-    flash_cmd(c, FLASH_ADDR(0), ERASE_RESUME_CMD);
-}
-
-/*
- * Test flash commands with a variety of device geometry.
- */
-static void test_geometry(const void *opaque)
-{
-    const FlashConfig *config = opaque;
-    QTestState *qtest;
-    qtest = qtest_initf("-M musicpal"
-                        " -drive if=pflash,file=%s,format=raw,copy-on-read"
-                        /* Device geometry properties. */
-                        " -global driver=cfi.pflash02,"
-                        "property=num-blocks0,value=%d"
-                        " -global driver=cfi.pflash02,"
-                        "property=sector-length0,value=%d"
-                        " -global driver=cfi.pflash02,"
-                        "property=num-blocks1,value=%d"
-                        " -global driver=cfi.pflash02,"
-                        "property=sector-length1,value=%d"
-                        " -global driver=cfi.pflash02,"
-                        "property=num-blocks2,value=%d"
-                        " -global driver=cfi.pflash02,"
-                        "property=sector-length2,value=%d"
-                        " -global driver=cfi.pflash02,"
-                        "property=num-blocks3,value=%d"
-                        " -global driver=cfi.pflash02,"
-                        "property=sector-length3,value=%d",
-                        image_path,
-                        config->nb_blocs[0],
-                        config->sector_len[0],
-                        config->nb_blocs[1],
-                        config->sector_len[1],
-                        config->nb_blocs[2],
-                        config->sector_len[2],
-                        config->nb_blocs[3],
-                        config->sector_len[3]);
-    FlashConfig explicit_config = expand_config_defaults(config);
-    explicit_config.qtest = qtest;
-    const FlashConfig *c = &explicit_config;
-
-    /* Check the IDs. */
-    unlock(c);
-    flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD);
-    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
-    if (c->bank_width >= 2) {
-        /*
-         * XXX: The ID returned by the musicpal flash chip is 16 bits which
-         * wouldn't happen with an 8-bit device. It would probably be best to
-         * prohibit addresses larger than the device width in pflash_cfi02.c,
-         * but then we couldn't test smaller device widths at all.
-         */
-        g_assert_cmphex(flash_query(c, FLASH_ADDR(1)), ==,
-                        replicate(c, 0x236D));
-    }
-    reset(c);
-
-    /* Check the erase blocks. */
-    flash_cmd(c, CFI_ADDR, CFI_CMD);
-    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
-    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
-    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
-
-    /* Num erase regions. */
-    int nb_erase_regions = flash_query_1(c, FLASH_ADDR(0x2C));
-    g_assert_cmphex(nb_erase_regions, ==,
-                    !!c->nb_blocs[0] + !!c->nb_blocs[1] + !!c->nb_blocs[2] +
-                    !!c->nb_blocs[3]);
-
-    /* Check device length. */
-    uint32_t device_len = 1 << flash_query_1(c, FLASH_ADDR(0x27));
-    g_assert_cmphex(device_len, ==, UNIFORM_FLASH_SIZE);
-
-    /* Check that erase suspend to read/write is supported. */
-    uint16_t pri = flash_query_1(c, FLASH_ADDR(0x15)) +
-                   (flash_query_1(c, FLASH_ADDR(0x16)) << 8);
-    g_assert_cmpint(pri, >=, 0x2D + 4 * nb_erase_regions);
-    g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 0)), ==, replicate(c, 'P'));
-    g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 1)), ==, replicate(c, 'R'));
-    g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 2)), ==, replicate(c, 'I'));
-    g_assert_cmpint(flash_query_1(c, FLASH_ADDR(pri + 6)), ==, 2); /* R/W */
-    reset(c);
-
-    const uint64_t dq7 = replicate(c, 0x80);
-    const uint64_t dq6 = replicate(c, 0x40);
-    const uint64_t dq3 = replicate(c, 0x08);
-    const uint64_t dq2 = replicate(c, 0x04);
-
-    uint64_t byte_addr = 0;
-    for (int region = 0; region < nb_erase_regions; ++region) {
-        uint64_t base = 0x2D + 4 * region;
-        flash_cmd(c, CFI_ADDR, CFI_CMD);
-        uint32_t nb_sectors = flash_query_1(c, FLASH_ADDR(base + 0)) +
-                              (flash_query_1(c, FLASH_ADDR(base + 1)) << 8) + 1;
-        uint32_t sector_len = (flash_query_1(c, FLASH_ADDR(base + 2)) << 8) +
-                              (flash_query_1(c, FLASH_ADDR(base + 3)) << 16);
-        g_assert_cmphex(nb_sectors, ==, c->nb_blocs[region]);
-        g_assert_cmphex(sector_len, ==, c->sector_len[region]);
-        reset(c);
-
-        /* Erase and program sector. */
-        for (uint32_t i = 0; i < nb_sectors; ++i) {
-            sector_erase(c, byte_addr);
-
-            /* Check that DQ3 is 0. */
-            g_assert_cmphex(flash_read(c, byte_addr) & dq3, ==, 0);
-            qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */
-
-            /* Check that DQ3 is 1. */
-            uint64_t status0 = flash_read(c, byte_addr);
-            g_assert_cmphex(status0 & dq3, ==, dq3);
-
-            /* DQ7 is 0 during an erase. */
-            g_assert_cmphex(status0 & dq7, ==, 0);
-            uint64_t status1 = flash_read(c, byte_addr);
-
-            /* DQ6 toggles during an erase. */
-            g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
-
-            /* Wait for erase to complete. */
-            wait_for_completion(c, byte_addr);
-
-            /* Ensure DQ6 has stopped toggling. */
-            g_assert_cmphex(flash_read(c, byte_addr), ==,
-                            flash_read(c, byte_addr));
-
-            /* Now the data should be valid. */
-            g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
-
-            /* Program a bit pattern. */
-            program(c, byte_addr, 0x55);
-            g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x55);
-            program(c, byte_addr, 0xA5);
-            g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x05);
-            byte_addr += sector_len;
-        }
-    }
-
-    /* Erase the chip. */
-    chip_erase(c);
-    /* Read toggle. */
-    uint64_t status0 = flash_read(c, 0);
-    /* DQ7 is 0 during an erase. */
-    g_assert_cmphex(status0 & dq7, ==, 0);
-    uint64_t status1 = flash_read(c, 0);
-    /* DQ6 toggles during an erase. */
-    g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
-    /* Wait for erase to complete. */
-    qtest_clock_step_next(c->qtest);
-    /* Ensure DQ6 has stopped toggling. */
-    g_assert_cmphex(flash_read(c, 0), ==, flash_read(c, 0));
-    /* Now the data should be valid. */
-
-    for (int region = 0; region < nb_erase_regions; ++region) {
-        for (uint32_t i = 0; i < c->nb_blocs[region]; ++i) {
-            uint64_t byte_addr = i * c->sector_len[region];
-            g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
-        }
-    }
-
-    /* Unlock bypass */
-    unlock(c);
-    flash_cmd(c, UNLOCK0_ADDR, UNLOCK_BYPASS_CMD);
-    bypass_program(c, 0 * c->bank_width, 0x01);
-    bypass_program(c, 1 * c->bank_width, 0x23);
-    bypass_program(c, 2 * c->bank_width, 0x45);
-    /*
-     * Test that bypass programming, unlike normal programming can use any
-     * address for the PROGRAM_CMD.
-     */
-    flash_cmd(c, FLASH_ADDR(3 * c->bank_width), PROGRAM_CMD);
-    flash_write(c, 3 * c->bank_width, 0x67);
-    wait_for_completion(c, 3 * c->bank_width);
-    flash_cmd(c, FLASH_ADDR(0), UNLOCK_BYPASS_RESET_CMD);
-    bypass_program(c, 4 * c->bank_width, 0x89); /* Should fail. */
-    g_assert_cmphex(flash_read(c, 0 * c->bank_width), ==, 0x01);
-    g_assert_cmphex(flash_read(c, 1 * c->bank_width), ==, 0x23);
-    g_assert_cmphex(flash_read(c, 2 * c->bank_width), ==, 0x45);
-    g_assert_cmphex(flash_read(c, 3 * c->bank_width), ==, 0x67);
-    g_assert_cmphex(flash_read(c, 4 * c->bank_width), ==, bank_mask(c));
-
-    /* Test ignored high order bits of address. */
-    flash_cmd(c, FLASH_ADDR(0x5555), UNLOCK0_CMD);
-    flash_cmd(c, FLASH_ADDR(0x2AAA), UNLOCK1_CMD);
-    flash_cmd(c, FLASH_ADDR(0x5555), AUTOSELECT_CMD);
-    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
-    reset(c);
-
-    /*
-     * Program a word on each sector, erase one or two sectors per region, and
-     * verify that all of those, and only those, are erased.
-     */
-    byte_addr = 0;
-    for (int region = 0; region < nb_erase_regions; ++region) {
-        for (int i = 0; i < config->nb_blocs[region]; ++i) {
-            program(c, byte_addr, 0);
-            byte_addr += config->sector_len[region];
-        }
-    }
-    unlock(c);
-    flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
-    unlock(c);
-    byte_addr = 0;
-    const uint64_t erase_cmd = replicate(c, SECTOR_ERASE_CMD);
-    for (int region = 0; region < nb_erase_regions; ++region) {
-        flash_write(c, byte_addr, erase_cmd);
-        if (c->nb_blocs[region] > 1) {
-            flash_write(c, byte_addr + c->sector_len[region], erase_cmd);
-        }
-        byte_addr += c->sector_len[region] * c->nb_blocs[region];
-    }
-
-    qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */
-    wait_for_completion(c, 0);
-    byte_addr = 0;
-    for (int region = 0; region < nb_erase_regions; ++region) {
-        for (int i = 0; i < config->nb_blocs[region]; ++i) {
-            if (i < 2) {
-                g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
-            } else {
-                g_assert_cmphex(flash_read(c, byte_addr), ==, 0);
-            }
-            byte_addr += config->sector_len[region];
-        }
-    }
-
-    /* Test erase suspend/resume during erase timeout. */
-    sector_erase(c, 0);
-    /*
-     * Check that DQ 3 is 0 and DQ6 and DQ2 are toggling in the sector being
-     * erased as well as in a sector not being erased.
-     */
-    byte_addr = c->sector_len[0];
-    status0 = flash_read(c, 0);
-    status1 = flash_read(c, 0);
-    g_assert_cmpint(status0 & dq3, ==, 0);
-    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
-    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
-    status0 = flash_read(c, byte_addr);
-    status1 = flash_read(c, byte_addr);
-    g_assert_cmpint(status0 & dq3, ==, 0);
-    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
-    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
-
-    /*
-     * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in
-     * an erase suspended sector but that neither toggle (we should be
-     * getting data) in a sector not being erased.
-     */
-    erase_suspend(c);
-    status0 = flash_read(c, 0);
-    status1 = flash_read(c, 0);
-    g_assert_cmpint(status0 & dq6, ==, status1 & dq6);
-    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
-    g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
-
-    /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */
-    erase_resume(c);
-    status0 = flash_read(c, 0);
-    status1 = flash_read(c, 0);
-    g_assert_cmpint(status0 & dq3, ==, dq3);
-    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
-    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
-    status0 = flash_read(c, byte_addr);
-    status1 = flash_read(c, byte_addr);
-    g_assert_cmpint(status0 & dq3, ==, dq3);
-    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
-    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
-    wait_for_completion(c, 0);
-
-    /* Repeat this process but this time suspend after the timeout. */
-    sector_erase(c, 0);
-    qtest_clock_step_next(c->qtest);
-    /*
-     * Check that DQ 3 is 1 and DQ6 and DQ2 are toggling in the sector being
-     * erased as well as in a sector not being erased.
-     */
-    byte_addr = c->sector_len[0];
-    status0 = flash_read(c, 0);
-    status1 = flash_read(c, 0);
-    g_assert_cmpint(status0 & dq3, ==, dq3);
-    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
-    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
-    status0 = flash_read(c, byte_addr);
-    status1 = flash_read(c, byte_addr);
-    g_assert_cmpint(status0 & dq3, ==, dq3);
-    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
-    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
-
-    /*
-     * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in
-     * an erase suspended sector but that neither toggle (we should be
-     * getting data) in a sector not being erased.
-     */
-    erase_suspend(c);
-    status0 = flash_read(c, 0);
-    status1 = flash_read(c, 0);
-    g_assert_cmpint(status0 & dq6, ==, status1 & dq6);
-    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
-    g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
-
-    /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */
-    erase_resume(c);
-    status0 = flash_read(c, 0);
-    status1 = flash_read(c, 0);
-    g_assert_cmpint(status0 & dq3, ==, dq3);
-    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
-    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
-    status0 = flash_read(c, byte_addr);
-    status1 = flash_read(c, byte_addr);
-    g_assert_cmpint(status0 & dq3, ==, dq3);
-    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
-    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
-    wait_for_completion(c, 0);
-
-    qtest_quit(qtest);
-}
-
-/*
- * Test that
- * 1. enter autoselect mode;
- * 2. enter CFI mode; and then
- * 3. exit CFI mode
- * leaves the flash device in autoselect mode.
- */
-static void test_cfi_in_autoselect(const void *opaque)
-{
-    const FlashConfig *config = opaque;
-    QTestState *qtest;
-    qtest = qtest_initf("-M musicpal"
-                        " -drive if=pflash,file=%s,format=raw,copy-on-read",
-                        image_path);
-    FlashConfig explicit_config = expand_config_defaults(config);
-    explicit_config.qtest = qtest;
-    const FlashConfig *c = &explicit_config;
-
-    /* 1. Enter autoselect. */
-    unlock(c);
-    flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD);
-    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
-
-    /* 2. Enter CFI. */
-    flash_cmd(c, CFI_ADDR, CFI_CMD);
-    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
-    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
-    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
-
-    /* 3. Exit CFI. */
-    reset(c);
-    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
-
-    qtest_quit(qtest);
-}
-
-static void cleanup(void *opaque)
-{
-    unlink(image_path);
-}
-
-/*
- * XXX: Tests are limited to bank_width = 2 for now because that's what
- * hw/arm/musicpal.c has.
- */
-static const FlashConfig configuration[] = {
-    /* One x16 device. */
-    {
-        .bank_width = 2,
-    },
-    /* Nonuniform sectors (top boot). */
-    {
-        .bank_width = 2,
-        .nb_blocs = { 127, 1, 2, 1 },
-        .sector_len = { 0x10000, 0x08000, 0x02000, 0x04000 },
-    },
-    /* Nonuniform sectors (bottom boot). */
-    {
-        .bank_width = 2,
-        .nb_blocs = { 1, 2, 1, 127 },
-        .sector_len = { 0x04000, 0x02000, 0x08000, 0x10000 },
-    },
-};
-
-int main(int argc, char **argv)
-{
-    int fd = mkstemp(image_path);
-    if (fd == -1) {
-        g_printerr("Failed to create temporary file %s: %s\n", image_path,
-                   strerror(errno));
-        exit(EXIT_FAILURE);
-    }
-    if (ftruncate(fd, UNIFORM_FLASH_SIZE) < 0) {
-        int error_code = errno;
-        close(fd);
-        unlink(image_path);
-        g_printerr("Failed to truncate file %s to %u MB: %s\n", image_path,
-                   UNIFORM_FLASH_SIZE, strerror(error_code));
-        exit(EXIT_FAILURE);
-    }
-    close(fd);
-
-    qtest_add_abrt_handler(cleanup, NULL);
-    g_test_init(&argc, &argv, NULL);
-
-    size_t nb_configurations = sizeof configuration / sizeof configuration[0];
-    for (size_t i = 0; i < nb_configurations; ++i) {
-        const FlashConfig *config = &configuration[i];
-        char *path = g_strdup_printf("pflash-cfi02"
-                                     "/geometry/%dx%x-%dx%x-%dx%x-%dx%x"
-                                     "/%d",
-                                     config->nb_blocs[0],
-                                     config->sector_len[0],
-                                     config->nb_blocs[1],
-                                     config->sector_len[1],
-                                     config->nb_blocs[2],
-                                     config->sector_len[2],
-                                     config->nb_blocs[3],
-                                     config->sector_len[3],
-                                     config->bank_width);
-        qtest_add_data_func(path, config, test_geometry);
-        g_free(path);
-    }
-
-    qtest_add_data_func("pflash-cfi02/cfi-in-autoselect", &configuration[0],
-                        test_cfi_in_autoselect);
-    int result = g_test_run();
-    cleanup(NULL);
-    return result;
-}
diff --git a/tests/pnv-xscom-test.c b/tests/pnv-xscom-test.c
deleted file mode 100644 (file)
index 2c46d5c..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * QTest testcase for PowerNV XSCOM bus
- *
- * Copyright (c) 2016, IBM Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or
- * later. See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-
-#include "libqtest.h"
-
-typedef enum PnvChipType {
-    PNV_CHIP_POWER8E,     /* AKA Murano (default) */
-    PNV_CHIP_POWER8,      /* AKA Venice */
-    PNV_CHIP_POWER8NVL,   /* AKA Naples */
-    PNV_CHIP_POWER9,      /* AKA Nimbus */
-} PnvChipType;
-
-typedef struct PnvChip {
-    PnvChipType chip_type;
-    const char *cpu_model;
-    uint64_t    xscom_base;
-    uint64_t    cfam_id;
-    uint32_t    first_core;
-} PnvChip;
-
-static const PnvChip pnv_chips[] = {
-    {
-        .chip_type  = PNV_CHIP_POWER8,
-        .cpu_model  = "POWER8",
-        .xscom_base = 0x0003fc0000000000ull,
-        .cfam_id    = 0x220ea04980000000ull,
-        .first_core = 0x1,
-    }, {
-        .chip_type  = PNV_CHIP_POWER8NVL,
-        .cpu_model  = "POWER8NVL",
-        .xscom_base = 0x0003fc0000000000ull,
-        .cfam_id    = 0x120d304980000000ull,
-        .first_core = 0x1,
-    },
-    {
-        .chip_type  = PNV_CHIP_POWER9,
-        .cpu_model  = "POWER9",
-        .xscom_base = 0x000603fc00000000ull,
-        .cfam_id    = 0x220d104900008000ull,
-        .first_core = 0x0,
-    },
-};
-
-static uint64_t pnv_xscom_addr(const PnvChip *chip, uint32_t pcba)
-{
-    uint64_t addr = chip->xscom_base;
-
-    if (chip->chip_type == PNV_CHIP_POWER9) {
-        addr |= ((uint64_t) pcba << 3);
-    } else {
-        addr |= (((uint64_t) pcba << 4) & ~0xffull) |
-            (((uint64_t) pcba << 3) & 0x78);
-    }
-    return addr;
-}
-
-static uint64_t pnv_xscom_read(QTestState *qts, const PnvChip *chip,
-                               uint32_t pcba)
-{
-    return qtest_readq(qts, pnv_xscom_addr(chip, pcba));
-}
-
-static void test_xscom_cfam_id(QTestState *qts, const PnvChip *chip)
-{
-    uint64_t f000f = pnv_xscom_read(qts, chip, 0xf000f);
-
-    g_assert_cmphex(f000f, ==, chip->cfam_id);
-}
-
-static void test_cfam_id(const void *data)
-{
-    const PnvChip *chip = data;
-    const char *machine = "powernv8";
-    QTestState *qts;
-
-    if (chip->chip_type == PNV_CHIP_POWER9) {
-        machine = "powernv9";
-    }
-
-    qts = qtest_initf("-M %s -accel tcg -cpu %s",
-                      machine, chip->cpu_model);
-    test_xscom_cfam_id(qts, chip);
-    qtest_quit(qts);
-}
-
-
-#define PNV_XSCOM_EX_CORE_BASE    0x10000000ull
-#define PNV_XSCOM_EX_BASE(core) \
-    (PNV_XSCOM_EX_CORE_BASE | ((uint64_t)(core) << 24))
-#define PNV_XSCOM_P9_EC_BASE(core) \
-    ((uint64_t)(((core) & 0x1F) + 0x20) << 24)
-
-#define PNV_XSCOM_EX_DTS_RESULT0     0x50000
-
-static void test_xscom_core(QTestState *qts, const PnvChip *chip)
-{
-    uint32_t first_core_dts0 = PNV_XSCOM_EX_DTS_RESULT0;
-    uint64_t dts0;
-
-    if (chip->chip_type != PNV_CHIP_POWER9) {
-        first_core_dts0 |= PNV_XSCOM_EX_BASE(chip->first_core);
-    } else {
-        first_core_dts0 |= PNV_XSCOM_P9_EC_BASE(chip->first_core);
-    }
-
-    dts0 = pnv_xscom_read(qts, chip, first_core_dts0);
-
-    g_assert_cmphex(dts0, ==, 0x26f024f023f0000ull);
-}
-
-static void test_core(const void *data)
-{
-    const PnvChip *chip = data;
-    QTestState *qts;
-    const char *machine = "powernv8";
-
-    if (chip->chip_type == PNV_CHIP_POWER9) {
-        machine = "powernv9";
-    }
-
-    qts = qtest_initf("-M %s -accel tcg -cpu %s",
-                      machine, chip->cpu_model);
-    test_xscom_core(qts, chip);
-    qtest_quit(qts);
-}
-
-static void add_test(const char *name, void (*test)(const void *data))
-{
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(pnv_chips); i++) {
-        char *tname = g_strdup_printf("pnv-xscom/%s/%s", name,
-                                      pnv_chips[i].cpu_model);
-        qtest_add_data_func(tname, &pnv_chips[i], test);
-        g_free(tname);
-    }
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-
-    add_test("cfam_id", test_cfam_id);
-    add_test("core", test_core);
-    return g_test_run();
-}
diff --git a/tests/prom-env-test.c b/tests/prom-env-test.c
deleted file mode 100644 (file)
index 9be52c7..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Test Open-Firmware-based machines.
- *
- * Copyright (c) 2016, 2017 Red Hat Inc.
- *
- * Author:
- *    Thomas Huth <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2
- * or later. See the COPYING file in the top-level directory.
- *
- * This test is used to check that some Open Firmware based machines (i.e.
- * OpenBIOS or SLOF) can be started successfully in TCG mode. To do this, we
- * first put some Forth code into the "boot-command" Open Firmware environment
- * variable. This Forth code writes a well-known magic value to a known location
- * in memory. Then we start the guest so that the firmware can boot and finally
- * run the Forth code.
- * The testing code here then can finally check whether the value has been
- * successfully written into the guest memory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-
-#define MAGIC   0xcafec0de
-#define ADDRESS 0x4000
-
-static void check_guest_memory(QTestState *qts)
-{
-    uint32_t signature;
-    int i;
-
-    /* Poll until code has run and modified memory. Wait at most 600 seconds */
-    for (i = 0; i < 60000; ++i) {
-        signature = qtest_readl(qts, ADDRESS);
-        if (signature == MAGIC) {
-            break;
-        }
-        g_usleep(10000);
-    }
-
-    g_assert_cmphex(signature, ==, MAGIC);
-}
-
-static void test_machine(const void *machine)
-{
-    const char *extra_args = "";
-    QTestState *qts;
-
-    /*
-     * The pseries firmware boots much faster without the default
-     * devices, it also needs Spectre/Meltdown workarounds disabled to
-     * avoid warnings with TCG
-     */
-    if (strcmp(machine, "pseries") == 0) {
-        extra_args = "-nodefaults"
-            " -machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken";
-    }
-
-    qts = qtest_initf("-M %s -accel tcg %s -prom-env 'use-nvramrc?=true' "
-                      "-prom-env 'nvramrc=%x %x l!' ", (const char *)machine,
-                      extra_args, MAGIC, ADDRESS);
-    check_guest_memory(qts);
-    qtest_quit(qts);
-}
-
-static void add_tests(const char *machines[])
-{
-    int i;
-    char *name;
-
-    for (i = 0; machines[i] != NULL; i++) {
-        name = g_strdup_printf("prom-env/%s", machines[i]);
-        qtest_add_data_func(name, machines[i], test_machine);
-        g_free(name);
-    }
-}
-
-int main(int argc, char *argv[])
-{
-    const char *sparc_machines[] = { "SPARCbook", "Voyager", "SS-20", NULL };
-    const char *sparc64_machines[] = { "sun4u", NULL };
-    const char *ppc_machines[] = { "mac99", "g3beige", NULL };
-    const char *arch = qtest_get_arch();
-
-    g_test_init(&argc, &argv, NULL);
-
-    if (!strcmp(arch, "ppc")) {
-        add_tests(ppc_machines);
-    } else if (!strcmp(arch, "ppc64")) {
-        add_tests(ppc_machines);
-        if (g_test_slow()) {
-            qtest_add_data_func("prom-env/pseries", "pseries", test_machine);
-        }
-    } else if (!strcmp(arch, "sparc")) {
-        add_tests(sparc_machines);
-    } else if (!strcmp(arch, "sparc64")) {
-        add_tests(sparc64_machines);
-    } else {
-        g_assert_not_reached();
-    }
-
-    return g_test_run();
-}
diff --git a/tests/pvpanic-test.c b/tests/pvpanic-test.c
deleted file mode 100644 (file)
index ff9176a..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * QTest testcase for PV Panic
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-
-static void test_panic(void)
-{
-    uint8_t val;
-    QDict *response, *data;
-    QTestState *qts;
-
-    qts = qtest_init("-device pvpanic");
-
-    val = qtest_inb(qts, 0x505);
-    g_assert_cmpuint(val, ==, 1);
-
-    qtest_outb(qts, 0x505, 0x1);
-
-    response = qtest_qmp_receive(qts);
-    g_assert(qdict_haskey(response, "event"));
-    g_assert_cmpstr(qdict_get_str(response, "event"), ==, "GUEST_PANICKED");
-    g_assert(qdict_haskey(response, "data"));
-    data = qdict_get_qdict(response, "data");
-    g_assert(qdict_haskey(data, "action"));
-    g_assert_cmpstr(qdict_get_str(data, "action"), ==, "pause");
-    qobject_unref(response);
-
-    qtest_quit(qts);
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/pvpanic/panic", test_panic);
-
-    ret = g_test_run();
-
-    return ret;
-}
diff --git a/tests/pxe-test.c b/tests/pxe-test.c
deleted file mode 100644 (file)
index f68d0aa..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * PXE test cases.
- *
- * Copyright (c) 2016, 2017 Red Hat Inc.
- *
- * Authors:
- *  Michael S. Tsirkin <[email protected]>,
- *  Victor Kaplansky <[email protected]>
- *  Thomas Huth <[email protected]>
- *
- * 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 "qemu-common.h"
-#include "libqtest.h"
-#include "boot-sector.h"
-
-#define NETNAME "net0"
-
-static char disk[] = "tests/pxe-test-disk-XXXXXX";
-
-typedef struct testdef {
-    const char *machine;    /* Machine type */
-    const char *model;      /* NIC device model */
-    const char *extra;      /* Any additional parameters */
-} testdef_t;
-
-static testdef_t x86_tests[] = {
-    { "pc", "e1000" },
-    { "pc", "virtio-net-pci" },
-    { "q35", "e1000e" },
-    { "q35", "virtio-net-pci", },
-    { NULL },
-};
-
-static testdef_t x86_tests_slow[] = {
-    { "pc", "ne2k_pci", },
-    { "pc", "i82550", },
-    { "pc", "rtl8139" },
-    { "pc", "vmxnet3" },
-    { NULL },
-};
-
-static testdef_t ppc64_tests[] = {
-    { "pseries", "spapr-vlan",
-      "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken,vsmt=8" },
-    { "pseries", "virtio-net-pci",
-      "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken,vsmt=8" },
-    { NULL },
-};
-
-static testdef_t ppc64_tests_slow[] = {
-    { "pseries", "e1000",
-      "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken,vsmt=8" },
-    { NULL },
-};
-
-static testdef_t s390x_tests[] = {
-    { "s390-ccw-virtio", "virtio-net-ccw" },
-    { NULL },
-};
-
-static void test_pxe_one(const testdef_t *test, bool ipv6)
-{
-    QTestState *qts;
-    char *args;
-    const char *extra = test->extra;
-
-    if (!extra) {
-        extra = "";
-    }
-
-    args = g_strdup_printf(
-        "-accel kvm -accel tcg -machine %s -nodefaults -boot order=n "
-        "-netdev user,id=" NETNAME ",tftp=./,bootfile=%s,ipv4=%s,ipv6=%s "
-        "-device %s,bootindex=1,netdev=" NETNAME " %s",
-        test->machine, disk, ipv6 ? "off" : "on", ipv6 ? "on" : "off",
-        test->model, extra);
-
-    qts = qtest_init(args);
-    boot_sector_test(qts);
-    qtest_quit(qts);
-    g_free(args);
-}
-
-static void test_pxe_ipv4(gconstpointer data)
-{
-    const testdef_t *test = data;
-
-    test_pxe_one(test, false);
-}
-
-static void test_pxe_ipv6(gconstpointer data)
-{
-    const testdef_t *test = data;
-
-    test_pxe_one(test, true);
-}
-
-static void test_batch(const testdef_t *tests, bool ipv6)
-{
-    int i;
-
-    for (i = 0; tests[i].machine; i++) {
-        const testdef_t *test = &tests[i];
-        char *testname;
-
-        testname = g_strdup_printf("pxe/ipv4/%s/%s",
-                                   test->machine, test->model);
-        qtest_add_data_func(testname, test, test_pxe_ipv4);
-        g_free(testname);
-
-        if (ipv6) {
-            testname = g_strdup_printf("pxe/ipv6/%s/%s",
-                                       test->machine, test->model);
-            qtest_add_data_func(testname, test, test_pxe_ipv6);
-            g_free(testname);
-        }
-    }
-}
-
-int main(int argc, char *argv[])
-{
-    int ret;
-    const char *arch = qtest_get_arch();
-
-    ret = boot_sector_init(disk);
-    if(ret)
-        return ret;
-
-    g_test_init(&argc, &argv, NULL);
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        test_batch(x86_tests, false);
-        if (g_test_slow()) {
-            test_batch(x86_tests_slow, false);
-        }
-    } else if (strcmp(arch, "ppc64") == 0) {
-        test_batch(ppc64_tests, g_test_slow());
-        if (g_test_slow()) {
-            test_batch(ppc64_tests_slow, true);
-        }
-    } else if (g_str_equal(arch, "s390x")) {
-        test_batch(s390x_tests, g_test_slow());
-    }
-    ret = g_test_run();
-    boot_sector_cleanup(disk);
-    return ret;
-}
diff --git a/tests/q35-test.c b/tests/q35-test.c
deleted file mode 100644 (file)
index a68183d..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * QTest testcase for Q35 northbridge
- *
- * Copyright (c) 2015 Red Hat, Inc.
- *
- * Author: Gerd Hoffmann <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "libqos/pci.h"
-#include "libqos/pci-pc.h"
-#include "hw/pci-host/q35.h"
-#include "qapi/qmp/qdict.h"
-
-#define TSEG_SIZE_TEST_GUEST_RAM_MBYTES 128
-
-/* @esmramc_tseg_sz: ESMRAMC.TSEG_SZ bitmask for selecting the requested TSEG
- *                   size. Must be a subset of
- *                   MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK.
- *
- * @extended_tseg_mbytes: Size of the extended TSEG. Only consulted if
- *                        @esmramc_tseg_sz equals
- *                        MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK precisely.
- *
- * @expected_tseg_mbytes: Expected guest-visible TSEG size in megabytes,
- *                        matching @esmramc_tseg_sz and @extended_tseg_mbytes
- *                        above.
- */
-struct TsegSizeArgs {
-    uint8_t esmramc_tseg_sz;
-    uint16_t extended_tseg_mbytes;
-    uint16_t expected_tseg_mbytes;
-};
-typedef struct TsegSizeArgs TsegSizeArgs;
-
-static const TsegSizeArgs tseg_1mb = {
-    .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB,
-    .extended_tseg_mbytes = 0,
-    .expected_tseg_mbytes = 1,
-};
-static const TsegSizeArgs tseg_2mb = {
-    .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB,
-    .extended_tseg_mbytes = 0,
-    .expected_tseg_mbytes = 2,
-};
-static const TsegSizeArgs tseg_8mb = {
-    .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_8MB,
-    .extended_tseg_mbytes = 0,
-    .expected_tseg_mbytes = 8,
-};
-static const TsegSizeArgs tseg_ext_16mb = {
-    .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK,
-    .extended_tseg_mbytes = 16,
-    .expected_tseg_mbytes = 16,
-};
-
-static void smram_set_bit(QPCIDevice *pcidev, uint8_t mask, bool enabled)
-{
-    uint8_t smram;
-
-    smram = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM);
-    if (enabled) {
-        smram |= mask;
-    } else {
-        smram &= ~mask;
-    }
-    qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram);
-}
-
-static bool smram_test_bit(QPCIDevice *pcidev, uint8_t mask)
-{
-    uint8_t smram;
-
-    smram = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM);
-    return smram & mask;
-}
-
-static void test_smram_lock(void)
-{
-    QPCIBus *pcibus;
-    QPCIDevice *pcidev;
-    QDict *response;
-    QTestState *qts;
-
-    qts = qtest_init("-M q35");
-
-    pcibus = qpci_new_pc(qts, NULL);
-    g_assert(pcibus != NULL);
-
-    pcidev = qpci_device_find(pcibus, 0);
-    g_assert(pcidev != NULL);
-
-    /* check open is settable */
-    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, false);
-    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
-    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
-    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == true);
-
-    /* lock, check open is cleared & not settable */
-    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_LCK, true);
-    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
-    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
-    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
-
-    /* reset */
-    response = qtest_qmp(qts, "{'execute': 'system_reset', 'arguments': {} }");
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-
-    /* check open is settable again */
-    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, false);
-    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
-    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
-    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == true);
-
-    g_free(pcidev);
-    qpci_free_pc(pcibus);
-
-    qtest_quit(qts);
-}
-
-static void test_tseg_size(const void *data)
-{
-    const TsegSizeArgs *args = data;
-    QPCIBus *pcibus;
-    QPCIDevice *pcidev;
-    uint8_t smram_val;
-    uint8_t esmramc_val;
-    uint32_t ram_offs;
-    QTestState *qts;
-
-    if (args->esmramc_tseg_sz == MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK) {
-        qts = qtest_initf("-M q35 -m %uM -global mch.extended-tseg-mbytes=%u",
-                          TSEG_SIZE_TEST_GUEST_RAM_MBYTES,
-                          args->extended_tseg_mbytes);
-    } else {
-        qts = qtest_initf("-M q35 -m %uM", TSEG_SIZE_TEST_GUEST_RAM_MBYTES);
-    }
-
-    /* locate the DRAM controller */
-    pcibus = qpci_new_pc(qts, NULL);
-    g_assert(pcibus != NULL);
-    pcidev = qpci_device_find(pcibus, 0);
-    g_assert(pcidev != NULL);
-
-    /* Set TSEG size. Restrict TSEG visibility to SMM by setting T_EN. */
-    esmramc_val = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_ESMRAMC);
-    esmramc_val &= ~MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK;
-    esmramc_val |= args->esmramc_tseg_sz;
-    esmramc_val |= MCH_HOST_BRIDGE_ESMRAMC_T_EN;
-    qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_ESMRAMC, esmramc_val);
-
-    /* Enable TSEG by setting G_SMRAME. Close TSEG by setting D_CLS. */
-    smram_val = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM);
-    smram_val &= ~(MCH_HOST_BRIDGE_SMRAM_D_OPEN |
-                   MCH_HOST_BRIDGE_SMRAM_D_LCK);
-    smram_val |= (MCH_HOST_BRIDGE_SMRAM_D_CLS |
-                  MCH_HOST_BRIDGE_SMRAM_G_SMRAME);
-    qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram_val);
-
-    /* lock TSEG */
-    smram_val |= MCH_HOST_BRIDGE_SMRAM_D_LCK;
-    qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram_val);
-
-    /* Now check that the byte right before the TSEG is r/w, and that the first
-     * byte in the TSEG always reads as 0xff.
-     */
-    ram_offs = (TSEG_SIZE_TEST_GUEST_RAM_MBYTES - args->expected_tseg_mbytes) *
-               1024 * 1024 - 1;
-    g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 0);
-    qtest_writeb(qts, ram_offs, 1);
-    g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 1);
-
-    ram_offs++;
-    g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 0xff);
-    qtest_writeb(qts, ram_offs, 1);
-    g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 0xff);
-
-    g_free(pcidev);
-    qpci_free_pc(pcibus);
-    qtest_quit(qts);
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("/q35/smram/lock", test_smram_lock);
-
-    qtest_add_data_func("/q35/tseg-size/1mb", &tseg_1mb, test_tseg_size);
-    qtest_add_data_func("/q35/tseg-size/2mb", &tseg_2mb, test_tseg_size);
-    qtest_add_data_func("/q35/tseg-size/8mb", &tseg_8mb, test_tseg_size);
-    qtest_add_data_func("/q35/tseg-size/ext/16mb", &tseg_ext_16mb,
-                        test_tseg_size);
-    return g_test_run();
-}
diff --git a/tests/qmp-cmd-test.c b/tests/qmp-cmd-test.c
deleted file mode 100644 (file)
index 9f5228c..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * QMP command test cases
- *
- * Copyright (c) 2017 Red Hat Inc.
- *
- * Authors:
- *  Markus Armbruster <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qapi/error.h"
-#include "qapi/qapi-visit-introspect.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qobject-input-visitor.h"
-
-const char common_args[] = "-nodefaults -machine none";
-
-/* Query smoke tests */
-
-static int query_error_class(const char *cmd)
-{
-    static struct {
-        const char *cmd;
-        int err_class;
-    } fails[] = {
-        /* Success depends on build configuration: */
-#ifndef CONFIG_SPICE
-        { "query-spice", ERROR_CLASS_COMMAND_NOT_FOUND },
-#endif
-#ifndef CONFIG_VNC
-        { "query-vnc", ERROR_CLASS_GENERIC_ERROR },
-        { "query-vnc-servers", ERROR_CLASS_GENERIC_ERROR },
-#endif
-#ifndef CONFIG_REPLICATION
-        { "query-xen-replication-status", ERROR_CLASS_COMMAND_NOT_FOUND },
-#endif
-        /* Likewise, and require special QEMU command-line arguments: */
-        { "query-acpi-ospm-status", ERROR_CLASS_GENERIC_ERROR },
-        { "query-balloon", ERROR_CLASS_DEVICE_NOT_ACTIVE },
-        { "query-hotpluggable-cpus", ERROR_CLASS_GENERIC_ERROR },
-        { "query-vm-generation-id", ERROR_CLASS_GENERIC_ERROR },
-        { NULL, -1 }
-    };
-    int i;
-
-    for (i = 0; fails[i].cmd; i++) {
-        if (!strcmp(cmd, fails[i].cmd)) {
-            return fails[i].err_class;
-        }
-    }
-    return -1;
-}
-
-static void test_query(const void *data)
-{
-    const char *cmd = data;
-    int expected_error_class = query_error_class(cmd);
-    QDict *resp, *error;
-    const char *error_class;
-    QTestState *qts;
-
-    qts = qtest_init(common_args);
-
-    resp = qtest_qmp(qts, "{ 'execute': %s }", cmd);
-    error = qdict_get_qdict(resp, "error");
-    error_class = error ? qdict_get_str(error, "class") : NULL;
-
-    if (expected_error_class < 0) {
-        g_assert(qdict_haskey(resp, "return"));
-    } else {
-        g_assert(error);
-        g_assert_cmpint(qapi_enum_parse(&QapiErrorClass_lookup, error_class,
-                                        -1, &error_abort),
-                        ==, expected_error_class);
-    }
-    qobject_unref(resp);
-
-    qtest_quit(qts);
-}
-
-static bool query_is_blacklisted(const char *cmd)
-{
-    const char *blacklist[] = {
-        /* Not actually queries: */
-        "add-fd",
-        /* Success depends on target arch: */
-        "query-cpu-definitions",  /* arm, i386, ppc, s390x */
-        "query-gic-capabilities", /* arm */
-        /* Success depends on target-specific build configuration: */
-        "query-pci",              /* CONFIG_PCI */
-        /* Success depends on launching SEV guest */
-        "query-sev-launch-measure",
-        /* Success depends on Host or Hypervisor SEV support */
-        "query-sev",
-        "query-sev-capabilities",
-        NULL
-    };
-    int i;
-
-    for (i = 0; blacklist[i]; i++) {
-        if (!strcmp(cmd, blacklist[i])) {
-            return true;
-        }
-    }
-    return false;
-}
-
-typedef struct {
-    SchemaInfoList *list;
-    GHashTable *hash;
-} QmpSchema;
-
-static void qmp_schema_init(QmpSchema *schema)
-{
-    QDict *resp;
-    Visitor *qiv;
-    SchemaInfoList *tail;
-    QTestState *qts;
-
-    qts = qtest_init(common_args);
-
-    resp = qtest_qmp(qts, "{ 'execute': 'query-qmp-schema' }");
-
-    qiv = qobject_input_visitor_new(qdict_get(resp, "return"));
-    visit_type_SchemaInfoList(qiv, NULL, &schema->list, &error_abort);
-    visit_free(qiv);
-
-    qobject_unref(resp);
-    qtest_quit(qts);
-
-    schema->hash = g_hash_table_new(g_str_hash, g_str_equal);
-
-    /* Build @schema: hash table mapping entity name to SchemaInfo */
-    for (tail = schema->list; tail; tail = tail->next) {
-        g_hash_table_insert(schema->hash, tail->value->name, tail->value);
-    }
-}
-
-static SchemaInfo *qmp_schema_lookup(QmpSchema *schema, const char *name)
-{
-    return g_hash_table_lookup(schema->hash, name);
-}
-
-static void qmp_schema_cleanup(QmpSchema *schema)
-{
-    qapi_free_SchemaInfoList(schema->list);
-    g_hash_table_destroy(schema->hash);
-}
-
-static bool object_type_has_mandatory_members(SchemaInfo *type)
-{
-    SchemaInfoObjectMemberList *tail;
-
-    g_assert(type->meta_type == SCHEMA_META_TYPE_OBJECT);
-
-    for (tail = type->u.object.members; tail; tail = tail->next) {
-        if (!tail->value->has_q_default) {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-static void add_query_tests(QmpSchema *schema)
-{
-    SchemaInfoList *tail;
-    SchemaInfo *si, *arg_type, *ret_type;
-    char *test_name;
-
-    /* Test the query-like commands */
-    for (tail = schema->list; tail; tail = tail->next) {
-        si = tail->value;
-        if (si->meta_type != SCHEMA_META_TYPE_COMMAND) {
-            continue;
-        }
-
-        if (query_is_blacklisted(si->name)) {
-            continue;
-        }
-
-        arg_type = qmp_schema_lookup(schema, si->u.command.arg_type);
-        if (object_type_has_mandatory_members(arg_type)) {
-            continue;
-        }
-
-        ret_type = qmp_schema_lookup(schema, si->u.command.ret_type);
-        if (ret_type->meta_type == SCHEMA_META_TYPE_OBJECT
-            && !ret_type->u.object.members) {
-            continue;
-        }
-
-        test_name = g_strdup_printf("qmp/%s", si->name);
-        qtest_add_data_func(test_name, si->name, test_query);
-        g_free(test_name);
-    }
-}
-
-static void test_object_add_without_props(void)
-{
-    QTestState *qts;
-    QDict *resp;
-
-    qts = qtest_init(common_args);
-    resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':"
-                    " {'qom-type': 'memory-backend-ram', 'id': 'ram1' } }");
-    g_assert_nonnull(resp);
-    qmp_assert_error_class(resp, "GenericError");
-    qtest_quit(qts);
-}
-
-int main(int argc, char *argv[])
-{
-    QmpSchema schema;
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-
-    qmp_schema_init(&schema);
-    add_query_tests(&schema);
-
-    qtest_add_func("qmp/object-add-without-props",
-                   test_object_add_without_props);
-    /* TODO: add coverage of generic object-add failure modes */
-
-    ret = g_test_run();
-
-    qmp_schema_cleanup(&schema);
-    return ret;
-}
diff --git a/tests/qmp-test.c b/tests/qmp-test.c
deleted file mode 100644 (file)
index 1b0eb69..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * QMP protocol test cases
- *
- * Copyright (c) 2017-2018 Red Hat Inc.
- *
- * Authors:
- *  Markus Armbruster <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qapi/error.h"
-#include "qapi/qapi-visit-misc.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qobject-input-visitor.h"
-#include "qapi/qmp/qstring.h"
-
-const char common_args[] = "-nodefaults -machine none";
-
-static void test_version(QObject *version)
-{
-    Visitor *v;
-    VersionInfo *vinfo;
-
-    g_assert(version);
-    v = qobject_input_visitor_new(version);
-    visit_type_VersionInfo(v, "version", &vinfo, &error_abort);
-    qapi_free_VersionInfo(vinfo);
-    visit_free(v);
-}
-
-static void assert_recovered(QTestState *qts)
-{
-    QDict *resp;
-
-    resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd' }");
-    qmp_assert_error_class(resp, "CommandNotFound");
-}
-
-static void test_malformed(QTestState *qts)
-{
-    QDict *resp;
-
-    /* syntax error */
-    qtest_qmp_send_raw(qts, "{]\n");
-    resp = qtest_qmp_receive(qts);
-    qmp_assert_error_class(resp, "GenericError");
-    assert_recovered(qts);
-
-    /* lexical error: impossible byte outside string */
-    qtest_qmp_send_raw(qts, "{\xFF");
-    resp = qtest_qmp_receive(qts);
-    qmp_assert_error_class(resp, "GenericError");
-    assert_recovered(qts);
-
-    /* lexical error: funny control character outside string */
-    qtest_qmp_send_raw(qts, "{\x01");
-    resp = qtest_qmp_receive(qts);
-    qmp_assert_error_class(resp, "GenericError");
-    assert_recovered(qts);
-
-    /* lexical error: impossible byte in string */
-    qtest_qmp_send_raw(qts, "{'bad \xFF");
-    resp = qtest_qmp_receive(qts);
-    qmp_assert_error_class(resp, "GenericError");
-    assert_recovered(qts);
-
-    /* lexical error: control character in string */
-    qtest_qmp_send_raw(qts, "{'execute': 'nonexistent', 'id':'\n");
-    resp = qtest_qmp_receive(qts);
-    qmp_assert_error_class(resp, "GenericError");
-    assert_recovered(qts);
-
-    /* lexical error: interpolation */
-    qtest_qmp_send_raw(qts, "%%p");
-    resp = qtest_qmp_receive(qts);
-    qmp_assert_error_class(resp, "GenericError");
-    assert_recovered(qts);
-
-    /* Not even a dictionary */
-    resp = qtest_qmp(qts, "null");
-    qmp_assert_error_class(resp, "GenericError");
-
-    /* No "execute" key */
-    resp = qtest_qmp(qts, "{}");
-    qmp_assert_error_class(resp, "GenericError");
-
-    /* "execute" isn't a string */
-    resp = qtest_qmp(qts, "{ 'execute': true }");
-    qmp_assert_error_class(resp, "GenericError");
-
-    /* "arguments" isn't a dictionary */
-    resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'arguments': [] }");
-    qmp_assert_error_class(resp, "GenericError");
-
-    /* extra key */
-    resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'extra': true }");
-    qmp_assert_error_class(resp, "GenericError");
-}
-
-static void test_qmp_protocol(void)
-{
-    QDict *resp, *q, *ret;
-    QList *capabilities;
-    QTestState *qts;
-
-    qts = qtest_init_without_qmp_handshake(common_args);
-
-    /* Test greeting */
-    resp = qtest_qmp_receive(qts);
-    q = qdict_get_qdict(resp, "QMP");
-    g_assert(q);
-    test_version(qdict_get(q, "version"));
-    capabilities = qdict_get_qlist(q, "capabilities");
-    g_assert(capabilities);
-    qobject_unref(resp);
-
-    /* Test valid command before handshake */
-    resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
-    qmp_assert_error_class(resp, "CommandNotFound");
-
-    /* Test malformed commands before handshake */
-    test_malformed(qts);
-
-    /* Test handshake */
-    resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
-    ret = qdict_get_qdict(resp, "return");
-    g_assert(ret && !qdict_size(ret));
-    qobject_unref(resp);
-
-    /* Test repeated handshake */
-    resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
-    qmp_assert_error_class(resp, "CommandNotFound");
-
-    /* Test valid command */
-    resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
-    test_version(qdict_get(resp, "return"));
-    qobject_unref(resp);
-
-    /* Test malformed commands */
-    test_malformed(qts);
-
-    /* Test 'id' */
-    resp = qtest_qmp(qts, "{ 'execute': 'query-name', 'id': 'cookie#1' }");
-    ret = qdict_get_qdict(resp, "return");
-    g_assert(ret);
-    g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1");
-    qobject_unref(resp);
-
-    /* Test command failure with 'id' */
-    resp = qtest_qmp(qts, "{ 'execute': 'human-monitor-command', 'id': 2 }");
-    g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2);
-    qmp_assert_error_class(resp, "GenericError");
-
-    qtest_quit(qts);
-}
-
-/* Out-of-band tests */
-
-char tmpdir[] = "/tmp/qmp-test-XXXXXX";
-char *fifo_name;
-
-static void setup_blocking_cmd(void)
-{
-    if (!mkdtemp(tmpdir)) {
-        g_error("mkdtemp: %s", strerror(errno));
-    }
-    fifo_name = g_strdup_printf("%s/fifo", tmpdir);
-    if (mkfifo(fifo_name, 0666)) {
-        g_error("mkfifo: %s", strerror(errno));
-    }
-}
-
-static void cleanup_blocking_cmd(void)
-{
-    unlink(fifo_name);
-    rmdir(tmpdir);
-}
-
-static void send_cmd_that_blocks(QTestState *s, const char *id)
-{
-    qtest_qmp_send(s, "{ 'execute': 'blockdev-add',  'id': %s,"
-                   " 'arguments': {"
-                   " 'driver': 'blkdebug', 'node-name': %s,"
-                   " 'config': %s,"
-                   " 'image': { 'driver': 'null-co', 'read-zeroes': true } } }",
-                   id, id, fifo_name);
-}
-
-static void unblock_blocked_cmd(void)
-{
-    int fd = open(fifo_name, O_WRONLY);
-    g_assert(fd >= 0);
-    close(fd);
-}
-
-static void send_oob_cmd_that_fails(QTestState *s, const char *id)
-{
-    qtest_qmp_send(s, "{ 'exec-oob': 'migrate-pause', 'id': %s }", id);
-}
-
-static void recv_cmd_id(QTestState *s, const char *id)
-{
-    QDict *resp = qtest_qmp_receive(s);
-
-    g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, id);
-    qobject_unref(resp);
-}
-
-static void test_qmp_oob(void)
-{
-    QTestState *qts;
-    QDict *resp, *q;
-    const QListEntry *entry;
-    QList *capabilities;
-    QString *qstr;
-
-    qts = qtest_init_without_qmp_handshake(common_args);
-
-    /* Check the greeting message. */
-    resp = qtest_qmp_receive(qts);
-    q = qdict_get_qdict(resp, "QMP");
-    g_assert(q);
-    capabilities = qdict_get_qlist(q, "capabilities");
-    g_assert(capabilities && !qlist_empty(capabilities));
-    entry = qlist_first(capabilities);
-    g_assert(entry);
-    qstr = qobject_to(QString, entry->value);
-    g_assert(qstr);
-    g_assert_cmpstr(qstring_get_str(qstr), ==, "oob");
-    qobject_unref(resp);
-
-    /* Try a fake capability, it should fail. */
-    resp = qtest_qmp(qts,
-                     "{ 'execute': 'qmp_capabilities', "
-                     "  'arguments': { 'enable': [ 'cap-does-not-exist' ] } }");
-    g_assert(qdict_haskey(resp, "error"));
-    qobject_unref(resp);
-
-    /* Now, enable OOB in current QMP session, it should succeed. */
-    resp = qtest_qmp(qts,
-                     "{ 'execute': 'qmp_capabilities', "
-                     "  'arguments': { 'enable': [ 'oob' ] } }");
-    g_assert(qdict_haskey(resp, "return"));
-    qobject_unref(resp);
-
-    /*
-     * Try any command that does not support OOB but with OOB flag. We
-     * should get failure.
-     */
-    resp = qtest_qmp(qts, "{ 'exec-oob': 'query-cpus' }");
-    g_assert(qdict_haskey(resp, "error"));
-    qobject_unref(resp);
-
-    /* OOB command overtakes slow in-band command */
-    setup_blocking_cmd();
-    send_cmd_that_blocks(qts, "ib-blocks-1");
-    qtest_qmp_send(qts, "{ 'execute': 'query-name', 'id': 'ib-quick-1' }");
-    send_oob_cmd_that_fails(qts, "oob-1");
-    recv_cmd_id(qts, "oob-1");
-    unblock_blocked_cmd();
-    recv_cmd_id(qts, "ib-blocks-1");
-    recv_cmd_id(qts, "ib-quick-1");
-
-    /* Even malformed in-band command fails in-band */
-    send_cmd_that_blocks(qts, "blocks-2");
-    qtest_qmp_send(qts, "{ 'id': 'err-2' }");
-    unblock_blocked_cmd();
-    recv_cmd_id(qts, "blocks-2");
-    recv_cmd_id(qts, "err-2");
-    cleanup_blocking_cmd();
-
-    qtest_quit(qts);
-}
-
-/* Preconfig tests */
-
-static void test_qmp_preconfig(void)
-{
-    QDict *rsp, *ret;
-    QTestState *qs = qtest_initf("%s --preconfig", common_args);
-
-    /* preconfig state */
-    /* enabled commands, no error expected  */
-    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-commands' }")));
-
-    /* forbidden commands, expected error */
-    g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
-
-    /* check that query-status returns preconfig state */
-    rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
-    ret = qdict_get_qdict(rsp, "return");
-    g_assert(ret);
-    g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "preconfig");
-    qobject_unref(rsp);
-
-    /* exit preconfig state */
-    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
-    qtest_qmp_eventwait(qs, "RESUME");
-
-    /* check that query-status returns running state */
-    rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
-    ret = qdict_get_qdict(rsp, "return");
-    g_assert(ret);
-    g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "running");
-    qobject_unref(rsp);
-
-    /* check that x-exit-preconfig returns error after exiting preconfig */
-    g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
-
-    /* enabled commands, no error expected  */
-    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
-
-    qtest_quit(qs);
-}
-
-static void test_qmp_missing_any_arg(void)
-{
-    QTestState *qts;
-    QDict *resp;
-
-    qts = qtest_init(common_args);
-    resp = qtest_qmp(qts, "{'execute': 'qom-set', 'arguments':"
-                     " { 'path': '/machine', 'property': 'rtc-time' } }");
-    g_assert_nonnull(resp);
-    qmp_assert_error_class(resp, "GenericError");
-    qtest_quit(qts);
-}
-
-int main(int argc, char *argv[])
-{
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("qmp/protocol", test_qmp_protocol);
-    qtest_add_func("qmp/oob", test_qmp_oob);
-    qtest_add_func("qmp/preconfig", test_qmp_preconfig);
-    qtest_add_func("qmp/missing-any-arg", test_qmp_missing_any_arg);
-
-    return g_test_run();
-}
diff --git a/tests/qom-test.c b/tests/qom-test.c
deleted file mode 100644 (file)
index 4f94cc6..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * QTest testcase for QOM
- *
- * Copyright (c) 2013 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-
-#include "qemu-common.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
-#include "qemu/cutils.h"
-#include "libqtest.h"
-
-static const char *blacklist_x86[] = {
-    "xenfv", "xenpv", NULL
-};
-
-static const struct {
-    const char *arch;
-    const char **machine;
-} blacklists[] = {
-    { "i386", blacklist_x86 },
-    { "x86_64", blacklist_x86 },
-};
-
-static bool is_blacklisted(const char *arch, const char *mach)
-{
-    int i;
-    const char **p;
-
-    for (i = 0; i < ARRAY_SIZE(blacklists); i++) {
-        if (!strcmp(blacklists[i].arch, arch)) {
-            for (p = blacklists[i].machine; *p; p++) {
-                if (!strcmp(*p, mach)) {
-                    return true;
-                }
-            }
-        }
-    }
-    return false;
-}
-
-static void test_properties(QTestState *qts, const char *path, bool recurse)
-{
-    char *child_path;
-    QDict *response, *tuple, *tmp;
-    QList *list;
-    QListEntry *entry;
-
-    g_test_message("Obtaining properties of %s", path);
-    response = qtest_qmp(qts, "{ 'execute': 'qom-list',"
-                              "  'arguments': { 'path': %s } }", path);
-    g_assert(response);
-
-    if (!recurse) {
-        qobject_unref(response);
-        return;
-    }
-
-    g_assert(qdict_haskey(response, "return"));
-    list = qobject_to(QList, qdict_get(response, "return"));
-    QLIST_FOREACH_ENTRY(list, entry) {
-        tuple = qobject_to(QDict, qlist_entry_obj(entry));
-        bool is_child = strstart(qdict_get_str(tuple, "type"), "child<", NULL);
-        bool is_link = strstart(qdict_get_str(tuple, "type"), "link<", NULL);
-
-        if (is_child || is_link) {
-            child_path = g_strdup_printf("%s/%s",
-                                         path, qdict_get_str(tuple, "name"));
-            test_properties(qts, child_path, is_child);
-            g_free(child_path);
-        } else {
-            const char *prop = qdict_get_str(tuple, "name");
-            g_test_message("Testing property %s.%s", path, prop);
-            tmp = qtest_qmp(qts,
-                            "{ 'execute': 'qom-get',"
-                            "  'arguments': { 'path': %s, 'property': %s } }",
-                            path, prop);
-            /* qom-get may fail but should not, e.g., segfault. */
-            g_assert(tmp);
-            qobject_unref(tmp);
-        }
-    }
-    qobject_unref(response);
-}
-
-static void test_machine(gconstpointer data)
-{
-    const char *machine = data;
-    QDict *response;
-    QTestState *qts;
-
-    qts = qtest_initf("-machine %s", machine);
-
-    test_properties(qts, "/machine", true);
-
-    response = qtest_qmp(qts, "{ 'execute': 'quit' }");
-    g_assert(qdict_haskey(response, "return"));
-    qobject_unref(response);
-
-    qtest_quit(qts);
-    g_free((void *)machine);
-}
-
-static void add_machine_test_case(const char *mname)
-{
-    const char *arch = qtest_get_arch();
-
-    if (!is_blacklisted(arch, mname)) {
-        char *path = g_strdup_printf("qom/%s", mname);
-        qtest_add_data_func(path, g_strdup(mname), test_machine);
-        g_free(path);
-    }
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_cb_for_every_machine(add_machine_test_case, g_test_quick());
-
-    return g_test_run();
-}
diff --git a/tests/qos-test.c b/tests/qos-test.c
deleted file mode 100644 (file)
index fd70d73..0000000
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * libqos driver framework
- *
- * Copyright (c) 2018 Emanuele Giuseppe Esposito <[email protected]>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-
-#include "qemu/osdep.h"
-#include <getopt.h>
-#include "libqtest-single.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qbool.h"
-#include "qapi/qmp/qstring.h"
-#include "qemu/module.h"
-#include "qapi/qmp/qlist.h"
-#include "libqos/malloc.h"
-#include "libqos/qgraph.h"
-#include "libqos/qgraph_internal.h"
-
-static char *old_path;
-
-static void apply_to_node(const char *name, bool is_machine, bool is_abstract)
-{
-    char *machine_name = NULL;
-    if (is_machine) {
-        const char *arch = qtest_get_arch();
-        machine_name = g_strconcat(arch, "/", name, NULL);
-        name = machine_name;
-    }
-    qos_graph_node_set_availability(name, true);
-    if (is_abstract) {
-        qos_delete_cmd_line(name);
-    }
-    g_free(machine_name);
-}
-
-/**
- * apply_to_qlist(): using QMP queries QEMU for a list of
- * machines and devices available, and sets the respective node
- * as true. If a node is found, also all its produced and contained
- * child are marked available.
- *
- * See qos_graph_node_set_availability() for more info
- */
-static void apply_to_qlist(QList *list, bool is_machine)
-{
-    const QListEntry *p;
-    const char *name;
-    bool abstract;
-    QDict *minfo;
-    QObject *qobj;
-    QString *qstr;
-    QBool *qbool;
-
-    for (p = qlist_first(list); p; p = qlist_next(p)) {
-        minfo = qobject_to(QDict, qlist_entry_obj(p));
-        qobj = qdict_get(minfo, "name");
-        qstr = qobject_to(QString, qobj);
-        name = qstring_get_str(qstr);
-
-        qobj = qdict_get(minfo, "abstract");
-        if (qobj) {
-            qbool = qobject_to(QBool, qobj);
-            abstract = qbool_get_bool(qbool);
-        } else {
-            abstract = false;
-        }
-
-        apply_to_node(name, is_machine, abstract);
-        qobj = qdict_get(minfo, "alias");
-        if (qobj) {
-            qstr = qobject_to(QString, qobj);
-            name = qstring_get_str(qstr);
-            apply_to_node(name, is_machine, abstract);
-        }
-    }
-}
-
-/**
- * qos_set_machines_devices_available(): sets availability of qgraph
- * machines and devices.
- *
- * This function firstly starts QEMU with "-machine none" option,
- * and then executes the QMP protocol asking for the list of devices
- * and machines available.
- *
- * for each of these items, it looks up the corresponding qgraph node,
- * setting it as available. The list currently returns all devices that
- * are either machines or QEDGE_CONSUMED_BY other nodes.
- * Therefore, in order to mark all other nodes, it recursively sets
- * all its QEDGE_CONTAINS and QEDGE_PRODUCES child as available too.
- */
-static void qos_set_machines_devices_available(void)
-{
-    QDict *response;
-    QDict *args = qdict_new();
-    QList *list;
-
-    qtest_start("-machine none");
-    response = qmp("{ 'execute': 'query-machines' }");
-    list = qdict_get_qlist(response, "return");
-
-    apply_to_qlist(list, true);
-
-    qobject_unref(response);
-
-    qdict_put_bool(args, "abstract", true);
-    qdict_put_str(args, "implements", "device");
-
-    response = qmp("{'execute': 'qom-list-types',"
-                   " 'arguments': %p }", args);
-    g_assert(qdict_haskey(response, "return"));
-    list = qdict_get_qlist(response, "return");
-
-    apply_to_qlist(list, false);
-
-    qtest_end();
-    qobject_unref(response);
-}
-
-static QGuestAllocator *get_machine_allocator(QOSGraphObject *obj)
-{
-    return obj->get_driver(obj, "memory");
-}
-
-static void restart_qemu_or_continue(char *path)
-{
-    /* compares the current command line with the
-     * one previously executed: if they are the same,
-     * don't restart QEMU, if they differ, stop previous
-     * QEMU subprocess (if active) and start over with
-     * the new command line
-     */
-    if (g_strcmp0(old_path, path)) {
-        qtest_end();
-        qos_invalidate_command_line();
-        old_path = g_strdup(path);
-        qtest_start(path);
-    } else { /* if cmd line is the same, reset the guest */
-        qobject_unref(qmp("{ 'execute': 'system_reset' }"));
-        qmp_eventwait("RESET");
-    }
-}
-
-void qos_invalidate_command_line(void)
-{
-    g_free(old_path);
-    old_path = NULL;
-}
-
-/**
- * allocate_objects(): given an array of nodes @arg,
- * walks the path invoking all constructors and
- * passing the corresponding parameter in order to
- * continue the objects allocation.
- * Once the test is reached, return the object it consumes.
- *
- * Since the machine and QEDGE_CONSUMED_BY nodes allocate
- * memory in the constructor, g_test_queue_destroy is used so
- * that after execution they can be safely free'd.  (The test's
- * ->before callback is also welcome to use g_test_queue_destroy).
- *
- * Note: as specified in walk_path() too, @arg is an array of
- * char *, where arg[0] is a pointer to the command line
- * string that will be used to properly start QEMU when executing
- * the test, and the remaining elements represent the actual objects
- * that will be allocated.
- */
-static void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc)
-{
-    int current = 0;
-    QGuestAllocator *alloc;
-    QOSGraphObject *parent = NULL;
-    QOSGraphEdge *edge;
-    QOSGraphNode *node;
-    void *edge_arg;
-    void *obj;
-
-    node = qos_graph_get_node(path[current]);
-    g_assert(node->type == QNODE_MACHINE);
-
-    obj = qos_machine_new(node, qts);
-    qos_object_queue_destroy(obj);
-
-    alloc = get_machine_allocator(obj);
-    if (p_alloc) {
-        *p_alloc = alloc;
-    }
-
-    for (;;) {
-        if (node->type != QNODE_INTERFACE) {
-            qos_object_start_hw(obj);
-            parent = obj;
-        }
-
-        /* follow edge and get object for next node constructor */
-        current++;
-        edge = qos_graph_get_edge(path[current - 1], path[current]);
-        node = qos_graph_get_node(path[current]);
-
-        if (node->type == QNODE_TEST) {
-            g_assert(qos_graph_edge_get_type(edge) == QEDGE_CONSUMED_BY);
-            return obj;
-        }
-
-        switch (qos_graph_edge_get_type(edge)) {
-        case QEDGE_PRODUCES:
-            obj = parent->get_driver(parent, path[current]);
-            break;
-
-        case QEDGE_CONSUMED_BY:
-            edge_arg = qos_graph_edge_get_arg(edge);
-            obj = qos_driver_new(node, obj, alloc, edge_arg);
-            qos_object_queue_destroy(obj);
-            break;
-
-        case QEDGE_CONTAINS:
-            obj = parent->get_device(parent, path[current]);
-            break;
-        }
-    }
-}
-
-/* The argument to run_one_test, which is the test function that is registered
- * with GTest, is a vector of strings.  The first item is the initial command
- * line (before it is modified by the test's "before" function), the remaining
- * items are node names forming the path to the test node.
- */
-static char **current_path;
-
-const char *qos_get_current_command_line(void)
-{
-    return current_path[0];
-}
-
-void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc)
-{
-    return allocate_objects(qts, current_path + 1, p_alloc);
-}
-
-/**
- * run_one_test(): given an array of nodes @arg,
- * walks the path invoking all constructors and
- * passing the corresponding parameter in order to
- * continue the objects allocation.
- * Once the test is reached, its function is executed.
- *
- * Since the machine and QEDGE_CONSUMED_BY nodes allocate
- * memory in the constructor, g_test_queue_destroy is used so
- * that after execution they can be safely free'd.  The test's
- * ->before callback is also welcome to use g_test_queue_destroy.
- *
- * Note: as specified in walk_path() too, @arg is an array of
- * char *, where arg[0] is a pointer to the command line
- * string that will be used to properly start QEMU when executing
- * the test, and the remaining elements represent the actual objects
- * that will be allocated.
- *
- * The order of execution is the following:
- * 1) @before test function as defined in the given QOSGraphTestOptions
- * 2) start QEMU
- * 3) call all nodes constructor and get_driver/get_device depending on edge,
- *    start the hardware (*_device_enable functions)
- * 4) start test
- */
-static void run_one_test(const void *arg)
-{
-    QOSGraphNode *test_node;
-    QGuestAllocator *alloc = NULL;
-    void *obj;
-    char **path = (char **) arg;
-    GString *cmd_line = g_string_new(path[0]);
-    void *test_arg;
-
-    /* Before test */
-    current_path = path;
-    test_node = qos_graph_get_node(path[(g_strv_length(path) - 1)]);
-    test_arg = test_node->u.test.arg;
-    if (test_node->u.test.before) {
-        test_arg = test_node->u.test.before(cmd_line, test_arg);
-    }
-
-    restart_qemu_or_continue(cmd_line->str);
-    g_string_free(cmd_line, true);
-
-    obj = qos_allocate_objects(global_qtest, &alloc);
-    test_node->u.test.function(obj, test_arg, alloc);
-}
-
-static void subprocess_run_one_test(const void *arg)
-{
-    const gchar *path = arg;
-    g_test_trap_subprocess(path, 0, 0);
-    g_test_trap_assert_passed();
-}
-
-/*
- * in this function, 2 path will be built:
- * path_str, a one-string path (ex "pc/i440FX-pcihost/...")
- * path_vec, a string-array path (ex [0] = "pc", [1] = "i440FX-pcihost").
- *
- * path_str will be only used to build the test name, and won't need the
- * architecture name at beginning, since it will be added by qtest_add_func().
- *
- * path_vec is used to allocate all constructors of the path nodes.
- * Each name in this array except position 0 must correspond to a valid
- * QOSGraphNode name.
- * Position 0 is special, initially contains just the <machine> name of
- * the node, (ex for "x86_64/pc" it will be "pc"), used to build the test
- * path (see below). After it will contain the command line used to start
- * qemu with all required devices.
- *
- * Note that the machine node name must be with format <arch>/<machine>
- * (ex "x86_64/pc"), because it will identify the node "x86_64/pc"
- * and start QEMU with "-M pc". For this reason,
- * when building path_str, path_vec
- * initially contains the <machine> at position 0 ("pc"),
- * and the node name at position 1 (<arch>/<machine>)
- * ("x86_64/pc"), followed by the rest of the nodes.
- */
-static void walk_path(QOSGraphNode *orig_path, int len)
-{
-    QOSGraphNode *path;
-    QOSGraphEdge *edge;
-
-    /* etype set to QEDGE_CONSUMED_BY so that machine can add to the command line */
-    QOSEdgeType etype = QEDGE_CONSUMED_BY;
-
-    /* twice QOS_PATH_MAX_ELEMENT_SIZE since each edge can have its arg */
-    char **path_vec = g_new0(char *, (QOS_PATH_MAX_ELEMENT_SIZE * 2));
-    int path_vec_size = 0;
-
-    char *after_cmd, *before_cmd, *after_device;
-    GString *after_device_str = g_string_new("");
-    char *node_name = orig_path->name, *path_str;
-
-    GString *cmd_line = g_string_new("");
-    GString *cmd_line2 = g_string_new("");
-
-    path = qos_graph_get_node(node_name); /* root */
-    node_name = qos_graph_edge_get_dest(path->path_edge); /* machine name */
-
-    path_vec[path_vec_size++] = node_name;
-    path_vec[path_vec_size++] = qos_get_machine_type(node_name);
-
-    for (;;) {
-        path = qos_graph_get_node(node_name);
-        if (!path->path_edge) {
-            break;
-        }
-
-        node_name = qos_graph_edge_get_dest(path->path_edge);
-
-        /* append node command line + previous edge command line */
-        if (path->command_line && etype == QEDGE_CONSUMED_BY) {
-            g_string_append(cmd_line, path->command_line);
-            g_string_append(cmd_line, after_device_str->str);
-            g_string_truncate(after_device_str, 0);
-        }
-
-        path_vec[path_vec_size++] = qos_graph_edge_get_name(path->path_edge);
-        /* detect if edge has command line args */
-        after_cmd = qos_graph_edge_get_after_cmd_line(path->path_edge);
-        after_device = qos_graph_edge_get_extra_device_opts(path->path_edge);
-        before_cmd = qos_graph_edge_get_before_cmd_line(path->path_edge);
-        edge = qos_graph_get_edge(path->name, node_name);
-        etype = qos_graph_edge_get_type(edge);
-
-        if (before_cmd) {
-            g_string_append(cmd_line, before_cmd);
-        }
-        if (after_cmd) {
-            g_string_append(cmd_line2, after_cmd);
-        }
-        if (after_device) {
-            g_string_append(after_device_str, after_device);
-        }
-    }
-
-    path_vec[path_vec_size++] = NULL;
-    g_string_append(cmd_line, after_device_str->str);
-    g_string_free(after_device_str, true);
-
-    g_string_append(cmd_line, cmd_line2->str);
-    g_string_free(cmd_line2, true);
-
-    /* here position 0 has <arch>/<machine>, position 1 has <machine>.
-     * The path must not have the <arch>, qtest_add_data_func adds it.
-     */
-    path_str = g_strjoinv("/", path_vec + 1);
-
-    /* put arch/machine in position 1 so run_one_test can do its work
-     * and add the command line at position 0.
-     */
-    path_vec[1] = path_vec[0];
-    path_vec[0] = g_string_free(cmd_line, false);
-
-    if (path->u.test.subprocess) {
-        gchar *subprocess_path = g_strdup_printf("/%s/%s/subprocess",
-                                                 qtest_get_arch(), path_str);
-        qtest_add_data_func(path_str, subprocess_path, subprocess_run_one_test);
-        g_test_add_data_func(subprocess_path, path_vec, run_one_test);
-    } else {
-        qtest_add_data_func(path_str, path_vec, run_one_test);
-    }
-
-    g_free(path_str);
-}
-
-
-
-/**
- * main(): heart of the qgraph framework.
- *
- * - Initializes the glib test framework
- * - Creates the graph by invoking the various _init constructors
- * - Starts QEMU to mark the available devices
- * - Walks the graph, and each path is added to
- *   the glib test framework (walk_path)
- * - Runs the tests, calling allocate_object() and allocating the
- *   machine/drivers/test objects
- * - Cleans up everything
- */
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-    qos_graph_init();
-    module_call_init(MODULE_INIT_QOM);
-    module_call_init(MODULE_INIT_LIBQOS);
-    qos_set_machines_devices_available();
-
-    qos_graph_foreach_test_path(walk_path);
-    g_test_run();
-    qtest_end();
-    qos_graph_destroy();
-    g_free(old_path);
-    return 0;
-}
diff --git a/tests/qtest/ac97-test.c b/tests/qtest/ac97-test.c
new file mode 100644 (file)
index 0000000..b084e31
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * QTest testcase for AC97
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
+
+typedef struct QAC97 QAC97;
+
+struct QAC97 {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *ac97_get_driver(void *obj, const char *interface)
+{
+    QAC97 *ac97 = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &ac97->dev;
+    }
+
+    fprintf(stderr, "%s not present in e1000e\n", interface);
+    g_assert_not_reached();
+}
+
+static void *ac97_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QAC97 *ac97 = g_new0(QAC97, 1);
+    QPCIBus *bus = pci_bus;
+
+    qpci_device_init(&ac97->dev, bus, addr);
+    ac97->obj.get_driver = ac97_get_driver;
+    return &ac97->obj;
+}
+
+static void ac97_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+
+    qos_node_create_driver("AC97", ac97_create);
+    qos_node_produces("AC97", "pci-device");
+    qos_node_consumes("AC97", "pci-bus", &opts);
+}
+
+libqos_init(ac97_register_nodes);
diff --git a/tests/qtest/acpi-utils.c b/tests/qtest/acpi-utils.c
new file mode 100644 (file)
index 0000000..d2a202e
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * ACPI Utility Functions
+ *
+ * Copyright (c) 2013 Red Hat Inc.
+ * Copyright (c) 2017 Skyport Systems
+ *
+ * Authors:
+ *  Michael S. Tsirkin <[email protected]>,
+ *  Ben Warren <[email protected]>
+ *
+ * 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 "qemu-common.h"
+#include "qemu/bitmap.h"
+#include "acpi-utils.h"
+#include "boot-sector.h"
+
+uint8_t acpi_calc_checksum(const uint8_t *data, int len)
+{
+    int i;
+    uint8_t sum = 0;
+
+    for (i = 0; i < len; i++) {
+        sum += data[i];
+    }
+
+    return sum;
+}
+
+uint32_t acpi_find_rsdp_address(QTestState *qts)
+{
+    uint32_t off;
+
+    /* RSDP location can vary across a narrow range */
+    for (off = 0xf0000; off < 0x100000; off += 0x10) {
+        uint8_t sig[] = "RSD PTR ";
+        int i;
+
+        for (i = 0; i < sizeof sig - 1; ++i) {
+            sig[i] = qtest_readb(qts, off + i);
+        }
+
+        if (!memcmp(sig, "RSD PTR ", sizeof sig)) {
+            break;
+        }
+    }
+    return off;
+}
+
+void acpi_fetch_rsdp_table(QTestState *qts, uint64_t addr, uint8_t *rsdp_table)
+{
+    uint8_t revision;
+
+    /* Read mandatory revision 0 table data (20 bytes) first */
+    qtest_memread(qts, addr, rsdp_table, 20);
+    revision = rsdp_table[15 /* Revision offset */];
+
+    switch (revision) {
+    case 0: /* ACPI 1.0 RSDP */
+        break;
+    case 2: /* ACPI 2.0+ RSDP */
+        /* Read the rest of the RSDP table */
+        qtest_memread(qts, addr + 20, rsdp_table + 20, 16);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    ACPI_ASSERT_CMP64(*((uint64_t *)(rsdp_table)), "RSD PTR ");
+}
+
+/** acpi_fetch_table
+ *  load ACPI table at @addr_ptr offset pointer into buffer and return it in
+ *  @aml, its length in @aml_len and check that signature/checksum matches
+ *  actual one.
+ */
+void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
+                      const uint8_t *addr_ptr, int addr_size, const char *sig,
+                      bool verify_checksum)
+{
+    uint32_t len;
+    uint64_t addr = 0;
+
+    g_assert(addr_size == 4 || addr_size == 8);
+    memcpy(&addr, addr_ptr , addr_size);
+    addr = le64_to_cpu(addr);
+    qtest_memread(qts, addr + 4, &len, 4); /* Length of ACPI table */
+    *aml_len = le32_to_cpu(len);
+    *aml = g_malloc0(*aml_len);
+    /* get whole table */
+    qtest_memread(qts, addr, *aml, *aml_len);
+
+    if (sig) {
+        ACPI_ASSERT_CMP(**aml, sig);
+    }
+    if (verify_checksum) {
+        g_assert(!acpi_calc_checksum(*aml, *aml_len));
+    }
+}
+
+#define GUID_SIZE 16
+static const uint8_t AcpiTestSupportGuid[GUID_SIZE] = {
+       0xb1, 0xa6, 0x87, 0xab,
+       0x34, 0x20,
+       0xa0, 0xbd,
+       0x71, 0xbd, 0x37, 0x50, 0x07, 0x75, 0x77, 0x85 };
+
+typedef struct {
+    uint8_t signature_guid[GUID_SIZE];
+    uint64_t rsdp10;
+    uint64_t rsdp20;
+} __attribute__((packed)) UefiTestSupport;
+
+/* Wait at most 600 seconds (test is slow with TCG and --enable-debug) */
+#define TEST_DELAY (1 * G_USEC_PER_SEC / 10)
+#define TEST_CYCLES MAX((600 * G_USEC_PER_SEC / TEST_DELAY), 1)
+#define MB 0x100000ULL
+uint64_t acpi_find_rsdp_address_uefi(QTestState *qts, uint64_t start,
+                                     uint64_t size)
+{
+    int i, j;
+    uint8_t data[GUID_SIZE];
+
+    for (i = 0; i < TEST_CYCLES; ++i) {
+        for (j = 0; j < size / MB; j++) {
+            /* look for GUID at every 1Mb block */
+            uint64_t addr = start + j * MB;
+
+            qtest_memread(qts, addr, data, sizeof(data));
+            if (!memcmp(AcpiTestSupportGuid, data, sizeof(data))) {
+                UefiTestSupport ret;
+
+                qtest_memread(qts, addr, &ret, sizeof(ret));
+                ret.rsdp10 = le64_to_cpu(ret.rsdp10);
+                ret.rsdp20 = le64_to_cpu(ret.rsdp20);
+                return ret.rsdp20 ? ret.rsdp20 : ret.rsdp10;
+            }
+        }
+        g_usleep(TEST_DELAY);
+    }
+    g_assert_not_reached();
+    return 0;
+}
diff --git a/tests/qtest/acpi-utils.h b/tests/qtest/acpi-utils.h
new file mode 100644 (file)
index 0000000..0c86780
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Utilities for working with ACPI tables
+ *
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * Authors:
+ *  Michael S. Tsirkin <[email protected]>,
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TEST_ACPI_UTILS_H
+#define TEST_ACPI_UTILS_H
+
+#include "libqtest.h"
+
+/* DSDT and SSDTs format */
+typedef struct {
+    uint8_t *aml;            /* aml bytecode from guest */
+    uint32_t aml_len;
+    gchar *aml_file;
+    gchar *asl;            /* asl code generated from aml */
+    gsize asl_len;
+    gchar *asl_file;
+    bool tmp_files_retain;   /* do not delete the temp asl/aml */
+} AcpiSdtTable;
+
+#define ACPI_ASSERT_CMP(actual, expected) do { \
+    char ACPI_ASSERT_CMP_str[5] = {}; \
+    memcpy(ACPI_ASSERT_CMP_str, &actual, 4); \
+    g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
+} while (0)
+
+#define ACPI_ASSERT_CMP64(actual, expected) do { \
+    char ACPI_ASSERT_CMP_str[9] = {}; \
+    memcpy(ACPI_ASSERT_CMP_str, &actual, 8); \
+    g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
+} while (0)
+
+
+#define ACPI_FOREACH_RSDT_ENTRY(table, table_len, entry_ptr, entry_size) \
+    for (entry_ptr = table + 36 /* 1st Entry */;                         \
+         entry_ptr < table + table_len;                                  \
+         entry_ptr += entry_size)
+
+uint8_t acpi_calc_checksum(const uint8_t *data, int len);
+uint32_t acpi_find_rsdp_address(QTestState *qts);
+uint64_t acpi_find_rsdp_address_uefi(QTestState *qts, uint64_t start,
+                                     uint64_t size);
+void acpi_fetch_rsdp_table(QTestState *qts, uint64_t addr, uint8_t *rsdp_table);
+void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
+                      const uint8_t *addr_ptr, int addr_size, const char *sig,
+                      bool verify_checksum);
+
+#endif /* TEST_ACPI_UTILS_H */
diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c
new file mode 100644 (file)
index 0000000..c8d42ce
--- /dev/null
@@ -0,0 +1,1954 @@
+/*
+ * AHCI test cases
+ *
+ * Copyright (c) 2014 John Snow <[email protected]>
+ *
+ * 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 <getopt.h>
+
+#include "libqtest.h"
+#include "libqos/libqos-pc.h"
+#include "libqos/ahci.h"
+#include "libqos/pci-pc.h"
+
+#include "qemu-common.h"
+#include "qapi/qmp/qdict.h"
+#include "qemu/host-utils.h"
+
+#include "hw/pci/pci_ids.h"
+#include "hw/pci/pci_regs.h"
+
+/* TODO actually test the results and get rid of this */
+#define qmp_discard_response(s, ...) qobject_unref(qtest_qmp(s, __VA_ARGS__))
+
+/* Test images sizes in MB */
+#define TEST_IMAGE_SIZE_MB_LARGE (200 * 1024)
+#define TEST_IMAGE_SIZE_MB_SMALL 64
+
+/*** Globals ***/
+static char tmp_path[] = "/tmp/qtest.XXXXXX";
+static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX";
+static char mig_socket[] = "/tmp/qtest-migration.XXXXXX";
+static bool ahci_pedantic;
+static const char *imgfmt;
+static unsigned test_image_size_mb;
+
+/*** Function Declarations ***/
+static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port);
+static void ahci_test_pci_spec(AHCIQState *ahci);
+static void ahci_test_pci_caps(AHCIQState *ahci, uint16_t header,
+                               uint8_t offset);
+static void ahci_test_satacap(AHCIQState *ahci, uint8_t offset);
+static void ahci_test_msicap(AHCIQState *ahci, uint8_t offset);
+static void ahci_test_pmcap(AHCIQState *ahci, uint8_t offset);
+
+/*** Utilities ***/
+
+static uint64_t mb_to_sectors(uint64_t image_size_mb)
+{
+    return (image_size_mb * 1024 * 1024) / AHCI_SECTOR_SIZE;
+}
+
+static void string_bswap16(uint16_t *s, size_t bytes)
+{
+    g_assert_cmphex((bytes & 1), ==, 0);
+    bytes /= 2;
+
+    while (bytes--) {
+        *s = bswap16(*s);
+        s++;
+    }
+}
+
+/**
+ * Verify that the transfer did not corrupt our state at all.
+ */
+static void verify_state(AHCIQState *ahci, uint64_t hba_old)
+{
+    int i, j;
+    uint32_t ahci_fingerprint;
+    uint64_t hba_base;
+    AHCICommandHeader cmd;
+
+    ahci_fingerprint = qpci_config_readl(ahci->dev, PCI_VENDOR_ID);
+    g_assert_cmphex(ahci_fingerprint, ==, ahci->fingerprint);
+
+    /* If we haven't initialized, this is as much as can be validated. */
+    if (!ahci->enabled) {
+        return;
+    }
+
+    hba_base = (uint64_t)qpci_config_readl(ahci->dev, PCI_BASE_ADDRESS_5);
+    g_assert_cmphex(hba_base, ==, hba_old);
+
+    g_assert_cmphex(ahci_rreg(ahci, AHCI_CAP), ==, ahci->cap);
+    g_assert_cmphex(ahci_rreg(ahci, AHCI_CAP2), ==, ahci->cap2);
+
+    for (i = 0; i < 32; i++) {
+        g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_FB), ==,
+                        ahci->port[i].fb);
+        g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_CLB), ==,
+                        ahci->port[i].clb);
+        for (j = 0; j < 32; j++) {
+            ahci_get_command_header(ahci, i, j, &cmd);
+            g_assert_cmphex(cmd.prdtl, ==, ahci->port[i].prdtl[j]);
+            g_assert_cmphex(cmd.ctba, ==, ahci->port[i].ctba[j]);
+        }
+    }
+}
+
+static void ahci_migrate(AHCIQState *from, AHCIQState *to, const char *uri)
+{
+    QOSState *tmp = to->parent;
+    QPCIDevice *dev = to->dev;
+    char *uri_local = NULL;
+    uint64_t hba_old;
+
+    if (uri == NULL) {
+        uri_local = g_strdup_printf("%s%s", "unix:", mig_socket);
+        uri = uri_local;
+    }
+
+    hba_old = (uint64_t)qpci_config_readl(from->dev, PCI_BASE_ADDRESS_5);
+
+    /* context will be 'to' after completion. */
+    migrate(from->parent, to->parent, uri);
+
+    /* We'd like for the AHCIState objects to still point
+     * to information specific to its specific parent
+     * instance, but otherwise just inherit the new data. */
+    memcpy(to, from, sizeof(AHCIQState));
+    to->parent = tmp;
+    to->dev = dev;
+
+    tmp = from->parent;
+    dev = from->dev;
+    memset(from, 0x00, sizeof(AHCIQState));
+    from->parent = tmp;
+    from->dev = dev;
+
+    verify_state(to, hba_old);
+    g_free(uri_local);
+}
+
+/*** Test Setup & Teardown ***/
+
+/**
+ * Start a Q35 machine and bookmark a handle to the AHCI device.
+ */
+static AHCIQState *ahci_vboot(const char *cli, va_list ap)
+{
+    AHCIQState *s;
+
+    s = g_new0(AHCIQState, 1);
+    s->parent = qtest_pc_vboot(cli, ap);
+    alloc_set_flags(&s->parent->alloc, ALLOC_LEAK_ASSERT);
+
+    /* Verify that we have an AHCI device present. */
+    s->dev = get_ahci_device(s->parent->qts, &s->fingerprint);
+
+    return s;
+}
+
+/**
+ * Start a Q35 machine and bookmark a handle to the AHCI device.
+ */
+static AHCIQState *ahci_boot(const char *cli, ...)
+{
+    AHCIQState *s;
+    va_list ap;
+
+    if (cli) {
+        va_start(ap, cli);
+        s = ahci_vboot(cli, ap);
+        va_end(ap);
+    } else {
+        cli = "-drive if=none,id=drive0,file=%s,cache=writeback,format=%s"
+            " -M q35 "
+            "-device ide-hd,drive=drive0 "
+            "-global ide-hd.serial=%s "
+            "-global ide-hd.ver=%s";
+        s = ahci_boot(cli, tmp_path, imgfmt, "testdisk", "version");
+    }
+
+    return s;
+}
+
+/**
+ * Clean up the PCI device, then terminate the QEMU instance.
+ */
+static void ahci_shutdown(AHCIQState *ahci)
+{
+    QOSState *qs = ahci->parent;
+
+    ahci_clean_mem(ahci);
+    free_ahci_device(ahci->dev);
+    g_free(ahci);
+    qtest_shutdown(qs);
+}
+
+/**
+ * Boot and fully enable the HBA device.
+ * @see ahci_boot, ahci_pci_enable and ahci_hba_enable.
+ */
+static AHCIQState *ahci_boot_and_enable(const char *cli, ...)
+{
+    AHCIQState *ahci;
+    va_list ap;
+    uint16_t buff[256];
+    uint8_t port;
+    uint8_t hello;
+
+    if (cli) {
+        va_start(ap, cli);
+        ahci = ahci_vboot(cli, ap);
+        va_end(ap);
+    } else {
+        ahci = ahci_boot(NULL);
+    }
+
+    ahci_pci_enable(ahci);
+    ahci_hba_enable(ahci);
+    /* Initialize test device */
+    port = ahci_port_select(ahci);
+    ahci_port_clear(ahci, port);
+    if (is_atapi(ahci, port)) {
+        hello = CMD_PACKET_ID;
+    } else {
+        hello = CMD_IDENTIFY;
+    }
+    ahci_io(ahci, port, hello, &buff, sizeof(buff), 0);
+
+    return ahci;
+}
+
+/*** Specification Adherence Tests ***/
+
+/**
+ * Implementation for test_pci_spec. Ensures PCI configuration space is sane.
+ */
+static void ahci_test_pci_spec(AHCIQState *ahci)
+{
+    uint8_t datab;
+    uint16_t data;
+    uint32_t datal;
+
+    /* Most of these bits should start cleared until we turn them on. */
+    data = qpci_config_readw(ahci->dev, PCI_COMMAND);
+    ASSERT_BIT_CLEAR(data, PCI_COMMAND_MEMORY);
+    ASSERT_BIT_CLEAR(data, PCI_COMMAND_MASTER);
+    ASSERT_BIT_CLEAR(data, PCI_COMMAND_SPECIAL);     /* Reserved */
+    ASSERT_BIT_CLEAR(data, PCI_COMMAND_VGA_PALETTE); /* Reserved */
+    ASSERT_BIT_CLEAR(data, PCI_COMMAND_PARITY);
+    ASSERT_BIT_CLEAR(data, PCI_COMMAND_WAIT);        /* Reserved */
+    ASSERT_BIT_CLEAR(data, PCI_COMMAND_SERR);
+    ASSERT_BIT_CLEAR(data, PCI_COMMAND_FAST_BACK);
+    ASSERT_BIT_CLEAR(data, PCI_COMMAND_INTX_DISABLE);
+    ASSERT_BIT_CLEAR(data, 0xF800);                  /* Reserved */
+
+    data = qpci_config_readw(ahci->dev, PCI_STATUS);
+    ASSERT_BIT_CLEAR(data, 0x01 | 0x02 | 0x04);     /* Reserved */
+    ASSERT_BIT_CLEAR(data, PCI_STATUS_INTERRUPT);
+    ASSERT_BIT_SET(data, PCI_STATUS_CAP_LIST);      /* must be set */
+    ASSERT_BIT_CLEAR(data, PCI_STATUS_UDF);         /* Reserved */
+    ASSERT_BIT_CLEAR(data, PCI_STATUS_PARITY);
+    ASSERT_BIT_CLEAR(data, PCI_STATUS_SIG_TARGET_ABORT);
+    ASSERT_BIT_CLEAR(data, PCI_STATUS_REC_TARGET_ABORT);
+    ASSERT_BIT_CLEAR(data, PCI_STATUS_REC_MASTER_ABORT);
+    ASSERT_BIT_CLEAR(data, PCI_STATUS_SIG_SYSTEM_ERROR);
+    ASSERT_BIT_CLEAR(data, PCI_STATUS_DETECTED_PARITY);
+
+    /* RID occupies the low byte, CCs occupy the high three. */
+    datal = qpci_config_readl(ahci->dev, PCI_CLASS_REVISION);
+    if (ahci_pedantic) {
+        /* AHCI 1.3 specifies that at-boot, the RID should reset to 0x00,
+         * Though in practice this is likely seldom true. */
+        ASSERT_BIT_CLEAR(datal, 0xFF);
+    }
+
+    /* BCC *must* equal 0x01. */
+    g_assert_cmphex(PCI_BCC(datal), ==, 0x01);
+    if (PCI_SCC(datal) == 0x01) {
+        /* IDE */
+        ASSERT_BIT_SET(0x80000000, datal);
+        ASSERT_BIT_CLEAR(0x60000000, datal);
+    } else if (PCI_SCC(datal) == 0x04) {
+        /* RAID */
+        g_assert_cmphex(PCI_PI(datal), ==, 0);
+    } else if (PCI_SCC(datal) == 0x06) {
+        /* AHCI */
+        g_assert_cmphex(PCI_PI(datal), ==, 0x01);
+    } else {
+        g_assert_not_reached();
+    }
+
+    datab = qpci_config_readb(ahci->dev, PCI_CACHE_LINE_SIZE);
+    g_assert_cmphex(datab, ==, 0);
+
+    datab = qpci_config_readb(ahci->dev, PCI_LATENCY_TIMER);
+    g_assert_cmphex(datab, ==, 0);
+
+    /* Only the bottom 7 bits must be off. */
+    datab = qpci_config_readb(ahci->dev, PCI_HEADER_TYPE);
+    ASSERT_BIT_CLEAR(datab, 0x7F);
+
+    /* BIST is optional, but the low 7 bits must always start off regardless. */
+    datab = qpci_config_readb(ahci->dev, PCI_BIST);
+    ASSERT_BIT_CLEAR(datab, 0x7F);
+
+    /* BARS 0-4 do not have a boot spec, but ABAR/BAR5 must be clean. */
+    datal = qpci_config_readl(ahci->dev, PCI_BASE_ADDRESS_5);
+    g_assert_cmphex(datal, ==, 0);
+
+    qpci_config_writel(ahci->dev, PCI_BASE_ADDRESS_5, 0xFFFFFFFF);
+    datal = qpci_config_readl(ahci->dev, PCI_BASE_ADDRESS_5);
+    /* ABAR must be 32-bit, memory mapped, non-prefetchable and
+     * must be >= 512 bytes. To that end, bits 0-8 must be off. */
+    ASSERT_BIT_CLEAR(datal, 0xFF);
+
+    /* Capability list MUST be present, */
+    datal = qpci_config_readl(ahci->dev, PCI_CAPABILITY_LIST);
+    /* But these bits are reserved. */
+    ASSERT_BIT_CLEAR(datal, ~0xFF);
+    g_assert_cmphex(datal, !=, 0);
+
+    /* Check specification adherence for capability extenstions. */
+    data = qpci_config_readw(ahci->dev, datal);
+
+    switch (ahci->fingerprint) {
+    case AHCI_INTEL_ICH9:
+        /* Intel ICH9 Family Datasheet 14.1.19 p.550 */
+        g_assert_cmphex((data & 0xFF), ==, PCI_CAP_ID_MSI);
+        break;
+    default:
+        /* AHCI 1.3, Section 2.1.14 -- CAP must point to PMCAP. */
+        g_assert_cmphex((data & 0xFF), ==, PCI_CAP_ID_PM);
+    }
+
+    ahci_test_pci_caps(ahci, data, (uint8_t)datal);
+
+    /* Reserved. */
+    datal = qpci_config_readl(ahci->dev, PCI_CAPABILITY_LIST + 4);
+    g_assert_cmphex(datal, ==, 0);
+
+    /* IPIN might vary, but ILINE must be off. */
+    datab = qpci_config_readb(ahci->dev, PCI_INTERRUPT_LINE);
+    g_assert_cmphex(datab, ==, 0);
+}
+
+/**
+ * Test PCI capabilities for AHCI specification adherence.
+ */
+static void ahci_test_pci_caps(AHCIQState *ahci, uint16_t header,
+                               uint8_t offset)
+{
+    uint8_t cid = header & 0xFF;
+    uint8_t next = header >> 8;
+
+    g_test_message("CID: %02x; next: %02x", cid, next);
+
+    switch (cid) {
+    case PCI_CAP_ID_PM:
+        ahci_test_pmcap(ahci, offset);
+        break;
+    case PCI_CAP_ID_MSI:
+        ahci_test_msicap(ahci, offset);
+        break;
+    case PCI_CAP_ID_SATA:
+        ahci_test_satacap(ahci, offset);
+        break;
+
+    default:
+        g_test_message("Unknown CAP 0x%02x", cid);
+    }
+
+    if (next) {
+        ahci_test_pci_caps(ahci, qpci_config_readw(ahci->dev, next), next);
+    }
+}
+
+/**
+ * Test SATA PCI capabilitity for AHCI specification adherence.
+ */
+static void ahci_test_satacap(AHCIQState *ahci, uint8_t offset)
+{
+    uint16_t dataw;
+    uint32_t datal;
+
+    g_test_message("Verifying SATACAP");
+
+    /* Assert that the SATACAP version is 1.0, And reserved bits are empty. */
+    dataw = qpci_config_readw(ahci->dev, offset + 2);
+    g_assert_cmphex(dataw, ==, 0x10);
+
+    /* Grab the SATACR1 register. */
+    datal = qpci_config_readw(ahci->dev, offset + 4);
+
+    switch (datal & 0x0F) {
+    case 0x04: /* BAR0 */
+    case 0x05: /* BAR1 */
+    case 0x06:
+    case 0x07:
+    case 0x08:
+    case 0x09: /* BAR5 */
+    case 0x0F: /* Immediately following SATACR1 in PCI config space. */
+        break;
+    default:
+        /* Invalid BARLOC for the Index Data Pair. */
+        g_assert_not_reached();
+    }
+
+    /* Reserved. */
+    g_assert_cmphex((datal >> 24), ==, 0x00);
+}
+
+/**
+ * Test MSI PCI capability for AHCI specification adherence.
+ */
+static void ahci_test_msicap(AHCIQState *ahci, uint8_t offset)
+{
+    uint16_t dataw;
+    uint32_t datal;
+
+    g_test_message("Verifying MSICAP");
+
+    dataw = qpci_config_readw(ahci->dev, offset + PCI_MSI_FLAGS);
+    ASSERT_BIT_CLEAR(dataw, PCI_MSI_FLAGS_ENABLE);
+    ASSERT_BIT_CLEAR(dataw, PCI_MSI_FLAGS_QSIZE);
+    ASSERT_BIT_CLEAR(dataw, PCI_MSI_FLAGS_RESERVED);
+
+    datal = qpci_config_readl(ahci->dev, offset + PCI_MSI_ADDRESS_LO);
+    g_assert_cmphex(datal, ==, 0);
+
+    if (dataw & PCI_MSI_FLAGS_64BIT) {
+        g_test_message("MSICAP is 64bit");
+        datal = qpci_config_readl(ahci->dev, offset + PCI_MSI_ADDRESS_HI);
+        g_assert_cmphex(datal, ==, 0);
+        dataw = qpci_config_readw(ahci->dev, offset + PCI_MSI_DATA_64);
+        g_assert_cmphex(dataw, ==, 0);
+    } else {
+        g_test_message("MSICAP is 32bit");
+        dataw = qpci_config_readw(ahci->dev, offset + PCI_MSI_DATA_32);
+        g_assert_cmphex(dataw, ==, 0);
+    }
+}
+
+/**
+ * Test Power Management PCI capability for AHCI specification adherence.
+ */
+static void ahci_test_pmcap(AHCIQState *ahci, uint8_t offset)
+{
+    uint16_t dataw;
+
+    g_test_message("Verifying PMCAP");
+
+    dataw = qpci_config_readw(ahci->dev, offset + PCI_PM_PMC);
+    ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_PME_CLOCK);
+    ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_RESERVED);
+    ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_D1);
+    ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_D2);
+
+    dataw = qpci_config_readw(ahci->dev, offset + PCI_PM_CTRL);
+    ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_STATE_MASK);
+    ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_RESERVED);
+    ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_DATA_SEL_MASK);
+    ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_DATA_SCALE_MASK);
+}
+
+static void ahci_test_hba_spec(AHCIQState *ahci)
+{
+    unsigned i;
+    uint32_t reg;
+    uint32_t ports;
+    uint8_t nports_impl;
+    uint8_t maxports;
+
+    g_assert(ahci != NULL);
+
+    /*
+     * Note that the AHCI spec does expect the BIOS to set up a few things:
+     * CAP.SSS    - Support for staggered spin-up            (t/f)
+     * CAP.SMPS   - Support for mechanical presence switches (t/f)
+     * PI         - Ports Implemented                        (1-32)
+     * PxCMD.HPCP - Hot Plug Capable Port
+     * PxCMD.MPSP - Mechanical Presence Switch Present
+     * PxCMD.CPD  - Cold Presence Detection support
+     *
+     * Additional items are touched if CAP.SSS is on, see AHCI 10.1.1 p.97:
+     * Foreach Port Implemented:
+     * -PxCMD.ST, PxCMD.CR, PxCMD.FRE, PxCMD.FR, PxSCTL.DET are 0
+     * -PxCLB/U and PxFB/U are set to valid regions in memory
+     * -PxSUD is set to 1.
+     * -PxSSTS.DET is polled for presence; if detected, we continue:
+     * -PxSERR is cleared with 1's.
+     * -If PxTFD.STS.BSY, PxTFD.STS.DRQ, and PxTFD.STS.ERR are all zero,
+     *  the device is ready.
+     */
+
+    /* 1 CAP - Capabilities Register */
+    ahci->cap = ahci_rreg(ahci, AHCI_CAP);
+    ASSERT_BIT_CLEAR(ahci->cap, AHCI_CAP_RESERVED);
+
+    /* 2 GHC - Global Host Control */
+    reg = ahci_rreg(ahci, AHCI_GHC);
+    ASSERT_BIT_CLEAR(reg, AHCI_GHC_HR);
+    ASSERT_BIT_CLEAR(reg, AHCI_GHC_IE);
+    ASSERT_BIT_CLEAR(reg, AHCI_GHC_MRSM);
+    if (BITSET(ahci->cap, AHCI_CAP_SAM)) {
+        g_test_message("Supports AHCI-Only Mode: GHC_AE is Read-Only.");
+        ASSERT_BIT_SET(reg, AHCI_GHC_AE);
+    } else {
+        g_test_message("Supports AHCI/Legacy mix.");
+        ASSERT_BIT_CLEAR(reg, AHCI_GHC_AE);
+    }
+
+    /* 3 IS - Interrupt Status */
+    reg = ahci_rreg(ahci, AHCI_IS);
+    g_assert_cmphex(reg, ==, 0);
+
+    /* 4 PI - Ports Implemented */
+    ports = ahci_rreg(ahci, AHCI_PI);
+    /* Ports Implemented must be non-zero. */
+    g_assert_cmphex(ports, !=, 0);
+    /* Ports Implemented must be <= Number of Ports. */
+    nports_impl = ctpopl(ports);
+    g_assert_cmpuint(((AHCI_CAP_NP & ahci->cap) + 1), >=, nports_impl);
+
+    /* Ports must be within the proper range. Given a mapping of SIZE,
+     * 256 bytes are used for global HBA control, and the rest is used
+     * for ports data, at 0x80 bytes each. */
+    g_assert_cmphex(ahci->barsize, >, 0);
+    maxports = (ahci->barsize - HBA_DATA_REGION_SIZE) / HBA_PORT_DATA_SIZE;
+    /* e.g, 30 ports for 4K of memory. (4096 - 256) / 128 = 30 */
+    g_assert_cmphex((reg >> maxports), ==, 0);
+
+    /* 5 AHCI Version */
+    reg = ahci_rreg(ahci, AHCI_VS);
+    switch (reg) {
+    case AHCI_VERSION_0_95:
+    case AHCI_VERSION_1_0:
+    case AHCI_VERSION_1_1:
+    case AHCI_VERSION_1_2:
+    case AHCI_VERSION_1_3:
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    /* 6 Command Completion Coalescing Control: depends on CAP.CCCS. */
+    reg = ahci_rreg(ahci, AHCI_CCCCTL);
+    if (BITSET(ahci->cap, AHCI_CAP_CCCS)) {
+        ASSERT_BIT_CLEAR(reg, AHCI_CCCCTL_EN);
+        ASSERT_BIT_CLEAR(reg, AHCI_CCCCTL_RESERVED);
+        ASSERT_BIT_SET(reg, AHCI_CCCCTL_CC);
+        ASSERT_BIT_SET(reg, AHCI_CCCCTL_TV);
+    } else {
+        g_assert_cmphex(reg, ==, 0);
+    }
+
+    /* 7 CCC_PORTS */
+    reg = ahci_rreg(ahci, AHCI_CCCPORTS);
+    /* Must be zeroes initially regardless of CAP.CCCS */
+    g_assert_cmphex(reg, ==, 0);
+
+    /* 8 EM_LOC */
+    reg = ahci_rreg(ahci, AHCI_EMLOC);
+    if (BITCLR(ahci->cap, AHCI_CAP_EMS)) {
+        g_assert_cmphex(reg, ==, 0);
+    }
+
+    /* 9 EM_CTL */
+    reg = ahci_rreg(ahci, AHCI_EMCTL);
+    if (BITSET(ahci->cap, AHCI_CAP_EMS)) {
+        ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_STSMR);
+        ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_CTLTM);
+        ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_CTLRST);
+        ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_RESERVED);
+    } else {
+        g_assert_cmphex(reg, ==, 0);
+    }
+
+    /* 10 CAP2 -- Capabilities Extended */
+    ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2);
+    ASSERT_BIT_CLEAR(ahci->cap2, AHCI_CAP2_RESERVED);
+
+    /* 11 BOHC -- Bios/OS Handoff Control */
+    reg = ahci_rreg(ahci, AHCI_BOHC);
+    g_assert_cmphex(reg, ==, 0);
+
+    /* 12 -- 23: Reserved */
+    g_test_message("Verifying HBA reserved area is empty.");
+    for (i = AHCI_RESERVED; i < AHCI_NVMHCI; ++i) {
+        reg = ahci_rreg(ahci, i);
+        g_assert_cmphex(reg, ==, 0);
+    }
+
+    /* 24 -- 39: NVMHCI */
+    if (BITCLR(ahci->cap2, AHCI_CAP2_NVMP)) {
+        g_test_message("Verifying HBA/NVMHCI area is empty.");
+        for (i = AHCI_NVMHCI; i < AHCI_VENDOR; ++i) {
+            reg = ahci_rreg(ahci, i);
+            g_assert_cmphex(reg, ==, 0);
+        }
+    }
+
+    /* 40 -- 63: Vendor */
+    g_test_message("Verifying HBA/Vendor area is empty.");
+    for (i = AHCI_VENDOR; i < AHCI_PORTS; ++i) {
+        reg = ahci_rreg(ahci, i);
+        g_assert_cmphex(reg, ==, 0);
+    }
+
+    /* 64 -- XX: Port Space */
+    for (i = 0; ports || (i < maxports); ports >>= 1, ++i) {
+        if (BITSET(ports, 0x1)) {
+            g_test_message("Testing port %u for spec", i);
+            ahci_test_port_spec(ahci, i);
+        } else {
+            uint16_t j;
+            uint16_t low = AHCI_PORTS + (32 * i);
+            uint16_t high = AHCI_PORTS + (32 * (i + 1));
+            g_test_message("Asserting unimplemented port %u "
+                           "(reg [%u-%u]) is empty.",
+                           i, low, high - 1);
+            for (j = low; j < high; ++j) {
+                reg = ahci_rreg(ahci, j);
+                g_assert_cmphex(reg, ==, 0);
+            }
+        }
+    }
+}
+
+/**
+ * Test the memory space for one port for specification adherence.
+ */
+static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port)
+{
+    uint32_t reg;
+    unsigned i;
+
+    /* (0) CLB */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_CLB);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_CLB_RESERVED);
+
+    /* (1) CLBU */
+    if (BITCLR(ahci->cap, AHCI_CAP_S64A)) {
+        reg = ahci_px_rreg(ahci, port, AHCI_PX_CLBU);
+        g_assert_cmphex(reg, ==, 0);
+    }
+
+    /* (2) FB */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_FB);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_FB_RESERVED);
+
+    /* (3) FBU */
+    if (BITCLR(ahci->cap, AHCI_CAP_S64A)) {
+        reg = ahci_px_rreg(ahci, port, AHCI_PX_FBU);
+        g_assert_cmphex(reg, ==, 0);
+    }
+
+    /* (4) IS */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_IS);
+    g_assert_cmphex(reg, ==, 0);
+
+    /* (5) IE */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_IE);
+    g_assert_cmphex(reg, ==, 0);
+
+    /* (6) CMD */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_CMD);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FRE);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_RESERVED);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CCS);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FR);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CR);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_PMA); /* And RW only if CAP.SPM */
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_APSTE); /* RW only if CAP2.APST */
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_ATAPI);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_DLAE);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_ALPE);  /* RW only if CAP.SALP */
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_ASP);   /* RW only if CAP.SALP */
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_ICC);
+    /* If CPDetect support does not exist, CPState must be off. */
+    if (BITCLR(reg, AHCI_PX_CMD_CPD)) {
+        ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CPS);
+    }
+    /* If MPSPresence is not set, MPSState must be off. */
+    if (BITCLR(reg, AHCI_PX_CMD_MPSP)) {
+        ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_MPSS);
+    }
+    /* If we do not support MPS, MPSS and MPSP must be off. */
+    if (BITCLR(ahci->cap, AHCI_CAP_SMPS)) {
+        ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_MPSS);
+        ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_MPSP);
+    }
+    /* If, via CPD or MPSP we detect a drive, HPCP must be on. */
+    if (BITANY(reg, AHCI_PX_CMD_CPD | AHCI_PX_CMD_MPSP)) {
+        ASSERT_BIT_SET(reg, AHCI_PX_CMD_HPCP);
+    }
+    /* HPCP and ESP cannot both be active. */
+    g_assert(!BITSET(reg, AHCI_PX_CMD_HPCP | AHCI_PX_CMD_ESP));
+    /* If CAP.FBSS is not set, FBSCP must not be set. */
+    if (BITCLR(ahci->cap, AHCI_CAP_FBSS)) {
+        ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FBSCP);
+    }
+
+    /* (7) RESERVED */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_RES1);
+    g_assert_cmphex(reg, ==, 0);
+
+    /* (8) TFD */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD);
+    /* At boot, prior to an FIS being received, the TFD register should be 0x7F,
+     * which breaks down as follows, as seen in AHCI 1.3 sec 3.3.8, p. 27. */
+    ASSERT_BIT_SET(reg, AHCI_PX_TFD_STS_ERR);
+    ASSERT_BIT_SET(reg, AHCI_PX_TFD_STS_CS1);
+    ASSERT_BIT_SET(reg, AHCI_PX_TFD_STS_DRQ);
+    ASSERT_BIT_SET(reg, AHCI_PX_TFD_STS_CS2);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_BSY);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_RESERVED);
+
+    /* (9) SIG */
+    /* Though AHCI specifies the boot value should be 0xFFFFFFFF,
+     * Even when GHC.ST is zero, the AHCI HBA may receive the initial
+     * D2H register FIS and update the signature asynchronously,
+     * so we cannot expect a value here. AHCI 1.3, sec 3.3.9, pp 27-28 */
+
+    /* (10) SSTS / SCR0: SStatus */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_SSTS);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_SSTS_RESERVED);
+    /* Even though the register should be 0 at boot, it is asynchronous and
+     * prone to change, so we cannot test any well known value. */
+
+    /* (11) SCTL / SCR2: SControl */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_SCTL);
+    g_assert_cmphex(reg, ==, 0);
+
+    /* (12) SERR / SCR1: SError */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_SERR);
+    g_assert_cmphex(reg, ==, 0);
+
+    /* (13) SACT / SCR3: SActive */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_SACT);
+    g_assert_cmphex(reg, ==, 0);
+
+    /* (14) CI */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_CI);
+    g_assert_cmphex(reg, ==, 0);
+
+    /* (15) SNTF */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_SNTF);
+    g_assert_cmphex(reg, ==, 0);
+
+    /* (16) FBS */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_FBS);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_EN);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_DEC);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_SDE);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_DEV);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_DWE);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_RESERVED);
+    if (BITSET(ahci->cap, AHCI_CAP_FBSS)) {
+        /* if Port-Multiplier FIS-based switching avail, ADO must >= 2 */
+        g_assert((reg & AHCI_PX_FBS_ADO) >> ctzl(AHCI_PX_FBS_ADO) >= 2);
+    }
+
+    /* [17 -- 27] RESERVED */
+    for (i = AHCI_PX_RES2; i < AHCI_PX_VS; ++i) {
+        reg = ahci_px_rreg(ahci, port, i);
+        g_assert_cmphex(reg, ==, 0);
+    }
+
+    /* [28 -- 31] Vendor-Specific */
+    for (i = AHCI_PX_VS; i < 32; ++i) {
+        reg = ahci_px_rreg(ahci, port, i);
+        if (reg) {
+            g_test_message("INFO: Vendor register %u non-empty", i);
+        }
+    }
+}
+
+/**
+ * Utilizing an initialized AHCI HBA, issue an IDENTIFY command to the first
+ * device we see, then read and check the response.
+ */
+static void ahci_test_identify(AHCIQState *ahci)
+{
+    uint16_t buff[256];
+    unsigned px;
+    int rc;
+    uint16_t sect_size;
+    const size_t buffsize = 512;
+
+    g_assert(ahci != NULL);
+
+    /**
+     * This serves as a bit of a tutorial on AHCI device programming:
+     *
+     * (1) Create a data buffer for the IDENTIFY response to be sent to
+     * (2) Create a Command Table buffer, where we will store the
+     *     command and PRDT (Physical Region Descriptor Table)
+     * (3) Construct an FIS host-to-device command structure, and write it to
+     *     the top of the Command Table buffer.
+     * (4) Create one or more Physical Region Descriptors (PRDs) that describe
+     *     a location in memory where data may be stored/retrieved.
+     * (5) Write these PRDTs to the bottom (offset 0x80) of the Command Table.
+     * (6) Each AHCI port has up to 32 command slots. Each slot contains a
+     *     header that points to a Command Table buffer. Pick an unused slot
+     *     and update it to point to the Command Table we have built.
+     * (7) Now: Command #n points to our Command Table, and our Command Table
+     *     contains the FIS (that describes our command) and the PRDTL, which
+     *     describes our buffer.
+     * (8) We inform the HBA via PxCI (Command Issue) that the command in slot
+     *     #n is ready for processing.
+     */
+
+    /* Pick the first implemented and running port */
+    px = ahci_port_select(ahci);
+    g_test_message("Selected port %u for test", px);
+
+    /* Clear out the FIS Receive area and any pending interrupts. */
+    ahci_port_clear(ahci, px);
+
+    /* "Read" 512 bytes using CMD_IDENTIFY into the host buffer. */
+    ahci_io(ahci, px, CMD_IDENTIFY, &buff, buffsize, 0);
+
+    /* Check serial number/version in the buffer */
+    /* NB: IDENTIFY strings are packed in 16bit little endian chunks.
+     * Since we copy byte-for-byte in ahci-test, on both LE and BE, we need to
+     * unchunk this data. By contrast, ide-test copies 2 bytes at a time, and
+     * as a consequence, only needs to unchunk the data on LE machines. */
+    string_bswap16(&buff[10], 20);
+    rc = memcmp(&buff[10], "testdisk            ", 20);
+    g_assert_cmphex(rc, ==, 0);
+
+    string_bswap16(&buff[23], 8);
+    rc = memcmp(&buff[23], "version ", 8);
+    g_assert_cmphex(rc, ==, 0);
+
+    sect_size = le16_to_cpu(*((uint16_t *)(&buff[5])));
+    g_assert_cmphex(sect_size, ==, AHCI_SECTOR_SIZE);
+}
+
+static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize,
+                                   uint64_t sector, uint8_t read_cmd,
+                                   uint8_t write_cmd)
+{
+    uint64_t ptr;
+    uint8_t port;
+    unsigned char *tx = g_malloc(bufsize);
+    unsigned char *rx = g_malloc0(bufsize);
+
+    g_assert(ahci != NULL);
+
+    /* Pick the first running port and clear it. */
+    port = ahci_port_select(ahci);
+    ahci_port_clear(ahci, port);
+
+    /*** Create pattern and transfer to guest ***/
+    /* Data buffer in the guest */
+    ptr = ahci_alloc(ahci, bufsize);
+    g_assert(ptr);
+
+    /* Write some indicative pattern to our buffer. */
+    generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
+    qtest_bufwrite(ahci->parent->qts, ptr, tx, bufsize);
+
+    /* Write this buffer to disk, then read it back to the DMA buffer. */
+    ahci_guest_io(ahci, port, write_cmd, ptr, bufsize, sector);
+    qtest_memset(ahci->parent->qts, ptr, 0x00, bufsize);
+    ahci_guest_io(ahci, port, read_cmd, ptr, bufsize, sector);
+
+    /*** Read back the Data ***/
+    qtest_bufread(ahci->parent->qts, ptr, rx, bufsize);
+    g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
+
+    ahci_free(ahci, ptr);
+    g_free(tx);
+    g_free(rx);
+}
+
+static uint8_t ahci_test_nondata(AHCIQState *ahci, uint8_t ide_cmd)
+{
+    uint8_t port;
+
+    /* Sanitize */
+    port = ahci_port_select(ahci);
+    ahci_port_clear(ahci, port);
+
+    ahci_io(ahci, port, ide_cmd, NULL, 0, 0);
+
+    return port;
+}
+
+static void ahci_test_flush(AHCIQState *ahci)
+{
+    ahci_test_nondata(ahci, CMD_FLUSH_CACHE);
+}
+
+static void ahci_test_max(AHCIQState *ahci)
+{
+    RegD2HFIS *d2h = g_malloc0(0x20);
+    uint64_t nsect;
+    uint8_t port;
+    uint8_t cmd;
+    uint64_t config_sect = mb_to_sectors(test_image_size_mb) - 1;
+
+    if (config_sect > 0xFFFFFF) {
+        cmd = CMD_READ_MAX_EXT;
+    } else {
+        cmd = CMD_READ_MAX;
+    }
+
+    port = ahci_test_nondata(ahci, cmd);
+    qtest_memread(ahci->parent->qts, ahci->port[port].fb + 0x40, d2h, 0x20);
+    nsect = (uint64_t)d2h->lba_hi[2] << 40 |
+        (uint64_t)d2h->lba_hi[1] << 32 |
+        (uint64_t)d2h->lba_hi[0] << 24 |
+        (uint64_t)d2h->lba_lo[2] << 16 |
+        (uint64_t)d2h->lba_lo[1] << 8 |
+        (uint64_t)d2h->lba_lo[0];
+
+    g_assert_cmphex(nsect, ==, config_sect);
+    g_free(d2h);
+}
+
+
+/******************************************************************************/
+/* Test Interfaces                                                            */
+/******************************************************************************/
+
+/**
+ * Basic sanity test to boot a machine, find an AHCI device, and shutdown.
+ */
+static void test_sanity(void)
+{
+    AHCIQState *ahci;
+    ahci = ahci_boot(NULL);
+    ahci_shutdown(ahci);
+}
+
+/**
+ * Ensure that the PCI configuration space for the AHCI device is in-line with
+ * the AHCI 1.3 specification for initial values.
+ */
+static void test_pci_spec(void)
+{
+    AHCIQState *ahci;
+    ahci = ahci_boot(NULL);
+    ahci_test_pci_spec(ahci);
+    ahci_shutdown(ahci);
+}
+
+/**
+ * Engage the PCI AHCI device and sanity check the response.
+ * Perform additional PCI config space bringup for the HBA.
+ */
+static void test_pci_enable(void)
+{
+    AHCIQState *ahci;
+    ahci = ahci_boot(NULL);
+    ahci_pci_enable(ahci);
+    ahci_shutdown(ahci);
+}
+
+/**
+ * Investigate the memory mapped regions of the HBA,
+ * and test them for AHCI specification adherence.
+ */
+static void test_hba_spec(void)
+{
+    AHCIQState *ahci;
+
+    ahci = ahci_boot(NULL);
+    ahci_pci_enable(ahci);
+    ahci_test_hba_spec(ahci);
+    ahci_shutdown(ahci);
+}
+
+/**
+ * Engage the HBA functionality of the AHCI PCI device,
+ * and bring it into a functional idle state.
+ */
+static void test_hba_enable(void)
+{
+    AHCIQState *ahci;
+
+    ahci = ahci_boot(NULL);
+    ahci_pci_enable(ahci);
+    ahci_hba_enable(ahci);
+    ahci_shutdown(ahci);
+}
+
+/**
+ * Bring up the device and issue an IDENTIFY command.
+ * Inspect the state of the HBA device and the data returned.
+ */
+static void test_identify(void)
+{
+    AHCIQState *ahci;
+
+    ahci = ahci_boot_and_enable(NULL);
+    ahci_test_identify(ahci);
+    ahci_shutdown(ahci);
+}
+
+/**
+ * Fragmented DMA test: Perform a standard 4K DMA read/write
+ * test, but make sure the physical regions are fragmented to
+ * be very small, each just 32 bytes, to see how AHCI performs
+ * with chunks defined to be much less than a sector.
+ */
+static void test_dma_fragmented(void)
+{
+    AHCIQState *ahci;
+    AHCICommand *cmd;
+    uint8_t px;
+    size_t bufsize = 4096;
+    unsigned char *tx = g_malloc(bufsize);
+    unsigned char *rx = g_malloc0(bufsize);
+    uint64_t ptr;
+
+    ahci = ahci_boot_and_enable(NULL);
+    px = ahci_port_select(ahci);
+    ahci_port_clear(ahci, px);
+
+    /* create pattern */
+    generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
+
+    /* Create a DMA buffer in guest memory, and write our pattern to it. */
+    ptr = guest_alloc(&ahci->parent->alloc, bufsize);
+    g_assert(ptr);
+    qtest_bufwrite(ahci->parent->qts, ptr, tx, bufsize);
+
+    cmd = ahci_command_create(CMD_WRITE_DMA);
+    ahci_command_adjust(cmd, 0, ptr, bufsize, 32);
+    ahci_command_commit(ahci, cmd, px);
+    ahci_command_issue(ahci, cmd);
+    ahci_command_verify(ahci, cmd);
+    ahci_command_free(cmd);
+
+    cmd = ahci_command_create(CMD_READ_DMA);
+    ahci_command_adjust(cmd, 0, ptr, bufsize, 32);
+    ahci_command_commit(ahci, cmd, px);
+    ahci_command_issue(ahci, cmd);
+    ahci_command_verify(ahci, cmd);
+    ahci_command_free(cmd);
+
+    /* Read back the guest's receive buffer into local memory */
+    qtest_bufread(ahci->parent->qts, ptr, rx, bufsize);
+    guest_free(&ahci->parent->alloc, ptr);
+
+    g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
+
+    ahci_shutdown(ahci);
+
+    g_free(rx);
+    g_free(tx);
+}
+
+/*
+ * Write sector 1 with random data to make AHCI storage dirty
+ * Needed for flush tests so that flushes actually go though the block layer
+ */
+static void make_dirty(AHCIQState* ahci, uint8_t port)
+{
+    uint64_t ptr;
+    unsigned bufsize = 512;
+
+    ptr = ahci_alloc(ahci, bufsize);
+    g_assert(ptr);
+
+    ahci_guest_io(ahci, port, CMD_WRITE_DMA, ptr, bufsize, 1);
+    ahci_free(ahci, ptr);
+}
+
+static void test_flush(void)
+{
+    AHCIQState *ahci;
+    uint8_t port;
+
+    ahci = ahci_boot_and_enable(NULL);
+
+    port = ahci_port_select(ahci);
+    ahci_port_clear(ahci, port);
+
+    make_dirty(ahci, port);
+
+    ahci_test_flush(ahci);
+    ahci_shutdown(ahci);
+}
+
+static void test_flush_retry(void)
+{
+    AHCIQState *ahci;
+    AHCICommand *cmd;
+    uint8_t port;
+
+    prepare_blkdebug_script(debug_path, "flush_to_disk");
+    ahci = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0,"
+                                "format=%s,cache=writeback,"
+                                "rerror=stop,werror=stop "
+                                "-M q35 "
+                                "-device ide-hd,drive=drive0 ",
+                                debug_path,
+                                tmp_path, imgfmt);
+
+    port = ahci_port_select(ahci);
+    ahci_port_clear(ahci, port);
+
+    /* Issue write so that flush actually goes to disk */
+    make_dirty(ahci, port);
+
+    /* Issue Flush Command and wait for error */
+    cmd = ahci_guest_io_halt(ahci, port, CMD_FLUSH_CACHE, 0, 0, 0);
+    ahci_guest_io_resume(ahci, cmd);
+
+    ahci_shutdown(ahci);
+}
+
+/**
+ * Basic sanity test to boot a machine, find an AHCI device, and shutdown.
+ */
+static void test_migrate_sanity(void)
+{
+    AHCIQState *src, *dst;
+    char *uri = g_strdup_printf("unix:%s", mig_socket);
+
+    src = ahci_boot("-m 384 -M q35 "
+                    "-drive if=ide,file=%s,format=%s ", tmp_path, imgfmt);
+    dst = ahci_boot("-m 384 -M q35 "
+                    "-drive if=ide,file=%s,format=%s "
+                    "-incoming %s", tmp_path, imgfmt, uri);
+
+    ahci_migrate(src, dst, uri);
+
+    ahci_shutdown(src);
+    ahci_shutdown(dst);
+    g_free(uri);
+}
+
+/**
+ * Simple migration test: Write a pattern, migrate, then read.
+ */
+static void ahci_migrate_simple(uint8_t cmd_read, uint8_t cmd_write)
+{
+    AHCIQState *src, *dst;
+    uint8_t px;
+    size_t bufsize = 4096;
+    unsigned char *tx = g_malloc(bufsize);
+    unsigned char *rx = g_malloc0(bufsize);
+    char *uri = g_strdup_printf("unix:%s", mig_socket);
+
+    src = ahci_boot_and_enable("-m 384 -M q35 "
+                               "-drive if=ide,format=%s,file=%s ",
+                               imgfmt, tmp_path);
+    dst = ahci_boot("-m 384 -M q35 "
+                    "-drive if=ide,format=%s,file=%s "
+                    "-incoming %s", imgfmt, tmp_path, uri);
+
+    /* initialize */
+    px = ahci_port_select(src);
+    ahci_port_clear(src, px);
+
+    /* create pattern */
+    generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
+
+    /* Write, migrate, then read. */
+    ahci_io(src, px, cmd_write, tx, bufsize, 0);
+    ahci_migrate(src, dst, uri);
+    ahci_io(dst, px, cmd_read, rx, bufsize, 0);
+
+    /* Verify pattern */
+    g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
+
+    ahci_shutdown(src);
+    ahci_shutdown(dst);
+    g_free(rx);
+    g_free(tx);
+    g_free(uri);
+}
+
+static void test_migrate_dma(void)
+{
+    ahci_migrate_simple(CMD_READ_DMA, CMD_WRITE_DMA);
+}
+
+static void test_migrate_ncq(void)
+{
+    ahci_migrate_simple(READ_FPDMA_QUEUED, WRITE_FPDMA_QUEUED);
+}
+
+/**
+ * Halted IO Error Test
+ *
+ * Simulate an error on first write, Try to write a pattern,
+ * Confirm the VM has stopped, resume the VM, verify command
+ * has completed, then read back the data and verify.
+ */
+static void ahci_halted_io_test(uint8_t cmd_read, uint8_t cmd_write)
+{
+    AHCIQState *ahci;
+    uint8_t port;
+    size_t bufsize = 4096;
+    unsigned char *tx = g_malloc(bufsize);
+    unsigned char *rx = g_malloc0(bufsize);
+    uint64_t ptr;
+    AHCICommand *cmd;
+
+    prepare_blkdebug_script(debug_path, "write_aio");
+
+    ahci = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0,"
+                                "format=%s,cache=writeback,"
+                                "rerror=stop,werror=stop "
+                                "-M q35 "
+                                "-device ide-hd,drive=drive0 ",
+                                debug_path,
+                                tmp_path, imgfmt);
+
+    /* Initialize and prepare */
+    port = ahci_port_select(ahci);
+    ahci_port_clear(ahci, port);
+
+    /* create DMA source buffer and write pattern */
+    generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
+    ptr = ahci_alloc(ahci, bufsize);
+    g_assert(ptr);
+    qtest_memwrite(ahci->parent->qts, ptr, tx, bufsize);
+
+    /* Attempt to write (and fail) */
+    cmd = ahci_guest_io_halt(ahci, port, cmd_write,
+                             ptr, bufsize, 0);
+
+    /* Attempt to resume the command */
+    ahci_guest_io_resume(ahci, cmd);
+    ahci_free(ahci, ptr);
+
+    /* Read back and verify */
+    ahci_io(ahci, port, cmd_read, rx, bufsize, 0);
+    g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
+
+    /* Cleanup and go home */
+    ahci_shutdown(ahci);
+    g_free(rx);
+    g_free(tx);
+}
+
+static void test_halted_dma(void)
+{
+    ahci_halted_io_test(CMD_READ_DMA, CMD_WRITE_DMA);
+}
+
+static void test_halted_ncq(void)
+{
+    ahci_halted_io_test(READ_FPDMA_QUEUED, WRITE_FPDMA_QUEUED);
+}
+
+/**
+ * IO Error Migration Test
+ *
+ * Simulate an error on first write, Try to write a pattern,
+ * Confirm the VM has stopped, migrate, resume the VM,
+ * verify command has completed, then read back the data and verify.
+ */
+static void ahci_migrate_halted_io(uint8_t cmd_read, uint8_t cmd_write)
+{
+    AHCIQState *src, *dst;
+    uint8_t port;
+    size_t bufsize = 4096;
+    unsigned char *tx = g_malloc(bufsize);
+    unsigned char *rx = g_malloc0(bufsize);
+    uint64_t ptr;
+    AHCICommand *cmd;
+    char *uri = g_strdup_printf("unix:%s", mig_socket);
+
+    prepare_blkdebug_script(debug_path, "write_aio");
+
+    src = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0,"
+                               "format=%s,cache=writeback,"
+                               "rerror=stop,werror=stop "
+                               "-M q35 "
+                               "-device ide-hd,drive=drive0 ",
+                               debug_path,
+                               tmp_path, imgfmt);
+
+    dst = ahci_boot("-drive file=%s,if=none,id=drive0,"
+                    "format=%s,cache=writeback,"
+                    "rerror=stop,werror=stop "
+                    "-M q35 "
+                    "-device ide-hd,drive=drive0 "
+                    "-incoming %s",
+                    tmp_path, imgfmt, uri);
+
+    /* Initialize and prepare */
+    port = ahci_port_select(src);
+    ahci_port_clear(src, port);
+    generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
+
+    /* create DMA source buffer and write pattern */
+    ptr = ahci_alloc(src, bufsize);
+    g_assert(ptr);
+    qtest_memwrite(src->parent->qts, ptr, tx, bufsize);
+
+    /* Write, trigger the VM to stop, migrate, then resume. */
+    cmd = ahci_guest_io_halt(src, port, cmd_write,
+                             ptr, bufsize, 0);
+    ahci_migrate(src, dst, uri);
+    ahci_guest_io_resume(dst, cmd);
+    ahci_free(dst, ptr);
+
+    /* Read back */
+    ahci_io(dst, port, cmd_read, rx, bufsize, 0);
+
+    /* Verify TX and RX are identical */
+    g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
+
+    /* Cleanup and go home. */
+    ahci_shutdown(src);
+    ahci_shutdown(dst);
+    g_free(rx);
+    g_free(tx);
+    g_free(uri);
+}
+
+static void test_migrate_halted_dma(void)
+{
+    ahci_migrate_halted_io(CMD_READ_DMA, CMD_WRITE_DMA);
+}
+
+static void test_migrate_halted_ncq(void)
+{
+    ahci_migrate_halted_io(READ_FPDMA_QUEUED, WRITE_FPDMA_QUEUED);
+}
+
+/**
+ * Migration test: Try to flush, migrate, then resume.
+ */
+static void test_flush_migrate(void)
+{
+    AHCIQState *src, *dst;
+    AHCICommand *cmd;
+    uint8_t px;
+    char *uri = g_strdup_printf("unix:%s", mig_socket);
+
+    prepare_blkdebug_script(debug_path, "flush_to_disk");
+
+    src = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0,"
+                               "cache=writeback,rerror=stop,werror=stop,"
+                               "format=%s "
+                               "-M q35 "
+                               "-device ide-hd,drive=drive0 ",
+                               debug_path, tmp_path, imgfmt);
+    dst = ahci_boot("-drive file=%s,if=none,id=drive0,"
+                    "cache=writeback,rerror=stop,werror=stop,"
+                    "format=%s "
+                    "-M q35 "
+                    "-device ide-hd,drive=drive0 "
+                    "-incoming %s", tmp_path, imgfmt, uri);
+
+    px = ahci_port_select(src);
+    ahci_port_clear(src, px);
+
+    /* Dirty device so that flush reaches disk */
+    make_dirty(src, px);
+
+    /* Issue Flush Command */
+    cmd = ahci_command_create(CMD_FLUSH_CACHE);
+    ahci_command_commit(src, cmd, px);
+    ahci_command_issue_async(src, cmd);
+    qtest_qmp_eventwait(src->parent->qts, "STOP");
+
+    /* Migrate over */
+    ahci_migrate(src, dst, uri);
+
+    /* Complete the command */
+    qtest_qmp_send(dst->parent->qts, "{'execute':'cont' }");
+    qtest_qmp_eventwait(dst->parent->qts, "RESUME");
+    ahci_command_wait(dst, cmd);
+    ahci_command_verify(dst, cmd);
+
+    ahci_command_free(cmd);
+    ahci_shutdown(src);
+    ahci_shutdown(dst);
+    g_free(uri);
+}
+
+static void test_max(void)
+{
+    AHCIQState *ahci;
+
+    ahci = ahci_boot_and_enable(NULL);
+    ahci_test_max(ahci);
+    ahci_shutdown(ahci);
+}
+
+static void test_reset(void)
+{
+    AHCIQState *ahci;
+    int i;
+
+    ahci = ahci_boot(NULL);
+    ahci_test_pci_spec(ahci);
+    ahci_pci_enable(ahci);
+
+    for (i = 0; i < 2; i++) {
+        ahci_test_hba_spec(ahci);
+        ahci_hba_enable(ahci);
+        ahci_test_identify(ahci);
+        ahci_test_io_rw_simple(ahci, 4096, 0,
+                               CMD_READ_DMA_EXT,
+                               CMD_WRITE_DMA_EXT);
+        ahci_set(ahci, AHCI_GHC, AHCI_GHC_HR);
+        ahci_clean_mem(ahci);
+    }
+
+    ahci_shutdown(ahci);
+}
+
+static void test_ncq_simple(void)
+{
+    AHCIQState *ahci;
+
+    ahci = ahci_boot_and_enable(NULL);
+    ahci_test_io_rw_simple(ahci, 4096, 0,
+                           READ_FPDMA_QUEUED,
+                           WRITE_FPDMA_QUEUED);
+    ahci_shutdown(ahci);
+}
+
+static int prepare_iso(size_t size, unsigned char **buf, char **name)
+{
+    char cdrom_path[] = "/tmp/qtest.iso.XXXXXX";
+    unsigned char *patt;
+    ssize_t ret;
+    int fd = mkstemp(cdrom_path);
+
+    g_assert(buf);
+    g_assert(name);
+    patt = g_malloc(size);
+
+    /* Generate a pattern and build a CDROM image to read from */
+    generate_pattern(patt, size, ATAPI_SECTOR_SIZE);
+    ret = write(fd, patt, size);
+    g_assert(ret == size);
+
+    *name = g_strdup(cdrom_path);
+    *buf = patt;
+    return fd;
+}
+
+static void remove_iso(int fd, char *name)
+{
+    unlink(name);
+    g_free(name);
+    close(fd);
+}
+
+static int ahci_cb_cmp_buff(AHCIQState *ahci, AHCICommand *cmd,
+                            const AHCIOpts *opts)
+{
+    unsigned char *tx = opts->opaque;
+    unsigned char *rx;
+
+    if (!opts->size) {
+        return 0;
+    }
+
+    rx = g_malloc0(opts->size);
+    qtest_bufread(ahci->parent->qts, opts->buffer, rx, opts->size);
+    g_assert_cmphex(memcmp(tx, rx, opts->size), ==, 0);
+    g_free(rx);
+
+    return 0;
+}
+
+static void ahci_test_cdrom(int nsectors, bool dma, uint8_t cmd,
+                            bool override_bcl, uint16_t bcl)
+{
+    AHCIQState *ahci;
+    unsigned char *tx;
+    char *iso;
+    int fd;
+    AHCIOpts opts = {
+        .size = (ATAPI_SECTOR_SIZE * nsectors),
+        .atapi = true,
+        .atapi_dma = dma,
+        .post_cb = ahci_cb_cmp_buff,
+        .set_bcl = override_bcl,
+        .bcl = bcl,
+    };
+    uint64_t iso_size = ATAPI_SECTOR_SIZE * (nsectors + 1);
+
+    /* Prepare ISO and fill 'tx' buffer */
+    fd = prepare_iso(iso_size, &tx, &iso);
+    opts.opaque = tx;
+
+    /* Standard startup wonkery, but use ide-cd and our special iso file */
+    ahci = ahci_boot_and_enable("-drive if=none,id=drive0,file=%s,format=raw "
+                                "-M q35 "
+                                "-device ide-cd,drive=drive0 ", iso);
+
+    /* Build & Send AHCI command */
+    ahci_exec(ahci, ahci_port_select(ahci), cmd, &opts);
+
+    /* Cleanup */
+    g_free(tx);
+    ahci_shutdown(ahci);
+    remove_iso(fd, iso);
+}
+
+static void ahci_test_cdrom_read10(int nsectors, bool dma)
+{
+    ahci_test_cdrom(nsectors, dma, CMD_ATAPI_READ_10, false, 0);
+}
+
+static void test_cdrom_dma(void)
+{
+    ahci_test_cdrom_read10(1, true);
+}
+
+static void test_cdrom_dma_multi(void)
+{
+    ahci_test_cdrom_read10(3, true);
+}
+
+static void test_cdrom_pio(void)
+{
+    ahci_test_cdrom_read10(1, false);
+}
+
+static void test_cdrom_pio_multi(void)
+{
+    ahci_test_cdrom_read10(3, false);
+}
+
+/* Regression test: Test that a READ_CD command with a BCL of 0 but a size of 0
+ * completes as a NOP instead of erroring out. */
+static void test_atapi_bcl(void)
+{
+    ahci_test_cdrom(0, false, CMD_ATAPI_READ_CD, true, 0);
+}
+
+
+static void atapi_wait_tray(AHCIQState *ahci, bool open)
+{
+    QDict *rsp = qtest_qmp_eventwait_ref(ahci->parent->qts,
+                                         "DEVICE_TRAY_MOVED");
+    QDict *data = qdict_get_qdict(rsp, "data");
+    if (open) {
+        g_assert(qdict_get_bool(data, "tray-open"));
+    } else {
+        g_assert(!qdict_get_bool(data, "tray-open"));
+    }
+    qobject_unref(rsp);
+}
+
+static void test_atapi_tray(void)
+{
+    AHCIQState *ahci;
+    unsigned char *tx;
+    char *iso;
+    int fd;
+    uint8_t port, sense, asc;
+    uint64_t iso_size = ATAPI_SECTOR_SIZE;
+    QDict *rsp;
+
+    fd = prepare_iso(iso_size, &tx, &iso);
+    ahci = ahci_boot_and_enable("-blockdev node-name=drive0,driver=file,filename=%s "
+                                "-M q35 "
+                                "-device ide-cd,id=cd0,drive=drive0 ", iso);
+    port = ahci_port_select(ahci);
+
+    ahci_atapi_eject(ahci, port);
+    atapi_wait_tray(ahci, true);
+
+    ahci_atapi_load(ahci, port);
+    atapi_wait_tray(ahci, false);
+
+    /* Remove media */
+    qtest_qmp_send(ahci->parent->qts, "{'execute': 'blockdev-open-tray', "
+                    "'arguments': {'id': 'cd0'}}");
+    atapi_wait_tray(ahci, true);
+    rsp = qtest_qmp_receive(ahci->parent->qts);
+    qobject_unref(rsp);
+
+    qmp_discard_response(ahci->parent->qts,
+                         "{'execute': 'blockdev-remove-medium', "
+                         "'arguments': {'id': 'cd0'}}");
+
+    /* Test the tray without a medium */
+    ahci_atapi_load(ahci, port);
+    atapi_wait_tray(ahci, false);
+
+    ahci_atapi_eject(ahci, port);
+    atapi_wait_tray(ahci, true);
+
+    /* Re-insert media */
+    qmp_discard_response(ahci->parent->qts,
+                         "{'execute': 'blockdev-add', "
+                         "'arguments': {'node-name': 'node0', "
+                                        "'driver': 'raw', "
+                                        "'file': { 'driver': 'file', "
+                                                  "'filename': %s }}}", iso);
+    qmp_discard_response(ahci->parent->qts,
+                         "{'execute': 'blockdev-insert-medium',"
+                         "'arguments': { 'id': 'cd0', "
+                                         "'node-name': 'node0' }}");
+
+    /* Again, the event shows up first */
+    qtest_qmp_send(ahci->parent->qts, "{'execute': 'blockdev-close-tray', "
+                   "'arguments': {'id': 'cd0'}}");
+    atapi_wait_tray(ahci, false);
+    rsp = qtest_qmp_receive(ahci->parent->qts);
+    qobject_unref(rsp);
+
+    /* Now, to convince ATAPI we understand the media has changed... */
+    ahci_atapi_test_ready(ahci, port, false, SENSE_NOT_READY);
+    ahci_atapi_get_sense(ahci, port, &sense, &asc);
+    g_assert_cmpuint(sense, ==, SENSE_NOT_READY);
+    g_assert_cmpuint(asc, ==, ASC_MEDIUM_NOT_PRESENT);
+
+    ahci_atapi_test_ready(ahci, port, false, SENSE_UNIT_ATTENTION);
+    ahci_atapi_get_sense(ahci, port, &sense, &asc);
+    g_assert_cmpuint(sense, ==, SENSE_UNIT_ATTENTION);
+    g_assert_cmpuint(asc, ==, ASC_MEDIUM_MAY_HAVE_CHANGED);
+
+    ahci_atapi_test_ready(ahci, port, true, SENSE_NO_SENSE);
+    ahci_atapi_get_sense(ahci, port, &sense, &asc);
+    g_assert_cmpuint(sense, ==, SENSE_NO_SENSE);
+
+    /* Final tray test. */
+    ahci_atapi_eject(ahci, port);
+    atapi_wait_tray(ahci, true);
+
+    ahci_atapi_load(ahci, port);
+    atapi_wait_tray(ahci, false);
+
+    /* Cleanup */
+    g_free(tx);
+    ahci_shutdown(ahci);
+    remove_iso(fd, iso);
+}
+
+/******************************************************************************/
+/* AHCI I/O Test Matrix Definitions                                           */
+
+enum BuffLen {
+    LEN_BEGIN = 0,
+    LEN_SIMPLE = LEN_BEGIN,
+    LEN_DOUBLE,
+    LEN_LONG,
+    LEN_SHORT,
+    NUM_LENGTHS
+};
+
+static const char *buff_len_str[NUM_LENGTHS] = { "simple", "double",
+                                                 "long", "short" };
+
+enum AddrMode {
+    ADDR_MODE_BEGIN = 0,
+    ADDR_MODE_LBA28 = ADDR_MODE_BEGIN,
+    ADDR_MODE_LBA48,
+    NUM_ADDR_MODES
+};
+
+static const char *addr_mode_str[NUM_ADDR_MODES] = { "lba28", "lba48" };
+
+enum IOMode {
+    MODE_BEGIN = 0,
+    MODE_PIO = MODE_BEGIN,
+    MODE_DMA,
+    NUM_MODES
+};
+
+static const char *io_mode_str[NUM_MODES] = { "pio", "dma" };
+
+enum IOOps {
+    IO_BEGIN = 0,
+    IO_READ = IO_BEGIN,
+    IO_WRITE,
+    NUM_IO_OPS
+};
+
+enum OffsetType {
+    OFFSET_BEGIN = 0,
+    OFFSET_ZERO = OFFSET_BEGIN,
+    OFFSET_LOW,
+    OFFSET_HIGH,
+    NUM_OFFSETS
+};
+
+static const char *offset_str[NUM_OFFSETS] = { "zero", "low", "high" };
+
+typedef struct AHCIIOTestOptions {
+    enum BuffLen length;
+    enum AddrMode address_type;
+    enum IOMode io_type;
+    enum OffsetType offset;
+} AHCIIOTestOptions;
+
+static uint64_t offset_sector(enum OffsetType ofst,
+                              enum AddrMode addr_type,
+                              uint64_t buffsize)
+{
+    uint64_t ceil;
+    uint64_t nsectors;
+
+    switch (ofst) {
+    case OFFSET_ZERO:
+        return 0;
+    case OFFSET_LOW:
+        return 1;
+    case OFFSET_HIGH:
+        ceil = (addr_type == ADDR_MODE_LBA28) ? 0xfffffff : 0xffffffffffff;
+        ceil = MIN(ceil, mb_to_sectors(test_image_size_mb) - 1);
+        nsectors = buffsize / AHCI_SECTOR_SIZE;
+        return ceil - nsectors + 1;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+/**
+ * Table of possible I/O ATA commands given a set of enumerations.
+ */
+static const uint8_t io_cmds[NUM_MODES][NUM_ADDR_MODES][NUM_IO_OPS] = {
+    [MODE_PIO] = {
+        [ADDR_MODE_LBA28] = {
+            [IO_READ] = CMD_READ_PIO,
+            [IO_WRITE] = CMD_WRITE_PIO },
+        [ADDR_MODE_LBA48] = {
+            [IO_READ] = CMD_READ_PIO_EXT,
+            [IO_WRITE] = CMD_WRITE_PIO_EXT }
+    },
+    [MODE_DMA] = {
+        [ADDR_MODE_LBA28] = {
+            [IO_READ] = CMD_READ_DMA,
+            [IO_WRITE] = CMD_WRITE_DMA },
+        [ADDR_MODE_LBA48] = {
+            [IO_READ] = CMD_READ_DMA_EXT,
+            [IO_WRITE] = CMD_WRITE_DMA_EXT }
+    }
+};
+
+/**
+ * Test a Read/Write pattern using various commands, addressing modes,
+ * transfer modes, and buffer sizes.
+ */
+static void test_io_rw_interface(enum AddrMode lba48, enum IOMode dma,
+                                 unsigned bufsize, uint64_t sector)
+{
+    AHCIQState *ahci;
+
+    ahci = ahci_boot_and_enable(NULL);
+    ahci_test_io_rw_simple(ahci, bufsize, sector,
+                           io_cmds[dma][lba48][IO_READ],
+                           io_cmds[dma][lba48][IO_WRITE]);
+    ahci_shutdown(ahci);
+}
+
+/**
+ * Demultiplex the test data and invoke the actual test routine.
+ */
+static void test_io_interface(gconstpointer opaque)
+{
+    AHCIIOTestOptions *opts = (AHCIIOTestOptions *)opaque;
+    unsigned bufsize;
+    uint64_t sector;
+
+    switch (opts->length) {
+    case LEN_SIMPLE:
+        bufsize = 4096;
+        break;
+    case LEN_DOUBLE:
+        bufsize = 8192;
+        break;
+    case LEN_LONG:
+        bufsize = 4096 * 64;
+        break;
+    case LEN_SHORT:
+        bufsize = 512;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    sector = offset_sector(opts->offset, opts->address_type, bufsize);
+    test_io_rw_interface(opts->address_type, opts->io_type, bufsize, sector);
+    g_free(opts);
+    return;
+}
+
+static void create_ahci_io_test(enum IOMode type, enum AddrMode addr,
+                                enum BuffLen len, enum OffsetType offset)
+{
+    char *name;
+    AHCIIOTestOptions *opts;
+
+    opts = g_new(AHCIIOTestOptions, 1);
+    opts->length = len;
+    opts->address_type = addr;
+    opts->io_type = type;
+    opts->offset = offset;
+
+    name = g_strdup_printf("ahci/io/%s/%s/%s/%s",
+                           io_mode_str[type],
+                           addr_mode_str[addr],
+                           buff_len_str[len],
+                           offset_str[offset]);
+
+    if ((addr == ADDR_MODE_LBA48) && (offset == OFFSET_HIGH) &&
+        (mb_to_sectors(test_image_size_mb) <= 0xFFFFFFF)) {
+        g_test_message("%s: skipped; test image too small", name);
+        g_free(opts);
+        g_free(name);
+        return;
+    }
+
+    qtest_add_data_func(name, opts, test_io_interface);
+    g_free(name);
+}
+
+/******************************************************************************/
+
+int main(int argc, char **argv)
+{
+    const char *arch;
+    int ret;
+    int fd;
+    int c;
+    int i, j, k, m;
+
+    static struct option long_options[] = {
+        {"pedantic", no_argument, 0, 'p' },
+        {0, 0, 0, 0},
+    };
+
+    /* Should be first to utilize g_test functionality, So we can see errors. */
+    g_test_init(&argc, &argv, NULL);
+
+    while (1) {
+        c = getopt_long(argc, argv, "", long_options, NULL);
+        if (c == -1) {
+            break;
+        }
+        switch (c) {
+        case -1:
+            break;
+        case 'p':
+            ahci_pedantic = 1;
+            break;
+        default:
+            fprintf(stderr, "Unrecognized ahci_test option.\n");
+            g_assert_not_reached();
+        }
+    }
+
+    /* Check architecture */
+    arch = qtest_get_arch();
+    if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) {
+        g_test_message("Skipping test for non-x86");
+        return 0;
+    }
+
+    /* Create a temporary image */
+    fd = mkstemp(tmp_path);
+    g_assert(fd >= 0);
+    if (have_qemu_img()) {
+        imgfmt = "qcow2";
+        test_image_size_mb = TEST_IMAGE_SIZE_MB_LARGE;
+        mkqcow2(tmp_path, TEST_IMAGE_SIZE_MB_LARGE);
+    } else {
+        g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
+                       "skipping LBA48 high-sector tests");
+        imgfmt = "raw";
+        test_image_size_mb = TEST_IMAGE_SIZE_MB_SMALL;
+        ret = ftruncate(fd, test_image_size_mb * 1024 * 1024);
+        g_assert(ret == 0);
+    }
+    close(fd);
+
+    /* Create temporary blkdebug instructions */
+    fd = mkstemp(debug_path);
+    g_assert(fd >= 0);
+    close(fd);
+
+    /* Reserve a hollow file to use as a socket for migration tests */
+    fd = mkstemp(mig_socket);
+    g_assert(fd >= 0);
+    close(fd);
+
+    /* Run the tests */
+    qtest_add_func("/ahci/sanity",     test_sanity);
+    qtest_add_func("/ahci/pci_spec",   test_pci_spec);
+    qtest_add_func("/ahci/pci_enable", test_pci_enable);
+    qtest_add_func("/ahci/hba_spec",   test_hba_spec);
+    qtest_add_func("/ahci/hba_enable", test_hba_enable);
+    qtest_add_func("/ahci/identify",   test_identify);
+
+    for (i = MODE_BEGIN; i < NUM_MODES; i++) {
+        for (j = ADDR_MODE_BEGIN; j < NUM_ADDR_MODES; j++) {
+            for (k = LEN_BEGIN; k < NUM_LENGTHS; k++) {
+                for (m = OFFSET_BEGIN; m < NUM_OFFSETS; m++) {
+                    create_ahci_io_test(i, j, k, m);
+                }
+            }
+        }
+    }
+
+    qtest_add_func("/ahci/io/dma/lba28/fragmented", test_dma_fragmented);
+
+    qtest_add_func("/ahci/flush/simple", test_flush);
+    qtest_add_func("/ahci/flush/retry", test_flush_retry);
+    qtest_add_func("/ahci/flush/migrate", test_flush_migrate);
+
+    qtest_add_func("/ahci/migrate/sanity", test_migrate_sanity);
+    qtest_add_func("/ahci/migrate/dma/simple", test_migrate_dma);
+    qtest_add_func("/ahci/io/dma/lba28/retry", test_halted_dma);
+    qtest_add_func("/ahci/migrate/dma/halted", test_migrate_halted_dma);
+
+    qtest_add_func("/ahci/max", test_max);
+    qtest_add_func("/ahci/reset", test_reset);
+
+    qtest_add_func("/ahci/io/ncq/simple", test_ncq_simple);
+    qtest_add_func("/ahci/migrate/ncq/simple", test_migrate_ncq);
+    qtest_add_func("/ahci/io/ncq/retry", test_halted_ncq);
+    qtest_add_func("/ahci/migrate/ncq/halted", test_migrate_halted_ncq);
+
+    qtest_add_func("/ahci/cdrom/dma/single", test_cdrom_dma);
+    qtest_add_func("/ahci/cdrom/dma/multi", test_cdrom_dma_multi);
+    qtest_add_func("/ahci/cdrom/pio/single", test_cdrom_pio);
+    qtest_add_func("/ahci/cdrom/pio/multi", test_cdrom_pio_multi);
+
+    qtest_add_func("/ahci/cdrom/pio/bcl", test_atapi_bcl);
+    qtest_add_func("/ahci/cdrom/eject", test_atapi_tray);
+
+    ret = g_test_run();
+
+    /* Cleanup */
+    unlink(tmp_path);
+    unlink(debug_path);
+    unlink(mig_socket);
+
+    return ret;
+}
diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c
new file mode 100644 (file)
index 0000000..bef3ed2
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ * Arm CPU feature test cases
+ *
+ * Copyright (c) 2019 Red Hat Inc.
+ * Authors:
+ *  Andrew Jones <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qjson.h"
+
+/*
+ * We expect the SVE max-vq to be 16. Also it must be <= 64
+ * for our test code, otherwise 'vls' can't just be a uint64_t.
+ */
+#define SVE_MAX_VQ 16
+
+#define MACHINE     "-machine virt,gic-version=max -accel tcg "
+#define MACHINE_KVM "-machine virt,gic-version=max -accel kvm -accel tcg "
+#define QUERY_HEAD  "{ 'execute': 'query-cpu-model-expansion', " \
+                    "  'arguments': { 'type': 'full', "
+#define QUERY_TAIL  "}}"
+
+static bool kvm_enabled(QTestState *qts)
+{
+    QDict *resp, *qdict;
+    bool enabled;
+
+    resp = qtest_qmp(qts, "{ 'execute': 'query-kvm' }");
+    g_assert(qdict_haskey(resp, "return"));
+    qdict = qdict_get_qdict(resp, "return");
+    g_assert(qdict_haskey(qdict, "enabled"));
+    enabled = qdict_get_bool(qdict, "enabled");
+    qobject_unref(resp);
+
+    return enabled;
+}
+
+static QDict *do_query_no_props(QTestState *qts, const char *cpu_type)
+{
+    return qtest_qmp(qts, QUERY_HEAD "'model': { 'name': %s }"
+                          QUERY_TAIL, cpu_type);
+}
+
+static QDict *do_query(QTestState *qts, const char *cpu_type,
+                       const char *fmt, ...)
+{
+    QDict *resp;
+
+    if (fmt) {
+        QDict *args;
+        va_list ap;
+
+        va_start(ap, fmt);
+        args = qdict_from_vjsonf_nofail(fmt, ap);
+        va_end(ap);
+
+        resp = qtest_qmp(qts, QUERY_HEAD "'model': { 'name': %s, "
+                                                    "'props': %p }"
+                              QUERY_TAIL, cpu_type, args);
+    } else {
+        resp = do_query_no_props(qts, cpu_type);
+    }
+
+    return resp;
+}
+
+static const char *resp_get_error(QDict *resp)
+{
+    QDict *qdict;
+
+    g_assert(resp);
+
+    qdict = qdict_get_qdict(resp, "error");
+    if (qdict) {
+        return qdict_get_str(qdict, "desc");
+    }
+
+    return NULL;
+}
+
+#define assert_error(qts, cpu_type, expected_error, fmt, ...)          \
+({                                                                     \
+    QDict *_resp;                                                      \
+    const char *_error;                                                \
+                                                                       \
+    _resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);               \
+    g_assert(_resp);                                                   \
+    _error = resp_get_error(_resp);                                    \
+    g_assert(_error);                                                  \
+    g_assert(g_str_equal(_error, expected_error));                     \
+    qobject_unref(_resp);                                              \
+})
+
+static bool resp_has_props(QDict *resp)
+{
+    QDict *qdict;
+
+    g_assert(resp);
+
+    if (!qdict_haskey(resp, "return")) {
+        return false;
+    }
+    qdict = qdict_get_qdict(resp, "return");
+
+    if (!qdict_haskey(qdict, "model")) {
+        return false;
+    }
+    qdict = qdict_get_qdict(qdict, "model");
+
+    return qdict_haskey(qdict, "props");
+}
+
+static QDict *resp_get_props(QDict *resp)
+{
+    QDict *qdict;
+
+    g_assert(resp);
+    g_assert(resp_has_props(resp));
+
+    qdict = qdict_get_qdict(resp, "return");
+    qdict = qdict_get_qdict(qdict, "model");
+    qdict = qdict_get_qdict(qdict, "props");
+
+    return qdict;
+}
+
+static bool resp_get_feature(QDict *resp, const char *feature)
+{
+    QDict *props;
+
+    g_assert(resp);
+    g_assert(resp_has_props(resp));
+    props = resp_get_props(resp);
+    g_assert(qdict_get(props, feature));
+    return qdict_get_bool(props, feature);
+}
+
+#define assert_has_feature(qts, cpu_type, feature)                     \
+({                                                                     \
+    QDict *_resp = do_query_no_props(qts, cpu_type);                   \
+    g_assert(_resp);                                                   \
+    g_assert(resp_has_props(_resp));                                   \
+    g_assert(qdict_get(resp_get_props(_resp), feature));               \
+    qobject_unref(_resp);                                              \
+})
+
+#define assert_has_not_feature(qts, cpu_type, feature)                 \
+({                                                                     \
+    QDict *_resp = do_query_no_props(qts, cpu_type);                   \
+    g_assert(_resp);                                                   \
+    g_assert(!resp_has_props(_resp) ||                                 \
+             !qdict_get(resp_get_props(_resp), feature));              \
+    qobject_unref(_resp);                                              \
+})
+
+static void assert_type_full(QTestState *qts)
+{
+    const char *error;
+    QDict *resp;
+
+    resp = qtest_qmp(qts, "{ 'execute': 'query-cpu-model-expansion', "
+                            "'arguments': { 'type': 'static', "
+                                           "'model': { 'name': 'foo' }}}");
+    g_assert(resp);
+    error = resp_get_error(resp);
+    g_assert(error);
+    g_assert(g_str_equal(error,
+                         "The requested expansion type is not supported"));
+    qobject_unref(resp);
+}
+
+static void assert_bad_props(QTestState *qts, const char *cpu_type)
+{
+    const char *error;
+    QDict *resp;
+
+    resp = qtest_qmp(qts, "{ 'execute': 'query-cpu-model-expansion', "
+                            "'arguments': { 'type': 'full', "
+                                           "'model': { 'name': %s, "
+                                                      "'props': false }}}",
+                     cpu_type);
+    g_assert(resp);
+    error = resp_get_error(resp);
+    g_assert(error);
+    g_assert(g_str_equal(error,
+                         "Invalid parameter type for 'props', expected: dict"));
+    qobject_unref(resp);
+}
+
+static uint64_t resp_get_sve_vls(QDict *resp)
+{
+    QDict *props;
+    const QDictEntry *e;
+    uint64_t vls = 0;
+    int n = 0;
+
+    g_assert(resp);
+    g_assert(resp_has_props(resp));
+
+    props = resp_get_props(resp);
+
+    for (e = qdict_first(props); e; e = qdict_next(props, e)) {
+        if (strlen(e->key) > 3 && !strncmp(e->key, "sve", 3) &&
+            g_ascii_isdigit(e->key[3])) {
+            char *endptr;
+            int bits;
+
+            bits = g_ascii_strtoll(&e->key[3], &endptr, 10);
+            if (!bits || *endptr != '\0') {
+                continue;
+            }
+
+            if (qdict_get_bool(props, e->key)) {
+                vls |= BIT_ULL((bits / 128) - 1);
+            }
+            ++n;
+        }
+    }
+
+    g_assert(n == SVE_MAX_VQ);
+
+    return vls;
+}
+
+#define assert_sve_vls(qts, cpu_type, expected_vls, fmt, ...)          \
+({                                                                     \
+    QDict *_resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);        \
+    g_assert(_resp);                                                   \
+    g_assert(resp_has_props(_resp));                                   \
+    g_assert(resp_get_sve_vls(_resp) == expected_vls);                 \
+    qobject_unref(_resp);                                              \
+})
+
+static void sve_tests_default(QTestState *qts, const char *cpu_type)
+{
+    /*
+     * With no sve-max-vq or sve<N> properties on the command line
+     * the default is to have all vector lengths enabled. This also
+     * tests that 'sve' is 'on' by default.
+     */
+    assert_sve_vls(qts, cpu_type, BIT_ULL(SVE_MAX_VQ) - 1, NULL);
+
+    /* With SVE off, all vector lengths should also be off. */
+    assert_sve_vls(qts, cpu_type, 0, "{ 'sve': false }");
+
+    /* With SVE on, we must have at least one vector length enabled. */
+    assert_error(qts, cpu_type, "cannot disable sve128", "{ 'sve128': false }");
+
+    /* Basic enable/disable tests. */
+    assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve384': true }");
+    assert_sve_vls(qts, cpu_type, ((BIT_ULL(SVE_MAX_VQ) - 1) & ~BIT_ULL(2)),
+                   "{ 'sve384': false }");
+
+    /*
+     * ---------------------------------------------------------------------
+     *               power-of-two(vq)   all-power-            can      can
+     *                                  of-two(< vq)        enable   disable
+     * ---------------------------------------------------------------------
+     * vq < max_vq      no                MUST*              yes      yes
+     * vq < max_vq      yes               MUST*              yes      no
+     * ---------------------------------------------------------------------
+     * vq == max_vq     n/a               MUST*              yes**    yes**
+     * ---------------------------------------------------------------------
+     * vq > max_vq      n/a               no                 no       yes
+     * vq > max_vq      n/a               yes                yes      yes
+     * ---------------------------------------------------------------------
+     *
+     * [*] "MUST" means this requirement must already be satisfied,
+     *     otherwise 'max_vq' couldn't itself be enabled.
+     *
+     * [**] Not testable with the QMP interface, only with the command line.
+     */
+
+    /* max_vq := 8 */
+    assert_sve_vls(qts, cpu_type, 0x8b, "{ 'sve1024': true }");
+
+    /* max_vq := 8, vq < max_vq, !power-of-two(vq) */
+    assert_sve_vls(qts, cpu_type, 0x8f,
+                   "{ 'sve1024': true, 'sve384': true }");
+    assert_sve_vls(qts, cpu_type, 0x8b,
+                   "{ 'sve1024': true, 'sve384': false }");
+
+    /* max_vq := 8, vq < max_vq, power-of-two(vq) */
+    assert_sve_vls(qts, cpu_type, 0x8b,
+                   "{ 'sve1024': true, 'sve256': true }");
+    assert_error(qts, cpu_type, "cannot disable sve256",
+                 "{ 'sve1024': true, 'sve256': false }");
+
+    /* max_vq := 3, vq > max_vq, !all-power-of-two(< vq) */
+    assert_error(qts, cpu_type, "cannot disable sve512",
+                 "{ 'sve384': true, 'sve512': false, 'sve640': true }");
+
+    /*
+     * We can disable power-of-two vector lengths when all larger lengths
+     * are also disabled. We only need to disable the power-of-two length,
+     * as all non-enabled larger lengths will then be auto-disabled.
+     */
+    assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve512': false }");
+
+    /* max_vq := 3, vq > max_vq, all-power-of-two(< vq) */
+    assert_sve_vls(qts, cpu_type, 0x1f,
+                   "{ 'sve384': true, 'sve512': true, 'sve640': true }");
+    assert_sve_vls(qts, cpu_type, 0xf,
+                   "{ 'sve384': true, 'sve512': true, 'sve640': false }");
+}
+
+static void sve_tests_sve_max_vq_8(const void *data)
+{
+    QTestState *qts;
+
+    qts = qtest_init(MACHINE "-cpu max,sve-max-vq=8");
+
+    assert_sve_vls(qts, "max", BIT_ULL(8) - 1, NULL);
+
+    /*
+     * Disabling the max-vq set by sve-max-vq is not allowed, but
+     * of course enabling it is OK.
+     */
+    assert_error(qts, "max", "cannot disable sve1024", "{ 'sve1024': false }");
+    assert_sve_vls(qts, "max", 0xff, "{ 'sve1024': true }");
+
+    /*
+     * Enabling anything larger than max-vq set by sve-max-vq is not
+     * allowed, but of course disabling everything larger is OK.
+     */
+    assert_error(qts, "max", "cannot enable sve1152", "{ 'sve1152': true }");
+    assert_sve_vls(qts, "max", 0xff, "{ 'sve1152': false }");
+
+    /*
+     * We can enable/disable non power-of-two lengths smaller than the
+     * max-vq set by sve-max-vq, but, while we can enable power-of-two
+     * lengths, we can't disable them.
+     */
+    assert_sve_vls(qts, "max", 0xff, "{ 'sve384': true }");
+    assert_sve_vls(qts, "max", 0xfb, "{ 'sve384': false }");
+    assert_sve_vls(qts, "max", 0xff, "{ 'sve256': true }");
+    assert_error(qts, "max", "cannot disable sve256", "{ 'sve256': false }");
+
+    qtest_quit(qts);
+}
+
+static void sve_tests_sve_off(const void *data)
+{
+    QTestState *qts;
+
+    qts = qtest_init(MACHINE "-cpu max,sve=off");
+
+    /* SVE is off, so the map should be empty. */
+    assert_sve_vls(qts, "max", 0, NULL);
+
+    /* The map stays empty even if we turn lengths off. */
+    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
+
+    /* It's an error to enable lengths when SVE is off. */
+    assert_error(qts, "max", "cannot enable sve128", "{ 'sve128': true }");
+
+    /* With SVE re-enabled we should get all vector lengths enabled. */
+    assert_sve_vls(qts, "max", BIT_ULL(SVE_MAX_VQ) - 1, "{ 'sve': true }");
+
+    /* Or enable SVE with just specific vector lengths. */
+    assert_sve_vls(qts, "max", 0x3,
+                   "{ 'sve': true, 'sve128': true, 'sve256': true }");
+
+    qtest_quit(qts);
+}
+
+static void sve_tests_sve_off_kvm(const void *data)
+{
+    QTestState *qts;
+
+    qts = qtest_init(MACHINE_KVM "-cpu max,sve=off");
+
+    /*
+     * We don't know if this host supports SVE so we don't
+     * attempt to test enabling anything. We only test that
+     * everything is disabled (as it should be with sve=off)
+     * and that using sve<N>=off to explicitly disable vector
+     * lengths is OK too.
+     */
+    assert_sve_vls(qts, "max", 0, NULL);
+    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
+
+    qtest_quit(qts);
+}
+
+static void test_query_cpu_model_expansion(const void *data)
+{
+    QTestState *qts;
+
+    qts = qtest_init(MACHINE "-cpu max");
+
+    /* Test common query-cpu-model-expansion input validation */
+    assert_type_full(qts);
+    assert_bad_props(qts, "max");
+    assert_error(qts, "foo", "The CPU type 'foo' is not a recognized "
+                 "ARM CPU type", NULL);
+    assert_error(qts, "max", "Parameter 'not-a-prop' is unexpected",
+                 "{ 'not-a-prop': false }");
+    assert_error(qts, "host", "The CPU type 'host' requires KVM", NULL);
+
+    /* Test expected feature presence/absence for some cpu types */
+    assert_has_feature(qts, "max", "pmu");
+    assert_has_feature(qts, "cortex-a15", "pmu");
+    assert_has_not_feature(qts, "cortex-a15", "aarch64");
+
+    if (g_str_equal(qtest_get_arch(), "aarch64")) {
+        assert_has_feature(qts, "max", "aarch64");
+        assert_has_feature(qts, "max", "sve");
+        assert_has_feature(qts, "max", "sve128");
+        assert_has_feature(qts, "cortex-a57", "pmu");
+        assert_has_feature(qts, "cortex-a57", "aarch64");
+
+        sve_tests_default(qts, "max");
+
+        /* Test that features that depend on KVM generate errors without. */
+        assert_error(qts, "max",
+                     "'aarch64' feature cannot be disabled "
+                     "unless KVM is enabled and 32-bit EL1 "
+                     "is supported",
+                     "{ 'aarch64': false }");
+    }
+
+    qtest_quit(qts);
+}
+
+static void test_query_cpu_model_expansion_kvm(const void *data)
+{
+    QTestState *qts;
+
+    qts = qtest_init(MACHINE_KVM "-cpu max");
+
+    /*
+     * These tests target the 'host' CPU type, so KVM must be enabled.
+     */
+    if (!kvm_enabled(qts)) {
+        qtest_quit(qts);
+        return;
+    }
+
+    if (g_str_equal(qtest_get_arch(), "aarch64")) {
+        bool kvm_supports_sve;
+        char max_name[8], name[8];
+        uint32_t max_vq, vq;
+        uint64_t vls;
+        QDict *resp;
+        char *error;
+
+        assert_has_feature(qts, "host", "aarch64");
+        assert_has_feature(qts, "host", "pmu");
+
+        assert_error(qts, "cortex-a15",
+            "We cannot guarantee the CPU type 'cortex-a15' works "
+            "with KVM on this host", NULL);
+
+        assert_has_feature(qts, "host", "sve");
+        resp = do_query_no_props(qts, "host");
+        kvm_supports_sve = resp_get_feature(resp, "sve");
+        vls = resp_get_sve_vls(resp);
+        qobject_unref(resp);
+
+        if (kvm_supports_sve) {
+            g_assert(vls != 0);
+            max_vq = 64 - __builtin_clzll(vls);
+            sprintf(max_name, "sve%d", max_vq * 128);
+
+            /* Enabling a supported length is of course fine. */
+            assert_sve_vls(qts, "host", vls, "{ %s: true }", max_name);
+
+            /* Get the next supported length smaller than max-vq. */
+            vq = 64 - __builtin_clzll(vls & ~BIT_ULL(max_vq - 1));
+            if (vq) {
+                /*
+                 * We have at least one length smaller than max-vq,
+                 * so we can disable max-vq.
+                 */
+                assert_sve_vls(qts, "host", (vls & ~BIT_ULL(max_vq - 1)),
+                               "{ %s: false }", max_name);
+
+                /*
+                 * Smaller, supported vector lengths cannot be disabled
+                 * unless all larger, supported vector lengths are also
+                 * disabled.
+                 */
+                sprintf(name, "sve%d", vq * 128);
+                error = g_strdup_printf("cannot disable %s", name);
+                assert_error(qts, "host", error,
+                             "{ %s: true, %s: false }",
+                             max_name, name);
+                g_free(error);
+            }
+
+            /*
+             * The smallest, supported vector length is required, because
+             * we need at least one vector length enabled.
+             */
+            vq = __builtin_ffsll(vls);
+            sprintf(name, "sve%d", vq * 128);
+            error = g_strdup_printf("cannot disable %s", name);
+            assert_error(qts, "host", error, "{ %s: false }", name);
+            g_free(error);
+
+            /* Get an unsupported length. */
+            for (vq = 1; vq <= max_vq; ++vq) {
+                if (!(vls & BIT_ULL(vq - 1))) {
+                    break;
+                }
+            }
+            if (vq <= SVE_MAX_VQ) {
+                sprintf(name, "sve%d", vq * 128);
+                error = g_strdup_printf("cannot enable %s", name);
+                assert_error(qts, "host", error, "{ %s: true }", name);
+                g_free(error);
+            }
+        } else {
+            g_assert(vls == 0);
+        }
+    } else {
+        assert_has_not_feature(qts, "host", "aarch64");
+        assert_has_not_feature(qts, "host", "pmu");
+        assert_has_not_feature(qts, "host", "sve");
+    }
+
+    qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_data_func("/arm/query-cpu-model-expansion",
+                        NULL, test_query_cpu_model_expansion);
+
+    /*
+     * For now we only run KVM specific tests with AArch64 QEMU in
+     * order avoid attempting to run an AArch32 QEMU with KVM on
+     * AArch64 hosts. That won't work and isn't easy to detect.
+     */
+    if (g_str_equal(qtest_get_arch(), "aarch64")) {
+        qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
+                            NULL, test_query_cpu_model_expansion_kvm);
+    }
+
+    if (g_str_equal(qtest_get_arch(), "aarch64")) {
+        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-max-vq-8",
+                            NULL, sve_tests_sve_max_vq_8);
+        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-off",
+                            NULL, sve_tests_sve_off);
+        qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off",
+                            NULL, sve_tests_sve_off_kvm);
+    }
+
+    return g_test_run();
+}
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
new file mode 100644 (file)
index 0000000..dfb8523
--- /dev/null
@@ -0,0 +1 @@
+/* List of comma-separated changed AML files to ignore */
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
new file mode 100644 (file)
index 0000000..f1ac2d7
--- /dev/null
@@ -0,0 +1,1046 @@
+/*
+ * Boot order test cases.
+ *
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * Authors:
+ *  Michael S. Tsirkin <[email protected]>,
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+/*
+ * How to add or update the tests:
+ * Contributor:
+ * 1. add empty files for new tables, if any, under tests/data/acpi
+ * 2. list any changed files in tests/bios-tables-test-allowed-diff.h
+ * 3. commit the above *before* making changes that affect the tables
+ * Maintainer:
+ * After 1-3 above tests will pass but ignore differences with the expected files.
+ * You will also notice that tests/bios-tables-test-allowed-diff.h lists
+ * a bunch of files. This is your hint that you need to do the below:
+ * 4. Run
+ *      make check V=1
+ * this will produce a bunch of warnings about differences
+ * beween actual and expected ACPI tables. If you have IASL installed,
+ * they will also be disassembled so you can look at the disassembled
+ * output. If not - disassemble them yourself in any way you like.
+ * Look at the differences - make sure they make sense and match what the
+ * changes you are merging are supposed to do.
+ *
+ * 5. From build directory, run:
+ *      $(SRC_PATH)/tests/data/acpi/rebuild-expected-aml.sh
+ * 6. Now commit any changes.
+ * 7. Before doing a pull request, make sure tests/bios-tables-test-allowed-diff.h
+ *    is empty - this will ensure following changes to ACPI tables will
+ *    be noticed.
+ */
+
+#include "qemu/osdep.h"
+#include <glib/gstdio.h>
+#include "qemu-common.h"
+#include "hw/firmware/smbios.h"
+#include "qemu/bitmap.h"
+#include "acpi-utils.h"
+#include "boot-sector.h"
+
+#define MACHINE_PC "pc"
+#define MACHINE_Q35 "q35"
+
+#define ACPI_REBUILD_EXPECTED_AML "TEST_ACPI_REBUILD_AML"
+
+typedef struct {
+    bool tcg_only;
+    const char *machine;
+    const char *variant;
+    const char *uefi_fl1;
+    const char *uefi_fl2;
+    const char *cd;
+    const uint64_t ram_start;
+    const uint64_t scan_len;
+    uint64_t rsdp_addr;
+    uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
+    GArray *tables;
+    uint32_t smbios_ep_addr;
+    struct smbios_21_entry_point smbios_ep_table;
+    uint8_t *required_struct_types;
+    int required_struct_types_len;
+    QTestState *qts;
+} test_data;
+
+static char disk[] = "tests/acpi-test-disk-XXXXXX";
+static const char *data_dir = "tests/data/acpi";
+#ifdef CONFIG_IASL
+static const char *iasl = stringify(CONFIG_IASL);
+#else
+static const char *iasl;
+#endif
+
+static bool compare_signature(const AcpiSdtTable *sdt, const char *signature)
+{
+   return !memcmp(sdt->aml, signature, 4);
+}
+
+static void cleanup_table_descriptor(AcpiSdtTable *table)
+{
+    g_free(table->aml);
+    if (table->aml_file &&
+        !table->tmp_files_retain &&
+        g_strstr_len(table->aml_file, -1, "aml-")) {
+        unlink(table->aml_file);
+    }
+    g_free(table->aml_file);
+    g_free(table->asl);
+    if (table->asl_file &&
+        !table->tmp_files_retain) {
+        unlink(table->asl_file);
+    }
+    g_free(table->asl_file);
+}
+
+static void free_test_data(test_data *data)
+{
+    int i;
+
+    for (i = 0; i < data->tables->len; ++i) {
+        cleanup_table_descriptor(&g_array_index(data->tables, AcpiSdtTable, i));
+    }
+
+    g_array_free(data->tables, true);
+}
+
+static void test_acpi_rsdp_table(test_data *data)
+{
+    uint8_t *rsdp_table = data->rsdp_table;
+
+    acpi_fetch_rsdp_table(data->qts, data->rsdp_addr, rsdp_table);
+
+    switch (rsdp_table[15 /* Revision offset */]) {
+    case 0: /* ACPI 1.0 RSDP */
+        /* With rev 1, checksum is only for the first 20 bytes */
+        g_assert(!acpi_calc_checksum(rsdp_table,  20));
+        break;
+    case 2: /* ACPI 2.0+ RSDP */
+        /* With revision 2, we have 2 checksums */
+        g_assert(!acpi_calc_checksum(rsdp_table, 20));
+        g_assert(!acpi_calc_checksum(rsdp_table, 36));
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void test_acpi_rxsdt_table(test_data *data)
+{
+    const char *sig = "RSDT";
+    AcpiSdtTable rsdt = {};
+    int entry_size = 4;
+    int addr_off = 16 /* RsdtAddress */;
+    uint8_t *ent;
+
+    if (data->rsdp_table[15 /* Revision offset */] != 0) {
+        addr_off = 24 /* XsdtAddress */;
+        entry_size = 8;
+        sig = "XSDT";
+    }
+    /* read [RX]SDT table */
+    acpi_fetch_table(data->qts, &rsdt.aml, &rsdt.aml_len,
+                     &data->rsdp_table[addr_off], entry_size, sig, true);
+
+    /* Load all tables and add to test list directly RSDT referenced tables */
+    ACPI_FOREACH_RSDT_ENTRY(rsdt.aml, rsdt.aml_len, ent, entry_size) {
+        AcpiSdtTable ssdt_table = {};
+
+        acpi_fetch_table(data->qts, &ssdt_table.aml, &ssdt_table.aml_len, ent,
+                         entry_size, NULL, true);
+        /* Add table to ASL test tables list */
+        g_array_append_val(data->tables, ssdt_table);
+    }
+    cleanup_table_descriptor(&rsdt);
+}
+
+static void test_acpi_fadt_table(test_data *data)
+{
+    /* FADT table is 1st */
+    AcpiSdtTable table = g_array_index(data->tables, typeof(table), 0);
+    uint8_t *fadt_aml = table.aml;
+    uint32_t fadt_len = table.aml_len;
+    uint32_t val;
+    int dsdt_offset = 40 /* DSDT */;
+    int dsdt_entry_size = 4;
+
+    g_assert(compare_signature(&table, "FACP"));
+
+    /* Since DSDT/FACS isn't in RSDT, add them to ASL test list manually */
+    memcpy(&val, fadt_aml + 112 /* Flags */, 4);
+    val = le32_to_cpu(val);
+    if (!(val & 1UL << 20 /* HW_REDUCED_ACPI */)) {
+        acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
+                         fadt_aml + 36 /* FIRMWARE_CTRL */, 4, "FACS", false);
+        g_array_append_val(data->tables, table);
+    }
+
+    memcpy(&val, fadt_aml + dsdt_offset, 4);
+    val = le32_to_cpu(val);
+    if (!val) {
+        dsdt_offset = 140 /* X_DSDT */;
+        dsdt_entry_size = 8;
+    }
+    acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
+                     fadt_aml + dsdt_offset, dsdt_entry_size, "DSDT", true);
+    g_array_append_val(data->tables, table);
+
+    memset(fadt_aml + 36, 0, 4); /* sanitize FIRMWARE_CTRL ptr */
+    memset(fadt_aml + 40, 0, 4); /* sanitize DSDT ptr */
+    if (fadt_aml[8 /* FADT Major Version */] >= 3) {
+        memset(fadt_aml + 132, 0, 8); /* sanitize X_FIRMWARE_CTRL ptr */
+        memset(fadt_aml + 140, 0, 8); /* sanitize X_DSDT ptr */
+    }
+
+    /* update checksum */
+    fadt_aml[9 /* Checksum */] = 0;
+    fadt_aml[9 /* Checksum */] -= acpi_calc_checksum(fadt_aml, fadt_len);
+}
+
+static void dump_aml_files(test_data *data, bool rebuild)
+{
+    AcpiSdtTable *sdt;
+    GError *error = NULL;
+    gchar *aml_file = NULL;
+    gint fd;
+    ssize_t ret;
+    int i;
+
+    for (i = 0; i < data->tables->len; ++i) {
+        const char *ext = data->variant ? data->variant : "";
+        sdt = &g_array_index(data->tables, AcpiSdtTable, i);
+        g_assert(sdt->aml);
+
+        if (rebuild) {
+            aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
+                                       sdt->aml, ext);
+            fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT,
+                        S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
+            if (fd < 0) {
+                perror(aml_file);
+            }
+            g_assert(fd >= 0);
+        } else {
+            fd = g_file_open_tmp("aml-XXXXXX", &sdt->aml_file, &error);
+            g_assert_no_error(error);
+        }
+
+        ret = qemu_write_full(fd, sdt->aml, sdt->aml_len);
+        g_assert(ret == sdt->aml_len);
+
+        close(fd);
+
+        g_free(aml_file);
+    }
+}
+
+static bool load_asl(GArray *sdts, AcpiSdtTable *sdt)
+{
+    AcpiSdtTable *temp;
+    GError *error = NULL;
+    GString *command_line = g_string_new(iasl);
+    gint fd;
+    gchar *out, *out_err;
+    gboolean ret;
+    int i;
+
+    fd = g_file_open_tmp("asl-XXXXXX.dsl", &sdt->asl_file, &error);
+    g_assert_no_error(error);
+    close(fd);
+
+    /* build command line */
+    g_string_append_printf(command_line, " -p %s ", sdt->asl_file);
+    if (compare_signature(sdt, "DSDT") ||
+        compare_signature(sdt, "SSDT")) {
+        for (i = 0; i < sdts->len; ++i) {
+            temp = &g_array_index(sdts, AcpiSdtTable, i);
+            if (compare_signature(temp, "DSDT") ||
+                compare_signature(temp, "SSDT")) {
+                g_string_append_printf(command_line, "-e %s ", temp->aml_file);
+            }
+        }
+    }
+    g_string_append_printf(command_line, "-d %s", sdt->aml_file);
+
+    /* pass 'out' and 'out_err' in order to be redirected */
+    ret = g_spawn_command_line_sync(command_line->str, &out, &out_err, NULL, &error);
+    g_assert_no_error(error);
+    if (ret) {
+        ret = g_file_get_contents(sdt->asl_file, &sdt->asl,
+                                  &sdt->asl_len, &error);
+        g_assert(ret);
+        g_assert_no_error(error);
+        ret = (sdt->asl_len > 0);
+    }
+
+    g_free(out);
+    g_free(out_err);
+    g_string_free(command_line, true);
+
+    return !ret;
+}
+
+#define COMMENT_END "*/"
+#define DEF_BLOCK "DefinitionBlock ("
+#define BLOCK_NAME_END ","
+
+static GString *normalize_asl(gchar *asl_code)
+{
+    GString *asl = g_string_new(asl_code);
+    gchar *comment, *block_name;
+
+    /* strip comments (different generation days) */
+    comment = g_strstr_len(asl->str, asl->len, COMMENT_END);
+    if (comment) {
+        comment += strlen(COMMENT_END);
+        while (*comment == '\n') {
+            comment++;
+        }
+        asl = g_string_erase(asl, 0, comment - asl->str);
+    }
+
+    /* strip def block name (it has file path in it) */
+    if (g_str_has_prefix(asl->str, DEF_BLOCK)) {
+        block_name = g_strstr_len(asl->str, asl->len, BLOCK_NAME_END);
+        g_assert(block_name);
+        asl = g_string_erase(asl, 0,
+                             block_name + sizeof(BLOCK_NAME_END) - asl->str);
+    }
+
+    return asl;
+}
+
+static GArray *load_expected_aml(test_data *data)
+{
+    int i;
+    AcpiSdtTable *sdt;
+    GError *error = NULL;
+    gboolean ret;
+    gsize aml_len;
+
+    GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable));
+    if (getenv("V")) {
+        fputc('\n', stderr);
+    }
+    for (i = 0; i < data->tables->len; ++i) {
+        AcpiSdtTable exp_sdt;
+        gchar *aml_file = NULL;
+        const char *ext = data->variant ? data->variant : "";
+
+        sdt = &g_array_index(data->tables, AcpiSdtTable, i);
+
+        memset(&exp_sdt, 0, sizeof(exp_sdt));
+
+try_again:
+        aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
+                                   sdt->aml, ext);
+        if (getenv("V")) {
+            fprintf(stderr, "Looking for expected file '%s'\n", aml_file);
+        }
+        if (g_file_test(aml_file, G_FILE_TEST_EXISTS)) {
+            exp_sdt.aml_file = aml_file;
+        } else if (*ext != '\0') {
+            /* try fallback to generic (extension less) expected file */
+            ext = "";
+            g_free(aml_file);
+            goto try_again;
+        }
+        g_assert(exp_sdt.aml_file);
+        if (getenv("V")) {
+            fprintf(stderr, "Using expected file '%s'\n", aml_file);
+        }
+        ret = g_file_get_contents(aml_file, (gchar **)&exp_sdt.aml,
+                                  &aml_len, &error);
+        exp_sdt.aml_len = aml_len;
+        g_assert(ret);
+        g_assert_no_error(error);
+        g_assert(exp_sdt.aml);
+        if (!exp_sdt.aml_len) {
+            fprintf(stderr, "Warning! zero length expected file '%s'\n",
+                    aml_file);
+        }
+
+        g_array_append_val(exp_tables, exp_sdt);
+    }
+
+    return exp_tables;
+}
+
+static bool test_acpi_find_diff_allowed(AcpiSdtTable *sdt)
+{
+    const gchar *allowed_diff_file[] = {
+#include "bios-tables-test-allowed-diff.h"
+        NULL
+    };
+    const gchar **f;
+
+    for (f = allowed_diff_file; *f; ++f) {
+        if (!g_strcmp0(sdt->aml_file, *f)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/* test the list of tables in @data->tables against reference tables */
+static void test_acpi_asl(test_data *data)
+{
+    int i;
+    AcpiSdtTable *sdt, *exp_sdt;
+    test_data exp_data;
+    gboolean exp_err, err, all_tables_match = true;
+
+    memset(&exp_data, 0, sizeof(exp_data));
+    exp_data.tables = load_expected_aml(data);
+    dump_aml_files(data, false);
+    for (i = 0; i < data->tables->len; ++i) {
+        GString *asl, *exp_asl;
+
+        sdt = &g_array_index(data->tables, AcpiSdtTable, i);
+        exp_sdt = &g_array_index(exp_data.tables, AcpiSdtTable, i);
+
+        if (sdt->aml_len == exp_sdt->aml_len &&
+            !memcmp(sdt->aml, exp_sdt->aml, sdt->aml_len)) {
+            /* Identical table binaries: no need to disassemble. */
+            continue;
+        }
+
+        fprintf(stderr,
+                "acpi-test: Warning! %.4s binary file mismatch. "
+                "Actual [aml:%s], Expected [aml:%s].\n",
+                exp_sdt->aml, sdt->aml_file, exp_sdt->aml_file);
+
+        all_tables_match = all_tables_match &&
+            test_acpi_find_diff_allowed(exp_sdt);
+
+        /*
+         *  don't try to decompile if IASL isn't present, in this case user
+         * will just 'get binary file mismatch' warnings and test failure
+         */
+        if (!iasl) {
+            continue;
+        }
+
+        err = load_asl(data->tables, sdt);
+        asl = normalize_asl(sdt->asl);
+
+        exp_err = load_asl(exp_data.tables, exp_sdt);
+        exp_asl = normalize_asl(exp_sdt->asl);
+
+        /* TODO: check for warnings */
+        g_assert(!err || exp_err);
+
+        if (g_strcmp0(asl->str, exp_asl->str)) {
+            sdt->tmp_files_retain = true;
+            if (exp_err) {
+                fprintf(stderr,
+                        "Warning! iasl couldn't parse the expected aml\n");
+            } else {
+                exp_sdt->tmp_files_retain = true;
+                fprintf(stderr,
+                        "acpi-test: Warning! %.4s mismatch. "
+                        "Actual [asl:%s, aml:%s], Expected [asl:%s, aml:%s].\n",
+                        exp_sdt->aml, sdt->asl_file, sdt->aml_file,
+                        exp_sdt->asl_file, exp_sdt->aml_file);
+                if (getenv("V")) {
+                    const char *diff_cmd = getenv("DIFF");
+                    if (diff_cmd) {
+                        int ret G_GNUC_UNUSED;
+                        char *diff = g_strdup_printf("%s %s %s", diff_cmd,
+                            exp_sdt->asl_file, sdt->asl_file);
+                        ret = system(diff) ;
+                        g_free(diff);
+                    } else {
+                        fprintf(stderr, "acpi-test: Warning. not showing "
+                            "difference since no diff utility is specified. "
+                            "Set 'DIFF' environment variable to a preferred "
+                            "diff utility and run 'make V=1 check' again to "
+                            "see ASL difference.");
+                    }
+                }
+            }
+        }
+        g_string_free(asl, true);
+        g_string_free(exp_asl, true);
+    }
+    if (!iasl && !all_tables_match) {
+        fprintf(stderr, "to see ASL diff between mismatched files install IASL,"
+                " rebuild QEMU from scratch and re-run tests with V=1"
+                " environment variable set");
+    }
+    g_assert(all_tables_match);
+
+    free_test_data(&exp_data);
+}
+
+static bool smbios_ep_table_ok(test_data *data)
+{
+    struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
+    uint32_t addr = data->smbios_ep_addr;
+
+    qtest_memread(data->qts, addr, ep_table, sizeof(*ep_table));
+    if (memcmp(ep_table->anchor_string, "_SM_", 4)) {
+        return false;
+    }
+    if (memcmp(ep_table->intermediate_anchor_string, "_DMI_", 5)) {
+        return false;
+    }
+    if (ep_table->structure_table_length == 0) {
+        return false;
+    }
+    if (ep_table->number_of_structures == 0) {
+        return false;
+    }
+    if (acpi_calc_checksum((uint8_t *)ep_table, sizeof *ep_table) ||
+        acpi_calc_checksum((uint8_t *)ep_table + 0x10,
+                           sizeof *ep_table - 0x10)) {
+        return false;
+    }
+    return true;
+}
+
+static void test_smbios_entry_point(test_data *data)
+{
+    uint32_t off;
+
+    /* find smbios entry point structure */
+    for (off = 0xf0000; off < 0x100000; off += 0x10) {
+        uint8_t sig[] = "_SM_";
+        int i;
+
+        for (i = 0; i < sizeof sig - 1; ++i) {
+            sig[i] = qtest_readb(data->qts, off + i);
+        }
+
+        if (!memcmp(sig, "_SM_", sizeof sig)) {
+            /* signature match, but is this a valid entry point? */
+            data->smbios_ep_addr = off;
+            if (smbios_ep_table_ok(data)) {
+                break;
+            }
+        }
+    }
+
+    g_assert_cmphex(off, <, 0x100000);
+}
+
+static inline bool smbios_single_instance(uint8_t type)
+{
+    switch (type) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 16:
+    case 32:
+    case 127:
+        return true;
+    default:
+        return false;
+    }
+}
+
+static void test_smbios_structs(test_data *data)
+{
+    DECLARE_BITMAP(struct_bitmap, SMBIOS_MAX_TYPE+1) = { 0 };
+    struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
+    uint32_t addr = le32_to_cpu(ep_table->structure_table_address);
+    int i, len, max_len = 0;
+    uint8_t type, prv, crt;
+
+    /* walk the smbios tables */
+    for (i = 0; i < le16_to_cpu(ep_table->number_of_structures); i++) {
+
+        /* grab type and formatted area length from struct header */
+        type = qtest_readb(data->qts, addr);
+        g_assert_cmpuint(type, <=, SMBIOS_MAX_TYPE);
+        len = qtest_readb(data->qts, addr + 1);
+
+        /* single-instance structs must not have been encountered before */
+        if (smbios_single_instance(type)) {
+            g_assert(!test_bit(type, struct_bitmap));
+        }
+        set_bit(type, struct_bitmap);
+
+        /* seek to end of unformatted string area of this struct ("\0\0") */
+        prv = crt = 1;
+        while (prv || crt) {
+            prv = crt;
+            crt = qtest_readb(data->qts, addr + len);
+            len++;
+        }
+
+        /* keep track of max. struct size */
+        if (max_len < len) {
+            max_len = len;
+            g_assert_cmpuint(max_len, <=, ep_table->max_structure_size);
+        }
+
+        /* start of next structure */
+        addr += len;
+    }
+
+    /* total table length and max struct size must match entry point values */
+    g_assert_cmpuint(le16_to_cpu(ep_table->structure_table_length), ==,
+                     addr - le32_to_cpu(ep_table->structure_table_address));
+    g_assert_cmpuint(le16_to_cpu(ep_table->max_structure_size), ==, max_len);
+
+    /* required struct types must all be present */
+    for (i = 0; i < data->required_struct_types_len; i++) {
+        g_assert(test_bit(data->required_struct_types[i], struct_bitmap));
+    }
+}
+
+static void test_acpi_one(const char *params, test_data *data)
+{
+    char *args;
+    bool use_uefi = data->uefi_fl1 && data->uefi_fl2;
+
+    if (use_uefi) {
+        /*
+         * TODO: convert '-drive if=pflash' to new syntax (see e33763be7cd3)
+         * when arm/virt boad starts to support it.
+         */
+        args = g_strdup_printf("-machine %s %s -accel tcg -nodefaults -nographic "
+            "-drive if=pflash,format=raw,file=%s,readonly "
+            "-drive if=pflash,format=raw,file=%s,snapshot=on -cdrom %s %s",
+            data->machine, data->tcg_only ? "" : "-accel kvm",
+            data->uefi_fl1, data->uefi_fl2, data->cd, params ? params : "");
+
+    } else {
+        /* Disable kernel irqchip to be able to override apic irq0. */
+        args = g_strdup_printf("-machine %s,kernel-irqchip=off %s -accel tcg "
+            "-net none -display none %s "
+            "-drive id=hd0,if=none,file=%s,format=raw "
+            "-device ide-hd,drive=hd0 ",
+             data->machine, data->tcg_only ? "" : "-accel kvm",
+             params ? params : "", disk);
+    }
+
+    data->qts = qtest_init(args);
+
+    if (use_uefi) {
+        g_assert(data->scan_len);
+        data->rsdp_addr = acpi_find_rsdp_address_uefi(data->qts,
+            data->ram_start, data->scan_len);
+    } else {
+        boot_sector_test(data->qts);
+        data->rsdp_addr = acpi_find_rsdp_address(data->qts);
+        g_assert_cmphex(data->rsdp_addr, <, 0x100000);
+    }
+
+    data->tables = g_array_new(false, true, sizeof(AcpiSdtTable));
+    test_acpi_rsdp_table(data);
+    test_acpi_rxsdt_table(data);
+    test_acpi_fadt_table(data);
+
+    if (getenv(ACPI_REBUILD_EXPECTED_AML)) {
+        dump_aml_files(data, true);
+    } else {
+        test_acpi_asl(data);
+    }
+
+    /*
+     * TODO: make SMBIOS tests work with UEFI firmware,
+     * Bug on uefi-test-tools to provide entry point:
+     * https://bugs.launchpad.net/qemu/+bug/1821884
+     */
+    if (!use_uefi) {
+        test_smbios_entry_point(data);
+        test_smbios_structs(data);
+    }
+
+    qtest_quit(data->qts);
+    g_free(args);
+}
+
+static uint8_t base_required_struct_types[] = {
+    0, 1, 3, 4, 16, 17, 19, 32, 127
+};
+
+static void test_acpi_piix4_tcg(void)
+{
+    test_data data;
+
+    /* Supplying -machine accel argument overrides the default (qtest).
+     * This is to make guest actually run.
+     */
+    memset(&data, 0, sizeof(data));
+    data.machine = MACHINE_PC;
+    data.required_struct_types = base_required_struct_types;
+    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
+    test_acpi_one(NULL, &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_piix4_tcg_bridge(void)
+{
+    test_data data;
+
+    memset(&data, 0, sizeof(data));
+    data.machine = MACHINE_PC;
+    data.variant = ".bridge";
+    data.required_struct_types = base_required_struct_types;
+    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
+    test_acpi_one("-device pci-bridge,chassis_nr=1", &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_q35_tcg(void)
+{
+    test_data data;
+
+    memset(&data, 0, sizeof(data));
+    data.machine = MACHINE_Q35;
+    data.required_struct_types = base_required_struct_types;
+    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
+    test_acpi_one(NULL, &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_q35_tcg_bridge(void)
+{
+    test_data data;
+
+    memset(&data, 0, sizeof(data));
+    data.machine = MACHINE_Q35;
+    data.variant = ".bridge";
+    data.required_struct_types = base_required_struct_types;
+    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
+    test_acpi_one("-device pci-bridge,chassis_nr=1",
+                  &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_q35_tcg_mmio64(void)
+{
+    test_data data = {
+        .machine = MACHINE_Q35,
+        .variant = ".mmio64",
+        .required_struct_types = base_required_struct_types,
+        .required_struct_types_len = ARRAY_SIZE(base_required_struct_types)
+    };
+
+    test_acpi_one("-m 128M,slots=1,maxmem=2G "
+                  "-object memory-backend-ram,id=ram0,size=128M "
+                  "-numa node,memdev=ram0 "
+                  "-device pci-testdev,membar=2G",
+                  &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_piix4_tcg_cphp(void)
+{
+    test_data data;
+
+    memset(&data, 0, sizeof(data));
+    data.machine = MACHINE_PC;
+    data.variant = ".cphp";
+    test_acpi_one("-smp 2,cores=3,sockets=2,maxcpus=6"
+                  " -object memory-backend-ram,id=ram0,size=64M"
+                  " -object memory-backend-ram,id=ram1,size=64M"
+                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
+                  " -numa dist,src=0,dst=1,val=21",
+                  &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_q35_tcg_cphp(void)
+{
+    test_data data;
+
+    memset(&data, 0, sizeof(data));
+    data.machine = MACHINE_Q35;
+    data.variant = ".cphp";
+    test_acpi_one(" -smp 2,cores=3,sockets=2,maxcpus=6"
+                  " -object memory-backend-ram,id=ram0,size=64M"
+                  " -object memory-backend-ram,id=ram1,size=64M"
+                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
+                  " -numa dist,src=0,dst=1,val=21",
+                  &data);
+    free_test_data(&data);
+}
+
+static uint8_t ipmi_required_struct_types[] = {
+    0, 1, 3, 4, 16, 17, 19, 32, 38, 127
+};
+
+static void test_acpi_q35_tcg_ipmi(void)
+{
+    test_data data;
+
+    memset(&data, 0, sizeof(data));
+    data.machine = MACHINE_Q35;
+    data.variant = ".ipmibt";
+    data.required_struct_types = ipmi_required_struct_types;
+    data.required_struct_types_len = ARRAY_SIZE(ipmi_required_struct_types);
+    test_acpi_one("-device ipmi-bmc-sim,id=bmc0"
+                  " -device isa-ipmi-bt,bmc=bmc0",
+                  &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_piix4_tcg_ipmi(void)
+{
+    test_data data;
+
+    /* Supplying -machine accel argument overrides the default (qtest).
+     * This is to make guest actually run.
+     */
+    memset(&data, 0, sizeof(data));
+    data.machine = MACHINE_PC;
+    data.variant = ".ipmikcs";
+    data.required_struct_types = ipmi_required_struct_types;
+    data.required_struct_types_len = ARRAY_SIZE(ipmi_required_struct_types);
+    test_acpi_one("-device ipmi-bmc-sim,id=bmc0"
+                  " -device isa-ipmi-kcs,irq=0,bmc=bmc0",
+                  &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_q35_tcg_memhp(void)
+{
+    test_data data;
+
+    memset(&data, 0, sizeof(data));
+    data.machine = MACHINE_Q35;
+    data.variant = ".memhp";
+    test_acpi_one(" -m 128,slots=3,maxmem=1G"
+                  " -object memory-backend-ram,id=ram0,size=64M"
+                  " -object memory-backend-ram,id=ram1,size=64M"
+                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
+                  " -numa dist,src=0,dst=1,val=21",
+                  &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_piix4_tcg_memhp(void)
+{
+    test_data data;
+
+    memset(&data, 0, sizeof(data));
+    data.machine = MACHINE_PC;
+    data.variant = ".memhp";
+    test_acpi_one(" -m 128,slots=3,maxmem=1G"
+                  " -object memory-backend-ram,id=ram0,size=64M"
+                  " -object memory-backend-ram,id=ram1,size=64M"
+                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
+                  " -numa dist,src=0,dst=1,val=21",
+                  &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_q35_tcg_numamem(void)
+{
+    test_data data;
+
+    memset(&data, 0, sizeof(data));
+    data.machine = MACHINE_Q35;
+    data.variant = ".numamem";
+    test_acpi_one(" -object memory-backend-ram,id=ram0,size=128M"
+                  " -numa node -numa node,memdev=ram0", &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_piix4_tcg_numamem(void)
+{
+    test_data data;
+
+    memset(&data, 0, sizeof(data));
+    data.machine = MACHINE_PC;
+    data.variant = ".numamem";
+    test_acpi_one(" -object memory-backend-ram,id=ram0,size=128M"
+                  " -numa node -numa node,memdev=ram0", &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_tcg_dimm_pxm(const char *machine)
+{
+    test_data data;
+
+    memset(&data, 0, sizeof(data));
+    data.machine = machine;
+    data.variant = ".dimmpxm";
+    test_acpi_one(" -machine nvdimm=on,nvdimm-persistence=cpu"
+                  " -smp 4,sockets=4"
+                  " -m 128M,slots=3,maxmem=1G"
+                  " -object memory-backend-ram,id=ram0,size=32M"
+                  " -object memory-backend-ram,id=ram1,size=32M"
+                  " -object memory-backend-ram,id=ram2,size=32M"
+                  " -object memory-backend-ram,id=ram3,size=32M"
+                  " -numa node,memdev=ram0,nodeid=0"
+                  " -numa node,memdev=ram1,nodeid=1"
+                  " -numa node,memdev=ram2,nodeid=2"
+                  " -numa node,memdev=ram3,nodeid=3"
+                  " -numa cpu,node-id=0,socket-id=0"
+                  " -numa cpu,node-id=1,socket-id=1"
+                  " -numa cpu,node-id=2,socket-id=2"
+                  " -numa cpu,node-id=3,socket-id=3"
+                  " -object memory-backend-ram,id=ram4,size=128M"
+                  " -object memory-backend-ram,id=nvm0,size=128M"
+                  " -device pc-dimm,id=dimm0,memdev=ram4,node=1"
+                  " -device nvdimm,id=dimm1,memdev=nvm0,node=2",
+                  &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_q35_tcg_dimm_pxm(void)
+{
+    test_acpi_tcg_dimm_pxm(MACHINE_Q35);
+}
+
+static void test_acpi_piix4_tcg_dimm_pxm(void)
+{
+    test_acpi_tcg_dimm_pxm(MACHINE_PC);
+}
+
+static void test_acpi_virt_tcg_memhp(void)
+{
+    test_data data = {
+        .machine = "virt",
+        .tcg_only = true,
+        .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
+        .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
+        .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
+        .ram_start = 0x40000000ULL,
+        .scan_len = 256ULL * 1024 * 1024,
+    };
+
+    data.variant = ".memhp";
+    test_acpi_one(" -cpu cortex-a57"
+                  " -m 256M,slots=3,maxmem=1G"
+                  " -object memory-backend-ram,id=ram0,size=128M"
+                  " -object memory-backend-ram,id=ram1,size=128M"
+                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
+                  " -numa dist,src=0,dst=1,val=21",
+                  &data);
+
+    free_test_data(&data);
+
+}
+
+static void test_acpi_virt_tcg_numamem(void)
+{
+    test_data data = {
+        .machine = "virt",
+        .tcg_only = true,
+        .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
+        .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
+        .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
+        .ram_start = 0x40000000ULL,
+        .scan_len = 128ULL * 1024 * 1024,
+    };
+
+    data.variant = ".numamem";
+    test_acpi_one(" -cpu cortex-a57"
+                  " -object memory-backend-ram,id=ram0,size=128M"
+                  " -numa node,memdev=ram0",
+                  &data);
+
+    free_test_data(&data);
+
+}
+
+static void test_acpi_tcg_acpi_hmat(const char *machine)
+{
+    test_data data;
+
+    memset(&data, 0, sizeof(data));
+    data.machine = machine;
+    data.variant = ".acpihmat";
+    test_acpi_one(" -machine hmat=on"
+                  " -smp 2,sockets=2"
+                  " -m 128M,slots=2,maxmem=1G"
+                  " -object memory-backend-ram,size=64M,id=m0"
+                  " -object memory-backend-ram,size=64M,id=m1"
+                  " -numa node,nodeid=0,memdev=m0"
+                  " -numa node,nodeid=1,memdev=m1,initiator=0"
+                  " -numa cpu,node-id=0,socket-id=0"
+                  " -numa cpu,node-id=0,socket-id=1"
+                  " -numa hmat-lb,initiator=0,target=0,hierarchy=memory,"
+                  "data-type=access-latency,latency=1"
+                  " -numa hmat-lb,initiator=0,target=0,hierarchy=memory,"
+                  "data-type=access-bandwidth,bandwidth=65534M"
+                  " -numa hmat-lb,initiator=0,target=1,hierarchy=memory,"
+                  "data-type=access-latency,latency=65534"
+                  " -numa hmat-lb,initiator=0,target=1,hierarchy=memory,"
+                  "data-type=access-bandwidth,bandwidth=32767M"
+                  " -numa hmat-cache,node-id=0,size=10K,level=1,"
+                  "associativity=direct,policy=write-back,line=8"
+                  " -numa hmat-cache,node-id=1,size=10K,level=1,"
+                  "associativity=direct,policy=write-back,line=8",
+                  &data);
+    free_test_data(&data);
+}
+
+static void test_acpi_q35_tcg_acpi_hmat(void)
+{
+    test_acpi_tcg_acpi_hmat(MACHINE_Q35);
+}
+
+static void test_acpi_piix4_tcg_acpi_hmat(void)
+{
+    test_acpi_tcg_acpi_hmat(MACHINE_PC);
+}
+
+static void test_acpi_virt_tcg(void)
+{
+    test_data data = {
+        .machine = "virt",
+        .tcg_only = true,
+        .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
+        .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
+        .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
+        .ram_start = 0x40000000ULL,
+        .scan_len = 128ULL * 1024 * 1024,
+    };
+
+    test_acpi_one("-cpu cortex-a57", &data);
+    free_test_data(&data);
+}
+
+int main(int argc, char *argv[])
+{
+    const char *arch = qtest_get_arch();
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        ret = boot_sector_init(disk);
+        if (ret) {
+            return ret;
+        }
+
+        qtest_add_func("acpi/piix4", test_acpi_piix4_tcg);
+        qtest_add_func("acpi/piix4/bridge", test_acpi_piix4_tcg_bridge);
+        qtest_add_func("acpi/q35", test_acpi_q35_tcg);
+        qtest_add_func("acpi/q35/bridge", test_acpi_q35_tcg_bridge);
+        qtest_add_func("acpi/q35/mmio64", test_acpi_q35_tcg_mmio64);
+        qtest_add_func("acpi/piix4/ipmi", test_acpi_piix4_tcg_ipmi);
+        qtest_add_func("acpi/q35/ipmi", test_acpi_q35_tcg_ipmi);
+        qtest_add_func("acpi/piix4/cpuhp", test_acpi_piix4_tcg_cphp);
+        qtest_add_func("acpi/q35/cpuhp", test_acpi_q35_tcg_cphp);
+        qtest_add_func("acpi/piix4/memhp", test_acpi_piix4_tcg_memhp);
+        qtest_add_func("acpi/q35/memhp", test_acpi_q35_tcg_memhp);
+        qtest_add_func("acpi/piix4/numamem", test_acpi_piix4_tcg_numamem);
+        qtest_add_func("acpi/q35/numamem", test_acpi_q35_tcg_numamem);
+        qtest_add_func("acpi/piix4/dimmpxm", test_acpi_piix4_tcg_dimm_pxm);
+        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);
+    } else if (strcmp(arch, "aarch64") == 0) {
+        qtest_add_func("acpi/virt", test_acpi_virt_tcg);
+        qtest_add_func("acpi/virt/numamem", test_acpi_virt_tcg_numamem);
+        qtest_add_func("acpi/virt/memhp", test_acpi_virt_tcg_memhp);
+    }
+    ret = g_test_run();
+    boot_sector_cleanup(disk);
+    return ret;
+}
diff --git a/tests/qtest/boot-order-test.c b/tests/qtest/boot-order-test.c
new file mode 100644 (file)
index 0000000..a725bce
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Boot order test cases.
+ *
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * Authors:
+ *  Markus Armbruster <[email protected]>,
+ *
+ * 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 "libqos/fw_cfg.h"
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "standard-headers/linux/qemu_fw_cfg.h"
+
+/* TODO actually test the results and get rid of this */
+#define qmp_discard_response(qs, ...) qobject_unref(qtest_qmp(qs, __VA_ARGS__))
+
+typedef struct {
+    const char *args;
+    uint64_t expected_boot;
+    uint64_t expected_reboot;
+} boot_order_test;
+
+static void test_a_boot_order(const char *machine,
+                              const char *test_args,
+                              uint64_t (*read_boot_order)(QTestState *),
+                              uint64_t expected_boot,
+                              uint64_t expected_reboot)
+{
+    uint64_t actual;
+    QTestState *qts;
+
+    qts = qtest_initf("-nodefaults%s%s %s", machine ? " -M " : "",
+                      machine ?: "", test_args);
+    actual = read_boot_order(qts);
+    g_assert_cmphex(actual, ==, expected_boot);
+    qmp_discard_response(qts, "{ 'execute': 'system_reset' }");
+    /*
+     * system_reset only requests reset.  We get a RESET event after
+     * the actual reset completes.  Need to wait for that.
+     */
+    qtest_qmp_eventwait(qts, "RESET");
+    actual = read_boot_order(qts);
+    g_assert_cmphex(actual, ==, expected_reboot);
+    qtest_quit(qts);
+}
+
+static void test_boot_orders(const char *machine,
+                             uint64_t (*read_boot_order)(QTestState *),
+                             const boot_order_test *tests)
+{
+    int i;
+
+    for (i = 0; tests[i].args; i++) {
+        test_a_boot_order(machine, tests[i].args,
+                          read_boot_order,
+                          tests[i].expected_boot,
+                          tests[i].expected_reboot);
+    }
+}
+
+static uint8_t read_mc146818(QTestState *qts, uint16_t port, uint8_t reg)
+{
+    qtest_outb(qts, port, reg);
+    return qtest_inb(qts, port + 1);
+}
+
+static uint64_t read_boot_order_pc(QTestState *qts)
+{
+    uint8_t b1 = read_mc146818(qts, 0x70, 0x38);
+    uint8_t b2 = read_mc146818(qts, 0x70, 0x3d);
+
+    return b1 | (b2 << 8);
+}
+
+static const boot_order_test test_cases_pc[] = {
+    { "",
+      0x1230, 0x1230 },
+    { "-no-fd-bootchk",
+      0x1231, 0x1231 },
+    { "-boot c",
+      0x0200, 0x0200 },
+    { "-boot nda",
+      0x3410, 0x3410 },
+    { "-boot order=",
+      0, 0 },
+    { "-boot order= -boot order=c",
+      0x0200, 0x0200 },
+    { "-boot once=a",
+      0x0100, 0x1230 },
+    { "-boot once=a -no-fd-bootchk",
+      0x0101, 0x1231 },
+    { "-boot once=a,order=c",
+      0x0100, 0x0200 },
+    { "-boot once=d -boot order=nda",
+      0x0300, 0x3410 },
+    { "-boot once=a -boot once=b -boot once=c",
+      0x0200, 0x1230 },
+    {}
+};
+
+static void test_pc_boot_order(void)
+{
+    test_boot_orders(NULL, read_boot_order_pc, test_cases_pc);
+}
+
+static uint8_t read_m48t59(QTestState *qts, uint64_t addr, uint16_t reg)
+{
+    qtest_writeb(qts, addr, reg & 0xff);
+    qtest_writeb(qts, addr + 1, reg >> 8);
+    return qtest_readb(qts, addr + 3);
+}
+
+static uint64_t read_boot_order_prep(QTestState *qts)
+{
+    return read_m48t59(qts, 0x80000000 + 0x74, 0x34);
+}
+
+static const boot_order_test test_cases_prep[] = {
+    { "", 'c', 'c' },
+    { "-boot c", 'c', 'c' },
+    { "-boot d", 'd', 'd' },
+    {}
+};
+
+static void test_prep_boot_order(void)
+{
+    test_boot_orders("prep", read_boot_order_prep, test_cases_prep);
+}
+
+static uint64_t read_boot_order_pmac(QTestState *qts)
+{
+    QFWCFG *fw_cfg = mm_fw_cfg_init(qts, 0xf0000510);
+
+    return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
+}
+
+static const boot_order_test test_cases_fw_cfg[] = {
+    { "", 'c', 'c' },
+    { "-boot c", 'c', 'c' },
+    { "-boot d", 'd', 'd' },
+    { "-boot once=d,order=c", 'd', 'c' },
+    {}
+};
+
+static void test_pmac_oldworld_boot_order(void)
+{
+    test_boot_orders("g3beige", read_boot_order_pmac, test_cases_fw_cfg);
+}
+
+static void test_pmac_newworld_boot_order(void)
+{
+    test_boot_orders("mac99", read_boot_order_pmac, test_cases_fw_cfg);
+}
+
+static uint64_t read_boot_order_sun4m(QTestState *qts)
+{
+    QFWCFG *fw_cfg = mm_fw_cfg_init(qts, 0xd00000510ULL);
+
+    return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
+}
+
+static void test_sun4m_boot_order(void)
+{
+    test_boot_orders("SS-5", read_boot_order_sun4m, test_cases_fw_cfg);
+}
+
+static uint64_t read_boot_order_sun4u(QTestState *qts)
+{
+    QFWCFG *fw_cfg = io_fw_cfg_init(qts, 0x510);
+
+    return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
+}
+
+static void test_sun4u_boot_order(void)
+{
+    test_boot_orders("sun4u", read_boot_order_sun4u, test_cases_fw_cfg);
+}
+
+int main(int argc, char *argv[])
+{
+    const char *arch = qtest_get_arch();
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        qtest_add_func("boot-order/pc", test_pc_boot_order);
+    } else if (strcmp(arch, "ppc") == 0 || strcmp(arch, "ppc64") == 0) {
+        qtest_add_func("boot-order/prep", test_prep_boot_order);
+        qtest_add_func("boot-order/pmac_oldworld",
+                       test_pmac_oldworld_boot_order);
+        qtest_add_func("boot-order/pmac_newworld",
+                       test_pmac_newworld_boot_order);
+    } else if (strcmp(arch, "sparc") == 0) {
+        qtest_add_func("boot-order/sun4m", test_sun4m_boot_order);
+    } else if (strcmp(arch, "sparc64") == 0) {
+        qtest_add_func("boot-order/sun4u", test_sun4u_boot_order);
+    }
+
+    return g_test_run();
+}
diff --git a/tests/qtest/boot-sector.c b/tests/qtest/boot-sector.c
new file mode 100644 (file)
index 0000000..9e66c6d
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * QEMU boot sector testing helpers.
+ *
+ * Copyright (c) 2016 Red Hat Inc.
+ *
+ * Authors:
+ *  Michael S. Tsirkin <[email protected]>
+ *  Victor Kaplansky <[email protected]>
+ *
+ * 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 "boot-sector.h"
+#include "qemu-common.h"
+#include "libqtest.h"
+
+#define LOW(x) ((x) & 0xff)
+#define HIGH(x) ((x) >> 8)
+
+#define SIGNATURE 0xdead
+#define SIGNATURE_OFFSET 0x10
+#define BOOT_SECTOR_ADDRESS 0x7c00
+#define SIGNATURE_ADDR (BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET)
+
+/* x86 boot sector code: write SIGNATURE into memory,
+ * then halt.
+ */
+static uint8_t x86_boot_sector[512] = {
+    /* The first sector will be placed at RAM address 00007C00, and
+     * the BIOS transfers control to 00007C00
+     */
+
+    /* Data Segment register should be initialized, since pxe
+     * boot loader can leave it dirty.
+     */
+
+    /* 7c00: move $0000,%ax */
+    [0x00] = 0xb8,
+    [0x01] = 0x00,
+    [0x02] = 0x00,
+    /* 7c03: move %ax,%ds */
+    [0x03] = 0x8e,
+    [0x04] = 0xd8,
+
+    /* 7c05: mov $0xdead,%ax */
+    [0x05] = 0xb8,
+    [0x06] = LOW(SIGNATURE),
+    [0x07] = HIGH(SIGNATURE),
+    /* 7c08:  mov %ax,0x7c10 */
+    [0x08] = 0xa3,
+    [0x09] = LOW(SIGNATURE_ADDR),
+    [0x0a] = HIGH(SIGNATURE_ADDR),
+
+    /* 7c0b cli */
+    [0x0b] = 0xfa,
+    /* 7c0c: hlt */
+    [0x0c] = 0xf4,
+    /* 7c0e: jmp 0x7c07=0x7c0f-3 */
+    [0x0d] = 0xeb,
+    [0x0e] = LOW(-3),
+    /* We mov 0xdead here: set value to make debugging easier */
+    [SIGNATURE_OFFSET] = LOW(0xface),
+    [SIGNATURE_OFFSET + 1] = HIGH(0xface),
+    /* End of boot sector marker */
+    [0x1FE] = 0x55,
+    [0x1FF] = 0xAA,
+};
+
+/* For s390x, use a mini "kernel" with the appropriate signature */
+static const uint8_t s390x_psw_and_magic[] = {
+    0x00, 0x08, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,  /* Program status word  */
+    0x02, 0x00, 0x00, 0x18, 0x60, 0x00, 0x00, 0x50,  /* Magic:               */
+    0x02, 0x00, 0x00, 0x68, 0x60, 0x00, 0x00, 0x50,  /* see linux_s390_magic */
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* in the s390-ccw bios */
+};
+static const uint8_t s390x_code[] = {
+    0xa7, 0xf4, 0x00, 0x08,                                /* j 0x10010 */
+    0x00, 0x00, 0x00, 0x00,
+    'S', '3', '9', '0',
+    'E', 'P', 0x00, 0x01,
+    0xa7, 0x39, HIGH(SIGNATURE_ADDR), LOW(SIGNATURE_ADDR), /* lghi r3,0x7c10 */
+    0xa7, 0x48, LOW(SIGNATURE), HIGH(SIGNATURE),           /* lhi r4,0xadde */
+    0x40, 0x40, 0x30, 0x00,                                /* sth r4,0(r3) */
+    0xa7, 0xf4, 0xff, 0xfa                                 /* j 0x10010 */
+};
+
+/* Create boot disk file.  */
+int boot_sector_init(char *fname)
+{
+    int fd, ret;
+    size_t len;
+    char *boot_code;
+    const char *arch = qtest_get_arch();
+
+    fd = mkstemp(fname);
+    if (fd < 0) {
+        fprintf(stderr, "Couldn't open \"%s\": %s", fname, strerror(errno));
+        return 1;
+    }
+
+    if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64")) {
+        /* Q35 requires a minimum 0x7e000 bytes disk (bug or feature?) */
+        len = MAX(0x7e000, sizeof(x86_boot_sector));
+        boot_code = g_malloc0(len);
+        memcpy(boot_code, x86_boot_sector, sizeof(x86_boot_sector));
+    } else if (g_str_equal(arch, "ppc64")) {
+        /* For Open Firmware based system, use a Forth script */
+        boot_code = g_strdup_printf("\\ Bootscript\n%x %x c! %x %x c!\n",
+                                    LOW(SIGNATURE), SIGNATURE_ADDR,
+                                    HIGH(SIGNATURE), SIGNATURE_ADDR + 1);
+        len = strlen(boot_code);
+    } else if (g_str_equal(arch, "s390x")) {
+        len = 0x10000 + sizeof(s390x_code);
+        boot_code = g_malloc0(len);
+        memcpy(boot_code, s390x_psw_and_magic, sizeof(s390x_psw_and_magic));
+        memcpy(&boot_code[0x10000], s390x_code, sizeof(s390x_code));
+    } else {
+        g_assert_not_reached();
+    }
+
+    ret = write(fd, boot_code, len);
+    close(fd);
+
+    g_free(boot_code);
+
+    if (ret != len) {
+        fprintf(stderr, "Could not write \"%s\"", fname);
+        return 1;
+    }
+
+    return 0;
+}
+
+/* Loop until signature in memory is OK.  */
+void boot_sector_test(QTestState *qts)
+{
+    uint8_t signature_low;
+    uint8_t signature_high;
+    uint16_t signature;
+    int i;
+
+    /* Wait at most 600 seconds (test is slow with TCI and --enable-debug) */
+#define TEST_DELAY (1 * G_USEC_PER_SEC / 10)
+#define TEST_CYCLES MAX((600 * G_USEC_PER_SEC / TEST_DELAY), 1)
+
+    /* Poll until code has run and modified memory.  Once it has we know BIOS
+     * initialization is done.  TODO: check that IP reached the halt
+     * instruction.
+     */
+    for (i = 0; i < TEST_CYCLES; ++i) {
+        signature_low = qtest_readb(qts, SIGNATURE_ADDR);
+        signature_high = qtest_readb(qts, SIGNATURE_ADDR + 1);
+        signature = (signature_high << 8) | signature_low;
+        if (signature == SIGNATURE) {
+            break;
+        }
+        g_usleep(TEST_DELAY);
+    }
+
+    g_assert_cmphex(signature, ==, SIGNATURE);
+}
+
+/* unlink boot disk file.  */
+void boot_sector_cleanup(const char *fname)
+{
+    unlink(fname);
+}
diff --git a/tests/qtest/boot-sector.h b/tests/qtest/boot-sector.h
new file mode 100644 (file)
index 0000000..6ee6bb4
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * QEMU boot sector testing helpers.
+ *
+ * Copyright (c) 2016 Red Hat Inc.
+ *
+ * Authors:
+ *  Michael S. Tsirkin <[email protected]>
+ *  Victor Kaplansky <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TEST_BOOT_SECTOR_H
+#define TEST_BOOT_SECTOR_H
+
+#include "libqtest.h"
+
+/* Create boot disk file. fname must be a suitable string for mkstemp() */
+int boot_sector_init(char *fname);
+
+/* Loop until signature in memory is OK.  */
+void boot_sector_test(QTestState *qts);
+
+/* unlink boot disk file.  */
+void boot_sector_cleanup(const char *fname);
+
+#endif /* TEST_BOOT_SECTOR_H */
diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c
new file mode 100644 (file)
index 0000000..05c7f44
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Test serial output of some machines.
+ *
+ * Copyright 2016 Thomas Huth, Red Hat Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2
+ * or later. See the COPYING file in the top-level directory.
+ *
+ * This test is used to check that the serial output of the firmware
+ * (that we provide for some machines) or some small mini-kernels that
+ * we provide here contains an expected string. Thus we check that the
+ * firmware/kernel still boots at least to a certain point and so we
+ * know that the machine is not completely broken.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+static const uint8_t kernel_mcf5208[] = {
+    0x41, 0xf9, 0xfc, 0x06, 0x00, 0x00,     /* lea 0xfc060000,%a0 */
+    0x10, 0x3c, 0x00, 0x54,                 /* move.b #'T',%d0 */
+    0x11, 0x7c, 0x00, 0x04, 0x00, 0x08,     /* move.b #4,8(%a0)     Enable TX */
+    0x11, 0x40, 0x00, 0x0c,                 /* move.b %d0,12(%a0)   Print 'T' */
+    0x60, 0xfa                              /* bra.s  loop */
+};
+
+static const uint8_t bios_nextcube[] = {
+    0x06, 0x00, 0x00, 0x00,                 /* Initial SP */
+    0x01, 0x00, 0x00, 0x08,                 /* Initial PC */
+    0x41, 0xf9, 0x02, 0x11, 0x80, 0x00,     /* lea 0x02118000,%a0 */
+    0x10, 0x3c, 0x00, 0x54,                 /* move.b #'T',%d0 */
+    0x11, 0x7c, 0x00, 0x05, 0x00, 0x01,     /* move.b #5,1(%a0)    Sel TXCTRL */
+    0x11, 0x7c, 0x00, 0x68, 0x00, 0x01,     /* move.b #0x68,1(%a0) Enable TX */
+    0x11, 0x40, 0x00, 0x03,                 /* move.b %d0,3(%a0)   Print 'T' */
+    0x60, 0xfa                              /* bra.s  loop */
+};
+
+static const uint8_t kernel_pls3adsp1800[] = {
+    0xb0, 0x00, 0x84, 0x00,                 /* imm   0x8400 */
+    0x30, 0x60, 0x00, 0x04,                 /* addik r3,r0,4 */
+    0x30, 0x80, 0x00, 0x54,                 /* addik r4,r0,'T' */
+    0xf0, 0x83, 0x00, 0x00,                 /* sbi   r4,r3,0 */
+    0xb8, 0x00, 0xff, 0xfc                  /* bri   -4  loop */
+};
+
+static const uint8_t kernel_plml605[] = {
+    0xe0, 0x83, 0x00, 0xb0,                 /* imm   0x83e0 */
+    0x00, 0x10, 0x60, 0x30,                 /* addik r3,r0,0x1000 */
+    0x54, 0x00, 0x80, 0x30,                 /* addik r4,r0,'T' */
+    0x00, 0x00, 0x83, 0xf0,                 /* sbi   r4,r3,0 */
+    0xfc, 0xff, 0x00, 0xb8                  /* bri   -4  loop */
+};
+
+static const uint8_t bios_moxiesim[] = {
+    0x20, 0x10, 0x00, 0x00, 0x03, 0xf8,     /* ldi.s r1,0x3f8 */
+    0x1b, 0x20, 0x00, 0x00, 0x00, 0x54,     /* ldi.b r2,'T' */
+    0x1e, 0x12,                             /* st.b  r1,r2 */
+    0x1a, 0x00, 0x00, 0x00, 0x10, 0x00      /* jmpa  0x1000 */
+};
+
+static const uint8_t bios_raspi2[] = {
+    0x08, 0x30, 0x9f, 0xe5,                 /* ldr   r3,[pc,#8]    Get base */
+    0x54, 0x20, 0xa0, 0xe3,                 /* mov     r2,#'T' */
+    0x00, 0x20, 0xc3, 0xe5,                 /* strb    r2,[r3] */
+    0xfb, 0xff, 0xff, 0xea,                 /* b       loop */
+    0x00, 0x10, 0x20, 0x3f,                 /* 0x3f201000 = UART0 base addr */
+};
+
+static const uint8_t kernel_aarch64[] = {
+    0x81, 0x0a, 0x80, 0x52,                 /* mov     w1, #0x54 */
+    0x02, 0x20, 0xa1, 0xd2,                 /* mov     x2, #0x9000000 */
+    0x41, 0x00, 0x00, 0x39,                 /* strb    w1, [x2] */
+    0xfd, 0xff, 0xff, 0x17,                 /* b       -12 (loop) */
+};
+
+static const uint8_t kernel_nrf51[] = {
+    0x00, 0x00, 0x00, 0x00,                 /* Stack top address */
+    0x09, 0x00, 0x00, 0x00,                 /* Reset handler address */
+    0x04, 0x4a,                             /* ldr  r2, [pc, #16] Get ENABLE */
+    0x04, 0x21,                             /* movs r1, #4 */
+    0x11, 0x60,                             /* str  r1, [r2] */
+    0x04, 0x4a,                             /* ldr  r2, [pc, #16] Get STARTTX */
+    0x01, 0x21,                             /* movs r1, #1 */
+    0x11, 0x60,                             /* str  r1, [r2] */
+    0x03, 0x4a,                             /* ldr  r2, [pc, #12] Get TXD */
+    0x54, 0x21,                             /* movs r1, 'T' */
+    0x11, 0x60,                             /* str  r1, [r2] */
+    0xfe, 0xe7,                             /* b    . */
+    0x00, 0x25, 0x00, 0x40,                 /* 0x40002500 = UART ENABLE */
+    0x08, 0x20, 0x00, 0x40,                 /* 0x40002008 = UART STARTTX */
+    0x1c, 0x25, 0x00, 0x40                  /* 0x4000251c = UART TXD */
+};
+
+typedef struct testdef {
+    const char *arch;       /* Target architecture */
+    const char *machine;    /* Name of the machine */
+    const char *extra;      /* Additional parameters */
+    const char *expect;     /* Expected string in the serial output */
+    size_t codesize;        /* Size of the kernel or bios data */
+    const uint8_t *kernel;  /* Set in case we use our own mini kernel */
+    const uint8_t *bios;    /* Set in case we use our own mini bios */
+} testdef_t;
+
+static testdef_t tests[] = {
+    { "alpha", "clipper", "", "PCI:" },
+    { "ppc", "ppce500", "", "U-Boot" },
+    { "ppc", "40p", "-vga none -boot d", "Trying cd:," },
+    { "ppc", "g3beige", "", "PowerPC,750" },
+    { "ppc", "mac99", "", "PowerPC,G4" },
+    { "ppc", "sam460ex", "-m 256", "DRAM:  256 MiB" },
+    { "ppc64", "ppce500", "", "U-Boot" },
+    { "ppc64", "40p", "-m 192", "Memory: 192M" },
+    { "ppc64", "mac99", "", "PowerPC,970FX" },
+    { "ppc64", "pseries",
+      "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken",
+      "Open Firmware" },
+    { "ppc64", "powernv8", "", "OPAL" },
+    { "ppc64", "powernv9", "", "OPAL" },
+    { "ppc64", "sam460ex", "-device e1000", "8086  100e" },
+    { "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
+    { "i386", "pc", "-device sga", "SGABIOS" },
+    { "i386", "q35", "-device sga", "SGABIOS" },
+    { "x86_64", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
+    { "x86_64", "q35", "-device sga", "SGABIOS" },
+    { "sparc", "LX", "", "TMS390S10" },
+    { "sparc", "SS-4", "", "MB86904" },
+    { "sparc", "SS-600MP", "", "TMS390Z55" },
+    { "sparc64", "sun4u", "", "UltraSPARC" },
+    { "s390x", "s390-ccw-virtio", "", "device" },
+    { "m68k", "mcf5208evb", "", "TT", sizeof(kernel_mcf5208), kernel_mcf5208 },
+    { "m68k", "next-cube", "", "TT", sizeof(bios_nextcube), 0, bios_nextcube },
+    { "microblaze", "petalogix-s3adsp1800", "", "TT",
+      sizeof(kernel_pls3adsp1800), kernel_pls3adsp1800 },
+    { "microblazeel", "petalogix-ml605", "", "TT",
+      sizeof(kernel_plml605), kernel_plml605 },
+    { "moxie", "moxiesim", "", "TT", sizeof(bios_moxiesim), 0, bios_moxiesim },
+    { "arm", "raspi2", "", "TT", sizeof(bios_raspi2), 0, bios_raspi2 },
+    { "hppa", "hppa", "", "SeaBIOS wants SYSTEM HALT" },
+    { "aarch64", "virt", "-cpu cortex-a57", "TT", sizeof(kernel_aarch64),
+      kernel_aarch64 },
+    { "arm", "microbit", "", "T", sizeof(kernel_nrf51), kernel_nrf51 },
+
+    { NULL }
+};
+
+static bool check_guest_output(QTestState *qts, const testdef_t *test, int fd)
+{
+    int nbr = 0, pos = 0, ccnt;
+    time_t now, start = time(NULL);
+    char ch;
+
+    /* Poll serial output... */
+    while (1) {
+        ccnt = 0;
+        while (ccnt++ < 512 && (nbr = read(fd, &ch, 1)) == 1) {
+            if (ch == test->expect[pos]) {
+                pos += 1;
+                if (test->expect[pos] == '\0') {
+                    /* We've reached the end of the expected string! */
+                    return true;
+                }
+            } else {
+                pos = 0;
+            }
+        }
+        g_assert(nbr >= 0);
+        /* Wait only if the child is still alive.  */
+        if (!qtest_probe_child(qts)) {
+            break;
+        }
+        /* Wait at most 360 seconds.  */
+        now = time(NULL);
+        if (now - start >= 360) {
+            break;
+        }
+        g_usleep(10000);
+    }
+
+    return false;
+}
+
+static void test_machine(const void *data)
+{
+    const testdef_t *test = data;
+    char serialtmp[] = "/tmp/qtest-boot-serial-sXXXXXX";
+    char codetmp[] = "/tmp/qtest-boot-serial-cXXXXXX";
+    const char *codeparam = "";
+    const uint8_t *code = NULL;
+    QTestState *qts;
+    int ser_fd;
+
+    ser_fd = mkstemp(serialtmp);
+    g_assert(ser_fd != -1);
+
+    if (test->kernel) {
+        code = test->kernel;
+        codeparam = "-kernel";
+    } else if (test->bios) {
+        code = test->bios;
+        codeparam = "-bios";
+    }
+
+    if (code) {
+        ssize_t wlen;
+        int code_fd;
+
+        code_fd = mkstemp(codetmp);
+        g_assert(code_fd != -1);
+        wlen = write(code_fd, code, test->codesize);
+        g_assert(wlen == test->codesize);
+        close(code_fd);
+    }
+
+    /*
+     * Make sure that this test uses tcg if available: It is used as a
+     * fast-enough smoketest for that.
+     */
+    qts = qtest_initf("%s %s -M %s -no-shutdown "
+                      "-chardev file,id=serial0,path=%s "
+                      "-serial chardev:serial0 -accel tcg -accel kvm %s",
+                      codeparam, code ? codetmp : "", test->machine,
+                      serialtmp, test->extra);
+    if (code) {
+        unlink(codetmp);
+    }
+
+    if (!check_guest_output(qts, test, ser_fd)) {
+        g_error("Failed to find expected string. Please check '%s'",
+                serialtmp);
+    }
+    unlink(serialtmp);
+
+    qtest_quit(qts);
+
+    close(ser_fd);
+}
+
+int main(int argc, char *argv[])
+{
+    const char *arch = qtest_get_arch();
+    int i;
+
+    g_test_init(&argc, &argv, NULL);
+
+    for (i = 0; tests[i].arch != NULL; i++) {
+        if (strcmp(arch, tests[i].arch) == 0) {
+            char *name = g_strdup_printf("boot-serial/%s", tests[i].machine);
+            qtest_add_data_func(name, &tests[i], test_machine);
+            g_free(name);
+        }
+    }
+
+    return g_test_run();
+}
diff --git a/tests/qtest/cdrom-test.c b/tests/qtest/cdrom-test.c
new file mode 100644 (file)
index 0000000..67635e3
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Various tests for emulated CD-ROM drives.
+ *
+ * Copyright (c) 2018 Red Hat Inc.
+ *
+ * Author:
+ *    Thomas Huth <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2
+ * or later. See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "boot-sector.h"
+#include "qapi/qmp/qdict.h"
+
+static char isoimage[] = "cdrom-boot-iso-XXXXXX";
+
+static int exec_genisoimg(const char **args)
+{
+    gchar *out_err = NULL;
+    gint exit_status = -1;
+    bool success;
+
+    success = g_spawn_sync(NULL, (gchar **)args, NULL,
+                           G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL,
+                           NULL, NULL, NULL, &out_err, &exit_status, NULL);
+    if (!success) {
+        return -ENOENT;
+    }
+    if (out_err) {
+        fputs(out_err, stderr);
+        g_free(out_err);
+    }
+
+    return exit_status;
+}
+
+static int prepare_image(const char *arch, char *isoimage)
+{
+    char srcdir[] = "cdrom-test-dir-XXXXXX";
+    char *codefile = NULL;
+    int ifh, ret = -1;
+    const char *args[] = {
+        "genisoimage", "-quiet", "-l", "-no-emul-boot",
+        "-b", NULL, "-o", isoimage, srcdir, NULL
+    };
+
+    ifh = mkstemp(isoimage);
+    if (ifh < 0) {
+        perror("Error creating temporary iso image file");
+        return -1;
+    }
+    if (!mkdtemp(srcdir)) {
+        perror("Error creating temporary directory");
+        goto cleanup;
+    }
+
+    if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64") ||
+        g_str_equal(arch, "s390x")) {
+        codefile = g_strdup_printf("%s/bootcode-XXXXXX", srcdir);
+        ret = boot_sector_init(codefile);
+        if (ret) {
+            goto cleanup;
+        }
+    } else {
+        /* Just create a dummy file */
+        char txt[] = "empty disc";
+        codefile = g_strdup_printf("%s/readme.txt", srcdir);
+        if (!g_file_set_contents(codefile, txt, sizeof(txt) - 1, NULL)) {
+            fprintf(stderr, "Failed to create '%s'\n", codefile);
+            goto cleanup;
+        }
+    }
+
+    args[5] = strchr(codefile, '/') + 1;
+    ret = exec_genisoimg(args);
+    if (ret) {
+        fprintf(stderr, "genisoimage failed: %i\n", ret);
+    }
+
+    unlink(codefile);
+
+cleanup:
+    g_free(codefile);
+    rmdir(srcdir);
+    close(ifh);
+
+    return ret;
+}
+
+/**
+ * Check that at least the -cdrom parameter is basically working, i.e. we can
+ * see the filename of the ISO image in the output of "info block" afterwards
+ */
+static void test_cdrom_param(gconstpointer data)
+{
+    QTestState *qts;
+    char *resp;
+
+    qts = qtest_initf("-M %s -cdrom %s", (const char *)data, isoimage);
+    resp = qtest_hmp(qts, "info block");
+    g_assert(strstr(resp, isoimage) != 0);
+    g_free(resp);
+    qtest_quit(qts);
+}
+
+static void add_cdrom_param_tests(const char **machines)
+{
+    while (*machines) {
+        char *testname = g_strdup_printf("cdrom/param/%s", *machines);
+        qtest_add_data_func(testname, *machines, test_cdrom_param);
+        g_free(testname);
+        machines++;
+    }
+}
+
+static void test_cdboot(gconstpointer data)
+{
+    QTestState *qts;
+
+    qts = qtest_initf("-accel kvm -accel tcg -no-shutdown %s%s", (const char *)data,
+                      isoimage);
+    boot_sector_test(qts);
+    qtest_quit(qts);
+}
+
+static void add_x86_tests(void)
+{
+    qtest_add_data_func("cdrom/boot/default", "-cdrom ", test_cdboot);
+    qtest_add_data_func("cdrom/boot/virtio-scsi",
+                        "-device virtio-scsi -device scsi-cd,drive=cdr "
+                        "-blockdev file,node-name=cdr,filename=", test_cdboot);
+    /*
+     * Unstable CI test under load
+     * See https://lists.gnu.org/archive/html/qemu-devel/2019-02/msg05509.html
+     */
+    if (g_test_slow()) {
+        qtest_add_data_func("cdrom/boot/isapc", "-M isapc "
+                            "-drive if=ide,media=cdrom,file=", test_cdboot);
+    }
+    qtest_add_data_func("cdrom/boot/am53c974",
+                        "-device am53c974 -device scsi-cd,drive=cd1 "
+                        "-drive if=none,id=cd1,format=raw,file=", test_cdboot);
+    qtest_add_data_func("cdrom/boot/dc390",
+                        "-device dc390 -device scsi-cd,drive=cd1 "
+                        "-blockdev file,node-name=cd1,filename=", test_cdboot);
+    qtest_add_data_func("cdrom/boot/lsi53c895a",
+                        "-device lsi53c895a -device scsi-cd,drive=cd1 "
+                        "-blockdev file,node-name=cd1,filename=", test_cdboot);
+    qtest_add_data_func("cdrom/boot/megasas", "-M q35 "
+                        "-device megasas -device scsi-cd,drive=cd1 "
+                        "-blockdev file,node-name=cd1,filename=", test_cdboot);
+    qtest_add_data_func("cdrom/boot/megasas-gen2", "-M q35 "
+                        "-device megasas-gen2 -device scsi-cd,drive=cd1 "
+                        "-blockdev file,node-name=cd1,filename=", test_cdboot);
+}
+
+static void add_s390x_tests(void)
+{
+    qtest_add_data_func("cdrom/boot/default", "-cdrom ", test_cdboot);
+    qtest_add_data_func("cdrom/boot/virtio-scsi",
+                        "-device virtio-scsi -device scsi-cd,drive=cdr "
+                        "-blockdev file,node-name=cdr,filename=", test_cdboot);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+    const char *arch = qtest_get_arch();
+    const char *genisocheck[] = { "genisoimage", "-version", NULL };
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (exec_genisoimg(genisocheck)) {
+        /* genisoimage not available - so can't run tests */
+        return g_test_run();
+    }
+
+    ret = prepare_image(arch, isoimage);
+    if (ret) {
+        return ret;
+    }
+
+    if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64")) {
+        add_x86_tests();
+    } else if (g_str_equal(arch, "s390x")) {
+        add_s390x_tests();
+    } else if (g_str_equal(arch, "ppc64")) {
+        const char *ppcmachines[] = {
+            "pseries", "mac99", "g3beige", "40p", "prep", NULL
+        };
+        add_cdrom_param_tests(ppcmachines);
+    } else if (g_str_equal(arch, "sparc")) {
+        const char *sparcmachines[] = {
+            "LX", "SPARCClassic", "SPARCbook", "SS-10", "SS-20", "SS-4",
+            "SS-5", "SS-600MP", "Voyager", "leon3_generic", NULL
+        };
+        add_cdrom_param_tests(sparcmachines);
+    } else if (g_str_equal(arch, "sparc64")) {
+        const char *sparc64machines[] = {
+            "niagara", "sun4u", "sun4v", NULL
+        };
+        add_cdrom_param_tests(sparc64machines);
+    } else if (!strncmp(arch, "mips64", 6)) {
+        const char *mips64machines[] = {
+            "magnum", "malta", "mips", "pica61", NULL
+        };
+        add_cdrom_param_tests(mips64machines);
+    } else if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) {
+        const char *armmachines[] = {
+            "realview-eb", "realview-eb-mpcore", "realview-pb-a8",
+            "realview-pbx-a9", "versatileab", "versatilepb", "vexpress-a15",
+            "vexpress-a9", "virt", NULL
+        };
+        add_cdrom_param_tests(armmachines);
+    } else {
+        const char *nonemachine[] = { "none", NULL };
+        add_cdrom_param_tests(nonemachine);
+    }
+
+    ret = g_test_run();
+
+    unlink(isoimage);
+
+    return ret;
+}
diff --git a/tests/qtest/cpu-plug-test.c b/tests/qtest/cpu-plug-test.c
new file mode 100644 (file)
index 0000000..e8ffbbc
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * QTest testcase for CPU plugging
+ *
+ * Copyright (c) 2015 SUSE Linux GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu-common.h"
+#include "libqtest-single.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
+
+struct PlugTestData {
+    char *machine;
+    const char *cpu_model;
+    char *device_model;
+    unsigned sockets;
+    unsigned cores;
+    unsigned threads;
+    unsigned maxcpus;
+};
+typedef struct PlugTestData PlugTestData;
+
+static void test_plug_with_cpu_add(gconstpointer data)
+{
+    const PlugTestData *s = data;
+    char *args;
+    QDict *response;
+    unsigned int i;
+
+    args = g_strdup_printf("-machine %s -cpu %s "
+                           "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u",
+                           s->machine, s->cpu_model,
+                           s->sockets, s->cores, s->threads, s->maxcpus);
+    qtest_start(args);
+
+    for (i = 1; i < s->maxcpus; i++) {
+        response = qmp("{ 'execute': 'cpu-add',"
+                       "  'arguments': { 'id': %d } }", i);
+        g_assert(response);
+        g_assert(!qdict_haskey(response, "error"));
+        qobject_unref(response);
+    }
+
+    qtest_end();
+    g_free(args);
+}
+
+static void test_plug_without_cpu_add(gconstpointer data)
+{
+    const PlugTestData *s = data;
+    char *args;
+    QDict *response;
+
+    args = g_strdup_printf("-machine %s -cpu %s "
+                           "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u",
+                           s->machine, s->cpu_model,
+                           s->sockets, s->cores, s->threads, s->maxcpus);
+    qtest_start(args);
+
+    response = qmp("{ 'execute': 'cpu-add',"
+                   "  'arguments': { 'id': %d } }",
+                   s->sockets * s->cores * s->threads);
+    g_assert(response);
+    g_assert(qdict_haskey(response, "error"));
+    qobject_unref(response);
+
+    qtest_end();
+    g_free(args);
+}
+
+static void test_plug_with_device_add(gconstpointer data)
+{
+    const PlugTestData *td = data;
+    char *args;
+    QTestState *qts;
+    QDict *resp;
+    QList *cpus;
+    QObject *e;
+    int hotplugged = 0;
+
+    args = g_strdup_printf("-machine %s -cpu %s "
+                           "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u",
+                           td->machine, td->cpu_model,
+                           td->sockets, td->cores, td->threads, td->maxcpus);
+    qts = qtest_init(args);
+
+    resp = qtest_qmp(qts, "{ 'execute': 'query-hotpluggable-cpus'}");
+    g_assert(qdict_haskey(resp, "return"));
+    cpus = qdict_get_qlist(resp, "return");
+    g_assert(cpus);
+
+    while ((e = qlist_pop(cpus))) {
+        const QDict *cpu, *props;
+
+        cpu = qobject_to(QDict, e);
+        if (qdict_haskey(cpu, "qom-path")) {
+            qobject_unref(e);
+            continue;
+        }
+
+        g_assert(qdict_haskey(cpu, "props"));
+        props = qdict_get_qdict(cpu, "props");
+
+        qtest_qmp_device_add_qdict(qts, td->device_model, props);
+        hotplugged++;
+        qobject_unref(e);
+    }
+
+    /* make sure that there were hotplugged CPUs */
+    g_assert(hotplugged);
+    qobject_unref(resp);
+    qtest_quit(qts);
+    g_free(args);
+}
+
+static void test_data_free(gpointer data)
+{
+    PlugTestData *pc = data;
+
+    g_free(pc->machine);
+    g_free(pc->device_model);
+    g_free(pc);
+}
+
+static void add_pc_test_case(const char *mname)
+{
+    char *path;
+    PlugTestData *data;
+
+    if (!g_str_has_prefix(mname, "pc-")) {
+        return;
+    }
+    data = g_new(PlugTestData, 1);
+    data->machine = g_strdup(mname);
+    data->cpu_model = "Haswell"; /* 1.3+ theoretically */
+    data->device_model = g_strdup_printf("%s-%s-cpu", data->cpu_model,
+                                         qtest_get_arch());
+    data->sockets = 1;
+    data->cores = 3;
+    data->threads = 2;
+    data->maxcpus = data->sockets * data->cores * data->threads;
+    if (g_str_has_suffix(mname, "-1.4") ||
+        (strcmp(mname, "pc-1.3") == 0) ||
+        (strcmp(mname, "pc-1.2") == 0) ||
+        (strcmp(mname, "pc-1.1") == 0) ||
+        (strcmp(mname, "pc-1.0") == 0)) {
+        path = g_strdup_printf("cpu-plug/%s/init/%ux%ux%u&maxcpus=%u",
+                               mname, data->sockets, data->cores,
+                               data->threads, data->maxcpus);
+        qtest_add_data_func_full(path, data, test_plug_without_cpu_add,
+                                 test_data_free);
+        g_free(path);
+    } else {
+        PlugTestData *data2 = g_memdup(data, sizeof(PlugTestData));
+
+        data2->machine = g_strdup(data->machine);
+        data2->device_model = g_strdup(data->device_model);
+
+        path = g_strdup_printf("cpu-plug/%s/cpu-add/%ux%ux%u&maxcpus=%u",
+                               mname, data->sockets, data->cores,
+                               data->threads, data->maxcpus);
+        qtest_add_data_func_full(path, data, test_plug_with_cpu_add,
+                                 test_data_free);
+        g_free(path);
+        path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u",
+                               mname, data2->sockets, data2->cores,
+                               data2->threads, data2->maxcpus);
+        qtest_add_data_func_full(path, data2, test_plug_with_device_add,
+                                 test_data_free);
+        g_free(path);
+    }
+}
+
+static void add_pseries_test_case(const char *mname)
+{
+    char *path;
+    PlugTestData *data;
+
+    if (!g_str_has_prefix(mname, "pseries-") ||
+        (g_str_has_prefix(mname, "pseries-2.") && atoi(&mname[10]) < 7)) {
+        return;
+    }
+    data = g_new(PlugTestData, 1);
+    data->machine = g_strdup(mname);
+    data->cpu_model = "power8_v2.0";
+    data->device_model = g_strdup("power8_v2.0-spapr-cpu-core");
+    data->sockets = 2;
+    data->cores = 3;
+    data->threads = 1;
+    data->maxcpus = data->sockets * data->cores * data->threads;
+
+    path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u",
+                           mname, data->sockets, data->cores,
+                           data->threads, data->maxcpus);
+    qtest_add_data_func_full(path, data, test_plug_with_device_add,
+                             test_data_free);
+    g_free(path);
+}
+
+static void add_s390x_test_case(const char *mname)
+{
+    char *path;
+    PlugTestData *data, *data2;
+
+    if (!g_str_has_prefix(mname, "s390-ccw-virtio-")) {
+        return;
+    }
+
+    data = g_new(PlugTestData, 1);
+    data->machine = g_strdup(mname);
+    data->cpu_model = "qemu";
+    data->device_model = g_strdup("qemu-s390x-cpu");
+    data->sockets = 1;
+    data->cores = 3;
+    data->threads = 1;
+    data->maxcpus = data->sockets * data->cores * data->threads;
+
+    data2 = g_memdup(data, sizeof(PlugTestData));
+    data2->machine = g_strdup(data->machine);
+    data2->device_model = g_strdup(data->device_model);
+
+    path = g_strdup_printf("cpu-plug/%s/cpu-add/%ux%ux%u&maxcpus=%u",
+                           mname, data->sockets, data->cores,
+                           data->threads, data->maxcpus);
+    qtest_add_data_func_full(path, data, test_plug_with_cpu_add,
+                             test_data_free);
+    g_free(path);
+
+    path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u",
+                           mname, data2->sockets, data2->cores,
+                           data2->threads, data2->maxcpus);
+    qtest_add_data_func_full(path, data2, test_plug_with_device_add,
+                             test_data_free);
+    g_free(path);
+}
+
+int main(int argc, char **argv)
+{
+    const char *arch = qtest_get_arch();
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        qtest_cb_for_every_machine(add_pc_test_case, g_test_quick());
+    } else if (g_str_equal(arch, "ppc64")) {
+        qtest_cb_for_every_machine(add_pseries_test_case, g_test_quick());
+    } else if (g_str_equal(arch, "s390x")) {
+        qtest_cb_for_every_machine(add_s390x_test_case, g_test_quick());
+    }
+
+    return g_test_run();
+}
diff --git a/tests/qtest/dbus-vmstate-test.c b/tests/qtest/dbus-vmstate-test.c
new file mode 100644 (file)
index 0000000..2e5e47d
--- /dev/null
@@ -0,0 +1,382 @@
+#include "qemu/osdep.h"
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+#include "libqtest.h"
+#include "qemu-common.h"
+#include "dbus-vmstate1.h"
+#include "migration-helpers.h"
+
+static char *workdir;
+
+typedef struct TestServerId {
+    const char *name;
+    const char *data;
+    size_t size;
+} TestServerId;
+
+static const TestServerId idA = {
+    "idA", "I'am\0idA!", sizeof("I'am\0idA!")
+};
+
+static const TestServerId idB = {
+    "idB", "I'am\0idB!", sizeof("I'am\0idB!")
+};
+
+typedef struct TestServer {
+    const TestServerId *id;
+    bool save_called;
+    bool load_called;
+} TestServer;
+
+typedef struct Test {
+    const char *id_list;
+    bool migrate_fail;
+    bool without_dst_b;
+    TestServer srcA;
+    TestServer dstA;
+    TestServer srcB;
+    TestServer dstB;
+    GMainLoop *loop;
+    QTestState *src_qemu;
+} Test;
+
+static gboolean
+vmstate_load(VMState1 *object, GDBusMethodInvocation *invocation,
+             const gchar *arg_data, gpointer user_data)
+{
+    TestServer *h = user_data;
+    g_autoptr(GVariant) var = NULL;
+    GVariant *args;
+    const uint8_t *data;
+    size_t size;
+
+    args = g_dbus_method_invocation_get_parameters(invocation);
+    var = g_variant_get_child_value(args, 0);
+    data = g_variant_get_fixed_array(var, &size, sizeof(char));
+    g_assert_cmpuint(size, ==, h->id->size);
+    g_assert(!memcmp(data, h->id->data, h->id->size));
+    h->load_called = true;
+
+    g_dbus_method_invocation_return_value(invocation, g_variant_new("()"));
+    return TRUE;
+}
+
+static gboolean
+vmstate_save(VMState1 *object, GDBusMethodInvocation *invocation,
+             gpointer user_data)
+{
+    TestServer *h = user_data;
+    GVariant *var;
+
+    var = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
+                                    h->id->data, h->id->size, sizeof(char));
+    g_dbus_method_invocation_return_value(invocation,
+                                          g_variant_new("(@ay)", var));
+    h->save_called = true;
+
+    return TRUE;
+}
+
+typedef struct WaitNamed {
+    GMainLoop *loop;
+    bool named;
+} WaitNamed;
+
+static void
+named_cb(GDBusConnection *connection,
+         const gchar *name,
+         gpointer user_data)
+{
+    WaitNamed *t = user_data;
+
+    t->named = true;
+    g_main_loop_quit(t->loop);
+}
+
+static GDBusConnection *
+get_connection(Test *test, guint *ownid)
+{
+    g_autofree gchar *addr = NULL;
+    WaitNamed *wait;
+    GError *err = NULL;
+    GDBusConnection *c;
+
+    wait = g_new0(WaitNamed, 1);
+    wait->loop = test->loop;
+    addr = g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SESSION, NULL, &err);
+    g_assert_no_error(err);
+
+    c = g_dbus_connection_new_for_address_sync(
+        addr,
+        G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION |
+        G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+        NULL, NULL, &err);
+    g_assert_no_error(err);
+    *ownid = g_bus_own_name_on_connection(c, "org.qemu.VMState1",
+                                          G_BUS_NAME_OWNER_FLAGS_NONE,
+                                          named_cb, named_cb, wait, g_free);
+    if (!wait->named) {
+        g_main_loop_run(wait->loop);
+    }
+
+    return c;
+}
+
+static GDBusObjectManagerServer *
+get_server(GDBusConnection *conn, TestServer *s, const TestServerId *id)
+{
+    g_autoptr(GDBusObjectSkeleton) sk = NULL;
+    g_autoptr(VMState1Skeleton) v = NULL;
+    GDBusObjectManagerServer *os;
+
+    s->id = id;
+    os = g_dbus_object_manager_server_new("/org/qemu");
+    sk = g_dbus_object_skeleton_new("/org/qemu/VMState1");
+
+    v = VMSTATE1_SKELETON(vmstate1_skeleton_new());
+    g_object_set(v, "id", id->name, NULL);
+
+    g_signal_connect(v, "handle-load", G_CALLBACK(vmstate_load), s);
+    g_signal_connect(v, "handle-save", G_CALLBACK(vmstate_save), s);
+
+    g_dbus_object_skeleton_add_interface(sk, G_DBUS_INTERFACE_SKELETON(v));
+    g_dbus_object_manager_server_export(os, sk);
+    g_dbus_object_manager_server_set_connection(os, conn);
+
+    return os;
+}
+
+static void
+set_id_list(Test *test, QTestState *s)
+{
+    if (!test->id_list) {
+        return;
+    }
+
+    g_assert(!qmp_rsp_is_err(qtest_qmp(s,
+        "{ 'execute': 'qom-set', 'arguments': "
+        "{ 'path': '/objects/dv', 'property': 'id-list', 'value': %s } }",
+        test->id_list)));
+}
+
+static gpointer
+dbus_vmstate_thread(gpointer data)
+{
+    GMainLoop *loop = data;
+
+    g_main_loop_run(loop);
+
+    return NULL;
+}
+
+static void
+test_dbus_vmstate(Test *test)
+{
+    g_autofree char *src_qemu_args = NULL;
+    g_autofree char *dst_qemu_args = NULL;
+    g_autoptr(GTestDBus) srcbus = NULL;
+    g_autoptr(GTestDBus) dstbus = NULL;
+    g_autoptr(GDBusConnection) srcconnA = NULL;
+    g_autoptr(GDBusConnection) srcconnB = NULL;
+    g_autoptr(GDBusConnection) dstconnA = NULL;
+    g_autoptr(GDBusConnection) dstconnB = NULL;
+    g_autoptr(GDBusObjectManagerServer) srcserverA = NULL;
+    g_autoptr(GDBusObjectManagerServer) srcserverB = NULL;
+    g_autoptr(GDBusObjectManagerServer) dstserverA = NULL;
+    g_autoptr(GDBusObjectManagerServer) dstserverB = NULL;
+    g_auto(GStrv) srcaddr = NULL;
+    g_auto(GStrv) dstaddr = NULL;
+    g_autoptr(GThread) thread = NULL;
+    g_autoptr(GMainLoop) loop = NULL;
+    g_autofree char *uri = NULL;
+    QTestState *src_qemu = NULL, *dst_qemu = NULL;
+    guint ownsrcA, ownsrcB, owndstA, owndstB;
+
+    uri = g_strdup_printf("unix:%s/migsocket", workdir);
+
+    loop = g_main_loop_new(NULL, FALSE);
+    test->loop = loop;
+
+    srcbus = g_test_dbus_new(G_TEST_DBUS_NONE);
+    g_test_dbus_up(srcbus);
+    srcconnA = get_connection(test, &ownsrcA);
+    srcserverA = get_server(srcconnA, &test->srcA, &idA);
+    srcconnB = get_connection(test, &ownsrcB);
+    srcserverB = get_server(srcconnB, &test->srcB, &idB);
+
+    /* remove ,guid=foo part */
+    srcaddr = g_strsplit(g_test_dbus_get_bus_address(srcbus), ",", 2);
+    src_qemu_args =
+        g_strdup_printf("-object dbus-vmstate,id=dv,addr=%s", srcaddr[0]);
+
+    dstbus = g_test_dbus_new(G_TEST_DBUS_NONE);
+    g_test_dbus_up(dstbus);
+    dstconnA = get_connection(test, &owndstA);
+    dstserverA = get_server(dstconnA, &test->dstA, &idA);
+    if (!test->without_dst_b) {
+        dstconnB = get_connection(test, &owndstB);
+        dstserverB = get_server(dstconnB, &test->dstB, &idB);
+    }
+
+    dstaddr = g_strsplit(g_test_dbus_get_bus_address(dstbus), ",", 2);
+    dst_qemu_args =
+        g_strdup_printf("-object dbus-vmstate,id=dv,addr=%s -incoming %s",
+                        dstaddr[0], uri);
+
+    src_qemu = qtest_init(src_qemu_args);
+    dst_qemu = qtest_init(dst_qemu_args);
+    set_id_list(test, src_qemu);
+    set_id_list(test, dst_qemu);
+
+    thread = g_thread_new("dbus-vmstate-thread", dbus_vmstate_thread, loop);
+
+    migrate_qmp(src_qemu, uri, "{}");
+    test->src_qemu = src_qemu;
+    if (test->migrate_fail) {
+        wait_for_migration_fail(src_qemu, true);
+        qtest_set_expected_status(dst_qemu, 1);
+    } else {
+        wait_for_migration_complete(src_qemu);
+    }
+
+    qtest_quit(dst_qemu);
+    qtest_quit(src_qemu);
+    g_bus_unown_name(ownsrcA);
+    g_bus_unown_name(ownsrcB);
+    g_bus_unown_name(owndstA);
+    if (!test->without_dst_b) {
+        g_bus_unown_name(owndstB);
+    }
+
+    g_main_loop_quit(test->loop);
+}
+
+static void
+check_not_migrated(TestServer *s, TestServer *d)
+{
+    assert(!s->save_called);
+    assert(!s->load_called);
+    assert(!d->save_called);
+    assert(!d->load_called);
+}
+
+static void
+check_migrated(TestServer *s, TestServer *d)
+{
+    assert(s->save_called);
+    assert(!s->load_called);
+    assert(!d->save_called);
+    assert(d->load_called);
+}
+
+static void
+test_dbus_vmstate_without_list(void)
+{
+    Test test = { 0, };
+
+    test_dbus_vmstate(&test);
+
+    check_migrated(&test.srcA, &test.dstA);
+    check_migrated(&test.srcB, &test.dstB);
+}
+
+static void
+test_dbus_vmstate_with_list(void)
+{
+    Test test = { .id_list = "idA,idB" };
+
+    test_dbus_vmstate(&test);
+
+    check_migrated(&test.srcA, &test.dstA);
+    check_migrated(&test.srcB, &test.dstB);
+}
+
+static void
+test_dbus_vmstate_only_a(void)
+{
+    Test test = { .id_list = "idA" };
+
+    test_dbus_vmstate(&test);
+
+    check_migrated(&test.srcA, &test.dstA);
+    check_not_migrated(&test.srcB, &test.dstB);
+}
+
+static void
+test_dbus_vmstate_missing_src(void)
+{
+    Test test = { .id_list = "idA,idC", .migrate_fail = true };
+
+    /* run in subprocess to silence QEMU error reporting */
+    if (g_test_subprocess()) {
+        test_dbus_vmstate(&test);
+        check_not_migrated(&test.srcA, &test.dstA);
+        check_not_migrated(&test.srcB, &test.dstB);
+        return;
+    }
+
+    g_test_trap_subprocess(NULL, 0, 0);
+    g_test_trap_assert_passed();
+}
+
+static void
+test_dbus_vmstate_missing_dst(void)
+{
+    Test test = { .id_list = "idA,idB",
+                  .without_dst_b = true,
+                  .migrate_fail = true };
+
+    /* run in subprocess to silence QEMU error reporting */
+    if (g_test_subprocess()) {
+        test_dbus_vmstate(&test);
+        assert(test.srcA.save_called);
+        assert(test.srcB.save_called);
+        assert(!test.dstB.save_called);
+        return;
+    }
+
+    g_test_trap_subprocess(NULL, 0, 0);
+    g_test_trap_assert_passed();
+}
+
+int
+main(int argc, char **argv)
+{
+    GError *err = NULL;
+    g_autofree char *dbus_daemon = NULL;
+    int ret;
+
+    dbus_daemon = g_build_filename(G_STRINGIFY(SRCDIR),
+                                   "tests",
+                                   "dbus-vmstate-daemon.sh",
+                                   NULL);
+    g_setenv("G_TEST_DBUS_DAEMON", dbus_daemon, true);
+
+    g_test_init(&argc, &argv, NULL);
+
+    workdir = g_dir_make_tmp("dbus-vmstate-test-XXXXXX", &err);
+    if (!workdir) {
+        g_error("Unable to create temporary dir: %s\n", err->message);
+        exit(1);
+    }
+
+    g_setenv("DBUS_VMSTATE_TEST_TMPDIR", workdir, true);
+
+    qtest_add_func("/dbus-vmstate/without-list",
+                   test_dbus_vmstate_without_list);
+    qtest_add_func("/dbus-vmstate/with-list",
+                   test_dbus_vmstate_with_list);
+    qtest_add_func("/dbus-vmstate/only-a",
+                   test_dbus_vmstate_only_a);
+    qtest_add_func("/dbus-vmstate/missing-src",
+                   test_dbus_vmstate_missing_src);
+    qtest_add_func("/dbus-vmstate/missing-dst",
+                   test_dbus_vmstate_missing_dst);
+
+    ret = g_test_run();
+
+    rmdir(workdir);
+    g_free(workdir);
+
+    return ret;
+}
diff --git a/tests/qtest/dbus-vmstate1.xml b/tests/qtest/dbus-vmstate1.xml
new file mode 100644 (file)
index 0000000..cc8563b
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+  <interface name="org.qemu.VMState1">
+    <property name="Id" type="s" access="read"/>
+    <method name="Load">
+      <arg type="ay" name="data" direction="in"/>
+    </method>
+    <method name="Save">
+      <arg type="ay" name="data" direction="out"/>
+    </method>
+  </interface>
+</node>
diff --git a/tests/qtest/device-introspect-test.c b/tests/qtest/device-introspect-test.c
new file mode 100644 (file)
index 0000000..04f2290
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Device introspection test cases
+ *
+ * Copyright (c) 2015 Red Hat Inc.
+ *
+ * Authors:
+ *  Markus Armbruster <[email protected]>,
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+/*
+ * Covers QMP device-list-properties and HMP device_add help.  We
+ * currently don't check that their output makes sense, only that QEMU
+ * survives.  Useful since we've had an astounding number of crash
+ * bugs around here.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qapi/qmp/qstring.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
+#include "libqtest.h"
+
+const char common_args[] = "-nodefaults -machine none";
+
+static QList *qom_list_types(QTestState * qts, const char *implements,
+                             bool abstract)
+{
+    QDict *resp;
+    QList *ret;
+    QDict *args = qdict_new();
+
+    qdict_put_bool(args, "abstract", abstract);
+    if (implements) {
+        qdict_put_str(args, "implements", implements);
+    }
+    resp = qtest_qmp(qts, "{'execute': 'qom-list-types', 'arguments': %p }",
+                     args);
+    g_assert(qdict_haskey(resp, "return"));
+    ret = qdict_get_qlist(resp, "return");
+    qobject_ref(ret);
+    qobject_unref(resp);
+    return ret;
+}
+
+/* Build a name -> ObjectTypeInfo index from a ObjectTypeInfo list */
+static QDict *qom_type_index(QList *types)
+{
+    QDict *index = qdict_new();
+    QListEntry *e;
+
+    QLIST_FOREACH_ENTRY(types, e) {
+        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
+        const char *name = qdict_get_str(d, "name");
+        qobject_ref(d);
+        qdict_put(index, name, d);
+    }
+    return index;
+}
+
+/* Check if @parent is present in the parent chain of @type */
+static bool qom_has_parent(QDict *index, const char *type, const char *parent)
+{
+    while (type) {
+        QDict *d = qdict_get_qdict(index, type);
+        const char *p = d && qdict_haskey(d, "parent") ?
+                        qdict_get_str(d, "parent") :
+                        NULL;
+
+        if (!strcmp(type, parent)) {
+            return true;
+        }
+
+        type = p;
+    }
+
+    return false;
+}
+
+/* Find an entry on a list returned by qom-list-types */
+static QDict *type_list_find(QList *types, const char *name)
+{
+    QListEntry *e;
+
+    QLIST_FOREACH_ENTRY(types, e) {
+        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
+        const char *ename = qdict_get_str(d, "name");
+        if (!strcmp(ename, name)) {
+            return d;
+        }
+    }
+
+    return NULL;
+}
+
+static QList *device_type_list(QTestState *qts, bool abstract)
+{
+    return qom_list_types(qts, "device", abstract);
+}
+
+static void test_one_device(QTestState *qts, const char *type)
+{
+    QDict *resp;
+    char *help;
+    char *qom_tree_start, *qom_tree_end;
+    char *qtree_start, *qtree_end;
+
+    g_test_message("Testing device '%s'", type);
+
+    qom_tree_start = qtest_hmp(qts, "info qom-tree");
+    qtree_start = qtest_hmp(qts, "info qtree");
+
+    resp = qtest_qmp(qts, "{'execute': 'device-list-properties',"
+                          " 'arguments': {'typename': %s}}",
+               type);
+    qobject_unref(resp);
+
+    help = qtest_hmp(qts, "device_add \"%s,help\"", type);
+    g_free(help);
+
+    /*
+     * Some devices leave dangling pointers in QOM behind.
+     * "info qom-tree" or "info qtree" have a good chance at crashing then.
+     * Also make sure that the tree did not change.
+     */
+    qom_tree_end = qtest_hmp(qts, "info qom-tree");
+    g_assert_cmpstr(qom_tree_start, ==, qom_tree_end);
+    g_free(qom_tree_start);
+    g_free(qom_tree_end);
+
+    qtree_end = qtest_hmp(qts, "info qtree");
+    g_assert_cmpstr(qtree_start, ==, qtree_end);
+    g_free(qtree_start);
+    g_free(qtree_end);
+}
+
+static void test_device_intro_list(void)
+{
+    QList *types;
+    char *help;
+    QTestState *qts;
+
+    qts = qtest_init(common_args);
+
+    types = device_type_list(qts, true);
+    qobject_unref(types);
+
+    help = qtest_hmp(qts, "device_add help");
+    g_free(help);
+
+    qtest_quit(qts);
+}
+
+/*
+ * Ensure all entries returned by qom-list-types implements=<parent>
+ * have <parent> as a parent.
+ */
+static void test_qom_list_parents(QTestState *qts, const char *parent)
+{
+    QList *types;
+    QListEntry *e;
+    QDict *index;
+
+    types = qom_list_types(qts, parent, true);
+    index = qom_type_index(types);
+
+    QLIST_FOREACH_ENTRY(types, e) {
+        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
+        const char *name = qdict_get_str(d, "name");
+
+        g_assert(qom_has_parent(index, name, parent));
+    }
+
+    qobject_unref(types);
+    qobject_unref(index);
+}
+
+static void test_qom_list_fields(void)
+{
+    QList *all_types;
+    QList *non_abstract;
+    QListEntry *e;
+    QTestState *qts;
+
+    qts = qtest_init(common_args);
+
+    all_types = qom_list_types(qts, NULL, true);
+    non_abstract = qom_list_types(qts, NULL, false);
+
+    QLIST_FOREACH_ENTRY(all_types, e) {
+        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
+        const char *name = qdict_get_str(d, "name");
+        bool abstract = qdict_haskey(d, "abstract") ?
+                        qdict_get_bool(d, "abstract") :
+                        false;
+        bool expected_abstract = !type_list_find(non_abstract, name);
+
+        g_assert(abstract == expected_abstract);
+    }
+
+    test_qom_list_parents(qts, "object");
+    test_qom_list_parents(qts, "device");
+    test_qom_list_parents(qts, "sys-bus-device");
+
+    qobject_unref(all_types);
+    qobject_unref(non_abstract);
+    qtest_quit(qts);
+}
+
+static void test_device_intro_none(void)
+{
+    QTestState *qts = qtest_init(common_args);
+
+    test_one_device(qts, "nonexistent");
+    qtest_quit(qts);
+}
+
+static void test_device_intro_abstract(void)
+{
+    QTestState *qts = qtest_init(common_args);
+
+    test_one_device(qts, "device");
+    qtest_quit(qts);
+}
+
+static void test_device_intro_concrete(const void *args)
+{
+    QList *types;
+    QListEntry *entry;
+    const char *type;
+    QTestState *qts;
+
+    qts = qtest_init(args);
+    types = device_type_list(qts, false);
+
+    QLIST_FOREACH_ENTRY(types, entry) {
+        type = qdict_get_try_str(qobject_to(QDict, qlist_entry_obj(entry)),
+                                 "name");
+        g_assert(type);
+        test_one_device(qts, type);
+    }
+
+    qobject_unref(types);
+    qtest_quit(qts);
+    g_free((void *)args);
+}
+
+static void test_abstract_interfaces(void)
+{
+    QList *all_types;
+    QListEntry *e;
+    QDict *index;
+    QTestState *qts;
+
+    qts = qtest_init(common_args);
+
+    all_types = qom_list_types(qts, "interface", true);
+    index = qom_type_index(all_types);
+
+    QLIST_FOREACH_ENTRY(all_types, e) {
+        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
+        const char *name = qdict_get_str(d, "name");
+
+        /*
+         * qom-list-types implements=interface returns all types
+         * that implement _any_ interface (not just interface
+         * types), so skip the ones that don't have "interface"
+         * on the parent type chain.
+         */
+        if (!qom_has_parent(index, name, "interface")) {
+            /* Not an interface type */
+            continue;
+        }
+
+        g_assert(qdict_haskey(d, "abstract") && qdict_get_bool(d, "abstract"));
+    }
+
+    qobject_unref(all_types);
+    qobject_unref(index);
+    qtest_quit(qts);
+}
+
+static void add_machine_test_case(const char *mname)
+{
+    char *path, *args;
+
+    /* Ignore blacklisted machines */
+    if (g_str_equal("xenfv", mname) || g_str_equal("xenpv", mname)) {
+        return;
+    }
+
+    path = g_strdup_printf("device/introspect/concrete/defaults/%s", mname);
+    args = g_strdup_printf("-M %s", mname);
+    qtest_add_data_func(path, args, test_device_intro_concrete);
+    g_free(path);
+
+    path = g_strdup_printf("device/introspect/concrete/nodefaults/%s", mname);
+    args = g_strdup_printf("-nodefaults -M %s", mname);
+    qtest_add_data_func(path, args, test_device_intro_concrete);
+    g_free(path);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("device/introspect/list", test_device_intro_list);
+    qtest_add_func("device/introspect/list-fields", test_qom_list_fields);
+    qtest_add_func("device/introspect/none", test_device_intro_none);
+    qtest_add_func("device/introspect/abstract", test_device_intro_abstract);
+    qtest_add_func("device/introspect/abstract-interfaces", test_abstract_interfaces);
+    if (g_test_quick()) {
+        qtest_add_data_func("device/introspect/concrete/defaults/none",
+                            g_strdup(common_args), test_device_intro_concrete);
+    } else {
+        qtest_cb_for_every_machine(add_machine_test_case, true);
+    }
+
+    return g_test_run();
+}
diff --git a/tests/qtest/device-plug-test.c b/tests/qtest/device-plug-test.c
new file mode 100644 (file)
index 0000000..318e422
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * QEMU device plug/unplug handling
+ *
+ * Copyright (C) 2019 Red Hat Inc.
+ *
+ * Authors:
+ *  David Hildenbrand <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qstring.h"
+
+static void device_del_start(QTestState *qtest, const char *id)
+{
+    qtest_qmp_send(qtest,
+                   "{'execute': 'device_del', 'arguments': { 'id': %s } }", id);
+}
+
+static void device_del_finish(QTestState *qtest)
+{
+    QDict *resp = qtest_qmp_receive(qtest);
+
+    g_assert(qdict_haskey(resp, "return"));
+    qobject_unref(resp);
+}
+
+static void device_del_request(QTestState *qtest, const char *id)
+{
+    device_del_start(qtest, id);
+    device_del_finish(qtest);
+}
+
+static void system_reset(QTestState *qtest)
+{
+    QDict *resp;
+
+    resp = qtest_qmp(qtest, "{'execute': 'system_reset'}");
+    g_assert(qdict_haskey(resp, "return"));
+    qobject_unref(resp);
+}
+
+static void wait_device_deleted_event(QTestState *qtest, const char *id)
+{
+    QDict *resp, *data;
+    QString *qstr;
+
+    /*
+     * Other devices might get removed along with the removed device. Skip
+     * these. The device of interest will be the last one.
+     */
+    for (;;) {
+        resp = qtest_qmp_eventwait_ref(qtest, "DEVICE_DELETED");
+        data = qdict_get_qdict(resp, "data");
+        if (!data || !qdict_get(data, "device")) {
+            qobject_unref(resp);
+            continue;
+        }
+        qstr = qobject_to(QString, qdict_get(data, "device"));
+        g_assert(qstr);
+        if (!strcmp(qstring_get_str(qstr), id)) {
+            qobject_unref(resp);
+            break;
+        }
+        qobject_unref(resp);
+    }
+}
+
+static void test_pci_unplug_request(void)
+{
+    QTestState *qtest = qtest_initf("-device virtio-mouse-pci,id=dev0");
+
+    /*
+     * Request device removal. As the guest is not running, the request won't
+     * be processed. However during system reset, the removal will be
+     * handled, removing the device.
+     */
+    device_del_request(qtest, "dev0");
+    system_reset(qtest);
+    wait_device_deleted_event(qtest, "dev0");
+
+    qtest_quit(qtest);
+}
+
+static void test_ccw_unplug(void)
+{
+    QTestState *qtest = qtest_initf("-device virtio-balloon-ccw,id=dev0");
+
+    /*
+     * The DEVICE_DELETED events will be sent before the command
+     * completes.
+     */
+    device_del_start(qtest, "dev0");
+    wait_device_deleted_event(qtest, "dev0");
+    device_del_finish(qtest);
+
+    qtest_quit(qtest);
+}
+
+static void test_spapr_cpu_unplug_request(void)
+{
+    QTestState *qtest;
+
+    qtest = qtest_initf("-cpu power9_v2.0 -smp 1,maxcpus=2 "
+                        "-device power9_v2.0-spapr-cpu-core,core-id=1,id=dev0");
+
+    /* similar to test_pci_unplug_request */
+    device_del_request(qtest, "dev0");
+    system_reset(qtest);
+    wait_device_deleted_event(qtest, "dev0");
+
+    qtest_quit(qtest);
+}
+
+static void test_spapr_memory_unplug_request(void)
+{
+    QTestState *qtest;
+
+    qtest = qtest_initf("-m 256M,slots=1,maxmem=768M "
+                        "-object memory-backend-ram,id=mem0,size=512M "
+                        "-device pc-dimm,id=dev0,memdev=mem0");
+
+    /* similar to test_pci_unplug_request */
+    device_del_request(qtest, "dev0");
+    system_reset(qtest);
+    wait_device_deleted_event(qtest, "dev0");
+
+    qtest_quit(qtest);
+}
+
+static void test_spapr_phb_unplug_request(void)
+{
+    QTestState *qtest;
+
+    qtest = qtest_initf("-device spapr-pci-host-bridge,index=1,id=dev0");
+
+    /* similar to test_pci_unplug_request */
+    device_del_request(qtest, "dev0");
+    system_reset(qtest);
+    wait_device_deleted_event(qtest, "dev0");
+
+    qtest_quit(qtest);
+}
+
+int main(int argc, char **argv)
+{
+    const char *arch = qtest_get_arch();
+
+    g_test_init(&argc, &argv, NULL);
+
+    /*
+     * We need a system that will process unplug requests during system resets
+     * and does not do PCI surprise removal. This holds for x86 ACPI,
+     * s390x and spapr.
+     */
+    qtest_add_func("/device-plug/pci-unplug-request",
+                   test_pci_unplug_request);
+
+    if (!strcmp(arch, "s390x")) {
+        qtest_add_func("/device-plug/ccw-unplug",
+                       test_ccw_unplug);
+    }
+
+    if (!strcmp(arch, "ppc64")) {
+        qtest_add_func("/device-plug/spapr-cpu-unplug-request",
+                       test_spapr_cpu_unplug_request);
+        qtest_add_func("/device-plug/spapr-memory-unplug-request",
+                       test_spapr_memory_unplug_request);
+        qtest_add_func("/device-plug/spapr-phb-unplug-request",
+                       test_spapr_phb_unplug_request);
+    }
+
+    return g_test_run();
+}
diff --git a/tests/qtest/display-vga-test.c b/tests/qtest/display-vga-test.c
new file mode 100644 (file)
index 0000000..ace3bb2
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * QTest testcase for vga cards
+ *
+ * Copyright (c) 2014 Red Hat, Inc
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+
+static void pci_cirrus(void)
+{
+    qtest_start("-vga none -device cirrus-vga");
+    qtest_end();
+}
+
+static void pci_stdvga(void)
+{
+    qtest_start("-vga none -device VGA");
+    qtest_end();
+}
+
+static void pci_secondary(void)
+{
+    qtest_start("-vga none -device secondary-vga");
+    qtest_end();
+}
+
+static void pci_multihead(void)
+{
+    qtest_start("-vga none -device VGA -device secondary-vga");
+    qtest_end();
+}
+
+static void pci_virtio_gpu(void)
+{
+    qtest_start("-vga none -device virtio-gpu-pci");
+    qtest_end();
+}
+
+static void pci_virtio_vga(void)
+{
+    qtest_start("-vga none -device virtio-vga");
+    qtest_end();
+}
+
+int main(int argc, char **argv)
+{
+    const char *arch = qtest_get_arch();
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (strcmp(arch, "alpha") == 0 || strcmp(arch, "i386") == 0 ||
+        strcmp(arch, "mips") == 0 || strcmp(arch, "x86_64") == 0) {
+        qtest_add_func("/display/pci/cirrus", pci_cirrus);
+    }
+    qtest_add_func("/display/pci/stdvga", pci_stdvga);
+    qtest_add_func("/display/pci/secondary", pci_secondary);
+    qtest_add_func("/display/pci/multihead", pci_multihead);
+    qtest_add_func("/display/pci/virtio-gpu", pci_virtio_gpu);
+    if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64") ||
+        g_str_equal(arch, "hppa") || g_str_equal(arch, "ppc64")) {
+        qtest_add_func("/display/pci/virtio-vga", pci_virtio_vga);
+    }
+
+    return g_test_run();
+}
diff --git a/tests/qtest/drive_del-test.c b/tests/qtest/drive_del-test.c
new file mode 100644 (file)
index 0000000..5f8839b
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * blockdev.c test cases
+ *
+ * Copyright (C) 2013-2014 Red Hat Inc.
+ *
+ * Authors:
+ *  Stefan Hajnoczi <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/virtio.h"
+#include "qapi/qmp/qdict.h"
+
+/* TODO actually test the results and get rid of this */
+#define qmp_discard_response(q, ...) qobject_unref(qtest_qmp(q, __VA_ARGS__))
+
+static void drive_add(QTestState *qts)
+{
+    char *resp = qtest_hmp(qts, "drive_add 0 if=none,id=drive0");
+
+    g_assert_cmpstr(resp, ==, "OK\r\n");
+    g_free(resp);
+}
+
+static void drive_del(QTestState *qts)
+{
+    char *resp = qtest_hmp(qts, "drive_del drive0");
+
+    g_assert_cmpstr(resp, ==, "");
+    g_free(resp);
+}
+
+static void device_del(QTestState *qts)
+{
+    QDict *response;
+
+    /* Complication: ignore DEVICE_DELETED event */
+    qmp_discard_response(qts, "{'execute': 'device_del',"
+                         " 'arguments': { 'id': 'dev0' } }");
+    response = qtest_qmp_receive(qts);
+    g_assert(response);
+    g_assert(qdict_haskey(response, "return"));
+    qobject_unref(response);
+}
+
+static void test_drive_without_dev(void)
+{
+    QTestState *qts;
+
+    /* Start with an empty drive */
+    qts = qtest_init("-drive if=none,id=drive0");
+
+    /* Delete the drive */
+    drive_del(qts);
+
+    /* Ensure re-adding the drive works - there should be no duplicate ID error
+     * because the old drive must be gone.
+     */
+    drive_add(qts);
+
+    qtest_quit(qts);
+}
+
+/*
+ * qvirtio_get_dev_type:
+ * Returns: the preferred virtio bus/device type for the current architecture.
+ * TODO: delete this
+ */
+static const char *qvirtio_get_dev_type(void)
+{
+    const char *arch = qtest_get_arch();
+
+    if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) {
+        return "device";  /* for virtio-mmio */
+    } else if (g_str_equal(arch, "s390x")) {
+        return "ccw";
+    } else {
+        return "pci";
+    }
+}
+
+static void test_after_failed_device_add(void)
+{
+    char driver[32];
+    QDict *response;
+    QTestState *qts;
+
+    snprintf(driver, sizeof(driver), "virtio-blk-%s",
+             qvirtio_get_dev_type());
+
+    qts = qtest_init("-drive if=none,id=drive0");
+
+    /* Make device_add fail. If this leaks the virtio-blk device then a
+     * reference to drive0 will also be held (via qdev properties).
+     */
+    response = qtest_qmp(qts, "{'execute': 'device_add',"
+                              " 'arguments': {"
+                              "   'driver': %s,"
+                              "   'drive': 'drive0'"
+                              "}}", driver);
+    g_assert(response);
+    qmp_assert_error_class(response, "GenericError");
+
+    /* Delete the drive */
+    drive_del(qts);
+
+    /* Try to re-add the drive.  This fails with duplicate IDs if a leaked
+     * virtio-blk device exists that holds a reference to the old drive0.
+     */
+    drive_add(qts);
+
+    qtest_quit(qts);
+}
+
+static void test_drive_del_device_del(void)
+{
+    QTestState *qts;
+
+    /* Start with a drive used by a device that unplugs instantaneously */
+    qts = qtest_initf("-drive if=none,id=drive0,file=null-co://,"
+                      "file.read-zeroes=on,format=raw"
+                      " -device virtio-scsi-%s"
+                      " -device scsi-hd,drive=drive0,id=dev0",
+                      qvirtio_get_dev_type());
+
+    /*
+     * Delete the drive, and then the device
+     * Doing it in this order takes notoriously tricky special paths
+     */
+    drive_del(qts);
+    device_del(qts);
+
+    qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/drive_del/without-dev", test_drive_without_dev);
+
+    if (qvirtio_get_dev_type() != NULL) {
+        qtest_add_func("/drive_del/after_failed_device_add",
+                       test_after_failed_device_add);
+        qtest_add_func("/blockdev/drive_del_device_del",
+                       test_drive_del_device_del);
+    }
+
+    return g_test_run();
+}
diff --git a/tests/qtest/ds1338-test.c b/tests/qtest/ds1338-test.c
new file mode 100644 (file)
index 0000000..f6ade9a
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * QTest testcase for the DS1338 RTC
+ *
+ * Copyright (c) 2013 Jean-Christophe Dubois
+ *
+ *  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/>.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/i2c.h"
+
+#define DS1338_ADDR 0x68
+
+static inline uint8_t bcd2bin(uint8_t x)
+{
+    return ((x) & 0x0f) + ((x) >> 4) * 10;
+}
+
+static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc)
+{
+    QI2CDevice *i2cdev = (QI2CDevice *)obj;
+
+    uint8_t resp[7];
+    time_t now = time(NULL);
+    struct tm *tm_ptr = gmtime(&now);
+
+    i2c_read_block(i2cdev, 0, resp, sizeof(resp));
+
+    /* check retrieved time againt local time */
+    g_assert_cmpuint(bcd2bin(resp[4]), == , tm_ptr->tm_mday);
+    g_assert_cmpuint(bcd2bin(resp[5]), == , 1 + tm_ptr->tm_mon);
+    g_assert_cmpuint(2000 + bcd2bin(resp[6]), == , 1900 + tm_ptr->tm_year);
+}
+
+static void ds1338_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "address=0x68"
+    };
+    add_qi2c_address(&opts, &(QI2CAddress) { DS1338_ADDR });
+
+    qos_node_create_driver("ds1338", i2c_device_create);
+    qos_node_consumes("ds1338", "i2c-bus", &opts);
+    qos_add_test("tx-rx", "ds1338", send_and_receive, NULL);
+}
+libqos_init(ds1338_register_nodes);
diff --git a/tests/qtest/e1000-test.c b/tests/qtest/e1000-test.c
new file mode 100644 (file)
index 0000000..c387984
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * QTest testcase for e1000 NIC
+ *
+ * Copyright (c) 2013-2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
+
+typedef struct QE1000 QE1000;
+
+struct QE1000 {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static const char *models[] = {
+    "e1000",
+    "e1000-82540em",
+    "e1000-82544gc",
+    "e1000-82545em",
+};
+
+static void *e1000_get_driver(void *obj, const char *interface)
+{
+    QE1000 *e1000 = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &e1000->dev;
+    }
+
+    fprintf(stderr, "%s not present in e1000e\n", interface);
+    g_assert_not_reached();
+}
+
+static void *e1000_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QE1000 *e1000 = g_new0(QE1000, 1);
+    QPCIBus *bus = pci_bus;
+
+    qpci_device_init(&e1000->dev, bus, addr);
+    e1000->obj.get_driver = e1000_get_driver;
+
+    return &e1000->obj;
+}
+
+static void e1000_register_nodes(void)
+{
+    int i;
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+
+    for (i = 0; i < ARRAY_SIZE(models); i++) {
+        qos_node_create_driver(models[i], e1000_create);
+        qos_node_consumes(models[i], "pci-bus", &opts);
+        qos_node_produces(models[i], "pci-device");
+    }
+}
+
+libqos_init(e1000_register_nodes);
diff --git a/tests/qtest/e1000e-test.c b/tests/qtest/e1000e-test.c
new file mode 100644 (file)
index 0000000..1a232a6
--- /dev/null
@@ -0,0 +1,279 @@
+ /*
+ * QTest testcase for e1000e NIC
+ *
+ * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <[email protected]>
+ * Leonid Bloch <[email protected]>
+ * Yan Vugenfirer <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "libqtest-single.h"
+#include "qemu-common.h"
+#include "libqos/pci-pc.h"
+#include "qemu/sockets.h"
+#include "qemu/iov.h"
+#include "qemu/module.h"
+#include "qemu/bitops.h"
+#include "libqos/malloc.h"
+#include "libqos/e1000e.h"
+
+static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
+{
+    struct {
+        uint64_t buffer_addr;
+        union {
+            uint32_t data;
+            struct {
+                uint16_t length;
+                uint8_t cso;
+                uint8_t cmd;
+            } flags;
+        } lower;
+        union {
+            uint32_t data;
+            struct {
+                uint8_t status;
+                uint8_t css;
+                uint16_t special;
+            } fields;
+        } upper;
+    } descr;
+
+    static const uint32_t dtyp_data = BIT(20);
+    static const uint32_t dtyp_ext  = BIT(29);
+    static const uint32_t dcmd_rs   = BIT(27);
+    static const uint32_t dcmd_eop  = BIT(24);
+    static const uint32_t dsta_dd   = BIT(0);
+    static const int data_len = 64;
+    char buffer[64];
+    int ret;
+    uint32_t recv_len;
+
+    /* Prepare test data buffer */
+    uint64_t data = guest_alloc(alloc, data_len);
+    memwrite(data, "TEST", 5);
+
+    /* Prepare TX descriptor */
+    memset(&descr, 0, sizeof(descr));
+    descr.buffer_addr = cpu_to_le64(data);
+    descr.lower.data = cpu_to_le32(dcmd_rs   |
+                                   dcmd_eop  |
+                                   dtyp_ext  |
+                                   dtyp_data |
+                                   data_len);
+
+    /* Put descriptor to the ring */
+    e1000e_tx_ring_push(d, &descr);
+
+    /* Wait for TX WB interrupt */
+    e1000e_wait_isr(d, E1000E_TX0_MSG_ID);
+
+    /* Check DD bit */
+    g_assert_cmphex(le32_to_cpu(descr.upper.data) & dsta_dd, ==, dsta_dd);
+
+    /* Check data sent to the backend */
+    ret = qemu_recv(test_sockets[0], &recv_len, sizeof(recv_len), 0);
+    g_assert_cmpint(ret, == , sizeof(recv_len));
+    qemu_recv(test_sockets[0], buffer, 64, 0);
+    g_assert_cmpstr(buffer, == , "TEST");
+
+    /* Free test data buffer */
+    guest_free(alloc, data);
+}
+
+static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
+{
+    union {
+        struct {
+            uint64_t buffer_addr;
+            uint64_t reserved;
+        } read;
+        struct {
+            struct {
+                uint32_t mrq;
+                union {
+                    uint32_t rss;
+                    struct {
+                        uint16_t ip_id;
+                        uint16_t csum;
+                    } csum_ip;
+                } hi_dword;
+            } lower;
+            struct {
+                uint32_t status_error;
+                uint16_t length;
+                uint16_t vlan;
+            } upper;
+        } wb;
+    } descr;
+
+    static const uint32_t esta_dd = BIT(0);
+
+    char test[] = "TEST";
+    int len = htonl(sizeof(test));
+    struct iovec iov[] = {
+        {
+            .iov_base = &len,
+            .iov_len = sizeof(len),
+        },{
+            .iov_base = test,
+            .iov_len = sizeof(test),
+        },
+    };
+
+    static const int data_len = 64;
+    char buffer[64];
+    int ret;
+
+    /* Send a dummy packet to device's socket*/
+    ret = iov_send(test_sockets[0], iov, 2, 0, sizeof(len) + sizeof(test));
+    g_assert_cmpint(ret, == , sizeof(test) + sizeof(len));
+
+    /* Prepare test data buffer */
+    uint64_t data = guest_alloc(alloc, data_len);
+
+    /* Prepare RX descriptor */
+    memset(&descr, 0, sizeof(descr));
+    descr.read.buffer_addr = cpu_to_le64(data);
+
+    /* Put descriptor to the ring */
+    e1000e_rx_ring_push(d, &descr);
+
+    /* Wait for TX WB interrupt */
+    e1000e_wait_isr(d, E1000E_RX0_MSG_ID);
+
+    /* Check DD bit */
+    g_assert_cmphex(le32_to_cpu(descr.wb.upper.status_error) &
+        esta_dd, ==, esta_dd);
+
+    /* Check data sent to the backend */
+    memread(data, buffer, sizeof(buffer));
+    g_assert_cmpstr(buffer, == , "TEST");
+
+    /* Free test data buffer */
+    guest_free(alloc, data);
+}
+
+static void test_e1000e_init(void *obj, void *data, QGuestAllocator * alloc)
+{
+    /* init does nothing */
+}
+
+static void test_e1000e_tx(void *obj, void *data, QGuestAllocator * alloc)
+{
+    QE1000E_PCI *e1000e = obj;
+    QE1000E *d = &e1000e->e1000e;
+    QOSGraphObject *e_object = obj;
+    QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
+
+    /* FIXME: add spapr support */
+    if (qpci_check_buggy_msi(dev)) {
+        return;
+    }
+
+    e1000e_send_verify(d, data, alloc);
+}
+
+static void test_e1000e_rx(void *obj, void *data, QGuestAllocator * alloc)
+{
+    QE1000E_PCI *e1000e = obj;
+    QE1000E *d = &e1000e->e1000e;
+    QOSGraphObject *e_object = obj;
+    QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
+
+    /* FIXME: add spapr support */
+    if (qpci_check_buggy_msi(dev)) {
+        return;
+    }
+
+    e1000e_receive_verify(d, data, alloc);
+}
+
+static void test_e1000e_multiple_transfers(void *obj, void *data,
+                                           QGuestAllocator *alloc)
+{
+    static const long iterations = 4 * 1024;
+    long i;
+
+    QE1000E_PCI *e1000e = obj;
+    QE1000E *d = &e1000e->e1000e;
+    QOSGraphObject *e_object = obj;
+    QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
+
+    /* FIXME: add spapr support */
+    if (qpci_check_buggy_msi(dev)) {
+        return;
+    }
+
+    for (i = 0; i < iterations; i++) {
+        e1000e_send_verify(d, data, alloc);
+        e1000e_receive_verify(d, data, alloc);
+    }
+
+}
+
+static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
+{
+    QTestState *qts = global_qtest;  /* TODO: get rid of global_qtest here */
+
+    qtest_qmp_device_add(qts, "e1000e", "e1000e_net", "{'addr': '0x06'}");
+    qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06);
+}
+
+static void data_test_clear(void *sockets)
+{
+    int *test_sockets = sockets;
+
+    close(test_sockets[0]);
+    qos_invalidate_command_line();
+    close(test_sockets[1]);
+    g_free(test_sockets);
+}
+
+static void *data_test_init(GString *cmd_line, void *arg)
+{
+    int *test_sockets = g_new(int, 2);
+    int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, test_sockets);
+    g_assert_cmpint(ret, != , -1);
+
+    g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ",
+                           test_sockets[1]);
+
+    g_test_queue_destroy(data_test_clear, test_sockets);
+    return test_sockets;
+}
+
+static void register_e1000e_test(void)
+{
+    QOSGraphTestOptions opts = {
+        .before = data_test_init,
+    };
+
+    qos_add_test("init", "e1000e", test_e1000e_init, &opts);
+    qos_add_test("tx", "e1000e", test_e1000e_tx, &opts);
+    qos_add_test("rx", "e1000e", test_e1000e_rx, &opts);
+    qos_add_test("multiple_transfers", "e1000e",
+                      test_e1000e_multiple_transfers, &opts);
+    qos_add_test("hotplug", "e1000e", test_e1000e_hotplug, &opts);
+}
+
+libqos_init(register_e1000e_test);
diff --git a/tests/qtest/eepro100-test.c b/tests/qtest/eepro100-test.c
new file mode 100644 (file)
index 0000000..8dbffff
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * QTest testcase for eepro100 NIC
+ *
+ * Copyright (c) 2013-2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
+
+typedef struct QEEPRO100 QEEPRO100;
+
+struct QEEPRO100 {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static const char *models[] = {
+    "i82550",
+    "i82551",
+    "i82557a",
+    "i82557b",
+    "i82557c",
+    "i82558a",
+    "i82558b",
+    "i82559a",
+    "i82559b",
+    "i82559c",
+    "i82559er",
+    "i82562",
+    "i82801",
+};
+
+static void *eepro100_get_driver(void *obj, const char *interface)
+{
+    QEEPRO100 *eepro100 = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &eepro100->dev;
+    }
+
+    fprintf(stderr, "%s not present in eepro100\n", interface);
+    g_assert_not_reached();
+}
+
+static void *eepro100_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QEEPRO100 *eepro100 = g_new0(QEEPRO100, 1);
+    QPCIBus *bus = pci_bus;
+
+    qpci_device_init(&eepro100->dev, bus, addr);
+    eepro100->obj.get_driver = eepro100_get_driver;
+
+    return &eepro100->obj;
+}
+
+static void eepro100_register_nodes(void)
+{
+    int i;
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+    for (i = 0; i < ARRAY_SIZE(models); i++) {
+        qos_node_create_driver(models[i], eepro100_create);
+        qos_node_consumes(models[i], "pci-bus", &opts);
+        qos_node_produces(models[i], "pci-device");
+    }
+}
+
+libqos_init(eepro100_register_nodes);
diff --git a/tests/qtest/endianness-test.c b/tests/qtest/endianness-test.c
new file mode 100644 (file)
index 0000000..5852795
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * QTest testcase for ISA endianness
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ *  Paolo Bonzini <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqtest.h"
+#include "qemu/bswap.h"
+
+typedef struct TestCase TestCase;
+struct TestCase {
+    const char *arch;
+    const char *machine;
+    uint64_t isa_base;
+    bool bswap;
+    const char *superio;
+};
+
+static const TestCase test_cases[] = {
+    { "i386", "pc", -1 },
+    { "mips", "mips", 0x14000000, .bswap = true },
+    { "mips", "malta", 0x10000000, .bswap = true },
+    { "mips64", "magnum", 0x90000000, .bswap = true },
+    { "mips64", "pica61", 0x90000000, .bswap = true },
+    { "mips64", "mips", 0x14000000, .bswap = true },
+    { "mips64", "malta", 0x10000000, .bswap = true },
+    { "mips64el", "fulong2e", 0x1fd00000 },
+    { "ppc", "g3beige", 0xfe000000, .bswap = true, .superio = "i82378" },
+    { "ppc", "prep", 0x80000000, .bswap = true },
+    { "ppc", "bamboo", 0xe8000000, .bswap = true, .superio = "i82378" },
+    { "ppc64", "mac99", 0xf2000000, .bswap = true, .superio = "i82378" },
+    { "ppc64", "pseries", (1ULL << 45), .bswap = true, .superio = "i82378" },
+    { "ppc64", "pseries-2.7", 0x10080000000ULL,
+      .bswap = true, .superio = "i82378" },
+    { "sh4", "r2d", 0xfe240000, .superio = "i82378" },
+    { "sh4eb", "r2d", 0xfe240000, .bswap = true, .superio = "i82378" },
+    { "sparc64", "sun4u", 0x1fe02000000LL, .bswap = true },
+    { "x86_64", "pc", -1 },
+    {}
+};
+
+static uint8_t isa_inb(QTestState *qts, const TestCase *test, uint16_t addr)
+{
+    uint8_t value;
+    if (test->isa_base == -1) {
+        value = qtest_inb(qts, addr);
+    } else {
+        value = qtest_readb(qts, test->isa_base + addr);
+    }
+    return value;
+}
+
+static uint16_t isa_inw(QTestState *qts, const TestCase *test, uint16_t addr)
+{
+    uint16_t value;
+    if (test->isa_base == -1) {
+        value = qtest_inw(qts, addr);
+    } else {
+        value = qtest_readw(qts, test->isa_base + addr);
+    }
+    return test->bswap ? bswap16(value) : value;
+}
+
+static uint32_t isa_inl(QTestState *qts, const TestCase *test, uint16_t addr)
+{
+    uint32_t value;
+    if (test->isa_base == -1) {
+        value = qtest_inl(qts, addr);
+    } else {
+        value = qtest_readl(qts, test->isa_base + addr);
+    }
+    return test->bswap ? bswap32(value) : value;
+}
+
+static void isa_outb(QTestState *qts, const TestCase *test, uint16_t addr,
+                     uint8_t value)
+{
+    if (test->isa_base == -1) {
+        qtest_outb(qts, addr, value);
+    } else {
+        qtest_writeb(qts, test->isa_base + addr, value);
+    }
+}
+
+static void isa_outw(QTestState *qts, const TestCase *test, uint16_t addr,
+                     uint16_t value)
+{
+    value = test->bswap ? bswap16(value) : value;
+    if (test->isa_base == -1) {
+        qtest_outw(qts, addr, value);
+    } else {
+        qtest_writew(qts, test->isa_base + addr, value);
+    }
+}
+
+static void isa_outl(QTestState *qts, const TestCase *test, uint16_t addr,
+                     uint32_t value)
+{
+    value = test->bswap ? bswap32(value) : value;
+    if (test->isa_base == -1) {
+        qtest_outl(qts, addr, value);
+    } else {
+        qtest_writel(qts, test->isa_base + addr, value);
+    }
+}
+
+
+static void test_endianness(gconstpointer data)
+{
+    const TestCase *test = data;
+    QTestState *qts;
+
+    qts = qtest_initf("-M %s%s%s -device pc-testdev", test->machine,
+                      test->superio ? " -device " : "",
+                      test->superio ?: "");
+    isa_outl(qts, test, 0xe0, 0x87654321);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
+    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
+    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65);
+    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43);
+    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x21);
+
+    isa_outw(qts, test, 0xe2, 0x8866);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664321);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866);
+    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
+    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x88);
+    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x66);
+    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43);
+    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x21);
+
+    isa_outw(qts, test, 0xe0, 0x4422);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664422);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866);
+    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422);
+    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x88);
+    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x66);
+    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x44);
+    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22);
+
+    isa_outb(qts, test, 0xe3, 0x87);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87664422);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8766);
+    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
+    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x66);
+    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x44);
+    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22);
+
+    isa_outb(qts, test, 0xe2, 0x65);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654422);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422);
+    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
+    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65);
+    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x44);
+    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22);
+
+    isa_outb(qts, test, 0xe1, 0x43);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654322);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4322);
+    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
+    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65);
+    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43);
+    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22);
+
+    isa_outb(qts, test, 0xe0, 0x21);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
+    g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
+    g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65);
+    g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43);
+    g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x21);
+    qtest_quit(qts);
+}
+
+static void test_endianness_split(gconstpointer data)
+{
+    const TestCase *test = data;
+    QTestState *qts;
+
+    qts = qtest_initf("-M %s%s%s -device pc-testdev", test->machine,
+                      test->superio ? " -device " : "",
+                      test->superio ?: "");
+    isa_outl(qts, test, 0xe8, 0x87654321);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
+
+    isa_outw(qts, test, 0xea, 0x8866);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664321);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866);
+    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
+
+    isa_outw(qts, test, 0xe8, 0x4422);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664422);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866);
+    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422);
+
+    isa_outb(qts, test, 0xeb, 0x87);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87664422);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8766);
+
+    isa_outb(qts, test, 0xea, 0x65);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654422);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422);
+
+    isa_outb(qts, test, 0xe9, 0x43);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654322);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4322);
+
+    isa_outb(qts, test, 0xe8, 0x21);
+    g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321);
+    g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+    g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
+    qtest_quit(qts);
+}
+
+static void test_endianness_combine(gconstpointer data)
+{
+    const TestCase *test = data;
+    QTestState *qts;
+
+    qts = qtest_initf("-M %s%s%s -device pc-testdev", test->machine,
+                      test->superio ? " -device " : "",
+                      test->superio ?: "");
+    isa_outl(qts, test, 0xe0, 0x87654321);
+    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654321);
+    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765);
+    g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4321);
+
+    isa_outw(qts, test, 0xe2, 0x8866);
+    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x88664321);
+    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8866);
+    g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4321);
+
+    isa_outw(qts, test, 0xe0, 0x4422);
+    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x88664422);
+    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8866);
+    g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4422);
+
+    isa_outb(qts, test, 0xe3, 0x87);
+    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87664422);
+    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8766);
+
+    isa_outb(qts, test, 0xe2, 0x65);
+    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654422);
+    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765);
+    g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4422);
+
+    isa_outb(qts, test, 0xe1, 0x43);
+    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654322);
+    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765);
+    g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4322);
+
+    isa_outb(qts, test, 0xe0, 0x21);
+    g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654321);
+    g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765);
+    g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4321);
+    qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+    const char *arch = qtest_get_arch();
+    int i;
+
+    g_test_init(&argc, &argv, NULL);
+
+    for (i = 0; test_cases[i].arch; i++) {
+        gchar *path;
+        if (strcmp(test_cases[i].arch, arch) != 0) {
+            continue;
+        }
+        path = g_strdup_printf("endianness/%s",
+                               test_cases[i].machine);
+        qtest_add_data_func(path, &test_cases[i], test_endianness);
+        g_free(path);
+
+        path = g_strdup_printf("endianness/split/%s",
+                               test_cases[i].machine);
+        qtest_add_data_func(path, &test_cases[i], test_endianness_split);
+        g_free(path);
+
+        path = g_strdup_printf("endianness/combine/%s",
+                               test_cases[i].machine);
+        qtest_add_data_func(path, &test_cases[i], test_endianness_combine);
+        g_free(path);
+    }
+
+    return g_test_run();
+}
diff --git a/tests/qtest/es1370-test.c b/tests/qtest/es1370-test.c
new file mode 100644 (file)
index 0000000..adccdac
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * QTest testcase for ES1370
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
+
+typedef struct QES1370 QES1370;
+
+struct QES1370 {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *es1370_get_driver(void *obj, const char *interface)
+{
+    QES1370 *es1370 = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &es1370->dev;
+    }
+
+    fprintf(stderr, "%s not present in e1000e\n", interface);
+    g_assert_not_reached();
+}
+
+static void *es1370_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QES1370 *es1370 = g_new0(QES1370, 1);
+    QPCIBus *bus = pci_bus;
+
+    qpci_device_init(&es1370->dev, bus, addr);
+    es1370->obj.get_driver = es1370_get_driver;
+
+    return &es1370->obj;
+}
+
+static void es1370_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+
+    qos_node_create_driver("ES1370", es1370_create);
+    qos_node_consumes("ES1370", "pci-bus", &opts);
+    qos_node_produces("ES1370", "pci-device");
+}
+
+libqos_init(es1370_register_nodes);
diff --git a/tests/qtest/fdc-test.c b/tests/qtest/fdc-test.c
new file mode 100644 (file)
index 0000000..26b69f7
--- /dev/null
@@ -0,0 +1,587 @@
+/*
+ * Floppy test cases.
+ *
+ * Copyright (c) 2012 Kevin Wolf <[email protected]>
+ *
+ * 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 "libqtest-single.h"
+#include "qapi/qmp/qdict.h"
+#include "qemu-common.h"
+
+/* TODO actually test the results and get rid of this */
+#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
+
+#define TEST_IMAGE_SIZE 1440 * 1024
+
+#define FLOPPY_BASE 0x3f0
+#define FLOPPY_IRQ 6
+
+enum {
+    reg_sra         = 0x0,
+    reg_srb         = 0x1,
+    reg_dor         = 0x2,
+    reg_msr         = 0x4,
+    reg_dsr         = 0x4,
+    reg_fifo        = 0x5,
+    reg_dir         = 0x7,
+};
+
+enum {
+    CMD_SENSE_INT           = 0x08,
+    CMD_READ_ID             = 0x0a,
+    CMD_SEEK                = 0x0f,
+    CMD_VERIFY              = 0x16,
+    CMD_READ                = 0xe6,
+    CMD_RELATIVE_SEEK_OUT   = 0x8f,
+    CMD_RELATIVE_SEEK_IN    = 0xcf,
+};
+
+enum {
+    BUSY    = 0x10,
+    NONDMA  = 0x20,
+    RQM     = 0x80,
+    DIO     = 0x40,
+
+    DSKCHG  = 0x80,
+};
+
+static char test_image[] = "/tmp/qtest.XXXXXX";
+
+#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
+#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
+
+static uint8_t base = 0x70;
+
+enum {
+    CMOS_FLOPPY     = 0x10,
+};
+
+static void floppy_send(uint8_t byte)
+{
+    uint8_t msr;
+
+    msr = inb(FLOPPY_BASE + reg_msr);
+    assert_bit_set(msr, RQM);
+    assert_bit_clear(msr, DIO);
+
+    outb(FLOPPY_BASE + reg_fifo, byte);
+}
+
+static uint8_t floppy_recv(void)
+{
+    uint8_t msr;
+
+    msr = inb(FLOPPY_BASE + reg_msr);
+    assert_bit_set(msr, RQM | DIO);
+
+    return inb(FLOPPY_BASE + reg_fifo);
+}
+
+/* pcn: Present Cylinder Number */
+static void ack_irq(uint8_t *pcn)
+{
+    uint8_t ret;
+
+    g_assert(get_irq(FLOPPY_IRQ));
+    floppy_send(CMD_SENSE_INT);
+    floppy_recv();
+
+    ret = floppy_recv();
+    if (pcn != NULL) {
+        *pcn = ret;
+    }
+
+    g_assert(!get_irq(FLOPPY_IRQ));
+}
+
+static uint8_t send_read_command(uint8_t cmd)
+{
+    uint8_t drive = 0;
+    uint8_t head = 0;
+    uint8_t cyl = 0;
+    uint8_t sect_addr = 1;
+    uint8_t sect_size = 2;
+    uint8_t eot = 1;
+    uint8_t gap = 0x1b;
+    uint8_t gpl = 0xff;
+
+    uint8_t msr = 0;
+    uint8_t st0;
+
+    uint8_t ret = 0;
+
+    floppy_send(cmd);
+    floppy_send(head << 2 | drive);
+    g_assert(!get_irq(FLOPPY_IRQ));
+    floppy_send(cyl);
+    floppy_send(head);
+    floppy_send(sect_addr);
+    floppy_send(sect_size);
+    floppy_send(eot);
+    floppy_send(gap);
+    floppy_send(gpl);
+
+    uint8_t i = 0;
+    uint8_t n = 2;
+    for (; i < n; i++) {
+        msr = inb(FLOPPY_BASE + reg_msr);
+        if (msr == 0xd0) {
+            break;
+        }
+        sleep(1);
+    }
+
+    if (i >= n) {
+        return 1;
+    }
+
+    st0 = floppy_recv();
+    if (st0 != 0x40) {
+        ret = 1;
+    }
+
+    floppy_recv();
+    floppy_recv();
+    floppy_recv();
+    floppy_recv();
+    floppy_recv();
+    floppy_recv();
+
+    return ret;
+}
+
+static uint8_t send_read_no_dma_command(int nb_sect, uint8_t expected_st0)
+{
+    uint8_t drive = 0;
+    uint8_t head = 0;
+    uint8_t cyl = 0;
+    uint8_t sect_addr = 1;
+    uint8_t sect_size = 2;
+    uint8_t eot = nb_sect;
+    uint8_t gap = 0x1b;
+    uint8_t gpl = 0xff;
+
+    uint8_t msr = 0;
+    uint8_t st0;
+
+    uint8_t ret = 0;
+
+    floppy_send(CMD_READ);
+    floppy_send(head << 2 | drive);
+    g_assert(!get_irq(FLOPPY_IRQ));
+    floppy_send(cyl);
+    floppy_send(head);
+    floppy_send(sect_addr);
+    floppy_send(sect_size);
+    floppy_send(eot);
+    floppy_send(gap);
+    floppy_send(gpl);
+
+    uint16_t i = 0;
+    uint8_t n = 2;
+    for (; i < n; i++) {
+        msr = inb(FLOPPY_BASE + reg_msr);
+        if (msr == (BUSY | NONDMA | DIO | RQM)) {
+            break;
+        }
+        sleep(1);
+    }
+
+    if (i >= n) {
+        return 1;
+    }
+
+    /* Non-DMA mode */
+    for (i = 0; i < 512 * 2 * nb_sect; i++) {
+        msr = inb(FLOPPY_BASE + reg_msr);
+        assert_bit_set(msr, BUSY | RQM | DIO);
+        inb(FLOPPY_BASE + reg_fifo);
+    }
+
+    msr = inb(FLOPPY_BASE + reg_msr);
+    assert_bit_set(msr, BUSY | RQM | DIO);
+    g_assert(get_irq(FLOPPY_IRQ));
+
+    st0 = floppy_recv();
+    if (st0 != expected_st0) {
+        ret = 1;
+    }
+
+    floppy_recv();
+    floppy_recv();
+    floppy_recv();
+    floppy_recv();
+    floppy_recv();
+    g_assert(get_irq(FLOPPY_IRQ));
+    floppy_recv();
+
+    /* Check that we're back in command phase */
+    msr = inb(FLOPPY_BASE + reg_msr);
+    assert_bit_clear(msr, BUSY | DIO);
+    assert_bit_set(msr, RQM);
+    g_assert(!get_irq(FLOPPY_IRQ));
+
+    return ret;
+}
+
+static void send_seek(int cyl)
+{
+    int drive = 0;
+    int head = 0;
+
+    floppy_send(CMD_SEEK);
+    floppy_send(head << 2 | drive);
+    g_assert(!get_irq(FLOPPY_IRQ));
+    floppy_send(cyl);
+    ack_irq(NULL);
+}
+
+static uint8_t cmos_read(uint8_t reg)
+{
+    outb(base + 0, reg);
+    return inb(base + 1);
+}
+
+static void test_cmos(void)
+{
+    uint8_t cmos;
+
+    cmos = cmos_read(CMOS_FLOPPY);
+    g_assert(cmos == 0x40 || cmos == 0x50);
+}
+
+static void test_no_media_on_start(void)
+{
+    uint8_t dir;
+
+    /* Media changed bit must be set all time after start if there is
+     * no media in drive. */
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+    send_seek(1);
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+}
+
+static void test_read_without_media(void)
+{
+    uint8_t ret;
+
+    ret = send_read_command(CMD_READ);
+    g_assert(ret == 0);
+}
+
+static void test_media_insert(void)
+{
+    uint8_t dir;
+
+    /* Insert media in drive. DSKCHK should not be reset until a step pulse
+     * is sent. */
+    qmp_discard_response("{'execute':'blockdev-change-medium', 'arguments':{"
+                         " 'id':'floppy0', 'filename': %s, 'format': 'raw' }}",
+                         test_image);
+
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+
+    send_seek(0);
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+
+    /* Step to next track should clear DSKCHG bit. */
+    send_seek(1);
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_clear(dir, DSKCHG);
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_clear(dir, DSKCHG);
+}
+
+static void test_media_change(void)
+{
+    uint8_t dir;
+
+    test_media_insert();
+
+    /* Eject the floppy and check that DSKCHG is set. Reading it out doesn't
+     * reset the bit. */
+    qmp_discard_response("{'execute':'eject', 'arguments':{"
+                         " 'id':'floppy0' }}");
+
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+
+    send_seek(0);
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+
+    send_seek(1);
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+    dir = inb(FLOPPY_BASE + reg_dir);
+    assert_bit_set(dir, DSKCHG);
+}
+
+static void test_sense_interrupt(void)
+{
+    int drive = 0;
+    int head = 0;
+    int cyl = 0;
+    int ret = 0;
+
+    floppy_send(CMD_SENSE_INT);
+    ret = floppy_recv();
+    g_assert(ret == 0x80);
+
+    floppy_send(CMD_SEEK);
+    floppy_send(head << 2 | drive);
+    g_assert(!get_irq(FLOPPY_IRQ));
+    floppy_send(cyl);
+
+    floppy_send(CMD_SENSE_INT);
+    ret = floppy_recv();
+    g_assert(ret == 0x20);
+    floppy_recv();
+}
+
+static void test_relative_seek(void)
+{
+    uint8_t drive = 0;
+    uint8_t head = 0;
+    uint8_t cyl = 1;
+    uint8_t pcn;
+
+    /* Send seek to track 0 */
+    send_seek(0);
+
+    /* Send relative seek to increase track by 1 */
+    floppy_send(CMD_RELATIVE_SEEK_IN);
+    floppy_send(head << 2 | drive);
+    g_assert(!get_irq(FLOPPY_IRQ));
+    floppy_send(cyl);
+
+    ack_irq(&pcn);
+    g_assert(pcn == 1);
+
+    /* Send relative seek to decrease track by 1 */
+    floppy_send(CMD_RELATIVE_SEEK_OUT);
+    floppy_send(head << 2 | drive);
+    g_assert(!get_irq(FLOPPY_IRQ));
+    floppy_send(cyl);
+
+    ack_irq(&pcn);
+    g_assert(pcn == 0);
+}
+
+static void test_read_id(void)
+{
+    uint8_t drive = 0;
+    uint8_t head = 0;
+    uint8_t cyl;
+    uint8_t st0;
+    uint8_t msr;
+
+    /* Seek to track 0 and check with READ ID */
+    send_seek(0);
+
+    floppy_send(CMD_READ_ID);
+    g_assert(!get_irq(FLOPPY_IRQ));
+    floppy_send(head << 2 | drive);
+
+    msr = inb(FLOPPY_BASE + reg_msr);
+    if (!get_irq(FLOPPY_IRQ)) {
+        assert_bit_set(msr, BUSY);
+        assert_bit_clear(msr, RQM);
+    }
+
+    while (!get_irq(FLOPPY_IRQ)) {
+        /* qemu involves a timer with READ ID... */
+        clock_step(1000000000LL / 50);
+    }
+
+    msr = inb(FLOPPY_BASE + reg_msr);
+    assert_bit_set(msr, BUSY | RQM | DIO);
+
+    st0 = floppy_recv();
+    floppy_recv();
+    floppy_recv();
+    cyl = floppy_recv();
+    head = floppy_recv();
+    floppy_recv();
+    g_assert(get_irq(FLOPPY_IRQ));
+    floppy_recv();
+    g_assert(!get_irq(FLOPPY_IRQ));
+
+    g_assert_cmpint(cyl, ==, 0);
+    g_assert_cmpint(head, ==, 0);
+    g_assert_cmpint(st0, ==, head << 2);
+
+    /* Seek to track 8 on head 1 and check with READ ID */
+    head = 1;
+    cyl = 8;
+
+    floppy_send(CMD_SEEK);
+    floppy_send(head << 2 | drive);
+    g_assert(!get_irq(FLOPPY_IRQ));
+    floppy_send(cyl);
+    g_assert(get_irq(FLOPPY_IRQ));
+    ack_irq(NULL);
+
+    floppy_send(CMD_READ_ID);
+    g_assert(!get_irq(FLOPPY_IRQ));
+    floppy_send(head << 2 | drive);
+
+    msr = inb(FLOPPY_BASE + reg_msr);
+    if (!get_irq(FLOPPY_IRQ)) {
+        assert_bit_set(msr, BUSY);
+        assert_bit_clear(msr, RQM);
+    }
+
+    while (!get_irq(FLOPPY_IRQ)) {
+        /* qemu involves a timer with READ ID... */
+        clock_step(1000000000LL / 50);
+    }
+
+    msr = inb(FLOPPY_BASE + reg_msr);
+    assert_bit_set(msr, BUSY | RQM | DIO);
+
+    st0 = floppy_recv();
+    floppy_recv();
+    floppy_recv();
+    cyl = floppy_recv();
+    head = floppy_recv();
+    floppy_recv();
+    g_assert(get_irq(FLOPPY_IRQ));
+    floppy_recv();
+    g_assert(!get_irq(FLOPPY_IRQ));
+
+    g_assert_cmpint(cyl, ==, 8);
+    g_assert_cmpint(head, ==, 1);
+    g_assert_cmpint(st0, ==, head << 2);
+}
+
+static void test_read_no_dma_1(void)
+{
+    uint8_t ret;
+
+    outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08);
+    send_seek(0);
+    ret = send_read_no_dma_command(1, 0x04);
+    g_assert(ret == 0);
+}
+
+static void test_read_no_dma_18(void)
+{
+    uint8_t ret;
+
+    outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08);
+    send_seek(0);
+    ret = send_read_no_dma_command(18, 0x04);
+    g_assert(ret == 0);
+}
+
+static void test_read_no_dma_19(void)
+{
+    uint8_t ret;
+
+    outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08);
+    send_seek(0);
+    ret = send_read_no_dma_command(19, 0x20);
+    g_assert(ret == 0);
+}
+
+static void test_verify(void)
+{
+    uint8_t ret;
+
+    ret = send_read_command(CMD_VERIFY);
+    g_assert(ret == 0);
+}
+
+/* success if no crash or abort */
+static void fuzz_registers(void)
+{
+    unsigned int i;
+
+    for (i = 0; i < 1000; i++) {
+        uint8_t reg, val;
+
+        reg = (uint8_t)g_test_rand_int_range(0, 8);
+        val = (uint8_t)g_test_rand_int_range(0, 256);
+
+        outb(FLOPPY_BASE + reg, val);
+        inb(FLOPPY_BASE + reg);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    int fd;
+    int ret;
+
+    /* Create a temporary raw image */
+    fd = mkstemp(test_image);
+    g_assert(fd >= 0);
+    ret = ftruncate(fd, TEST_IMAGE_SIZE);
+    g_assert(ret == 0);
+    close(fd);
+
+    /* Run the tests */
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_start("-device floppy,id=floppy0");
+    qtest_irq_intercept_in(global_qtest, "ioapic");
+    qtest_add_func("/fdc/cmos", test_cmos);
+    qtest_add_func("/fdc/no_media_on_start", test_no_media_on_start);
+    qtest_add_func("/fdc/read_without_media", test_read_without_media);
+    qtest_add_func("/fdc/media_change", test_media_change);
+    qtest_add_func("/fdc/sense_interrupt", test_sense_interrupt);
+    qtest_add_func("/fdc/relative_seek", test_relative_seek);
+    qtest_add_func("/fdc/read_id", test_read_id);
+    qtest_add_func("/fdc/verify", test_verify);
+    qtest_add_func("/fdc/media_insert", test_media_insert);
+    qtest_add_func("/fdc/read_no_dma_1", test_read_no_dma_1);
+    qtest_add_func("/fdc/read_no_dma_18", test_read_no_dma_18);
+    qtest_add_func("/fdc/read_no_dma_19", test_read_no_dma_19);
+    qtest_add_func("/fdc/fuzz-registers", fuzz_registers);
+
+    ret = g_test_run();
+
+    /* Cleanup */
+    qtest_end();
+    unlink(test_image);
+
+    return ret;
+}
diff --git a/tests/qtest/fw_cfg-test.c b/tests/qtest/fw_cfg-test.c
new file mode 100644 (file)
index 0000000..5dc807b
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * qtest fw_cfg test case
+ *
+ * Copyright IBM, Corp. 2012-2013
+ *
+ * Authors:
+ *  Anthony Liguori   <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqtest.h"
+#include "standard-headers/linux/qemu_fw_cfg.h"
+#include "libqos/fw_cfg.h"
+#include "qemu/bswap.h"
+
+static uint64_t ram_size = 128 << 20;
+static uint16_t nb_cpus = 1;
+static uint16_t max_cpus = 1;
+static uint64_t nb_nodes = 0;
+static uint16_t boot_menu = 0;
+
+static void test_fw_cfg_signature(void)
+{
+    QFWCFG *fw_cfg;
+    QTestState *s;
+    char buf[5];
+
+    s = qtest_init("");
+    fw_cfg = pc_fw_cfg_init(s);
+
+    qfw_cfg_get(fw_cfg, FW_CFG_SIGNATURE, buf, 4);
+    buf[4] = 0;
+
+    g_assert_cmpstr(buf, ==, "QEMU");
+    pc_fw_cfg_uninit(fw_cfg);
+    qtest_quit(s);
+}
+
+static void test_fw_cfg_id(void)
+{
+    QFWCFG *fw_cfg;
+    QTestState *s;
+    uint32_t id;
+
+    s = qtest_init("");
+    fw_cfg = pc_fw_cfg_init(s);
+
+    id = qfw_cfg_get_u32(fw_cfg, FW_CFG_ID);
+    g_assert((id == 1) ||
+             (id == 3));
+    pc_fw_cfg_uninit(fw_cfg);
+    qtest_quit(s);
+}
+
+static void test_fw_cfg_uuid(void)
+{
+    QFWCFG *fw_cfg;
+    QTestState *s;
+
+    uint8_t buf[16];
+    static const uint8_t uuid[16] = {
+        0x46, 0x00, 0xcb, 0x32, 0x38, 0xec, 0x4b, 0x2f,
+        0x8a, 0xcb, 0x81, 0xc6, 0xea, 0x54, 0xf2, 0xd8,
+    };
+
+    s = qtest_init("-uuid 4600cb32-38ec-4b2f-8acb-81c6ea54f2d8");
+    fw_cfg = pc_fw_cfg_init(s);
+
+    qfw_cfg_get(fw_cfg, FW_CFG_UUID, buf, 16);
+    g_assert(memcmp(buf, uuid, sizeof(buf)) == 0);
+
+    pc_fw_cfg_uninit(fw_cfg);
+    qtest_quit(s);
+
+}
+
+static void test_fw_cfg_ram_size(void)
+{
+    QFWCFG *fw_cfg;
+    QTestState *s;
+
+    s = qtest_init("");
+    fw_cfg = pc_fw_cfg_init(s);
+
+    g_assert_cmpint(qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE), ==, ram_size);
+
+    pc_fw_cfg_uninit(fw_cfg);
+    qtest_quit(s);
+}
+
+static void test_fw_cfg_nographic(void)
+{
+    QFWCFG *fw_cfg;
+    QTestState *s;
+
+    s = qtest_init("");
+    fw_cfg = pc_fw_cfg_init(s);
+
+    g_assert_cmpint(qfw_cfg_get_u16(fw_cfg, FW_CFG_NOGRAPHIC), ==, 0);
+
+    pc_fw_cfg_uninit(fw_cfg);
+    qtest_quit(s);
+}
+
+static void test_fw_cfg_nb_cpus(void)
+{
+    QFWCFG *fw_cfg;
+    QTestState *s;
+
+    s = qtest_init("");
+    fw_cfg = pc_fw_cfg_init(s);
+
+    g_assert_cmpint(qfw_cfg_get_u16(fw_cfg, FW_CFG_NB_CPUS), ==, nb_cpus);
+
+    pc_fw_cfg_uninit(fw_cfg);
+    qtest_quit(s);
+}
+
+static void test_fw_cfg_max_cpus(void)
+{
+    QFWCFG *fw_cfg;
+    QTestState *s;
+
+    s = qtest_init("");
+    fw_cfg = pc_fw_cfg_init(s);
+
+    g_assert_cmpint(qfw_cfg_get_u16(fw_cfg, FW_CFG_MAX_CPUS), ==, max_cpus);
+    pc_fw_cfg_uninit(fw_cfg);
+    qtest_quit(s);
+}
+
+static void test_fw_cfg_numa(void)
+{
+    QFWCFG *fw_cfg;
+    QTestState *s;
+    uint64_t *cpu_mask;
+    uint64_t *node_mask;
+
+    s = qtest_init("");
+    fw_cfg = pc_fw_cfg_init(s);
+
+    g_assert_cmpint(qfw_cfg_get_u64(fw_cfg, FW_CFG_NUMA), ==, nb_nodes);
+
+    cpu_mask = g_new0(uint64_t, max_cpus);
+    node_mask = g_new0(uint64_t, nb_nodes);
+
+    qfw_cfg_read_data(fw_cfg, cpu_mask, sizeof(uint64_t) * max_cpus);
+    qfw_cfg_read_data(fw_cfg, node_mask, sizeof(uint64_t) * nb_nodes);
+
+    if (nb_nodes) {
+        g_assert(cpu_mask[0] & 0x01);
+        g_assert_cmpint(node_mask[0], ==, ram_size);
+    }
+
+    g_free(node_mask);
+    g_free(cpu_mask);
+    pc_fw_cfg_uninit(fw_cfg);
+    qtest_quit(s);
+}
+
+static void test_fw_cfg_boot_menu(void)
+{
+    QFWCFG *fw_cfg;
+    QTestState *s;
+
+    s = qtest_init("");
+    fw_cfg = pc_fw_cfg_init(s);
+
+    g_assert_cmpint(qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_MENU), ==, boot_menu);
+    pc_fw_cfg_uninit(fw_cfg);
+    qtest_quit(s);
+}
+
+static void test_fw_cfg_reboot_timeout(void)
+{
+    QFWCFG *fw_cfg;
+    QTestState *s;
+    uint32_t reboot_timeout = 0;
+    size_t filesize;
+
+    s = qtest_init("-boot reboot-timeout=15");
+    fw_cfg = pc_fw_cfg_init(s);
+
+    filesize = qfw_cfg_get_file(fw_cfg, "etc/boot-fail-wait",
+                                &reboot_timeout, sizeof(reboot_timeout));
+    g_assert_cmpint(filesize, ==, sizeof(reboot_timeout));
+    reboot_timeout = le32_to_cpu(reboot_timeout);
+    g_assert_cmpint(reboot_timeout, ==, 15);
+    pc_fw_cfg_uninit(fw_cfg);
+    qtest_quit(s);
+}
+
+static void test_fw_cfg_no_reboot_timeout(void)
+{
+    QFWCFG *fw_cfg;
+    QTestState *s;
+    uint32_t reboot_timeout = 0;
+    size_t filesize;
+
+    /* Special value -1 means "don't reboot" */
+    s = qtest_init("-boot reboot-timeout=-1");
+    fw_cfg = pc_fw_cfg_init(s);
+
+    filesize = qfw_cfg_get_file(fw_cfg, "etc/boot-fail-wait",
+                                &reboot_timeout, sizeof(reboot_timeout));
+    g_assert_cmpint(filesize, ==, sizeof(reboot_timeout));
+    reboot_timeout = le32_to_cpu(reboot_timeout);
+    g_assert_cmpint(reboot_timeout, ==, UINT32_MAX);
+    pc_fw_cfg_uninit(fw_cfg);
+    qtest_quit(s);
+}
+
+static void test_fw_cfg_splash_time(void)
+{
+    QFWCFG *fw_cfg;
+    QTestState *s;
+    uint16_t splash_time = 0;
+    size_t filesize;
+
+    s = qtest_init("-boot splash-time=12");
+    fw_cfg = pc_fw_cfg_init(s);
+
+    filesize = qfw_cfg_get_file(fw_cfg, "etc/boot-menu-wait",
+                                &splash_time, sizeof(splash_time));
+    g_assert_cmpint(filesize, ==, sizeof(splash_time));
+    splash_time = le16_to_cpu(splash_time);
+    g_assert_cmpint(splash_time, ==, 12);
+    pc_fw_cfg_uninit(fw_cfg);
+    qtest_quit(s);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("fw_cfg/signature", test_fw_cfg_signature);
+    qtest_add_func("fw_cfg/id", test_fw_cfg_id);
+    qtest_add_func("fw_cfg/uuid", test_fw_cfg_uuid);
+    qtest_add_func("fw_cfg/ram_size", test_fw_cfg_ram_size);
+    qtest_add_func("fw_cfg/nographic", test_fw_cfg_nographic);
+    qtest_add_func("fw_cfg/nb_cpus", test_fw_cfg_nb_cpus);
+#if 0
+    qtest_add_func("fw_cfg/machine_id", test_fw_cfg_machine_id);
+    qtest_add_func("fw_cfg/kernel", test_fw_cfg_kernel);
+    qtest_add_func("fw_cfg/initrd", test_fw_cfg_initrd);
+    qtest_add_func("fw_cfg/boot_device", test_fw_cfg_boot_device);
+#endif
+    qtest_add_func("fw_cfg/max_cpus", test_fw_cfg_max_cpus);
+    qtest_add_func("fw_cfg/numa", test_fw_cfg_numa);
+    qtest_add_func("fw_cfg/boot_menu", test_fw_cfg_boot_menu);
+    qtest_add_func("fw_cfg/reboot_timeout", test_fw_cfg_reboot_timeout);
+    qtest_add_func("fw_cfg/no_reboot_timeout", test_fw_cfg_no_reboot_timeout);
+    qtest_add_func("fw_cfg/splash_time", test_fw_cfg_splash_time);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/hd-geo-test.c b/tests/qtest/hd-geo-test.c
new file mode 100644 (file)
index 0000000..a249800
--- /dev/null
@@ -0,0 +1,988 @@
+/*
+ * Hard disk geometry test cases.
+ *
+ * Copyright (c) 2012 Red Hat Inc.
+ *
+ * Authors:
+ *  Markus Armbruster <[email protected]>,
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+/*
+ * Covers only IDE and tests only CMOS contents.  Better than nothing.
+ * Improvements welcome.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/bswap.h"
+#include "qapi/qmp/qlist.h"
+#include "libqtest.h"
+#include "libqos/fw_cfg.h"
+#include "libqos/libqos.h"
+#include "standard-headers/linux/qemu_fw_cfg.h"
+
+#define ARGV_SIZE 256
+
+static char *create_test_img(int secs)
+{
+    char *template = strdup("/tmp/qtest.XXXXXX");
+    int fd, ret;
+
+    fd = mkstemp(template);
+    g_assert(fd >= 0);
+    ret = ftruncate(fd, (off_t)secs * 512);
+    close(fd);
+
+    if (ret) {
+        free(template);
+        template = NULL;
+    }
+
+    return template;
+}
+
+typedef struct {
+    int cyls, heads, secs, trans;
+} CHST;
+
+typedef enum {
+    mbr_blank, mbr_lba, mbr_chs,
+    mbr_last
+} MBRcontents;
+
+typedef enum {
+    /* order is relevant */
+    backend_small, backend_large, backend_empty,
+    backend_last
+} Backend;
+
+static const int img_secs[backend_last] = {
+    [backend_small] = 61440,
+    [backend_large] = 8388608,
+    [backend_empty] = -1,
+};
+
+static const CHST hd_chst[backend_last][mbr_last] = {
+    [backend_small] = {
+        [mbr_blank] = { 60, 16, 63, 0 },
+        [mbr_lba]   = { 60, 16, 63, 2 },
+        [mbr_chs]   = { 60, 16, 63, 0 }
+    },
+    [backend_large] = {
+        [mbr_blank] = { 8322, 16, 63, 1 },
+        [mbr_lba]   = { 8322, 16, 63, 1 },
+        [mbr_chs]   = { 8322, 16, 63, 0 }
+    },
+};
+
+static char *img_file_name[backend_last];
+
+static const CHST *cur_ide[4];
+
+static bool is_hd(const CHST *expected_chst)
+{
+    return expected_chst && expected_chst->cyls;
+}
+
+static void test_cmos_byte(QTestState *qts, int reg, int expected)
+{
+    enum { cmos_base = 0x70 };
+    int actual;
+
+    qtest_outb(qts, cmos_base + 0, reg);
+    actual = qtest_inb(qts, cmos_base + 1);
+    g_assert(actual == expected);
+}
+
+static void test_cmos_bytes(QTestState *qts, int reg0, int n,
+                            uint8_t expected[])
+{
+    int i;
+
+    for (i = 0; i < 9; i++) {
+        test_cmos_byte(qts, reg0 + i, expected[i]);
+    }
+}
+
+static void test_cmos_disk_data(QTestState *qts)
+{
+    test_cmos_byte(qts, 0x12,
+                   (is_hd(cur_ide[0]) ? 0xf0 : 0) |
+                   (is_hd(cur_ide[1]) ? 0x0f : 0));
+}
+
+static void test_cmos_drive_cyl(QTestState *qts, int reg0,
+                                const CHST *expected_chst)
+{
+    if (is_hd(expected_chst)) {
+        int c = expected_chst->cyls;
+        int h = expected_chst->heads;
+        int s = expected_chst->secs;
+        uint8_t expected_bytes[9] = {
+            c & 0xff, c >> 8, h, 0xff, 0xff, 0xc0 | ((h > 8) << 3),
+            c & 0xff, c >> 8, s
+        };
+        test_cmos_bytes(qts, reg0, 9, expected_bytes);
+    } else {
+        int i;
+
+        for (i = 0; i < 9; i++) {
+            test_cmos_byte(qts, reg0 + i, 0);
+        }
+    }
+}
+
+static void test_cmos_drive1(QTestState *qts)
+{
+    test_cmos_byte(qts, 0x19, is_hd(cur_ide[0]) ? 47 : 0);
+    test_cmos_drive_cyl(qts, 0x1b, cur_ide[0]);
+}
+
+static void test_cmos_drive2(QTestState *qts)
+{
+    test_cmos_byte(qts, 0x1a, is_hd(cur_ide[1]) ? 47 : 0);
+    test_cmos_drive_cyl(qts, 0x24, cur_ide[1]);
+}
+
+static void test_cmos_disktransflag(QTestState *qts)
+{
+    int val, i;
+
+    val = 0;
+    for (i = 0; i < ARRAY_SIZE(cur_ide); i++) {
+        if (is_hd(cur_ide[i])) {
+            val |= cur_ide[i]->trans << (2 * i);
+        }
+    }
+    test_cmos_byte(qts, 0x39, val);
+}
+
+static void test_cmos(QTestState *qts)
+{
+    test_cmos_disk_data(qts);
+    test_cmos_drive1(qts);
+    test_cmos_drive2(qts);
+    test_cmos_disktransflag(qts);
+}
+
+static int append_arg(int argc, char *argv[], int argv_sz, char *arg)
+{
+    g_assert(argc + 1 < argv_sz);
+    argv[argc++] = arg;
+    argv[argc] = NULL;
+    return argc;
+}
+
+static int setup_common(char *argv[], int argv_sz)
+{
+    memset(cur_ide, 0, sizeof(cur_ide));
+    return append_arg(0, argv, argv_sz,
+                      g_strdup("-nodefaults"));
+}
+
+static void setup_mbr(int img_idx, MBRcontents mbr)
+{
+    static const uint8_t part_lba[16] = {
+        /* chs 0,1,1 (lba 63) to chs 0,127,63 (8001 sectors) */
+        0x80, 1, 1, 0, 6, 127, 63, 0, 63, 0, 0, 0, 0x41, 0x1F, 0, 0,
+    };
+    static const uint8_t part_chs[16] = {
+        /* chs 0,1,1 (lba 63) to chs 7,15,63 (8001 sectors) */
+        0x80, 1, 1, 0, 6,  15, 63, 7, 63, 0, 0, 0, 0x41, 0x1F, 0, 0,
+    };
+    uint8_t buf[512];
+    int fd, ret;
+
+    memset(buf, 0, sizeof(buf));
+
+    if (mbr != mbr_blank) {
+        buf[0x1fe] = 0x55;
+        buf[0x1ff] = 0xAA;
+        memcpy(buf + 0x1BE, mbr == mbr_lba ? part_lba : part_chs, 16);
+    }
+
+    fd = open(img_file_name[img_idx], O_WRONLY);
+    g_assert(fd >= 0);
+    ret = write(fd, buf, sizeof(buf));
+    g_assert(ret == sizeof(buf));
+    close(fd);
+}
+
+static int setup_ide(int argc, char *argv[], int argv_sz,
+                     int ide_idx, const char *dev, int img_idx,
+                     MBRcontents mbr)
+{
+    char *s1, *s2, *s3;
+
+    s1 = g_strdup_printf("-drive id=drive%d,if=%s",
+                         ide_idx, dev ? "none" : "ide");
+    s2 = dev ? g_strdup("") : g_strdup_printf(",index=%d", ide_idx);
+
+    if (img_secs[img_idx] >= 0) {
+        setup_mbr(img_idx, mbr);
+        s3 = g_strdup_printf(",format=raw,file=%s", img_file_name[img_idx]);
+    } else {
+        s3 = g_strdup(",media=cdrom");
+    }
+    argc = append_arg(argc, argv, argv_sz,
+                      g_strdup_printf("%s%s%s", s1, s2, s3));
+    g_free(s1);
+    g_free(s2);
+    g_free(s3);
+
+    if (dev) {
+        argc = append_arg(argc, argv, argv_sz,
+                          g_strdup_printf("-device %s,drive=drive%d,"
+                                          "bus=ide.%d,unit=%d",
+                                          dev, ide_idx,
+                                          ide_idx / 2, ide_idx % 2));
+    }
+    return argc;
+}
+
+/*
+ * Test case: no IDE devices
+ */
+static void test_ide_none(void)
+{
+    char **argv = g_new0(char *, ARGV_SIZE);
+    char *args;
+    QTestState *qts;
+
+    setup_common(argv, ARGV_SIZE);
+    args = g_strjoinv(" ", argv);
+    qts = qtest_init(args);
+    g_strfreev(argv);
+    g_free(args);
+    test_cmos(qts);
+    qtest_quit(qts);
+}
+
+static void test_ide_mbr(bool use_device, MBRcontents mbr)
+{
+    char **argv = g_new0(char *, ARGV_SIZE);
+    char *args;
+    int argc;
+    Backend i;
+    const char *dev;
+    QTestState *qts;
+
+    argc = setup_common(argv, ARGV_SIZE);
+    for (i = 0; i < backend_last; i++) {
+        cur_ide[i] = &hd_chst[i][mbr];
+        dev = use_device ? (is_hd(cur_ide[i]) ? "ide-hd" : "ide-cd") : NULL;
+        argc = setup_ide(argc, argv, ARGV_SIZE, i, dev, i, mbr);
+    }
+    args = g_strjoinv(" ", argv);
+    qts = qtest_init(args);
+    g_strfreev(argv);
+    g_free(args);
+    test_cmos(qts);
+    qtest_quit(qts);
+}
+
+/*
+ * Test case: IDE devices (if=ide) with blank MBRs
+ */
+static void test_ide_drive_mbr_blank(void)
+{
+    test_ide_mbr(false, mbr_blank);
+}
+
+/*
+ * Test case: IDE devices (if=ide) with MBRs indicating LBA is in use
+ */
+static void test_ide_drive_mbr_lba(void)
+{
+    test_ide_mbr(false, mbr_lba);
+}
+
+/*
+ * Test case: IDE devices (if=ide) with MBRs indicating CHS is in use
+ */
+static void test_ide_drive_mbr_chs(void)
+{
+    test_ide_mbr(false, mbr_chs);
+}
+
+/*
+ * Test case: IDE devices (if=none) with blank MBRs
+ */
+static void test_ide_device_mbr_blank(void)
+{
+    test_ide_mbr(true, mbr_blank);
+}
+
+/*
+ * Test case: IDE devices (if=none) with MBRs indicating LBA is in use
+ */
+static void test_ide_device_mbr_lba(void)
+{
+    test_ide_mbr(true, mbr_lba);
+}
+
+/*
+ * Test case: IDE devices (if=none) with MBRs indicating CHS is in use
+ */
+static void test_ide_device_mbr_chs(void)
+{
+    test_ide_mbr(true, mbr_chs);
+}
+
+static void test_ide_drive_user(const char *dev, bool trans)
+{
+    char **argv = g_new0(char *, ARGV_SIZE);
+    char *args, *opts;
+    int argc;
+    int secs = img_secs[backend_small];
+    const CHST expected_chst = { secs / (4 * 32) , 4, 32, trans };
+    QTestState *qts;
+
+    argc = setup_common(argv, ARGV_SIZE);
+    opts = g_strdup_printf("%s,%scyls=%d,heads=%d,secs=%d",
+                           dev, trans ? "bios-chs-trans=lba," : "",
+                           expected_chst.cyls, expected_chst.heads,
+                           expected_chst.secs);
+    cur_ide[0] = &expected_chst;
+    argc = setup_ide(argc, argv, ARGV_SIZE, 0, opts, backend_small, mbr_chs);
+    g_free(opts);
+    args = g_strjoinv(" ", argv);
+    qts = qtest_init(args);
+    g_strfreev(argv);
+    g_free(args);
+    test_cmos(qts);
+    qtest_quit(qts);
+}
+
+/*
+ * Test case: IDE device (if=none) with explicit CHS
+ */
+static void test_ide_device_user_chs(void)
+{
+    test_ide_drive_user("ide-hd", false);
+}
+
+/*
+ * Test case: IDE device (if=none) with explicit CHS and translation
+ */
+static void test_ide_device_user_chst(void)
+{
+    test_ide_drive_user("ide-hd", true);
+}
+
+/*
+ * Test case: IDE devices (if=ide), but use index=0 for CD-ROM
+ */
+static void test_ide_drive_cd_0(void)
+{
+    char **argv = g_new0(char *, ARGV_SIZE);
+    char *args;
+    int argc, ide_idx;
+    Backend i;
+    QTestState *qts;
+
+    argc = setup_common(argv, ARGV_SIZE);
+    for (i = 0; i <= backend_empty; i++) {
+        ide_idx = backend_empty - i;
+        cur_ide[ide_idx] = &hd_chst[i][mbr_blank];
+        argc = setup_ide(argc, argv, ARGV_SIZE, ide_idx, NULL, i, mbr_blank);
+    }
+    args = g_strjoinv(" ", argv);
+    qts = qtest_init(args);
+    g_strfreev(argv);
+    g_free(args);
+    test_cmos(qts);
+    qtest_quit(qts);
+}
+
+typedef struct {
+    bool active;
+    uint32_t head;
+    uint32_t sector;
+    uint32_t cyl;
+    uint32_t end_head;
+    uint32_t end_sector;
+    uint32_t end_cyl;
+    uint32_t start_sect;
+    uint32_t nr_sects;
+} MBRpartitions[4];
+
+static MBRpartitions empty_mbr = { {false, 0, 0, 0, 0, 0, 0, 0, 0},
+                                   {false, 0, 0, 0, 0, 0, 0, 0, 0},
+                                   {false, 0, 0, 0, 0, 0, 0, 0, 0},
+                                   {false, 0, 0, 0, 0, 0, 0, 0, 0} };
+
+static char *create_qcow2_with_mbr(MBRpartitions mbr, uint64_t sectors)
+{
+    const char *template = "/tmp/qtest.XXXXXX";
+    char *raw_path = strdup(template);
+    char *qcow2_path = strdup(template);
+    char cmd[100 + 2 * PATH_MAX];
+    uint8_t buf[512];
+    int i, ret, fd, offset;
+    uint64_t qcow2_size = sectors * 512;
+    uint8_t status, parttype, head, sector, cyl;
+    char *qemu_img_path;
+    char *qemu_img_abs_path;
+
+    offset = 0xbe;
+
+    for (i = 0; i < 4; i++) {
+        status = mbr[i].active ? 0x80 : 0x00;
+        g_assert(mbr[i].head < 256);
+        g_assert(mbr[i].sector < 64);
+        g_assert(mbr[i].cyl < 1024);
+        head = mbr[i].head;
+        sector = mbr[i].sector + ((mbr[i].cyl & 0x300) >> 2);
+        cyl = mbr[i].cyl & 0xff;
+
+        buf[offset + 0x0] = status;
+        buf[offset + 0x1] = head;
+        buf[offset + 0x2] = sector;
+        buf[offset + 0x3] = cyl;
+
+        parttype = 0;
+        g_assert(mbr[i].end_head < 256);
+        g_assert(mbr[i].end_sector < 64);
+        g_assert(mbr[i].end_cyl < 1024);
+        head = mbr[i].end_head;
+        sector = mbr[i].end_sector + ((mbr[i].end_cyl & 0x300) >> 2);
+        cyl = mbr[i].end_cyl & 0xff;
+
+        buf[offset + 0x4] = parttype;
+        buf[offset + 0x5] = head;
+        buf[offset + 0x6] = sector;
+        buf[offset + 0x7] = cyl;
+
+        (*(uint32_t *)&buf[offset + 0x8]) = cpu_to_le32(mbr[i].start_sect);
+        (*(uint32_t *)&buf[offset + 0xc]) = cpu_to_le32(mbr[i].nr_sects);
+
+        offset += 0x10;
+    }
+
+    fd = mkstemp(raw_path);
+    g_assert(fd);
+    close(fd);
+
+    fd = open(raw_path, O_WRONLY);
+    g_assert(fd >= 0);
+    ret = write(fd, buf, sizeof(buf));
+    g_assert(ret == sizeof(buf));
+    close(fd);
+
+    fd = mkstemp(qcow2_path);
+    g_assert(fd);
+    close(fd);
+
+    qemu_img_path = getenv("QTEST_QEMU_IMG");
+    g_assert(qemu_img_path);
+    qemu_img_abs_path = realpath(qemu_img_path, NULL);
+    g_assert(qemu_img_abs_path);
+
+    ret = snprintf(cmd, sizeof(cmd),
+                   "%s convert -f raw -O qcow2 %s %s > /dev/null",
+                   qemu_img_abs_path,
+                   raw_path, qcow2_path);
+    g_assert((0 < ret) && (ret <= sizeof(cmd)));
+    ret = system(cmd);
+    g_assert(ret == 0);
+
+    ret = snprintf(cmd, sizeof(cmd),
+                   "%s resize %s %" PRIu64 " > /dev/null",
+                   qemu_img_abs_path,
+                   qcow2_path, qcow2_size);
+    g_assert((0 < ret) && (ret <= sizeof(cmd)));
+    ret = system(cmd);
+    g_assert(ret == 0);
+
+    free(qemu_img_abs_path);
+
+    unlink(raw_path);
+    free(raw_path);
+
+    return qcow2_path;
+}
+
+#define BIOS_GEOMETRY_MAX_SIZE 10000
+
+typedef struct {
+    uint32_t c;
+    uint32_t h;
+    uint32_t s;
+} CHS;
+
+typedef struct {
+    const char *dev_path;
+    CHS chs;
+} CHSResult;
+
+static void read_bootdevices(QFWCFG *fw_cfg, CHSResult expected[])
+{
+    char *buf = g_malloc0(BIOS_GEOMETRY_MAX_SIZE);
+    char *cur;
+    GList *results = NULL, *cur_result;
+    CHSResult *r;
+    int i;
+    int res;
+    bool found;
+
+    qfw_cfg_get_file(fw_cfg, "bios-geometry", buf, BIOS_GEOMETRY_MAX_SIZE);
+
+    for (cur = buf; *cur; cur++) {
+        if (*cur == '\n') {
+            *cur = '\0';
+        }
+    }
+    cur = buf;
+
+    while (strlen(cur)) {
+
+        r = g_malloc0(sizeof(*r));
+        r->dev_path = g_malloc0(strlen(cur) + 1);
+        res = sscanf(cur, "%s %" PRIu32 " %" PRIu32 " %" PRIu32,
+                     (char *)r->dev_path,
+                     &(r->chs.c), &(r->chs.h), &(r->chs.s));
+
+        g_assert(res == 4);
+
+        results = g_list_prepend(results, r);
+
+        cur += strlen(cur) + 1;
+    }
+
+    i = 0;
+
+    while (expected[i].dev_path) {
+        found = false;
+        cur_result = results;
+        while (cur_result) {
+            r = cur_result->data;
+            if (!strcmp(r->dev_path, expected[i].dev_path) &&
+                !memcmp(&(r->chs), &(expected[i].chs), sizeof(r->chs))) {
+                found = true;
+                break;
+            }
+            cur_result = g_list_next(cur_result);
+        }
+        g_assert(found);
+        g_free((char *)((CHSResult *)cur_result->data)->dev_path);
+        g_free(cur_result->data);
+        results = g_list_delete_link(results, cur_result);
+        i++;
+    }
+
+    g_assert(results == NULL);
+
+    g_free(buf);
+}
+
+#define MAX_DRIVES 30
+
+typedef struct {
+    char **argv;
+    int argc;
+    char **drives;
+    int n_drives;
+    int n_scsi_disks;
+    int n_scsi_controllers;
+    int n_virtio_disks;
+} TestArgs;
+
+static TestArgs *create_args(void)
+{
+    TestArgs *args = g_malloc0(sizeof(*args));
+    args->argv = g_new0(char *, ARGV_SIZE);
+    args->argc = append_arg(args->argc, args->argv,
+                            ARGV_SIZE, g_strdup("-nodefaults"));
+    args->drives = g_new0(char *, MAX_DRIVES);
+    return args;
+}
+
+static void add_drive_with_mbr(TestArgs *args,
+                               MBRpartitions mbr, uint64_t sectors)
+{
+    char *img_file_name;
+    char part[300];
+    int ret;
+
+    g_assert(args->n_drives < MAX_DRIVES);
+
+    img_file_name = create_qcow2_with_mbr(mbr, sectors);
+
+    args->drives[args->n_drives] = img_file_name;
+    ret = snprintf(part, sizeof(part),
+                   "-drive file=%s,if=none,format=qcow2,id=disk%d",
+                   img_file_name, args->n_drives);
+    g_assert((0 < ret) && (ret <= sizeof(part)));
+    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
+    args->n_drives++;
+}
+
+static void add_ide_disk(TestArgs *args,
+                         int drive_idx, int bus, int unit, int c, int h, int s)
+{
+    char part[300];
+    int ret;
+
+    ret = snprintf(part, sizeof(part),
+                   "-device ide-hd,drive=disk%d,bus=ide.%d,unit=%d,"
+                   "lcyls=%d,lheads=%d,lsecs=%d",
+                   drive_idx, bus, unit, c, h, s);
+    g_assert((0 < ret) && (ret <= sizeof(part)));
+    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
+}
+
+static void add_scsi_controller(TestArgs *args,
+                                const char *type,
+                                const char *bus,
+                                int addr)
+{
+    char part[300];
+    int ret;
+
+    ret = snprintf(part, sizeof(part),
+                   "-device %s,id=scsi%d,bus=%s,addr=%d",
+                   type, args->n_scsi_controllers, bus, addr);
+    g_assert((0 < ret) && (ret <= sizeof(part)));
+    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
+    args->n_scsi_controllers++;
+}
+
+static void add_scsi_disk(TestArgs *args,
+                          int drive_idx, int bus,
+                          int channel, int scsi_id, int lun,
+                          int c, int h, int s)
+{
+    char part[300];
+    int ret;
+
+    ret = snprintf(part, sizeof(part),
+                   "-device scsi-hd,id=scsi-disk%d,drive=disk%d,"
+                   "bus=scsi%d.0,"
+                   "channel=%d,scsi-id=%d,lun=%d,"
+                   "lcyls=%d,lheads=%d,lsecs=%d",
+                   args->n_scsi_disks, drive_idx, bus, channel, scsi_id, lun,
+                   c, h, s);
+    g_assert((0 < ret) && (ret <= sizeof(part)));
+    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
+    args->n_scsi_disks++;
+}
+
+static void add_virtio_disk(TestArgs *args,
+                            int drive_idx, const char *bus, int addr,
+                            int c, int h, int s)
+{
+    char part[300];
+    int ret;
+
+    ret = snprintf(part, sizeof(part),
+                   "-device virtio-blk-pci,id=virtio-disk%d,"
+                   "drive=disk%d,bus=%s,addr=%d,"
+                   "lcyls=%d,lheads=%d,lsecs=%d",
+                   args->n_virtio_disks, drive_idx, bus, addr, c, h, s);
+    g_assert((0 < ret) && (ret <= sizeof(part)));
+    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
+    args->n_virtio_disks++;
+}
+
+static void test_override(TestArgs *args, CHSResult expected[])
+{
+    QTestState *qts;
+    char *joined_args;
+    QFWCFG *fw_cfg;
+    int i;
+
+    joined_args = g_strjoinv(" ", args->argv);
+
+    qts = qtest_init(joined_args);
+    fw_cfg = pc_fw_cfg_init(qts);
+
+    read_bootdevices(fw_cfg, expected);
+
+    g_free(joined_args);
+    qtest_quit(qts);
+
+    g_free(fw_cfg);
+
+    for (i = 0; i < args->n_drives; i++) {
+        unlink(args->drives[i]);
+        free(args->drives[i]);
+    }
+    g_free(args->drives);
+    g_strfreev(args->argv);
+    g_free(args);
+}
+
+static void test_override_ide(void)
+{
+    TestArgs *args = create_args();
+    CHSResult expected[] = {
+        {"/pci@i0cf8/ide@1,1/drive@0/disk@0", {10000, 120, 30} },
+        {"/pci@i0cf8/ide@1,1/drive@0/disk@1", {9000, 120, 30} },
+        {"/pci@i0cf8/ide@1,1/drive@1/disk@0", {0, 1, 1} },
+        {"/pci@i0cf8/ide@1,1/drive@1/disk@1", {1, 0, 0} },
+        {NULL, {0, 0, 0} }
+    };
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_ide_disk(args, 0, 0, 0, 10000, 120, 30);
+    add_ide_disk(args, 1, 0, 1, 9000, 120, 30);
+    add_ide_disk(args, 2, 1, 0, 0, 1, 1);
+    add_ide_disk(args, 3, 1, 1, 1, 0, 0);
+    test_override(args, expected);
+}
+
+static void test_override_scsi(void)
+{
+    TestArgs *args = create_args();
+    CHSResult expected[] = {
+        {"/pci@i0cf8/scsi@3/channel@0/disk@0,0", {10000, 120, 30} },
+        {"/pci@i0cf8/scsi@3/channel@0/disk@1,0", {9000, 120, 30} },
+        {"/pci@i0cf8/scsi@3/channel@0/disk@2,0", {1, 0, 0} },
+        {"/pci@i0cf8/scsi@3/channel@0/disk@3,0", {0, 1, 0} },
+        {NULL, {0, 0, 0} }
+    };
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_scsi_controller(args, "lsi53c895a", "pci.0", 3);
+    add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
+    add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30);
+    add_scsi_disk(args, 2, 0, 0, 2, 0, 1, 0, 0);
+    add_scsi_disk(args, 3, 0, 0, 3, 0, 0, 1, 0);
+    test_override(args, expected);
+}
+
+static void test_override_scsi_2_controllers(void)
+{
+    TestArgs *args = create_args();
+    CHSResult expected[] = {
+        {"/pci@i0cf8/scsi@3/channel@0/disk@0,0", {10000, 120, 30} },
+        {"/pci@i0cf8/scsi@3/channel@0/disk@1,0", {9000, 120, 30} },
+        {"/pci@i0cf8/scsi@4/channel@0/disk@0,1", {1, 0, 0} },
+        {"/pci@i0cf8/scsi@4/channel@0/disk@1,2", {0, 1, 0} },
+        {NULL, {0, 0, 0} }
+    };
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_scsi_controller(args, "lsi53c895a", "pci.0", 3);
+    add_scsi_controller(args, "virtio-scsi-pci", "pci.0", 4);
+    add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
+    add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30);
+    add_scsi_disk(args, 2, 1, 0, 0, 1, 1, 0, 0);
+    add_scsi_disk(args, 3, 1, 0, 1, 2, 0, 1, 0);
+    test_override(args, expected);
+}
+
+static void test_override_virtio_blk(void)
+{
+    TestArgs *args = create_args();
+    CHSResult expected[] = {
+        {"/pci@i0cf8/scsi@3/disk@0,0", {10000, 120, 30} },
+        {"/pci@i0cf8/scsi@4/disk@0,0", {9000, 120, 30} },
+        {NULL, {0, 0, 0} }
+    };
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_virtio_disk(args, 0, "pci.0", 3, 10000, 120, 30);
+    add_virtio_disk(args, 1, "pci.0", 4, 9000, 120, 30);
+    test_override(args, expected);
+}
+
+static void test_override_zero_chs(void)
+{
+    TestArgs *args = create_args();
+    CHSResult expected[] = {
+        {NULL, {0, 0, 0} }
+    };
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_ide_disk(args, 0, 1, 1, 0, 0, 0);
+    test_override(args, expected);
+}
+
+static void test_override_scsi_hot_unplug(void)
+{
+    QTestState *qts;
+    char *joined_args;
+    QFWCFG *fw_cfg;
+    QDict *response;
+    int i;
+    TestArgs *args = create_args();
+    CHSResult expected[] = {
+        {"/pci@i0cf8/scsi@2/channel@0/disk@0,0", {10000, 120, 30} },
+        {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} },
+        {NULL, {0, 0, 0} }
+    };
+    CHSResult expected2[] = {
+        {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} },
+        {NULL, {0, 0, 0} }
+    };
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_scsi_controller(args, "virtio-scsi-pci", "pci.0", 2);
+    add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
+    add_scsi_disk(args, 1, 0, 0, 1, 0, 20, 20, 20);
+
+    joined_args = g_strjoinv(" ", args->argv);
+
+    qts = qtest_init(joined_args);
+    fw_cfg = pc_fw_cfg_init(qts);
+
+    read_bootdevices(fw_cfg, expected);
+
+    /* unplug device an restart */
+    response = qtest_qmp(qts,
+                         "{ 'execute': 'device_del',"
+                         "  'arguments': {'id': 'scsi-disk0' }}");
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+    response = qtest_qmp(qts,
+                         "{ 'execute': 'system_reset', 'arguments': { }}");
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+
+    qtest_qmp_eventwait(qts, "RESET");
+
+    read_bootdevices(fw_cfg, expected2);
+
+    g_free(joined_args);
+    qtest_quit(qts);
+
+    g_free(fw_cfg);
+
+    for (i = 0; i < args->n_drives; i++) {
+        unlink(args->drives[i]);
+        free(args->drives[i]);
+    }
+    g_free(args->drives);
+    g_strfreev(args->argv);
+    g_free(args);
+}
+
+static void test_override_virtio_hot_unplug(void)
+{
+    QTestState *qts;
+    char *joined_args;
+    QFWCFG *fw_cfg;
+    QDict *response;
+    int i;
+    TestArgs *args = create_args();
+    CHSResult expected[] = {
+        {"/pci@i0cf8/scsi@2/disk@0,0", {10000, 120, 30} },
+        {"/pci@i0cf8/scsi@3/disk@0,0", {20, 20, 20} },
+        {NULL, {0, 0, 0} }
+    };
+    CHSResult expected2[] = {
+        {"/pci@i0cf8/scsi@3/disk@0,0", {20, 20, 20} },
+        {NULL, {0, 0, 0} }
+    };
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_drive_with_mbr(args, empty_mbr, 1);
+    add_virtio_disk(args, 0, "pci.0", 2, 10000, 120, 30);
+    add_virtio_disk(args, 1, "pci.0", 3, 20, 20, 20);
+
+    joined_args = g_strjoinv(" ", args->argv);
+
+    qts = qtest_init(joined_args);
+    fw_cfg = pc_fw_cfg_init(qts);
+
+    read_bootdevices(fw_cfg, expected);
+
+    /* unplug device an restart */
+    response = qtest_qmp(qts,
+                         "{ 'execute': 'device_del',"
+                         "  'arguments': {'id': 'virtio-disk0' }}");
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+    response = qtest_qmp(qts,
+                         "{ 'execute': 'system_reset', 'arguments': { }}");
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+
+    qtest_qmp_eventwait(qts, "RESET");
+
+    read_bootdevices(fw_cfg, expected2);
+
+    g_free(joined_args);
+    qtest_quit(qts);
+
+    g_free(fw_cfg);
+
+    for (i = 0; i < args->n_drives; i++) {
+        unlink(args->drives[i]);
+        free(args->drives[i]);
+    }
+    g_free(args->drives);
+    g_strfreev(args->argv);
+    g_free(args);
+}
+
+int main(int argc, char **argv)
+{
+    Backend i;
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    for (i = 0; i < backend_last; i++) {
+        if (img_secs[i] >= 0) {
+            img_file_name[i] = create_test_img(img_secs[i]);
+            if (!img_file_name[i]) {
+                g_test_message("Could not create test images.");
+                goto test_add_done;
+            }
+        } else {
+            img_file_name[i] = NULL;
+        }
+    }
+
+    qtest_add_func("hd-geo/ide/none", test_ide_none);
+    qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank);
+    qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba);
+    qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs);
+    qtest_add_func("hd-geo/ide/drive/cd_0", test_ide_drive_cd_0);
+    qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank);
+    qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba);
+    qtest_add_func("hd-geo/ide/device/mbr/chs", test_ide_device_mbr_chs);
+    qtest_add_func("hd-geo/ide/device/user/chs", test_ide_device_user_chs);
+    qtest_add_func("hd-geo/ide/device/user/chst", test_ide_device_user_chst);
+    if (have_qemu_img()) {
+        qtest_add_func("hd-geo/override/ide", test_override_ide);
+        qtest_add_func("hd-geo/override/scsi", test_override_scsi);
+        qtest_add_func("hd-geo/override/scsi_2_controllers",
+                       test_override_scsi_2_controllers);
+        qtest_add_func("hd-geo/override/virtio_blk", test_override_virtio_blk);
+        qtest_add_func("hd-geo/override/zero_chs", test_override_zero_chs);
+        qtest_add_func("hd-geo/override/scsi_hot_unplug",
+                       test_override_scsi_hot_unplug);
+        qtest_add_func("hd-geo/override/virtio_hot_unplug",
+                       test_override_virtio_hot_unplug);
+    } else {
+        g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
+                       "skipping hd-geo/override/* tests");
+    }
+
+test_add_done:
+    ret = g_test_run();
+
+    for (i = 0; i < backend_last; i++) {
+        if (img_file_name[i]) {
+            unlink(img_file_name[i]);
+            free(img_file_name[i]);
+        }
+    }
+
+    return ret;
+}
diff --git a/tests/qtest/hexloader-test.c b/tests/qtest/hexloader-test.c
new file mode 100644 (file)
index 0000000..8b7aa2d
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * QTest testcase for the Intel Hexadecimal Object File Loader
+ *
+ * Authors:
+ *  Su Hang <[email protected]> 2018
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+/* Load 'test.hex' and verify that the in-memory contents are as expected.
+ * 'test.hex' is a memory test pattern stored in Hexadecimal Object
+ * format.  It loads at 0x10000 in RAM and contains values from 0 through
+ * 255.
+ */
+static void hex_loader_test(void)
+{
+    unsigned int i;
+    const unsigned int base_addr = 0x00010000;
+
+    QTestState *s = qtest_initf(
+        "-M vexpress-a9 -device loader,file=tests/data/hex-loader/test.hex");
+
+    for (i = 0; i < 256; ++i) {
+        uint8_t val = qtest_readb(s, base_addr + i);
+        g_assert_cmpuint(i, ==, val);
+    }
+    qtest_quit(s);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/tmp/hex_loader", hex_loader_test);
+    ret = g_test_run();
+
+    return ret;
+}
diff --git a/tests/qtest/i440fx-test.c b/tests/qtest/i440fx-test.c
new file mode 100644 (file)
index 0000000..1f57d96
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * qtest I440FX test case
+ *
+ * Copyright IBM, Corp. 2012-2013
+ * Copyright Red Hat, Inc. 2013
+ *
+ * Authors:
+ *  Anthony Liguori   <[email protected]>
+ *  Laszlo Ersek      <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqtest-single.h"
+#include "libqos/pci.h"
+#include "libqos/pci-pc.h"
+#include "hw/pci/pci_regs.h"
+
+#define BROKEN 1
+
+typedef struct TestData
+{
+    int num_cpus;
+} TestData;
+
+typedef struct FirmwareTestFixture {
+    /* decides whether we're testing -bios or -pflash */
+    bool is_bios;
+} FirmwareTestFixture;
+
+static QPCIBus *test_start_get_bus(const TestData *s)
+{
+    char *cmdline;
+
+    cmdline = g_strdup_printf("-smp %d", s->num_cpus);
+    qtest_start(cmdline);
+    g_free(cmdline);
+    return qpci_new_pc(global_qtest, NULL);
+}
+
+static void test_i440fx_defaults(gconstpointer opaque)
+{
+    const TestData *s = opaque;
+    QPCIBus *bus;
+    QPCIDevice *dev;
+    uint32_t value;
+
+    bus = test_start_get_bus(s);
+    dev = qpci_device_find(bus, QPCI_DEVFN(0, 0));
+    g_assert(dev != NULL);
+
+    /* 3.2.2 */
+    g_assert_cmpint(qpci_config_readw(dev, PCI_VENDOR_ID), ==, 0x8086);
+    /* 3.2.3 */
+    g_assert_cmpint(qpci_config_readw(dev, PCI_DEVICE_ID), ==, 0x1237);
+#ifndef BROKEN
+    /* 3.2.4 */
+    g_assert_cmpint(qpci_config_readw(dev, PCI_COMMAND), ==, 0x0006);
+    /* 3.2.5 */
+    g_assert_cmpint(qpci_config_readw(dev, PCI_STATUS), ==, 0x0280);
+#endif
+    /* 3.2.7 */
+    g_assert_cmpint(qpci_config_readb(dev, PCI_CLASS_PROG), ==, 0x00);
+    g_assert_cmpint(qpci_config_readw(dev, PCI_CLASS_DEVICE), ==, 0x0600);
+    /* 3.2.8 */
+    g_assert_cmpint(qpci_config_readb(dev, PCI_LATENCY_TIMER), ==, 0x00);
+    /* 3.2.9 */
+    g_assert_cmpint(qpci_config_readb(dev, PCI_HEADER_TYPE), ==, 0x00);
+    /* 3.2.10 */
+    g_assert_cmpint(qpci_config_readb(dev, PCI_BIST), ==, 0x00);
+
+    /* 3.2.11 */
+    value = qpci_config_readw(dev, 0x50); /* PMCCFG */
+    if (s->num_cpus == 1) { /* WPE */
+        g_assert(!(value & (1 << 15)));
+    } else {
+        g_assert((value & (1 << 15)));
+    }
+
+    g_assert(!(value & (1 << 6))); /* EPTE */
+
+    /* 3.2.12 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x52), ==, 0x00); /* DETURBO */
+    /* 3.2.13 */
+#ifndef BROKEN
+    g_assert_cmpint(qpci_config_readb(dev, 0x53), ==, 0x80); /* DBC */
+#endif
+    /* 3.2.14 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x54), ==, 0x00); /* AXC */
+    /* 3.2.15 */
+    g_assert_cmpint(qpci_config_readw(dev, 0x55), ==, 0x0000); /* DRT */
+#ifndef BROKEN
+    /* 3.2.16 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x57), ==, 0x01); /* DRAMC */
+    /* 3.2.17 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x58), ==, 0x10); /* DRAMT */
+#endif
+    /* 3.2.18 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x59), ==, 0x00); /* PAM0 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x5A), ==, 0x00); /* PAM1 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x5B), ==, 0x00); /* PAM2 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x5C), ==, 0x00); /* PAM3 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x5D), ==, 0x00); /* PAM4 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x5E), ==, 0x00); /* PAM5 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x5F), ==, 0x00); /* PAM6 */
+#ifndef BROKEN
+    /* 3.2.19 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x60), ==, 0x01); /* DRB0 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x61), ==, 0x01); /* DRB1 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x62), ==, 0x01); /* DRB2 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x63), ==, 0x01); /* DRB3 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x64), ==, 0x01); /* DRB4 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x65), ==, 0x01); /* DRB5 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x66), ==, 0x01); /* DRB6 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x67), ==, 0x01); /* DRB7 */
+#endif
+    /* 3.2.20 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x68), ==, 0x00); /* FDHC */
+    /* 3.2.21 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x70), ==, 0x00); /* MTT */
+#ifndef BROKEN
+    /* 3.2.22 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x71), ==, 0x10); /* CLT */
+#endif
+    /* 3.2.23 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x72), ==, 0x02); /* SMRAM */
+    /* 3.2.24 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x90), ==, 0x00); /* ERRCMD */
+    /* 3.2.25 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x91), ==, 0x00); /* ERRSTS */
+    /* 3.2.26 */
+    g_assert_cmpint(qpci_config_readb(dev, 0x93), ==, 0x00); /* TRC */
+
+    g_free(dev);
+    qpci_free_pc(bus);
+    qtest_end();
+}
+
+#define PAM_RE 1
+#define PAM_WE 2
+
+static void pam_set(QPCIDevice *dev, int index, int flags)
+{
+    int regno = 0x59 + (index / 2);
+    uint8_t reg;
+
+    reg = qpci_config_readb(dev, regno);
+    if (index & 1) {
+        reg = (reg & 0x0F) | (flags << 4);
+    } else {
+        reg = (reg & 0xF0) | flags;
+    }
+    qpci_config_writeb(dev, regno, reg);
+}
+
+static gboolean verify_area(uint32_t start, uint32_t end, uint8_t value)
+{
+    uint32_t size = end - start + 1;
+    gboolean ret = TRUE;
+    uint8_t *data;
+    int i;
+
+    data = g_malloc0(size);
+    memread(start, data, size);
+
+    g_test_message("verify_area: data[0] = 0x%x", data[0]);
+
+    for (i = 0; i < size; i++) {
+        if (data[i] != value) {
+            ret = FALSE;
+            break;
+        }
+    }
+
+    g_free(data);
+
+    return ret;
+}
+
+static void write_area(uint32_t start, uint32_t end, uint8_t value)
+{
+    uint32_t size = end - start + 1;
+    uint8_t *data;
+
+    data = g_malloc(size);
+    memset(data, value, size);
+    memwrite(start, data, size);
+
+    g_free(data);
+}
+
+static void test_i440fx_pam(gconstpointer opaque)
+{
+    const TestData *s = opaque;
+    QPCIBus *bus;
+    QPCIDevice *dev;
+    int i;
+    static struct {
+        uint32_t start;
+        uint32_t end;
+    } pam_area[] = {
+        { 0, 0 },             /* Reserved */
+        { 0xF0000, 0xFFFFF }, /* BIOS Area */
+        { 0xC0000, 0xC3FFF }, /* Option ROM */
+        { 0xC4000, 0xC7FFF }, /* Option ROM */
+        { 0xC8000, 0xCBFFF }, /* Option ROM */
+        { 0xCC000, 0xCFFFF }, /* Option ROM */
+        { 0xD0000, 0xD3FFF }, /* Option ROM */
+        { 0xD4000, 0xD7FFF }, /* Option ROM */
+        { 0xD8000, 0xDBFFF }, /* Option ROM */
+        { 0xDC000, 0xDFFFF }, /* Option ROM */
+        { 0xE0000, 0xE3FFF }, /* BIOS Extension */
+        { 0xE4000, 0xE7FFF }, /* BIOS Extension */
+        { 0xE8000, 0xEBFFF }, /* BIOS Extension */
+        { 0xEC000, 0xEFFFF }, /* BIOS Extension */
+    };
+
+    bus = test_start_get_bus(s);
+    dev = qpci_device_find(bus, QPCI_DEVFN(0, 0));
+    g_assert(dev != NULL);
+
+    for (i = 0; i < ARRAY_SIZE(pam_area); i++) {
+        if (pam_area[i].start == pam_area[i].end) {
+            continue;
+        }
+
+        g_test_message("Checking area 0x%05x..0x%05x",
+                       pam_area[i].start, pam_area[i].end);
+        /* Switch to RE for the area */
+        pam_set(dev, i, PAM_RE);
+        /* Verify the RAM is all zeros */
+        g_assert(verify_area(pam_area[i].start, pam_area[i].end, 0));
+
+        /* Switch to WE for the area */
+        pam_set(dev, i, PAM_RE | PAM_WE);
+        /* Write out a non-zero mask to the full area */
+        write_area(pam_area[i].start, pam_area[i].end, 0x42);
+
+#ifndef BROKEN
+        /* QEMU only supports a limited form of PAM */
+
+        /* Switch to !RE for the area */
+        pam_set(dev, i, PAM_WE);
+        /* Verify the area is not our mask */
+        g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x42));
+#endif
+
+        /* Verify the area is our new mask */
+        g_assert(verify_area(pam_area[i].start, pam_area[i].end, 0x42));
+
+        /* Write out a new mask */
+        write_area(pam_area[i].start, pam_area[i].end, 0x82);
+
+#ifndef BROKEN
+        /* QEMU only supports a limited form of PAM */
+
+        /* Verify the area is not our mask */
+        g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x82));
+
+        /* Switch to RE for the area */
+        pam_set(dev, i, PAM_RE | PAM_WE);
+#endif
+        /* Verify the area is our new mask */
+        g_assert(verify_area(pam_area[i].start, pam_area[i].end, 0x82));
+
+        /* Reset area */
+        pam_set(dev, i, 0);
+
+        /* Verify the area is not our new mask */
+        g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x82));
+    }
+
+    g_free(dev);
+    qpci_free_pc(bus);
+    qtest_end();
+}
+
+#define BLOB_SIZE ((size_t)65536)
+#define ISA_BIOS_MAXSZ ((size_t)(128 * 1024))
+
+/* Create a blob file, and return its absolute pathname as a dynamically
+ * allocated string.
+ * The file is closed before the function returns.
+ * In case of error, NULL is returned. The function prints the error message.
+ */
+static char *create_blob_file(void)
+{
+    int ret, fd;
+    char *pathname;
+    GError *error = NULL;
+
+    ret = -1;
+    fd = g_file_open_tmp("blob_XXXXXX", &pathname, &error);
+    if (fd == -1) {
+        fprintf(stderr, "unable to create blob file: %s\n", error->message);
+        g_error_free(error);
+    } else {
+        if (ftruncate(fd, BLOB_SIZE) == -1) {
+            fprintf(stderr, "ftruncate(\"%s\", %zu): %s\n", pathname,
+                    BLOB_SIZE, strerror(errno));
+        } else {
+            void *buf;
+
+            buf = mmap(NULL, BLOB_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
+            if (buf == MAP_FAILED) {
+                fprintf(stderr, "mmap(\"%s\", %zu): %s\n", pathname, BLOB_SIZE,
+                        strerror(errno));
+            } else {
+                size_t i;
+
+                for (i = 0; i < BLOB_SIZE; ++i) {
+                    ((uint8_t *)buf)[i] = i;
+                }
+                munmap(buf, BLOB_SIZE);
+                ret = 0;
+            }
+        }
+        close(fd);
+        if (ret == -1) {
+            unlink(pathname);
+            g_free(pathname);
+        }
+    }
+
+    return ret == -1 ? NULL : pathname;
+}
+
+static void test_i440fx_firmware(FirmwareTestFixture *fixture,
+                                 gconstpointer user_data)
+{
+    char *fw_pathname, *cmdline;
+    uint8_t *buf;
+    size_t i, isa_bios_size;
+
+    fw_pathname = create_blob_file();
+    g_assert(fw_pathname != NULL);
+
+    /* Better hope the user didn't put metacharacters in TMPDIR and co. */
+    cmdline = g_strdup_printf("-S %s%s", fixture->is_bios
+                                         ? "-bios "
+                                         : "-drive if=pflash,format=raw,file=",
+                              fw_pathname);
+    g_test_message("qemu cmdline: %s", cmdline);
+    qtest_start(cmdline);
+    g_free(cmdline);
+
+    /* QEMU has loaded the firmware (because qtest_start() only returns after
+     * the QMP handshake completes). We must unlink the firmware blob right
+     * here, because any assertion firing below would leak it in the
+     * filesystem. This is also the reason why we recreate the blob every time
+     * this function is invoked.
+     */
+    unlink(fw_pathname);
+    g_free(fw_pathname);
+
+    /* check below 4G */
+    buf = g_malloc0(BLOB_SIZE);
+    memread(0x100000000ULL - BLOB_SIZE, buf, BLOB_SIZE);
+    for (i = 0; i < BLOB_SIZE; ++i) {
+        g_assert_cmphex(buf[i], ==, (uint8_t)i);
+    }
+
+    /* check in ISA space too */
+    memset(buf, 0, BLOB_SIZE);
+    isa_bios_size = ISA_BIOS_MAXSZ < BLOB_SIZE ? ISA_BIOS_MAXSZ : BLOB_SIZE;
+    memread(0x100000 - isa_bios_size, buf, isa_bios_size);
+    for (i = 0; i < isa_bios_size; ++i) {
+        g_assert_cmphex(buf[i], ==,
+                        (uint8_t)((BLOB_SIZE - isa_bios_size) + i));
+    }
+
+    g_free(buf);
+    qtest_end();
+}
+
+static void add_firmware_test(const char *testpath,
+                              void (*setup_fixture)(FirmwareTestFixture *f,
+                                                    gconstpointer test_data))
+{
+    qtest_add(testpath, FirmwareTestFixture, NULL, setup_fixture,
+              test_i440fx_firmware, NULL);
+}
+
+static void request_bios(FirmwareTestFixture *fixture,
+                         gconstpointer user_data)
+{
+    fixture->is_bios = true;
+}
+
+static void request_pflash(FirmwareTestFixture *fixture,
+                           gconstpointer user_data)
+{
+    fixture->is_bios = false;
+}
+
+int main(int argc, char **argv)
+{
+    TestData data;
+
+    g_test_init(&argc, &argv, NULL);
+
+    data.num_cpus = 1;
+
+    qtest_add_data_func("i440fx/defaults", &data, test_i440fx_defaults);
+    qtest_add_data_func("i440fx/pam", &data, test_i440fx_pam);
+    add_firmware_test("i440fx/firmware/bios", request_bios);
+    add_firmware_test("i440fx/firmware/pflash", request_pflash);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/i82801b11-test.c b/tests/qtest/i82801b11-test.c
new file mode 100644 (file)
index 0000000..4345da3
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * QTest testcase for i82801b11
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void nop(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/i82801b11/nop", nop);
+
+    qtest_start("-machine q35 -device i82801b11-bridge,bus=pcie.0,addr=1e.0");
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c
new file mode 100644 (file)
index 0000000..0277e7d
--- /dev/null
@@ -0,0 +1,1092 @@
+/*
+ * IDE test cases
+ *
+ * Copyright (c) 2013 Kevin Wolf <[email protected]>
+ *
+ * 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 "libqtest.h"
+#include "libqos/libqos.h"
+#include "libqos/pci-pc.h"
+#include "libqos/malloc-pc.h"
+#include "qapi/qmp/qdict.h"
+#include "qemu-common.h"
+#include "qemu/bswap.h"
+#include "hw/pci/pci_ids.h"
+#include "hw/pci/pci_regs.h"
+
+/* TODO actually test the results and get rid of this */
+#define qmp_discard_response(q, ...) qobject_unref(qtest_qmp(q, __VA_ARGS__))
+
+#define TEST_IMAGE_SIZE 64 * 1024 * 1024
+
+#define IDE_PCI_DEV     1
+#define IDE_PCI_FUNC    1
+
+#define IDE_BASE 0x1f0
+#define IDE_PRIMARY_IRQ 14
+
+#define ATAPI_BLOCK_SIZE 2048
+
+/* How many bytes to receive via ATAPI PIO at one time.
+ * Must be less than 0xFFFF. */
+#define BYTE_COUNT_LIMIT 5120
+
+enum {
+    reg_data        = 0x0,
+    reg_feature     = 0x1,
+    reg_error       = 0x1,
+    reg_nsectors    = 0x2,
+    reg_lba_low     = 0x3,
+    reg_lba_middle  = 0x4,
+    reg_lba_high    = 0x5,
+    reg_device      = 0x6,
+    reg_status      = 0x7,
+    reg_command     = 0x7,
+};
+
+enum {
+    BSY     = 0x80,
+    DRDY    = 0x40,
+    DF      = 0x20,
+    DRQ     = 0x08,
+    ERR     = 0x01,
+};
+
+/* Error field */
+enum {
+    ABRT    = 0x04,
+};
+
+enum {
+    DEV     = 0x10,
+    LBA     = 0x40,
+};
+
+enum {
+    bmreg_cmd       = 0x0,
+    bmreg_status    = 0x2,
+    bmreg_prdt      = 0x4,
+};
+
+enum {
+    CMD_DSM         = 0x06,
+    CMD_READ_DMA    = 0xc8,
+    CMD_WRITE_DMA   = 0xca,
+    CMD_FLUSH_CACHE = 0xe7,
+    CMD_IDENTIFY    = 0xec,
+    CMD_PACKET      = 0xa0,
+
+    CMDF_ABORT      = 0x100,
+    CMDF_NO_BM      = 0x200,
+};
+
+enum {
+    BM_CMD_START    =  0x1,
+    BM_CMD_WRITE    =  0x8, /* write = from device to memory */
+};
+
+enum {
+    BM_STS_ACTIVE   =  0x1,
+    BM_STS_ERROR    =  0x2,
+    BM_STS_INTR     =  0x4,
+};
+
+enum {
+    PRDT_EOT        = 0x80000000,
+};
+
+#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
+#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
+
+static QPCIBus *pcibus = NULL;
+static QGuestAllocator guest_malloc;
+
+static char tmp_path[] = "/tmp/qtest.XXXXXX";
+static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX";
+
+static QTestState *ide_test_start(const char *cmdline_fmt, ...)
+{
+    QTestState *qts;
+    va_list ap;
+
+    va_start(ap, cmdline_fmt);
+    qts = qtest_vinitf(cmdline_fmt, ap);
+    va_end(ap);
+
+    pc_alloc_init(&guest_malloc, qts, 0);
+
+    return qts;
+}
+
+static void ide_test_quit(QTestState *qts)
+{
+    if (pcibus) {
+        qpci_free_pc(pcibus);
+        pcibus = NULL;
+    }
+    alloc_destroy(&guest_malloc);
+    qtest_quit(qts);
+}
+
+static QPCIDevice *get_pci_device(QTestState *qts, QPCIBar *bmdma_bar,
+                                  QPCIBar *ide_bar)
+{
+    QPCIDevice *dev;
+    uint16_t vendor_id, device_id;
+
+    if (!pcibus) {
+        pcibus = qpci_new_pc(qts, NULL);
+    }
+
+    /* Find PCI device and verify it's the right one */
+    dev = qpci_device_find(pcibus, QPCI_DEVFN(IDE_PCI_DEV, IDE_PCI_FUNC));
+    g_assert(dev != NULL);
+
+    vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);
+    device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
+    g_assert(vendor_id == PCI_VENDOR_ID_INTEL);
+    g_assert(device_id == PCI_DEVICE_ID_INTEL_82371SB_1);
+
+    /* Map bmdma BAR */
+    *bmdma_bar = qpci_iomap(dev, 4, NULL);
+
+    *ide_bar = qpci_legacy_iomap(dev, IDE_BASE);
+
+    qpci_device_enable(dev);
+
+    return dev;
+}
+
+static void free_pci_device(QPCIDevice *dev)
+{
+    /* libqos doesn't have a function for this, so free it manually */
+    g_free(dev);
+}
+
+typedef struct PrdtEntry {
+    uint32_t addr;
+    uint32_t size;
+} QEMU_PACKED PrdtEntry;
+
+#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
+#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
+
+static uint64_t trim_range_le(uint64_t sector, uint16_t count)
+{
+    /* 2-byte range, 6-byte LBA */
+    return cpu_to_le64(((uint64_t)count << 48) + sector);
+}
+
+static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
+                            int nb_sectors, PrdtEntry *prdt, int prdt_entries,
+                            void(*post_exec)(QPCIDevice *dev, QPCIBar ide_bar,
+                                             uint64_t sector, int nb_sectors))
+{
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uintptr_t guest_prdt;
+    size_t len;
+    bool from_dev;
+    uint8_t status;
+    int flags;
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    flags = cmd & ~0xff;
+    cmd &= 0xff;
+
+    switch (cmd) {
+    case CMD_READ_DMA:
+    case CMD_PACKET:
+        /* Assuming we only test data reads w/ ATAPI, otherwise we need to know
+         * the SCSI command being sent in the packet, too. */
+        from_dev = true;
+        break;
+    case CMD_DSM:
+    case CMD_WRITE_DMA:
+        from_dev = false;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    if (flags & CMDF_NO_BM) {
+        qpci_config_writew(dev, PCI_COMMAND,
+                           PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+    }
+
+    /* Select device 0 */
+    qpci_io_writeb(dev, ide_bar, reg_device, 0 | LBA);
+
+    /* Stop any running transfer, clear any pending interrupt */
+    qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
+    qpci_io_writeb(dev, bmdma_bar, bmreg_status, BM_STS_INTR);
+
+    /* Setup PRDT */
+    len = sizeof(*prdt) * prdt_entries;
+    guest_prdt = guest_alloc(&guest_malloc, len);
+    qtest_memwrite(qts, guest_prdt, prdt, len);
+    qpci_io_writel(dev, bmdma_bar, bmreg_prdt, guest_prdt);
+
+    /* ATA DMA command */
+    if (cmd == CMD_PACKET) {
+        /* Enables ATAPI DMA; otherwise PIO is attempted */
+        qpci_io_writeb(dev, ide_bar, reg_feature, 0x01);
+    } else {
+        if (cmd == CMD_DSM) {
+            /* trim bit */
+            qpci_io_writeb(dev, ide_bar, reg_feature, 0x01);
+        }
+        qpci_io_writeb(dev, ide_bar, reg_nsectors, nb_sectors);
+        qpci_io_writeb(dev, ide_bar, reg_lba_low,    sector & 0xff);
+        qpci_io_writeb(dev, ide_bar, reg_lba_middle, (sector >> 8) & 0xff);
+        qpci_io_writeb(dev, ide_bar, reg_lba_high,   (sector >> 16) & 0xff);
+    }
+
+    qpci_io_writeb(dev, ide_bar, reg_command, cmd);
+
+    if (post_exec) {
+        post_exec(dev, ide_bar, sector, nb_sectors);
+    }
+
+    /* Start DMA transfer */
+    qpci_io_writeb(dev, bmdma_bar, bmreg_cmd,
+                   BM_CMD_START | (from_dev ? BM_CMD_WRITE : 0));
+
+    if (flags & CMDF_ABORT) {
+        qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
+    }
+
+    /* Wait for the DMA transfer to complete */
+    do {
+        status = qpci_io_readb(dev, bmdma_bar, bmreg_status);
+    } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
+
+    g_assert_cmpint(qtest_get_irq(qts, IDE_PRIMARY_IRQ), ==,
+                    !!(status & BM_STS_INTR));
+
+    /* Check IDE status code */
+    assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), DRDY);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), BSY | DRQ);
+
+    /* Reading the status register clears the IRQ */
+    g_assert(!qtest_get_irq(qts, IDE_PRIMARY_IRQ));
+
+    /* Stop DMA transfer if still active */
+    if (status & BM_STS_ACTIVE) {
+        qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
+    }
+
+    free_pci_device(dev);
+
+    return status;
+}
+
+static QTestState *test_bmdma_setup(void)
+{
+    QTestState *qts;
+
+    qts = ide_test_start(
+        "-drive file=%s,if=ide,cache=writeback,format=raw "
+        "-global ide-hd.serial=%s -global ide-hd.ver=%s",
+        tmp_path, "testdisk", "version");
+    qtest_irq_intercept_in(qts, "ioapic");
+
+    return qts;
+}
+
+static void test_bmdma_teardown(QTestState *qts)
+{
+    ide_test_quit(qts);
+}
+
+static void test_bmdma_simple_rw(void)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uint8_t status;
+    uint8_t *buf;
+    uint8_t *cmpbuf;
+    size_t len = 512;
+    uintptr_t guest_buf;
+    PrdtEntry prdt[1];
+
+    qts = test_bmdma_setup();
+
+    guest_buf  = guest_alloc(&guest_malloc, len);
+    prdt[0].addr = cpu_to_le32(guest_buf);
+    prdt[0].size = cpu_to_le32(len | PRDT_EOT);
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    buf = g_malloc(len);
+    cmpbuf = g_malloc(len);
+
+    /* Write 0x55 pattern to sector 0 */
+    memset(buf, 0x55, len);
+    qtest_memwrite(qts, guest_buf, buf, len);
+
+    status = send_dma_request(qts, CMD_WRITE_DMA, 0, 1, prdt,
+                              ARRAY_SIZE(prdt), NULL);
+    g_assert_cmphex(status, ==, BM_STS_INTR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+
+    /* Write 0xaa pattern to sector 1 */
+    memset(buf, 0xaa, len);
+    qtest_memwrite(qts, guest_buf, buf, len);
+
+    status = send_dma_request(qts, CMD_WRITE_DMA, 1, 1, prdt,
+                              ARRAY_SIZE(prdt), NULL);
+    g_assert_cmphex(status, ==, BM_STS_INTR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+
+    /* Read and verify 0x55 pattern in sector 0 */
+    memset(cmpbuf, 0x55, len);
+
+    status = send_dma_request(qts, CMD_READ_DMA, 0, 1, prdt, ARRAY_SIZE(prdt),
+                              NULL);
+    g_assert_cmphex(status, ==, BM_STS_INTR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+
+    qtest_memread(qts, guest_buf, buf, len);
+    g_assert(memcmp(buf, cmpbuf, len) == 0);
+
+    /* Read and verify 0xaa pattern in sector 1 */
+    memset(cmpbuf, 0xaa, len);
+
+    status = send_dma_request(qts, CMD_READ_DMA, 1, 1, prdt, ARRAY_SIZE(prdt),
+                              NULL);
+    g_assert_cmphex(status, ==, BM_STS_INTR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+
+    qtest_memread(qts, guest_buf, buf, len);
+    g_assert(memcmp(buf, cmpbuf, len) == 0);
+
+    free_pci_device(dev);
+    g_free(buf);
+    g_free(cmpbuf);
+
+    test_bmdma_teardown(qts);
+}
+
+static void test_bmdma_trim(void)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uint8_t status;
+    const uint64_t trim_range[] = { trim_range_le(0, 2),
+                                    trim_range_le(6, 8),
+                                    trim_range_le(10, 1),
+                                  };
+    const uint64_t bad_range = trim_range_le(TEST_IMAGE_SIZE / 512 - 1, 2);
+    size_t len = 512;
+    uint8_t *buf;
+    uintptr_t guest_buf;
+    PrdtEntry prdt[1];
+
+    qts = test_bmdma_setup();
+
+    guest_buf = guest_alloc(&guest_malloc, len);
+    prdt[0].addr = cpu_to_le32(guest_buf),
+    prdt[0].size = cpu_to_le32(len | PRDT_EOT),
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    buf = g_malloc(len);
+
+    /* Normal request */
+    *((uint64_t *)buf) = trim_range[0];
+    *((uint64_t *)buf + 1) = trim_range[1];
+
+    qtest_memwrite(qts, guest_buf, buf, 2 * sizeof(uint64_t));
+
+    status = send_dma_request(qts, CMD_DSM, 0, 1, prdt,
+                              ARRAY_SIZE(prdt), NULL);
+    g_assert_cmphex(status, ==, BM_STS_INTR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+
+    /* Request contains invalid range */
+    *((uint64_t *)buf) = trim_range[2];
+    *((uint64_t *)buf + 1) = bad_range;
+
+    qtest_memwrite(qts, guest_buf, buf, 2 * sizeof(uint64_t));
+
+    status = send_dma_request(qts, CMD_DSM, 0, 1, prdt,
+                              ARRAY_SIZE(prdt), NULL);
+    g_assert_cmphex(status, ==, BM_STS_INTR);
+    assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), ERR);
+    assert_bit_set(qpci_io_readb(dev, ide_bar, reg_error), ABRT);
+
+    free_pci_device(dev);
+    g_free(buf);
+    test_bmdma_teardown(qts);
+}
+
+static void test_bmdma_short_prdt(void)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uint8_t status;
+
+    PrdtEntry prdt[] = {
+        {
+            .addr = 0,
+            .size = cpu_to_le32(0x10 | PRDT_EOT),
+        },
+    };
+
+    qts = test_bmdma_setup();
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    /* Normal request */
+    status = send_dma_request(qts, CMD_READ_DMA, 0, 1,
+                              prdt, ARRAY_SIZE(prdt), NULL);
+    g_assert_cmphex(status, ==, 0);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+
+    /* Abort the request before it completes */
+    status = send_dma_request(qts, CMD_READ_DMA | CMDF_ABORT, 0, 1,
+                              prdt, ARRAY_SIZE(prdt), NULL);
+    g_assert_cmphex(status, ==, 0);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+    free_pci_device(dev);
+    test_bmdma_teardown(qts);
+}
+
+static void test_bmdma_one_sector_short_prdt(void)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uint8_t status;
+
+    /* Read 2 sectors but only give 1 sector in PRDT */
+    PrdtEntry prdt[] = {
+        {
+            .addr = 0,
+            .size = cpu_to_le32(0x200 | PRDT_EOT),
+        },
+    };
+
+    qts = test_bmdma_setup();
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    /* Normal request */
+    status = send_dma_request(qts, CMD_READ_DMA, 0, 2,
+                              prdt, ARRAY_SIZE(prdt), NULL);
+    g_assert_cmphex(status, ==, 0);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+
+    /* Abort the request before it completes */
+    status = send_dma_request(qts, CMD_READ_DMA | CMDF_ABORT, 0, 2,
+                              prdt, ARRAY_SIZE(prdt), NULL);
+    g_assert_cmphex(status, ==, 0);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+    free_pci_device(dev);
+    test_bmdma_teardown(qts);
+}
+
+static void test_bmdma_long_prdt(void)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uint8_t status;
+
+    PrdtEntry prdt[] = {
+        {
+            .addr = 0,
+            .size = cpu_to_le32(0x1000 | PRDT_EOT),
+        },
+    };
+
+    qts = test_bmdma_setup();
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    /* Normal request */
+    status = send_dma_request(qts, CMD_READ_DMA, 0, 1,
+                              prdt, ARRAY_SIZE(prdt), NULL);
+    g_assert_cmphex(status, ==, BM_STS_ACTIVE | BM_STS_INTR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+
+    /* Abort the request before it completes */
+    status = send_dma_request(qts, CMD_READ_DMA | CMDF_ABORT, 0, 1,
+                              prdt, ARRAY_SIZE(prdt), NULL);
+    g_assert_cmphex(status, ==, BM_STS_INTR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+    free_pci_device(dev);
+    test_bmdma_teardown(qts);
+}
+
+static void test_bmdma_no_busmaster(void)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uint8_t status;
+
+    qts = test_bmdma_setup();
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    /* No PRDT_EOT, each entry addr 0/size 64k, and in theory qemu shouldn't be
+     * able to access it anyway because the Bus Master bit in the PCI command
+     * register isn't set. This is complete nonsense, but it used to be pretty
+     * good at confusing and occasionally crashing qemu. */
+    PrdtEntry prdt[4096] = { };
+
+    status = send_dma_request(qts, CMD_READ_DMA | CMDF_NO_BM, 0, 512,
+                              prdt, ARRAY_SIZE(prdt), NULL);
+
+    /* Not entirely clear what the expected result is, but this is what we get
+     * in practice. At least we want to be aware of any changes. */
+    g_assert_cmphex(status, ==, BM_STS_ACTIVE | BM_STS_INTR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+    free_pci_device(dev);
+    test_bmdma_teardown(qts);
+}
+
+static void string_cpu_to_be16(uint16_t *s, size_t bytes)
+{
+    g_assert((bytes & 1) == 0);
+    bytes /= 2;
+
+    while (bytes--) {
+        *s = cpu_to_be16(*s);
+        s++;
+    }
+}
+
+static void test_identify(void)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uint8_t data;
+    uint16_t buf[256];
+    int i;
+    int ret;
+
+    qts = ide_test_start(
+        "-drive file=%s,if=ide,cache=writeback,format=raw "
+        "-global ide-hd.serial=%s -global ide-hd.ver=%s",
+        tmp_path, "testdisk", "version");
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    /* IDENTIFY command on device 0*/
+    qpci_io_writeb(dev, ide_bar, reg_device, 0);
+    qpci_io_writeb(dev, ide_bar, reg_command, CMD_IDENTIFY);
+
+    /* Read in the IDENTIFY buffer and check registers */
+    data = qpci_io_readb(dev, ide_bar, reg_device);
+    g_assert_cmpint(data & DEV, ==, 0);
+
+    for (i = 0; i < 256; i++) {
+        data = qpci_io_readb(dev, ide_bar, reg_status);
+        assert_bit_set(data, DRDY | DRQ);
+        assert_bit_clear(data, BSY | DF | ERR);
+
+        buf[i] = qpci_io_readw(dev, ide_bar, reg_data);
+    }
+
+    data = qpci_io_readb(dev, ide_bar, reg_status);
+    assert_bit_set(data, DRDY);
+    assert_bit_clear(data, BSY | DF | ERR | DRQ);
+
+    /* Check serial number/version in the buffer */
+    string_cpu_to_be16(&buf[10], 20);
+    ret = memcmp(&buf[10], "testdisk            ", 20);
+    g_assert(ret == 0);
+
+    string_cpu_to_be16(&buf[23], 8);
+    ret = memcmp(&buf[23], "version ", 8);
+    g_assert(ret == 0);
+
+    /* Write cache enabled bit */
+    assert_bit_set(buf[85], 0x20);
+
+    ide_test_quit(qts);
+    free_pci_device(dev);
+}
+
+/*
+ * Write sector 1 with random data to make IDE storage dirty
+ * Needed for flush tests so that flushes actually go though the block layer
+ */
+static void make_dirty(QTestState *qts, uint8_t device)
+{
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uint8_t status;
+    size_t len = 512;
+    uintptr_t guest_buf;
+    void* buf;
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    guest_buf = guest_alloc(&guest_malloc, len);
+    buf = g_malloc(len);
+    memset(buf, rand() % 255 + 1, len);
+    g_assert(guest_buf);
+    g_assert(buf);
+
+    qtest_memwrite(qts, guest_buf, buf, len);
+
+    PrdtEntry prdt[] = {
+        {
+            .addr = cpu_to_le32(guest_buf),
+            .size = cpu_to_le32(len | PRDT_EOT),
+        },
+    };
+
+    status = send_dma_request(qts, CMD_WRITE_DMA, 1, 1, prdt,
+                              ARRAY_SIZE(prdt), NULL);
+    g_assert_cmphex(status, ==, BM_STS_INTR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+
+    g_free(buf);
+    free_pci_device(dev);
+}
+
+static void test_flush(void)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uint8_t data;
+
+    qts = ide_test_start(
+        "-drive file=blkdebug::%s,if=ide,cache=writeback,format=raw",
+        tmp_path);
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    qtest_irq_intercept_in(qts, "ioapic");
+
+    /* Dirty media so that CMD_FLUSH_CACHE will actually go to disk */
+    make_dirty(qts, 0);
+
+    /* Delay the completion of the flush request until we explicitly do it */
+    g_free(qtest_hmp(qts, "qemu-io ide0-hd0 \"break flush_to_os A\""));
+
+    /* FLUSH CACHE command on device 0*/
+    qpci_io_writeb(dev, ide_bar, reg_device, 0);
+    qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE);
+
+    /* Check status while request is in flight*/
+    data = qpci_io_readb(dev, ide_bar, reg_status);
+    assert_bit_set(data, BSY | DRDY);
+    assert_bit_clear(data, DF | ERR | DRQ);
+
+    /* Complete the command */
+    g_free(qtest_hmp(qts, "qemu-io ide0-hd0 \"resume A\""));
+
+    /* Check registers */
+    data = qpci_io_readb(dev, ide_bar, reg_device);
+    g_assert_cmpint(data & DEV, ==, 0);
+
+    do {
+        data = qpci_io_readb(dev, ide_bar, reg_status);
+    } while (data & BSY);
+
+    assert_bit_set(data, DRDY);
+    assert_bit_clear(data, BSY | DF | ERR | DRQ);
+
+    ide_test_quit(qts);
+    free_pci_device(dev);
+}
+
+static void test_retry_flush(const char *machine)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uint8_t data;
+
+    prepare_blkdebug_script(debug_path, "flush_to_disk");
+
+    qts = ide_test_start(
+        "-drive file=blkdebug:%s:%s,if=ide,cache=writeback,format=raw,"
+        "rerror=stop,werror=stop",
+        debug_path, tmp_path);
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    qtest_irq_intercept_in(qts, "ioapic");
+
+    /* Dirty media so that CMD_FLUSH_CACHE will actually go to disk */
+    make_dirty(qts, 0);
+
+    /* FLUSH CACHE command on device 0*/
+    qpci_io_writeb(dev, ide_bar, reg_device, 0);
+    qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE);
+
+    /* Check status while request is in flight*/
+    data = qpci_io_readb(dev, ide_bar, reg_status);
+    assert_bit_set(data, BSY | DRDY);
+    assert_bit_clear(data, DF | ERR | DRQ);
+
+    qtest_qmp_eventwait(qts, "STOP");
+
+    /* Complete the command */
+    qmp_discard_response(qts, "{'execute':'cont' }");
+
+    /* Check registers */
+    data = qpci_io_readb(dev, ide_bar, reg_device);
+    g_assert_cmpint(data & DEV, ==, 0);
+
+    do {
+        data = qpci_io_readb(dev, ide_bar, reg_status);
+    } while (data & BSY);
+
+    assert_bit_set(data, DRDY);
+    assert_bit_clear(data, BSY | DF | ERR | DRQ);
+
+    ide_test_quit(qts);
+    free_pci_device(dev);
+}
+
+static void test_flush_nodev(void)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+
+    qts = ide_test_start("");
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    /* FLUSH CACHE command on device 0*/
+    qpci_io_writeb(dev, ide_bar, reg_device, 0);
+    qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE);
+
+    /* Just testing that qemu doesn't crash... */
+
+    free_pci_device(dev);
+    ide_test_quit(qts);
+}
+
+static void test_flush_empty_drive(void)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+
+    qts = ide_test_start("-device ide-cd,bus=ide.0");
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    /* FLUSH CACHE command on device 0 */
+    qpci_io_writeb(dev, ide_bar, reg_device, 0);
+    qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE);
+
+    /* Just testing that qemu doesn't crash... */
+
+    free_pci_device(dev);
+    ide_test_quit(qts);
+}
+
+static void test_pci_retry_flush(void)
+{
+    test_retry_flush("pc");
+}
+
+static void test_isa_retry_flush(void)
+{
+    test_retry_flush("isapc");
+}
+
+typedef struct Read10CDB {
+    uint8_t opcode;
+    uint8_t flags;
+    uint32_t lba;
+    uint8_t reserved;
+    uint16_t nblocks;
+    uint8_t control;
+    uint16_t padding;
+} __attribute__((__packed__)) Read10CDB;
+
+static void send_scsi_cdb_read10(QPCIDevice *dev, QPCIBar ide_bar,
+                                 uint64_t lba, int nblocks)
+{
+    Read10CDB pkt = { .padding = 0 };
+    int i;
+
+    g_assert_cmpint(lba, <=, UINT32_MAX);
+    g_assert_cmpint(nblocks, <=, UINT16_MAX);
+    g_assert_cmpint(nblocks, >=, 0);
+
+    /* Construct SCSI CDB packet */
+    pkt.opcode = 0x28;
+    pkt.lba = cpu_to_be32(lba);
+    pkt.nblocks = cpu_to_be16(nblocks);
+
+    /* Send Packet */
+    for (i = 0; i < sizeof(Read10CDB)/2; i++) {
+        qpci_io_writew(dev, ide_bar, reg_data,
+                       le16_to_cpu(((uint16_t *)&pkt)[i]));
+    }
+}
+
+static void nsleep(QTestState *qts, int64_t nsecs)
+{
+    const struct timespec val = { .tv_nsec = nsecs };
+    nanosleep(&val, NULL);
+    qtest_clock_set(qts, nsecs);
+}
+
+static uint8_t ide_wait_clear(QTestState *qts, uint8_t flag)
+{
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uint8_t data;
+    time_t st;
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+
+    /* Wait with a 5 second timeout */
+    time(&st);
+    while (true) {
+        data = qpci_io_readb(dev, ide_bar, reg_status);
+        if (!(data & flag)) {
+            free_pci_device(dev);
+            return data;
+        }
+        if (difftime(time(NULL), st) > 5.0) {
+            break;
+        }
+        nsleep(qts, 400);
+    }
+    g_assert_not_reached();
+}
+
+static void ide_wait_intr(QTestState *qts, int irq)
+{
+    time_t st;
+    bool intr;
+
+    time(&st);
+    while (true) {
+        intr = qtest_get_irq(qts, irq);
+        if (intr) {
+            return;
+        }
+        if (difftime(time(NULL), st) > 5.0) {
+            break;
+        }
+        nsleep(qts, 400);
+    }
+
+    g_assert_not_reached();
+}
+
+static void cdrom_pio_impl(int nblocks)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    FILE *fh;
+    int patt_blocks = MAX(16, nblocks);
+    size_t patt_len = ATAPI_BLOCK_SIZE * patt_blocks;
+    char *pattern = g_malloc(patt_len);
+    size_t rxsize = ATAPI_BLOCK_SIZE * nblocks;
+    uint16_t *rx = g_malloc0(rxsize);
+    int i, j;
+    uint8_t data;
+    uint16_t limit;
+    size_t ret;
+
+    /* Prepopulate the CDROM with an interesting pattern */
+    generate_pattern(pattern, patt_len, ATAPI_BLOCK_SIZE);
+    fh = fopen(tmp_path, "w+");
+    ret = fwrite(pattern, ATAPI_BLOCK_SIZE, patt_blocks, fh);
+    g_assert_cmpint(ret, ==, patt_blocks);
+    fclose(fh);
+
+    qts = ide_test_start(
+            "-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 "
+            "-device ide-cd,drive=sr0,bus=ide.0", tmp_path);
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+    qtest_irq_intercept_in(qts, "ioapic");
+
+    /* PACKET command on device 0 */
+    qpci_io_writeb(dev, ide_bar, reg_device, 0);
+    qpci_io_writeb(dev, ide_bar, reg_lba_middle, BYTE_COUNT_LIMIT & 0xFF);
+    qpci_io_writeb(dev, ide_bar, reg_lba_high, (BYTE_COUNT_LIMIT >> 8 & 0xFF));
+    qpci_io_writeb(dev, ide_bar, reg_command, CMD_PACKET);
+    /* HP0: Check_Status_A State */
+    nsleep(qts, 400);
+    data = ide_wait_clear(qts, BSY);
+    /* HP1: Send_Packet State */
+    assert_bit_set(data, DRQ | DRDY);
+    assert_bit_clear(data, ERR | DF | BSY);
+
+    /* SCSI CDB (READ10) -- read n*2048 bytes from block 0 */
+    send_scsi_cdb_read10(dev, ide_bar, 0, nblocks);
+
+    /* Read data back: occurs in bursts of 'BYTE_COUNT_LIMIT' bytes.
+     * If BYTE_COUNT_LIMIT is odd, we transfer BYTE_COUNT_LIMIT - 1 bytes.
+     * We allow an odd limit only when the remaining transfer size is
+     * less than BYTE_COUNT_LIMIT. However, SCSI's read10 command can only
+     * request n blocks, so our request size is always even.
+     * For this reason, we assume there is never a hanging byte to fetch. */
+    g_assert(!(rxsize & 1));
+    limit = BYTE_COUNT_LIMIT & ~1;
+    for (i = 0; i < DIV_ROUND_UP(rxsize, limit); i++) {
+        size_t offset = i * (limit / 2);
+        size_t rem = (rxsize / 2) - offset;
+
+        /* HP3: INTRQ_Wait */
+        ide_wait_intr(qts, IDE_PRIMARY_IRQ);
+
+        /* HP2: Check_Status_B (and clear IRQ) */
+        data = ide_wait_clear(qts, BSY);
+        assert_bit_set(data, DRQ | DRDY);
+        assert_bit_clear(data, ERR | DF | BSY);
+
+        /* HP4: Transfer_Data */
+        for (j = 0; j < MIN((limit / 2), rem); j++) {
+            rx[offset + j] = cpu_to_le16(qpci_io_readw(dev, ide_bar,
+                                                       reg_data));
+        }
+    }
+
+    /* Check for final completion IRQ */
+    ide_wait_intr(qts, IDE_PRIMARY_IRQ);
+
+    /* Sanity check final state */
+    data = ide_wait_clear(qts, DRQ);
+    assert_bit_set(data, DRDY);
+    assert_bit_clear(data, DRQ | ERR | DF | BSY);
+
+    g_assert_cmpint(memcmp(pattern, rx, rxsize), ==, 0);
+    g_free(pattern);
+    g_free(rx);
+    test_bmdma_teardown(qts);
+    free_pci_device(dev);
+}
+
+static void test_cdrom_pio(void)
+{
+    cdrom_pio_impl(1);
+}
+
+static void test_cdrom_pio_large(void)
+{
+    /* Test a few loops of the PIO DRQ mechanism. */
+    cdrom_pio_impl(BYTE_COUNT_LIMIT * 4 / ATAPI_BLOCK_SIZE);
+}
+
+
+static void test_cdrom_dma(void)
+{
+    QTestState *qts;
+    static const size_t len = ATAPI_BLOCK_SIZE;
+    size_t ret;
+    char *pattern = g_malloc(ATAPI_BLOCK_SIZE * 16);
+    char *rx = g_malloc0(len);
+    uintptr_t guest_buf;
+    PrdtEntry prdt[1];
+    FILE *fh;
+
+    qts = ide_test_start(
+            "-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 "
+            "-device ide-cd,drive=sr0,bus=ide.0", tmp_path);
+    qtest_irq_intercept_in(qts, "ioapic");
+
+    guest_buf = guest_alloc(&guest_malloc, len);
+    prdt[0].addr = cpu_to_le32(guest_buf);
+    prdt[0].size = cpu_to_le32(len | PRDT_EOT);
+
+    generate_pattern(pattern, ATAPI_BLOCK_SIZE * 16, ATAPI_BLOCK_SIZE);
+    fh = fopen(tmp_path, "w+");
+    ret = fwrite(pattern, ATAPI_BLOCK_SIZE, 16, fh);
+    g_assert_cmpint(ret, ==, 16);
+    fclose(fh);
+
+    send_dma_request(qts, CMD_PACKET, 0, 1, prdt, 1, send_scsi_cdb_read10);
+
+    /* Read back data from guest memory into local qtest memory */
+    qtest_memread(qts, guest_buf, rx, len);
+    g_assert_cmpint(memcmp(pattern, rx, len), ==, 0);
+
+    g_free(pattern);
+    g_free(rx);
+    test_bmdma_teardown(qts);
+}
+
+int main(int argc, char **argv)
+{
+    int fd;
+    int ret;
+
+    /* Create temporary blkdebug instructions */
+    fd = mkstemp(debug_path);
+    g_assert(fd >= 0);
+    close(fd);
+
+    /* Create a temporary raw image */
+    fd = mkstemp(tmp_path);
+    g_assert(fd >= 0);
+    ret = ftruncate(fd, TEST_IMAGE_SIZE);
+    g_assert(ret == 0);
+    close(fd);
+
+    /* Run the tests */
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/ide/identify", test_identify);
+
+    qtest_add_func("/ide/bmdma/simple_rw", test_bmdma_simple_rw);
+    qtest_add_func("/ide/bmdma/trim", test_bmdma_trim);
+    qtest_add_func("/ide/bmdma/short_prdt", test_bmdma_short_prdt);
+    qtest_add_func("/ide/bmdma/one_sector_short_prdt",
+                   test_bmdma_one_sector_short_prdt);
+    qtest_add_func("/ide/bmdma/long_prdt", test_bmdma_long_prdt);
+    qtest_add_func("/ide/bmdma/no_busmaster", test_bmdma_no_busmaster);
+
+    qtest_add_func("/ide/flush", test_flush);
+    qtest_add_func("/ide/flush/nodev", test_flush_nodev);
+    qtest_add_func("/ide/flush/empty_drive", test_flush_empty_drive);
+    qtest_add_func("/ide/flush/retry_pci", test_pci_retry_flush);
+    qtest_add_func("/ide/flush/retry_isa", test_isa_retry_flush);
+
+    qtest_add_func("/ide/cdrom/pio", test_cdrom_pio);
+    qtest_add_func("/ide/cdrom/pio_large", test_cdrom_pio_large);
+    qtest_add_func("/ide/cdrom/dma", test_cdrom_dma);
+
+    ret = g_test_run();
+
+    /* Cleanup */
+    unlink(tmp_path);
+    unlink(debug_path);
+
+    return ret;
+}
diff --git a/tests/qtest/intel-hda-test.c b/tests/qtest/intel-hda-test.c
new file mode 100644 (file)
index 0000000..fc25ccc
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * QTest testcase for Intel HDA
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+
+#define HDA_ID "hda0"
+#define CODEC_DEVICES " -device hda-output,bus=" HDA_ID ".0" \
+                      " -device hda-micro,bus=" HDA_ID ".0" \
+                      " -device hda-duplex,bus=" HDA_ID ".0"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void ich6_test(void)
+{
+    qtest_start("-device intel-hda,id=" HDA_ID CODEC_DEVICES);
+    qtest_end();
+}
+
+static void ich9_test(void)
+{
+    qtest_start("-machine q35 -device ich9-intel-hda,bus=pcie.0,addr=1b.0,id="
+                HDA_ID CODEC_DEVICES);
+    qtest_end();
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/intel-hda/ich6", ich6_test);
+    qtest_add_func("/intel-hda/ich9", ich9_test);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/ioh3420-test.c b/tests/qtest/ioh3420-test.c
new file mode 100644 (file)
index 0000000..f6ca43c
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * QTest testcase for Intel X58 north bridge IOH
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void nop(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/ioh3420/nop", nop);
+
+    qtest_start("-machine q35 -device ioh3420,bus=pcie.0,addr=1c.0,port=1,"
+                "chassis=1,multifunction=on");
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
diff --git a/tests/qtest/ipmi-bt-test.c b/tests/qtest/ipmi-bt-test.c
new file mode 100644 (file)
index 0000000..a42207d
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * IPMI BT test cases, using the external interface for checking
+ *
+ * Copyright (c) 2012 Corey Minyard <[email protected]>
+ *
+ * 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 <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+
+#include "libqtest-single.h"
+#include "qemu-common.h"
+
+#define IPMI_IRQ        5
+
+#define IPMI_BT_BASE    0xe4
+
+#define IPMI_BT_CTLREG_CLR_WR_PTR  0
+#define IPMI_BT_CTLREG_CLR_RD_PTR  1
+#define IPMI_BT_CTLREG_H2B_ATN     2
+#define IPMI_BT_CTLREG_B2H_ATN     3
+#define IPMI_BT_CTLREG_SMS_ATN     4
+#define IPMI_BT_CTLREG_H_BUSY      6
+#define IPMI_BT_CTLREG_B_BUSY      7
+
+#define IPMI_BT_CTLREG_GET(b) ((bt_get_ctrlreg() >> (b)) & 1)
+#define IPMI_BT_CTLREG_GET_H2B_ATN() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_H2B_ATN)
+#define IPMI_BT_CTLREG_GET_B2H_ATN() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_B2H_ATN)
+#define IPMI_BT_CTLREG_GET_SMS_ATN() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_SMS_ATN)
+#define IPMI_BT_CTLREG_GET_H_BUSY()  IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_H_BUSY)
+#define IPMI_BT_CTLREG_GET_B_BUSY()  IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_B_BUSY)
+
+#define IPMI_BT_CTLREG_SET(b) bt_write_ctrlreg(1 << (b))
+#define IPMI_BT_CTLREG_SET_CLR_WR_PTR() IPMI_BT_CTLREG_SET( \
+                                                IPMI_BT_CTLREG_CLR_WR_PTR)
+#define IPMI_BT_CTLREG_SET_CLR_RD_PTR() IPMI_BT_CTLREG_SET( \
+                                                IPMI_BT_CTLREG_CLR_RD_PTR)
+#define IPMI_BT_CTLREG_SET_H2B_ATN()  IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_H2B_ATN)
+#define IPMI_BT_CTLREG_SET_B2H_ATN()  IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_B2H_ATN)
+#define IPMI_BT_CTLREG_SET_SMS_ATN()  IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_SMS_ATN)
+#define IPMI_BT_CTLREG_SET_H_BUSY()   IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_H_BUSY)
+
+static int bt_ints_enabled;
+
+static uint8_t bt_get_ctrlreg(void)
+{
+    return inb(IPMI_BT_BASE);
+}
+
+static void bt_write_ctrlreg(uint8_t val)
+{
+    outb(IPMI_BT_BASE, val);
+}
+
+static uint8_t bt_get_buf(void)
+{
+    return inb(IPMI_BT_BASE + 1);
+}
+
+static void bt_write_buf(uint8_t val)
+{
+    outb(IPMI_BT_BASE + 1, val);
+}
+
+static uint8_t bt_get_irqreg(void)
+{
+    return inb(IPMI_BT_BASE + 2);
+}
+
+static void bt_write_irqreg(uint8_t val)
+{
+    outb(IPMI_BT_BASE + 2, val);
+}
+
+static void bt_wait_b_busy(void)
+{
+    unsigned int count = 1000;
+    while (IPMI_BT_CTLREG_GET_B_BUSY() != 0) {
+        g_assert(--count != 0);
+        usleep(100);
+    }
+}
+
+static void bt_wait_b2h_atn(void)
+{
+    unsigned int count = 1000;
+    while (IPMI_BT_CTLREG_GET_B2H_ATN() == 0) {
+        g_assert(--count != 0);
+        usleep(100);
+    }
+}
+
+
+static int emu_lfd;
+static int emu_fd;
+static in_port_t emu_port;
+static uint8_t inbuf[100];
+static unsigned int inbuf_len;
+static unsigned int inbuf_pos;
+static int last_was_aa;
+
+static void read_emu_data(void)
+{
+    fd_set readfds;
+    int rv;
+    struct timeval tv;
+
+    FD_ZERO(&readfds);
+    FD_SET(emu_fd, &readfds);
+    tv.tv_sec = 10;
+    tv.tv_usec = 0;
+    rv = select(emu_fd + 1, &readfds, NULL, NULL, &tv);
+    if (rv == -1) {
+        perror("select");
+    }
+    g_assert(rv == 1);
+    rv = read(emu_fd, inbuf, sizeof(inbuf));
+    if (rv == -1) {
+        perror("read");
+    }
+    g_assert(rv > 0);
+    inbuf_len = rv;
+    inbuf_pos = 0;
+}
+
+static void write_emu_msg(uint8_t *msg, unsigned int len)
+{
+    int rv;
+
+#ifdef DEBUG_TEST
+    {
+        unsigned int i;
+        printf("sending:");
+        for (i = 0; i < len; i++) {
+            printf(" %2.2x", msg[i]);
+        }
+        printf("\n");
+    }
+#endif
+    rv = write(emu_fd, msg, len);
+    g_assert(rv == len);
+}
+
+static void get_emu_msg(uint8_t *msg, unsigned int *len)
+{
+    unsigned int outpos = 0;
+
+    for (;;) {
+        while (inbuf_pos < inbuf_len) {
+            uint8_t ch = inbuf[inbuf_pos++];
+
+            g_assert(outpos < *len);
+            if (last_was_aa) {
+                assert(ch & 0x10);
+                msg[outpos++] = ch & ~0x10;
+                last_was_aa = 0;
+            } else if (ch == 0xaa) {
+                last_was_aa = 1;
+            } else {
+                msg[outpos++] = ch;
+                if ((ch == 0xa0) || (ch == 0xa1)) {
+                    /* Message complete */
+                    *len = outpos;
+                    goto done;
+                }
+            }
+        }
+        read_emu_data();
+    }
+ done:
+#ifdef DEBUG_TEST
+    {
+        unsigned int i;
+        printf("Msg:");
+        for (i = 0; i < outpos; i++) {
+            printf(" %2.2x", msg[i]);
+        }
+        printf("\n");
+    }
+#endif
+    return;
+}
+
+static uint8_t
+ipmb_checksum(const unsigned char *data, int size, unsigned char start)
+{
+        unsigned char csum = start;
+
+        for (; size > 0; size--, data++) {
+                csum += *data;
+        }
+        return csum;
+}
+
+static uint8_t get_dev_id_cmd[] = { 0x18, 0x01 };
+static uint8_t get_dev_id_rsp[] = { 0x1c, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
+                                    0x02, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static uint8_t set_bmc_globals_cmd[] = { 0x18, 0x2e, 0x0f };
+static uint8_t set_bmc_globals_rsp[] = { 0x1c, 0x2e, 0x00 };
+static uint8_t enable_irq_cmd[] = { 0x05, 0xa1 };
+
+static void emu_msg_handler(void)
+{
+    uint8_t msg[100];
+    unsigned int msg_len = sizeof(msg);
+
+    get_emu_msg(msg, &msg_len);
+    g_assert(msg_len >= 5);
+    g_assert(msg[msg_len - 1] == 0xa0);
+    msg_len--;
+    g_assert(ipmb_checksum(msg, msg_len, 0) == 0);
+    msg_len--;
+    if ((msg[1] == get_dev_id_cmd[0]) && (msg[2] == get_dev_id_cmd[1])) {
+        memcpy(msg + 1, get_dev_id_rsp, sizeof(get_dev_id_rsp));
+        msg_len = sizeof(get_dev_id_rsp) + 1;
+        msg[msg_len] = -ipmb_checksum(msg, msg_len, 0);
+        msg_len++;
+        msg[msg_len++] = 0xa0;
+        write_emu_msg(msg, msg_len);
+    } else if ((msg[1] == set_bmc_globals_cmd[0]) &&
+               (msg[2] == set_bmc_globals_cmd[1])) {
+        write_emu_msg(enable_irq_cmd, sizeof(enable_irq_cmd));
+        memcpy(msg + 1, set_bmc_globals_rsp, sizeof(set_bmc_globals_rsp));
+        msg_len = sizeof(set_bmc_globals_rsp) + 1;
+        msg[msg_len] = -ipmb_checksum(msg, msg_len, 0);
+        msg_len++;
+        msg[msg_len++] = 0xa0;
+        write_emu_msg(msg, msg_len);
+    } else {
+        g_assert(0);
+    }
+}
+
+static void bt_cmd(uint8_t *cmd, unsigned int cmd_len,
+                    uint8_t *rsp, unsigned int *rsp_len)
+{
+    unsigned int i, len, j = 0;
+    uint8_t seq = 5;
+
+    /* Should be idle */
+    g_assert(bt_get_ctrlreg() == 0);
+
+    bt_wait_b_busy();
+    IPMI_BT_CTLREG_SET_CLR_WR_PTR();
+    bt_write_buf(cmd_len + 1);
+    bt_write_buf(cmd[0]);
+    bt_write_buf(seq);
+    for (i = 1; i < cmd_len; i++) {
+        bt_write_buf(cmd[i]);
+    }
+    IPMI_BT_CTLREG_SET_H2B_ATN();
+
+    emu_msg_handler(); /* We should get a message on the socket here. */
+
+    bt_wait_b2h_atn();
+    if (bt_ints_enabled) {
+        g_assert((bt_get_irqreg() & 0x02) == 0x02);
+        g_assert(get_irq(IPMI_IRQ));
+        bt_write_irqreg(0x03);
+    } else {
+        g_assert(!get_irq(IPMI_IRQ));
+    }
+    IPMI_BT_CTLREG_SET_H_BUSY();
+    IPMI_BT_CTLREG_SET_B2H_ATN();
+    IPMI_BT_CTLREG_SET_CLR_RD_PTR();
+    len = bt_get_buf();
+    g_assert(len >= 4);
+    rsp[0] = bt_get_buf();
+    assert(bt_get_buf() == seq);
+    len--;
+    for (j = 1; j < len; j++) {
+        rsp[j] = bt_get_buf();
+    }
+    IPMI_BT_CTLREG_SET_H_BUSY();
+    *rsp_len = j;
+}
+
+
+/*
+ * We should get a connect request and a short message with capabilities.
+ */
+static void test_connect(void)
+{
+    fd_set readfds;
+    int rv;
+    int val;
+    struct timeval tv;
+    uint8_t msg[100];
+    unsigned int msglen;
+    static uint8_t exp1[] = { 0xff, 0x01, 0xa1 }; /* A protocol version */
+    static uint8_t exp2[] = { 0x08, 0x3f, 0xa1 }; /* A capabilities cmd */
+
+    FD_ZERO(&readfds);
+    FD_SET(emu_lfd, &readfds);
+    tv.tv_sec = 10;
+    tv.tv_usec = 0;
+    rv = select(emu_lfd + 1, &readfds, NULL, NULL, &tv);
+    g_assert(rv == 1);
+    emu_fd = accept(emu_lfd, NULL, 0);
+    if (emu_fd < 0) {
+        perror("accept");
+    }
+    g_assert(emu_fd >= 0);
+
+    val = 1;
+    rv = setsockopt(emu_fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+    g_assert(rv != -1);
+
+    /* Report our version */
+    write_emu_msg(exp1, sizeof(exp1));
+
+    /* Validate that we get the info we expect. */
+    msglen = sizeof(msg);
+    get_emu_msg(msg, &msglen);
+    g_assert(msglen == sizeof(exp1));
+    g_assert(memcmp(msg, exp1, msglen) == 0);
+    msglen = sizeof(msg);
+    get_emu_msg(msg, &msglen);
+    g_assert(msglen == sizeof(exp2));
+    g_assert(memcmp(msg, exp2, msglen) == 0);
+}
+
+/*
+ * Send a get_device_id to do a basic test.
+ */
+static void test_bt_base(void)
+{
+    uint8_t rsp[20];
+    unsigned int rsplen = sizeof(rsp);
+
+    bt_cmd(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen);
+    g_assert(rsplen == sizeof(get_dev_id_rsp));
+    g_assert(memcmp(get_dev_id_rsp, rsp, rsplen) == 0);
+}
+
+/*
+ * Enable IRQs for the interface.
+ */
+static void test_enable_irq(void)
+{
+    uint8_t rsp[20];
+    unsigned int rsplen = sizeof(rsp);
+
+    bt_cmd(set_bmc_globals_cmd, sizeof(set_bmc_globals_cmd), rsp, &rsplen);
+    g_assert(rsplen == sizeof(set_bmc_globals_rsp));
+    g_assert(memcmp(set_bmc_globals_rsp, rsp, rsplen) == 0);
+    bt_write_irqreg(0x01);
+    bt_ints_enabled = 1;
+}
+
+/*
+ * Create a local TCP socket with any port, then save off the port we got.
+ */
+static void open_socket(void)
+{
+    struct sockaddr_in myaddr;
+    socklen_t addrlen;
+
+    myaddr.sin_family = AF_INET;
+    myaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    myaddr.sin_port = 0;
+    emu_lfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (emu_lfd == -1) {
+        perror("socket");
+        exit(1);
+    }
+    if (bind(emu_lfd, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) {
+        perror("bind");
+        exit(1);
+    }
+    addrlen = sizeof(myaddr);
+    if (getsockname(emu_lfd, (struct sockaddr *) &myaddr , &addrlen) == -1) {
+        perror("getsockname");
+        exit(1);
+    }
+    emu_port = ntohs(myaddr.sin_port);
+    assert(listen(emu_lfd, 1) != -1);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    open_socket();
+
+    /* Run the tests */
+    g_test_init(&argc, &argv, NULL);
+
+    global_qtest = qtest_initf(
+        " -chardev socket,id=ipmi0,host=localhost,port=%d,reconnect=10"
+        " -device ipmi-bmc-extern,chardev=ipmi0,id=bmc0"
+        " -device isa-ipmi-bt,bmc=bmc0", emu_port);
+    qtest_irq_intercept_in(global_qtest, "ioapic");
+    qtest_add_func("/ipmi/extern/connect", test_connect);
+    qtest_add_func("/ipmi/extern/bt_base", test_bt_base);
+    qtest_add_func("/ipmi/extern/bt_enable_irq", test_enable_irq);
+    qtest_add_func("/ipmi/extern/bt_base_irq", test_bt_base);
+    ret = g_test_run();
+    qtest_quit(global_qtest);
+
+    return ret;
+}
diff --git a/tests/qtest/ipmi-kcs-test.c b/tests/qtest/ipmi-kcs-test.c
new file mode 100644 (file)
index 0000000..693a6aa
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * IPMI KCS test cases, using the local interface.
+ *
+ * Copyright (c) 2012 Corey Minyard <[email protected]>
+ *
+ * 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 "libqtest-single.h"
+
+#define IPMI_IRQ        5
+
+#define IPMI_KCS_BASE   0xca2
+
+#define IPMI_KCS_STATUS_ABORT           0x60
+#define IPMI_KCS_CMD_WRITE_START        0x61
+#define IPMI_KCS_CMD_WRITE_END          0x62
+#define IPMI_KCS_CMD_READ               0x68
+
+#define IPMI_KCS_ABORTED_BY_CMD         0x01
+
+#define IPMI_KCS_CMDREG_GET_STATE() ((kcs_get_cmdreg() >> 6) & 3)
+#define IPMI_KCS_STATE_IDLE     0
+#define IPMI_KCS_STATE_READ     1
+#define IPMI_KCS_STATE_WRITE    2
+#define IPMI_KCS_STATE_ERROR    3
+#define IPMI_KCS_CMDREG_GET_CD()    ((kcs_get_cmdreg() >> 3) & 1)
+#define IPMI_KCS_CMDREG_GET_ATN()   ((kcs_get_cmdreg() >> 2) & 1)
+#define IPMI_KCS_CMDREG_GET_IBF()   ((kcs_get_cmdreg() >> 1) & 1)
+#define IPMI_KCS_CMDREG_GET_OBF()   ((kcs_get_cmdreg() >> 0) & 1)
+
+static int kcs_ints_enabled;
+
+static uint8_t kcs_get_cmdreg(void)
+{
+    return inb(IPMI_KCS_BASE + 1);
+}
+
+static void kcs_write_cmdreg(uint8_t val)
+{
+    outb(IPMI_KCS_BASE + 1, val);
+}
+
+static uint8_t kcs_get_datareg(void)
+{
+    return inb(IPMI_KCS_BASE);
+}
+
+static void kcs_write_datareg(uint8_t val)
+{
+    outb(IPMI_KCS_BASE, val);
+}
+
+static void kcs_wait_ibf(void)
+{
+    unsigned int count = 1000;
+    while (IPMI_KCS_CMDREG_GET_IBF() != 0) {
+        g_assert(--count != 0);
+    }
+}
+
+static void kcs_wait_obf(void)
+{
+    unsigned int count = 1000;
+    while (IPMI_KCS_CMDREG_GET_OBF() == 0) {
+        g_assert(--count != 0);
+    }
+}
+
+static void kcs_clear_obf(void)
+{
+    if (kcs_ints_enabled) {
+        g_assert(get_irq(IPMI_IRQ));
+    } else {
+        g_assert(!get_irq(IPMI_IRQ));
+    }
+    g_assert(IPMI_KCS_CMDREG_GET_OBF() == 1);
+    kcs_get_datareg();
+    g_assert(IPMI_KCS_CMDREG_GET_OBF() == 0);
+    g_assert(!get_irq(IPMI_IRQ));
+}
+
+static void kcs_check_state(uint8_t state)
+{
+    g_assert(IPMI_KCS_CMDREG_GET_STATE() == state);
+}
+
+static void kcs_cmd(uint8_t *cmd, unsigned int cmd_len,
+                    uint8_t *rsp, unsigned int *rsp_len)
+{
+    unsigned int i, j = 0;
+
+    /* Should be idle */
+    g_assert(kcs_get_cmdreg() == 0);
+
+    kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_START);
+    kcs_wait_ibf();
+    kcs_check_state(IPMI_KCS_STATE_WRITE);
+    kcs_clear_obf();
+    for (i = 0; i < cmd_len; i++) {
+        kcs_write_datareg(cmd[i]);
+        kcs_wait_ibf();
+        kcs_check_state(IPMI_KCS_STATE_WRITE);
+        kcs_clear_obf();
+    }
+    kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_END);
+    kcs_wait_ibf();
+    kcs_check_state(IPMI_KCS_STATE_WRITE);
+    kcs_clear_obf();
+    kcs_write_datareg(0);
+ next_read_byte:
+    kcs_wait_ibf();
+    switch (IPMI_KCS_CMDREG_GET_STATE()) {
+    case IPMI_KCS_STATE_READ:
+        kcs_wait_obf();
+        g_assert(j < *rsp_len);
+        rsp[j++] = kcs_get_datareg();
+        kcs_write_datareg(IPMI_KCS_CMD_READ);
+        goto next_read_byte;
+        break;
+
+    case IPMI_KCS_STATE_IDLE:
+        kcs_wait_obf();
+        kcs_get_datareg();
+        break;
+
+    default:
+        g_assert(0);
+    }
+    *rsp_len = j;
+}
+
+static void kcs_abort(uint8_t *cmd, unsigned int cmd_len,
+                      uint8_t *rsp, unsigned int *rsp_len)
+{
+    unsigned int i, j = 0;
+    unsigned int retries = 4;
+
+    /* Should be idle */
+    g_assert(kcs_get_cmdreg() == 0);
+
+    kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_START);
+    kcs_wait_ibf();
+    kcs_check_state(IPMI_KCS_STATE_WRITE);
+    kcs_clear_obf();
+    for (i = 0; i < cmd_len; i++) {
+        kcs_write_datareg(cmd[i]);
+        kcs_wait_ibf();
+        kcs_check_state(IPMI_KCS_STATE_WRITE);
+        kcs_clear_obf();
+    }
+    kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_END);
+    kcs_wait_ibf();
+    kcs_check_state(IPMI_KCS_STATE_WRITE);
+    kcs_clear_obf();
+    kcs_write_datareg(0);
+    kcs_wait_ibf();
+    switch (IPMI_KCS_CMDREG_GET_STATE()) {
+    case IPMI_KCS_STATE_READ:
+        kcs_wait_obf();
+        g_assert(j < *rsp_len);
+        rsp[j++] = kcs_get_datareg();
+        kcs_write_datareg(IPMI_KCS_CMD_READ);
+        break;
+
+    default:
+        g_assert(0);
+    }
+
+    /* Start the abort here */
+ retry_abort:
+    g_assert(retries > 0);
+
+    kcs_wait_ibf();
+    kcs_write_cmdreg(IPMI_KCS_STATUS_ABORT);
+    kcs_wait_ibf();
+    kcs_clear_obf();
+    kcs_write_datareg(0);
+    kcs_wait_ibf();
+    if (IPMI_KCS_CMDREG_GET_STATE() != IPMI_KCS_STATE_READ) {
+        retries--;
+        goto retry_abort;
+    }
+    kcs_wait_obf();
+    rsp[0] = kcs_get_datareg();
+    kcs_write_datareg(IPMI_KCS_CMD_READ);
+    kcs_wait_ibf();
+    if (IPMI_KCS_CMDREG_GET_STATE() != IPMI_KCS_STATE_IDLE) {
+        retries--;
+        goto retry_abort;
+    }
+    kcs_wait_obf();
+    kcs_clear_obf();
+
+    *rsp_len = j;
+}
+
+
+static uint8_t get_dev_id_cmd[] = { 0x18, 0x01 };
+static uint8_t get_dev_id_rsp[] = { 0x1c, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
+                                    0x02, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+/*
+ * Send a get_device_id to do a basic test.
+ */
+static void test_kcs_base(void)
+{
+    uint8_t rsp[20];
+    unsigned int rsplen = sizeof(rsp);
+
+    kcs_cmd(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen);
+    g_assert(rsplen == sizeof(get_dev_id_rsp));
+    g_assert(memcmp(get_dev_id_rsp, rsp, rsplen) == 0);
+}
+
+/*
+ * Abort a kcs operation while reading
+ */
+static void test_kcs_abort(void)
+{
+    uint8_t rsp[20];
+    unsigned int rsplen = sizeof(rsp);
+
+    kcs_abort(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen);
+    g_assert(rsp[0] == IPMI_KCS_ABORTED_BY_CMD);
+}
+
+static uint8_t set_bmc_globals_cmd[] = { 0x18, 0x2e, 0x0f };
+static uint8_t set_bmc_globals_rsp[] = { 0x1c, 0x2e, 0x00 };
+
+/*
+ * Enable interrupts
+ */
+static void test_enable_irq(void)
+{
+    uint8_t rsp[20];
+    unsigned int rsplen = sizeof(rsp);
+
+    kcs_cmd(set_bmc_globals_cmd, sizeof(set_bmc_globals_cmd), rsp, &rsplen);
+    g_assert(rsplen == sizeof(set_bmc_globals_rsp));
+    g_assert(memcmp(set_bmc_globals_rsp, rsp, rsplen) == 0);
+    kcs_ints_enabled = 1;
+}
+
+int main(int argc, char **argv)
+{
+    char *cmdline;
+    int ret;
+
+    /* Run the tests */
+    g_test_init(&argc, &argv, NULL);
+
+    cmdline = g_strdup_printf("-device ipmi-bmc-sim,id=bmc0"
+                              " -device isa-ipmi-kcs,bmc=bmc0");
+    qtest_start(cmdline);
+    g_free(cmdline);
+    qtest_irq_intercept_in(global_qtest, "ioapic");
+    qtest_add_func("/ipmi/local/kcs_base", test_kcs_base);
+    qtest_add_func("/ipmi/local/kcs_abort", test_kcs_abort);
+    qtest_add_func("/ipmi/local/kcs_enable_irq", test_enable_irq);
+    qtest_add_func("/ipmi/local/kcs_base_irq", test_kcs_base);
+    qtest_add_func("/ipmi/local/kcs_abort_irq", test_kcs_abort);
+    ret = g_test_run();
+    qtest_quit(global_qtest);
+
+    return ret;
+}
diff --git a/tests/qtest/ipoctal232-test.c b/tests/qtest/ipoctal232-test.c
new file mode 100644 (file)
index 0000000..53a8c9b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * QTest testcase for IndustryPack Octal-RS232
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+
+typedef struct QIpoctal232 QIpoctal232;
+
+struct QIpoctal232 {
+    QOSGraphObject obj;
+};
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void nop(void *obj, void *data, QGuestAllocator *alloc)
+{
+}
+
+static void *ipoctal232_create(void *pci_bus, QGuestAllocator *alloc,
+                               void *addr)
+{
+    QIpoctal232 *ipoctal232 = g_new0(QIpoctal232, 1);
+
+    return &ipoctal232->obj;
+}
+
+static void ipoctal232_register_nodes(void)
+{
+    qos_node_create_driver("ipoctal232", ipoctal232_create);
+    qos_node_consumes("ipoctal232", "ipack", &(QOSGraphEdgeOptions) {
+        .extra_device_opts = "bus=ipack0.0",
+    });
+}
+
+libqos_init(ipoctal232_register_nodes);
+
+static void register_ipoctal232_test(void)
+{
+    qos_add_test("nop", "ipoctal232", nop, NULL);
+}
+
+libqos_init(register_ipoctal232_test);
diff --git a/tests/qtest/ivshmem-test.c b/tests/qtest/ivshmem-test.c
new file mode 100644 (file)
index 0000000..ecda256
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * QTest testcase for ivshmem
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include <glib/gstdio.h>
+#include "contrib/ivshmem-server/ivshmem-server.h"
+#include "libqos/libqos-pc.h"
+#include "libqos/libqos-spapr.h"
+#include "libqtest.h"
+#include "qemu-common.h"
+
+#define TMPSHMSIZE (1 << 20)
+static char *tmpshm;
+static void *tmpshmem;
+static char *tmpdir;
+static char *tmpserver;
+
+static void save_fn(QPCIDevice *dev, int devfn, void *data)
+{
+    QPCIDevice **pdev = (QPCIDevice **) data;
+
+    *pdev = dev;
+}
+
+static QPCIDevice *get_device(QPCIBus *pcibus)
+{
+    QPCIDevice *dev;
+
+    dev = NULL;
+    qpci_device_foreach(pcibus, 0x1af4, 0x1110, save_fn, &dev);
+    g_assert(dev != NULL);
+
+    return dev;
+}
+
+typedef struct _IVState {
+    QOSState *qs;
+    QPCIBar reg_bar, mem_bar;
+    QPCIDevice *dev;
+} IVState;
+
+enum Reg {
+    INTRMASK = 0,
+    INTRSTATUS = 4,
+    IVPOSITION = 8,
+    DOORBELL = 12,
+};
+
+static const char* reg2str(enum Reg reg) {
+    switch (reg) {
+    case INTRMASK:
+        return "IntrMask";
+    case INTRSTATUS:
+        return "IntrStatus";
+    case IVPOSITION:
+        return "IVPosition";
+    case DOORBELL:
+        return "DoorBell";
+    default:
+        return NULL;
+    }
+}
+
+static inline unsigned in_reg(IVState *s, enum Reg reg)
+{
+    const char *name = reg2str(reg);
+    unsigned res;
+
+    res = qpci_io_readl(s->dev, s->reg_bar, reg);
+    g_test_message("*%s -> %x", name, res);
+
+    return res;
+}
+
+static inline void out_reg(IVState *s, enum Reg reg, unsigned v)
+{
+    const char *name = reg2str(reg);
+
+    g_test_message("%x -> *%s", v, name);
+    qpci_io_writel(s->dev, s->reg_bar, reg, v);
+}
+
+static inline void read_mem(IVState *s, uint64_t off, void *buf, size_t len)
+{
+    qpci_memread(s->dev, s->mem_bar, off, buf, len);
+}
+
+static inline void write_mem(IVState *s, uint64_t off,
+                             const void *buf, size_t len)
+{
+    qpci_memwrite(s->dev, s->mem_bar, off, buf, len);
+}
+
+static void cleanup_vm(IVState *s)
+{
+    g_free(s->dev);
+    qtest_shutdown(s->qs);
+}
+
+static void setup_vm_cmd(IVState *s, const char *cmd, bool msix)
+{
+    uint64_t barsize;
+    const char *arch = qtest_get_arch();
+
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        s->qs = qtest_pc_boot(cmd);
+    } else if (strcmp(arch, "ppc64") == 0) {
+        s->qs = qtest_spapr_boot(cmd);
+    } else {
+        g_printerr("ivshmem-test tests are only available on x86 or ppc64\n");
+        exit(EXIT_FAILURE);
+    }
+    s->dev = get_device(s->qs->pcibus);
+
+    s->reg_bar = qpci_iomap(s->dev, 0, &barsize);
+    g_assert_cmpuint(barsize, ==, 256);
+
+    if (msix) {
+        qpci_msix_enable(s->dev);
+    }
+
+    s->mem_bar = qpci_iomap(s->dev, 2, &barsize);
+    g_assert_cmpuint(barsize, ==, TMPSHMSIZE);
+
+    qpci_device_enable(s->dev);
+}
+
+static void setup_vm(IVState *s)
+{
+    char *cmd = g_strdup_printf("-object memory-backend-file"
+                                ",id=mb1,size=1M,share,mem-path=/dev/shm%s"
+                                " -device ivshmem-plain,memdev=mb1", tmpshm);
+
+    setup_vm_cmd(s, cmd, false);
+
+    g_free(cmd);
+}
+
+static void test_ivshmem_single(void)
+{
+    IVState state, *s;
+    uint32_t data[1024];
+    int i;
+
+    setup_vm(&state);
+    s = &state;
+
+    /* initial state of readable registers */
+    g_assert_cmpuint(in_reg(s, INTRMASK), ==, 0);
+    g_assert_cmpuint(in_reg(s, INTRSTATUS), ==, 0);
+    g_assert_cmpuint(in_reg(s, IVPOSITION), ==, 0);
+
+    /* trigger interrupt via registers */
+    out_reg(s, INTRMASK, 0xffffffff);
+    g_assert_cmpuint(in_reg(s, INTRMASK), ==, 0xffffffff);
+    out_reg(s, INTRSTATUS, 1);
+    /* check interrupt status */
+    g_assert_cmpuint(in_reg(s, INTRSTATUS), ==, 1);
+    /* reading clears */
+    g_assert_cmpuint(in_reg(s, INTRSTATUS), ==, 0);
+    /* TODO intercept actual interrupt (needs qtest work) */
+
+    /* invalid register access */
+    out_reg(s, IVPOSITION, 1);
+    in_reg(s, DOORBELL);
+
+    /* ring the (non-functional) doorbell */
+    out_reg(s, DOORBELL, 8 << 16);
+
+    /* write shared memory */
+    for (i = 0; i < G_N_ELEMENTS(data); i++) {
+        data[i] = i;
+    }
+    write_mem(s, 0, data, sizeof(data));
+
+    /* verify write */
+    for (i = 0; i < G_N_ELEMENTS(data); i++) {
+        g_assert_cmpuint(((uint32_t *)tmpshmem)[i], ==, i);
+    }
+
+    /* read it back and verify read */
+    memset(data, 0, sizeof(data));
+    read_mem(s, 0, data, sizeof(data));
+    for (i = 0; i < G_N_ELEMENTS(data); i++) {
+        g_assert_cmpuint(data[i], ==, i);
+    }
+
+    cleanup_vm(s);
+}
+
+static void test_ivshmem_pair(void)
+{
+    IVState state1, state2, *s1, *s2;
+    char *data;
+    int i;
+
+    setup_vm(&state1);
+    s1 = &state1;
+    setup_vm(&state2);
+    s2 = &state2;
+
+    data = g_malloc0(TMPSHMSIZE);
+
+    /* host write, guest 1 & 2 read */
+    memset(tmpshmem, 0x42, TMPSHMSIZE);
+    read_mem(s1, 0, data, TMPSHMSIZE);
+    for (i = 0; i < TMPSHMSIZE; i++) {
+        g_assert_cmpuint(data[i], ==, 0x42);
+    }
+    read_mem(s2, 0, data, TMPSHMSIZE);
+    for (i = 0; i < TMPSHMSIZE; i++) {
+        g_assert_cmpuint(data[i], ==, 0x42);
+    }
+
+    /* guest 1 write, guest 2 read */
+    memset(data, 0x43, TMPSHMSIZE);
+    write_mem(s1, 0, data, TMPSHMSIZE);
+    memset(data, 0, TMPSHMSIZE);
+    read_mem(s2, 0, data, TMPSHMSIZE);
+    for (i = 0; i < TMPSHMSIZE; i++) {
+        g_assert_cmpuint(data[i], ==, 0x43);
+    }
+
+    /* guest 2 write, guest 1 read */
+    memset(data, 0x44, TMPSHMSIZE);
+    write_mem(s2, 0, data, TMPSHMSIZE);
+    memset(data, 0, TMPSHMSIZE);
+    read_mem(s1, 0, data, TMPSHMSIZE);
+    for (i = 0; i < TMPSHMSIZE; i++) {
+        g_assert_cmpuint(data[i], ==, 0x44);
+    }
+
+    cleanup_vm(s1);
+    cleanup_vm(s2);
+    g_free(data);
+}
+
+typedef struct ServerThread {
+    GThread *thread;
+    IvshmemServer *server;
+    int pipe[2]; /* to handle quit */
+} ServerThread;
+
+static void *server_thread(void *data)
+{
+    ServerThread *t = data;
+    IvshmemServer *server = t->server;
+
+    while (true) {
+        fd_set fds;
+        int maxfd, ret;
+
+        FD_ZERO(&fds);
+        FD_SET(t->pipe[0], &fds);
+        maxfd = t->pipe[0] + 1;
+
+        ivshmem_server_get_fds(server, &fds, &maxfd);
+
+        ret = select(maxfd, &fds, NULL, NULL, NULL);
+
+        if (ret < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+
+            g_critical("select error: %s\n", strerror(errno));
+            break;
+        }
+        if (ret == 0) {
+            continue;
+        }
+
+        if (FD_ISSET(t->pipe[0], &fds)) {
+            break;
+        }
+
+        if (ivshmem_server_handle_fds(server, &fds, maxfd) < 0) {
+            g_critical("ivshmem_server_handle_fds() failed\n");
+            break;
+        }
+    }
+
+    return NULL;
+}
+
+static void setup_vm_with_server(IVState *s, int nvectors)
+{
+    char *cmd;
+
+    cmd = g_strdup_printf("-chardev socket,id=chr0,path=%s "
+                          "-device ivshmem-doorbell,chardev=chr0,vectors=%d",
+                          tmpserver, nvectors);
+
+    setup_vm_cmd(s, cmd, true);
+
+    g_free(cmd);
+}
+
+static void test_ivshmem_server(void)
+{
+    IVState state1, state2, *s1, *s2;
+    ServerThread thread;
+    IvshmemServer server;
+    int ret, vm1, vm2;
+    int nvectors = 2;
+    guint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+
+    ret = ivshmem_server_init(&server, tmpserver, tmpshm, true,
+                              TMPSHMSIZE, nvectors,
+                              g_test_verbose());
+    g_assert_cmpint(ret, ==, 0);
+
+    ret = ivshmem_server_start(&server);
+    g_assert_cmpint(ret, ==, 0);
+
+    thread.server = &server;
+    ret = pipe(thread.pipe);
+    g_assert_cmpint(ret, ==, 0);
+    thread.thread = g_thread_new("ivshmem-server", server_thread, &thread);
+    g_assert(thread.thread != NULL);
+
+    setup_vm_with_server(&state1, nvectors);
+    s1 = &state1;
+    setup_vm_with_server(&state2, nvectors);
+    s2 = &state2;
+
+    /* check got different VM ids */
+    vm1 = in_reg(s1, IVPOSITION);
+    vm2 = in_reg(s2, IVPOSITION);
+    g_assert_cmpint(vm1, >=, 0);
+    g_assert_cmpint(vm2, >=, 0);
+    g_assert_cmpint(vm1, !=, vm2);
+
+    /* check number of MSI-X vectors */
+    ret = qpci_msix_table_size(s1->dev);
+    g_assert_cmpuint(ret, ==, nvectors);
+
+    /* TODO test behavior before MSI-X is enabled */
+
+    /* ping vm2 -> vm1 on vector 0 */
+    ret = qpci_msix_pending(s1->dev, 0);
+    g_assert_cmpuint(ret, ==, 0);
+    out_reg(s2, DOORBELL, vm1 << 16);
+    do {
+        g_usleep(10000);
+        ret = qpci_msix_pending(s1->dev, 0);
+    } while (ret == 0 && g_get_monotonic_time() < end_time);
+    g_assert_cmpuint(ret, !=, 0);
+
+    /* ping vm1 -> vm2 on vector 1 */
+    ret = qpci_msix_pending(s2->dev, 1);
+    g_assert_cmpuint(ret, ==, 0);
+    out_reg(s1, DOORBELL, vm2 << 16 | 1);
+    do {
+        g_usleep(10000);
+        ret = qpci_msix_pending(s2->dev, 1);
+    } while (ret == 0 && g_get_monotonic_time() < end_time);
+    g_assert_cmpuint(ret, !=, 0);
+
+    cleanup_vm(s2);
+    cleanup_vm(s1);
+
+    if (qemu_write_full(thread.pipe[1], "q", 1) != 1) {
+        g_error("qemu_write_full: %s", g_strerror(errno));
+    }
+
+    g_thread_join(thread.thread);
+
+    ivshmem_server_close(&server);
+    close(thread.pipe[1]);
+    close(thread.pipe[0]);
+}
+
+#define PCI_SLOT_HP             0x06
+
+static void test_ivshmem_hotplug(void)
+{
+    QTestState *qts;
+    const char *arch = qtest_get_arch();
+
+    qts = qtest_init("-object memory-backend-ram,size=1M,id=mb1");
+
+    qtest_qmp_device_add(qts, "ivshmem-plain", "iv1",
+                         "{'addr': %s, 'memdev': 'mb1'}",
+                         stringify(PCI_SLOT_HP));
+    if (strcmp(arch, "ppc64") != 0) {
+        qpci_unplug_acpi_device_test(qts, "iv1", PCI_SLOT_HP);
+    }
+
+    qtest_quit(qts);
+}
+
+static void test_ivshmem_memdev(void)
+{
+    IVState state;
+
+    /* just for the sake of checking memory-backend property */
+    setup_vm_cmd(&state, "-object memory-backend-ram,size=1M,id=mb1"
+                 " -device ivshmem-plain,memdev=mb1", false);
+
+    cleanup_vm(&state);
+}
+
+static void cleanup(void)
+{
+    if (tmpshmem) {
+        munmap(tmpshmem, TMPSHMSIZE);
+        tmpshmem = NULL;
+    }
+
+    if (tmpshm) {
+        shm_unlink(tmpshm);
+        g_free(tmpshm);
+        tmpshm = NULL;
+    }
+
+    if (tmpserver) {
+        g_unlink(tmpserver);
+        g_free(tmpserver);
+        tmpserver = NULL;
+    }
+
+    if (tmpdir) {
+        g_rmdir(tmpdir);
+        tmpdir = NULL;
+    }
+}
+
+static void abrt_handler(void *data)
+{
+    cleanup();
+}
+
+static gchar *mktempshm(int size, int *fd)
+{
+    while (true) {
+        gchar *name;
+
+        name = g_strdup_printf("/qtest-%u-%u", getpid(), g_test_rand_int());
+        *fd = shm_open(name, O_CREAT|O_RDWR|O_EXCL,
+                       S_IRWXU|S_IRWXG|S_IRWXO);
+        if (*fd > 0) {
+            g_assert(ftruncate(*fd, size) == 0);
+            return name;
+        }
+
+        g_free(name);
+
+        if (errno != EEXIST) {
+            perror("shm_open");
+            return NULL;
+        }
+    }
+}
+
+int main(int argc, char **argv)
+{
+    int ret, fd;
+    const char *arch = qtest_get_arch();
+    gchar dir[] = "/tmp/ivshmem-test.XXXXXX";
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_abrt_handler(abrt_handler, NULL);
+    /* shm */
+    tmpshm = mktempshm(TMPSHMSIZE, &fd);
+    if (!tmpshm) {
+        goto out;
+    }
+    tmpshmem = mmap(0, TMPSHMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+    g_assert(tmpshmem != MAP_FAILED);
+    /* server */
+    if (mkdtemp(dir) == NULL) {
+        g_error("mkdtemp: %s", g_strerror(errno));
+    }
+    tmpdir = dir;
+    tmpserver = g_strconcat(tmpdir, "/server", NULL);
+
+    qtest_add_func("/ivshmem/single", test_ivshmem_single);
+    qtest_add_func("/ivshmem/hotplug", test_ivshmem_hotplug);
+    qtest_add_func("/ivshmem/memdev", test_ivshmem_memdev);
+    if (g_test_slow()) {
+        qtest_add_func("/ivshmem/pair", test_ivshmem_pair);
+        if (strcmp(arch, "ppc64") != 0) {
+            qtest_add_func("/ivshmem/server", test_ivshmem_server);
+        }
+    }
+
+out:
+    ret = g_test_run();
+    cleanup();
+    return ret;
+}
diff --git a/tests/qtest/libqtest-single.h b/tests/qtest/libqtest-single.h
new file mode 100644 (file)
index 0000000..6f1bb13
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * QTest - wrappers for test with single QEMU instances
+ *
+ * Copyright IBM, Corp. 2012
+ * Copyright Red Hat, Inc. 2012
+ * Copyright SUSE LINUX Products GmbH 2013
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef LIBQTEST_SINGLE_H
+#define LIBQTEST_SINGLE_H
+
+#include "libqtest.h"
+
+QTestState *global_qtest __attribute__((common, weak));
+
+/**
+ * qtest_start:
+ * @args: other arguments to pass to QEMU
+ *
+ * Start QEMU and assign the resulting #QTestState to a global variable.
+ * The global variable is used by "shortcut" functions documented below.
+ *
+ * Returns: #QTestState instance.
+ */
+static inline QTestState *qtest_start(const char *args)
+{
+    global_qtest = qtest_init(args);
+    return global_qtest;
+}
+
+/**
+ * qtest_end:
+ *
+ * Shut down the QEMU process started by qtest_start().
+ */
+static inline void qtest_end(void)
+{
+    if (!global_qtest) {
+        return;
+    }
+    qtest_quit(global_qtest);
+    global_qtest = NULL;
+}
+
+/**
+ * qmp:
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf_nofail().  See parse_escape() for what's
+ * supported after '%'.
+ *
+ * Sends a QMP message to QEMU and returns the response.
+ */
+GCC_FMT_ATTR(1, 2)
+static inline QDict *qmp(const char *fmt, ...)
+{
+    va_list ap;
+    QDict *response;
+
+    va_start(ap, fmt);
+    response = qtest_vqmp(global_qtest, fmt, ap);
+    va_end(ap);
+    return response;
+}
+
+/**
+ * qmp_eventwait:
+ * @s: #event event to wait for.
+ *
+ * Continuously polls for QMP responses until it receives the desired event.
+ */
+static inline void qmp_eventwait(const char *event)
+{
+    return qtest_qmp_eventwait(global_qtest, event);
+}
+
+/**
+ * get_irq:
+ * @num: Interrupt to observe.
+ *
+ * Returns: The level of the @num interrupt.
+ */
+static inline bool get_irq(int num)
+{
+    return qtest_get_irq(global_qtest, num);
+}
+
+/**
+ * outb:
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write an 8-bit value to an I/O port.
+ */
+static inline void outb(uint16_t addr, uint8_t value)
+{
+    qtest_outb(global_qtest, addr, value);
+}
+
+/**
+ * outw:
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 16-bit value to an I/O port.
+ */
+static inline void outw(uint16_t addr, uint16_t value)
+{
+    qtest_outw(global_qtest, addr, value);
+}
+
+/**
+ * outl:
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 32-bit value to an I/O port.
+ */
+static inline void outl(uint16_t addr, uint32_t value)
+{
+    qtest_outl(global_qtest, addr, value);
+}
+
+/**
+ * inb:
+ * @addr: I/O port to read from.
+ *
+ * Reads an 8-bit value from an I/O port.
+ *
+ * Returns: Value read.
+ */
+static inline uint8_t inb(uint16_t addr)
+{
+    return qtest_inb(global_qtest, addr);
+}
+
+/**
+ * inw:
+ * @addr: I/O port to read from.
+ *
+ * Reads a 16-bit value from an I/O port.
+ *
+ * Returns: Value read.
+ */
+static inline uint16_t inw(uint16_t addr)
+{
+    return qtest_inw(global_qtest, addr);
+}
+
+/**
+ * inl:
+ * @addr: I/O port to read from.
+ *
+ * Reads a 32-bit value from an I/O port.
+ *
+ * Returns: Value read.
+ */
+static inline uint32_t inl(uint16_t addr)
+{
+    return qtest_inl(global_qtest, addr);
+}
+
+/**
+ * writeb:
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes an 8-bit value to guest memory.
+ */
+static inline void writeb(uint64_t addr, uint8_t value)
+{
+    qtest_writeb(global_qtest, addr, value);
+}
+
+/**
+ * writew:
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 16-bit value to guest memory.
+ */
+static inline void writew(uint64_t addr, uint16_t value)
+{
+    qtest_writew(global_qtest, addr, value);
+}
+
+/**
+ * writel:
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 32-bit value to guest memory.
+ */
+static inline void writel(uint64_t addr, uint32_t value)
+{
+    qtest_writel(global_qtest, addr, value);
+}
+
+/**
+ * writeq:
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 64-bit value to guest memory.
+ */
+static inline void writeq(uint64_t addr, uint64_t value)
+{
+    qtest_writeq(global_qtest, addr, value);
+}
+
+/**
+ * readb:
+ * @addr: Guest address to read from.
+ *
+ * Reads an 8-bit value from guest memory.
+ *
+ * Returns: Value read.
+ */
+static inline uint8_t readb(uint64_t addr)
+{
+    return qtest_readb(global_qtest, addr);
+}
+
+/**
+ * readw:
+ * @addr: Guest address to read from.
+ *
+ * Reads a 16-bit value from guest memory.
+ *
+ * Returns: Value read.
+ */
+static inline uint16_t readw(uint64_t addr)
+{
+    return qtest_readw(global_qtest, addr);
+}
+
+/**
+ * readl:
+ * @addr: Guest address to read from.
+ *
+ * Reads a 32-bit value from guest memory.
+ *
+ * Returns: Value read.
+ */
+static inline uint32_t readl(uint64_t addr)
+{
+    return qtest_readl(global_qtest, addr);
+}
+
+/**
+ * readq:
+ * @addr: Guest address to read from.
+ *
+ * Reads a 64-bit value from guest memory.
+ *
+ * Returns: Value read.
+ */
+static inline uint64_t readq(uint64_t addr)
+{
+    return qtest_readq(global_qtest, addr);
+}
+
+/**
+ * memread:
+ * @addr: Guest address to read from.
+ * @data: Pointer to where memory contents will be stored.
+ * @size: Number of bytes to read.
+ *
+ * Read guest memory into a buffer.
+ */
+static inline void memread(uint64_t addr, void *data, size_t size)
+{
+    qtest_memread(global_qtest, addr, data, size);
+}
+
+/**
+ * memwrite:
+ * @addr: Guest address to write to.
+ * @data: Pointer to the bytes that will be written to guest memory.
+ * @size: Number of bytes to write.
+ *
+ * Write a buffer to guest memory.
+ */
+static inline void memwrite(uint64_t addr, const void *data, size_t size)
+{
+    qtest_memwrite(global_qtest, addr, data, size);
+}
+
+/**
+ * clock_step_next:
+ *
+ * Advance the QEMU_CLOCK_VIRTUAL to the next deadline.
+ *
+ * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
+ */
+static inline int64_t clock_step_next(void)
+{
+    return qtest_clock_step_next(global_qtest);
+}
+
+/**
+ * clock_step:
+ * @step: Number of nanoseconds to advance the clock by.
+ *
+ * Advance the QEMU_CLOCK_VIRTUAL by @step nanoseconds.
+ *
+ * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
+ */
+static inline int64_t clock_step(int64_t step)
+{
+    return qtest_clock_step(global_qtest, step);
+}
+
+#endif
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
new file mode 100644 (file)
index 0000000..76c9f8e
--- /dev/null
@@ -0,0 +1,1339 @@
+/*
+ * QTest
+ *
+ * Copyright IBM, Corp. 2012
+ * Copyright Red Hat, Inc. 2012
+ * Copyright SUSE LINUX Products GmbH 2013
+ *
+ * Authors:
+ *  Anthony Liguori   <[email protected]>
+ *  Paolo Bonzini     <[email protected]>
+ *  Andreas Färber    <[email protected]>
+ *
+ * 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 <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+
+#include "libqtest.h"
+#include "qemu-common.h"
+#include "qemu/ctype.h"
+#include "qemu/cutils.h"
+#include "qapi/error.h"
+#include "qapi/qmp/json-parser.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qjson.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qmp/qstring.h"
+
+#define MAX_IRQ 256
+#define SOCKET_TIMEOUT 50
+#define SOCKET_MAX_FDS 16
+
+struct QTestState
+{
+    int fd;
+    int qmp_fd;
+    pid_t qemu_pid;  /* our child QEMU process */
+    int wstatus;
+    int expected_status;
+    bool big_endian;
+    bool irq_level[MAX_IRQ];
+    GString *rx;
+};
+
+static GHookList abrt_hooks;
+static struct sigaction sigact_old;
+
+static int qtest_query_target_endianness(QTestState *s);
+
+static int init_socket(const char *socket_path)
+{
+    struct sockaddr_un addr;
+    int sock;
+    int ret;
+
+    sock = socket(PF_UNIX, SOCK_STREAM, 0);
+    g_assert_cmpint(sock, !=, -1);
+
+    addr.sun_family = AF_UNIX;
+    snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path);
+    qemu_set_cloexec(sock);
+
+    do {
+        ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
+    } while (ret == -1 && errno == EINTR);
+    g_assert_cmpint(ret, !=, -1);
+    ret = listen(sock, 1);
+    g_assert_cmpint(ret, !=, -1);
+
+    return sock;
+}
+
+static int socket_accept(int sock)
+{
+    struct sockaddr_un addr;
+    socklen_t addrlen;
+    int ret;
+    struct timeval timeout = { .tv_sec = SOCKET_TIMEOUT,
+                               .tv_usec = 0 };
+
+    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout,
+               sizeof(timeout));
+
+    do {
+        addrlen = sizeof(addr);
+        ret = accept(sock, (struct sockaddr *)&addr, &addrlen);
+    } while (ret == -1 && errno == EINTR);
+    if (ret == -1) {
+        fprintf(stderr, "%s failed: %s\n", __func__, strerror(errno));
+    }
+    close(sock);
+
+    return ret;
+}
+
+bool qtest_probe_child(QTestState *s)
+{
+    pid_t pid = s->qemu_pid;
+
+    if (pid != -1) {
+        pid = waitpid(pid, &s->wstatus, WNOHANG);
+        if (pid == 0) {
+            return true;
+        }
+        s->qemu_pid = -1;
+    }
+    return false;
+}
+
+void qtest_set_expected_status(QTestState *s, int status)
+{
+    s->expected_status = status;
+}
+
+static void kill_qemu(QTestState *s)
+{
+    pid_t pid = s->qemu_pid;
+    int wstatus;
+
+    /* Skip wait if qtest_probe_child already reaped.  */
+    if (pid != -1) {
+        kill(pid, SIGTERM);
+        TFR(pid = waitpid(s->qemu_pid, &s->wstatus, 0));
+        assert(pid == s->qemu_pid);
+    }
+
+    /*
+     * Check whether qemu exited with expected exit status; anything else is
+     * fishy and should be logged with as much detail as possible.
+     */
+    wstatus = s->wstatus;
+    if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != s->expected_status) {
+        fprintf(stderr, "%s:%d: kill_qemu() tried to terminate QEMU "
+                "process but encountered exit status %d (expected %d)\n",
+                __FILE__, __LINE__, WEXITSTATUS(wstatus), s->expected_status);
+        abort();
+    } else if (WIFSIGNALED(wstatus)) {
+        int sig = WTERMSIG(wstatus);
+        const char *signame = strsignal(sig) ?: "unknown ???";
+        const char *dump = WCOREDUMP(wstatus) ? " (core dumped)" : "";
+
+        fprintf(stderr, "%s:%d: kill_qemu() detected QEMU death "
+                "from signal %d (%s)%s\n",
+                __FILE__, __LINE__, sig, signame, dump);
+        abort();
+    }
+}
+
+static void kill_qemu_hook_func(void *s)
+{
+    kill_qemu(s);
+}
+
+static void sigabrt_handler(int signo)
+{
+    g_hook_list_invoke(&abrt_hooks, FALSE);
+}
+
+static void setup_sigabrt_handler(void)
+{
+    struct sigaction sigact;
+
+    /* Catch SIGABRT to clean up on g_assert() failure */
+    sigact = (struct sigaction){
+        .sa_handler = sigabrt_handler,
+        .sa_flags = SA_RESETHAND,
+    };
+    sigemptyset(&sigact.sa_mask);
+    sigaction(SIGABRT, &sigact, &sigact_old);
+}
+
+static void cleanup_sigabrt_handler(void)
+{
+    sigaction(SIGABRT, &sigact_old, NULL);
+}
+
+void qtest_add_abrt_handler(GHookFunc fn, const void *data)
+{
+    GHook *hook;
+
+    /* Only install SIGABRT handler once */
+    if (!abrt_hooks.is_setup) {
+        g_hook_list_init(&abrt_hooks, sizeof(GHook));
+    }
+    setup_sigabrt_handler();
+
+    hook = g_hook_alloc(&abrt_hooks);
+    hook->func = fn;
+    hook->data = (void *)data;
+
+    g_hook_prepend(&abrt_hooks, hook);
+}
+
+static const char *qtest_qemu_binary(void)
+{
+    const char *qemu_bin;
+
+    qemu_bin = getenv("QTEST_QEMU_BINARY");
+    if (!qemu_bin) {
+        fprintf(stderr, "Environment variable QTEST_QEMU_BINARY required\n");
+        exit(1);
+    }
+
+    return qemu_bin;
+}
+
+QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
+{
+    QTestState *s;
+    int sock, qmpsock, i;
+    gchar *socket_path;
+    gchar *qmp_socket_path;
+    gchar *command;
+    const char *qemu_binary = qtest_qemu_binary();
+
+    s = g_new(QTestState, 1);
+
+    socket_path = g_strdup_printf("/tmp/qtest-%d.sock", getpid());
+    qmp_socket_path = g_strdup_printf("/tmp/qtest-%d.qmp", getpid());
+
+    /* It's possible that if an earlier test run crashed it might
+     * have left a stale unix socket lying around. Delete any
+     * stale old socket to avoid spurious test failures with
+     * tests/libqtest.c:70:init_socket: assertion failed (ret != -1): (-1 != -1)
+     */
+    unlink(socket_path);
+    unlink(qmp_socket_path);
+
+    sock = init_socket(socket_path);
+    qmpsock = init_socket(qmp_socket_path);
+
+    qtest_add_abrt_handler(kill_qemu_hook_func, s);
+
+    command = g_strdup_printf("exec %s "
+                              "-qtest unix:%s "
+                              "-qtest-log %s "
+                              "-chardev socket,path=%s,id=char0 "
+                              "-mon chardev=char0,mode=control "
+                              "-display none "
+                              "%s"
+                              " -accel qtest", qemu_binary, socket_path,
+                              getenv("QTEST_LOG") ? "/dev/fd/2" : "/dev/null",
+                              qmp_socket_path,
+                              extra_args ?: "");
+
+    g_test_message("starting QEMU: %s", command);
+
+    s->wstatus = 0;
+    s->expected_status = 0;
+    s->qemu_pid = fork();
+    if (s->qemu_pid == 0) {
+        g_setenv("QEMU_AUDIO_DRV", "none", true);
+        execlp("/bin/sh", "sh", "-c", command, NULL);
+        exit(1);
+    }
+
+    g_free(command);
+    s->fd = socket_accept(sock);
+    if (s->fd >= 0) {
+        s->qmp_fd = socket_accept(qmpsock);
+    }
+    unlink(socket_path);
+    unlink(qmp_socket_path);
+    g_free(socket_path);
+    g_free(qmp_socket_path);
+
+    g_assert(s->fd >= 0 && s->qmp_fd >= 0);
+
+    s->rx = g_string_new("");
+    for (i = 0; i < MAX_IRQ; i++) {
+        s->irq_level[i] = false;
+    }
+
+    if (getenv("QTEST_STOP")) {
+        kill(s->qemu_pid, SIGSTOP);
+    }
+
+    /* ask endianness of the target */
+
+    s->big_endian = qtest_query_target_endianness(s);
+
+    return s;
+}
+
+QTestState *qtest_init(const char *extra_args)
+{
+    QTestState *s = qtest_init_without_qmp_handshake(extra_args);
+    QDict *greeting;
+
+    /* Read the QMP greeting and then do the handshake */
+    greeting = qtest_qmp_receive(s);
+    qobject_unref(greeting);
+    qobject_unref(qtest_qmp(s, "{ 'execute': 'qmp_capabilities' }"));
+
+    return s;
+}
+
+QTestState *qtest_vinitf(const char *fmt, va_list ap)
+{
+    char *args = g_strdup_vprintf(fmt, ap);
+    QTestState *s;
+
+    s = qtest_init(args);
+    g_free(args);
+    return s;
+}
+
+QTestState *qtest_initf(const char *fmt, ...)
+{
+    va_list ap;
+    QTestState *s;
+
+    va_start(ap, fmt);
+    s = qtest_vinitf(fmt, ap);
+    va_end(ap);
+    return s;
+}
+
+QTestState *qtest_init_with_serial(const char *extra_args, int *sock_fd)
+{
+    int sock_fd_init;
+    char *sock_path, sock_dir[] = "/tmp/qtest-serial-XXXXXX";
+    QTestState *qts;
+
+    g_assert_true(mkdtemp(sock_dir) != NULL);
+    sock_path = g_strdup_printf("%s/sock", sock_dir);
+
+    sock_fd_init = init_socket(sock_path);
+
+    qts = qtest_initf("-chardev socket,id=s0,path=%s -serial chardev:s0 %s",
+                      sock_path, extra_args);
+
+    *sock_fd = socket_accept(sock_fd_init);
+
+    unlink(sock_path);
+    g_free(sock_path);
+    rmdir(sock_dir);
+
+    g_assert_true(*sock_fd >= 0);
+
+    return qts;
+}
+
+void qtest_quit(QTestState *s)
+{
+    g_hook_destroy_link(&abrt_hooks, g_hook_find_data(&abrt_hooks, TRUE, s));
+
+    /* Uninstall SIGABRT handler on last instance */
+    cleanup_sigabrt_handler();
+
+    kill_qemu(s);
+    close(s->fd);
+    close(s->qmp_fd);
+    g_string_free(s->rx, true);
+    g_free(s);
+}
+
+static void socket_send(int fd, const char *buf, size_t size)
+{
+    size_t offset;
+
+    offset = 0;
+    while (offset < size) {
+        ssize_t len;
+
+        len = write(fd, buf + offset, size - offset);
+        if (len == -1 && errno == EINTR) {
+            continue;
+        }
+
+        g_assert_cmpint(len, >, 0);
+
+        offset += len;
+    }
+}
+
+static void socket_sendf(int fd, const char *fmt, va_list ap)
+{
+    gchar *str = g_strdup_vprintf(fmt, ap);
+    size_t size = strlen(str);
+
+    socket_send(fd, str, size);
+    g_free(str);
+}
+
+static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    socket_sendf(s->fd, fmt, ap);
+    va_end(ap);
+}
+
+/* Sends a message and file descriptors to the socket.
+ * It's needed for qmp-commands like getfd/add-fd */
+static void socket_send_fds(int socket_fd, int *fds, size_t fds_num,
+                            const char *buf, size_t buf_size)
+{
+    ssize_t ret;
+    struct msghdr msg = { 0 };
+    char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)] = { 0 };
+    size_t fdsize = sizeof(int) * fds_num;
+    struct cmsghdr *cmsg;
+    struct iovec iov = { .iov_base = (char *)buf, .iov_len = buf_size };
+
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+
+    if (fds && fds_num > 0) {
+        g_assert_cmpuint(fds_num, <, SOCKET_MAX_FDS);
+
+        msg.msg_control = control;
+        msg.msg_controllen = CMSG_SPACE(fdsize);
+
+        cmsg = CMSG_FIRSTHDR(&msg);
+        cmsg->cmsg_len = CMSG_LEN(fdsize);
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        memcpy(CMSG_DATA(cmsg), fds, fdsize);
+    }
+
+    do {
+        ret = sendmsg(socket_fd, &msg, 0);
+    } while (ret < 0 && errno == EINTR);
+    g_assert_cmpint(ret, >, 0);
+}
+
+static GString *qtest_recv_line(QTestState *s)
+{
+    GString *line;
+    size_t offset;
+    char *eol;
+
+    while ((eol = strchr(s->rx->str, '\n')) == NULL) {
+        ssize_t len;
+        char buffer[1024];
+
+        len = read(s->fd, buffer, sizeof(buffer));
+        if (len == -1 && errno == EINTR) {
+            continue;
+        }
+
+        if (len == -1 || len == 0) {
+            fprintf(stderr, "Broken pipe\n");
+            abort();
+        }
+
+        g_string_append_len(s->rx, buffer, len);
+    }
+
+    offset = eol - s->rx->str;
+    line = g_string_new_len(s->rx->str, offset);
+    g_string_erase(s->rx, 0, offset + 1);
+
+    return line;
+}
+
+static gchar **qtest_rsp(QTestState *s, int expected_args)
+{
+    GString *line;
+    gchar **words;
+    int i;
+
+redo:
+    line = qtest_recv_line(s);
+    words = g_strsplit(line->str, " ", 0);
+    g_string_free(line, TRUE);
+
+    if (strcmp(words[0], "IRQ") == 0) {
+        long irq;
+        int ret;
+
+        g_assert(words[1] != NULL);
+        g_assert(words[2] != NULL);
+
+        ret = qemu_strtol(words[2], NULL, 0, &irq);
+        g_assert(!ret);
+        g_assert_cmpint(irq, >=, 0);
+        g_assert_cmpint(irq, <, MAX_IRQ);
+
+        if (strcmp(words[1], "raise") == 0) {
+            s->irq_level[irq] = true;
+        } else {
+            s->irq_level[irq] = false;
+        }
+
+        g_strfreev(words);
+        goto redo;
+    }
+
+    g_assert(words[0] != NULL);
+    g_assert_cmpstr(words[0], ==, "OK");
+
+    if (expected_args) {
+        for (i = 0; i < expected_args; i++) {
+            g_assert(words[i] != NULL);
+        }
+    } else {
+        g_strfreev(words);
+    }
+
+    return words;
+}
+
+static int qtest_query_target_endianness(QTestState *s)
+{
+    gchar **args;
+    int big_endian;
+
+    qtest_sendf(s, "endianness\n");
+    args = qtest_rsp(s, 1);
+    g_assert(strcmp(args[1], "big") == 0 || strcmp(args[1], "little") == 0);
+    big_endian = strcmp(args[1], "big") == 0;
+    g_strfreev(args);
+
+    return big_endian;
+}
+
+typedef struct {
+    JSONMessageParser parser;
+    QDict *response;
+} QMPResponseParser;
+
+static void qmp_response(void *opaque, QObject *obj, Error *err)
+{
+    QMPResponseParser *qmp = opaque;
+
+    assert(!obj != !err);
+
+    if (err) {
+        error_prepend(&err, "QMP JSON response parsing failed: ");
+        error_report_err(err);
+        abort();
+    }
+
+    g_assert(!qmp->response);
+    qmp->response = qobject_to(QDict, obj);
+    g_assert(qmp->response);
+}
+
+QDict *qmp_fd_receive(int fd)
+{
+    QMPResponseParser qmp;
+    bool log = getenv("QTEST_LOG") != NULL;
+
+    qmp.response = NULL;
+    json_message_parser_init(&qmp.parser, qmp_response, &qmp, NULL);
+    while (!qmp.response) {
+        ssize_t len;
+        char c;
+
+        len = read(fd, &c, 1);
+        if (len == -1 && errno == EINTR) {
+            continue;
+        }
+
+        if (len == -1 || len == 0) {
+            fprintf(stderr, "Broken pipe\n");
+            abort();
+        }
+
+        if (log) {
+            len = write(2, &c, 1);
+        }
+        json_message_parser_feed(&qmp.parser, &c, 1);
+    }
+    json_message_parser_destroy(&qmp.parser);
+
+    return qmp.response;
+}
+
+QDict *qtest_qmp_receive(QTestState *s)
+{
+    return qmp_fd_receive(s->qmp_fd);
+}
+
+/**
+ * Allow users to send a message without waiting for the reply,
+ * in the case that they choose to discard all replies up until
+ * a particular EVENT is received.
+ */
+void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
+                      const char *fmt, va_list ap)
+{
+    QObject *qobj;
+
+    /* Going through qobject ensures we escape strings properly */
+    qobj = qobject_from_vjsonf_nofail(fmt, ap);
+
+    /* No need to send anything for an empty QObject.  */
+    if (qobj) {
+        int log = getenv("QTEST_LOG") != NULL;
+        QString *qstr = qobject_to_json(qobj);
+        const char *str;
+
+        /*
+         * BUG: QMP doesn't react to input until it sees a newline, an
+         * object, or an array.  Work-around: give it a newline.
+         */
+        qstring_append_chr(qstr, '\n');
+        str = qstring_get_str(qstr);
+
+        if (log) {
+            fprintf(stderr, "%s", str);
+        }
+        /* Send QMP request */
+        if (fds && fds_num > 0) {
+            socket_send_fds(fd, fds, fds_num, str, qstring_get_length(qstr));
+        } else {
+            socket_send(fd, str, qstring_get_length(qstr));
+        }
+
+        qobject_unref(qstr);
+        qobject_unref(qobj);
+    }
+}
+
+void qmp_fd_vsend(int fd, const char *fmt, va_list ap)
+{
+    qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap);
+}
+
+void qtest_qmp_vsend_fds(QTestState *s, int *fds, size_t fds_num,
+                         const char *fmt, va_list ap)
+{
+    qmp_fd_vsend_fds(s->qmp_fd, fds, fds_num, fmt, ap);
+}
+
+void qtest_qmp_vsend(QTestState *s, const char *fmt, va_list ap)
+{
+    qmp_fd_vsend_fds(s->qmp_fd, NULL, 0, fmt, ap);
+}
+
+QDict *qmp_fdv(int fd, const char *fmt, va_list ap)
+{
+    qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap);
+
+    return qmp_fd_receive(fd);
+}
+
+QDict *qtest_vqmp_fds(QTestState *s, int *fds, size_t fds_num,
+                      const char *fmt, va_list ap)
+{
+    qtest_qmp_vsend_fds(s, fds, fds_num, fmt, ap);
+
+    /* Receive reply */
+    return qtest_qmp_receive(s);
+}
+
+QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap)
+{
+    qtest_qmp_vsend(s, fmt, ap);
+
+    /* Receive reply */
+    return qtest_qmp_receive(s);
+}
+
+QDict *qmp_fd(int fd, const char *fmt, ...)
+{
+    va_list ap;
+    QDict *response;
+
+    va_start(ap, fmt);
+    response = qmp_fdv(fd, fmt, ap);
+    va_end(ap);
+    return response;
+}
+
+void qmp_fd_send(int fd, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    qmp_fd_vsend(fd, fmt, ap);
+    va_end(ap);
+}
+
+QDict *qtest_qmp_fds(QTestState *s, int *fds, size_t fds_num,
+                     const char *fmt, ...)
+{
+    va_list ap;
+    QDict *response;
+
+    va_start(ap, fmt);
+    response = qtest_vqmp_fds(s, fds, fds_num, fmt, ap);
+    va_end(ap);
+    return response;
+}
+
+QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
+{
+    va_list ap;
+    QDict *response;
+
+    va_start(ap, fmt);
+    response = qtest_vqmp(s, fmt, ap);
+    va_end(ap);
+    return response;
+}
+
+void qtest_qmp_send(QTestState *s, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    qtest_qmp_vsend(s, fmt, ap);
+    va_end(ap);
+}
+
+void qmp_fd_vsend_raw(int fd, const char *fmt, va_list ap)
+{
+    bool log = getenv("QTEST_LOG") != NULL;
+    char *str = g_strdup_vprintf(fmt, ap);
+
+    if (log) {
+        fprintf(stderr, "%s", str);
+    }
+    socket_send(fd, str, strlen(str));
+    g_free(str);
+}
+
+void qmp_fd_send_raw(int fd, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    qmp_fd_vsend_raw(fd, fmt, ap);
+    va_end(ap);
+}
+
+void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    qmp_fd_vsend_raw(s->qmp_fd, fmt, ap);
+    va_end(ap);
+}
+
+QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event)
+{
+    QDict *response;
+
+    for (;;) {
+        response = qtest_qmp_receive(s);
+        if ((qdict_haskey(response, "event")) &&
+            (strcmp(qdict_get_str(response, "event"), event) == 0)) {
+            return response;
+        }
+        qobject_unref(response);
+    }
+}
+
+void qtest_qmp_eventwait(QTestState *s, const char *event)
+{
+    QDict *response;
+
+    response = qtest_qmp_eventwait_ref(s, event);
+    qobject_unref(response);
+}
+
+char *qtest_vhmp(QTestState *s, const char *fmt, va_list ap)
+{
+    char *cmd;
+    QDict *resp;
+    char *ret;
+
+    cmd = g_strdup_vprintf(fmt, ap);
+    resp = qtest_qmp(s, "{'execute': 'human-monitor-command',"
+                     " 'arguments': {'command-line': %s}}",
+                     cmd);
+    ret = g_strdup(qdict_get_try_str(resp, "return"));
+    while (ret == NULL && qdict_get_try_str(resp, "event")) {
+        /* Ignore asynchronous QMP events */
+        qobject_unref(resp);
+        resp = qtest_qmp_receive(s);
+        ret = g_strdup(qdict_get_try_str(resp, "return"));
+    }
+    g_assert(ret);
+    qobject_unref(resp);
+    g_free(cmd);
+    return ret;
+}
+
+char *qtest_hmp(QTestState *s, const char *fmt, ...)
+{
+    va_list ap;
+    char *ret;
+
+    va_start(ap, fmt);
+    ret = qtest_vhmp(s, fmt, ap);
+    va_end(ap);
+    return ret;
+}
+
+const char *qtest_get_arch(void)
+{
+    const char *qemu = qtest_qemu_binary();
+    const char *end = strrchr(qemu, '/');
+
+    return end + strlen("/qemu-system-");
+}
+
+bool qtest_get_irq(QTestState *s, int num)
+{
+    /* dummy operation in order to make sure irq is up to date */
+    qtest_inb(s, 0);
+
+    return s->irq_level[num];
+}
+
+void qtest_module_load(QTestState *s, const char *prefix, const char *libname)
+{
+    qtest_sendf(s, "module_load %s %s\n", prefix, libname);
+    qtest_rsp(s, 0);
+}
+
+static int64_t qtest_clock_rsp(QTestState *s)
+{
+    gchar **words;
+    int64_t clock;
+    words = qtest_rsp(s, 2);
+    clock = g_ascii_strtoll(words[1], NULL, 0);
+    g_strfreev(words);
+    return clock;
+}
+
+int64_t qtest_clock_step_next(QTestState *s)
+{
+    qtest_sendf(s, "clock_step\n");
+    return qtest_clock_rsp(s);
+}
+
+int64_t qtest_clock_step(QTestState *s, int64_t step)
+{
+    qtest_sendf(s, "clock_step %"PRIi64"\n", step);
+    return qtest_clock_rsp(s);
+}
+
+int64_t qtest_clock_set(QTestState *s, int64_t val)
+{
+    qtest_sendf(s, "clock_set %"PRIi64"\n", val);
+    return qtest_clock_rsp(s);
+}
+
+void qtest_irq_intercept_out(QTestState *s, const char *qom_path)
+{
+    qtest_sendf(s, "irq_intercept_out %s\n", qom_path);
+    qtest_rsp(s, 0);
+}
+
+void qtest_irq_intercept_in(QTestState *s, const char *qom_path)
+{
+    qtest_sendf(s, "irq_intercept_in %s\n", qom_path);
+    qtest_rsp(s, 0);
+}
+
+void qtest_set_irq_in(QTestState *s, const char *qom_path, const char *name,
+                      int num, int level)
+{
+    if (!name) {
+        name = "unnamed-gpio-in";
+    }
+    qtest_sendf(s, "set_irq_in %s %s %d %d\n", qom_path, name, num, level);
+    qtest_rsp(s, 0);
+}
+
+static void qtest_out(QTestState *s, const char *cmd, uint16_t addr, uint32_t value)
+{
+    qtest_sendf(s, "%s 0x%x 0x%x\n", cmd, addr, value);
+    qtest_rsp(s, 0);
+}
+
+void qtest_outb(QTestState *s, uint16_t addr, uint8_t value)
+{
+    qtest_out(s, "outb", addr, value);
+}
+
+void qtest_outw(QTestState *s, uint16_t addr, uint16_t value)
+{
+    qtest_out(s, "outw", addr, value);
+}
+
+void qtest_outl(QTestState *s, uint16_t addr, uint32_t value)
+{
+    qtest_out(s, "outl", addr, value);
+}
+
+static uint32_t qtest_in(QTestState *s, const char *cmd, uint16_t addr)
+{
+    gchar **args;
+    int ret;
+    unsigned long value;
+
+    qtest_sendf(s, "%s 0x%x\n", cmd, addr);
+    args = qtest_rsp(s, 2);
+    ret = qemu_strtoul(args[1], NULL, 0, &value);
+    g_assert(!ret && value <= UINT32_MAX);
+    g_strfreev(args);
+
+    return value;
+}
+
+uint8_t qtest_inb(QTestState *s, uint16_t addr)
+{
+    return qtest_in(s, "inb", addr);
+}
+
+uint16_t qtest_inw(QTestState *s, uint16_t addr)
+{
+    return qtest_in(s, "inw", addr);
+}
+
+uint32_t qtest_inl(QTestState *s, uint16_t addr)
+{
+    return qtest_in(s, "inl", addr);
+}
+
+static void qtest_write(QTestState *s, const char *cmd, uint64_t addr,
+                        uint64_t value)
+{
+    qtest_sendf(s, "%s 0x%" PRIx64 " 0x%" PRIx64 "\n", cmd, addr, value);
+    qtest_rsp(s, 0);
+}
+
+void qtest_writeb(QTestState *s, uint64_t addr, uint8_t value)
+{
+    qtest_write(s, "writeb", addr, value);
+}
+
+void qtest_writew(QTestState *s, uint64_t addr, uint16_t value)
+{
+    qtest_write(s, "writew", addr, value);
+}
+
+void qtest_writel(QTestState *s, uint64_t addr, uint32_t value)
+{
+    qtest_write(s, "writel", addr, value);
+}
+
+void qtest_writeq(QTestState *s, uint64_t addr, uint64_t value)
+{
+    qtest_write(s, "writeq", addr, value);
+}
+
+static uint64_t qtest_read(QTestState *s, const char *cmd, uint64_t addr)
+{
+    gchar **args;
+    int ret;
+    uint64_t value;
+
+    qtest_sendf(s, "%s 0x%" PRIx64 "\n", cmd, addr);
+    args = qtest_rsp(s, 2);
+    ret = qemu_strtou64(args[1], NULL, 0, &value);
+    g_assert(!ret);
+    g_strfreev(args);
+
+    return value;
+}
+
+uint8_t qtest_readb(QTestState *s, uint64_t addr)
+{
+    return qtest_read(s, "readb", addr);
+}
+
+uint16_t qtest_readw(QTestState *s, uint64_t addr)
+{
+    return qtest_read(s, "readw", addr);
+}
+
+uint32_t qtest_readl(QTestState *s, uint64_t addr)
+{
+    return qtest_read(s, "readl", addr);
+}
+
+uint64_t qtest_readq(QTestState *s, uint64_t addr)
+{
+    return qtest_read(s, "readq", addr);
+}
+
+static int hex2nib(char ch)
+{
+    if (ch >= '0' && ch <= '9') {
+        return ch - '0';
+    } else if (ch >= 'a' && ch <= 'f') {
+        return 10 + (ch - 'a');
+    } else if (ch >= 'A' && ch <= 'F') {
+        return 10 + (ch - 'a');
+    } else {
+        return -1;
+    }
+}
+
+void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size)
+{
+    uint8_t *ptr = data;
+    gchar **args;
+    size_t i;
+
+    if (!size) {
+        return;
+    }
+
+    qtest_sendf(s, "read 0x%" PRIx64 " 0x%zx\n", addr, size);
+    args = qtest_rsp(s, 2);
+
+    for (i = 0; i < size; i++) {
+        ptr[i] = hex2nib(args[1][2 + (i * 2)]) << 4;
+        ptr[i] |= hex2nib(args[1][2 + (i * 2) + 1]);
+    }
+
+    g_strfreev(args);
+}
+
+uint64_t qtest_rtas_call(QTestState *s, const char *name,
+                         uint32_t nargs, uint64_t args,
+                         uint32_t nret, uint64_t ret)
+{
+    qtest_sendf(s, "rtas %s %u 0x%"PRIx64" %u 0x%"PRIx64"\n",
+                name, nargs, args, nret, ret);
+    qtest_rsp(s, 0);
+    return 0;
+}
+
+void qtest_add_func(const char *str, void (*fn)(void))
+{
+    gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
+    g_test_add_func(path, fn);
+    g_free(path);
+}
+
+void qtest_add_data_func_full(const char *str, void *data,
+                              void (*fn)(const void *),
+                              GDestroyNotify data_free_func)
+{
+    gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
+    g_test_add_data_func_full(path, data, fn, data_free_func);
+    g_free(path);
+}
+
+void qtest_add_data_func(const char *str, const void *data,
+                         void (*fn)(const void *))
+{
+    gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
+    g_test_add_data_func(path, data, fn);
+    g_free(path);
+}
+
+void qtest_bufwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
+{
+    gchar *bdata;
+
+    bdata = g_base64_encode(data, size);
+    qtest_sendf(s, "b64write 0x%" PRIx64 " 0x%zx ", addr, size);
+    socket_send(s->fd, bdata, strlen(bdata));
+    socket_send(s->fd, "\n", 1);
+    qtest_rsp(s, 0);
+    g_free(bdata);
+}
+
+void qtest_bufread(QTestState *s, uint64_t addr, void *data, size_t size)
+{
+    gchar **args;
+    size_t len;
+
+    qtest_sendf(s, "b64read 0x%" PRIx64 " 0x%zx\n", addr, size);
+    args = qtest_rsp(s, 2);
+
+    g_base64_decode_inplace(args[1], &len);
+    if (size != len) {
+        fprintf(stderr, "bufread: asked for %zu bytes but decoded %zu\n",
+                size, len);
+        len = MIN(len, size);
+    }
+
+    memcpy(data, args[1], len);
+    g_strfreev(args);
+}
+
+void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
+{
+    const uint8_t *ptr = data;
+    size_t i;
+    char *enc;
+
+    if (!size) {
+        return;
+    }
+
+    enc = g_malloc(2 * size + 1);
+
+    for (i = 0; i < size; i++) {
+        sprintf(&enc[i * 2], "%02x", ptr[i]);
+    }
+
+    qtest_sendf(s, "write 0x%" PRIx64 " 0x%zx 0x%s\n", addr, size, enc);
+    qtest_rsp(s, 0);
+    g_free(enc);
+}
+
+void qtest_memset(QTestState *s, uint64_t addr, uint8_t pattern, size_t size)
+{
+    qtest_sendf(s, "memset 0x%" PRIx64 " 0x%zx 0x%02x\n", addr, size, pattern);
+    qtest_rsp(s, 0);
+}
+
+void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
+{
+    va_list ap;
+    QDict *response;
+
+    va_start(ap, fmt);
+    response = qtest_vqmp(qts, fmt, ap);
+    va_end(ap);
+
+    g_assert(response);
+    if (!qdict_haskey(response, "return")) {
+        QString *s = qobject_to_json_pretty(QOBJECT(response));
+        g_test_message("%s", qstring_get_str(s));
+        qobject_unref(s);
+    }
+    g_assert(qdict_haskey(response, "return"));
+    qobject_unref(response);
+}
+
+bool qtest_big_endian(QTestState *s)
+{
+    return s->big_endian;
+}
+
+static bool qtest_check_machine_version(const char *mname, const char *basename,
+                                        int major, int minor)
+{
+    char *newname;
+    bool is_equal;
+
+    newname = g_strdup_printf("%s-%i.%i", basename, major, minor);
+    is_equal = g_str_equal(mname, newname);
+    g_free(newname);
+
+    return is_equal;
+}
+
+static bool qtest_is_old_versioned_machine(const char *mname)
+{
+    const char *dash = strrchr(mname, '-');
+    const char *dot = strrchr(mname, '.');
+    const char *chr;
+    char *bname;
+    const int major = QEMU_VERSION_MAJOR;
+    const int minor = QEMU_VERSION_MINOR;
+    bool res = false;
+
+    if (dash && dot && dot > dash) {
+        for (chr = dash + 1; *chr; chr++) {
+            if (!qemu_isdigit(*chr) && *chr != '.') {
+                return false;
+            }
+        }
+        /*
+         * Now check if it is one of the latest versions. Check major + 1
+         * and minor + 1 versions as well, since they might already exist
+         * in the development branch.
+         */
+        bname = g_strdup(mname);
+        bname[dash - mname] = 0;
+        res = !qtest_check_machine_version(mname, bname, major + 1, 0) &&
+              !qtest_check_machine_version(mname, bname, major, minor + 1) &&
+              !qtest_check_machine_version(mname, bname, major, minor);
+        g_free(bname);
+    }
+
+    return res;
+}
+
+void qtest_cb_for_every_machine(void (*cb)(const char *machine),
+                                bool skip_old_versioned)
+{
+    QDict *response, *minfo;
+    QList *list;
+    const QListEntry *p;
+    QObject *qobj;
+    QString *qstr;
+    const char *mname;
+    QTestState *qts;
+
+    qts = qtest_init("-machine none");
+    response = qtest_qmp(qts, "{ 'execute': 'query-machines' }");
+    g_assert(response);
+    list = qdict_get_qlist(response, "return");
+    g_assert(list);
+
+    for (p = qlist_first(list); p; p = qlist_next(p)) {
+        minfo = qobject_to(QDict, qlist_entry_obj(p));
+        g_assert(minfo);
+        qobj = qdict_get(minfo, "name");
+        g_assert(qobj);
+        qstr = qobject_to(QString, qobj);
+        g_assert(qstr);
+        mname = qstring_get_str(qstr);
+        if (!skip_old_versioned || !qtest_is_old_versioned_machine(mname)) {
+            cb(mname);
+        }
+    }
+
+    qtest_quit(qts);
+    qobject_unref(response);
+}
+
+QDict *qtest_qmp_receive_success(QTestState *s,
+                                 void (*event_cb)(void *opaque,
+                                                  const char *event,
+                                                  QDict *data),
+                                 void *opaque)
+{
+    QDict *response, *ret, *data;
+    const char *event;
+
+    for (;;) {
+        response = qtest_qmp_receive(s);
+        g_assert(!qdict_haskey(response, "error"));
+        ret = qdict_get_qdict(response, "return");
+        if (ret) {
+            break;
+        }
+        event = qdict_get_str(response, "event");
+        data = qdict_get_qdict(response, "data");
+        if (event_cb) {
+            event_cb(opaque, event, data);
+        }
+        qobject_unref(response);
+    }
+
+    qobject_ref(ret);
+    qobject_unref(response);
+    return ret;
+}
+
+/*
+ * Generic hot-plugging test via the device_add QMP commands.
+ */
+void qtest_qmp_device_add_qdict(QTestState *qts, const char *drv,
+                                const QDict *arguments)
+{
+    QDict *resp;
+    QDict *args = arguments ? qdict_clone_shallow(arguments) : qdict_new();
+
+    g_assert(!qdict_haskey(args, "driver"));
+    qdict_put_str(args, "driver", drv);
+    resp = qtest_qmp(qts, "{'execute': 'device_add', 'arguments': %p}", args);
+    g_assert(resp);
+    g_assert(!qdict_haskey(resp, "event")); /* We don't expect any events */
+    g_assert(!qdict_haskey(resp, "error"));
+    qobject_unref(resp);
+}
+
+void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id,
+                          const char *fmt, ...)
+{
+    QDict *args;
+    va_list ap;
+
+    va_start(ap, fmt);
+    args = qdict_from_vjsonf_nofail(fmt, ap);
+    va_end(ap);
+
+    g_assert(!qdict_haskey(args, "id"));
+    qdict_put_str(args, "id", id);
+
+    qtest_qmp_device_add_qdict(qts, driver, args);
+    qobject_unref(args);
+}
+
+static void device_deleted_cb(void *opaque, const char *name, QDict *data)
+{
+    bool *got_event = opaque;
+
+    g_assert_cmpstr(name, ==, "DEVICE_DELETED");
+    *got_event = true;
+}
+
+/*
+ * Generic hot-unplugging test via the device_del QMP command.
+ * Device deletion will get one response and one event. For example:
+ *
+ * {'execute': 'device_del','arguments': { 'id': 'scsi-hd'}}
+ *
+ * will get this one:
+ *
+ * {"timestamp": {"seconds": 1505289667, "microseconds": 569862},
+ *  "event": "DEVICE_DELETED", "data": {"device": "scsi-hd",
+ *  "path": "/machine/peripheral/scsi-hd"}}
+ *
+ * and this one:
+ *
+ * {"return": {}}
+ *
+ * But the order of arrival may vary - so we've got to detect both.
+ */
+void qtest_qmp_device_del(QTestState *qts, const char *id)
+{
+    bool got_event = false;
+    QDict *rsp;
+
+    qtest_qmp_send(qts, "{'execute': 'device_del', 'arguments': {'id': %s}}",
+                   id);
+    rsp = qtest_qmp_receive_success(qts, device_deleted_cb, &got_event);
+    qobject_unref(rsp);
+    if (!got_event) {
+        rsp = qtest_qmp_receive(qts);
+        g_assert_cmpstr(qdict_get_try_str(rsp, "event"),
+                        ==, "DEVICE_DELETED");
+        qobject_unref(rsp);
+    }
+}
+
+bool qmp_rsp_is_err(QDict *rsp)
+{
+    QDict *error = qdict_get_qdict(rsp, "error");
+    qobject_unref(rsp);
+    return !!error;
+}
+
+void qmp_assert_error_class(QDict *rsp, const char *class)
+{
+    QDict *error = qdict_get_qdict(rsp, "error");
+
+    g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, class);
+    g_assert_nonnull(qdict_get_try_str(error, "desc"));
+    g_assert(!qdict_haskey(rsp, "return"));
+
+    qobject_unref(rsp);
+}
diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
new file mode 100644 (file)
index 0000000..c9e21e0
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * QTest
+ *
+ * Copyright IBM, Corp. 2012
+ * Copyright Red Hat, Inc. 2012
+ * Copyright SUSE LINUX Products GmbH 2013
+ *
+ * Authors:
+ *  Anthony Liguori   <[email protected]>
+ *  Paolo Bonzini     <[email protected]>
+ *  Andreas Färber    <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#ifndef LIBQTEST_H
+#define LIBQTEST_H
+
+#include "qapi/qmp/qobject.h"
+#include "qapi/qmp/qdict.h"
+
+typedef struct QTestState QTestState;
+
+/**
+ * qtest_initf:
+ * @fmt...: Format for creating other arguments to pass to QEMU, formatted
+ * like sprintf().
+ *
+ * Convenience wrapper around qtest_init().
+ *
+ * Returns: #QTestState instance.
+ */
+QTestState *qtest_initf(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+
+/**
+ * qtest_vinitf:
+ * @fmt: Format for creating other arguments to pass to QEMU, formatted
+ * like vsprintf().
+ * @ap: Format arguments.
+ *
+ * Convenience wrapper around qtest_init().
+ *
+ * Returns: #QTestState instance.
+ */
+QTestState *qtest_vinitf(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0);
+
+/**
+ * qtest_init:
+ * @extra_args: other arguments to pass to QEMU.  CAUTION: these
+ * arguments are subject to word splitting and shell evaluation.
+ *
+ * Returns: #QTestState instance.
+ */
+QTestState *qtest_init(const char *extra_args);
+
+/**
+ * qtest_init_without_qmp_handshake:
+ * @extra_args: other arguments to pass to QEMU.  CAUTION: these
+ * arguments are subject to word splitting and shell evaluation.
+ *
+ * Returns: #QTestState instance.
+ */
+QTestState *qtest_init_without_qmp_handshake(const char *extra_args);
+
+/**
+ * qtest_init_with_serial:
+ * @extra_args: other arguments to pass to QEMU.  CAUTION: these
+ * arguments are subject to word splitting and shell evaluation.
+ * @sock_fd: pointer to store the socket file descriptor for
+ * connection with serial.
+ *
+ * Returns: #QTestState instance.
+ */
+QTestState *qtest_init_with_serial(const char *extra_args, int *sock_fd);
+
+/**
+ * qtest_quit:
+ * @s: #QTestState instance to operate on.
+ *
+ * Shut down the QEMU process associated to @s.
+ */
+void qtest_quit(QTestState *s);
+
+/**
+ * qtest_qmp_fds:
+ * @s: #QTestState instance to operate on.
+ * @fds: array of file descriptors
+ * @fds_num: number of elements in @fds
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf_nofail().  See parse_escape() for what's
+ * supported after '%'.
+ *
+ * Sends a QMP message to QEMU with fds and returns the response.
+ */
+QDict *qtest_qmp_fds(QTestState *s, int *fds, size_t fds_num,
+                     const char *fmt, ...)
+    GCC_FMT_ATTR(4, 5);
+
+/**
+ * qtest_qmp:
+ * @s: #QTestState instance to operate on.
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf_nofail().  See parse_escape() for what's
+ * supported after '%'.
+ *
+ * Sends a QMP message to QEMU and returns the response.
+ */
+QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
+
+/**
+ * qtest_qmp_send:
+ * @s: #QTestState instance to operate on.
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf_nofail().  See parse_escape() for what's
+ * supported after '%'.
+ *
+ * Sends a QMP message to QEMU and leaves the response in the stream.
+ */
+void qtest_qmp_send(QTestState *s, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
+
+/**
+ * qtest_qmp_send_raw:
+ * @s: #QTestState instance to operate on.
+ * @fmt...: text to send, formatted like sprintf()
+ *
+ * Sends text to the QMP monitor verbatim.  Need not be valid JSON;
+ * this is useful for negative tests.
+ */
+void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
+
+/**
+ * qtest_vqmp_fds:
+ * @s: #QTestState instance to operate on.
+ * @fds: array of file descriptors
+ * @fds_num: number of elements in @fds
+ * @fmt: QMP message to send to QEMU, formatted like
+ * qobject_from_jsonf_nofail().  See parse_escape() for what's
+ * supported after '%'.
+ * @ap: QMP message arguments
+ *
+ * Sends a QMP message to QEMU with fds and returns the response.
+ */
+QDict *qtest_vqmp_fds(QTestState *s, int *fds, size_t fds_num,
+                      const char *fmt, va_list ap)
+    GCC_FMT_ATTR(4, 0);
+
+/**
+ * qtest_vqmp:
+ * @s: #QTestState instance to operate on.
+ * @fmt: QMP message to send to QEMU, formatted like
+ * qobject_from_jsonf_nofail().  See parse_escape() for what's
+ * supported after '%'.
+ * @ap: QMP message arguments
+ *
+ * Sends a QMP message to QEMU and returns the response.
+ */
+QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap)
+    GCC_FMT_ATTR(2, 0);
+
+/**
+ * qtest_qmp_vsend_fds:
+ * @s: #QTestState instance to operate on.
+ * @fds: array of file descriptors
+ * @fds_num: number of elements in @fds
+ * @fmt: QMP message to send to QEMU, formatted like
+ * qobject_from_jsonf_nofail().  See parse_escape() for what's
+ * supported after '%'.
+ * @ap: QMP message arguments
+ *
+ * Sends a QMP message to QEMU and leaves the response in the stream.
+ */
+void qtest_qmp_vsend_fds(QTestState *s, int *fds, size_t fds_num,
+                         const char *fmt, va_list ap)
+    GCC_FMT_ATTR(4, 0);
+
+/**
+ * qtest_qmp_vsend:
+ * @s: #QTestState instance to operate on.
+ * @fmt: QMP message to send to QEMU, formatted like
+ * qobject_from_jsonf_nofail().  See parse_escape() for what's
+ * supported after '%'.
+ * @ap: QMP message arguments
+ *
+ * Sends a QMP message to QEMU and leaves the response in the stream.
+ */
+void qtest_qmp_vsend(QTestState *s, const char *fmt, va_list ap)
+    GCC_FMT_ATTR(2, 0);
+
+/**
+ * qtest_receive:
+ * @s: #QTestState instance to operate on.
+ *
+ * Reads a QMP message from QEMU and returns the response.
+ */
+QDict *qtest_qmp_receive(QTestState *s);
+
+/**
+ * qtest_qmp_eventwait:
+ * @s: #QTestState instance to operate on.
+ * @s: #event event to wait for.
+ *
+ * Continuously polls for QMP responses until it receives the desired event.
+ */
+void qtest_qmp_eventwait(QTestState *s, const char *event);
+
+/**
+ * qtest_qmp_eventwait_ref:
+ * @s: #QTestState instance to operate on.
+ * @s: #event event to wait for.
+ *
+ * Continuously polls for QMP responses until it receives the desired event.
+ * Returns a copy of the event for further investigation.
+ */
+QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event);
+
+/**
+ * qtest_qmp_receive_success:
+ * @s: #QTestState instance to operate on
+ * @event_cb: Event callback
+ * @opaque: Argument for @event_cb
+ *
+ * Poll QMP messages until a command success response is received.
+ * If @event_cb, call it for each event received, passing @opaque,
+ * the event's name and data.
+ * Return the success response's "return" member.
+ */
+QDict *qtest_qmp_receive_success(QTestState *s,
+                                 void (*event_cb)(void *opaque,
+                                                  const char *name,
+                                                  QDict *data),
+                                 void *opaque);
+
+/**
+ * qtest_hmp:
+ * @s: #QTestState instance to operate on.
+ * @fmt...: HMP command to send to QEMU, formats arguments like sprintf().
+ *
+ * Send HMP command to QEMU via QMP's human-monitor-command.
+ * QMP events are discarded.
+ *
+ * Returns: the command's output.  The caller should g_free() it.
+ */
+char *qtest_hmp(QTestState *s, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+
+/**
+ * qtest_hmpv:
+ * @s: #QTestState instance to operate on.
+ * @fmt: HMP command to send to QEMU, formats arguments like vsprintf().
+ * @ap: HMP command arguments
+ *
+ * Send HMP command to QEMU via QMP's human-monitor-command.
+ * QMP events are discarded.
+ *
+ * Returns: the command's output.  The caller should g_free() it.
+ */
+char *qtest_vhmp(QTestState *s, const char *fmt, va_list ap)
+    GCC_FMT_ATTR(2, 0);
+
+void qtest_module_load(QTestState *s, const char *prefix, const char *libname);
+
+/**
+ * qtest_get_irq:
+ * @s: #QTestState instance to operate on.
+ * @num: Interrupt to observe.
+ *
+ * Returns: The level of the @num interrupt.
+ */
+bool qtest_get_irq(QTestState *s, int num);
+
+/**
+ * qtest_irq_intercept_in:
+ * @s: #QTestState instance to operate on.
+ * @string: QOM path of a device.
+ *
+ * Associate qtest irqs with the GPIO-in pins of the device
+ * whose path is specified by @string.
+ */
+void qtest_irq_intercept_in(QTestState *s, const char *string);
+
+/**
+ * qtest_irq_intercept_out:
+ * @s: #QTestState instance to operate on.
+ * @string: QOM path of a device.
+ *
+ * Associate qtest irqs with the GPIO-out pins of the device
+ * whose path is specified by @string.
+ */
+void qtest_irq_intercept_out(QTestState *s, const char *string);
+
+/**
+ * qtest_set_irq_in:
+ * @s: QTestState instance to operate on.
+ * @string: QOM path of a device
+ * @name: IRQ name
+ * @irq: IRQ number
+ * @level: IRQ level
+ *
+ * Force given device/irq GPIO-in pin to the given level.
+ */
+void qtest_set_irq_in(QTestState *s, const char *string, const char *name,
+                      int irq, int level);
+
+/**
+ * qtest_outb:
+ * @s: #QTestState instance to operate on.
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write an 8-bit value to an I/O port.
+ */
+void qtest_outb(QTestState *s, uint16_t addr, uint8_t value);
+
+/**
+ * qtest_outw:
+ * @s: #QTestState instance to operate on.
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 16-bit value to an I/O port.
+ */
+void qtest_outw(QTestState *s, uint16_t addr, uint16_t value);
+
+/**
+ * qtest_outl:
+ * @s: #QTestState instance to operate on.
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 32-bit value to an I/O port.
+ */
+void qtest_outl(QTestState *s, uint16_t addr, uint32_t value);
+
+/**
+ * qtest_inb:
+ * @s: #QTestState instance to operate on.
+ * @addr: I/O port to read from.
+ *
+ * Returns an 8-bit value from an I/O port.
+ */
+uint8_t qtest_inb(QTestState *s, uint16_t addr);
+
+/**
+ * qtest_inw:
+ * @s: #QTestState instance to operate on.
+ * @addr: I/O port to read from.
+ *
+ * Returns a 16-bit value from an I/O port.
+ */
+uint16_t qtest_inw(QTestState *s, uint16_t addr);
+
+/**
+ * qtest_inl:
+ * @s: #QTestState instance to operate on.
+ * @addr: I/O port to read from.
+ *
+ * Returns a 32-bit value from an I/O port.
+ */
+uint32_t qtest_inl(QTestState *s, uint16_t addr);
+
+/**
+ * qtest_writeb:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes an 8-bit value to memory.
+ */
+void qtest_writeb(QTestState *s, uint64_t addr, uint8_t value);
+
+/**
+ * qtest_writew:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 16-bit value to memory.
+ */
+void qtest_writew(QTestState *s, uint64_t addr, uint16_t value);
+
+/**
+ * qtest_writel:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 32-bit value to memory.
+ */
+void qtest_writel(QTestState *s, uint64_t addr, uint32_t value);
+
+/**
+ * qtest_writeq:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 64-bit value to memory.
+ */
+void qtest_writeq(QTestState *s, uint64_t addr, uint64_t value);
+
+/**
+ * qtest_readb:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to read from.
+ *
+ * Reads an 8-bit value from memory.
+ *
+ * Returns: Value read.
+ */
+uint8_t qtest_readb(QTestState *s, uint64_t addr);
+
+/**
+ * qtest_readw:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to read from.
+ *
+ * Reads a 16-bit value from memory.
+ *
+ * Returns: Value read.
+ */
+uint16_t qtest_readw(QTestState *s, uint64_t addr);
+
+/**
+ * qtest_readl:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to read from.
+ *
+ * Reads a 32-bit value from memory.
+ *
+ * Returns: Value read.
+ */
+uint32_t qtest_readl(QTestState *s, uint64_t addr);
+
+/**
+ * qtest_readq:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to read from.
+ *
+ * Reads a 64-bit value from memory.
+ *
+ * Returns: Value read.
+ */
+uint64_t qtest_readq(QTestState *s, uint64_t addr);
+
+/**
+ * qtest_memread:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to read from.
+ * @data: Pointer to where memory contents will be stored.
+ * @size: Number of bytes to read.
+ *
+ * Read guest memory into a buffer.
+ */
+void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
+
+/**
+ * qtest_rtas_call:
+ * @s: #QTestState instance to operate on.
+ * @name: name of the command to call.
+ * @nargs: Number of args.
+ * @args: Guest address to read args from.
+ * @nret: Number of return value.
+ * @ret: Guest address to write return values to.
+ *
+ * Call an RTAS function
+ */
+uint64_t qtest_rtas_call(QTestState *s, const char *name,
+                         uint32_t nargs, uint64_t args,
+                         uint32_t nret, uint64_t ret);
+
+/**
+ * qtest_bufread:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to read from.
+ * @data: Pointer to where memory contents will be stored.
+ * @size: Number of bytes to read.
+ *
+ * Read guest memory into a buffer and receive using a base64 encoding.
+ */
+void qtest_bufread(QTestState *s, uint64_t addr, void *data, size_t size);
+
+/**
+ * qtest_memwrite:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @data: Pointer to the bytes that will be written to guest memory.
+ * @size: Number of bytes to write.
+ *
+ * Write a buffer to guest memory.
+ */
+void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size);
+
+/**
+ * qtest_bufwrite:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @data: Pointer to the bytes that will be written to guest memory.
+ * @size: Number of bytes to write.
+ *
+ * Write a buffer to guest memory and transmit using a base64 encoding.
+ */
+void qtest_bufwrite(QTestState *s, uint64_t addr,
+                    const void *data, size_t size);
+
+/**
+ * qtest_memset:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @patt: Byte pattern to fill the guest memory region with.
+ * @size: Number of bytes to write.
+ *
+ * Write a pattern to guest memory.
+ */
+void qtest_memset(QTestState *s, uint64_t addr, uint8_t patt, size_t size);
+
+/**
+ * qtest_clock_step_next:
+ * @s: #QTestState instance to operate on.
+ *
+ * Advance the QEMU_CLOCK_VIRTUAL to the next deadline.
+ *
+ * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
+ */
+int64_t qtest_clock_step_next(QTestState *s);
+
+/**
+ * qtest_clock_step:
+ * @s: QTestState instance to operate on.
+ * @step: Number of nanoseconds to advance the clock by.
+ *
+ * Advance the QEMU_CLOCK_VIRTUAL by @step nanoseconds.
+ *
+ * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
+ */
+int64_t qtest_clock_step(QTestState *s, int64_t step);
+
+/**
+ * qtest_clock_set:
+ * @s: QTestState instance to operate on.
+ * @val: Nanoseconds value to advance the clock to.
+ *
+ * Advance the QEMU_CLOCK_VIRTUAL to @val nanoseconds since the VM was launched.
+ *
+ * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
+ */
+int64_t qtest_clock_set(QTestState *s, int64_t val);
+
+/**
+ * qtest_big_endian:
+ * @s: QTestState instance to operate on.
+ *
+ * Returns: True if the architecture under test has a big endian configuration.
+ */
+bool qtest_big_endian(QTestState *s);
+
+/**
+ * qtest_get_arch:
+ *
+ * Returns: The architecture for the QEMU executable under test.
+ */
+const char *qtest_get_arch(void);
+
+/**
+ * qtest_add_func:
+ * @str: Test case path.
+ * @fn: Test case function
+ *
+ * Add a GTester testcase with the given name and function.
+ * The path is prefixed with the architecture under test, as
+ * returned by qtest_get_arch().
+ */
+void qtest_add_func(const char *str, void (*fn)(void));
+
+/**
+ * qtest_add_data_func:
+ * @str: Test case path.
+ * @data: Test case data
+ * @fn: Test case function
+ *
+ * Add a GTester testcase with the given name, data and function.
+ * The path is prefixed with the architecture under test, as
+ * returned by qtest_get_arch().
+ */
+void qtest_add_data_func(const char *str, const void *data,
+                         void (*fn)(const void *));
+
+/**
+ * qtest_add_data_func_full:
+ * @str: Test case path.
+ * @data: Test case data
+ * @fn: Test case function
+ * @data_free_func: GDestroyNotify for data
+ *
+ * Add a GTester testcase with the given name, data and function.
+ * The path is prefixed with the architecture under test, as
+ * returned by qtest_get_arch().
+ *
+ * @data is passed to @data_free_func() on test completion.
+ */
+void qtest_add_data_func_full(const char *str, void *data,
+                              void (*fn)(const void *),
+                              GDestroyNotify data_free_func);
+
+/**
+ * qtest_add:
+ * @testpath: Test case path
+ * @Fixture: Fixture type
+ * @tdata: Test case data
+ * @fsetup: Test case setup function
+ * @ftest: Test case function
+ * @fteardown: Test case teardown function
+ *
+ * Add a GTester testcase with the given name, data and functions.
+ * The path is prefixed with the architecture under test, as
+ * returned by qtest_get_arch().
+ */
+#define qtest_add(testpath, Fixture, tdata, fsetup, ftest, fteardown) \
+    do { \
+        char *path = g_strdup_printf("/%s/%s", qtest_get_arch(), testpath); \
+        g_test_add(path, Fixture, tdata, fsetup, ftest, fteardown); \
+        g_free(path); \
+    } while (0)
+
+void qtest_add_abrt_handler(GHookFunc fn, const void *data);
+
+/**
+ * qtest_qmp_assert_success:
+ * @qts: QTestState instance to operate on
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf_nofail().  See parse_escape() for what's
+ * supported after '%'.
+ *
+ * Sends a QMP message to QEMU and asserts that a 'return' key is present in
+ * the response.
+ */
+void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
+
+QDict *qmp_fd_receive(int fd);
+void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
+                      const char *fmt, va_list ap) GCC_FMT_ATTR(4, 0);
+void qmp_fd_vsend(int fd, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
+void qmp_fd_send(int fd, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+void qmp_fd_send_raw(int fd, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+void qmp_fd_vsend_raw(int fd, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
+QDict *qmp_fdv(int fd, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
+QDict *qmp_fd(int fd, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+
+/**
+ * qtest_cb_for_every_machine:
+ * @cb: Pointer to the callback function
+ * @skip_old_versioned: true if versioned old machine types should be skipped
+ *
+ *  Call a callback function for every name of all available machines.
+ */
+void qtest_cb_for_every_machine(void (*cb)(const char *machine),
+                                bool skip_old_versioned);
+
+/**
+ * qtest_qmp_device_add_qdict:
+ * @qts: QTestState instance to operate on
+ * @drv: Name of the device that should be added
+ * @arguments: QDict with properties for the device to intialize
+ *
+ * Generic hot-plugging test via the device_add QMP command with properties
+ * supplied in form of QDict. Use NULL for empty properties list.
+ */
+void qtest_qmp_device_add_qdict(QTestState *qts, const char *drv,
+                                const QDict *arguments);
+
+/**
+ * qtest_qmp_device_add:
+ * @qts: QTestState instance to operate on
+ * @driver: Name of the device that should be added
+ * @id: Identification string
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf_nofail().  See parse_escape() for what's
+ * supported after '%'.
+ *
+ * Generic hot-plugging test via the device_add QMP command.
+ */
+void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id,
+                          const char *fmt, ...) GCC_FMT_ATTR(4, 5);
+
+/**
+ * qtest_qmp_device_del:
+ * @qts: QTestState instance to operate on
+ * @id: Identification string
+ *
+ * Generic hot-unplugging test via the device_del QMP command.
+ */
+void qtest_qmp_device_del(QTestState *qts, const char *id);
+
+/**
+ * qmp_rsp_is_err:
+ * @rsp: QMP response to check for error
+ *
+ * Test @rsp for error and discard @rsp.
+ * Returns 'true' if there is error in @rsp and 'false' otherwise.
+ */
+bool qmp_rsp_is_err(QDict *rsp);
+
+/**
+ * qmp_assert_error_class:
+ * @rsp: QMP response to check for error
+ * @class: an error class
+ *
+ * Assert the response has the given error class and discard @rsp.
+ */
+void qmp_assert_error_class(QDict *rsp, const char *class);
+
+/**
+ * qtest_probe_child:
+ * @s: QTestState instance to operate on.
+ *
+ * Returns: true if the child is still alive.
+ */
+bool qtest_probe_child(QTestState *s);
+
+/**
+ * qtest_set_expected_status:
+ * @s: QTestState instance to operate on.
+ * @status: an expected exit status.
+ *
+ * Set expected exit status of the child.
+ */
+void qtest_set_expected_status(QTestState *s, int status);
+
+#endif
diff --git a/tests/qtest/m25p80-test.c b/tests/qtest/m25p80-test.c
new file mode 100644 (file)
index 0000000..50c6b79
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * QTest testcase for the M25P80 Flash (Using the Aspeed SPI
+ * Controller)
+ *
+ * Copyright (C) 2016 IBM Corp.
+ *
+ * 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 "qemu/bswap.h"
+#include "libqtest-single.h"
+
+/*
+ * ASPEED SPI Controller registers
+ */
+#define R_CONF              0x00
+#define   CONF_ENABLE_W0       (1 << 16)
+#define R_CE_CTRL           0x04
+#define   CRTL_EXTENDED0       0  /* 32 bit addressing for SPI */
+#define R_CTRL0             0x10
+#define   CTRL_CE_STOP_ACTIVE  (1 << 2)
+#define   CTRL_READMODE        0x0
+#define   CTRL_FREADMODE       0x1
+#define   CTRL_WRITEMODE       0x2
+#define   CTRL_USERMODE        0x3
+
+#define ASPEED_FMC_BASE    0x1E620000
+#define ASPEED_FLASH_BASE  0x20000000
+
+/*
+ * Flash commands
+ */
+enum {
+    JEDEC_READ = 0x9f,
+    BULK_ERASE = 0xc7,
+    READ = 0x03,
+    PP = 0x02,
+    WREN = 0x6,
+    RESET_ENABLE = 0x66,
+    RESET_MEMORY = 0x99,
+    EN_4BYTE_ADDR = 0xB7,
+    ERASE_SECTOR = 0xd8,
+};
+
+#define FLASH_JEDEC         0x20ba19  /* n25q256a */
+#define FLASH_SIZE          (32 * 1024 * 1024)
+
+#define PAGE_SIZE           256
+
+/*
+ * Use an explicit bswap for the values read/wrote to the flash region
+ * as they are BE and the Aspeed CPU is LE.
+ */
+static inline uint32_t make_be32(uint32_t data)
+{
+    return bswap32(data);
+}
+
+static void spi_conf(uint32_t value)
+{
+    uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
+
+    conf |= value;
+    writel(ASPEED_FMC_BASE + R_CONF, conf);
+}
+
+static void spi_conf_remove(uint32_t value)
+{
+    uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
+
+    conf &= ~value;
+    writel(ASPEED_FMC_BASE + R_CONF, conf);
+}
+
+static void spi_ce_ctrl(uint32_t value)
+{
+    uint32_t conf = readl(ASPEED_FMC_BASE + R_CE_CTRL);
+
+    conf |= value;
+    writel(ASPEED_FMC_BASE + R_CE_CTRL, conf);
+}
+
+static void spi_ctrl_setmode(uint8_t mode, uint8_t cmd)
+{
+    uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
+    ctrl &= ~(CTRL_USERMODE | 0xff << 16);
+    ctrl |= mode | (cmd << 16);
+    writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
+}
+
+static void spi_ctrl_start_user(void)
+{
+    uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
+
+    ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
+    writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
+
+    ctrl &= ~CTRL_CE_STOP_ACTIVE;
+    writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
+}
+
+static void spi_ctrl_stop_user(void)
+{
+    uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
+
+    ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
+    writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
+}
+
+static void flash_reset(void)
+{
+    spi_conf(CONF_ENABLE_W0);
+
+    spi_ctrl_start_user();
+    writeb(ASPEED_FLASH_BASE, RESET_ENABLE);
+    writeb(ASPEED_FLASH_BASE, RESET_MEMORY);
+    spi_ctrl_stop_user();
+
+    spi_conf_remove(CONF_ENABLE_W0);
+}
+
+static void test_read_jedec(void)
+{
+    uint32_t jedec = 0x0;
+
+    spi_conf(CONF_ENABLE_W0);
+
+    spi_ctrl_start_user();
+    writeb(ASPEED_FLASH_BASE, JEDEC_READ);
+    jedec |= readb(ASPEED_FLASH_BASE) << 16;
+    jedec |= readb(ASPEED_FLASH_BASE) << 8;
+    jedec |= readb(ASPEED_FLASH_BASE);
+    spi_ctrl_stop_user();
+
+    flash_reset();
+
+    g_assert_cmphex(jedec, ==, FLASH_JEDEC);
+}
+
+static void read_page(uint32_t addr, uint32_t *page)
+{
+    int i;
+
+    spi_ctrl_start_user();
+
+    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
+    writeb(ASPEED_FLASH_BASE, READ);
+    writel(ASPEED_FLASH_BASE, make_be32(addr));
+
+    /* Continuous read are supported */
+    for (i = 0; i < PAGE_SIZE / 4; i++) {
+        page[i] = make_be32(readl(ASPEED_FLASH_BASE));
+    }
+    spi_ctrl_stop_user();
+}
+
+static void read_page_mem(uint32_t addr, uint32_t *page)
+{
+    int i;
+
+    /* move out USER mode to use direct reads from the AHB bus */
+    spi_ctrl_setmode(CTRL_READMODE, READ);
+
+    for (i = 0; i < PAGE_SIZE / 4; i++) {
+        page[i] = make_be32(readl(ASPEED_FLASH_BASE + addr + i * 4));
+    }
+}
+
+static void test_erase_sector(void)
+{
+    uint32_t some_page_addr = 0x600 * PAGE_SIZE;
+    uint32_t page[PAGE_SIZE / 4];
+    int i;
+
+    spi_conf(CONF_ENABLE_W0);
+
+    spi_ctrl_start_user();
+    writeb(ASPEED_FLASH_BASE, WREN);
+    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
+    writeb(ASPEED_FLASH_BASE, ERASE_SECTOR);
+    writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
+    spi_ctrl_stop_user();
+
+    /* Previous page should be full of zeroes as backend is not
+     * initialized */
+    read_page(some_page_addr - PAGE_SIZE, page);
+    for (i = 0; i < PAGE_SIZE / 4; i++) {
+        g_assert_cmphex(page[i], ==, 0x0);
+    }
+
+    /* But this one was erased */
+    read_page(some_page_addr, page);
+    for (i = 0; i < PAGE_SIZE / 4; i++) {
+        g_assert_cmphex(page[i], ==, 0xffffffff);
+    }
+
+    flash_reset();
+}
+
+static void test_erase_all(void)
+{
+    uint32_t some_page_addr = 0x15000 * PAGE_SIZE;
+    uint32_t page[PAGE_SIZE / 4];
+    int i;
+
+    spi_conf(CONF_ENABLE_W0);
+
+    /* Check some random page. Should be full of zeroes as backend is
+     * not initialized */
+    read_page(some_page_addr, page);
+    for (i = 0; i < PAGE_SIZE / 4; i++) {
+        g_assert_cmphex(page[i], ==, 0x0);
+    }
+
+    spi_ctrl_start_user();
+    writeb(ASPEED_FLASH_BASE, WREN);
+    writeb(ASPEED_FLASH_BASE, BULK_ERASE);
+    spi_ctrl_stop_user();
+
+    /* Recheck that some random page */
+    read_page(some_page_addr, page);
+    for (i = 0; i < PAGE_SIZE / 4; i++) {
+        g_assert_cmphex(page[i], ==, 0xffffffff);
+    }
+
+    flash_reset();
+}
+
+static void test_write_page(void)
+{
+    uint32_t my_page_addr = 0x14000 * PAGE_SIZE; /* beyond 16MB */
+    uint32_t some_page_addr = 0x15000 * PAGE_SIZE;
+    uint32_t page[PAGE_SIZE / 4];
+    int i;
+
+    spi_conf(CONF_ENABLE_W0);
+
+    spi_ctrl_start_user();
+    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
+    writeb(ASPEED_FLASH_BASE, WREN);
+    writeb(ASPEED_FLASH_BASE, PP);
+    writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
+
+    /* Fill the page with its own addresses */
+    for (i = 0; i < PAGE_SIZE / 4; i++) {
+        writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
+    }
+    spi_ctrl_stop_user();
+
+    /* Check what was written */
+    read_page(my_page_addr, page);
+    for (i = 0; i < PAGE_SIZE / 4; i++) {
+        g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
+    }
+
+    /* Check some other page. It should be full of 0xff */
+    read_page(some_page_addr, page);
+    for (i = 0; i < PAGE_SIZE / 4; i++) {
+        g_assert_cmphex(page[i], ==, 0xffffffff);
+    }
+
+    flash_reset();
+}
+
+static void test_read_page_mem(void)
+{
+    uint32_t my_page_addr = 0x14000 * PAGE_SIZE; /* beyond 16MB */
+    uint32_t some_page_addr = 0x15000 * PAGE_SIZE;
+    uint32_t page[PAGE_SIZE / 4];
+    int i;
+
+    /* Enable 4BYTE mode for controller. This is should be strapped by
+     * HW for CE0 anyhow.
+     */
+    spi_ce_ctrl(1 << CRTL_EXTENDED0);
+
+    /* Enable 4BYTE mode for flash. */
+    spi_conf(CONF_ENABLE_W0);
+    spi_ctrl_start_user();
+    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
+    spi_ctrl_stop_user();
+    spi_conf_remove(CONF_ENABLE_W0);
+
+    /* Check what was written */
+    read_page_mem(my_page_addr, page);
+    for (i = 0; i < PAGE_SIZE / 4; i++) {
+        g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
+    }
+
+    /* Check some other page. It should be full of 0xff */
+    read_page_mem(some_page_addr, page);
+    for (i = 0; i < PAGE_SIZE / 4; i++) {
+        g_assert_cmphex(page[i], ==, 0xffffffff);
+    }
+
+    flash_reset();
+}
+
+static void test_write_page_mem(void)
+{
+    uint32_t my_page_addr = 0x15000 * PAGE_SIZE;
+    uint32_t page[PAGE_SIZE / 4];
+    int i;
+
+    /* Enable 4BYTE mode for controller. This is should be strapped by
+     * HW for CE0 anyhow.
+     */
+    spi_ce_ctrl(1 << CRTL_EXTENDED0);
+
+    /* Enable 4BYTE mode for flash. */
+    spi_conf(CONF_ENABLE_W0);
+    spi_ctrl_start_user();
+    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
+    writeb(ASPEED_FLASH_BASE, WREN);
+    spi_ctrl_stop_user();
+
+    /* move out USER mode to use direct writes to the AHB bus */
+    spi_ctrl_setmode(CTRL_WRITEMODE, PP);
+
+    for (i = 0; i < PAGE_SIZE / 4; i++) {
+        writel(ASPEED_FLASH_BASE + my_page_addr + i * 4,
+               make_be32(my_page_addr + i * 4));
+    }
+
+    /* Check what was written */
+    read_page_mem(my_page_addr, page);
+    for (i = 0; i < PAGE_SIZE / 4; i++) {
+        g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
+    }
+
+    flash_reset();
+}
+
+static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX";
+
+int main(int argc, char **argv)
+{
+    int ret;
+    int fd;
+
+    g_test_init(&argc, &argv, NULL);
+
+    fd = mkstemp(tmp_path);
+    g_assert(fd >= 0);
+    ret = ftruncate(fd, FLASH_SIZE);
+    g_assert(ret == 0);
+    close(fd);
+
+    global_qtest = qtest_initf("-m 256 -machine palmetto-bmc "
+                               "-drive file=%s,format=raw,if=mtd",
+                               tmp_path);
+
+    qtest_add_func("/m25p80/read_jedec", test_read_jedec);
+    qtest_add_func("/m25p80/erase_sector", test_erase_sector);
+    qtest_add_func("/m25p80/erase_all",  test_erase_all);
+    qtest_add_func("/m25p80/write_page", test_write_page);
+    qtest_add_func("/m25p80/read_page_mem", test_read_page_mem);
+    qtest_add_func("/m25p80/write_page_mem", test_write_page_mem);
+
+    ret = g_test_run();
+
+    qtest_quit(global_qtest);
+    unlink(tmp_path);
+    return ret;
+}
diff --git a/tests/qtest/m48t59-test.c b/tests/qtest/m48t59-test.c
new file mode 100644 (file)
index 0000000..b94a123
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * QTest testcase for the M48T59 and M48T08 real-time clocks
+ *
+ * Based on MC146818 RTC test:
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Anthony Liguori   <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqtest.h"
+
+#define RTC_SECONDS             0x9
+#define RTC_MINUTES             0xa
+#define RTC_HOURS               0xb
+
+#define RTC_DAY_OF_WEEK         0xc
+#define RTC_DAY_OF_MONTH        0xd
+#define RTC_MONTH               0xe
+#define RTC_YEAR                0xf
+
+static uint32_t base;
+static uint16_t reg_base = 0x1ff0; /* 0x7f0 for m48t02 */
+static int base_year;
+static const char *base_machine;
+static bool use_mmio;
+
+static uint8_t cmos_read_mmio(QTestState *s, uint8_t reg)
+{
+    return qtest_readb(s, base + (uint32_t)reg_base + (uint32_t)reg);
+}
+
+static void cmos_write_mmio(QTestState *s, uint8_t reg, uint8_t val)
+{
+    uint8_t data = val;
+
+    qtest_writeb(s, base + (uint32_t)reg_base + (uint32_t)reg, data);
+}
+
+static uint8_t cmos_read_ioio(QTestState *s, uint8_t reg)
+{
+    qtest_outw(s, base + 0, reg_base + (uint16_t)reg);
+    return qtest_inb(s, base + 3);
+}
+
+static void cmos_write_ioio(QTestState *s, uint8_t reg, uint8_t val)
+{
+    qtest_outw(s, base + 0, reg_base + (uint16_t)reg);
+    qtest_outb(s, base + 3, val);
+}
+
+static uint8_t cmos_read(QTestState *s, uint8_t reg)
+{
+    if (use_mmio) {
+        return cmos_read_mmio(s, reg);
+    } else {
+        return cmos_read_ioio(s, reg);
+    }
+}
+
+static void cmos_write(QTestState *s, uint8_t reg, uint8_t val)
+{
+    if (use_mmio) {
+        cmos_write_mmio(s, reg, val);
+    } else {
+        cmos_write_ioio(s, reg, val);
+    }
+}
+
+static int bcd2dec(int value)
+{
+    return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
+}
+
+static int tm_cmp(struct tm *lhs, struct tm *rhs)
+{
+    time_t a, b;
+    struct tm d1, d2;
+
+    memcpy(&d1, lhs, sizeof(d1));
+    memcpy(&d2, rhs, sizeof(d2));
+
+    a = mktime(&d1);
+    b = mktime(&d2);
+
+    if (a < b) {
+        return -1;
+    } else if (a > b) {
+        return 1;
+    }
+
+    return 0;
+}
+
+#if 0
+static void print_tm(struct tm *tm)
+{
+    printf("%04d-%02d-%02d %02d:%02d:%02d %+02ld\n",
+           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+           tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
+}
+#endif
+
+static void cmos_get_date_time(QTestState *s, struct tm *date)
+{
+    int sec, min, hour, mday, mon, year;
+    time_t ts;
+    struct tm dummy;
+
+    sec = cmos_read(s, RTC_SECONDS);
+    min = cmos_read(s, RTC_MINUTES);
+    hour = cmos_read(s, RTC_HOURS);
+    mday = cmos_read(s, RTC_DAY_OF_MONTH);
+    mon = cmos_read(s, RTC_MONTH);
+    year = cmos_read(s, RTC_YEAR);
+
+    sec = bcd2dec(sec);
+    min = bcd2dec(min);
+    hour = bcd2dec(hour);
+    mday = bcd2dec(mday);
+    mon = bcd2dec(mon);
+    year = bcd2dec(year);
+
+    ts = time(NULL);
+    localtime_r(&ts, &dummy);
+
+    date->tm_isdst = dummy.tm_isdst;
+    date->tm_sec = sec;
+    date->tm_min = min;
+    date->tm_hour = hour;
+    date->tm_mday = mday;
+    date->tm_mon = mon - 1;
+    date->tm_year = base_year + year - 1900;
+#ifndef __sun__
+    date->tm_gmtoff = 0;
+#endif
+
+    ts = mktime(date);
+}
+
+static QTestState *m48t59_qtest_start(void)
+{
+    return qtest_initf("-M %s -rtc clock=vm", base_machine);
+}
+
+static void bcd_check_time(void)
+{
+    struct tm start, date[4], end;
+    struct tm *datep;
+    time_t ts;
+    const int wiggle = 2;
+    QTestState *s = m48t59_qtest_start();
+
+    /*
+     * This check assumes a few things.  First, we cannot guarantee that we get
+     * a consistent reading from the wall clock because we may hit an edge of
+     * the clock while reading.  To work around this, we read four clock readings
+     * such that at least two of them should match.  We need to assume that one
+     * reading is corrupt so we need four readings to ensure that we have at
+     * least two consecutive identical readings
+     *
+     * It's also possible that we'll cross an edge reading the host clock so
+     * simply check to make sure that the clock reading is within the period of
+     * when we expect it to be.
+     */
+
+    ts = time(NULL);
+    gmtime_r(&ts, &start);
+
+    cmos_get_date_time(s, &date[0]);
+    cmos_get_date_time(s, &date[1]);
+    cmos_get_date_time(s, &date[2]);
+    cmos_get_date_time(s, &date[3]);
+
+    ts = time(NULL);
+    gmtime_r(&ts, &end);
+
+    if (tm_cmp(&date[0], &date[1]) == 0) {
+        datep = &date[0];
+    } else if (tm_cmp(&date[1], &date[2]) == 0) {
+        datep = &date[1];
+    } else if (tm_cmp(&date[2], &date[3]) == 0) {
+        datep = &date[2];
+    } else {
+        g_assert_not_reached();
+    }
+
+    if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
+        long t, s;
+
+        start.tm_isdst = datep->tm_isdst;
+
+        t = (long)mktime(datep);
+        s = (long)mktime(&start);
+        if (t < s) {
+            g_test_message("RTC is %ld second(s) behind wall-clock", (s - t));
+        } else {
+            g_test_message("RTC is %ld second(s) ahead of wall-clock", (t - s));
+        }
+
+        g_assert_cmpint(ABS(t - s), <=, wiggle);
+    }
+
+    qtest_quit(s);
+}
+
+/* success if no crash or abort */
+static void fuzz_registers(void)
+{
+    unsigned int i;
+    QTestState *s = m48t59_qtest_start();
+
+    for (i = 0; i < 1000; i++) {
+        uint8_t reg, val;
+
+        reg = (uint8_t)g_test_rand_int_range(0, 16);
+        val = (uint8_t)g_test_rand_int_range(0, 256);
+
+        if (reg == 7) {
+            /* watchdog setup register, may trigger system reset, skip */
+            continue;
+        }
+
+        cmos_write(s, reg, val);
+        cmos_read(s, reg);
+    }
+
+    qtest_quit(s);
+}
+
+static void base_setup(void)
+{
+    const char *arch = qtest_get_arch();
+
+    if (g_str_equal(arch, "sparc")) {
+        /* Note: For sparc64, we'd need to map-in the PCI bridge memory first */
+        base = 0x71200000;
+        base_year = 1968;
+        base_machine = "SS-5";
+        use_mmio = true;
+    } else if (g_str_equal(arch, "ppc") || g_str_equal(arch, "ppc64")) {
+        base = 0xF0000000;
+        base_year = 1968;
+        base_machine = "ref405ep";
+        use_mmio = true;
+    } else {
+        g_assert_not_reached();
+    }
+}
+
+int main(int argc, char **argv)
+{
+    base_setup();
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (g_test_slow()) {
+        /* Do not run this in timing-sensitive environments */
+        qtest_add_func("/rtc/bcd-check-time", bcd_check_time);
+    }
+    qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
+    return g_test_run();
+}
diff --git a/tests/qtest/machine-none-test.c b/tests/qtest/machine-none-test.c
new file mode 100644 (file)
index 0000000..5953d31
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Machine 'none' tests.
+ *
+ * Copyright (c) 2018 Red Hat Inc.
+ *
+ * Authors:
+ *  Igor Mammedov <[email protected]>,
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu-common.h"
+#include "qemu/cutils.h"
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+
+
+struct arch2cpu {
+    const char *arch;
+    const char *cpu_model;
+};
+
+static struct arch2cpu cpus_map[] = {
+    /* tested targets list */
+    { "arm", "cortex-a15" },
+    { "aarch64", "cortex-a57" },
+    { "x86_64", "qemu64,apic-id=0" },
+    { "i386", "qemu32,apic-id=0" },
+    { "alpha", "ev67" },
+    { "cris", "crisv32" },
+    { "lm32", "lm32-full" },
+    { "m68k", "m5206" },
+    /* FIXME: { "microblaze", "any" }, doesn't work with -M none -cpu any */
+    /* FIXME: { "microblazeel", "any" }, doesn't work with -M none -cpu any */
+    { "mips", "4Kc" },
+    { "mipsel", "I7200" },
+    { "mips64", "20Kc" },
+    { "mips64el", "I6500" },
+    { "moxie", "MoxieLite" },
+    { "nios2", "FIXME" },
+    { "or1k", "or1200" },
+    { "ppc", "604" },
+    { "ppc64", "power8e_v2.1" },
+    { "s390x", "qemu" },
+    { "sh4", "sh7750r" },
+    { "sh4eb", "sh7751r" },
+    { "sparc", "LEON2" },
+    { "sparc64", "Fujitsu Sparc64" },
+    { "tricore", "tc1796" },
+    { "unicore32", "UniCore-II" },
+    { "xtensa", "dc233c" },
+    { "xtensaeb", "fsf" },
+    { "hppa", "hppa" },
+    { "riscv64", "rv64gcsu-v1.10.0" },
+    { "riscv32", "rv32gcsu-v1.9.1" },
+};
+
+static const char *get_cpu_model_by_arch(const char *arch)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(cpus_map); i++) {
+        if (!strcmp(arch, cpus_map[i].arch)) {
+            return cpus_map[i].cpu_model;
+        }
+    }
+    return NULL;
+}
+
+static void test_machine_cpu_cli(void)
+{
+    QDict *response;
+    const char *arch = qtest_get_arch();
+    const char *cpu_model = get_cpu_model_by_arch(arch);
+    QTestState *qts;
+
+    if (!cpu_model) {
+        if (!(!strcmp(arch, "microblaze") || !strcmp(arch, "microblazeel"))) {
+            fprintf(stderr, "WARNING: cpu name for target '%s' isn't defined,"
+                    " add it to cpus_map\n", arch);
+        }
+        return; /* TODO: die here to force all targets have a test */
+    }
+    qts = qtest_initf("-machine none -cpu '%s'", cpu_model);
+
+    response = qtest_qmp(qts, "{ 'execute': 'quit' }");
+    g_assert(qdict_haskey(response, "return"));
+    qobject_unref(response);
+
+    qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("machine/none/cpu_option", test_machine_cpu_cli);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/megasas-test.c b/tests/qtest/megasas-test.c
new file mode 100644 (file)
index 0000000..d6796b9
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * QTest testcase for LSI MegaRAID
+ *
+ * Copyright (c) 2017 Red Hat Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/bswap.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
+
+typedef struct QMegasas QMegasas;
+
+struct QMegasas {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *megasas_get_driver(void *obj, const char *interface)
+{
+    QMegasas *megasas = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &megasas->dev;
+    }
+
+    fprintf(stderr, "%s not present in megasas\n", interface);
+    g_assert_not_reached();
+}
+
+static void *megasas_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QMegasas *megasas = g_new0(QMegasas, 1);
+    QPCIBus *bus = pci_bus;
+
+    qpci_device_init(&megasas->dev, bus, addr);
+    megasas->obj.get_driver = megasas_get_driver;
+
+    return &megasas->obj;
+}
+
+/* This used to cause a NULL pointer dereference.  */
+static void megasas_pd_get_info_fuzz(void *obj, void *data, QGuestAllocator *alloc)
+{
+    QMegasas *megasas = obj;
+    QPCIDevice *dev = &megasas->dev;
+    QPCIBar bar;
+    uint32_t context[256];
+    uint64_t context_pa;
+    int i;
+
+    qpci_device_enable(dev);
+    bar = qpci_iomap(dev, 0, NULL);
+
+    memset(context, 0, sizeof(context));
+    context[0] = cpu_to_le32(0x05050505);
+    context[1] = cpu_to_le32(0x01010101);
+    for (i = 2; i < ARRAY_SIZE(context); i++) {
+        context[i] = cpu_to_le32(0x41414141);
+    }
+    context[6] = cpu_to_le32(0x02020000);
+    context[7] = cpu_to_le32(0);
+
+    context_pa = guest_alloc(alloc, sizeof(context));
+    qtest_memwrite(dev->bus->qts, context_pa, context, sizeof(context));
+    qpci_io_writel(dev, bar, 0x40, context_pa);
+}
+
+static void megasas_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0,id=scsi0",
+        .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,"
+                           "file.read-zeroes=on,format=raw",
+        .after_cmd_line = "-device scsi-hd,bus=scsi0.0,drive=drv0",
+    };
+
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+
+    qos_node_create_driver("megasas", megasas_create);
+    qos_node_consumes("megasas", "pci-bus", &opts);
+    qos_node_produces("megasas", "pci-device");
+
+    qos_add_test("dcmd/pd-get-info/fuzz", "megasas", megasas_pd_get_info_fuzz, NULL);
+}
+libqos_init(megasas_register_nodes);
diff --git a/tests/qtest/microbit-test.c b/tests/qtest/microbit-test.c
new file mode 100644 (file)
index 0000000..04e199e
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * QTest testcase for Microbit board using the Nordic Semiconductor nRF51 SoC.
+ *
+ * nRF51:
+ * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
+ * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
+ *
+ * Microbit Board: http://microbit.org/
+ *
+ * Copyright 2018 Steffen Görtz <[email protected]>
+ *
+ * This code is licensed under the GPL version 2 or later.  See
+ * the COPYING file in the top-level directory.
+ */
+
+
+#include "qemu/osdep.h"
+#include "exec/hwaddr.h"
+#include "libqtest.h"
+
+#include "hw/arm/nrf51.h"
+#include "hw/char/nrf51_uart.h"
+#include "hw/gpio/nrf51_gpio.h"
+#include "hw/nvram/nrf51_nvm.h"
+#include "hw/timer/nrf51_timer.h"
+#include "hw/i2c/microbit_i2c.h"
+
+static bool uart_wait_for_event(QTestState *qts, uint32_t event_addr)
+{
+    time_t now, start = time(NULL);
+
+    while (true) {
+        if (qtest_readl(qts, event_addr) == 1) {
+            qtest_writel(qts, event_addr, 0x00);
+            return true;
+        }
+
+        /* Wait at most 10 minutes */
+        now = time(NULL);
+        if (now - start > 600) {
+            break;
+        }
+        g_usleep(10000);
+    }
+
+    return false;
+}
+
+static void uart_rw_to_rxd(QTestState *qts, int sock_fd, const char *in,
+                           char *out)
+{
+    int i, in_len = strlen(in);
+
+    g_assert_true(write(sock_fd, in, in_len) == in_len);
+    for (i = 0; i < in_len; i++) {
+        g_assert_true(uart_wait_for_event(qts, NRF51_UART_BASE +
+                                               A_UART_RXDRDY));
+        out[i] = qtest_readl(qts, NRF51_UART_BASE + A_UART_RXD);
+    }
+    out[i] = '\0';
+}
+
+static void uart_w_to_txd(QTestState *qts, const char *in)
+{
+    int i, in_len = strlen(in);
+
+    for (i = 0; i < in_len; i++) {
+        qtest_writel(qts, NRF51_UART_BASE + A_UART_TXD, in[i]);
+        g_assert_true(uart_wait_for_event(qts, NRF51_UART_BASE +
+                                               A_UART_TXDRDY));
+    }
+}
+
+static void test_nrf51_uart(void)
+{
+    int sock_fd;
+    char s[10];
+    QTestState *qts = qtest_init_with_serial("-M microbit", &sock_fd);
+
+    g_assert_true(write(sock_fd, "c", 1) == 1);
+    g_assert_cmphex(qtest_readl(qts, NRF51_UART_BASE + A_UART_RXD), ==, 0x00);
+
+    qtest_writel(qts, NRF51_UART_BASE + A_UART_ENABLE, 0x04);
+    qtest_writel(qts, NRF51_UART_BASE + A_UART_STARTRX, 0x01);
+
+    g_assert_true(uart_wait_for_event(qts, NRF51_UART_BASE + A_UART_RXDRDY));
+    qtest_writel(qts, NRF51_UART_BASE + A_UART_RXDRDY, 0x00);
+    g_assert_cmphex(qtest_readl(qts, NRF51_UART_BASE + A_UART_RXD), ==, 'c');
+
+    qtest_writel(qts, NRF51_UART_BASE + A_UART_INTENSET, 0x04);
+    g_assert_cmphex(qtest_readl(qts, NRF51_UART_BASE + A_UART_INTEN), ==, 0x04);
+    qtest_writel(qts, NRF51_UART_BASE + A_UART_INTENCLR, 0x04);
+    g_assert_cmphex(qtest_readl(qts, NRF51_UART_BASE + A_UART_INTEN), ==, 0x00);
+
+    uart_rw_to_rxd(qts, sock_fd, "hello", s);
+    g_assert_true(memcmp(s, "hello", 5) == 0);
+
+    qtest_writel(qts, NRF51_UART_BASE + A_UART_STARTTX, 0x01);
+    uart_w_to_txd(qts, "d");
+    g_assert_true(read(sock_fd, s, 10) == 1);
+    g_assert_cmphex(s[0], ==, 'd');
+
+    qtest_writel(qts, NRF51_UART_BASE + A_UART_SUSPEND, 0x01);
+    qtest_writel(qts, NRF51_UART_BASE + A_UART_TXD, 'h');
+    qtest_writel(qts, NRF51_UART_BASE + A_UART_STARTTX, 0x01);
+    uart_w_to_txd(qts, "world");
+    g_assert_true(read(sock_fd, s, 10) == 5);
+    g_assert_true(memcmp(s, "world", 5) == 0);
+
+    close(sock_fd);
+
+    qtest_quit(qts);
+}
+
+/* Read a byte from I2C device at @addr from register @reg */
+static uint32_t i2c_read_byte(QTestState *qts, uint32_t addr, uint32_t reg)
+{
+    uint32_t val;
+
+    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_REG_ADDRESS, addr);
+    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_TASK_STARTTX, 1);
+    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_REG_TXD, reg);
+    val = qtest_readl(qts, NRF51_TWI_BASE + NRF51_TWI_EVENT_TXDSENT);
+    g_assert_cmpuint(val, ==, 1);
+    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_TASK_STOP, 1);
+
+    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_TASK_STARTRX, 1);
+    val = qtest_readl(qts, NRF51_TWI_BASE + NRF51_TWI_EVENT_RXDREADY);
+    g_assert_cmpuint(val, ==, 1);
+    val = qtest_readl(qts, NRF51_TWI_BASE + NRF51_TWI_REG_RXD);
+    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_TASK_STOP, 1);
+
+    return val;
+}
+
+static void test_microbit_i2c(void)
+{
+    uint32_t val;
+    QTestState *qts = qtest_init("-M microbit");
+
+    /* We don't program pins/irqs but at least enable the device */
+    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_REG_ENABLE, 5);
+
+    /* MMA8653 magnetometer detection */
+    val = i2c_read_byte(qts, 0x3A, 0x0D);
+    g_assert_cmpuint(val, ==, 0x5A);
+
+    val = i2c_read_byte(qts, 0x3A, 0x0D);
+    g_assert_cmpuint(val, ==, 0x5A);
+
+    /* LSM303 accelerometer detection */
+    val = i2c_read_byte(qts, 0x3C, 0x4F);
+    g_assert_cmpuint(val, ==, 0x40);
+
+    qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_REG_ENABLE, 0);
+
+    qtest_quit(qts);
+}
+
+#define FLASH_SIZE          (256 * NRF51_PAGE_SIZE)
+
+static void fill_and_erase(QTestState *qts, hwaddr base, hwaddr size,
+                           uint32_t address_reg)
+{
+    hwaddr i;
+
+    /* Erase Page */
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02);
+    qtest_writel(qts, NRF51_NVMC_BASE + address_reg, base);
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
+
+    /* Check memory */
+    for (i = 0; i < size / 4; i++) {
+        g_assert_cmpuint(qtest_readl(qts, base + i * 4), ==, 0xFFFFFFFF);
+    }
+
+    /* Fill memory */
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x01);
+    for (i = 0; i < size / 4; i++) {
+        qtest_writel(qts, base + i * 4, i);
+        g_assert_cmpuint(qtest_readl(qts, base + i * 4), ==, i);
+    }
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
+}
+
+static void test_nrf51_nvmc(void)
+{
+    uint32_t value;
+    hwaddr i;
+    QTestState *qts = qtest_init("-M microbit");
+
+    /* Test always ready */
+    value = qtest_readl(qts, NRF51_NVMC_BASE + NRF51_NVMC_READY);
+    g_assert_cmpuint(value & 0x01, ==, 0x01);
+
+    /* Test write-read config register */
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x03);
+    g_assert_cmpuint(qtest_readl(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG),
+                     ==, 0x03);
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
+    g_assert_cmpuint(qtest_readl(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG),
+                     ==, 0x00);
+
+    /* Test PCR0 */
+    fill_and_erase(qts, NRF51_FLASH_BASE, NRF51_PAGE_SIZE,
+                   NRF51_NVMC_ERASEPCR0);
+    fill_and_erase(qts, NRF51_FLASH_BASE + NRF51_PAGE_SIZE,
+                   NRF51_PAGE_SIZE, NRF51_NVMC_ERASEPCR0);
+
+    /* Test PCR1 */
+    fill_and_erase(qts, NRF51_FLASH_BASE, NRF51_PAGE_SIZE,
+                   NRF51_NVMC_ERASEPCR1);
+    fill_and_erase(qts, NRF51_FLASH_BASE + NRF51_PAGE_SIZE,
+                   NRF51_PAGE_SIZE, NRF51_NVMC_ERASEPCR1);
+
+    /* Erase all */
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02);
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_ERASEALL, 0x01);
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
+
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x01);
+    for (i = 0; i < FLASH_SIZE / 4; i++) {
+        qtest_writel(qts, NRF51_FLASH_BASE + i * 4, i);
+        g_assert_cmpuint(qtest_readl(qts, NRF51_FLASH_BASE + i * 4), ==, i);
+    }
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
+
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02);
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_ERASEALL, 0x01);
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
+
+    for (i = 0; i < FLASH_SIZE / 4; i++) {
+        g_assert_cmpuint(qtest_readl(qts, NRF51_FLASH_BASE + i * 4),
+                         ==, 0xFFFFFFFF);
+    }
+
+    /* Erase UICR */
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02);
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_ERASEUICR, 0x01);
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
+
+    for (i = 0; i < NRF51_UICR_SIZE / 4; i++) {
+        g_assert_cmpuint(qtest_readl(qts, NRF51_UICR_BASE + i * 4),
+                         ==, 0xFFFFFFFF);
+    }
+
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x01);
+    for (i = 0; i < NRF51_UICR_SIZE / 4; i++) {
+        qtest_writel(qts, NRF51_UICR_BASE + i * 4, i);
+        g_assert_cmpuint(qtest_readl(qts, NRF51_UICR_BASE + i * 4), ==, i);
+    }
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
+
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02);
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_ERASEUICR, 0x01);
+    qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00);
+
+    for (i = 0; i < NRF51_UICR_SIZE / 4; i++) {
+        g_assert_cmpuint(qtest_readl(qts, NRF51_UICR_BASE + i * 4),
+                         ==, 0xFFFFFFFF);
+    }
+
+    qtest_quit(qts);
+}
+
+static void test_nrf51_gpio(void)
+{
+    size_t i;
+    uint32_t actual, expected;
+
+    struct {
+        hwaddr addr;
+        uint32_t expected;
+    } const reset_state[] = {
+        {NRF51_GPIO_REG_OUT, 0x00000000}, {NRF51_GPIO_REG_OUTSET, 0x00000000},
+        {NRF51_GPIO_REG_OUTCLR, 0x00000000}, {NRF51_GPIO_REG_IN, 0x00000000},
+        {NRF51_GPIO_REG_DIR, 0x00000000}, {NRF51_GPIO_REG_DIRSET, 0x00000000},
+        {NRF51_GPIO_REG_DIRCLR, 0x00000000}
+    };
+
+    QTestState *qts = qtest_init("-M microbit");
+
+    /* Check reset state */
+    for (i = 0; i < ARRAY_SIZE(reset_state); i++) {
+        expected = reset_state[i].expected;
+        actual = qtest_readl(qts, NRF51_GPIO_BASE + reset_state[i].addr);
+        g_assert_cmpuint(actual, ==, expected);
+    }
+
+    for (i = 0; i < NRF51_GPIO_PINS; i++) {
+        expected = 0x00000002;
+        actual = qtest_readl(qts, NRF51_GPIO_BASE +
+                                  NRF51_GPIO_REG_CNF_START + i * 4);
+        g_assert_cmpuint(actual, ==, expected);
+    }
+
+    /* Check dir bit consistency between dir and cnf */
+    /* Check set via DIRSET */
+    expected = 0x80000001;
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRSET, expected);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
+    g_assert_cmpuint(actual, ==, expected);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START)
+             & 0x01;
+    g_assert_cmpuint(actual, ==, 0x01);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
+    g_assert_cmpuint(actual, ==, 0x01);
+
+    /* Check clear via DIRCLR */
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRCLR, 0x80000001);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
+    g_assert_cmpuint(actual, ==, 0x00000000);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START)
+             & 0x01;
+    g_assert_cmpuint(actual, ==, 0x00);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
+    g_assert_cmpuint(actual, ==, 0x00);
+
+    /* Check set via DIR */
+    expected = 0x80000001;
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, expected);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
+    g_assert_cmpuint(actual, ==, expected);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START)
+             & 0x01;
+    g_assert_cmpuint(actual, ==, 0x01);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
+    g_assert_cmpuint(actual, ==, 0x01);
+
+    /* Reset DIR */
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, 0x00000000);
+
+    /* Check Input propagates */
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x00);
+    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+    g_assert_cmpuint(actual, ==, 0x00);
+    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 1);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+    g_assert_cmpuint(actual, ==, 0x01);
+    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, -1);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+    g_assert_cmpuint(actual, ==, 0x01);
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
+
+    /* Check pull-up working */
+    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+    g_assert_cmpuint(actual, ==, 0x00);
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b1110);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+    g_assert_cmpuint(actual, ==, 0x01);
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
+
+    /* Check pull-down working */
+    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 1);
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+    g_assert_cmpuint(actual, ==, 0x01);
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0110);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+    g_assert_cmpuint(actual, ==, 0x00);
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
+    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, -1);
+
+    /* Check Output propagates */
+    qtest_irq_intercept_out(qts, "/machine/nrf51");
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0011);
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
+    g_assert_true(qtest_get_irq(qts, 0));
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01);
+    g_assert_false(qtest_get_irq(qts, 0));
+
+    /* Check self-stimulation */
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01);
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+    g_assert_cmpuint(actual, ==, 0x01);
+
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01);
+    actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+    g_assert_cmpuint(actual, ==, 0x00);
+
+    /*
+     * Check short-circuit - generates an guest_error which must be checked
+     * manually as long as qtest can not scan qemu_log messages
+     */
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01);
+    qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
+    qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
+
+    qtest_quit(qts);
+}
+
+static void timer_task(QTestState *qts, hwaddr task)
+{
+    qtest_writel(qts, NRF51_TIMER_BASE + task, NRF51_TRIGGER_TASK);
+}
+
+static void timer_clear_event(QTestState *qts, hwaddr event)
+{
+    qtest_writel(qts, NRF51_TIMER_BASE + event, NRF51_EVENT_CLEAR);
+}
+
+static void timer_set_bitmode(QTestState *qts, uint8_t mode)
+{
+    qtest_writel(qts, NRF51_TIMER_BASE + NRF51_TIMER_REG_BITMODE, mode);
+}
+
+static void timer_set_prescaler(QTestState *qts, uint8_t prescaler)
+{
+    qtest_writel(qts, NRF51_TIMER_BASE + NRF51_TIMER_REG_PRESCALER, prescaler);
+}
+
+static void timer_set_cc(QTestState *qts, size_t idx, uint32_t value)
+{
+    qtest_writel(qts, NRF51_TIMER_BASE + NRF51_TIMER_REG_CC0 + idx * 4, value);
+}
+
+static void timer_assert_events(QTestState *qts, uint32_t ev0, uint32_t ev1,
+                                uint32_t ev2, uint32_t ev3)
+{
+    g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_0)
+             == ev0);
+    g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_1)
+             == ev1);
+    g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_2)
+             == ev2);
+    g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_3)
+             == ev3);
+}
+
+static void test_nrf51_timer(void)
+{
+    uint32_t steps_to_overflow = 408;
+    QTestState *qts = qtest_init("-M microbit");
+
+    /* Compare Match */
+    timer_task(qts, NRF51_TIMER_TASK_STOP);
+    timer_task(qts, NRF51_TIMER_TASK_CLEAR);
+
+    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_0);
+    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_1);
+    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_2);
+    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_3);
+
+    timer_set_bitmode(qts, NRF51_TIMER_WIDTH_16); /* 16 MHz Timer */
+    timer_set_prescaler(qts, 0);
+    /* Swept over in first step */
+    timer_set_cc(qts, 0, 2);
+    /* Barely miss on first step */
+    timer_set_cc(qts, 1, 162);
+    /* Spot on on third step */
+    timer_set_cc(qts, 2, 480);
+
+    timer_assert_events(qts, 0, 0, 0, 0);
+
+    timer_task(qts, NRF51_TIMER_TASK_START);
+    qtest_clock_step(qts, 10000);
+    timer_assert_events(qts, 1, 0, 0, 0);
+
+    /* Swept over on first overflow */
+    timer_set_cc(qts, 3, 114);
+
+    qtest_clock_step(qts, 10000);
+    timer_assert_events(qts, 1, 1, 0, 0);
+
+    qtest_clock_step(qts, 10000);
+    timer_assert_events(qts, 1, 1, 1, 0);
+
+    /* Wrap time until internal counter overflows */
+    while (steps_to_overflow--) {
+        timer_assert_events(qts, 1, 1, 1, 0);
+        qtest_clock_step(qts, 10000);
+    }
+
+    timer_assert_events(qts, 1, 1, 1, 1);
+
+    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_0);
+    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_1);
+    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_2);
+    timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_3);
+    timer_assert_events(qts, 0, 0, 0, 0);
+
+    timer_task(qts, NRF51_TIMER_TASK_STOP);
+
+    /* Test Proposal: Stop/Shutdown */
+    /* Test Proposal: Shortcut Compare -> Clear */
+    /* Test Proposal: Shortcut Compare -> Stop */
+    /* Test Proposal: Counter Mode */
+
+    qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/microbit/nrf51/uart", test_nrf51_uart);
+    qtest_add_func("/microbit/nrf51/gpio", test_nrf51_gpio);
+    qtest_add_func("/microbit/nrf51/nvmc", test_nrf51_nvmc);
+    qtest_add_func("/microbit/nrf51/timer", test_nrf51_timer);
+    qtest_add_func("/microbit/microbit/i2c", test_microbit_i2c);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c
new file mode 100644 (file)
index 0000000..516093b
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * QTest migration helpers
+ *
+ * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
+ *   based on the vhost-user-test.c that is:
+ *      Copyright (c) 2014 Virtual Open Systems Sarl.
+ *
+ * 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 "qapi/qmp/qjson.h"
+
+#include "migration-helpers.h"
+
+bool got_stop;
+
+static void stop_cb(void *opaque, const char *name, QDict *data)
+{
+    if (!strcmp(name, "STOP")) {
+        got_stop = true;
+    }
+}
+
+/*
+ * Events can get in the way of responses we are actually waiting for.
+ */
+QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...)
+{
+    va_list ap;
+
+    va_start(ap, command);
+    qtest_qmp_vsend_fds(who, &fd, 1, command, ap);
+    va_end(ap);
+
+    return qtest_qmp_receive_success(who, stop_cb, NULL);
+}
+
+/*
+ * Events can get in the way of responses we are actually waiting for.
+ */
+QDict *wait_command(QTestState *who, const char *command, ...)
+{
+    va_list ap;
+
+    va_start(ap, command);
+    qtest_qmp_vsend(who, command, ap);
+    va_end(ap);
+
+    return qtest_qmp_receive_success(who, stop_cb, NULL);
+}
+
+/*
+ * Send QMP command "migrate".
+ * Arguments are built from @fmt... (formatted like
+ * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
+ */
+void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...)
+{
+    va_list ap;
+    QDict *args, *rsp;
+
+    va_start(ap, fmt);
+    args = qdict_from_vjsonf_nofail(fmt, ap);
+    va_end(ap);
+
+    g_assert(!qdict_haskey(args, "uri"));
+    qdict_put_str(args, "uri", uri);
+
+    rsp = qtest_qmp(who, "{ 'execute': 'migrate', 'arguments': %p}", args);
+
+    g_assert(qdict_haskey(rsp, "return"));
+    qobject_unref(rsp);
+}
+
+/*
+ * Note: caller is responsible to free the returned object via
+ * qobject_unref() after use
+ */
+QDict *migrate_query(QTestState *who)
+{
+    return wait_command(who, "{ 'execute': 'query-migrate' }");
+}
+
+/*
+ * Note: caller is responsible to free the returned object via
+ * g_free() after use
+ */
+static gchar *migrate_query_status(QTestState *who)
+{
+    QDict *rsp_return = migrate_query(who);
+    gchar *status = g_strdup(qdict_get_str(rsp_return, "status"));
+
+    g_assert(status);
+    qobject_unref(rsp_return);
+
+    return status;
+}
+
+static bool check_migration_status(QTestState *who, const char *goal,
+                                   const char **ungoals)
+{
+    bool ready;
+    char *current_status;
+    const char **ungoal;
+
+    current_status = migrate_query_status(who);
+    ready = strcmp(current_status, goal) == 0;
+    if (!ungoals) {
+        g_assert_cmpstr(current_status, !=, "failed");
+        /*
+         * If looking for a state other than completed,
+         * completion of migration would cause the test to
+         * hang.
+         */
+        if (strcmp(goal, "completed") != 0) {
+            g_assert_cmpstr(current_status, !=, "completed");
+        }
+    } else {
+        for (ungoal = ungoals; *ungoal; ungoal++) {
+            g_assert_cmpstr(current_status, !=,  *ungoal);
+        }
+    }
+    g_free(current_status);
+    return ready;
+}
+
+void wait_for_migration_status(QTestState *who,
+                               const char *goal, const char **ungoals)
+{
+    while (!check_migration_status(who, goal, ungoals)) {
+        usleep(1000);
+    }
+}
+
+void wait_for_migration_complete(QTestState *who)
+{
+    wait_for_migration_status(who, "completed", NULL);
+}
+
+void wait_for_migration_fail(QTestState *from, bool allow_active)
+{
+    QDict *rsp_return;
+    char *status;
+    bool failed;
+
+    do {
+        status = migrate_query_status(from);
+        bool result = !strcmp(status, "setup") || !strcmp(status, "failed") ||
+            (allow_active && !strcmp(status, "active"));
+        if (!result) {
+            fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n",
+                    __func__, status, allow_active);
+        }
+        g_assert(result);
+        failed = !strcmp(status, "failed");
+        g_free(status);
+    } while (!failed);
+
+    /* Is the machine currently running? */
+    rsp_return = wait_command(from, "{ 'execute': 'query-status' }");
+    g_assert(qdict_haskey(rsp_return, "running"));
+    g_assert(qdict_get_bool(rsp_return, "running"));
+    qobject_unref(rsp_return);
+}
diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h
new file mode 100644 (file)
index 0000000..a11808b
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * QTest migration helpers
+ *
+ * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
+ *   based on the vhost-user-test.c that is:
+ *      Copyright (c) 2014 Virtual Open Systems Sarl.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#ifndef MIGRATION_HELPERS_H_
+#define MIGRATION_HELPERS_H_
+
+#include "libqtest.h"
+
+extern bool got_stop;
+
+GCC_FMT_ATTR(3, 4)
+QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...);
+
+GCC_FMT_ATTR(2, 3)
+QDict *wait_command(QTestState *who, const char *command, ...);
+
+GCC_FMT_ATTR(3, 4)
+void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...);
+
+QDict *migrate_query(QTestState *who);
+
+void wait_for_migration_status(QTestState *who,
+                               const char *goal, const char **ungoals);
+
+void wait_for_migration_complete(QTestState *who);
+
+void wait_for_migration_fail(QTestState *from, bool allow_active);
+
+#endif /* MIGRATION_HELPERS_H_ */
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
new file mode 100644 (file)
index 0000000..53afec4
--- /dev/null
@@ -0,0 +1,1281 @@
+/*
+ * QTest testcase for migration
+ *
+ * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
+ *   based on the vhost-user-test.c that is:
+ *      Copyright (c) 2014 Virtual Open Systems Sarl.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "qemu/module.h"
+#include "qemu/option.h"
+#include "qemu/range.h"
+#include "qemu/sockets.h"
+#include "chardev/char.h"
+#include "qapi/qapi-visit-sockets.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/qobject-output-visitor.h"
+
+#include "migration-helpers.h"
+#include "migration/migration-test.h"
+
+/* TODO actually test the results and get rid of this */
+#define qtest_qmp_discard_response(...) qobject_unref(qtest_qmp(__VA_ARGS__))
+
+unsigned start_address;
+unsigned end_address;
+static bool uffd_feature_thread_id;
+
+#if defined(__linux__)
+#include <sys/syscall.h>
+#include <sys/vfs.h>
+#endif
+
+#if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD)
+#include <sys/eventfd.h>
+#include <sys/ioctl.h>
+#include <linux/userfaultfd.h>
+
+static bool ufd_version_check(void)
+{
+    struct uffdio_api api_struct;
+    uint64_t ioctl_mask;
+
+    int ufd = syscall(__NR_userfaultfd, O_CLOEXEC);
+
+    if (ufd == -1) {
+        g_test_message("Skipping test: userfaultfd not available");
+        return false;
+    }
+
+    api_struct.api = UFFD_API;
+    api_struct.features = 0;
+    if (ioctl(ufd, UFFDIO_API, &api_struct)) {
+        g_test_message("Skipping test: UFFDIO_API failed");
+        return false;
+    }
+    uffd_feature_thread_id = api_struct.features & UFFD_FEATURE_THREAD_ID;
+
+    ioctl_mask = (__u64)1 << _UFFDIO_REGISTER |
+                 (__u64)1 << _UFFDIO_UNREGISTER;
+    if ((api_struct.ioctls & ioctl_mask) != ioctl_mask) {
+        g_test_message("Skipping test: Missing userfault feature");
+        return false;
+    }
+
+    return true;
+}
+
+#else
+static bool ufd_version_check(void)
+{
+    g_test_message("Skipping test: Userfault not available (builtdtime)");
+    return false;
+}
+
+#endif
+
+static const char *tmpfs;
+
+/* The boot file modifies memory area in [start_address, end_address)
+ * repeatedly. It outputs a 'B' at a fixed rate while it's still running.
+ */
+#include "tests/migration/i386/a-b-bootblock.h"
+#include "tests/migration/aarch64/a-b-kernel.h"
+#include "tests/migration/s390x/a-b-bios.h"
+
+static void init_bootfile(const char *bootpath, void *content, size_t len)
+{
+    FILE *bootfile = fopen(bootpath, "wb");
+
+    g_assert_cmpint(fwrite(content, len, 1, bootfile), ==, 1);
+    fclose(bootfile);
+}
+
+/*
+ * Wait for some output in the serial output file,
+ * we get an 'A' followed by an endless string of 'B's
+ * but on the destination we won't have the A.
+ */
+static void wait_for_serial(const char *side)
+{
+    char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
+    FILE *serialfile = fopen(serialpath, "r");
+    const char *arch = qtest_get_arch();
+    int started = (strcmp(side, "src_serial") == 0 &&
+                   strcmp(arch, "ppc64") == 0) ? 0 : 1;
+
+    g_free(serialpath);
+    do {
+        int readvalue = fgetc(serialfile);
+
+        if (!started) {
+            /* SLOF prints its banner before starting test,
+             * to ignore it, mark the start of the test with '_',
+             * ignore all characters until this marker
+             */
+            switch (readvalue) {
+            case '_':
+                started = 1;
+                break;
+            case EOF:
+                fseek(serialfile, 0, SEEK_SET);
+                usleep(1000);
+                break;
+            }
+            continue;
+        }
+        switch (readvalue) {
+        case 'A':
+            /* Fine */
+            break;
+
+        case 'B':
+            /* It's alive! */
+            fclose(serialfile);
+            return;
+
+        case EOF:
+            started = (strcmp(side, "src_serial") == 0 &&
+                       strcmp(arch, "ppc64") == 0) ? 0 : 1;
+            fseek(serialfile, 0, SEEK_SET);
+            usleep(1000);
+            break;
+
+        default:
+            fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, side);
+            g_assert_not_reached();
+        }
+    } while (true);
+}
+
+/*
+ * It's tricky to use qemu's migration event capability with qtest,
+ * events suddenly appearing confuse the qmp()/hmp() responses.
+ */
+
+static int64_t read_ram_property_int(QTestState *who, const char *property)
+{
+    QDict *rsp_return, *rsp_ram;
+    int64_t result;
+
+    rsp_return = migrate_query(who);
+    if (!qdict_haskey(rsp_return, "ram")) {
+        /* Still in setup */
+        result = 0;
+    } else {
+        rsp_ram = qdict_get_qdict(rsp_return, "ram");
+        result = qdict_get_try_int(rsp_ram, property, 0);
+    }
+    qobject_unref(rsp_return);
+    return result;
+}
+
+static int64_t read_migrate_property_int(QTestState *who, const char *property)
+{
+    QDict *rsp_return;
+    int64_t result;
+
+    rsp_return = migrate_query(who);
+    result = qdict_get_try_int(rsp_return, property, 0);
+    qobject_unref(rsp_return);
+    return result;
+}
+
+static uint64_t get_migration_pass(QTestState *who)
+{
+    return read_ram_property_int(who, "dirty-sync-count");
+}
+
+static void read_blocktime(QTestState *who)
+{
+    QDict *rsp_return;
+
+    rsp_return = migrate_query(who);
+    g_assert(qdict_haskey(rsp_return, "postcopy-blocktime"));
+    qobject_unref(rsp_return);
+}
+
+static void wait_for_migration_pass(QTestState *who)
+{
+    uint64_t initial_pass = get_migration_pass(who);
+    uint64_t pass;
+
+    /* Wait for the 1st sync */
+    while (!got_stop && !initial_pass) {
+        usleep(1000);
+        initial_pass = get_migration_pass(who);
+    }
+
+    do {
+        usleep(1000);
+        pass = get_migration_pass(who);
+    } while (pass == initial_pass && !got_stop);
+}
+
+static void check_guests_ram(QTestState *who)
+{
+    /* Our ASM test will have been incrementing one byte from each page from
+     * start_address to < end_address in order. This gives us a constraint
+     * that any page's byte should be equal or less than the previous pages
+     * byte (mod 256); and they should all be equal except for one transition
+     * at the point where we meet the incrementer. (We're running this with
+     * the guest stopped).
+     */
+    unsigned address;
+    uint8_t first_byte;
+    uint8_t last_byte;
+    bool hit_edge = false;
+    int bad = 0;
+
+    qtest_memread(who, start_address, &first_byte, 1);
+    last_byte = first_byte;
+
+    for (address = start_address + TEST_MEM_PAGE_SIZE; address < end_address;
+         address += TEST_MEM_PAGE_SIZE)
+    {
+        uint8_t b;
+        qtest_memread(who, address, &b, 1);
+        if (b != last_byte) {
+            if (((b + 1) % 256) == last_byte && !hit_edge) {
+                /* This is OK, the guest stopped at the point of
+                 * incrementing the previous page but didn't get
+                 * to us yet.
+                 */
+                hit_edge = true;
+                last_byte = b;
+            } else {
+                bad++;
+                if (bad <= 10) {
+                    fprintf(stderr, "Memory content inconsistency at %x"
+                            " first_byte = %x last_byte = %x current = %x"
+                            " hit_edge = %x\n",
+                            address, first_byte, last_byte, b, hit_edge);
+                }
+            }
+        }
+    }
+    if (bad >= 10) {
+        fprintf(stderr, "and in another %d pages", bad - 10);
+    }
+    g_assert(bad == 0);
+}
+
+static void cleanup(const char *filename)
+{
+    char *path = g_strdup_printf("%s/%s", tmpfs, filename);
+
+    unlink(path);
+    g_free(path);
+}
+
+static char *SocketAddress_to_str(SocketAddress *addr)
+{
+    switch (addr->type) {
+    case SOCKET_ADDRESS_TYPE_INET:
+        return g_strdup_printf("tcp:%s:%s",
+                               addr->u.inet.host,
+                               addr->u.inet.port);
+    case SOCKET_ADDRESS_TYPE_UNIX:
+        return g_strdup_printf("unix:%s",
+                               addr->u.q_unix.path);
+    case SOCKET_ADDRESS_TYPE_FD:
+        return g_strdup_printf("fd:%s", addr->u.fd.str);
+    case SOCKET_ADDRESS_TYPE_VSOCK:
+        return g_strdup_printf("tcp:%s:%s",
+                               addr->u.vsock.cid,
+                               addr->u.vsock.port);
+    default:
+        return g_strdup("unknown address type");
+    }
+}
+
+static char *migrate_get_socket_address(QTestState *who, const char *parameter)
+{
+    QDict *rsp;
+    char *result;
+    Error *local_err = NULL;
+    SocketAddressList *addrs;
+    Visitor *iv = NULL;
+    QObject *object;
+
+    rsp = migrate_query(who);
+    object = qdict_get(rsp, parameter);
+
+    iv = qobject_input_visitor_new(object);
+    visit_type_SocketAddressList(iv, NULL, &addrs, &local_err);
+    visit_free(iv);
+
+    /* we are only using a single address */
+    result = SocketAddress_to_str(addrs->value);
+
+    qapi_free_SocketAddressList(addrs);
+    qobject_unref(rsp);
+    return result;
+}
+
+static long long migrate_get_parameter_int(QTestState *who,
+                                           const char *parameter)
+{
+    QDict *rsp;
+    long long result;
+
+    rsp = wait_command(who, "{ 'execute': 'query-migrate-parameters' }");
+    result = qdict_get_int(rsp, parameter);
+    qobject_unref(rsp);
+    return result;
+}
+
+static void migrate_check_parameter_int(QTestState *who, const char *parameter,
+                                        long long value)
+{
+    long long result;
+
+    result = migrate_get_parameter_int(who, parameter);
+    g_assert_cmpint(result, ==, value);
+}
+
+static void migrate_set_parameter_int(QTestState *who, const char *parameter,
+                                      long long value)
+{
+    QDict *rsp;
+
+    rsp = qtest_qmp(who,
+                    "{ 'execute': 'migrate-set-parameters',"
+                    "'arguments': { %s: %lld } }",
+                    parameter, value);
+    g_assert(qdict_haskey(rsp, "return"));
+    qobject_unref(rsp);
+    migrate_check_parameter_int(who, parameter, value);
+}
+
+static void migrate_pause(QTestState *who)
+{
+    QDict *rsp;
+
+    rsp = wait_command(who, "{ 'execute': 'migrate-pause' }");
+    qobject_unref(rsp);
+}
+
+static void migrate_continue(QTestState *who, const char *state)
+{
+    QDict *rsp;
+
+    rsp = wait_command(who,
+                       "{ 'execute': 'migrate-continue',"
+                       "  'arguments': { 'state': %s } }",
+                       state);
+    qobject_unref(rsp);
+}
+
+static void migrate_recover(QTestState *who, const char *uri)
+{
+    QDict *rsp;
+
+    rsp = wait_command(who,
+                       "{ 'execute': 'migrate-recover', "
+                       "  'id': 'recover-cmd', "
+                       "  'arguments': { 'uri': %s } }",
+                       uri);
+    qobject_unref(rsp);
+}
+
+static void migrate_set_capability(QTestState *who, const char *capability,
+                                   bool value)
+{
+    QDict *rsp;
+
+    rsp = qtest_qmp(who,
+                    "{ 'execute': 'migrate-set-capabilities',"
+                    "'arguments': { "
+                    "'capabilities': [ { "
+                    "'capability': %s, 'state': %i } ] } }",
+                    capability, value);
+    g_assert(qdict_haskey(rsp, "return"));
+    qobject_unref(rsp);
+}
+
+static void migrate_postcopy_start(QTestState *from, QTestState *to)
+{
+    QDict *rsp;
+
+    rsp = wait_command(from, "{ 'execute': 'migrate-start-postcopy' }");
+    qobject_unref(rsp);
+
+    if (!got_stop) {
+        qtest_qmp_eventwait(from, "STOP");
+    }
+
+    qtest_qmp_eventwait(to, "RESUME");
+}
+
+typedef struct {
+    bool hide_stderr;
+    bool use_shmem;
+    char *opts_source;
+    char *opts_target;
+} MigrateStart;
+
+static MigrateStart *migrate_start_new(void)
+{
+    MigrateStart *args = g_new0(MigrateStart, 1);
+
+    args->opts_source = g_strdup("");
+    args->opts_target = g_strdup("");
+    return args;
+}
+
+static void migrate_start_destroy(MigrateStart *args)
+{
+    g_free(args->opts_source);
+    g_free(args->opts_target);
+    g_free(args);
+}
+
+static int test_migrate_start(QTestState **from, QTestState **to,
+                              const char *uri, MigrateStart *args)
+{
+    gchar *arch_source, *arch_target;
+    gchar *cmd_source, *cmd_target;
+    const gchar *ignore_stderr;
+    char *bootpath = NULL;
+    char *shmem_opts;
+    char *shmem_path;
+    const char *arch = qtest_get_arch();
+    const char *machine_opts = NULL;
+    const char *memory_size;
+
+    if (args->use_shmem) {
+        if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) {
+            g_test_skip("/dev/shm is not supported");
+            return -1;
+        }
+    }
+
+    got_stop = false;
+    bootpath = g_strdup_printf("%s/bootsect", tmpfs);
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        /* the assembled x86 boot sector should be exactly one sector large */
+        assert(sizeof(x86_bootsect) == 512);
+        init_bootfile(bootpath, x86_bootsect, sizeof(x86_bootsect));
+        memory_size = "150M";
+        arch_source = g_strdup_printf("-drive file=%s,format=raw", bootpath);
+        arch_target = g_strdup(arch_source);
+        start_address = X86_TEST_MEM_START;
+        end_address = X86_TEST_MEM_END;
+    } else if (g_str_equal(arch, "s390x")) {
+        init_bootfile(bootpath, s390x_elf, sizeof(s390x_elf));
+        memory_size = "128M";
+        arch_source = g_strdup_printf("-bios %s", bootpath);
+        arch_target = g_strdup(arch_source);
+        start_address = S390_TEST_MEM_START;
+        end_address = S390_TEST_MEM_END;
+    } else if (strcmp(arch, "ppc64") == 0) {
+        machine_opts = "vsmt=8";
+        memory_size = "256M";
+        arch_source = g_strdup_printf("-nodefaults "
+                                      "-prom-env 'use-nvramrc?=true' -prom-env "
+                                      "'nvramrc=hex .\" _\" begin %x %x "
+                                      "do i c@ 1 + i c! 1000 +loop .\" B\" 0 "
+                                      "until'", end_address, start_address);
+        arch_target = g_strdup("");
+        start_address = PPC_TEST_MEM_START;
+        end_address = PPC_TEST_MEM_END;
+    } else if (strcmp(arch, "aarch64") == 0) {
+        init_bootfile(bootpath, aarch64_kernel, sizeof(aarch64_kernel));
+        machine_opts = "virt,gic-version=max";
+        memory_size = "150M";
+        arch_source = g_strdup_printf("-cpu max "
+                                      "-kernel %s",
+                                      bootpath);
+        arch_target = g_strdup(arch_source);
+        start_address = ARM_TEST_MEM_START;
+        end_address = ARM_TEST_MEM_END;
+
+        g_assert(sizeof(aarch64_kernel) <= ARM_TEST_MAX_KERNEL_SIZE);
+    } else {
+        g_assert_not_reached();
+    }
+
+    g_free(bootpath);
+
+    if (args->hide_stderr) {
+        ignore_stderr = "2>/dev/null";
+    } else {
+        ignore_stderr = "";
+    }
+
+    if (args->use_shmem) {
+        shmem_path = g_strdup_printf("/dev/shm/qemu-%d", getpid());
+        shmem_opts = g_strdup_printf(
+            "-object memory-backend-file,id=mem0,size=%s"
+            ",mem-path=%s,share=on -numa node,memdev=mem0",
+            memory_size, shmem_path);
+    } else {
+        shmem_path = NULL;
+        shmem_opts = g_strdup("");
+    }
+
+    cmd_source = g_strdup_printf("-accel kvm -accel tcg%s%s "
+                                 "-name source,debug-threads=on "
+                                 "-m %s "
+                                 "-serial file:%s/src_serial "
+                                 "%s %s %s %s",
+                                 machine_opts ? " -machine " : "",
+                                 machine_opts ? machine_opts : "",
+                                 memory_size, tmpfs,
+                                 arch_source, shmem_opts, args->opts_source,
+                                 ignore_stderr);
+    g_free(arch_source);
+    *from = qtest_init(cmd_source);
+    g_free(cmd_source);
+
+    cmd_target = g_strdup_printf("-accel kvm -accel tcg%s%s "
+                                 "-name target,debug-threads=on "
+                                 "-m %s "
+                                 "-serial file:%s/dest_serial "
+                                 "-incoming %s "
+                                 "%s %s %s %s",
+                                 machine_opts ? " -machine " : "",
+                                 machine_opts ? machine_opts : "",
+                                 memory_size, tmpfs, uri,
+                                 arch_target, shmem_opts,
+                                 args->opts_target, ignore_stderr);
+    g_free(arch_target);
+    *to = qtest_init(cmd_target);
+    g_free(cmd_target);
+
+    g_free(shmem_opts);
+    /*
+     * Remove shmem file immediately to avoid memory leak in test failed case.
+     * It's valid becase QEMU has already opened this file
+     */
+    if (args->use_shmem) {
+        unlink(shmem_path);
+        g_free(shmem_path);
+    }
+
+    migrate_start_destroy(args);
+    return 0;
+}
+
+static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest)
+{
+    unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
+
+    qtest_quit(from);
+
+    if (test_dest) {
+        qtest_memread(to, start_address, &dest_byte_a, 1);
+
+        /* Destination still running, wait for a byte to change */
+        do {
+            qtest_memread(to, start_address, &dest_byte_b, 1);
+            usleep(1000 * 10);
+        } while (dest_byte_a == dest_byte_b);
+
+        qtest_qmp_discard_response(to, "{ 'execute' : 'stop'}");
+
+        /* With it stopped, check nothing changes */
+        qtest_memread(to, start_address, &dest_byte_c, 1);
+        usleep(1000 * 200);
+        qtest_memread(to, start_address, &dest_byte_d, 1);
+        g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
+
+        check_guests_ram(to);
+    }
+
+    qtest_quit(to);
+
+    cleanup("bootsect");
+    cleanup("migsocket");
+    cleanup("src_serial");
+    cleanup("dest_serial");
+}
+
+static void deprecated_set_downtime(QTestState *who, const double value)
+{
+    QDict *rsp;
+
+    rsp = qtest_qmp(who,
+                    "{ 'execute': 'migrate_set_downtime',"
+                    " 'arguments': { 'value': %f } }", value);
+    g_assert(qdict_haskey(rsp, "return"));
+    qobject_unref(rsp);
+    migrate_check_parameter_int(who, "downtime-limit", value * 1000);
+}
+
+static void deprecated_set_speed(QTestState *who, long long value)
+{
+    QDict *rsp;
+
+    rsp = qtest_qmp(who, "{ 'execute': 'migrate_set_speed',"
+                          "'arguments': { 'value': %lld } }", value);
+    g_assert(qdict_haskey(rsp, "return"));
+    qobject_unref(rsp);
+    migrate_check_parameter_int(who, "max-bandwidth", value);
+}
+
+static void deprecated_set_cache_size(QTestState *who, long long value)
+{
+    QDict *rsp;
+
+    rsp = qtest_qmp(who, "{ 'execute': 'migrate-set-cache-size',"
+                         "'arguments': { 'value': %lld } }", value);
+    g_assert(qdict_haskey(rsp, "return"));
+    qobject_unref(rsp);
+    migrate_check_parameter_int(who, "xbzrle-cache-size", value);
+}
+
+static void test_deprecated(void)
+{
+    QTestState *from;
+
+    from = qtest_init("-machine none");
+
+    deprecated_set_downtime(from, 0.12345);
+    deprecated_set_speed(from, 12345);
+    deprecated_set_cache_size(from, 4096);
+
+    qtest_quit(from);
+}
+
+static int migrate_postcopy_prepare(QTestState **from_ptr,
+                                    QTestState **to_ptr,
+                                    MigrateStart *args)
+{
+    char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+    QTestState *from, *to;
+
+    if (test_migrate_start(&from, &to, uri, args)) {
+        return -1;
+    }
+
+    migrate_set_capability(from, "postcopy-ram", true);
+    migrate_set_capability(to, "postcopy-ram", true);
+    migrate_set_capability(to, "postcopy-blocktime", true);
+
+    /* We want to pick a speed slow enough that the test completes
+     * quickly, but that it doesn't complete precopy even on a slow
+     * machine, so also set the downtime.
+     */
+    migrate_set_parameter_int(from, "max-bandwidth", 30000000);
+    migrate_set_parameter_int(from, "downtime-limit", 1);
+
+    /* Wait for the first serial output from the source */
+    wait_for_serial("src_serial");
+
+    migrate_qmp(from, uri, "{}");
+    g_free(uri);
+
+    wait_for_migration_pass(from);
+
+    *from_ptr = from;
+    *to_ptr = to;
+
+    return 0;
+}
+
+static void migrate_postcopy_complete(QTestState *from, QTestState *to)
+{
+    wait_for_migration_complete(from);
+
+    /* Make sure we get at least one "B" on destination */
+    wait_for_serial("dest_serial");
+
+    if (uffd_feature_thread_id) {
+        read_blocktime(to);
+    }
+
+    test_migrate_end(from, to, true);
+}
+
+static void test_postcopy(void)
+{
+    MigrateStart *args = migrate_start_new();
+    QTestState *from, *to;
+
+    if (migrate_postcopy_prepare(&from, &to, args)) {
+        return;
+    }
+    migrate_postcopy_start(from, to);
+    migrate_postcopy_complete(from, to);
+}
+
+static void test_postcopy_recovery(void)
+{
+    MigrateStart *args = migrate_start_new();
+    QTestState *from, *to;
+    char *uri;
+
+    args->hide_stderr = true;
+
+    if (migrate_postcopy_prepare(&from, &to, args)) {
+        return;
+    }
+
+    /* Turn postcopy speed down, 4K/s is slow enough on any machines */
+    migrate_set_parameter_int(from, "max-postcopy-bandwidth", 4096);
+
+    /* Now we start the postcopy */
+    migrate_postcopy_start(from, to);
+
+    /*
+     * Wait until postcopy is really started; we can only run the
+     * migrate-pause command during a postcopy
+     */
+    wait_for_migration_status(from, "postcopy-active", NULL);
+
+    /*
+     * Manually stop the postcopy migration. This emulates a network
+     * failure with the migration socket
+     */
+    migrate_pause(from);
+
+    /*
+     * Wait for destination side to reach postcopy-paused state.  The
+     * migrate-recover command can only succeed if destination machine
+     * is in the paused state
+     */
+    wait_for_migration_status(to, "postcopy-paused",
+                              (const char * []) { "failed", "active",
+                                                  "completed", NULL });
+
+    /*
+     * Create a new socket to emulate a new channel that is different
+     * from the broken migration channel; tell the destination to
+     * listen to the new port
+     */
+    uri = g_strdup_printf("unix:%s/migsocket-recover", tmpfs);
+    migrate_recover(to, uri);
+
+    /*
+     * Try to rebuild the migration channel using the resume flag and
+     * the newly created channel
+     */
+    wait_for_migration_status(from, "postcopy-paused",
+                              (const char * []) { "failed", "active",
+                                                  "completed", NULL });
+    migrate_qmp(from, uri, "{'resume': true}");
+    g_free(uri);
+
+    /* Restore the postcopy bandwidth to unlimited */
+    migrate_set_parameter_int(from, "max-postcopy-bandwidth", 0);
+
+    migrate_postcopy_complete(from, to);
+}
+
+static void test_baddest(void)
+{
+    MigrateStart *args = migrate_start_new();
+    QTestState *from, *to;
+
+    args->hide_stderr = true;
+
+    if (test_migrate_start(&from, &to, "tcp:0:0", args)) {
+        return;
+    }
+    migrate_qmp(from, "tcp:0:0", "{}");
+    wait_for_migration_fail(from, false);
+    test_migrate_end(from, to, false);
+}
+
+static void test_precopy_unix(void)
+{
+    char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+    MigrateStart *args = migrate_start_new();
+    QTestState *from, *to;
+
+    if (test_migrate_start(&from, &to, uri, args)) {
+        return;
+    }
+
+    /* We want to pick a speed slow enough that the test completes
+     * quickly, but that it doesn't complete precopy even on a slow
+     * machine, so also set the downtime.
+     */
+    /* 1 ms should make it not converge*/
+    migrate_set_parameter_int(from, "downtime-limit", 1);
+    /* 1GB/s */
+    migrate_set_parameter_int(from, "max-bandwidth", 1000000000);
+
+    /* Wait for the first serial output from the source */
+    wait_for_serial("src_serial");
+
+    migrate_qmp(from, uri, "{}");
+
+    wait_for_migration_pass(from);
+
+    /* 300 ms should converge */
+    migrate_set_parameter_int(from, "downtime-limit", 300);
+
+    if (!got_stop) {
+        qtest_qmp_eventwait(from, "STOP");
+    }
+
+    qtest_qmp_eventwait(to, "RESUME");
+
+    wait_for_serial("dest_serial");
+    wait_for_migration_complete(from);
+
+    test_migrate_end(from, to, true);
+    g_free(uri);
+}
+
+#if 0
+/* Currently upset on aarch64 TCG */
+static void test_ignore_shared(void)
+{
+    char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+    QTestState *from, *to;
+
+    if (test_migrate_start(&from, &to, uri, false, true, NULL, NULL)) {
+        return;
+    }
+
+    migrate_set_capability(from, "x-ignore-shared", true);
+    migrate_set_capability(to, "x-ignore-shared", true);
+
+    /* Wait for the first serial output from the source */
+    wait_for_serial("src_serial");
+
+    migrate_qmp(from, uri, "{}");
+
+    wait_for_migration_pass(from);
+
+    if (!got_stop) {
+        qtest_qmp_eventwait(from, "STOP");
+    }
+
+    qtest_qmp_eventwait(to, "RESUME");
+
+    wait_for_serial("dest_serial");
+    wait_for_migration_complete(from);
+
+    /* Check whether shared RAM has been really skipped */
+    g_assert_cmpint(read_ram_property_int(from, "transferred"), <, 1024 * 1024);
+
+    test_migrate_end(from, to, true);
+    g_free(uri);
+}
+#endif
+
+static void test_xbzrle(const char *uri)
+{
+    MigrateStart *args = migrate_start_new();
+    QTestState *from, *to;
+
+    if (test_migrate_start(&from, &to, uri, args)) {
+        return;
+    }
+
+    /*
+     * We want to pick a speed slow enough that the test completes
+     * quickly, but that it doesn't complete precopy even on a slow
+     * machine, so also set the downtime.
+     */
+    /* 1 ms should make it not converge*/
+    migrate_set_parameter_int(from, "downtime-limit", 1);
+    /* 1GB/s */
+    migrate_set_parameter_int(from, "max-bandwidth", 1000000000);
+
+    migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432);
+
+    migrate_set_capability(from, "xbzrle", "true");
+    migrate_set_capability(to, "xbzrle", "true");
+    /* Wait for the first serial output from the source */
+    wait_for_serial("src_serial");
+
+    migrate_qmp(from, uri, "{}");
+
+    wait_for_migration_pass(from);
+
+    /* 300ms should converge */
+    migrate_set_parameter_int(from, "downtime-limit", 300);
+
+    if (!got_stop) {
+        qtest_qmp_eventwait(from, "STOP");
+    }
+    qtest_qmp_eventwait(to, "RESUME");
+
+    wait_for_serial("dest_serial");
+    wait_for_migration_complete(from);
+
+    test_migrate_end(from, to, true);
+}
+
+static void test_xbzrle_unix(void)
+{
+    char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+
+    test_xbzrle(uri);
+    g_free(uri);
+}
+
+static void test_precopy_tcp(void)
+{
+    MigrateStart *args = migrate_start_new();
+    char *uri;
+    QTestState *from, *to;
+
+    if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", args)) {
+        return;
+    }
+
+    /*
+     * We want to pick a speed slow enough that the test completes
+     * quickly, but that it doesn't complete precopy even on a slow
+     * machine, so also set the downtime.
+     */
+    /* 1 ms should make it not converge*/
+    migrate_set_parameter_int(from, "downtime-limit", 1);
+    /* 1GB/s */
+    migrate_set_parameter_int(from, "max-bandwidth", 1000000000);
+
+    /* Wait for the first serial output from the source */
+    wait_for_serial("src_serial");
+
+    uri = migrate_get_socket_address(to, "socket-address");
+
+    migrate_qmp(from, uri, "{}");
+
+    wait_for_migration_pass(from);
+
+    /* 300ms should converge */
+    migrate_set_parameter_int(from, "downtime-limit", 300);
+
+    if (!got_stop) {
+        qtest_qmp_eventwait(from, "STOP");
+    }
+    qtest_qmp_eventwait(to, "RESUME");
+
+    wait_for_serial("dest_serial");
+    wait_for_migration_complete(from);
+
+    test_migrate_end(from, to, true);
+    g_free(uri);
+}
+
+static void test_migrate_fd_proto(void)
+{
+    MigrateStart *args = migrate_start_new();
+    QTestState *from, *to;
+    int ret;
+    int pair[2];
+    QDict *rsp;
+    const char *error_desc;
+
+    if (test_migrate_start(&from, &to, "defer", args)) {
+        return;
+    }
+
+    /*
+     * We want to pick a speed slow enough that the test completes
+     * quickly, but that it doesn't complete precopy even on a slow
+     * machine, so also set the downtime.
+     */
+    /* 1 ms should make it not converge */
+    migrate_set_parameter_int(from, "downtime-limit", 1);
+    /* 1GB/s */
+    migrate_set_parameter_int(from, "max-bandwidth", 1000000000);
+
+    /* Wait for the first serial output from the source */
+    wait_for_serial("src_serial");
+
+    /* Create two connected sockets for migration */
+    ret = socketpair(PF_LOCAL, SOCK_STREAM, 0, pair);
+    g_assert_cmpint(ret, ==, 0);
+
+    /* Send the 1st socket to the target */
+    rsp = wait_command_fd(to, pair[0],
+                          "{ 'execute': 'getfd',"
+                          "  'arguments': { 'fdname': 'fd-mig' }}");
+    qobject_unref(rsp);
+    close(pair[0]);
+
+    /* Start incoming migration from the 1st socket */
+    rsp = wait_command(to, "{ 'execute': 'migrate-incoming',"
+                           "  'arguments': { 'uri': 'fd:fd-mig' }}");
+    qobject_unref(rsp);
+
+    /* Send the 2nd socket to the target */
+    rsp = wait_command_fd(from, pair[1],
+                          "{ 'execute': 'getfd',"
+                          "  'arguments': { 'fdname': 'fd-mig' }}");
+    qobject_unref(rsp);
+    close(pair[1]);
+
+    /* Start migration to the 2nd socket*/
+    migrate_qmp(from, "fd:fd-mig", "{}");
+
+    wait_for_migration_pass(from);
+
+    /* 300ms should converge */
+    migrate_set_parameter_int(from, "downtime-limit", 300);
+
+    if (!got_stop) {
+        qtest_qmp_eventwait(from, "STOP");
+    }
+    qtest_qmp_eventwait(to, "RESUME");
+
+    /* Test closing fds */
+    /* We assume, that QEMU removes named fd from its list,
+     * so this should fail */
+    rsp = qtest_qmp(from, "{ 'execute': 'closefd',"
+                          "  'arguments': { 'fdname': 'fd-mig' }}");
+    g_assert_true(qdict_haskey(rsp, "error"));
+    error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc");
+    g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found");
+    qobject_unref(rsp);
+
+    rsp = qtest_qmp(to, "{ 'execute': 'closefd',"
+                        "  'arguments': { 'fdname': 'fd-mig' }}");
+    g_assert_true(qdict_haskey(rsp, "error"));
+    error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc");
+    g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found");
+    qobject_unref(rsp);
+
+    /* Complete migration */
+    wait_for_serial("dest_serial");
+    wait_for_migration_complete(from);
+    test_migrate_end(from, to, true);
+}
+
+static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
+{
+    char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+    QTestState *from, *to;
+
+    if (test_migrate_start(&from, &to, uri, args)) {
+        return;
+    }
+
+    /*
+     * UUID validation is at the begin of migration. So, the main process of
+     * migration is not interesting for us here. Thus, set huge downtime for
+     * very fast migration.
+     */
+    migrate_set_parameter_int(from, "downtime-limit", 1000000);
+    migrate_set_capability(from, "validate-uuid", true);
+
+    /* Wait for the first serial output from the source */
+    wait_for_serial("src_serial");
+
+    migrate_qmp(from, uri, "{}");
+
+    if (should_fail) {
+        qtest_set_expected_status(to, 1);
+        wait_for_migration_fail(from, true);
+    } else {
+        wait_for_migration_complete(from);
+    }
+
+    test_migrate_end(from, to, false);
+    g_free(uri);
+}
+
+static void test_validate_uuid(void)
+{
+    MigrateStart *args = migrate_start_new();
+
+    args->opts_source = g_strdup("-uuid 11111111-1111-1111-1111-111111111111");
+    args->opts_target = g_strdup("-uuid 11111111-1111-1111-1111-111111111111");
+    do_test_validate_uuid(args, false);
+}
+
+static void test_validate_uuid_error(void)
+{
+    MigrateStart *args = migrate_start_new();
+
+    args->opts_source = g_strdup("-uuid 11111111-1111-1111-1111-111111111111");
+    args->opts_target = g_strdup("-uuid 22222222-2222-2222-2222-222222222222");
+    args->hide_stderr = true;
+    do_test_validate_uuid(args, true);
+}
+
+static void test_validate_uuid_src_not_set(void)
+{
+    MigrateStart *args = migrate_start_new();
+
+    args->opts_target = g_strdup("-uuid 22222222-2222-2222-2222-222222222222");
+    args->hide_stderr = true;
+    do_test_validate_uuid(args, false);
+}
+
+static void test_validate_uuid_dst_not_set(void)
+{
+    MigrateStart *args = migrate_start_new();
+
+    args->opts_source = g_strdup("-uuid 11111111-1111-1111-1111-111111111111");
+    args->hide_stderr = true;
+    do_test_validate_uuid(args, false);
+}
+
+static void test_migrate_auto_converge(void)
+{
+    char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+    MigrateStart *args = migrate_start_new();
+    QTestState *from, *to;
+    int64_t remaining, percentage;
+
+    /*
+     * We want the test to be stable and as fast as possible.
+     * E.g., with 1Gb/s bandwith migration may pass without throttling,
+     * so we need to decrease a bandwidth.
+     */
+    const int64_t init_pct = 5, inc_pct = 50, max_pct = 95;
+    const int64_t max_bandwidth = 400000000; /* ~400Mb/s */
+    const int64_t downtime_limit = 250; /* 250ms */
+    /*
+     * We migrate through unix-socket (> 500Mb/s).
+     * Thus, expected migration speed ~= bandwidth limit (< 500Mb/s).
+     * So, we can predict expected_threshold
+     */
+    const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000;
+
+    if (test_migrate_start(&from, &to, uri, args)) {
+        return;
+    }
+
+    migrate_set_capability(from, "auto-converge", true);
+    migrate_set_parameter_int(from, "cpu-throttle-initial", init_pct);
+    migrate_set_parameter_int(from, "cpu-throttle-increment", inc_pct);
+    migrate_set_parameter_int(from, "max-cpu-throttle", max_pct);
+
+    /*
+     * Set the initial parameters so that the migration could not converge
+     * without throttling.
+     */
+    migrate_set_parameter_int(from, "downtime-limit", 1);
+    migrate_set_parameter_int(from, "max-bandwidth", 100000000); /* ~100Mb/s */
+
+    /* To check remaining size after precopy */
+    migrate_set_capability(from, "pause-before-switchover", true);
+
+    /* Wait for the first serial output from the source */
+    wait_for_serial("src_serial");
+
+    migrate_qmp(from, uri, "{}");
+
+    /* Wait for throttling begins */
+    percentage = 0;
+    while (percentage == 0) {
+        percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
+        usleep(100);
+        g_assert_false(got_stop);
+    }
+    /* The first percentage of throttling should be equal to init_pct */
+    g_assert_cmpint(percentage, ==, init_pct);
+    /* Now, when we tested that throttling works, let it converge */
+    migrate_set_parameter_int(from, "downtime-limit", downtime_limit);
+    migrate_set_parameter_int(from, "max-bandwidth", max_bandwidth);
+
+    /*
+     * Wait for pre-switchover status to check last throttle percentage
+     * and remaining. These values will be zeroed later
+     */
+    wait_for_migration_status(from, "pre-switchover", NULL);
+
+    /* The final percentage of throttling shouldn't be greater than max_pct */
+    percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
+    g_assert_cmpint(percentage, <=, max_pct);
+
+    remaining = read_ram_property_int(from, "remaining");
+    g_assert_cmpint(remaining, <, expected_threshold);
+
+    migrate_continue(from, "pre-switchover");
+
+    qtest_qmp_eventwait(to, "RESUME");
+
+    wait_for_serial("dest_serial");
+    wait_for_migration_complete(from);
+
+    g_free(uri);
+
+    test_migrate_end(from, to, true);
+}
+
+int main(int argc, char **argv)
+{
+    char template[] = "/tmp/migration-test-XXXXXX";
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (!ufd_version_check()) {
+        return g_test_run();
+    }
+
+    /*
+     * On ppc64, the test only works with kvm-hv, but not with kvm-pr and TCG
+     * is touchy due to race conditions on dirty bits (especially on PPC for
+     * some reason)
+     */
+    if (g_str_equal(qtest_get_arch(), "ppc64") &&
+        (access("/sys/module/kvm_hv", F_OK) ||
+         access("/dev/kvm", R_OK | W_OK))) {
+        g_test_message("Skipping test: kvm_hv not available");
+        return g_test_run();
+    }
+
+    /*
+     * Similar to ppc64, s390x seems to be touchy with TCG, so disable it
+     * there until the problems are resolved
+     */
+    if (g_str_equal(qtest_get_arch(), "s390x")) {
+#if defined(HOST_S390X)
+        if (access("/dev/kvm", R_OK | W_OK)) {
+            g_test_message("Skipping test: kvm not available");
+            return g_test_run();
+        }
+#else
+        g_test_message("Skipping test: Need s390x host to work properly");
+        return g_test_run();
+#endif
+    }
+
+    tmpfs = mkdtemp(template);
+    if (!tmpfs) {
+        g_test_message("mkdtemp on path (%s): %s", template, strerror(errno));
+    }
+    g_assert(tmpfs);
+
+    module_call_init(MODULE_INIT_QOM);
+
+    qtest_add_func("/migration/postcopy/unix", test_postcopy);
+    qtest_add_func("/migration/postcopy/recovery", test_postcopy_recovery);
+    qtest_add_func("/migration/deprecated", test_deprecated);
+    qtest_add_func("/migration/bad_dest", test_baddest);
+    qtest_add_func("/migration/precopy/unix", test_precopy_unix);
+    qtest_add_func("/migration/precopy/tcp", test_precopy_tcp);
+    /* qtest_add_func("/migration/ignore_shared", test_ignore_shared); */
+    qtest_add_func("/migration/xbzrle/unix", test_xbzrle_unix);
+    qtest_add_func("/migration/fd_proto", test_migrate_fd_proto);
+    qtest_add_func("/migration/validate_uuid", test_validate_uuid);
+    qtest_add_func("/migration/validate_uuid_error", test_validate_uuid_error);
+    qtest_add_func("/migration/validate_uuid_src_not_set",
+                   test_validate_uuid_src_not_set);
+    qtest_add_func("/migration/validate_uuid_dst_not_set",
+                   test_validate_uuid_dst_not_set);
+
+    qtest_add_func("/migration/auto_converge", test_migrate_auto_converge);
+
+    ret = g_test_run();
+
+    g_assert_cmpint(ret, ==, 0);
+
+    ret = rmdir(tmpfs);
+    if (ret != 0) {
+        g_test_message("unable to rmdir: path (%s): %s",
+                       tmpfs, strerror(errno));
+    }
+
+    return ret;
+}
diff --git a/tests/qtest/modules-test.c b/tests/qtest/modules-test.c
new file mode 100644 (file)
index 0000000..8821768
--- /dev/null
@@ -0,0 +1,74 @@
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+const char common_args[] = "-nodefaults -machine none";
+
+static void test_modules_load(const void *data)
+{
+    QTestState *qts;
+    const char **args = (const char **)data;
+
+    qts = qtest_init(common_args);
+    qtest_module_load(qts, args[0], args[1]);
+    qtest_quit(qts);
+}
+
+int main(int argc, char *argv[])
+{
+    const char *modules[] = {
+#ifdef CONFIG_CURL
+        "block-", "curl",
+#endif
+#ifdef CONFIG_GLUSTERFS
+        "block-", "gluster",
+#endif
+#ifdef CONFIG_LIBISCSI
+        "block-", "iscsi",
+#endif
+#ifdef CONFIG_LIBNFS
+        "block-", "nfs",
+#endif
+#ifdef CONFIG_LIBSSH
+        "block-", "ssh",
+#endif
+#ifdef CONFIG_RBD
+        "block-", "rbd",
+#endif
+#ifdef CONFIG_AUDIO_ALSA
+        "audio-", "alsa",
+#endif
+#ifdef CONFIG_AUDIO_OSS
+        "audio-", "oss",
+#endif
+#ifdef CONFIG_AUDIO_PA
+        "audio-", "pa",
+#endif
+#ifdef CONFIG_AUDIO_SDL
+        "audio-", "sdl",
+#endif
+#ifdef CONFIG_CURSES
+        "ui-", "curses",
+#endif
+#if defined(CONFIG_GTK) && defined(CONFIG_VTE)
+        "ui-", "gtk",
+#endif
+#ifdef CONFIG_SDL
+        "ui-", "sdl",
+#endif
+#if defined(CONFIG_SPICE) && defined(CONFIG_GIO)
+        "ui-", "spice-app",
+#endif
+    };
+    int i;
+
+    g_test_init(&argc, &argv, NULL);
+
+    for (i = 0; i < G_N_ELEMENTS(modules); i += 2) {
+        char *testname = g_strdup_printf("/module/load/%s%s",
+                                         modules[i], modules[i + 1]);
+        qtest_add_data_func(testname, modules + i, test_modules_load);
+        g_free(testname);
+    }
+
+    return g_test_run();
+}
diff --git a/tests/qtest/ne2000-test.c b/tests/qtest/ne2000-test.c
new file mode 100644 (file)
index 0000000..3fc0e55
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * QTest testcase for ne2000 NIC
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
+
+typedef struct QNe2k_pci QNe2k_pci;
+
+struct QNe2k_pci {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *ne2k_pci_get_driver(void *obj, const char *interface)
+{
+    QNe2k_pci *ne2k_pci = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &ne2k_pci->dev;
+    }
+
+    fprintf(stderr, "%s not present in ne2k_pci\n", interface);
+    g_assert_not_reached();
+}
+
+static void *ne2k_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QNe2k_pci *ne2k_pci = g_new0(QNe2k_pci, 1);
+    QPCIBus *bus = pci_bus;
+
+    qpci_device_init(&ne2k_pci->dev, bus, addr);
+    ne2k_pci->obj.get_driver = ne2k_pci_get_driver;
+
+    return &ne2k_pci->obj;
+}
+
+static void ne2000_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+
+    qos_node_create_driver("ne2k_pci", ne2k_pci_create);
+    qos_node_consumes("ne2k_pci", "pci-bus", &opts);
+    qos_node_produces("ne2k_pci", "pci-device");
+}
+
+libqos_init(ne2000_register_nodes);
diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c
new file mode 100644 (file)
index 0000000..17dd807
--- /dev/null
@@ -0,0 +1,574 @@
+/*
+ * NUMA configuration test cases
+ *
+ * Copyright (c) 2017 Red Hat Inc.
+ * Authors:
+ *  Igor Mammedov <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
+
+static char *make_cli(const char *generic_cli, const char *test_cli)
+{
+    return g_strdup_printf("%s %s", generic_cli ? generic_cli : "", test_cli);
+}
+
+static void test_mon_explicit(const void *data)
+{
+    char *s;
+    char *cli;
+    QTestState *qts;
+
+    cli = make_cli(data, "-smp 8 "
+                   "-numa node,nodeid=0,cpus=0-3 "
+                   "-numa node,nodeid=1,cpus=4-7 ");
+    qts = qtest_init(cli);
+
+    s = qtest_hmp(qts, "info numa");
+    g_assert(strstr(s, "node 0 cpus: 0 1 2 3"));
+    g_assert(strstr(s, "node 1 cpus: 4 5 6 7"));
+    g_free(s);
+
+    qtest_quit(qts);
+    g_free(cli);
+}
+
+static void test_mon_default(const void *data)
+{
+    char *s;
+    char *cli;
+    QTestState *qts;
+
+    cli = make_cli(data, "-smp 8 -numa node -numa node");
+    qts = qtest_init(cli);
+
+    s = qtest_hmp(qts, "info numa");
+    g_assert(strstr(s, "node 0 cpus: 0 2 4 6"));
+    g_assert(strstr(s, "node 1 cpus: 1 3 5 7"));
+    g_free(s);
+
+    qtest_quit(qts);
+    g_free(cli);
+}
+
+static void test_mon_partial(const void *data)
+{
+    char *s;
+    char *cli;
+    QTestState *qts;
+
+    cli = make_cli(data, "-smp 8 "
+                   "-numa node,nodeid=0,cpus=0-1 "
+                   "-numa node,nodeid=1,cpus=4-5 ");
+    qts = qtest_init(cli);
+
+    s = qtest_hmp(qts, "info numa");
+    g_assert(strstr(s, "node 0 cpus: 0 1 2 3 6 7"));
+    g_assert(strstr(s, "node 1 cpus: 4 5"));
+    g_free(s);
+
+    qtest_quit(qts);
+    g_free(cli);
+}
+
+static QList *get_cpus(QTestState *qts, QDict **resp)
+{
+    *resp = qtest_qmp(qts, "{ 'execute': 'query-cpus' }");
+    g_assert(*resp);
+    g_assert(qdict_haskey(*resp, "return"));
+    return qdict_get_qlist(*resp, "return");
+}
+
+static void test_query_cpus(const void *data)
+{
+    char *cli;
+    QDict *resp;
+    QList *cpus;
+    QObject *e;
+    QTestState *qts;
+
+    cli = make_cli(data, "-smp 8 -numa node,cpus=0-3 -numa node,cpus=4-7");
+    qts = qtest_init(cli);
+    cpus = get_cpus(qts, &resp);
+    g_assert(cpus);
+
+    while ((e = qlist_pop(cpus))) {
+        QDict *cpu, *props;
+        int64_t cpu_idx, node;
+
+        cpu = qobject_to(QDict, e);
+        g_assert(qdict_haskey(cpu, "CPU"));
+        g_assert(qdict_haskey(cpu, "props"));
+
+        cpu_idx = qdict_get_int(cpu, "CPU");
+        props = qdict_get_qdict(cpu, "props");
+        g_assert(qdict_haskey(props, "node-id"));
+        node = qdict_get_int(props, "node-id");
+        if (cpu_idx >= 0 && cpu_idx < 4) {
+            g_assert_cmpint(node, ==, 0);
+        } else {
+            g_assert_cmpint(node, ==, 1);
+        }
+        qobject_unref(e);
+    }
+
+    qobject_unref(resp);
+    qtest_quit(qts);
+    g_free(cli);
+}
+
+static void pc_numa_cpu(const void *data)
+{
+    char *cli;
+    QDict *resp;
+    QList *cpus;
+    QObject *e;
+    QTestState *qts;
+
+    cli = make_cli(data, "-cpu pentium -smp 8,sockets=2,cores=2,threads=2 "
+        "-numa node,nodeid=0 -numa node,nodeid=1 "
+        "-numa cpu,node-id=1,socket-id=0 "
+        "-numa cpu,node-id=0,socket-id=1,core-id=0 "
+        "-numa cpu,node-id=0,socket-id=1,core-id=1,thread-id=0 "
+        "-numa cpu,node-id=1,socket-id=1,core-id=1,thread-id=1");
+    qts = qtest_init(cli);
+    cpus = get_cpus(qts, &resp);
+    g_assert(cpus);
+
+    while ((e = qlist_pop(cpus))) {
+        QDict *cpu, *props;
+        int64_t socket, core, thread, node;
+
+        cpu = qobject_to(QDict, e);
+        g_assert(qdict_haskey(cpu, "props"));
+        props = qdict_get_qdict(cpu, "props");
+
+        g_assert(qdict_haskey(props, "node-id"));
+        node = qdict_get_int(props, "node-id");
+        g_assert(qdict_haskey(props, "socket-id"));
+        socket = qdict_get_int(props, "socket-id");
+        g_assert(qdict_haskey(props, "core-id"));
+        core = qdict_get_int(props, "core-id");
+        g_assert(qdict_haskey(props, "thread-id"));
+        thread = qdict_get_int(props, "thread-id");
+
+        if (socket == 0) {
+            g_assert_cmpint(node, ==, 1);
+        } else if (socket == 1 && core == 0) {
+            g_assert_cmpint(node, ==, 0);
+        } else if (socket == 1 && core == 1 && thread == 0) {
+            g_assert_cmpint(node, ==, 0);
+        } else if (socket == 1 && core == 1 && thread == 1) {
+            g_assert_cmpint(node, ==, 1);
+        } else {
+            g_assert(false);
+        }
+        qobject_unref(e);
+    }
+
+    qobject_unref(resp);
+    qtest_quit(qts);
+    g_free(cli);
+}
+
+static void spapr_numa_cpu(const void *data)
+{
+    char *cli;
+    QDict *resp;
+    QList *cpus;
+    QObject *e;
+    QTestState *qts;
+
+    cli = make_cli(data, "-smp 4,cores=4 "
+        "-numa node,nodeid=0 -numa node,nodeid=1 "
+        "-numa cpu,node-id=0,core-id=0 "
+        "-numa cpu,node-id=0,core-id=1 "
+        "-numa cpu,node-id=0,core-id=2 "
+        "-numa cpu,node-id=1,core-id=3");
+    qts = qtest_init(cli);
+    cpus = get_cpus(qts, &resp);
+    g_assert(cpus);
+
+    while ((e = qlist_pop(cpus))) {
+        QDict *cpu, *props;
+        int64_t core, node;
+
+        cpu = qobject_to(QDict, e);
+        g_assert(qdict_haskey(cpu, "props"));
+        props = qdict_get_qdict(cpu, "props");
+
+        g_assert(qdict_haskey(props, "node-id"));
+        node = qdict_get_int(props, "node-id");
+        g_assert(qdict_haskey(props, "core-id"));
+        core = qdict_get_int(props, "core-id");
+
+        if (core >= 0 && core < 3) {
+            g_assert_cmpint(node, ==, 0);
+        } else if (core == 3) {
+            g_assert_cmpint(node, ==, 1);
+        } else {
+            g_assert(false);
+        }
+        qobject_unref(e);
+    }
+
+    qobject_unref(resp);
+    qtest_quit(qts);
+    g_free(cli);
+}
+
+static void aarch64_numa_cpu(const void *data)
+{
+    char *cli;
+    QDict *resp;
+    QList *cpus;
+    QObject *e;
+    QTestState *qts;
+
+    cli = make_cli(data, "-smp 2 "
+        "-numa node,nodeid=0 -numa node,nodeid=1 "
+        "-numa cpu,node-id=1,thread-id=0 "
+        "-numa cpu,node-id=0,thread-id=1");
+    qts = qtest_init(cli);
+    cpus = get_cpus(qts, &resp);
+    g_assert(cpus);
+
+    while ((e = qlist_pop(cpus))) {
+        QDict *cpu, *props;
+        int64_t thread, node;
+
+        cpu = qobject_to(QDict, e);
+        g_assert(qdict_haskey(cpu, "props"));
+        props = qdict_get_qdict(cpu, "props");
+
+        g_assert(qdict_haskey(props, "node-id"));
+        node = qdict_get_int(props, "node-id");
+        g_assert(qdict_haskey(props, "thread-id"));
+        thread = qdict_get_int(props, "thread-id");
+
+        if (thread == 0) {
+            g_assert_cmpint(node, ==, 1);
+        } else if (thread == 1) {
+            g_assert_cmpint(node, ==, 0);
+        } else {
+            g_assert(false);
+        }
+        qobject_unref(e);
+    }
+
+    qobject_unref(resp);
+    qtest_quit(qts);
+    g_free(cli);
+}
+
+static void pc_dynamic_cpu_cfg(const void *data)
+{
+    QObject *e;
+    QDict *resp;
+    QList *cpus;
+    QTestState *qs;
+
+    qs = qtest_initf("%s -nodefaults --preconfig -smp 2",
+                     data ? (char *)data : "");
+
+    /* create 2 numa nodes */
+    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'node', 'nodeid': 0 } }")));
+    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'node', 'nodeid': 1 } }")));
+
+    /* map 2 cpus in non default reverse order
+     * i.e socket1->node0, socket0->node1
+     */
+    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'cpu', 'node-id': 0, 'socket-id': 1 } }")));
+    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'cpu', 'node-id': 1, 'socket-id': 0 } }")));
+
+    /* let machine initialization to complete and run */
+    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
+    qtest_qmp_eventwait(qs, "RESUME");
+
+    /* check that CPUs are mapped as expected */
+    resp = qtest_qmp(qs, "{ 'execute': 'query-hotpluggable-cpus'}");
+    g_assert(qdict_haskey(resp, "return"));
+    cpus = qdict_get_qlist(resp, "return");
+    g_assert(cpus);
+    while ((e = qlist_pop(cpus))) {
+        const QDict *cpu, *props;
+        int64_t socket, node;
+
+        cpu = qobject_to(QDict, e);
+        g_assert(qdict_haskey(cpu, "props"));
+        props = qdict_get_qdict(cpu, "props");
+
+        g_assert(qdict_haskey(props, "node-id"));
+        node = qdict_get_int(props, "node-id");
+        g_assert(qdict_haskey(props, "socket-id"));
+        socket = qdict_get_int(props, "socket-id");
+
+        if (socket == 0) {
+            g_assert_cmpint(node, ==, 1);
+        } else if (socket == 1) {
+            g_assert_cmpint(node, ==, 0);
+        } else {
+            g_assert(false);
+        }
+        qobject_unref(e);
+    }
+    qobject_unref(resp);
+
+    qtest_quit(qs);
+}
+
+static void pc_hmat_build_cfg(const void *data)
+{
+    QTestState *qs = qtest_initf("%s -nodefaults --preconfig -machine hmat=on "
+                     "-smp 2,sockets=2 "
+                     "-m 128M,slots=2,maxmem=1G "
+                     "-object memory-backend-ram,size=64M,id=m0 "
+                     "-object memory-backend-ram,size=64M,id=m1 "
+                     "-numa node,nodeid=0,memdev=m0 "
+                     "-numa node,nodeid=1,memdev=m1,initiator=0 "
+                     "-numa cpu,node-id=0,socket-id=0 "
+                     "-numa cpu,node-id=0,socket-id=1",
+                     data ? (char *)data : "");
+
+    /* Fail: Initiator should be less than the number of nodes */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 2, 'target': 0,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-latency\" } }")));
+
+    /* Fail: Target should be less than the number of nodes */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 2,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-latency\" } }")));
+
+    /* Fail: Initiator should contain cpu */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 1, 'target': 0,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-latency\" } }")));
+
+    /* Fail: Data-type mismatch */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
+        " 'hierarchy': \"memory\", 'data-type': \"write-latency\","
+        " 'bandwidth': 524288000 } }")));
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
+        " 'hierarchy': \"memory\", 'data-type': \"read-bandwidth\","
+        " 'latency': 5 } }")));
+
+    /* Fail: Bandwidth should be 1MB (1048576) aligned */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-bandwidth\","
+        " 'bandwidth': 1048575 } }")));
+
+    /* Configuring HMAT bandwidth and latency details */
+    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-latency\","
+        " 'latency': 1 } }")));    /* 1 ns */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-latency\","
+        " 'latency': 5 } }")));    /* Fail: Duplicate configuration */
+    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-bandwidth\","
+        " 'bandwidth': 68717379584 } }")));    /* 65534 MB/s */
+    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 1,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-latency\","
+        " 'latency': 65534 } }")));    /* 65534 ns */
+    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 1,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-bandwidth\","
+        " 'bandwidth': 34358689792 } }")));    /* 32767 MB/s */
+
+    /* Fail: node_id should be less than the number of nodes */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-cache', 'node-id': 2, 'size': 10240,"
+        " 'level': 1, 'associativity': \"direct\", 'policy': \"write-back\","
+        " 'line': 8 } }")));
+
+    /* Fail: level should be less than HMAT_LB_LEVELS (4) */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
+        " 'level': 4, 'associativity': \"direct\", 'policy': \"write-back\","
+        " 'line': 8 } }")));
+
+    /* Fail: associativity option should be 'none', if level is 0 */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
+        " 'level': 0, 'associativity': \"direct\", 'policy': \"none\","
+        " 'line': 0 } }")));
+    /* Fail: policy option should be 'none', if level is 0 */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
+        " 'level': 0, 'associativity': \"none\", 'policy': \"write-back\","
+        " 'line': 0 } }")));
+    /* Fail: line option should be 0, if level is 0 */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
+        " 'level': 0, 'associativity': \"none\", 'policy': \"none\","
+        " 'line': 8 } }")));
+
+    /* Configuring HMAT memory side cache attributes */
+    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
+        " 'level': 1, 'associativity': \"direct\", 'policy': \"write-back\","
+        " 'line': 8 } }")));
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
+        " 'level': 1, 'associativity': \"direct\", 'policy': \"write-back\","
+        " 'line': 8 } }")));    /* Fail: Duplicate configuration */
+    /* Fail: The size of level 2 size should be small than level 1 */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
+        " 'level': 2, 'associativity': \"direct\", 'policy': \"write-back\","
+        " 'line': 8 } }")));
+    /* Fail: The size of level 0 size should be larger than level 1 */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
+        " 'level': 0, 'associativity': \"direct\", 'policy': \"write-back\","
+        " 'line': 8 } }")));
+    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-cache', 'node-id': 1, 'size': 10240,"
+        " 'level': 1, 'associativity': \"direct\", 'policy': \"write-back\","
+        " 'line': 8 } }")));
+
+    /* let machine initialization to complete and run */
+    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs,
+        "{ 'execute': 'x-exit-preconfig' }")));
+    qtest_qmp_eventwait(qs, "RESUME");
+
+    qtest_quit(qs);
+}
+
+static void pc_hmat_off_cfg(const void *data)
+{
+    QTestState *qs = qtest_initf("%s -nodefaults --preconfig "
+                     "-smp 2,sockets=2 "
+                     "-m 128M,slots=2,maxmem=1G "
+                     "-object memory-backend-ram,size=64M,id=m0 "
+                     "-object memory-backend-ram,size=64M,id=m1 "
+                     "-numa node,nodeid=0,memdev=m0",
+                     data ? (char *)data : "");
+
+    /*
+     * Fail: Enable HMAT with -machine hmat=on
+     * before using any of hmat specific options
+     */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'node', 'nodeid': 1, 'memdev': \"m1\","
+        " 'initiator': 0 } }")));
+    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'node', 'nodeid': 1, 'memdev': \"m1\" } }")));
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-latency\","
+        " 'latency': 1 } }")));
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
+        " 'level': 1, 'associativity': \"direct\", 'policy': \"write-back\","
+        " 'line': 8 } }")));
+
+    /* let machine initialization to complete and run */
+    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs,
+        "{ 'execute': 'x-exit-preconfig' }")));
+    qtest_qmp_eventwait(qs, "RESUME");
+
+    qtest_quit(qs);
+}
+
+static void pc_hmat_erange_cfg(const void *data)
+{
+    QTestState *qs = qtest_initf("%s -nodefaults --preconfig -machine hmat=on "
+                     "-smp 2,sockets=2 "
+                     "-m 128M,slots=2,maxmem=1G "
+                     "-object memory-backend-ram,size=64M,id=m0 "
+                     "-object memory-backend-ram,size=64M,id=m1 "
+                     "-numa node,nodeid=0,memdev=m0 "
+                     "-numa node,nodeid=1,memdev=m1,initiator=0 "
+                     "-numa cpu,node-id=0,socket-id=0 "
+                     "-numa cpu,node-id=0,socket-id=1",
+                     data ? (char *)data : "");
+
+    /* Can't store the compressed latency */
+    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-latency\","
+        " 'latency': 1 } }")));    /* 1 ns */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 1,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-latency\","
+        " 'latency': 65535 } }")));    /* 65535 ns */
+
+    /* Test the 0 input (bandwidth not provided) */
+    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 0,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-bandwidth\","
+        " 'bandwidth': 0 } }")));    /* 0 MB/s */
+    /* Fail: bandwidth should be provided before memory side cache attributes */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-cache', 'node-id': 0, 'size': 10240,"
+        " 'level': 1, 'associativity': \"direct\", 'policy': \"write-back\","
+        " 'line': 8 } }")));
+
+    /* Can't store the compressed bandwidth */
+    g_assert_true(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+        " 'arguments': { 'type': 'hmat-lb', 'initiator': 0, 'target': 1,"
+        " 'hierarchy': \"memory\", 'data-type': \"access-bandwidth\","
+        " 'bandwidth': 68718428160 } }")));    /* 65535 MB/s */
+
+    /* let machine initialization to complete and run */
+    g_assert_false(qmp_rsp_is_err(qtest_qmp(qs,
+        "{ 'execute': 'x-exit-preconfig' }")));
+    qtest_qmp_eventwait(qs, "RESUME");
+
+    qtest_quit(qs);
+}
+
+int main(int argc, char **argv)
+{
+    const char *args = NULL;
+    const char *arch = qtest_get_arch();
+
+    if (strcmp(arch, "aarch64") == 0) {
+        args = "-machine virt";
+    }
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_data_func("/numa/mon/default", args, test_mon_default);
+    qtest_add_data_func("/numa/mon/cpus/explicit", args, test_mon_explicit);
+    qtest_add_data_func("/numa/mon/cpus/partial", args, test_mon_partial);
+    qtest_add_data_func("/numa/qmp/cpus/query-cpus", args, test_query_cpus);
+
+    if (!strcmp(arch, "i386") || !strcmp(arch, "x86_64")) {
+        qtest_add_data_func("/numa/pc/cpu/explicit", args, pc_numa_cpu);
+        qtest_add_data_func("/numa/pc/dynamic/cpu", args, pc_dynamic_cpu_cfg);
+        qtest_add_data_func("/numa/pc/hmat/build", args, pc_hmat_build_cfg);
+        qtest_add_data_func("/numa/pc/hmat/off", args, pc_hmat_off_cfg);
+        qtest_add_data_func("/numa/pc/hmat/erange", args, pc_hmat_erange_cfg);
+    }
+
+    if (!strcmp(arch, "ppc64")) {
+        qtest_add_data_func("/numa/spapr/cpu/explicit", args, spapr_numa_cpu);
+    }
+
+    if (!strcmp(arch, "aarch64")) {
+        qtest_add_data_func("/numa/aarch64/cpu/explicit", args,
+                            aarch64_numa_cpu);
+    }
+
+    return g_test_run();
+}
diff --git a/tests/qtest/nvme-test.c b/tests/qtest/nvme-test.c
new file mode 100644 (file)
index 0000000..ff04421
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * QTest testcase for NVMe
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qemu/units.h"
+#include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
+
+typedef struct QNvme QNvme;
+
+struct QNvme {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *nvme_get_driver(void *obj, const char *interface)
+{
+    QNvme *nvme = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &nvme->dev;
+    }
+
+    fprintf(stderr, "%s not present in nvme\n", interface);
+    g_assert_not_reached();
+}
+
+static void *nvme_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QNvme *nvme = g_new0(QNvme, 1);
+    QPCIBus *bus = pci_bus;
+
+    qpci_device_init(&nvme->dev, bus, addr);
+    nvme->obj.get_driver = nvme_get_driver;
+
+    return &nvme->obj;
+}
+
+/* This used to cause a NULL pointer dereference.  */
+static void nvmetest_oob_cmb_test(void *obj, void *data, QGuestAllocator *alloc)
+{
+    const int cmb_bar_size = 2 * MiB;
+    QNvme *nvme = obj;
+    QPCIDevice *pdev = &nvme->dev;
+    QPCIBar bar;
+
+    qpci_device_enable(pdev);
+    bar = qpci_iomap(pdev, 2, NULL);
+
+    qpci_io_writel(pdev, bar, 0, 0xccbbaa99);
+    g_assert_cmpint(qpci_io_readb(pdev, bar, 0), ==, 0x99);
+    g_assert_cmpint(qpci_io_readw(pdev, bar, 0), ==, 0xaa99);
+
+    /* Test partially out-of-bounds accesses.  */
+    qpci_io_writel(pdev, bar, cmb_bar_size - 1, 0x44332211);
+    g_assert_cmpint(qpci_io_readb(pdev, bar, cmb_bar_size - 1), ==, 0x11);
+    g_assert_cmpint(qpci_io_readw(pdev, bar, cmb_bar_size - 1), !=, 0x2211);
+    g_assert_cmpint(qpci_io_readl(pdev, bar, cmb_bar_size - 1), !=, 0x44332211);
+}
+
+static void nvme_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0,drive=drv0,serial=foo",
+        .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,"
+                           "file.read-zeroes=on,format=raw",
+    };
+
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+
+    qos_node_create_driver("nvme", nvme_create);
+    qos_node_consumes("nvme", "pci-bus", &opts);
+    qos_node_produces("nvme", "pci-device");
+
+    qos_add_test("oob-cmb-access", "nvme", nvmetest_oob_cmb_test, &(QOSGraphTestOptions) {
+        .edge.extra_device_opts = "cmb_size_mb=2"
+    });
+}
+
+libqos_init(nvme_register_nodes);
diff --git a/tests/qtest/pca9552-test.c b/tests/qtest/pca9552-test.c
new file mode 100644 (file)
index 0000000..4b800d3
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * QTest testcase for the PCA9552 LED blinker
+ *
+ * Copyright (c) 2017-2018, IBM Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/i2c.h"
+#include "hw/misc/pca9552_regs.h"
+
+#define PCA9552_TEST_ID   "pca9552-test"
+#define PCA9552_TEST_ADDR 0x60
+
+static void pca9552_init(QI2CDevice *i2cdev)
+{
+    /* Switch on LEDs 0 and 12 */
+    i2c_set8(i2cdev, PCA9552_LS0, 0x54);
+    i2c_set8(i2cdev, PCA9552_LS3, 0x54);
+}
+
+static void receive_autoinc(void *obj, void *data, QGuestAllocator *alloc)
+{
+    QI2CDevice *i2cdev = (QI2CDevice *)obj;
+    uint8_t resp;
+    uint8_t reg = PCA9552_LS0 | PCA9552_AUTOINC;
+
+    pca9552_init(i2cdev);
+
+    i2c_send(i2cdev, &reg, 1);
+
+    /* PCA9552_LS0 */
+    i2c_recv(i2cdev, &resp, 1);
+    g_assert_cmphex(resp, ==, 0x54);
+
+    /* PCA9552_LS1 */
+    i2c_recv(i2cdev, &resp, 1);
+    g_assert_cmphex(resp, ==, 0x55);
+
+    /* PCA9552_LS2 */
+    i2c_recv(i2cdev, &resp, 1);
+    g_assert_cmphex(resp, ==, 0x55);
+
+    /* PCA9552_LS3 */
+    i2c_recv(i2cdev, &resp, 1);
+    g_assert_cmphex(resp, ==, 0x54);
+}
+
+static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc)
+{
+    QI2CDevice *i2cdev = (QI2CDevice *)obj;
+    uint8_t value;
+
+    value = i2c_get8(i2cdev, PCA9552_LS0);
+    g_assert_cmphex(value, ==, 0x55);
+
+    value = i2c_get8(i2cdev, PCA9552_INPUT0);
+    g_assert_cmphex(value, ==, 0x0);
+
+    pca9552_init(i2cdev);
+
+    value = i2c_get8(i2cdev, PCA9552_LS0);
+    g_assert_cmphex(value, ==, 0x54);
+
+    value = i2c_get8(i2cdev, PCA9552_INPUT0);
+    g_assert_cmphex(value, ==, 0x01);
+
+    value = i2c_get8(i2cdev, PCA9552_LS3);
+    g_assert_cmphex(value, ==, 0x54);
+
+    value = i2c_get8(i2cdev, PCA9552_INPUT1);
+    g_assert_cmphex(value, ==, 0x10);
+}
+
+static void pca9552_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "address=0x60"
+    };
+    add_qi2c_address(&opts, &(QI2CAddress) { 0x60 });
+
+    qos_node_create_driver("pca9552", i2c_device_create);
+    qos_node_consumes("pca9552", "i2c-bus", &opts);
+
+    qos_add_test("tx-rx", "pca9552", send_and_receive, NULL);
+    qos_add_test("rx-autoinc", "pca9552", receive_autoinc, NULL);
+}
+libqos_init(pca9552_register_nodes);
diff --git a/tests/qtest/pci-test.c b/tests/qtest/pci-test.c
new file mode 100644 (file)
index 0000000..4b2092b
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * QTest testcase for PCI
+ *
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void nop(void *obj, void *data, QGuestAllocator *alloc)
+{
+}
+
+static void register_pci_test(void)
+{
+    qos_add_test("nop", "pci-device", nop, NULL);
+}
+
+libqos_init(register_pci_test);
diff --git a/tests/qtest/pcnet-test.c b/tests/qtest/pcnet-test.c
new file mode 100644 (file)
index 0000000..900944f
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * QTest testcase for PC-Net NIC
+ *
+ * Copyright (c) 2013-2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
+
+typedef struct QPCNet QPCNet;
+
+struct QPCNet {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *pcnet_get_driver(void *obj, const char *interface)
+{
+    QPCNet *pcnet = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &pcnet->dev;
+    }
+
+    fprintf(stderr, "%s not present in pcnet\n", interface);
+    g_assert_not_reached();
+}
+
+static void *pcnet_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QPCNet *pcnet = g_new0(QPCNet, 1);
+    QPCIBus *bus = pci_bus;
+
+    qpci_device_init(&pcnet->dev, bus, addr);
+    pcnet->obj.get_driver = pcnet_get_driver;
+
+    return &pcnet->obj;
+}
+
+static void pcnet_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+
+    qos_node_create_driver("pcnet", pcnet_create);
+    qos_node_consumes("pcnet", "pci-bus", &opts);
+    qos_node_produces("pcnet", "pci-device");
+}
+
+libqos_init(pcnet_register_nodes);
diff --git a/tests/qtest/pflash-cfi02-test.c b/tests/qtest/pflash-cfi02-test.c
new file mode 100644 (file)
index 0000000..17aa669
--- /dev/null
@@ -0,0 +1,681 @@
+/*
+ * QTest testcase for parallel flash with AMD command set
+ *
+ * Copyright (c) 2019 Stephen Checkoway
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+/*
+ * To test the pflash_cfi02 device, we run QEMU with the musicpal machine with
+ * a pflash drive. This enables us to test some flash configurations, but not
+ * all. In particular, we're limited to a 16-bit wide flash device.
+ */
+
+#define MP_FLASH_SIZE_MAX (32 * 1024 * 1024)
+#define BASE_ADDR (0x100000000ULL - MP_FLASH_SIZE_MAX)
+
+#define UNIFORM_FLASH_SIZE (8 * 1024 * 1024)
+#define UNIFORM_FLASH_SECTOR_SIZE (64 * 1024)
+
+/* Use a newtype to keep flash addresses separate from byte addresses. */
+typedef struct {
+    uint64_t addr;
+} faddr;
+#define FLASH_ADDR(x) ((faddr) { .addr = (x) })
+
+#define CFI_ADDR FLASH_ADDR(0x55)
+#define UNLOCK0_ADDR FLASH_ADDR(0x555)
+#define UNLOCK1_ADDR FLASH_ADDR(0x2AA)
+
+#define CFI_CMD 0x98
+#define UNLOCK0_CMD 0xAA
+#define UNLOCK1_CMD 0x55
+#define SECOND_UNLOCK_CMD 0x80
+#define AUTOSELECT_CMD 0x90
+#define RESET_CMD 0xF0
+#define PROGRAM_CMD 0xA0
+#define SECTOR_ERASE_CMD 0x30
+#define CHIP_ERASE_CMD 0x10
+#define UNLOCK_BYPASS_CMD 0x20
+#define UNLOCK_BYPASS_RESET_CMD 0x00
+#define ERASE_SUSPEND_CMD 0xB0
+#define ERASE_RESUME_CMD SECTOR_ERASE_CMD
+
+typedef struct {
+    int bank_width;
+
+    /* Nonuniform block size. */
+    int nb_blocs[4];
+    int sector_len[4];
+
+    QTestState *qtest;
+} FlashConfig;
+
+static char image_path[] = "/tmp/qtest.XXXXXX";
+
+/*
+ * The pflash implementation allows some parameters to be unspecified. We want
+ * to test those configurations but we also need to know the real values in
+ * our testing code. So after we launch qemu, we'll need a new FlashConfig
+ * with the correct values filled in.
+ */
+static FlashConfig expand_config_defaults(const FlashConfig *c)
+{
+    FlashConfig ret = *c;
+
+    if (ret.bank_width == 0) {
+        ret.bank_width = 2;
+    }
+    if (ret.nb_blocs[0] == 0 && ret.sector_len[0] == 0) {
+        ret.sector_len[0] = UNIFORM_FLASH_SECTOR_SIZE;
+        ret.nb_blocs[0] = UNIFORM_FLASH_SIZE / UNIFORM_FLASH_SECTOR_SIZE;
+    }
+
+    /* XXX: Limitations of test harness. */
+    assert(ret.bank_width == 2);
+    return ret;
+}
+
+/*
+ * Return a bit mask suitable for extracting the least significant
+ * status/query response from an interleaved response.
+ */
+static inline uint64_t device_mask(const FlashConfig *c)
+{
+    return (uint64_t)-1;
+}
+
+/*
+ * Return a bit mask exactly as long as the bank_width.
+ */
+static inline uint64_t bank_mask(const FlashConfig *c)
+{
+    if (c->bank_width == 8) {
+        return (uint64_t)-1;
+    }
+    return (1ULL << (c->bank_width * 8)) - 1ULL;
+}
+
+static inline void flash_write(const FlashConfig *c, uint64_t byte_addr,
+                               uint64_t data)
+{
+    /* Sanity check our tests. */
+    assert((data & ~bank_mask(c)) == 0);
+    uint64_t addr = BASE_ADDR + byte_addr;
+    switch (c->bank_width) {
+    case 1:
+        qtest_writeb(c->qtest, addr, data);
+        break;
+    case 2:
+        qtest_writew(c->qtest, addr, data);
+        break;
+    case 4:
+        qtest_writel(c->qtest, addr, data);
+        break;
+    case 8:
+        qtest_writeq(c->qtest, addr, data);
+        break;
+    default:
+        abort();
+    }
+}
+
+static inline uint64_t flash_read(const FlashConfig *c, uint64_t byte_addr)
+{
+    uint64_t addr = BASE_ADDR + byte_addr;
+    switch (c->bank_width) {
+    case 1:
+        return qtest_readb(c->qtest, addr);
+    case 2:
+        return qtest_readw(c->qtest, addr);
+    case 4:
+        return qtest_readl(c->qtest, addr);
+    case 8:
+        return qtest_readq(c->qtest, addr);
+    default:
+        abort();
+    }
+}
+
+/*
+ * Convert a flash address expressed in the maximum width of the device as a
+ * byte address.
+ */
+static inline uint64_t as_byte_addr(const FlashConfig *c, faddr flash_addr)
+{
+    /*
+     * Command addresses are always given as addresses in the maximum
+     * supported bus size for the flash chip. So an x8/x16 chip in x8 mode
+     * uses addresses 0xAAA and 0x555 to unlock because the least significant
+     * bit is ignored. (0x555 rather than 0x554 is traditional.)
+     *
+     * In general we need to multiply by the maximum device width.
+     */
+    return flash_addr.addr * c->bank_width;
+}
+
+/*
+ * Return the command value or expected status replicated across all devices.
+ */
+static inline uint64_t replicate(const FlashConfig *c, uint64_t data)
+{
+    /* Sanity check our tests. */
+    assert((data & ~device_mask(c)) == 0);
+    return data;
+}
+
+static inline void flash_cmd(const FlashConfig *c, faddr cmd_addr,
+                             uint8_t cmd)
+{
+    flash_write(c, as_byte_addr(c, cmd_addr), replicate(c, cmd));
+}
+
+static inline uint64_t flash_query(const FlashConfig *c, faddr query_addr)
+{
+    return flash_read(c, as_byte_addr(c, query_addr));
+}
+
+static inline uint64_t flash_query_1(const FlashConfig *c, faddr query_addr)
+{
+    return flash_query(c, query_addr) & device_mask(c);
+}
+
+static void unlock(const FlashConfig *c)
+{
+    flash_cmd(c, UNLOCK0_ADDR, UNLOCK0_CMD);
+    flash_cmd(c, UNLOCK1_ADDR, UNLOCK1_CMD);
+}
+
+static void reset(const FlashConfig *c)
+{
+    flash_cmd(c, FLASH_ADDR(0), RESET_CMD);
+}
+
+static void sector_erase(const FlashConfig *c, uint64_t byte_addr)
+{
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
+    unlock(c);
+    flash_write(c, byte_addr, replicate(c, SECTOR_ERASE_CMD));
+}
+
+static void wait_for_completion(const FlashConfig *c, uint64_t byte_addr)
+{
+    /* If DQ6 is toggling, step the clock and ensure the toggle stops. */
+    const uint64_t dq6 = replicate(c, 0x40);
+    if ((flash_read(c, byte_addr) & dq6) ^ (flash_read(c, byte_addr) & dq6)) {
+        /* Wait for erase or program to finish. */
+        qtest_clock_step_next(c->qtest);
+        /* Ensure that DQ6 has stopped toggling. */
+        g_assert_cmphex(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
+    }
+}
+
+static void bypass_program(const FlashConfig *c, uint64_t byte_addr,
+                           uint16_t data)
+{
+    flash_cmd(c, UNLOCK0_ADDR, PROGRAM_CMD);
+    flash_write(c, byte_addr, data);
+    /*
+     * Data isn't valid until DQ6 stops toggling. We don't model this as
+     * writes are immediate, but if this changes in the future, we can wait
+     * until the program is complete.
+     */
+    wait_for_completion(c, byte_addr);
+}
+
+static void program(const FlashConfig *c, uint64_t byte_addr, uint16_t data)
+{
+    unlock(c);
+    bypass_program(c, byte_addr, data);
+}
+
+static void chip_erase(const FlashConfig *c)
+{
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, CHIP_ERASE_CMD);
+}
+
+static void erase_suspend(const FlashConfig *c)
+{
+    flash_cmd(c, FLASH_ADDR(0), ERASE_SUSPEND_CMD);
+}
+
+static void erase_resume(const FlashConfig *c)
+{
+    flash_cmd(c, FLASH_ADDR(0), ERASE_RESUME_CMD);
+}
+
+/*
+ * Test flash commands with a variety of device geometry.
+ */
+static void test_geometry(const void *opaque)
+{
+    const FlashConfig *config = opaque;
+    QTestState *qtest;
+    qtest = qtest_initf("-M musicpal"
+                        " -drive if=pflash,file=%s,format=raw,copy-on-read"
+                        /* Device geometry properties. */
+                        " -global driver=cfi.pflash02,"
+                        "property=num-blocks0,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=sector-length0,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=num-blocks1,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=sector-length1,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=num-blocks2,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=sector-length2,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=num-blocks3,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=sector-length3,value=%d",
+                        image_path,
+                        config->nb_blocs[0],
+                        config->sector_len[0],
+                        config->nb_blocs[1],
+                        config->sector_len[1],
+                        config->nb_blocs[2],
+                        config->sector_len[2],
+                        config->nb_blocs[3],
+                        config->sector_len[3]);
+    FlashConfig explicit_config = expand_config_defaults(config);
+    explicit_config.qtest = qtest;
+    const FlashConfig *c = &explicit_config;
+
+    /* Check the IDs. */
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD);
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+    if (c->bank_width >= 2) {
+        /*
+         * XXX: The ID returned by the musicpal flash chip is 16 bits which
+         * wouldn't happen with an 8-bit device. It would probably be best to
+         * prohibit addresses larger than the device width in pflash_cfi02.c,
+         * but then we couldn't test smaller device widths at all.
+         */
+        g_assert_cmphex(flash_query(c, FLASH_ADDR(1)), ==,
+                        replicate(c, 0x236D));
+    }
+    reset(c);
+
+    /* Check the erase blocks. */
+    flash_cmd(c, CFI_ADDR, CFI_CMD);
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
+
+    /* Num erase regions. */
+    int nb_erase_regions = flash_query_1(c, FLASH_ADDR(0x2C));
+    g_assert_cmphex(nb_erase_regions, ==,
+                    !!c->nb_blocs[0] + !!c->nb_blocs[1] + !!c->nb_blocs[2] +
+                    !!c->nb_blocs[3]);
+
+    /* Check device length. */
+    uint32_t device_len = 1 << flash_query_1(c, FLASH_ADDR(0x27));
+    g_assert_cmphex(device_len, ==, UNIFORM_FLASH_SIZE);
+
+    /* Check that erase suspend to read/write is supported. */
+    uint16_t pri = flash_query_1(c, FLASH_ADDR(0x15)) +
+                   (flash_query_1(c, FLASH_ADDR(0x16)) << 8);
+    g_assert_cmpint(pri, >=, 0x2D + 4 * nb_erase_regions);
+    g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 0)), ==, replicate(c, 'P'));
+    g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 1)), ==, replicate(c, 'R'));
+    g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 2)), ==, replicate(c, 'I'));
+    g_assert_cmpint(flash_query_1(c, FLASH_ADDR(pri + 6)), ==, 2); /* R/W */
+    reset(c);
+
+    const uint64_t dq7 = replicate(c, 0x80);
+    const uint64_t dq6 = replicate(c, 0x40);
+    const uint64_t dq3 = replicate(c, 0x08);
+    const uint64_t dq2 = replicate(c, 0x04);
+
+    uint64_t byte_addr = 0;
+    for (int region = 0; region < nb_erase_regions; ++region) {
+        uint64_t base = 0x2D + 4 * region;
+        flash_cmd(c, CFI_ADDR, CFI_CMD);
+        uint32_t nb_sectors = flash_query_1(c, FLASH_ADDR(base + 0)) +
+                              (flash_query_1(c, FLASH_ADDR(base + 1)) << 8) + 1;
+        uint32_t sector_len = (flash_query_1(c, FLASH_ADDR(base + 2)) << 8) +
+                              (flash_query_1(c, FLASH_ADDR(base + 3)) << 16);
+        g_assert_cmphex(nb_sectors, ==, c->nb_blocs[region]);
+        g_assert_cmphex(sector_len, ==, c->sector_len[region]);
+        reset(c);
+
+        /* Erase and program sector. */
+        for (uint32_t i = 0; i < nb_sectors; ++i) {
+            sector_erase(c, byte_addr);
+
+            /* Check that DQ3 is 0. */
+            g_assert_cmphex(flash_read(c, byte_addr) & dq3, ==, 0);
+            qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */
+
+            /* Check that DQ3 is 1. */
+            uint64_t status0 = flash_read(c, byte_addr);
+            g_assert_cmphex(status0 & dq3, ==, dq3);
+
+            /* DQ7 is 0 during an erase. */
+            g_assert_cmphex(status0 & dq7, ==, 0);
+            uint64_t status1 = flash_read(c, byte_addr);
+
+            /* DQ6 toggles during an erase. */
+            g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
+
+            /* Wait for erase to complete. */
+            wait_for_completion(c, byte_addr);
+
+            /* Ensure DQ6 has stopped toggling. */
+            g_assert_cmphex(flash_read(c, byte_addr), ==,
+                            flash_read(c, byte_addr));
+
+            /* Now the data should be valid. */
+            g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
+
+            /* Program a bit pattern. */
+            program(c, byte_addr, 0x55);
+            g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x55);
+            program(c, byte_addr, 0xA5);
+            g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x05);
+            byte_addr += sector_len;
+        }
+    }
+
+    /* Erase the chip. */
+    chip_erase(c);
+    /* Read toggle. */
+    uint64_t status0 = flash_read(c, 0);
+    /* DQ7 is 0 during an erase. */
+    g_assert_cmphex(status0 & dq7, ==, 0);
+    uint64_t status1 = flash_read(c, 0);
+    /* DQ6 toggles during an erase. */
+    g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
+    /* Wait for erase to complete. */
+    qtest_clock_step_next(c->qtest);
+    /* Ensure DQ6 has stopped toggling. */
+    g_assert_cmphex(flash_read(c, 0), ==, flash_read(c, 0));
+    /* Now the data should be valid. */
+
+    for (int region = 0; region < nb_erase_regions; ++region) {
+        for (uint32_t i = 0; i < c->nb_blocs[region]; ++i) {
+            uint64_t byte_addr = i * c->sector_len[region];
+            g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
+        }
+    }
+
+    /* Unlock bypass */
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, UNLOCK_BYPASS_CMD);
+    bypass_program(c, 0 * c->bank_width, 0x01);
+    bypass_program(c, 1 * c->bank_width, 0x23);
+    bypass_program(c, 2 * c->bank_width, 0x45);
+    /*
+     * Test that bypass programming, unlike normal programming can use any
+     * address for the PROGRAM_CMD.
+     */
+    flash_cmd(c, FLASH_ADDR(3 * c->bank_width), PROGRAM_CMD);
+    flash_write(c, 3 * c->bank_width, 0x67);
+    wait_for_completion(c, 3 * c->bank_width);
+    flash_cmd(c, FLASH_ADDR(0), UNLOCK_BYPASS_RESET_CMD);
+    bypass_program(c, 4 * c->bank_width, 0x89); /* Should fail. */
+    g_assert_cmphex(flash_read(c, 0 * c->bank_width), ==, 0x01);
+    g_assert_cmphex(flash_read(c, 1 * c->bank_width), ==, 0x23);
+    g_assert_cmphex(flash_read(c, 2 * c->bank_width), ==, 0x45);
+    g_assert_cmphex(flash_read(c, 3 * c->bank_width), ==, 0x67);
+    g_assert_cmphex(flash_read(c, 4 * c->bank_width), ==, bank_mask(c));
+
+    /* Test ignored high order bits of address. */
+    flash_cmd(c, FLASH_ADDR(0x5555), UNLOCK0_CMD);
+    flash_cmd(c, FLASH_ADDR(0x2AAA), UNLOCK1_CMD);
+    flash_cmd(c, FLASH_ADDR(0x5555), AUTOSELECT_CMD);
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+    reset(c);
+
+    /*
+     * Program a word on each sector, erase one or two sectors per region, and
+     * verify that all of those, and only those, are erased.
+     */
+    byte_addr = 0;
+    for (int region = 0; region < nb_erase_regions; ++region) {
+        for (int i = 0; i < config->nb_blocs[region]; ++i) {
+            program(c, byte_addr, 0);
+            byte_addr += config->sector_len[region];
+        }
+    }
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
+    unlock(c);
+    byte_addr = 0;
+    const uint64_t erase_cmd = replicate(c, SECTOR_ERASE_CMD);
+    for (int region = 0; region < nb_erase_regions; ++region) {
+        flash_write(c, byte_addr, erase_cmd);
+        if (c->nb_blocs[region] > 1) {
+            flash_write(c, byte_addr + c->sector_len[region], erase_cmd);
+        }
+        byte_addr += c->sector_len[region] * c->nb_blocs[region];
+    }
+
+    qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */
+    wait_for_completion(c, 0);
+    byte_addr = 0;
+    for (int region = 0; region < nb_erase_regions; ++region) {
+        for (int i = 0; i < config->nb_blocs[region]; ++i) {
+            if (i < 2) {
+                g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
+            } else {
+                g_assert_cmphex(flash_read(c, byte_addr), ==, 0);
+            }
+            byte_addr += config->sector_len[region];
+        }
+    }
+
+    /* Test erase suspend/resume during erase timeout. */
+    sector_erase(c, 0);
+    /*
+     * Check that DQ 3 is 0 and DQ6 and DQ2 are toggling in the sector being
+     * erased as well as in a sector not being erased.
+     */
+    byte_addr = c->sector_len[0];
+    status0 = flash_read(c, 0);
+    status1 = flash_read(c, 0);
+    g_assert_cmpint(status0 & dq3, ==, 0);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    status0 = flash_read(c, byte_addr);
+    status1 = flash_read(c, byte_addr);
+    g_assert_cmpint(status0 & dq3, ==, 0);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+
+    /*
+     * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in
+     * an erase suspended sector but that neither toggle (we should be
+     * getting data) in a sector not being erased.
+     */
+    erase_suspend(c);
+    status0 = flash_read(c, 0);
+    status1 = flash_read(c, 0);
+    g_assert_cmpint(status0 & dq6, ==, status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
+
+    /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */
+    erase_resume(c);
+    status0 = flash_read(c, 0);
+    status1 = flash_read(c, 0);
+    g_assert_cmpint(status0 & dq3, ==, dq3);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    status0 = flash_read(c, byte_addr);
+    status1 = flash_read(c, byte_addr);
+    g_assert_cmpint(status0 & dq3, ==, dq3);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    wait_for_completion(c, 0);
+
+    /* Repeat this process but this time suspend after the timeout. */
+    sector_erase(c, 0);
+    qtest_clock_step_next(c->qtest);
+    /*
+     * Check that DQ 3 is 1 and DQ6 and DQ2 are toggling in the sector being
+     * erased as well as in a sector not being erased.
+     */
+    byte_addr = c->sector_len[0];
+    status0 = flash_read(c, 0);
+    status1 = flash_read(c, 0);
+    g_assert_cmpint(status0 & dq3, ==, dq3);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    status0 = flash_read(c, byte_addr);
+    status1 = flash_read(c, byte_addr);
+    g_assert_cmpint(status0 & dq3, ==, dq3);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+
+    /*
+     * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in
+     * an erase suspended sector but that neither toggle (we should be
+     * getting data) in a sector not being erased.
+     */
+    erase_suspend(c);
+    status0 = flash_read(c, 0);
+    status1 = flash_read(c, 0);
+    g_assert_cmpint(status0 & dq6, ==, status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
+
+    /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */
+    erase_resume(c);
+    status0 = flash_read(c, 0);
+    status1 = flash_read(c, 0);
+    g_assert_cmpint(status0 & dq3, ==, dq3);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    status0 = flash_read(c, byte_addr);
+    status1 = flash_read(c, byte_addr);
+    g_assert_cmpint(status0 & dq3, ==, dq3);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    wait_for_completion(c, 0);
+
+    qtest_quit(qtest);
+}
+
+/*
+ * Test that
+ * 1. enter autoselect mode;
+ * 2. enter CFI mode; and then
+ * 3. exit CFI mode
+ * leaves the flash device in autoselect mode.
+ */
+static void test_cfi_in_autoselect(const void *opaque)
+{
+    const FlashConfig *config = opaque;
+    QTestState *qtest;
+    qtest = qtest_initf("-M musicpal"
+                        " -drive if=pflash,file=%s,format=raw,copy-on-read",
+                        image_path);
+    FlashConfig explicit_config = expand_config_defaults(config);
+    explicit_config.qtest = qtest;
+    const FlashConfig *c = &explicit_config;
+
+    /* 1. Enter autoselect. */
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD);
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+
+    /* 2. Enter CFI. */
+    flash_cmd(c, CFI_ADDR, CFI_CMD);
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
+
+    /* 3. Exit CFI. */
+    reset(c);
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+
+    qtest_quit(qtest);
+}
+
+static void cleanup(void *opaque)
+{
+    unlink(image_path);
+}
+
+/*
+ * XXX: Tests are limited to bank_width = 2 for now because that's what
+ * hw/arm/musicpal.c has.
+ */
+static const FlashConfig configuration[] = {
+    /* One x16 device. */
+    {
+        .bank_width = 2,
+    },
+    /* Nonuniform sectors (top boot). */
+    {
+        .bank_width = 2,
+        .nb_blocs = { 127, 1, 2, 1 },
+        .sector_len = { 0x10000, 0x08000, 0x02000, 0x04000 },
+    },
+    /* Nonuniform sectors (bottom boot). */
+    {
+        .bank_width = 2,
+        .nb_blocs = { 1, 2, 1, 127 },
+        .sector_len = { 0x04000, 0x02000, 0x08000, 0x10000 },
+    },
+};
+
+int main(int argc, char **argv)
+{
+    int fd = mkstemp(image_path);
+    if (fd == -1) {
+        g_printerr("Failed to create temporary file %s: %s\n", image_path,
+                   strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+    if (ftruncate(fd, UNIFORM_FLASH_SIZE) < 0) {
+        int error_code = errno;
+        close(fd);
+        unlink(image_path);
+        g_printerr("Failed to truncate file %s to %u MB: %s\n", image_path,
+                   UNIFORM_FLASH_SIZE, strerror(error_code));
+        exit(EXIT_FAILURE);
+    }
+    close(fd);
+
+    qtest_add_abrt_handler(cleanup, NULL);
+    g_test_init(&argc, &argv, NULL);
+
+    size_t nb_configurations = sizeof configuration / sizeof configuration[0];
+    for (size_t i = 0; i < nb_configurations; ++i) {
+        const FlashConfig *config = &configuration[i];
+        char *path = g_strdup_printf("pflash-cfi02"
+                                     "/geometry/%dx%x-%dx%x-%dx%x-%dx%x"
+                                     "/%d",
+                                     config->nb_blocs[0],
+                                     config->sector_len[0],
+                                     config->nb_blocs[1],
+                                     config->sector_len[1],
+                                     config->nb_blocs[2],
+                                     config->sector_len[2],
+                                     config->nb_blocs[3],
+                                     config->sector_len[3],
+                                     config->bank_width);
+        qtest_add_data_func(path, config, test_geometry);
+        g_free(path);
+    }
+
+    qtest_add_data_func("pflash-cfi02/cfi-in-autoselect", &configuration[0],
+                        test_cfi_in_autoselect);
+    int result = g_test_run();
+    cleanup(NULL);
+    return result;
+}
diff --git a/tests/qtest/pnv-xscom-test.c b/tests/qtest/pnv-xscom-test.c
new file mode 100644 (file)
index 0000000..2c46d5c
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * QTest testcase for PowerNV XSCOM bus
+ *
+ * Copyright (c) 2016, IBM Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+
+#include "libqtest.h"
+
+typedef enum PnvChipType {
+    PNV_CHIP_POWER8E,     /* AKA Murano (default) */
+    PNV_CHIP_POWER8,      /* AKA Venice */
+    PNV_CHIP_POWER8NVL,   /* AKA Naples */
+    PNV_CHIP_POWER9,      /* AKA Nimbus */
+} PnvChipType;
+
+typedef struct PnvChip {
+    PnvChipType chip_type;
+    const char *cpu_model;
+    uint64_t    xscom_base;
+    uint64_t    cfam_id;
+    uint32_t    first_core;
+} PnvChip;
+
+static const PnvChip pnv_chips[] = {
+    {
+        .chip_type  = PNV_CHIP_POWER8,
+        .cpu_model  = "POWER8",
+        .xscom_base = 0x0003fc0000000000ull,
+        .cfam_id    = 0x220ea04980000000ull,
+        .first_core = 0x1,
+    }, {
+        .chip_type  = PNV_CHIP_POWER8NVL,
+        .cpu_model  = "POWER8NVL",
+        .xscom_base = 0x0003fc0000000000ull,
+        .cfam_id    = 0x120d304980000000ull,
+        .first_core = 0x1,
+    },
+    {
+        .chip_type  = PNV_CHIP_POWER9,
+        .cpu_model  = "POWER9",
+        .xscom_base = 0x000603fc00000000ull,
+        .cfam_id    = 0x220d104900008000ull,
+        .first_core = 0x0,
+    },
+};
+
+static uint64_t pnv_xscom_addr(const PnvChip *chip, uint32_t pcba)
+{
+    uint64_t addr = chip->xscom_base;
+
+    if (chip->chip_type == PNV_CHIP_POWER9) {
+        addr |= ((uint64_t) pcba << 3);
+    } else {
+        addr |= (((uint64_t) pcba << 4) & ~0xffull) |
+            (((uint64_t) pcba << 3) & 0x78);
+    }
+    return addr;
+}
+
+static uint64_t pnv_xscom_read(QTestState *qts, const PnvChip *chip,
+                               uint32_t pcba)
+{
+    return qtest_readq(qts, pnv_xscom_addr(chip, pcba));
+}
+
+static void test_xscom_cfam_id(QTestState *qts, const PnvChip *chip)
+{
+    uint64_t f000f = pnv_xscom_read(qts, chip, 0xf000f);
+
+    g_assert_cmphex(f000f, ==, chip->cfam_id);
+}
+
+static void test_cfam_id(const void *data)
+{
+    const PnvChip *chip = data;
+    const char *machine = "powernv8";
+    QTestState *qts;
+
+    if (chip->chip_type == PNV_CHIP_POWER9) {
+        machine = "powernv9";
+    }
+
+    qts = qtest_initf("-M %s -accel tcg -cpu %s",
+                      machine, chip->cpu_model);
+    test_xscom_cfam_id(qts, chip);
+    qtest_quit(qts);
+}
+
+
+#define PNV_XSCOM_EX_CORE_BASE    0x10000000ull
+#define PNV_XSCOM_EX_BASE(core) \
+    (PNV_XSCOM_EX_CORE_BASE | ((uint64_t)(core) << 24))
+#define PNV_XSCOM_P9_EC_BASE(core) \
+    ((uint64_t)(((core) & 0x1F) + 0x20) << 24)
+
+#define PNV_XSCOM_EX_DTS_RESULT0     0x50000
+
+static void test_xscom_core(QTestState *qts, const PnvChip *chip)
+{
+    uint32_t first_core_dts0 = PNV_XSCOM_EX_DTS_RESULT0;
+    uint64_t dts0;
+
+    if (chip->chip_type != PNV_CHIP_POWER9) {
+        first_core_dts0 |= PNV_XSCOM_EX_BASE(chip->first_core);
+    } else {
+        first_core_dts0 |= PNV_XSCOM_P9_EC_BASE(chip->first_core);
+    }
+
+    dts0 = pnv_xscom_read(qts, chip, first_core_dts0);
+
+    g_assert_cmphex(dts0, ==, 0x26f024f023f0000ull);
+}
+
+static void test_core(const void *data)
+{
+    const PnvChip *chip = data;
+    QTestState *qts;
+    const char *machine = "powernv8";
+
+    if (chip->chip_type == PNV_CHIP_POWER9) {
+        machine = "powernv9";
+    }
+
+    qts = qtest_initf("-M %s -accel tcg -cpu %s",
+                      machine, chip->cpu_model);
+    test_xscom_core(qts, chip);
+    qtest_quit(qts);
+}
+
+static void add_test(const char *name, void (*test)(const void *data))
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(pnv_chips); i++) {
+        char *tname = g_strdup_printf("pnv-xscom/%s/%s", name,
+                                      pnv_chips[i].cpu_model);
+        qtest_add_data_func(tname, &pnv_chips[i], test);
+        g_free(tname);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    add_test("cfam_id", test_cfam_id);
+    add_test("core", test_core);
+    return g_test_run();
+}
diff --git a/tests/qtest/prom-env-test.c b/tests/qtest/prom-env-test.c
new file mode 100644 (file)
index 0000000..9be52c7
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Test Open-Firmware-based machines.
+ *
+ * Copyright (c) 2016, 2017 Red Hat Inc.
+ *
+ * Author:
+ *    Thomas Huth <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2
+ * or later. See the COPYING file in the top-level directory.
+ *
+ * This test is used to check that some Open Firmware based machines (i.e.
+ * OpenBIOS or SLOF) can be started successfully in TCG mode. To do this, we
+ * first put some Forth code into the "boot-command" Open Firmware environment
+ * variable. This Forth code writes a well-known magic value to a known location
+ * in memory. Then we start the guest so that the firmware can boot and finally
+ * run the Forth code.
+ * The testing code here then can finally check whether the value has been
+ * successfully written into the guest memory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+#define MAGIC   0xcafec0de
+#define ADDRESS 0x4000
+
+static void check_guest_memory(QTestState *qts)
+{
+    uint32_t signature;
+    int i;
+
+    /* Poll until code has run and modified memory. Wait at most 600 seconds */
+    for (i = 0; i < 60000; ++i) {
+        signature = qtest_readl(qts, ADDRESS);
+        if (signature == MAGIC) {
+            break;
+        }
+        g_usleep(10000);
+    }
+
+    g_assert_cmphex(signature, ==, MAGIC);
+}
+
+static void test_machine(const void *machine)
+{
+    const char *extra_args = "";
+    QTestState *qts;
+
+    /*
+     * The pseries firmware boots much faster without the default
+     * devices, it also needs Spectre/Meltdown workarounds disabled to
+     * avoid warnings with TCG
+     */
+    if (strcmp(machine, "pseries") == 0) {
+        extra_args = "-nodefaults"
+            " -machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken";
+    }
+
+    qts = qtest_initf("-M %s -accel tcg %s -prom-env 'use-nvramrc?=true' "
+                      "-prom-env 'nvramrc=%x %x l!' ", (const char *)machine,
+                      extra_args, MAGIC, ADDRESS);
+    check_guest_memory(qts);
+    qtest_quit(qts);
+}
+
+static void add_tests(const char *machines[])
+{
+    int i;
+    char *name;
+
+    for (i = 0; machines[i] != NULL; i++) {
+        name = g_strdup_printf("prom-env/%s", machines[i]);
+        qtest_add_data_func(name, machines[i], test_machine);
+        g_free(name);
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    const char *sparc_machines[] = { "SPARCbook", "Voyager", "SS-20", NULL };
+    const char *sparc64_machines[] = { "sun4u", NULL };
+    const char *ppc_machines[] = { "mac99", "g3beige", NULL };
+    const char *arch = qtest_get_arch();
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (!strcmp(arch, "ppc")) {
+        add_tests(ppc_machines);
+    } else if (!strcmp(arch, "ppc64")) {
+        add_tests(ppc_machines);
+        if (g_test_slow()) {
+            qtest_add_data_func("prom-env/pseries", "pseries", test_machine);
+        }
+    } else if (!strcmp(arch, "sparc")) {
+        add_tests(sparc_machines);
+    } else if (!strcmp(arch, "sparc64")) {
+        add_tests(sparc64_machines);
+    } else {
+        g_assert_not_reached();
+    }
+
+    return g_test_run();
+}
diff --git a/tests/qtest/pvpanic-test.c b/tests/qtest/pvpanic-test.c
new file mode 100644 (file)
index 0000000..ff9176a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * QTest testcase for PV Panic
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+
+static void test_panic(void)
+{
+    uint8_t val;
+    QDict *response, *data;
+    QTestState *qts;
+
+    qts = qtest_init("-device pvpanic");
+
+    val = qtest_inb(qts, 0x505);
+    g_assert_cmpuint(val, ==, 1);
+
+    qtest_outb(qts, 0x505, 0x1);
+
+    response = qtest_qmp_receive(qts);
+    g_assert(qdict_haskey(response, "event"));
+    g_assert_cmpstr(qdict_get_str(response, "event"), ==, "GUEST_PANICKED");
+    g_assert(qdict_haskey(response, "data"));
+    data = qdict_get_qdict(response, "data");
+    g_assert(qdict_haskey(data, "action"));
+    g_assert_cmpstr(qdict_get_str(data, "action"), ==, "pause");
+    qobject_unref(response);
+
+    qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/pvpanic/panic", test_panic);
+
+    ret = g_test_run();
+
+    return ret;
+}
diff --git a/tests/qtest/pxe-test.c b/tests/qtest/pxe-test.c
new file mode 100644 (file)
index 0000000..f68d0aa
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * PXE test cases.
+ *
+ * Copyright (c) 2016, 2017 Red Hat Inc.
+ *
+ * Authors:
+ *  Michael S. Tsirkin <[email protected]>,
+ *  Victor Kaplansky <[email protected]>
+ *  Thomas Huth <[email protected]>
+ *
+ * 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 "qemu-common.h"
+#include "libqtest.h"
+#include "boot-sector.h"
+
+#define NETNAME "net0"
+
+static char disk[] = "tests/pxe-test-disk-XXXXXX";
+
+typedef struct testdef {
+    const char *machine;    /* Machine type */
+    const char *model;      /* NIC device model */
+    const char *extra;      /* Any additional parameters */
+} testdef_t;
+
+static testdef_t x86_tests[] = {
+    { "pc", "e1000" },
+    { "pc", "virtio-net-pci" },
+    { "q35", "e1000e" },
+    { "q35", "virtio-net-pci", },
+    { NULL },
+};
+
+static testdef_t x86_tests_slow[] = {
+    { "pc", "ne2k_pci", },
+    { "pc", "i82550", },
+    { "pc", "rtl8139" },
+    { "pc", "vmxnet3" },
+    { NULL },
+};
+
+static testdef_t ppc64_tests[] = {
+    { "pseries", "spapr-vlan",
+      "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken,vsmt=8" },
+    { "pseries", "virtio-net-pci",
+      "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken,vsmt=8" },
+    { NULL },
+};
+
+static testdef_t ppc64_tests_slow[] = {
+    { "pseries", "e1000",
+      "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken,vsmt=8" },
+    { NULL },
+};
+
+static testdef_t s390x_tests[] = {
+    { "s390-ccw-virtio", "virtio-net-ccw" },
+    { NULL },
+};
+
+static void test_pxe_one(const testdef_t *test, bool ipv6)
+{
+    QTestState *qts;
+    char *args;
+    const char *extra = test->extra;
+
+    if (!extra) {
+        extra = "";
+    }
+
+    args = g_strdup_printf(
+        "-accel kvm -accel tcg -machine %s -nodefaults -boot order=n "
+        "-netdev user,id=" NETNAME ",tftp=./,bootfile=%s,ipv4=%s,ipv6=%s "
+        "-device %s,bootindex=1,netdev=" NETNAME " %s",
+        test->machine, disk, ipv6 ? "off" : "on", ipv6 ? "on" : "off",
+        test->model, extra);
+
+    qts = qtest_init(args);
+    boot_sector_test(qts);
+    qtest_quit(qts);
+    g_free(args);
+}
+
+static void test_pxe_ipv4(gconstpointer data)
+{
+    const testdef_t *test = data;
+
+    test_pxe_one(test, false);
+}
+
+static void test_pxe_ipv6(gconstpointer data)
+{
+    const testdef_t *test = data;
+
+    test_pxe_one(test, true);
+}
+
+static void test_batch(const testdef_t *tests, bool ipv6)
+{
+    int i;
+
+    for (i = 0; tests[i].machine; i++) {
+        const testdef_t *test = &tests[i];
+        char *testname;
+
+        testname = g_strdup_printf("pxe/ipv4/%s/%s",
+                                   test->machine, test->model);
+        qtest_add_data_func(testname, test, test_pxe_ipv4);
+        g_free(testname);
+
+        if (ipv6) {
+            testname = g_strdup_printf("pxe/ipv6/%s/%s",
+                                       test->machine, test->model);
+            qtest_add_data_func(testname, test, test_pxe_ipv6);
+            g_free(testname);
+        }
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    int ret;
+    const char *arch = qtest_get_arch();
+
+    ret = boot_sector_init(disk);
+    if(ret)
+        return ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        test_batch(x86_tests, false);
+        if (g_test_slow()) {
+            test_batch(x86_tests_slow, false);
+        }
+    } else if (strcmp(arch, "ppc64") == 0) {
+        test_batch(ppc64_tests, g_test_slow());
+        if (g_test_slow()) {
+            test_batch(ppc64_tests_slow, true);
+        }
+    } else if (g_str_equal(arch, "s390x")) {
+        test_batch(s390x_tests, g_test_slow());
+    }
+    ret = g_test_run();
+    boot_sector_cleanup(disk);
+    return ret;
+}
diff --git a/tests/qtest/q35-test.c b/tests/qtest/q35-test.c
new file mode 100644 (file)
index 0000000..a68183d
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * QTest testcase for Q35 northbridge
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * Author: Gerd Hoffmann <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/pci.h"
+#include "libqos/pci-pc.h"
+#include "hw/pci-host/q35.h"
+#include "qapi/qmp/qdict.h"
+
+#define TSEG_SIZE_TEST_GUEST_RAM_MBYTES 128
+
+/* @esmramc_tseg_sz: ESMRAMC.TSEG_SZ bitmask for selecting the requested TSEG
+ *                   size. Must be a subset of
+ *                   MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK.
+ *
+ * @extended_tseg_mbytes: Size of the extended TSEG. Only consulted if
+ *                        @esmramc_tseg_sz equals
+ *                        MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK precisely.
+ *
+ * @expected_tseg_mbytes: Expected guest-visible TSEG size in megabytes,
+ *                        matching @esmramc_tseg_sz and @extended_tseg_mbytes
+ *                        above.
+ */
+struct TsegSizeArgs {
+    uint8_t esmramc_tseg_sz;
+    uint16_t extended_tseg_mbytes;
+    uint16_t expected_tseg_mbytes;
+};
+typedef struct TsegSizeArgs TsegSizeArgs;
+
+static const TsegSizeArgs tseg_1mb = {
+    .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB,
+    .extended_tseg_mbytes = 0,
+    .expected_tseg_mbytes = 1,
+};
+static const TsegSizeArgs tseg_2mb = {
+    .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB,
+    .extended_tseg_mbytes = 0,
+    .expected_tseg_mbytes = 2,
+};
+static const TsegSizeArgs tseg_8mb = {
+    .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_8MB,
+    .extended_tseg_mbytes = 0,
+    .expected_tseg_mbytes = 8,
+};
+static const TsegSizeArgs tseg_ext_16mb = {
+    .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK,
+    .extended_tseg_mbytes = 16,
+    .expected_tseg_mbytes = 16,
+};
+
+static void smram_set_bit(QPCIDevice *pcidev, uint8_t mask, bool enabled)
+{
+    uint8_t smram;
+
+    smram = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM);
+    if (enabled) {
+        smram |= mask;
+    } else {
+        smram &= ~mask;
+    }
+    qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram);
+}
+
+static bool smram_test_bit(QPCIDevice *pcidev, uint8_t mask)
+{
+    uint8_t smram;
+
+    smram = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM);
+    return smram & mask;
+}
+
+static void test_smram_lock(void)
+{
+    QPCIBus *pcibus;
+    QPCIDevice *pcidev;
+    QDict *response;
+    QTestState *qts;
+
+    qts = qtest_init("-M q35");
+
+    pcibus = qpci_new_pc(qts, NULL);
+    g_assert(pcibus != NULL);
+
+    pcidev = qpci_device_find(pcibus, 0);
+    g_assert(pcidev != NULL);
+
+    /* check open is settable */
+    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, false);
+    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
+    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
+    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == true);
+
+    /* lock, check open is cleared & not settable */
+    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_LCK, true);
+    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
+    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
+    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
+
+    /* reset */
+    response = qtest_qmp(qts, "{'execute': 'system_reset', 'arguments': {} }");
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+
+    /* check open is settable again */
+    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, false);
+    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
+    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
+    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == true);
+
+    g_free(pcidev);
+    qpci_free_pc(pcibus);
+
+    qtest_quit(qts);
+}
+
+static void test_tseg_size(const void *data)
+{
+    const TsegSizeArgs *args = data;
+    QPCIBus *pcibus;
+    QPCIDevice *pcidev;
+    uint8_t smram_val;
+    uint8_t esmramc_val;
+    uint32_t ram_offs;
+    QTestState *qts;
+
+    if (args->esmramc_tseg_sz == MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK) {
+        qts = qtest_initf("-M q35 -m %uM -global mch.extended-tseg-mbytes=%u",
+                          TSEG_SIZE_TEST_GUEST_RAM_MBYTES,
+                          args->extended_tseg_mbytes);
+    } else {
+        qts = qtest_initf("-M q35 -m %uM", TSEG_SIZE_TEST_GUEST_RAM_MBYTES);
+    }
+
+    /* locate the DRAM controller */
+    pcibus = qpci_new_pc(qts, NULL);
+    g_assert(pcibus != NULL);
+    pcidev = qpci_device_find(pcibus, 0);
+    g_assert(pcidev != NULL);
+
+    /* Set TSEG size. Restrict TSEG visibility to SMM by setting T_EN. */
+    esmramc_val = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_ESMRAMC);
+    esmramc_val &= ~MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK;
+    esmramc_val |= args->esmramc_tseg_sz;
+    esmramc_val |= MCH_HOST_BRIDGE_ESMRAMC_T_EN;
+    qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_ESMRAMC, esmramc_val);
+
+    /* Enable TSEG by setting G_SMRAME. Close TSEG by setting D_CLS. */
+    smram_val = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM);
+    smram_val &= ~(MCH_HOST_BRIDGE_SMRAM_D_OPEN |
+                   MCH_HOST_BRIDGE_SMRAM_D_LCK);
+    smram_val |= (MCH_HOST_BRIDGE_SMRAM_D_CLS |
+                  MCH_HOST_BRIDGE_SMRAM_G_SMRAME);
+    qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram_val);
+
+    /* lock TSEG */
+    smram_val |= MCH_HOST_BRIDGE_SMRAM_D_LCK;
+    qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram_val);
+
+    /* Now check that the byte right before the TSEG is r/w, and that the first
+     * byte in the TSEG always reads as 0xff.
+     */
+    ram_offs = (TSEG_SIZE_TEST_GUEST_RAM_MBYTES - args->expected_tseg_mbytes) *
+               1024 * 1024 - 1;
+    g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 0);
+    qtest_writeb(qts, ram_offs, 1);
+    g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 1);
+
+    ram_offs++;
+    g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 0xff);
+    qtest_writeb(qts, ram_offs, 1);
+    g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 0xff);
+
+    g_free(pcidev);
+    qpci_free_pc(pcibus);
+    qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/q35/smram/lock", test_smram_lock);
+
+    qtest_add_data_func("/q35/tseg-size/1mb", &tseg_1mb, test_tseg_size);
+    qtest_add_data_func("/q35/tseg-size/2mb", &tseg_2mb, test_tseg_size);
+    qtest_add_data_func("/q35/tseg-size/8mb", &tseg_8mb, test_tseg_size);
+    qtest_add_data_func("/q35/tseg-size/ext/16mb", &tseg_ext_16mb,
+                        test_tseg_size);
+    return g_test_run();
+}
diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
new file mode 100644 (file)
index 0000000..9f5228c
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * QMP command test cases
+ *
+ * Copyright (c) 2017 Red Hat Inc.
+ *
+ * Authors:
+ *  Markus Armbruster <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qapi/error.h"
+#include "qapi/qapi-visit-introspect.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qobject-input-visitor.h"
+
+const char common_args[] = "-nodefaults -machine none";
+
+/* Query smoke tests */
+
+static int query_error_class(const char *cmd)
+{
+    static struct {
+        const char *cmd;
+        int err_class;
+    } fails[] = {
+        /* Success depends on build configuration: */
+#ifndef CONFIG_SPICE
+        { "query-spice", ERROR_CLASS_COMMAND_NOT_FOUND },
+#endif
+#ifndef CONFIG_VNC
+        { "query-vnc", ERROR_CLASS_GENERIC_ERROR },
+        { "query-vnc-servers", ERROR_CLASS_GENERIC_ERROR },
+#endif
+#ifndef CONFIG_REPLICATION
+        { "query-xen-replication-status", ERROR_CLASS_COMMAND_NOT_FOUND },
+#endif
+        /* Likewise, and require special QEMU command-line arguments: */
+        { "query-acpi-ospm-status", ERROR_CLASS_GENERIC_ERROR },
+        { "query-balloon", ERROR_CLASS_DEVICE_NOT_ACTIVE },
+        { "query-hotpluggable-cpus", ERROR_CLASS_GENERIC_ERROR },
+        { "query-vm-generation-id", ERROR_CLASS_GENERIC_ERROR },
+        { NULL, -1 }
+    };
+    int i;
+
+    for (i = 0; fails[i].cmd; i++) {
+        if (!strcmp(cmd, fails[i].cmd)) {
+            return fails[i].err_class;
+        }
+    }
+    return -1;
+}
+
+static void test_query(const void *data)
+{
+    const char *cmd = data;
+    int expected_error_class = query_error_class(cmd);
+    QDict *resp, *error;
+    const char *error_class;
+    QTestState *qts;
+
+    qts = qtest_init(common_args);
+
+    resp = qtest_qmp(qts, "{ 'execute': %s }", cmd);
+    error = qdict_get_qdict(resp, "error");
+    error_class = error ? qdict_get_str(error, "class") : NULL;
+
+    if (expected_error_class < 0) {
+        g_assert(qdict_haskey(resp, "return"));
+    } else {
+        g_assert(error);
+        g_assert_cmpint(qapi_enum_parse(&QapiErrorClass_lookup, error_class,
+                                        -1, &error_abort),
+                        ==, expected_error_class);
+    }
+    qobject_unref(resp);
+
+    qtest_quit(qts);
+}
+
+static bool query_is_blacklisted(const char *cmd)
+{
+    const char *blacklist[] = {
+        /* Not actually queries: */
+        "add-fd",
+        /* Success depends on target arch: */
+        "query-cpu-definitions",  /* arm, i386, ppc, s390x */
+        "query-gic-capabilities", /* arm */
+        /* Success depends on target-specific build configuration: */
+        "query-pci",              /* CONFIG_PCI */
+        /* Success depends on launching SEV guest */
+        "query-sev-launch-measure",
+        /* Success depends on Host or Hypervisor SEV support */
+        "query-sev",
+        "query-sev-capabilities",
+        NULL
+    };
+    int i;
+
+    for (i = 0; blacklist[i]; i++) {
+        if (!strcmp(cmd, blacklist[i])) {
+            return true;
+        }
+    }
+    return false;
+}
+
+typedef struct {
+    SchemaInfoList *list;
+    GHashTable *hash;
+} QmpSchema;
+
+static void qmp_schema_init(QmpSchema *schema)
+{
+    QDict *resp;
+    Visitor *qiv;
+    SchemaInfoList *tail;
+    QTestState *qts;
+
+    qts = qtest_init(common_args);
+
+    resp = qtest_qmp(qts, "{ 'execute': 'query-qmp-schema' }");
+
+    qiv = qobject_input_visitor_new(qdict_get(resp, "return"));
+    visit_type_SchemaInfoList(qiv, NULL, &schema->list, &error_abort);
+    visit_free(qiv);
+
+    qobject_unref(resp);
+    qtest_quit(qts);
+
+    schema->hash = g_hash_table_new(g_str_hash, g_str_equal);
+
+    /* Build @schema: hash table mapping entity name to SchemaInfo */
+    for (tail = schema->list; tail; tail = tail->next) {
+        g_hash_table_insert(schema->hash, tail->value->name, tail->value);
+    }
+}
+
+static SchemaInfo *qmp_schema_lookup(QmpSchema *schema, const char *name)
+{
+    return g_hash_table_lookup(schema->hash, name);
+}
+
+static void qmp_schema_cleanup(QmpSchema *schema)
+{
+    qapi_free_SchemaInfoList(schema->list);
+    g_hash_table_destroy(schema->hash);
+}
+
+static bool object_type_has_mandatory_members(SchemaInfo *type)
+{
+    SchemaInfoObjectMemberList *tail;
+
+    g_assert(type->meta_type == SCHEMA_META_TYPE_OBJECT);
+
+    for (tail = type->u.object.members; tail; tail = tail->next) {
+        if (!tail->value->has_q_default) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static void add_query_tests(QmpSchema *schema)
+{
+    SchemaInfoList *tail;
+    SchemaInfo *si, *arg_type, *ret_type;
+    char *test_name;
+
+    /* Test the query-like commands */
+    for (tail = schema->list; tail; tail = tail->next) {
+        si = tail->value;
+        if (si->meta_type != SCHEMA_META_TYPE_COMMAND) {
+            continue;
+        }
+
+        if (query_is_blacklisted(si->name)) {
+            continue;
+        }
+
+        arg_type = qmp_schema_lookup(schema, si->u.command.arg_type);
+        if (object_type_has_mandatory_members(arg_type)) {
+            continue;
+        }
+
+        ret_type = qmp_schema_lookup(schema, si->u.command.ret_type);
+        if (ret_type->meta_type == SCHEMA_META_TYPE_OBJECT
+            && !ret_type->u.object.members) {
+            continue;
+        }
+
+        test_name = g_strdup_printf("qmp/%s", si->name);
+        qtest_add_data_func(test_name, si->name, test_query);
+        g_free(test_name);
+    }
+}
+
+static void test_object_add_without_props(void)
+{
+    QTestState *qts;
+    QDict *resp;
+
+    qts = qtest_init(common_args);
+    resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':"
+                    " {'qom-type': 'memory-backend-ram', 'id': 'ram1' } }");
+    g_assert_nonnull(resp);
+    qmp_assert_error_class(resp, "GenericError");
+    qtest_quit(qts);
+}
+
+int main(int argc, char *argv[])
+{
+    QmpSchema schema;
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    qmp_schema_init(&schema);
+    add_query_tests(&schema);
+
+    qtest_add_func("qmp/object-add-without-props",
+                   test_object_add_without_props);
+    /* TODO: add coverage of generic object-add failure modes */
+
+    ret = g_test_run();
+
+    qmp_schema_cleanup(&schema);
+    return ret;
+}
diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c
new file mode 100644 (file)
index 0000000..1b0eb69
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * QMP protocol test cases
+ *
+ * Copyright (c) 2017-2018 Red Hat Inc.
+ *
+ * Authors:
+ *  Markus Armbruster <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qapi/error.h"
+#include "qapi/qapi-visit-misc.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/qmp/qstring.h"
+
+const char common_args[] = "-nodefaults -machine none";
+
+static void test_version(QObject *version)
+{
+    Visitor *v;
+    VersionInfo *vinfo;
+
+    g_assert(version);
+    v = qobject_input_visitor_new(version);
+    visit_type_VersionInfo(v, "version", &vinfo, &error_abort);
+    qapi_free_VersionInfo(vinfo);
+    visit_free(v);
+}
+
+static void assert_recovered(QTestState *qts)
+{
+    QDict *resp;
+
+    resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd' }");
+    qmp_assert_error_class(resp, "CommandNotFound");
+}
+
+static void test_malformed(QTestState *qts)
+{
+    QDict *resp;
+
+    /* syntax error */
+    qtest_qmp_send_raw(qts, "{]\n");
+    resp = qtest_qmp_receive(qts);
+    qmp_assert_error_class(resp, "GenericError");
+    assert_recovered(qts);
+
+    /* lexical error: impossible byte outside string */
+    qtest_qmp_send_raw(qts, "{\xFF");
+    resp = qtest_qmp_receive(qts);
+    qmp_assert_error_class(resp, "GenericError");
+    assert_recovered(qts);
+
+    /* lexical error: funny control character outside string */
+    qtest_qmp_send_raw(qts, "{\x01");
+    resp = qtest_qmp_receive(qts);
+    qmp_assert_error_class(resp, "GenericError");
+    assert_recovered(qts);
+
+    /* lexical error: impossible byte in string */
+    qtest_qmp_send_raw(qts, "{'bad \xFF");
+    resp = qtest_qmp_receive(qts);
+    qmp_assert_error_class(resp, "GenericError");
+    assert_recovered(qts);
+
+    /* lexical error: control character in string */
+    qtest_qmp_send_raw(qts, "{'execute': 'nonexistent', 'id':'\n");
+    resp = qtest_qmp_receive(qts);
+    qmp_assert_error_class(resp, "GenericError");
+    assert_recovered(qts);
+
+    /* lexical error: interpolation */
+    qtest_qmp_send_raw(qts, "%%p");
+    resp = qtest_qmp_receive(qts);
+    qmp_assert_error_class(resp, "GenericError");
+    assert_recovered(qts);
+
+    /* Not even a dictionary */
+    resp = qtest_qmp(qts, "null");
+    qmp_assert_error_class(resp, "GenericError");
+
+    /* No "execute" key */
+    resp = qtest_qmp(qts, "{}");
+    qmp_assert_error_class(resp, "GenericError");
+
+    /* "execute" isn't a string */
+    resp = qtest_qmp(qts, "{ 'execute': true }");
+    qmp_assert_error_class(resp, "GenericError");
+
+    /* "arguments" isn't a dictionary */
+    resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'arguments': [] }");
+    qmp_assert_error_class(resp, "GenericError");
+
+    /* extra key */
+    resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'extra': true }");
+    qmp_assert_error_class(resp, "GenericError");
+}
+
+static void test_qmp_protocol(void)
+{
+    QDict *resp, *q, *ret;
+    QList *capabilities;
+    QTestState *qts;
+
+    qts = qtest_init_without_qmp_handshake(common_args);
+
+    /* Test greeting */
+    resp = qtest_qmp_receive(qts);
+    q = qdict_get_qdict(resp, "QMP");
+    g_assert(q);
+    test_version(qdict_get(q, "version"));
+    capabilities = qdict_get_qlist(q, "capabilities");
+    g_assert(capabilities);
+    qobject_unref(resp);
+
+    /* Test valid command before handshake */
+    resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
+    qmp_assert_error_class(resp, "CommandNotFound");
+
+    /* Test malformed commands before handshake */
+    test_malformed(qts);
+
+    /* Test handshake */
+    resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
+    ret = qdict_get_qdict(resp, "return");
+    g_assert(ret && !qdict_size(ret));
+    qobject_unref(resp);
+
+    /* Test repeated handshake */
+    resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
+    qmp_assert_error_class(resp, "CommandNotFound");
+
+    /* Test valid command */
+    resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
+    test_version(qdict_get(resp, "return"));
+    qobject_unref(resp);
+
+    /* Test malformed commands */
+    test_malformed(qts);
+
+    /* Test 'id' */
+    resp = qtest_qmp(qts, "{ 'execute': 'query-name', 'id': 'cookie#1' }");
+    ret = qdict_get_qdict(resp, "return");
+    g_assert(ret);
+    g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1");
+    qobject_unref(resp);
+
+    /* Test command failure with 'id' */
+    resp = qtest_qmp(qts, "{ 'execute': 'human-monitor-command', 'id': 2 }");
+    g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2);
+    qmp_assert_error_class(resp, "GenericError");
+
+    qtest_quit(qts);
+}
+
+/* Out-of-band tests */
+
+char tmpdir[] = "/tmp/qmp-test-XXXXXX";
+char *fifo_name;
+
+static void setup_blocking_cmd(void)
+{
+    if (!mkdtemp(tmpdir)) {
+        g_error("mkdtemp: %s", strerror(errno));
+    }
+    fifo_name = g_strdup_printf("%s/fifo", tmpdir);
+    if (mkfifo(fifo_name, 0666)) {
+        g_error("mkfifo: %s", strerror(errno));
+    }
+}
+
+static void cleanup_blocking_cmd(void)
+{
+    unlink(fifo_name);
+    rmdir(tmpdir);
+}
+
+static void send_cmd_that_blocks(QTestState *s, const char *id)
+{
+    qtest_qmp_send(s, "{ 'execute': 'blockdev-add',  'id': %s,"
+                   " 'arguments': {"
+                   " 'driver': 'blkdebug', 'node-name': %s,"
+                   " 'config': %s,"
+                   " 'image': { 'driver': 'null-co', 'read-zeroes': true } } }",
+                   id, id, fifo_name);
+}
+
+static void unblock_blocked_cmd(void)
+{
+    int fd = open(fifo_name, O_WRONLY);
+    g_assert(fd >= 0);
+    close(fd);
+}
+
+static void send_oob_cmd_that_fails(QTestState *s, const char *id)
+{
+    qtest_qmp_send(s, "{ 'exec-oob': 'migrate-pause', 'id': %s }", id);
+}
+
+static void recv_cmd_id(QTestState *s, const char *id)
+{
+    QDict *resp = qtest_qmp_receive(s);
+
+    g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, id);
+    qobject_unref(resp);
+}
+
+static void test_qmp_oob(void)
+{
+    QTestState *qts;
+    QDict *resp, *q;
+    const QListEntry *entry;
+    QList *capabilities;
+    QString *qstr;
+
+    qts = qtest_init_without_qmp_handshake(common_args);
+
+    /* Check the greeting message. */
+    resp = qtest_qmp_receive(qts);
+    q = qdict_get_qdict(resp, "QMP");
+    g_assert(q);
+    capabilities = qdict_get_qlist(q, "capabilities");
+    g_assert(capabilities && !qlist_empty(capabilities));
+    entry = qlist_first(capabilities);
+    g_assert(entry);
+    qstr = qobject_to(QString, entry->value);
+    g_assert(qstr);
+    g_assert_cmpstr(qstring_get_str(qstr), ==, "oob");
+    qobject_unref(resp);
+
+    /* Try a fake capability, it should fail. */
+    resp = qtest_qmp(qts,
+                     "{ 'execute': 'qmp_capabilities', "
+                     "  'arguments': { 'enable': [ 'cap-does-not-exist' ] } }");
+    g_assert(qdict_haskey(resp, "error"));
+    qobject_unref(resp);
+
+    /* Now, enable OOB in current QMP session, it should succeed. */
+    resp = qtest_qmp(qts,
+                     "{ 'execute': 'qmp_capabilities', "
+                     "  'arguments': { 'enable': [ 'oob' ] } }");
+    g_assert(qdict_haskey(resp, "return"));
+    qobject_unref(resp);
+
+    /*
+     * Try any command that does not support OOB but with OOB flag. We
+     * should get failure.
+     */
+    resp = qtest_qmp(qts, "{ 'exec-oob': 'query-cpus' }");
+    g_assert(qdict_haskey(resp, "error"));
+    qobject_unref(resp);
+
+    /* OOB command overtakes slow in-band command */
+    setup_blocking_cmd();
+    send_cmd_that_blocks(qts, "ib-blocks-1");
+    qtest_qmp_send(qts, "{ 'execute': 'query-name', 'id': 'ib-quick-1' }");
+    send_oob_cmd_that_fails(qts, "oob-1");
+    recv_cmd_id(qts, "oob-1");
+    unblock_blocked_cmd();
+    recv_cmd_id(qts, "ib-blocks-1");
+    recv_cmd_id(qts, "ib-quick-1");
+
+    /* Even malformed in-band command fails in-band */
+    send_cmd_that_blocks(qts, "blocks-2");
+    qtest_qmp_send(qts, "{ 'id': 'err-2' }");
+    unblock_blocked_cmd();
+    recv_cmd_id(qts, "blocks-2");
+    recv_cmd_id(qts, "err-2");
+    cleanup_blocking_cmd();
+
+    qtest_quit(qts);
+}
+
+/* Preconfig tests */
+
+static void test_qmp_preconfig(void)
+{
+    QDict *rsp, *ret;
+    QTestState *qs = qtest_initf("%s --preconfig", common_args);
+
+    /* preconfig state */
+    /* enabled commands, no error expected  */
+    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-commands' }")));
+
+    /* forbidden commands, expected error */
+    g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
+
+    /* check that query-status returns preconfig state */
+    rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
+    ret = qdict_get_qdict(rsp, "return");
+    g_assert(ret);
+    g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "preconfig");
+    qobject_unref(rsp);
+
+    /* exit preconfig state */
+    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
+    qtest_qmp_eventwait(qs, "RESUME");
+
+    /* check that query-status returns running state */
+    rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
+    ret = qdict_get_qdict(rsp, "return");
+    g_assert(ret);
+    g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "running");
+    qobject_unref(rsp);
+
+    /* check that x-exit-preconfig returns error after exiting preconfig */
+    g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
+
+    /* enabled commands, no error expected  */
+    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
+
+    qtest_quit(qs);
+}
+
+static void test_qmp_missing_any_arg(void)
+{
+    QTestState *qts;
+    QDict *resp;
+
+    qts = qtest_init(common_args);
+    resp = qtest_qmp(qts, "{'execute': 'qom-set', 'arguments':"
+                     " { 'path': '/machine', 'property': 'rtc-time' } }");
+    g_assert_nonnull(resp);
+    qmp_assert_error_class(resp, "GenericError");
+    qtest_quit(qts);
+}
+
+int main(int argc, char *argv[])
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("qmp/protocol", test_qmp_protocol);
+    qtest_add_func("qmp/oob", test_qmp_oob);
+    qtest_add_func("qmp/preconfig", test_qmp_preconfig);
+    qtest_add_func("qmp/missing-any-arg", test_qmp_missing_any_arg);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/qom-test.c b/tests/qtest/qom-test.c
new file mode 100644 (file)
index 0000000..4f94cc6
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * QTest testcase for QOM
+ *
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu-common.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
+#include "qemu/cutils.h"
+#include "libqtest.h"
+
+static const char *blacklist_x86[] = {
+    "xenfv", "xenpv", NULL
+};
+
+static const struct {
+    const char *arch;
+    const char **machine;
+} blacklists[] = {
+    { "i386", blacklist_x86 },
+    { "x86_64", blacklist_x86 },
+};
+
+static bool is_blacklisted(const char *arch, const char *mach)
+{
+    int i;
+    const char **p;
+
+    for (i = 0; i < ARRAY_SIZE(blacklists); i++) {
+        if (!strcmp(blacklists[i].arch, arch)) {
+            for (p = blacklists[i].machine; *p; p++) {
+                if (!strcmp(*p, mach)) {
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+static void test_properties(QTestState *qts, const char *path, bool recurse)
+{
+    char *child_path;
+    QDict *response, *tuple, *tmp;
+    QList *list;
+    QListEntry *entry;
+
+    g_test_message("Obtaining properties of %s", path);
+    response = qtest_qmp(qts, "{ 'execute': 'qom-list',"
+                              "  'arguments': { 'path': %s } }", path);
+    g_assert(response);
+
+    if (!recurse) {
+        qobject_unref(response);
+        return;
+    }
+
+    g_assert(qdict_haskey(response, "return"));
+    list = qobject_to(QList, qdict_get(response, "return"));
+    QLIST_FOREACH_ENTRY(list, entry) {
+        tuple = qobject_to(QDict, qlist_entry_obj(entry));
+        bool is_child = strstart(qdict_get_str(tuple, "type"), "child<", NULL);
+        bool is_link = strstart(qdict_get_str(tuple, "type"), "link<", NULL);
+
+        if (is_child || is_link) {
+            child_path = g_strdup_printf("%s/%s",
+                                         path, qdict_get_str(tuple, "name"));
+            test_properties(qts, child_path, is_child);
+            g_free(child_path);
+        } else {
+            const char *prop = qdict_get_str(tuple, "name");
+            g_test_message("Testing property %s.%s", path, prop);
+            tmp = qtest_qmp(qts,
+                            "{ 'execute': 'qom-get',"
+                            "  'arguments': { 'path': %s, 'property': %s } }",
+                            path, prop);
+            /* qom-get may fail but should not, e.g., segfault. */
+            g_assert(tmp);
+            qobject_unref(tmp);
+        }
+    }
+    qobject_unref(response);
+}
+
+static void test_machine(gconstpointer data)
+{
+    const char *machine = data;
+    QDict *response;
+    QTestState *qts;
+
+    qts = qtest_initf("-machine %s", machine);
+
+    test_properties(qts, "/machine", true);
+
+    response = qtest_qmp(qts, "{ 'execute': 'quit' }");
+    g_assert(qdict_haskey(response, "return"));
+    qobject_unref(response);
+
+    qtest_quit(qts);
+    g_free((void *)machine);
+}
+
+static void add_machine_test_case(const char *mname)
+{
+    const char *arch = qtest_get_arch();
+
+    if (!is_blacklisted(arch, mname)) {
+        char *path = g_strdup_printf("qom/%s", mname);
+        qtest_add_data_func(path, g_strdup(mname), test_machine);
+        g_free(path);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_cb_for_every_machine(add_machine_test_case, g_test_quick());
+
+    return g_test_run();
+}
diff --git a/tests/qtest/qos-test.c b/tests/qtest/qos-test.c
new file mode 100644 (file)
index 0000000..fd70d73
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include <getopt.h>
+#include "libqtest-single.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qstring.h"
+#include "qemu/module.h"
+#include "qapi/qmp/qlist.h"
+#include "libqos/malloc.h"
+#include "libqos/qgraph.h"
+#include "libqos/qgraph_internal.h"
+
+static char *old_path;
+
+static void apply_to_node(const char *name, bool is_machine, bool is_abstract)
+{
+    char *machine_name = NULL;
+    if (is_machine) {
+        const char *arch = qtest_get_arch();
+        machine_name = g_strconcat(arch, "/", name, NULL);
+        name = machine_name;
+    }
+    qos_graph_node_set_availability(name, true);
+    if (is_abstract) {
+        qos_delete_cmd_line(name);
+    }
+    g_free(machine_name);
+}
+
+/**
+ * apply_to_qlist(): using QMP queries QEMU for a list of
+ * machines and devices available, and sets the respective node
+ * as true. If a node is found, also all its produced and contained
+ * child are marked available.
+ *
+ * See qos_graph_node_set_availability() for more info
+ */
+static void apply_to_qlist(QList *list, bool is_machine)
+{
+    const QListEntry *p;
+    const char *name;
+    bool abstract;
+    QDict *minfo;
+    QObject *qobj;
+    QString *qstr;
+    QBool *qbool;
+
+    for (p = qlist_first(list); p; p = qlist_next(p)) {
+        minfo = qobject_to(QDict, qlist_entry_obj(p));
+        qobj = qdict_get(minfo, "name");
+        qstr = qobject_to(QString, qobj);
+        name = qstring_get_str(qstr);
+
+        qobj = qdict_get(minfo, "abstract");
+        if (qobj) {
+            qbool = qobject_to(QBool, qobj);
+            abstract = qbool_get_bool(qbool);
+        } else {
+            abstract = false;
+        }
+
+        apply_to_node(name, is_machine, abstract);
+        qobj = qdict_get(minfo, "alias");
+        if (qobj) {
+            qstr = qobject_to(QString, qobj);
+            name = qstring_get_str(qstr);
+            apply_to_node(name, is_machine, abstract);
+        }
+    }
+}
+
+/**
+ * qos_set_machines_devices_available(): sets availability of qgraph
+ * machines and devices.
+ *
+ * This function firstly starts QEMU with "-machine none" option,
+ * and then executes the QMP protocol asking for the list of devices
+ * and machines available.
+ *
+ * for each of these items, it looks up the corresponding qgraph node,
+ * setting it as available. The list currently returns all devices that
+ * are either machines or QEDGE_CONSUMED_BY other nodes.
+ * Therefore, in order to mark all other nodes, it recursively sets
+ * all its QEDGE_CONTAINS and QEDGE_PRODUCES child as available too.
+ */
+static void qos_set_machines_devices_available(void)
+{
+    QDict *response;
+    QDict *args = qdict_new();
+    QList *list;
+
+    qtest_start("-machine none");
+    response = qmp("{ 'execute': 'query-machines' }");
+    list = qdict_get_qlist(response, "return");
+
+    apply_to_qlist(list, true);
+
+    qobject_unref(response);
+
+    qdict_put_bool(args, "abstract", true);
+    qdict_put_str(args, "implements", "device");
+
+    response = qmp("{'execute': 'qom-list-types',"
+                   " 'arguments': %p }", args);
+    g_assert(qdict_haskey(response, "return"));
+    list = qdict_get_qlist(response, "return");
+
+    apply_to_qlist(list, false);
+
+    qtest_end();
+    qobject_unref(response);
+}
+
+static QGuestAllocator *get_machine_allocator(QOSGraphObject *obj)
+{
+    return obj->get_driver(obj, "memory");
+}
+
+static void restart_qemu_or_continue(char *path)
+{
+    /* compares the current command line with the
+     * one previously executed: if they are the same,
+     * don't restart QEMU, if they differ, stop previous
+     * QEMU subprocess (if active) and start over with
+     * the new command line
+     */
+    if (g_strcmp0(old_path, path)) {
+        qtest_end();
+        qos_invalidate_command_line();
+        old_path = g_strdup(path);
+        qtest_start(path);
+    } else { /* if cmd line is the same, reset the guest */
+        qobject_unref(qmp("{ 'execute': 'system_reset' }"));
+        qmp_eventwait("RESET");
+    }
+}
+
+void qos_invalidate_command_line(void)
+{
+    g_free(old_path);
+    old_path = NULL;
+}
+
+/**
+ * allocate_objects(): given an array of nodes @arg,
+ * walks the path invoking all constructors and
+ * passing the corresponding parameter in order to
+ * continue the objects allocation.
+ * Once the test is reached, return the object it consumes.
+ *
+ * Since the machine and QEDGE_CONSUMED_BY nodes allocate
+ * memory in the constructor, g_test_queue_destroy is used so
+ * that after execution they can be safely free'd.  (The test's
+ * ->before callback is also welcome to use g_test_queue_destroy).
+ *
+ * Note: as specified in walk_path() too, @arg is an array of
+ * char *, where arg[0] is a pointer to the command line
+ * string that will be used to properly start QEMU when executing
+ * the test, and the remaining elements represent the actual objects
+ * that will be allocated.
+ */
+static void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc)
+{
+    int current = 0;
+    QGuestAllocator *alloc;
+    QOSGraphObject *parent = NULL;
+    QOSGraphEdge *edge;
+    QOSGraphNode *node;
+    void *edge_arg;
+    void *obj;
+
+    node = qos_graph_get_node(path[current]);
+    g_assert(node->type == QNODE_MACHINE);
+
+    obj = qos_machine_new(node, qts);
+    qos_object_queue_destroy(obj);
+
+    alloc = get_machine_allocator(obj);
+    if (p_alloc) {
+        *p_alloc = alloc;
+    }
+
+    for (;;) {
+        if (node->type != QNODE_INTERFACE) {
+            qos_object_start_hw(obj);
+            parent = obj;
+        }
+
+        /* follow edge and get object for next node constructor */
+        current++;
+        edge = qos_graph_get_edge(path[current - 1], path[current]);
+        node = qos_graph_get_node(path[current]);
+
+        if (node->type == QNODE_TEST) {
+            g_assert(qos_graph_edge_get_type(edge) == QEDGE_CONSUMED_BY);
+            return obj;
+        }
+
+        switch (qos_graph_edge_get_type(edge)) {
+        case QEDGE_PRODUCES:
+            obj = parent->get_driver(parent, path[current]);
+            break;
+
+        case QEDGE_CONSUMED_BY:
+            edge_arg = qos_graph_edge_get_arg(edge);
+            obj = qos_driver_new(node, obj, alloc, edge_arg);
+            qos_object_queue_destroy(obj);
+            break;
+
+        case QEDGE_CONTAINS:
+            obj = parent->get_device(parent, path[current]);
+            break;
+        }
+    }
+}
+
+/* The argument to run_one_test, which is the test function that is registered
+ * with GTest, is a vector of strings.  The first item is the initial command
+ * line (before it is modified by the test's "before" function), the remaining
+ * items are node names forming the path to the test node.
+ */
+static char **current_path;
+
+const char *qos_get_current_command_line(void)
+{
+    return current_path[0];
+}
+
+void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc)
+{
+    return allocate_objects(qts, current_path + 1, p_alloc);
+}
+
+/**
+ * run_one_test(): given an array of nodes @arg,
+ * walks the path invoking all constructors and
+ * passing the corresponding parameter in order to
+ * continue the objects allocation.
+ * Once the test is reached, its function is executed.
+ *
+ * Since the machine and QEDGE_CONSUMED_BY nodes allocate
+ * memory in the constructor, g_test_queue_destroy is used so
+ * that after execution they can be safely free'd.  The test's
+ * ->before callback is also welcome to use g_test_queue_destroy.
+ *
+ * Note: as specified in walk_path() too, @arg is an array of
+ * char *, where arg[0] is a pointer to the command line
+ * string that will be used to properly start QEMU when executing
+ * the test, and the remaining elements represent the actual objects
+ * that will be allocated.
+ *
+ * The order of execution is the following:
+ * 1) @before test function as defined in the given QOSGraphTestOptions
+ * 2) start QEMU
+ * 3) call all nodes constructor and get_driver/get_device depending on edge,
+ *    start the hardware (*_device_enable functions)
+ * 4) start test
+ */
+static void run_one_test(const void *arg)
+{
+    QOSGraphNode *test_node;
+    QGuestAllocator *alloc = NULL;
+    void *obj;
+    char **path = (char **) arg;
+    GString *cmd_line = g_string_new(path[0]);
+    void *test_arg;
+
+    /* Before test */
+    current_path = path;
+    test_node = qos_graph_get_node(path[(g_strv_length(path) - 1)]);
+    test_arg = test_node->u.test.arg;
+    if (test_node->u.test.before) {
+        test_arg = test_node->u.test.before(cmd_line, test_arg);
+    }
+
+    restart_qemu_or_continue(cmd_line->str);
+    g_string_free(cmd_line, true);
+
+    obj = qos_allocate_objects(global_qtest, &alloc);
+    test_node->u.test.function(obj, test_arg, alloc);
+}
+
+static void subprocess_run_one_test(const void *arg)
+{
+    const gchar *path = arg;
+    g_test_trap_subprocess(path, 0, 0);
+    g_test_trap_assert_passed();
+}
+
+/*
+ * in this function, 2 path will be built:
+ * path_str, a one-string path (ex "pc/i440FX-pcihost/...")
+ * path_vec, a string-array path (ex [0] = "pc", [1] = "i440FX-pcihost").
+ *
+ * path_str will be only used to build the test name, and won't need the
+ * architecture name at beginning, since it will be added by qtest_add_func().
+ *
+ * path_vec is used to allocate all constructors of the path nodes.
+ * Each name in this array except position 0 must correspond to a valid
+ * QOSGraphNode name.
+ * Position 0 is special, initially contains just the <machine> name of
+ * the node, (ex for "x86_64/pc" it will be "pc"), used to build the test
+ * path (see below). After it will contain the command line used to start
+ * qemu with all required devices.
+ *
+ * Note that the machine node name must be with format <arch>/<machine>
+ * (ex "x86_64/pc"), because it will identify the node "x86_64/pc"
+ * and start QEMU with "-M pc". For this reason,
+ * when building path_str, path_vec
+ * initially contains the <machine> at position 0 ("pc"),
+ * and the node name at position 1 (<arch>/<machine>)
+ * ("x86_64/pc"), followed by the rest of the nodes.
+ */
+static void walk_path(QOSGraphNode *orig_path, int len)
+{
+    QOSGraphNode *path;
+    QOSGraphEdge *edge;
+
+    /* etype set to QEDGE_CONSUMED_BY so that machine can add to the command line */
+    QOSEdgeType etype = QEDGE_CONSUMED_BY;
+
+    /* twice QOS_PATH_MAX_ELEMENT_SIZE since each edge can have its arg */
+    char **path_vec = g_new0(char *, (QOS_PATH_MAX_ELEMENT_SIZE * 2));
+    int path_vec_size = 0;
+
+    char *after_cmd, *before_cmd, *after_device;
+    GString *after_device_str = g_string_new("");
+    char *node_name = orig_path->name, *path_str;
+
+    GString *cmd_line = g_string_new("");
+    GString *cmd_line2 = g_string_new("");
+
+    path = qos_graph_get_node(node_name); /* root */
+    node_name = qos_graph_edge_get_dest(path->path_edge); /* machine name */
+
+    path_vec[path_vec_size++] = node_name;
+    path_vec[path_vec_size++] = qos_get_machine_type(node_name);
+
+    for (;;) {
+        path = qos_graph_get_node(node_name);
+        if (!path->path_edge) {
+            break;
+        }
+
+        node_name = qos_graph_edge_get_dest(path->path_edge);
+
+        /* append node command line + previous edge command line */
+        if (path->command_line && etype == QEDGE_CONSUMED_BY) {
+            g_string_append(cmd_line, path->command_line);
+            g_string_append(cmd_line, after_device_str->str);
+            g_string_truncate(after_device_str, 0);
+        }
+
+        path_vec[path_vec_size++] = qos_graph_edge_get_name(path->path_edge);
+        /* detect if edge has command line args */
+        after_cmd = qos_graph_edge_get_after_cmd_line(path->path_edge);
+        after_device = qos_graph_edge_get_extra_device_opts(path->path_edge);
+        before_cmd = qos_graph_edge_get_before_cmd_line(path->path_edge);
+        edge = qos_graph_get_edge(path->name, node_name);
+        etype = qos_graph_edge_get_type(edge);
+
+        if (before_cmd) {
+            g_string_append(cmd_line, before_cmd);
+        }
+        if (after_cmd) {
+            g_string_append(cmd_line2, after_cmd);
+        }
+        if (after_device) {
+            g_string_append(after_device_str, after_device);
+        }
+    }
+
+    path_vec[path_vec_size++] = NULL;
+    g_string_append(cmd_line, after_device_str->str);
+    g_string_free(after_device_str, true);
+
+    g_string_append(cmd_line, cmd_line2->str);
+    g_string_free(cmd_line2, true);
+
+    /* here position 0 has <arch>/<machine>, position 1 has <machine>.
+     * The path must not have the <arch>, qtest_add_data_func adds it.
+     */
+    path_str = g_strjoinv("/", path_vec + 1);
+
+    /* put arch/machine in position 1 so run_one_test can do its work
+     * and add the command line at position 0.
+     */
+    path_vec[1] = path_vec[0];
+    path_vec[0] = g_string_free(cmd_line, false);
+
+    if (path->u.test.subprocess) {
+        gchar *subprocess_path = g_strdup_printf("/%s/%s/subprocess",
+                                                 qtest_get_arch(), path_str);
+        qtest_add_data_func(path_str, subprocess_path, subprocess_run_one_test);
+        g_test_add_data_func(subprocess_path, path_vec, run_one_test);
+    } else {
+        qtest_add_data_func(path_str, path_vec, run_one_test);
+    }
+
+    g_free(path_str);
+}
+
+
+
+/**
+ * main(): heart of the qgraph framework.
+ *
+ * - Initializes the glib test framework
+ * - Creates the graph by invoking the various _init constructors
+ * - Starts QEMU to mark the available devices
+ * - Walks the graph, and each path is added to
+ *   the glib test framework (walk_path)
+ * - Runs the tests, calling allocate_object() and allocating the
+ *   machine/drivers/test objects
+ * - Cleans up everything
+ */
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+    qos_graph_init();
+    module_call_init(MODULE_INIT_QOM);
+    module_call_init(MODULE_INIT_LIBQOS);
+    qos_set_machines_devices_available();
+
+    qos_graph_foreach_test_path(walk_path);
+    g_test_run();
+    qtest_end();
+    qos_graph_destroy();
+    g_free(old_path);
+    return 0;
+}
diff --git a/tests/qtest/rtas-test.c b/tests/qtest/rtas-test.c
new file mode 100644 (file)
index 0000000..167b42d
--- /dev/null
@@ -0,0 +1,40 @@
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "libqtest.h"
+
+#include "libqos/libqos-spapr.h"
+#include "libqos/rtas.h"
+
+static void test_rtas_get_time_of_day(void)
+{
+    QOSState *qs;
+    struct tm tm;
+    uint32_t ns;
+    uint64_t ret;
+    time_t t1, t2;
+
+    qs = qtest_spapr_boot("-machine pseries");
+
+    t1 = time(NULL);
+    ret = qrtas_get_time_of_day(qs->qts, &qs->alloc, &tm, &ns);
+    g_assert_cmpint(ret, ==, 0);
+    t2 = mktimegm(&tm);
+    g_assert(t2 - t1 < 5); /* 5 sec max to run the test */
+
+    qtest_shutdown(qs);
+}
+
+int main(int argc, char *argv[])
+{
+    const char *arch = qtest_get_arch();
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (strcmp(arch, "ppc64")) {
+        g_printerr("RTAS requires ppc64-softmmu/qemu-system-ppc64\n");
+        exit(EXIT_FAILURE);
+    }
+    qtest_add_func("rtas/get-time-of-day", test_rtas_get_time_of_day);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/rtc-test.c b/tests/qtest/rtc-test.c
new file mode 100644 (file)
index 0000000..c7af34f
--- /dev/null
@@ -0,0 +1,720 @@
+/*
+ * QTest testcase for the MC146818 real-time clock
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Anthony Liguori   <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqtest-single.h"
+#include "qemu/timer.h"
+#include "hw/rtc/mc146818rtc.h"
+#include "hw/rtc/mc146818rtc_regs.h"
+
+#define UIP_HOLD_LENGTH           (8 * NANOSECONDS_PER_SECOND / 32768)
+
+static uint8_t base = 0x70;
+
+static int bcd2dec(int value)
+{
+    return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
+}
+
+static uint8_t cmos_read(uint8_t reg)
+{
+    outb(base + 0, reg);
+    return inb(base + 1);
+}
+
+static void cmos_write(uint8_t reg, uint8_t val)
+{
+    outb(base + 0, reg);
+    outb(base + 1, val);
+}
+
+static int tm_cmp(struct tm *lhs, struct tm *rhs)
+{
+    time_t a, b;
+    struct tm d1, d2;
+
+    memcpy(&d1, lhs, sizeof(d1));
+    memcpy(&d2, rhs, sizeof(d2));
+
+    a = mktime(&d1);
+    b = mktime(&d2);
+
+    if (a < b) {
+        return -1;
+    } else if (a > b) {
+        return 1;
+    }
+
+    return 0;
+}
+
+#if 0
+static void print_tm(struct tm *tm)
+{
+    printf("%04d-%02d-%02d %02d:%02d:%02d\n",
+           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+           tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
+}
+#endif
+
+static void cmos_get_date_time(struct tm *date)
+{
+    int base_year = 2000, hour_offset;
+    int sec, min, hour, mday, mon, year;
+    time_t ts;
+    struct tm dummy;
+
+    sec = cmos_read(RTC_SECONDS);
+    min = cmos_read(RTC_MINUTES);
+    hour = cmos_read(RTC_HOURS);
+    mday = cmos_read(RTC_DAY_OF_MONTH);
+    mon = cmos_read(RTC_MONTH);
+    year = cmos_read(RTC_YEAR);
+
+    if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) {
+        sec = bcd2dec(sec);
+        min = bcd2dec(min);
+        hour = bcd2dec(hour);
+        mday = bcd2dec(mday);
+        mon = bcd2dec(mon);
+        year = bcd2dec(year);
+        hour_offset = 80;
+    } else {
+        hour_offset = 0x80;
+    }
+
+    if ((cmos_read(0x0B) & REG_B_24H) == 0) {
+        if (hour >= hour_offset) {
+            hour -= hour_offset;
+            hour += 12;
+        }
+    }
+
+    ts = time(NULL);
+    localtime_r(&ts, &dummy);
+
+    date->tm_isdst = dummy.tm_isdst;
+    date->tm_sec = sec;
+    date->tm_min = min;
+    date->tm_hour = hour;
+    date->tm_mday = mday;
+    date->tm_mon = mon - 1;
+    date->tm_year = base_year + year - 1900;
+#ifndef __sun__
+    date->tm_gmtoff = 0;
+#endif
+
+    ts = mktime(date);
+}
+
+static void check_time(int wiggle)
+{
+    struct tm start, date[4], end;
+    struct tm *datep;
+    time_t ts;
+
+    /*
+     * This check assumes a few things.  First, we cannot guarantee that we get
+     * a consistent reading from the wall clock because we may hit an edge of
+     * the clock while reading.  To work around this, we read four clock readings
+     * such that at least two of them should match.  We need to assume that one
+     * reading is corrupt so we need four readings to ensure that we have at
+     * least two consecutive identical readings
+     *
+     * It's also possible that we'll cross an edge reading the host clock so
+     * simply check to make sure that the clock reading is within the period of
+     * when we expect it to be.
+     */
+
+    ts = time(NULL);
+    gmtime_r(&ts, &start);
+
+    cmos_get_date_time(&date[0]);
+    cmos_get_date_time(&date[1]);
+    cmos_get_date_time(&date[2]);
+    cmos_get_date_time(&date[3]);
+
+    ts = time(NULL);
+    gmtime_r(&ts, &end);
+
+    if (tm_cmp(&date[0], &date[1]) == 0) {
+        datep = &date[0];
+    } else if (tm_cmp(&date[1], &date[2]) == 0) {
+        datep = &date[1];
+    } else if (tm_cmp(&date[2], &date[3]) == 0) {
+        datep = &date[2];
+    } else {
+        g_assert_not_reached();
+    }
+
+    if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
+        long t, s;
+
+        start.tm_isdst = datep->tm_isdst;
+
+        t = (long)mktime(datep);
+        s = (long)mktime(&start);
+        if (t < s) {
+            g_test_message("RTC is %ld second(s) behind wall-clock", (s - t));
+        } else {
+            g_test_message("RTC is %ld second(s) ahead of wall-clock", (t - s));
+        }
+
+        g_assert_cmpint(ABS(t - s), <=, wiggle);
+    }
+}
+
+static int wiggle = 2;
+
+static void set_year_20xx(void)
+{
+    /* Set BCD mode */
+    cmos_write(RTC_REG_B, REG_B_24H);
+    cmos_write(RTC_REG_A, 0x76);
+    cmos_write(RTC_YEAR, 0x11);
+    cmos_write(RTC_CENTURY, 0x20);
+    cmos_write(RTC_MONTH, 0x02);
+    cmos_write(RTC_DAY_OF_MONTH, 0x02);
+    cmos_write(RTC_HOURS, 0x02);
+    cmos_write(RTC_MINUTES, 0x04);
+    cmos_write(RTC_SECONDS, 0x58);
+    cmos_write(RTC_REG_A, 0x26);
+
+    g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
+    g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
+    g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
+    g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
+    g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
+    g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11);
+    g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
+
+    if (sizeof(time_t) == 4) {
+        return;
+    }
+
+    /* Set a date in 2080 to ensure there is no year-2038 overflow.  */
+    cmos_write(RTC_REG_A, 0x76);
+    cmos_write(RTC_YEAR, 0x80);
+    cmos_write(RTC_REG_A, 0x26);
+
+    g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
+    g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
+    g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
+    g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
+    g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
+    g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x80);
+    g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
+
+    cmos_write(RTC_REG_A, 0x76);
+    cmos_write(RTC_YEAR, 0x11);
+    cmos_write(RTC_REG_A, 0x26);
+
+    g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
+    g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
+    g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
+    g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
+    g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
+    g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11);
+    g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
+}
+
+static void set_year_1980(void)
+{
+    /* Set BCD mode */
+    cmos_write(RTC_REG_B, REG_B_24H);
+    cmos_write(RTC_REG_A, 0x76);
+    cmos_write(RTC_YEAR, 0x80);
+    cmos_write(RTC_CENTURY, 0x19);
+    cmos_write(RTC_MONTH, 0x02);
+    cmos_write(RTC_DAY_OF_MONTH, 0x02);
+    cmos_write(RTC_HOURS, 0x02);
+    cmos_write(RTC_MINUTES, 0x04);
+    cmos_write(RTC_SECONDS, 0x58);
+    cmos_write(RTC_REG_A, 0x26);
+
+    g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
+    g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
+    g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
+    g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
+    g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
+    g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x80);
+    g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x19);
+}
+
+static void bcd_check_time(void)
+{
+    /* Set BCD mode */
+    cmos_write(RTC_REG_B, REG_B_24H);
+    check_time(wiggle);
+}
+
+static void dec_check_time(void)
+{
+    /* Set DEC mode */
+    cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM);
+    check_time(wiggle);
+}
+
+static void alarm_time(void)
+{
+    struct tm now;
+    time_t ts;
+    int i;
+
+    ts = time(NULL);
+    gmtime_r(&ts, &now);
+
+    /* set DEC mode */
+    cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM);
+
+    g_assert(!get_irq(RTC_ISA_IRQ));
+    cmos_read(RTC_REG_C);
+
+    now.tm_sec = (now.tm_sec + 2) % 60;
+    cmos_write(RTC_SECONDS_ALARM, now.tm_sec);
+    cmos_write(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE);
+    cmos_write(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE);
+    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
+
+    for (i = 0; i < 2 + wiggle; i++) {
+        if (get_irq(RTC_ISA_IRQ)) {
+            break;
+        }
+
+        clock_step(1000000000);
+    }
+
+    g_assert(get_irq(RTC_ISA_IRQ));
+    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
+    g_assert(cmos_read(RTC_REG_C) == 0);
+}
+
+static void set_time_regs(int h, int m, int s)
+{
+    cmos_write(RTC_HOURS, h);
+    cmos_write(RTC_MINUTES, m);
+    cmos_write(RTC_SECONDS, s);
+}
+
+static void set_time(int mode, int h, int m, int s)
+{
+    cmos_write(RTC_REG_B, mode);
+    cmos_write(RTC_REG_A, 0x76);
+    set_time_regs(h, m, s);
+    cmos_write(RTC_REG_A, 0x26);
+}
+
+static void set_datetime_bcd(int h, int min, int s, int d, int m, int y)
+{
+    cmos_write(RTC_HOURS, h);
+    cmos_write(RTC_MINUTES, min);
+    cmos_write(RTC_SECONDS, s);
+    cmos_write(RTC_YEAR, y & 0xFF);
+    cmos_write(RTC_CENTURY, y >> 8);
+    cmos_write(RTC_MONTH, m);
+    cmos_write(RTC_DAY_OF_MONTH, d);
+}
+
+static void set_datetime_dec(int h, int min, int s, int d, int m, int y)
+{
+    cmos_write(RTC_HOURS, h);
+    cmos_write(RTC_MINUTES, min);
+    cmos_write(RTC_SECONDS, s);
+    cmos_write(RTC_YEAR, y % 100);
+    cmos_write(RTC_CENTURY, y / 100);
+    cmos_write(RTC_MONTH, m);
+    cmos_write(RTC_DAY_OF_MONTH, d);
+}
+
+static void set_datetime(int mode, int h, int min, int s, int d, int m, int y)
+{
+    cmos_write(RTC_REG_B, mode);
+
+    cmos_write(RTC_REG_A, 0x76);
+    if (mode & REG_B_DM) {
+        set_datetime_dec(h, min, s, d, m, y);
+    } else {
+        set_datetime_bcd(h, min, s, d, m, y);
+    }
+    cmos_write(RTC_REG_A, 0x26);
+}
+
+#define assert_time(h, m, s) \
+    do { \
+        g_assert_cmpint(cmos_read(RTC_HOURS), ==, h); \
+        g_assert_cmpint(cmos_read(RTC_MINUTES), ==, m); \
+        g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \
+    } while(0)
+
+#define assert_datetime_bcd(h, min, s, d, m, y) \
+    do { \
+        g_assert_cmpint(cmos_read(RTC_HOURS), ==, h); \
+        g_assert_cmpint(cmos_read(RTC_MINUTES), ==, min); \
+        g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \
+        g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, d); \
+        g_assert_cmpint(cmos_read(RTC_MONTH), ==, m); \
+        g_assert_cmpint(cmos_read(RTC_YEAR), ==, (y & 0xFF)); \
+        g_assert_cmpint(cmos_read(RTC_CENTURY), ==, (y >> 8)); \
+    } while(0)
+
+static void basic_12h_bcd(void)
+{
+    /* set BCD 12 hour mode */
+    set_time(0, 0x81, 0x59, 0x00);
+    clock_step(1000000000LL);
+    assert_time(0x81, 0x59, 0x01);
+    clock_step(59000000000LL);
+    assert_time(0x82, 0x00, 0x00);
+
+    /* test BCD wraparound */
+    set_time(0, 0x09, 0x59, 0x59);
+    clock_step(60000000000LL);
+    assert_time(0x10, 0x00, 0x59);
+
+    /* 12 AM -> 1 AM */
+    set_time(0, 0x12, 0x59, 0x59);
+    clock_step(1000000000LL);
+    assert_time(0x01, 0x00, 0x00);
+
+    /* 12 PM -> 1 PM */
+    set_time(0, 0x92, 0x59, 0x59);
+    clock_step(1000000000LL);
+    assert_time(0x81, 0x00, 0x00);
+
+    /* 11 AM -> 12 PM */
+    set_time(0, 0x11, 0x59, 0x59);
+    clock_step(1000000000LL);
+    assert_time(0x92, 0x00, 0x00);
+    /* TODO: test day wraparound */
+
+    /* 11 PM -> 12 AM */
+    set_time(0, 0x91, 0x59, 0x59);
+    clock_step(1000000000LL);
+    assert_time(0x12, 0x00, 0x00);
+    /* TODO: test day wraparound */
+}
+
+static void basic_12h_dec(void)
+{
+    /* set decimal 12 hour mode */
+    set_time(REG_B_DM, 0x81, 59, 0);
+    clock_step(1000000000LL);
+    assert_time(0x81, 59, 1);
+    clock_step(59000000000LL);
+    assert_time(0x82, 0, 0);
+
+    /* 12 PM -> 1 PM */
+    set_time(REG_B_DM, 0x8c, 59, 59);
+    clock_step(1000000000LL);
+    assert_time(0x81, 0, 0);
+
+    /* 12 AM -> 1 AM */
+    set_time(REG_B_DM, 0x0c, 59, 59);
+    clock_step(1000000000LL);
+    assert_time(0x01, 0, 0);
+
+    /* 11 AM -> 12 PM */
+    set_time(REG_B_DM, 0x0b, 59, 59);
+    clock_step(1000000000LL);
+    assert_time(0x8c, 0, 0);
+
+    /* 11 PM -> 12 AM */
+    set_time(REG_B_DM, 0x8b, 59, 59);
+    clock_step(1000000000LL);
+    assert_time(0x0c, 0, 0);
+    /* TODO: test day wraparound */
+}
+
+static void basic_24h_bcd(void)
+{
+    /* set BCD 24 hour mode */
+    set_time(REG_B_24H, 0x09, 0x59, 0x00);
+    clock_step(1000000000LL);
+    assert_time(0x09, 0x59, 0x01);
+    clock_step(59000000000LL);
+    assert_time(0x10, 0x00, 0x00);
+
+    /* test BCD wraparound */
+    set_time(REG_B_24H, 0x09, 0x59, 0x00);
+    clock_step(60000000000LL);
+    assert_time(0x10, 0x00, 0x00);
+
+    /* TODO: test day wraparound */
+    set_time(REG_B_24H, 0x23, 0x59, 0x00);
+    clock_step(60000000000LL);
+    assert_time(0x00, 0x00, 0x00);
+}
+
+static void basic_24h_dec(void)
+{
+    /* set decimal 24 hour mode */
+    set_time(REG_B_24H | REG_B_DM, 9, 59, 0);
+    clock_step(1000000000LL);
+    assert_time(9, 59, 1);
+    clock_step(59000000000LL);
+    assert_time(10, 0, 0);
+
+    /* test BCD wraparound */
+    set_time(REG_B_24H | REG_B_DM, 9, 59, 0);
+    clock_step(60000000000LL);
+    assert_time(10, 0, 0);
+
+    /* TODO: test day wraparound */
+    set_time(REG_B_24H | REG_B_DM, 23, 59, 0);
+    clock_step(60000000000LL);
+    assert_time(0, 0, 0);
+}
+
+static void am_pm_alarm(void)
+{
+    cmos_write(RTC_MINUTES_ALARM, 0xC0);
+    cmos_write(RTC_SECONDS_ALARM, 0xC0);
+
+    /* set BCD 12 hour mode */
+    cmos_write(RTC_REG_B, 0);
+
+    /* Set time and alarm hour.  */
+    cmos_write(RTC_REG_A, 0x76);
+    cmos_write(RTC_HOURS_ALARM, 0x82);
+    cmos_write(RTC_HOURS, 0x81);
+    cmos_write(RTC_MINUTES, 0x59);
+    cmos_write(RTC_SECONDS, 0x00);
+    cmos_read(RTC_REG_C);
+    cmos_write(RTC_REG_A, 0x26);
+
+    /* Check that alarm triggers when AM/PM is set.  */
+    clock_step(60000000000LL);
+    g_assert(cmos_read(RTC_HOURS) == 0x82);
+    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
+
+    /*
+     * Each of the following two tests takes over 60 seconds due to the time
+     * needed to report the PIT interrupts.  Unfortunately, our PIT device
+     * model keeps counting even when GATE=0, so we cannot simply disable
+     * it in main().
+     */
+    if (g_test_quick()) {
+        return;
+    }
+
+    /* set DEC 12 hour mode */
+    cmos_write(RTC_REG_B, REG_B_DM);
+
+    /* Set time and alarm hour.  */
+    cmos_write(RTC_REG_A, 0x76);
+    cmos_write(RTC_HOURS_ALARM, 0x82);
+    cmos_write(RTC_HOURS, 3);
+    cmos_write(RTC_MINUTES, 0);
+    cmos_write(RTC_SECONDS, 0);
+    cmos_read(RTC_REG_C);
+    cmos_write(RTC_REG_A, 0x26);
+
+    /* Check that alarm triggers.  */
+    clock_step(3600 * 11 * 1000000000LL);
+    g_assert(cmos_read(RTC_HOURS) == 0x82);
+    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
+
+    /* Same as above, with inverted HOURS and HOURS_ALARM.  */
+    cmos_write(RTC_REG_A, 0x76);
+    cmos_write(RTC_HOURS_ALARM, 2);
+    cmos_write(RTC_HOURS, 3);
+    cmos_write(RTC_MINUTES, 0);
+    cmos_write(RTC_SECONDS, 0);
+    cmos_read(RTC_REG_C);
+    cmos_write(RTC_REG_A, 0x26);
+
+    /* Check that alarm does not trigger if hours differ only by AM/PM.  */
+    clock_step(3600 * 11 * 1000000000LL);
+    g_assert(cmos_read(RTC_HOURS) == 0x82);
+    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) == 0);
+}
+
+/* success if no crash or abort */
+static void fuzz_registers(void)
+{
+    unsigned int i;
+
+    for (i = 0; i < 1000; i++) {
+        uint8_t reg, val;
+
+        reg = (uint8_t)g_test_rand_int_range(0, 16);
+        val = (uint8_t)g_test_rand_int_range(0, 256);
+
+        cmos_write(reg, val);
+        cmos_read(reg);
+    }
+}
+
+static void register_b_set_flag(void)
+{
+    if (cmos_read(RTC_REG_A) & REG_A_UIP) {
+        clock_step(UIP_HOLD_LENGTH + NANOSECONDS_PER_SECOND / 5);
+    }
+    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
+
+    /* Enable binary-coded decimal (BCD) mode and SET flag in Register B*/
+    cmos_write(RTC_REG_B, REG_B_24H | REG_B_SET);
+
+    set_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
+
+    assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
+
+    /* Since SET flag is still enabled, time does not advance. */
+    clock_step(1000000000LL);
+    assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
+
+    /* Disable SET flag in Register B */
+    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_SET);
+
+    assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
+
+    /* Since SET flag is disabled, the clock now advances.  */
+    clock_step(1000000000LL);
+    assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011);
+}
+
+static void divider_reset(void)
+{
+    /* Enable binary-coded decimal (BCD) mode in Register B*/
+    cmos_write(RTC_REG_B, REG_B_24H);
+
+    /* Enter divider reset */
+    cmos_write(RTC_REG_A, 0x76);
+    set_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
+
+    assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
+
+    /* Since divider reset flag is still enabled, these are equality checks. */
+    clock_step(1000000000LL);
+    assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
+
+    /* The first update ends 500 ms after divider reset */
+    cmos_write(RTC_REG_A, 0x26);
+    clock_step(500000000LL - UIP_HOLD_LENGTH - 1);
+    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
+    assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
+
+    clock_step(1);
+    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, !=, 0);
+    clock_step(UIP_HOLD_LENGTH);
+    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
+
+    assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011);
+}
+
+static void uip_stuck(void)
+{
+    set_datetime(REG_B_24H, 0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
+
+    /* The first update ends 500 ms after divider reset */
+    (void)cmos_read(RTC_REG_C);
+    clock_step(500000000LL);
+    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
+    assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011);
+
+    /* UF is now set.  */
+    cmos_write(RTC_HOURS_ALARM, 0x02);
+    cmos_write(RTC_MINUTES_ALARM, 0xC0);
+    cmos_write(RTC_SECONDS_ALARM, 0xC0);
+
+    /* Because the alarm will fire soon, reading register A will latch UIP.  */
+    clock_step(1000000000LL - UIP_HOLD_LENGTH / 2);
+    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, !=, 0);
+
+    /* Move the alarm far away.  This must not cause UIP to remain stuck!  */
+    cmos_write(RTC_HOURS_ALARM, 0x03);
+    clock_step(UIP_HOLD_LENGTH);
+    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
+}
+
+#define RTC_PERIOD_CODE1    13   /* 8 Hz */
+#define RTC_PERIOD_CODE2    15   /* 2 Hz */
+
+#define RTC_PERIOD_TEST_NR  50
+
+static uint64_t wait_periodic_interrupt(uint64_t real_time)
+{
+    while (!get_irq(RTC_ISA_IRQ)) {
+        real_time = clock_step_next();
+    }
+
+    g_assert((cmos_read(RTC_REG_C) & REG_C_PF) != 0);
+    return real_time;
+}
+
+static void periodic_timer(void)
+{
+    int i;
+    uint64_t period_clocks, period_time, start_time, real_time;
+
+    /* disable all interrupts. */
+    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) &
+                                   ~(REG_B_PIE | REG_B_AIE | REG_B_UIE));
+    cmos_write(RTC_REG_A, RTC_PERIOD_CODE1);
+    /* enable periodic interrupt after properly configure the period. */
+    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_PIE);
+
+    start_time = real_time = clock_step_next();
+
+    for (i = 0; i < RTC_PERIOD_TEST_NR; i++) {
+        cmos_write(RTC_REG_A, RTC_PERIOD_CODE1);
+        real_time = wait_periodic_interrupt(real_time);
+        cmos_write(RTC_REG_A, RTC_PERIOD_CODE2);
+        real_time = wait_periodic_interrupt(real_time);
+    }
+
+    period_clocks = periodic_period_to_clock(RTC_PERIOD_CODE1) +
+                       periodic_period_to_clock(RTC_PERIOD_CODE2);
+    period_clocks *= RTC_PERIOD_TEST_NR;
+    period_time = periodic_clock_to_ns(period_clocks);
+
+    real_time -= start_time;
+    g_assert_cmpint(ABS((int64_t)(real_time - period_time)), <=,
+                    NANOSECONDS_PER_SECOND * 0.5);
+}
+
+int main(int argc, char **argv)
+{
+    QTestState *s = NULL;
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    s = qtest_start("-rtc clock=vm");
+    qtest_irq_intercept_in(s, "ioapic");
+
+    qtest_add_func("/rtc/check-time/bcd", bcd_check_time);
+    qtest_add_func("/rtc/check-time/dec", dec_check_time);
+    qtest_add_func("/rtc/alarm/interrupt", alarm_time);
+    qtest_add_func("/rtc/alarm/am-pm", am_pm_alarm);
+    qtest_add_func("/rtc/basic/dec-24h", basic_24h_dec);
+    qtest_add_func("/rtc/basic/bcd-24h", basic_24h_bcd);
+    qtest_add_func("/rtc/basic/dec-12h", basic_12h_dec);
+    qtest_add_func("/rtc/basic/bcd-12h", basic_12h_bcd);
+    qtest_add_func("/rtc/set-year/20xx", set_year_20xx);
+    qtest_add_func("/rtc/set-year/1980", set_year_1980);
+    qtest_add_func("/rtc/update/register_b_set_flag", register_b_set_flag);
+    qtest_add_func("/rtc/update/divider-reset", divider_reset);
+    qtest_add_func("/rtc/update/uip-stuck", uip_stuck);
+    qtest_add_func("/rtc/misc/fuzz-registers", fuzz_registers);
+    qtest_add_func("/rtc/periodic/interrupt", periodic_timer);
+
+    ret = g_test_run();
+
+    if (s) {
+        qtest_quit(s);
+    }
+
+    return ret;
+}
diff --git a/tests/qtest/rtl8139-test.c b/tests/qtest/rtl8139-test.c
new file mode 100644 (file)
index 0000000..4506049
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * QTest testcase for Realtek 8139 NIC
+ *
+ * Copyright (c) 2013-2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "libqos/pci-pc.h"
+#include "qemu/timer.h"
+#include "qemu-common.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void nop(void)
+{
+}
+
+#define CLK 33333333
+
+static QPCIBus *pcibus;
+static QPCIDevice *dev;
+static QPCIBar dev_bar;
+
+static void save_fn(QPCIDevice *dev, int devfn, void *data)
+{
+    QPCIDevice **pdev = (QPCIDevice **) data;
+
+    *pdev = dev;
+}
+
+static QPCIDevice *get_device(void)
+{
+    QPCIDevice *dev;
+
+    pcibus = qpci_new_pc(global_qtest, NULL);
+    qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev);
+    g_assert(dev != NULL);
+
+    return dev;
+}
+
+#define PORT(name, len, val) \
+static unsigned __attribute__((unused)) in_##name(void) \
+{ \
+    unsigned res = qpci_io_read##len(dev, dev_bar, (val));     \
+    g_test_message("*%s -> %x", #name, res); \
+    return res; \
+} \
+static void out_##name(unsigned v) \
+{ \
+    g_test_message("%x -> *%s", v, #name); \
+    qpci_io_write##len(dev, dev_bar, (val), v);        \
+}
+
+PORT(Timer, l, 0x48)
+PORT(IntrMask, w, 0x3c)
+PORT(IntrStatus, w, 0x3E)
+PORT(TimerInt, l, 0x54)
+
+#define fatal(...) do { g_test_message(__VA_ARGS__); g_assert(0); } while (0)
+
+static void test_timer(void)
+{
+    const unsigned from = 0.95 * CLK;
+    const unsigned to = 1.6 * CLK;
+    unsigned prev, curr, next;
+    unsigned cnt, diff;
+
+    out_IntrMask(0);
+
+    in_IntrStatus();
+    in_Timer();
+    in_Timer();
+
+    /* Test 1. test counter continue and continue */
+    out_TimerInt(0); /* disable timer */
+    out_IntrStatus(0x4000);
+    out_Timer(12345); /* reset timer to 0 */
+    curr = in_Timer();
+    if (curr > 0.1 * CLK) {
+        fatal("time too big %u\n", curr);
+    }
+    for (cnt = 0; ; ) {
+        clock_step(1 * NANOSECONDS_PER_SECOND);
+        prev = curr;
+        curr = in_Timer();
+
+        /* test skip is in a specific range */
+        diff = (curr-prev) & 0xffffffffu;
+        if (diff < from || diff > to) {
+            fatal("Invalid diff %u (%u-%u)\n", diff, from, to);
+        }
+        if (curr < prev && ++cnt == 3) {
+            break;
+        }
+    }
+
+    /* Test 2. Check we didn't get an interrupt with TimerInt == 0 */
+    if (in_IntrStatus() & 0x4000) {
+        fatal("got an interrupt\n");
+    }
+
+    /* Test 3. Setting TimerInt to 1 and Timer to 0 get interrupt */
+    out_TimerInt(1);
+    out_Timer(0);
+    clock_step(40);
+    if ((in_IntrStatus() & 0x4000) == 0) {
+        fatal("we should have an interrupt here!\n");
+    }
+
+    /* Test 3. Check acknowledge */
+    out_IntrStatus(0x4000);
+    if (in_IntrStatus() & 0x4000) {
+        fatal("got an interrupt\n");
+    }
+
+    /* Test. Status set after Timer reset */
+    out_Timer(0);
+    out_TimerInt(0);
+    out_IntrStatus(0x4000);
+    curr = in_Timer();
+    out_TimerInt(curr + 0.5 * CLK);
+    clock_step(1 * NANOSECONDS_PER_SECOND);
+    out_Timer(0);
+    if ((in_IntrStatus() & 0x4000) == 0) {
+        fatal("we should have an interrupt here!\n");
+    }
+
+    /* Test. Status set after TimerInt reset */
+    out_Timer(0);
+    out_TimerInt(0);
+    out_IntrStatus(0x4000);
+    curr = in_Timer();
+    out_TimerInt(curr + 0.5 * CLK);
+    clock_step(1 * NANOSECONDS_PER_SECOND);
+    out_TimerInt(0);
+    if ((in_IntrStatus() & 0x4000) == 0) {
+        fatal("we should have an interrupt here!\n");
+    }
+
+    /* Test 4. Increment TimerInt we should see an interrupt */
+    curr = in_Timer();
+    next = curr + 5.0 * CLK;
+    out_TimerInt(next);
+    for (cnt = 0; ; ) {
+        clock_step(1 * NANOSECONDS_PER_SECOND);
+        prev = curr;
+        curr = in_Timer();
+        diff = (curr-prev) & 0xffffffffu;
+        if (diff < from || diff > to) {
+            fatal("Invalid diff %u (%u-%u)\n", diff, from, to);
+        }
+        if (cnt < 3 && curr > next) {
+            if ((in_IntrStatus() & 0x4000) == 0) {
+                fatal("we should have an interrupt here!\n");
+            }
+            out_IntrStatus(0x4000);
+            next = curr + 5.0 * CLK;
+            out_TimerInt(next);
+            if (++cnt == 3) {
+                out_TimerInt(1);
+            }
+        /* Test 5. Second time we pass from 0 should see an interrupt */
+        } else if (cnt >= 3 && curr < prev) {
+            /* here we should have an interrupt */
+            if ((in_IntrStatus() & 0x4000) == 0) {
+                fatal("we should have an interrupt here!\n");
+            }
+            out_IntrStatus(0x4000);
+            if (++cnt == 5) {
+                break;
+            }
+        }
+    }
+
+    g_test_message("Everythink is ok!");
+}
+
+
+static void test_init(void)
+{
+    uint64_t barsize;
+
+    dev = get_device();
+
+    dev_bar = qpci_iomap(dev, 0, &barsize);
+
+    qpci_device_enable(dev);
+
+    test_timer();
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    qtest_start("-device rtl8139");
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/rtl8139/nop", nop);
+    qtest_add_func("/rtl8139/timer", test_init);
+
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
diff --git a/tests/qtest/sdhci-test.c b/tests/qtest/sdhci-test.c
new file mode 100644 (file)
index 0000000..6275e76
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * QTest testcase for SDHCI controllers
+ *
+ * Written by Philippe Mathieu-Daudé <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/registerfields.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/pci-pc.h"
+#include "hw/pci/pci.h"
+#include "libqos/qgraph.h"
+#include "libqos/sdhci.h"
+
+#define SDHC_CAPAB                      0x40
+FIELD(SDHC_CAPAB, BASECLKFREQ,               8, 8); /* since v2 */
+FIELD(SDHC_CAPAB, SDMA,                     22, 1);
+FIELD(SDHC_CAPAB, SDR,                      32, 3); /* since v3 */
+FIELD(SDHC_CAPAB, DRIVER,                   36, 3); /* since v3 */
+#define SDHC_HCVER                      0xFE
+
+static void check_specs_version(QSDHCI *s, uint8_t version)
+{
+    uint32_t v;
+
+    v = s->readw(s, SDHC_HCVER);
+    v &= 0xff;
+    v += 1;
+    g_assert_cmpuint(v, ==, version);
+}
+
+static void check_capab_capareg(QSDHCI *s, uint64_t expec_capab)
+{
+    uint64_t capab;
+
+    capab = s->readq(s, SDHC_CAPAB);
+    g_assert_cmphex(capab, ==, expec_capab);
+}
+
+static void check_capab_readonly(QSDHCI *s)
+{
+    const uint64_t vrand = 0x123456789abcdef;
+    uint64_t capab0, capab1;
+
+    capab0 = s->readq(s, SDHC_CAPAB);
+    g_assert_cmpuint(capab0, !=, vrand);
+
+    s->writeq(s, SDHC_CAPAB, vrand);
+    capab1 = s->readq(s, SDHC_CAPAB);
+    g_assert_cmpuint(capab1, !=, vrand);
+    g_assert_cmpuint(capab1, ==, capab0);
+}
+
+static void check_capab_baseclock(QSDHCI *s, uint8_t expec_freq)
+{
+    uint64_t capab, capab_freq;
+
+    if (!expec_freq) {
+        return;
+    }
+    capab = s->readq(s, SDHC_CAPAB);
+    capab_freq = FIELD_EX64(capab, SDHC_CAPAB, BASECLKFREQ);
+    g_assert_cmpuint(capab_freq, ==, expec_freq);
+}
+
+static void check_capab_sdma(QSDHCI *s, bool supported)
+{
+    uint64_t capab, capab_sdma;
+
+    capab = s->readq(s, SDHC_CAPAB);
+    capab_sdma = FIELD_EX64(capab, SDHC_CAPAB, SDMA);
+    g_assert_cmpuint(capab_sdma, ==, supported);
+}
+
+static void check_capab_v3(QSDHCI *s, uint8_t version)
+{
+    uint64_t capab, capab_v3;
+
+    if (version < 3) {
+        /* before v3 those fields are RESERVED */
+        capab = s->readq(s, SDHC_CAPAB);
+        capab_v3 = FIELD_EX64(capab, SDHC_CAPAB, SDR);
+        g_assert_cmpuint(capab_v3, ==, 0);
+        capab_v3 = FIELD_EX64(capab, SDHC_CAPAB, DRIVER);
+        g_assert_cmpuint(capab_v3, ==, 0);
+    }
+}
+
+static void test_registers(void *obj, void *data, QGuestAllocator *alloc)
+{
+    QSDHCI *s = obj;
+
+    check_specs_version(s, s->props.version);
+    check_capab_capareg(s, s->props.capab.reg);
+    check_capab_readonly(s);
+    check_capab_v3(s, s->props.version);
+    check_capab_sdma(s, s->props.capab.sdma);
+    check_capab_baseclock(s, s->props.baseclock);
+}
+
+static void register_sdhci_test(void)
+{
+    qos_add_test("registers", "sdhci", test_registers, NULL);
+}
+
+libqos_init(register_sdhci_test);
diff --git a/tests/qtest/spapr-phb-test.c b/tests/qtest/spapr-phb-test.c
new file mode 100644 (file)
index 0000000..093dc22
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * QTest testcase for SPAPR PHB
+ *
+ * Authors:
+ *  Alexey Kardashevskiy <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests,
+ * for example by producing pci-bus.
+ */
+static void test_phb_device(void *obj, void *data, QGuestAllocator *alloc)
+{
+}
+
+static void register_phb_test(void)
+{
+    qos_add_test("spapr-phb-test", "ppc64/pseries",
+                 test_phb_device, &(QOSGraphTestOptions) {
+                     .edge.before_cmd_line = "-device spapr-pci-host-bridge"
+                                             ",index=30",
+                 });
+}
+
+libqos_init(register_phb_test);
diff --git a/tests/qtest/tco-test.c b/tests/qtest/tco-test.c
new file mode 100644 (file)
index 0000000..254f735
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * QEMU ICH9 TCO emulation tests
+ *
+ * Copyright (c) 2015 Paulo Alcantara <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqtest.h"
+#include "libqos/pci.h"
+#include "libqos/pci-pc.h"
+#include "qapi/qmp/qdict.h"
+#include "hw/pci/pci_regs.h"
+#include "hw/i386/ich9.h"
+#include "hw/acpi/ich9.h"
+#include "hw/acpi/tco.h"
+
+#define RCBA_BASE_ADDR    0xfed1c000
+#define PM_IO_BASE_ADDR   0xb000
+
+enum {
+    TCO_RLD_DEFAULT         = 0x0000,
+    TCO_DAT_IN_DEFAULT      = 0x00,
+    TCO_DAT_OUT_DEFAULT     = 0x00,
+    TCO1_STS_DEFAULT        = 0x0000,
+    TCO2_STS_DEFAULT        = 0x0000,
+    TCO1_CNT_DEFAULT        = 0x0000,
+    TCO2_CNT_DEFAULT        = 0x0008,
+    TCO_MESSAGE1_DEFAULT    = 0x00,
+    TCO_MESSAGE2_DEFAULT    = 0x00,
+    TCO_WDCNT_DEFAULT       = 0x00,
+    TCO_TMR_DEFAULT         = 0x0004,
+    SW_IRQ_GEN_DEFAULT      = 0x03,
+};
+
+#define TCO_SECS_TO_TICKS(secs)     (((secs) * 10) / 6)
+#define TCO_TICKS_TO_SECS(ticks)    (((ticks) * 6) / 10)
+
+typedef struct {
+    const char *args;
+    bool noreboot;
+    QPCIDevice *dev;
+    QPCIBar tco_io_bar;
+    QPCIBus *bus;
+    QTestState *qts;
+} TestData;
+
+static void test_end(TestData *d)
+{
+    g_free(d->dev);
+    qpci_free_pc(d->bus);
+    qtest_quit(d->qts);
+}
+
+static void test_init(TestData *d)
+{
+    QTestState *qs;
+
+    qs = qtest_initf("-machine q35 %s %s",
+                     d->noreboot ? "" : "-global ICH9-LPC.noreboot=false",
+                     !d->args ? "" : d->args);
+    qtest_irq_intercept_in(qs, "ioapic");
+
+    d->bus = qpci_new_pc(qs, NULL);
+    d->dev = qpci_device_find(d->bus, QPCI_DEVFN(0x1f, 0x00));
+    g_assert(d->dev != NULL);
+
+    qpci_device_enable(d->dev);
+
+    /* set ACPI PM I/O space base address */
+    qpci_config_writel(d->dev, ICH9_LPC_PMBASE, PM_IO_BASE_ADDR | 0x1);
+    /* enable ACPI I/O */
+    qpci_config_writeb(d->dev, ICH9_LPC_ACPI_CTRL, 0x80);
+    /* set Root Complex BAR */
+    qpci_config_writel(d->dev, ICH9_LPC_RCBA, RCBA_BASE_ADDR | 0x1);
+
+    d->tco_io_bar = qpci_legacy_iomap(d->dev, PM_IO_BASE_ADDR + 0x60);
+    d->qts = qs;
+}
+
+static void stop_tco(const TestData *d)
+{
+    uint32_t val;
+
+    val = qpci_io_readw(d->dev, d->tco_io_bar, TCO1_CNT);
+    val |= TCO_TMR_HLT;
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO1_CNT, val);
+}
+
+static void start_tco(const TestData *d)
+{
+    uint32_t val;
+
+    val = qpci_io_readw(d->dev, d->tco_io_bar, TCO1_CNT);
+    val &= ~TCO_TMR_HLT;
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO1_CNT, val);
+}
+
+static void load_tco(const TestData *d)
+{
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO_RLD, 4);
+}
+
+static void set_tco_timeout(const TestData *d, uint16_t ticks)
+{
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO_TMR, ticks);
+}
+
+static void clear_tco_status(const TestData *d)
+{
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO1_STS, 0x0008);
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO2_STS, 0x0002);
+    qpci_io_writew(d->dev, d->tco_io_bar, TCO2_STS, 0x0004);
+}
+
+static void reset_on_second_timeout(const TestData *td, bool enable)
+{
+    uint32_t val;
+
+    val = qtest_readl(td->qts, RCBA_BASE_ADDR + ICH9_CC_GCS);
+    if (enable) {
+        val &= ~ICH9_CC_GCS_NO_REBOOT;
+    } else {
+        val |= ICH9_CC_GCS_NO_REBOOT;
+    }
+    qtest_writel(td->qts, RCBA_BASE_ADDR + ICH9_CC_GCS, val);
+}
+
+static void test_tco_defaults(void)
+{
+    TestData d;
+
+    d.args = NULL;
+    d.noreboot = true;
+    test_init(&d);
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD), ==,
+                    TCO_RLD_DEFAULT);
+    /* TCO_DAT_IN & TCO_DAT_OUT */
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_DAT_IN), ==,
+                    (TCO_DAT_OUT_DEFAULT << 8) | TCO_DAT_IN_DEFAULT);
+    /* TCO1_STS & TCO2_STS */
+    g_assert_cmpint(qpci_io_readl(d.dev, d.tco_io_bar, TCO1_STS), ==,
+                    (TCO2_STS_DEFAULT << 16) | TCO1_STS_DEFAULT);
+    /* TCO1_CNT & TCO2_CNT */
+    g_assert_cmpint(qpci_io_readl(d.dev, d.tco_io_bar, TCO1_CNT), ==,
+                    (TCO2_CNT_DEFAULT << 16) | TCO1_CNT_DEFAULT);
+    /* TCO_MESSAGE1 & TCO_MESSAGE2 */
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_MESSAGE1), ==,
+                    (TCO_MESSAGE2_DEFAULT << 8) | TCO_MESSAGE1_DEFAULT);
+    g_assert_cmpint(qpci_io_readb(d.dev, d.tco_io_bar, TCO_WDCNT), ==,
+                    TCO_WDCNT_DEFAULT);
+    g_assert_cmpint(qpci_io_readb(d.dev, d.tco_io_bar, SW_IRQ_GEN), ==,
+                    SW_IRQ_GEN_DEFAULT);
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_TMR), ==,
+                    TCO_TMR_DEFAULT);
+    test_end(&d);
+}
+
+static void test_tco_timeout(void)
+{
+    TestData d;
+    const uint16_t ticks = TCO_SECS_TO_TICKS(4);
+    uint32_t val;
+    int ret;
+
+    d.args = NULL;
+    d.noreboot = true;
+    test_init(&d);
+
+    stop_tco(&d);
+    clear_tco_status(&d);
+    reset_on_second_timeout(&d, false);
+    set_tco_timeout(&d, ticks);
+    load_tco(&d);
+    start_tco(&d);
+    qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC);
+
+    /* test first timeout */
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
+    ret = val & TCO_TIMEOUT ? 1 : 0;
+    g_assert(ret == 1);
+
+    /* test clearing timeout bit */
+    val |= TCO_TIMEOUT;
+    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_STS, val);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
+    ret = val & TCO_TIMEOUT ? 1 : 0;
+    g_assert(ret == 0);
+
+    /* test second timeout */
+    qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
+    ret = val & TCO_TIMEOUT ? 1 : 0;
+    g_assert(ret == 1);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO2_STS);
+    ret = val & TCO_SECOND_TO_STS ? 1 : 0;
+    g_assert(ret == 1);
+
+    stop_tco(&d);
+    test_end(&d);
+}
+
+static void test_tco_max_timeout(void)
+{
+    TestData d;
+    const uint16_t ticks = 0xffff;
+    uint32_t val;
+    int ret;
+
+    d.args = NULL;
+    d.noreboot = true;
+    test_init(&d);
+
+    stop_tco(&d);
+    clear_tco_status(&d);
+    reset_on_second_timeout(&d, false);
+    set_tco_timeout(&d, ticks);
+    load_tco(&d);
+    start_tco(&d);
+    qtest_clock_step(d.qts, ((ticks & TCO_TMR_MASK) - 1) * TCO_TICK_NSEC);
+
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD);
+    g_assert_cmpint(val & TCO_RLD_MASK, ==, 1);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
+    ret = val & TCO_TIMEOUT ? 1 : 0;
+    g_assert(ret == 0);
+    qtest_clock_step(d.qts, TCO_TICK_NSEC);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
+    ret = val & TCO_TIMEOUT ? 1 : 0;
+    g_assert(ret == 1);
+
+    stop_tco(&d);
+    test_end(&d);
+}
+
+static QDict *get_watchdog_action(const TestData *td)
+{
+    QDict *ev = qtest_qmp_eventwait_ref(td->qts, "WATCHDOG");
+    QDict *data;
+
+    data = qdict_get_qdict(ev, "data");
+    qobject_ref(data);
+    qobject_unref(ev);
+    return data;
+}
+
+static void test_tco_second_timeout_pause(void)
+{
+    TestData td;
+    const uint16_t ticks = TCO_SECS_TO_TICKS(32);
+    QDict *ad;
+
+    td.args = "-watchdog-action pause";
+    td.noreboot = false;
+    test_init(&td);
+
+    stop_tco(&td);
+    clear_tco_status(&td);
+    reset_on_second_timeout(&td, true);
+    set_tco_timeout(&td, TCO_SECS_TO_TICKS(16));
+    load_tco(&td);
+    start_tco(&td);
+    qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
+    ad = get_watchdog_action(&td);
+    g_assert(!strcmp(qdict_get_str(ad, "action"), "pause"));
+    qobject_unref(ad);
+
+    stop_tco(&td);
+    test_end(&td);
+}
+
+static void test_tco_second_timeout_reset(void)
+{
+    TestData td;
+    const uint16_t ticks = TCO_SECS_TO_TICKS(16);
+    QDict *ad;
+
+    td.args = "-watchdog-action reset";
+    td.noreboot = false;
+    test_init(&td);
+
+    stop_tco(&td);
+    clear_tco_status(&td);
+    reset_on_second_timeout(&td, true);
+    set_tco_timeout(&td, TCO_SECS_TO_TICKS(16));
+    load_tco(&td);
+    start_tco(&td);
+    qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
+    ad = get_watchdog_action(&td);
+    g_assert(!strcmp(qdict_get_str(ad, "action"), "reset"));
+    qobject_unref(ad);
+
+    stop_tco(&td);
+    test_end(&td);
+}
+
+static void test_tco_second_timeout_shutdown(void)
+{
+    TestData td;
+    const uint16_t ticks = TCO_SECS_TO_TICKS(128);
+    QDict *ad;
+
+    td.args = "-watchdog-action shutdown";
+    td.noreboot = false;
+    test_init(&td);
+
+    stop_tco(&td);
+    clear_tco_status(&td);
+    reset_on_second_timeout(&td, true);
+    set_tco_timeout(&td, ticks);
+    load_tco(&td);
+    start_tco(&td);
+    qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
+    ad = get_watchdog_action(&td);
+    g_assert(!strcmp(qdict_get_str(ad, "action"), "shutdown"));
+    qobject_unref(ad);
+
+    stop_tco(&td);
+    test_end(&td);
+}
+
+static void test_tco_second_timeout_none(void)
+{
+    TestData td;
+    const uint16_t ticks = TCO_SECS_TO_TICKS(256);
+    QDict *ad;
+
+    td.args = "-watchdog-action none";
+    td.noreboot = false;
+    test_init(&td);
+
+    stop_tco(&td);
+    clear_tco_status(&td);
+    reset_on_second_timeout(&td, true);
+    set_tco_timeout(&td, ticks);
+    load_tco(&td);
+    start_tco(&td);
+    qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
+    ad = get_watchdog_action(&td);
+    g_assert(!strcmp(qdict_get_str(ad, "action"), "none"));
+    qobject_unref(ad);
+
+    stop_tco(&td);
+    test_end(&td);
+}
+
+static void test_tco_ticks_counter(void)
+{
+    TestData d;
+    uint16_t ticks = TCO_SECS_TO_TICKS(8);
+    uint16_t rld;
+
+    d.args = NULL;
+    d.noreboot = true;
+    test_init(&d);
+
+    stop_tco(&d);
+    clear_tco_status(&d);
+    reset_on_second_timeout(&d, false);
+    set_tco_timeout(&d, ticks);
+    load_tco(&d);
+    start_tco(&d);
+
+    do {
+        rld = qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD) & TCO_RLD_MASK;
+        g_assert_cmpint(rld, ==, ticks);
+        qtest_clock_step(d.qts, TCO_TICK_NSEC);
+        ticks--;
+    } while (!(qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS) & TCO_TIMEOUT));
+
+    stop_tco(&d);
+    test_end(&d);
+}
+
+static void test_tco1_control_bits(void)
+{
+    TestData d;
+    uint16_t val;
+
+    d.args = NULL;
+    d.noreboot = true;
+    test_init(&d);
+
+    val = TCO_LOCK;
+    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_CNT, val);
+    val &= ~TCO_LOCK;
+    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_CNT, val);
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO1_CNT), ==,
+                    TCO_LOCK);
+    test_end(&d);
+}
+
+static void test_tco1_status_bits(void)
+{
+    TestData d;
+    uint16_t ticks = 8;
+    uint16_t val;
+    int ret;
+
+    d.args = NULL;
+    d.noreboot = true;
+    test_init(&d);
+
+    stop_tco(&d);
+    clear_tco_status(&d);
+    reset_on_second_timeout(&d, false);
+    set_tco_timeout(&d, ticks);
+    load_tco(&d);
+    start_tco(&d);
+    qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC);
+
+    qpci_io_writeb(d.dev, d.tco_io_bar, TCO_DAT_IN, 0);
+    qpci_io_writeb(d.dev, d.tco_io_bar, TCO_DAT_OUT, 0);
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
+    ret = val & (TCO_TIMEOUT | SW_TCO_SMI | TCO_INT_STS) ? 1 : 0;
+    g_assert(ret == 1);
+    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_STS, val);
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS), ==, 0);
+    test_end(&d);
+}
+
+static void test_tco2_status_bits(void)
+{
+    TestData d;
+    uint16_t ticks = 8;
+    uint16_t val;
+    int ret;
+
+    d.args = NULL;
+    d.noreboot = true;
+    test_init(&d);
+
+    stop_tco(&d);
+    clear_tco_status(&d);
+    reset_on_second_timeout(&d, true);
+    set_tco_timeout(&d, ticks);
+    load_tco(&d);
+    start_tco(&d);
+    qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC * 2);
+
+    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO2_STS);
+    ret = val & (TCO_SECOND_TO_STS | TCO_BOOT_STS) ? 1 : 0;
+    g_assert(ret == 1);
+    qpci_io_writew(d.dev, d.tco_io_bar, TCO2_STS, val);
+    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO2_STS), ==, 0);
+    test_end(&d);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("tco/defaults", test_tco_defaults);
+    qtest_add_func("tco/timeout/no_action", test_tco_timeout);
+    qtest_add_func("tco/timeout/no_action/max", test_tco_max_timeout);
+    qtest_add_func("tco/second_timeout/pause", test_tco_second_timeout_pause);
+    qtest_add_func("tco/second_timeout/reset", test_tco_second_timeout_reset);
+    qtest_add_func("tco/second_timeout/shutdown",
+                   test_tco_second_timeout_shutdown);
+    qtest_add_func("tco/second_timeout/none", test_tco_second_timeout_none);
+    qtest_add_func("tco/counter", test_tco_ticks_counter);
+    qtest_add_func("tco/tco1_control/bits", test_tco1_control_bits);
+    qtest_add_func("tco/tco1_status/bits", test_tco1_status_bits);
+    qtest_add_func("tco/tco2_status/bits", test_tco2_status_bits);
+    return g_test_run();
+}
diff --git a/tests/qtest/test-arm-mptimer.c b/tests/qtest/test-arm-mptimer.c
new file mode 100644 (file)
index 0000000..7a56d56
--- /dev/null
@@ -0,0 +1,1090 @@
+/*
+ * QTest testcase for the ARM MPTimer
+ *
+ * Copyright (c) 2016 Dmitry Osipenko <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+#include "libqtest-single.h"
+
+#define TIMER_BLOCK_SCALE(s)    ((((s) & 0xff) + 1) * 10)
+
+#define TIMER_BLOCK_STEP(scaler, steps_nb) \
+    clock_step(TIMER_BLOCK_SCALE(scaler) * (int64_t)(steps_nb) + 1)
+
+#define TIMER_BASE_PHYS 0x1e000600
+
+#define TIMER_LOAD      0x00
+#define TIMER_COUNTER   0x04
+#define TIMER_CONTROL   0x08
+#define TIMER_INTSTAT   0x0C
+
+#define TIMER_CONTROL_ENABLE        (1 << 0)
+#define TIMER_CONTROL_PERIODIC      (1 << 1)
+#define TIMER_CONTROL_IT_ENABLE     (1 << 2)
+#define TIMER_CONTROL_PRESCALER(p)  (((p) & 0xff) << 8)
+
+#define PERIODIC     1
+#define ONESHOT      0
+#define NOSCALE      0
+
+static int nonscaled = NOSCALE;
+static int scaled = 122;
+
+static void timer_load(uint32_t load)
+{
+    writel(TIMER_BASE_PHYS + TIMER_LOAD, load);
+}
+
+static void timer_start(int periodic, uint32_t scale)
+{
+    uint32_t ctl = TIMER_CONTROL_ENABLE | TIMER_CONTROL_PRESCALER(scale);
+
+    if (periodic) {
+        ctl |= TIMER_CONTROL_PERIODIC;
+    }
+
+    writel(TIMER_BASE_PHYS + TIMER_CONTROL, ctl);
+}
+
+static void timer_stop(void)
+{
+    writel(TIMER_BASE_PHYS + TIMER_CONTROL, 0);
+}
+
+static void timer_int_clr(void)
+{
+    writel(TIMER_BASE_PHYS + TIMER_INTSTAT, 1);
+}
+
+static void timer_reset(void)
+{
+    timer_stop();
+    timer_load(0);
+    timer_int_clr();
+}
+
+static uint32_t timer_get_and_clr_int_sts(void)
+{
+    uint32_t int_sts = readl(TIMER_BASE_PHYS + TIMER_INTSTAT);
+
+    if (int_sts) {
+        timer_int_clr();
+    }
+
+    return int_sts;
+}
+
+static uint32_t timer_counter(void)
+{
+    return readl(TIMER_BASE_PHYS + TIMER_COUNTER);
+}
+
+static void timer_set_counter(uint32_t value)
+{
+    writel(TIMER_BASE_PHYS + TIMER_COUNTER, value);
+}
+
+static void test_timer_oneshot(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(9999999);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 9999);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+    g_assert_cmpuint(timer_counter(), ==, 9990000);
+
+    TIMER_BLOCK_STEP(scaler, 9990000);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    TIMER_BLOCK_STEP(scaler, 9990000);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_pause(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(999999999);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 999);
+
+    g_assert_cmpuint(timer_counter(), ==, 999999000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(scaler, 9000);
+
+    g_assert_cmpuint(timer_counter(), ==, 999990000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_stop();
+
+    g_assert_cmpuint(timer_counter(), ==, 999990000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(scaler, 90000);
+
+    g_assert_cmpuint(timer_counter(), ==, 999990000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 999990000);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    TIMER_BLOCK_STEP(scaler, 999990000);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+}
+
+static void test_timer_reload(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 90000);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 90000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_load(UINT32_MAX);
+
+    TIMER_BLOCK_STEP(scaler, 90000);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 90000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_periodic(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+    int repeat = 10;
+
+    timer_reset();
+    timer_load(100);
+    timer_start(PERIODIC, scaler);
+
+    while (repeat--) {
+        clock_step(TIMER_BLOCK_SCALE(scaler) * (101 + repeat) + 1);
+
+        g_assert_cmpuint(timer_counter(), ==, 100 - repeat);
+        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+        clock_step(TIMER_BLOCK_SCALE(scaler) * (101 - repeat) - 1);
+    }
+}
+
+static void test_timer_oneshot_to_periodic(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(10000);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1000);
+
+    g_assert_cmpuint(timer_counter(), ==, 9000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 14001);
+
+    g_assert_cmpuint(timer_counter(), ==, 5000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+}
+
+static void test_timer_periodic_to_oneshot(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(99999999);
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 999);
+
+    g_assert_cmpuint(timer_counter(), ==, 99999000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 99999009);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+}
+
+static void test_timer_prescaler(void)
+{
+    timer_reset();
+    timer_load(9999999);
+    timer_start(ONESHOT, NOSCALE);
+
+    TIMER_BLOCK_STEP(NOSCALE, 9999998);
+
+    g_assert_cmpuint(timer_counter(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(NOSCALE, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    timer_reset();
+    timer_load(9999999);
+    timer_start(ONESHOT, 0xAB);
+
+    TIMER_BLOCK_STEP(0xAB, 9999998);
+
+    g_assert_cmpuint(timer_counter(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(0xAB, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+}
+
+static void test_timer_prescaler_on_the_fly(void)
+{
+    timer_reset();
+    timer_load(9999999);
+    timer_start(ONESHOT, NOSCALE);
+
+    TIMER_BLOCK_STEP(NOSCALE, 999);
+
+    g_assert_cmpuint(timer_counter(), ==, 9999000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(ONESHOT, 0xAB);
+
+    TIMER_BLOCK_STEP(0xAB, 9000);
+
+    g_assert_cmpuint(timer_counter(), ==, 9990000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_set_oneshot_counter_to_0(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_set_counter(0);
+
+    TIMER_BLOCK_STEP(scaler, 10);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_set_periodic_counter_to_0(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_set_counter(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - (scaler ? 0 : 1));
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    timer_reset();
+    timer_set_counter(UINT32_MAX);
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_set_counter(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_noload_oneshot(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_noload_periodic(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_zero_load_oneshot(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_zero_load_periodic(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_zero_load_oneshot_to_nonzero(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    timer_load(999);
+
+    TIMER_BLOCK_STEP(scaler, 1001);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+}
+
+static void test_timer_zero_load_periodic_to_nonzero(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+    int i;
+
+    timer_reset();
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    timer_load(1999999);
+
+    for (i = 1; i < 10; i++) {
+        TIMER_BLOCK_STEP(scaler, 2000001);
+
+        g_assert_cmpuint(timer_counter(), ==, 1999999 - i);
+        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+    }
+}
+
+static void test_timer_nonzero_load_oneshot_to_zero(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    timer_load(UINT32_MAX);
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_nonzero_load_periodic_to_zero(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    timer_load(UINT32_MAX);
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_set_periodic_counter_on_the_fly(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(UINT32_MAX / 2);
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX / 2 - 100);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_set_counter(UINT32_MAX);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_enable_and_set_counter(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    timer_set_counter(UINT32_MAX);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_set_counter_and_enable(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_set_counter(UINT32_MAX);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_set_counter_disabled(void)
+{
+    timer_reset();
+    timer_set_counter(999999999);
+
+    TIMER_BLOCK_STEP(NOSCALE, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 999999999);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_load_disabled(void)
+{
+    timer_reset();
+    timer_load(999999999);
+
+    TIMER_BLOCK_STEP(NOSCALE, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 999999999);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_oneshot_with_counter_0_on_start(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(999);
+    timer_set_counter(0);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_periodic_with_counter_0_on_start(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+    int i;
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_set_counter(0);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX + (scaler ? 1 : 0) - 100);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX + (scaler ? 1 : 0) - 200);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_reset();
+    timer_load(1999999);
+    timer_set_counter(0);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    for (i = 2 - (!!scaler ? 1 : 0); i < 10; i++) {
+        TIMER_BLOCK_STEP(scaler, 2000001);
+
+        g_assert_cmpuint(timer_counter(), ==, 1999999 - i);
+        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+    }
+}
+
+static void test_periodic_counter(gconstpointer arg)
+{
+    const int test_load = 10;
+    int scaler = *((int *) arg);
+    int test_val;
+
+    timer_reset();
+    timer_load(test_load);
+    timer_start(PERIODIC, scaler);
+
+    clock_step(1);
+
+    for (test_val = 0; test_val <= test_load; test_val++) {
+        clock_step(TIMER_BLOCK_SCALE(scaler) * test_load);
+        g_assert_cmpint(timer_counter(), ==, test_val);
+    }
+}
+
+static void test_timer_set_counter_periodic_with_zero_load(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(PERIODIC, scaler);
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    timer_set_counter(999);
+
+    TIMER_BLOCK_STEP(scaler, 999);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_set_oneshot_load_to_0(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_set_periodic_load_to_0(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+}
+
+static void test_deferred_trigger(void)
+{
+    int mode = ONESHOT;
+
+again:
+    timer_reset();
+    timer_start(mode, 255);
+
+    clock_step(100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    timer_reset();
+    timer_load(2);
+    timer_start(mode, 255);
+
+    clock_step(100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(mode, 255);
+
+    clock_step(100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_set_counter(0);
+
+    clock_step(100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(mode, 255);
+
+    clock_step(100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_load(0);
+
+    clock_step(100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    if (mode == ONESHOT) {
+        mode = PERIODIC;
+        goto again;
+    }
+}
+
+static void test_timer_zero_load_mode_switch(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(0);
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_zero_load_prescaled_periodic_to_nonscaled_oneshot(void)
+{
+    timer_reset();
+    timer_load(0);
+    timer_start(PERIODIC, 255);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    timer_start(ONESHOT, NOSCALE);
+
+    TIMER_BLOCK_STEP(NOSCALE, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(NOSCALE, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_zero_load_prescaled_oneshot_to_nonscaled_periodic(void)
+{
+    timer_reset();
+    timer_load(0);
+    timer_start(ONESHOT, 255);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(PERIODIC, NOSCALE);
+
+    TIMER_BLOCK_STEP(NOSCALE, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_zero_load_nonscaled_oneshot_to_prescaled_periodic(void)
+{
+    timer_reset();
+    timer_load(0);
+    timer_start(ONESHOT, NOSCALE);
+
+    TIMER_BLOCK_STEP(NOSCALE, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(PERIODIC, 255);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_zero_load_nonscaled_periodic_to_prescaled_oneshot(void)
+{
+    timer_reset();
+    timer_load(0);
+    timer_start(PERIODIC, NOSCALE);
+
+    TIMER_BLOCK_STEP(NOSCALE, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(ONESHOT, 255);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+/*
+ * Add a qtest test that comes in two versions: one with
+ * a timer scaler setting, and one with the timer nonscaled.
+ */
+static void add_scaler_test(const char *str, bool scale,
+                            void (*fn)(const void *))
+{
+    char *name;
+    int *scaler = scale ? &scaled : &nonscaled;
+
+    name = g_strdup_printf("%s=%d", str, *scaler);
+    qtest_add_data_func(name, scaler, fn);
+    g_free(name);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+    int scale;
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("mptimer/deferred_trigger", test_deferred_trigger);
+    qtest_add_func("mptimer/load_disabled", test_timer_load_disabled);
+    qtest_add_func("mptimer/set_counter_disabled", test_timer_set_counter_disabled);
+    qtest_add_func("mptimer/zero_load_prescaled_periodic_to_nonscaled_oneshot",
+                   test_timer_zero_load_prescaled_periodic_to_nonscaled_oneshot);
+    qtest_add_func("mptimer/zero_load_prescaled_oneshot_to_nonscaled_periodic",
+                   test_timer_zero_load_prescaled_oneshot_to_nonscaled_periodic);
+    qtest_add_func("mptimer/zero_load_nonscaled_oneshot_to_prescaled_periodic",
+                   test_timer_zero_load_nonscaled_oneshot_to_prescaled_periodic);
+    qtest_add_func("mptimer/zero_load_nonscaled_periodic_to_prescaled_oneshot",
+                   test_timer_zero_load_nonscaled_periodic_to_prescaled_oneshot);
+    qtest_add_func("mptimer/prescaler", test_timer_prescaler);
+    qtest_add_func("mptimer/prescaler_on_the_fly", test_timer_prescaler_on_the_fly);
+
+    for (scale = 0; scale < 2; scale++) {
+        add_scaler_test("mptimer/oneshot scaler",
+                        scale, test_timer_oneshot);
+        add_scaler_test("mptimer/pause scaler",
+                        scale, test_timer_pause);
+        add_scaler_test("mptimer/reload scaler",
+                        scale, test_timer_reload);
+        add_scaler_test("mptimer/periodic scaler",
+                        scale, test_timer_periodic);
+        add_scaler_test("mptimer/oneshot_to_periodic scaler",
+                        scale, test_timer_oneshot_to_periodic);
+        add_scaler_test("mptimer/periodic_to_oneshot scaler",
+                        scale, test_timer_periodic_to_oneshot);
+        add_scaler_test("mptimer/set_oneshot_counter_to_0 scaler",
+                        scale, test_timer_set_oneshot_counter_to_0);
+        add_scaler_test("mptimer/set_periodic_counter_to_0 scaler",
+                        scale, test_timer_set_periodic_counter_to_0);
+        add_scaler_test("mptimer/noload_oneshot scaler",
+                        scale, test_timer_noload_oneshot);
+        add_scaler_test("mptimer/noload_periodic scaler",
+                        scale, test_timer_noload_periodic);
+        add_scaler_test("mptimer/zero_load_oneshot scaler",
+                        scale, test_timer_zero_load_oneshot);
+        add_scaler_test("mptimer/zero_load_periodic scaler",
+                        scale, test_timer_zero_load_periodic);
+        add_scaler_test("mptimer/zero_load_oneshot_to_nonzero scaler",
+                        scale, test_timer_zero_load_oneshot_to_nonzero);
+        add_scaler_test("mptimer/zero_load_periodic_to_nonzero scaler",
+                        scale, test_timer_zero_load_periodic_to_nonzero);
+        add_scaler_test("mptimer/nonzero_load_oneshot_to_zero scaler",
+                        scale, test_timer_nonzero_load_oneshot_to_zero);
+        add_scaler_test("mptimer/nonzero_load_periodic_to_zero scaler",
+                        scale, test_timer_nonzero_load_periodic_to_zero);
+        add_scaler_test("mptimer/set_periodic_counter_on_the_fly scaler",
+                        scale, test_timer_set_periodic_counter_on_the_fly);
+        add_scaler_test("mptimer/enable_and_set_counter scaler",
+                        scale, test_timer_enable_and_set_counter);
+        add_scaler_test("mptimer/set_counter_and_enable scaler",
+                        scale, test_timer_set_counter_and_enable);
+        add_scaler_test("mptimer/oneshot_with_counter_0_on_start scaler",
+                        scale, test_timer_oneshot_with_counter_0_on_start);
+        add_scaler_test("mptimer/periodic_with_counter_0_on_start scaler",
+                        scale, test_timer_periodic_with_counter_0_on_start);
+        add_scaler_test("mptimer/periodic_counter scaler",
+                        scale, test_periodic_counter);
+        add_scaler_test("mptimer/set_counter_periodic_with_zero_load scaler",
+                        scale, test_timer_set_counter_periodic_with_zero_load);
+        add_scaler_test("mptimer/set_oneshot_load_to_0 scaler",
+                        scale, test_timer_set_oneshot_load_to_0);
+        add_scaler_test("mptimer/set_periodic_load_to_0 scaler",
+                        scale, test_timer_set_periodic_load_to_0);
+        add_scaler_test("mptimer/zero_load_mode_switch scaler",
+                        scale, test_timer_zero_load_mode_switch);
+    }
+
+    qtest_start("-machine vexpress-a9");
+    ret = g_test_run();
+    qtest_end();
+
+    return ret;
+}
diff --git a/tests/qtest/test-filter-mirror.c b/tests/qtest/test-filter-mirror.c
new file mode 100644 (file)
index 0000000..1e3ced8
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * QTest testcase for filter-mirror
+ *
+ * Copyright (c) 2016 FUJITSU LIMITED
+ * Author: Zhang Chen <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later.  See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "qemu/iov.h"
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
+
+/* TODO actually test the results and get rid of this */
+#define qmp_discard_response(qs, ...) qobject_unref(qtest_qmp(qs, __VA_ARGS__))
+
+static void test_mirror(void)
+{
+    int send_sock[2], recv_sock[2];
+    uint32_t ret = 0, len = 0;
+    char send_buf[] = "Hello! filter-mirror~";
+    char *recv_buf;
+    uint32_t size = sizeof(send_buf);
+    size = htonl(size);
+    const char *devstr = "e1000";
+    QTestState *qts;
+
+    if (g_str_equal(qtest_get_arch(), "s390x")) {
+        devstr = "virtio-net-ccw";
+    }
+
+    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, send_sock);
+    g_assert_cmpint(ret, !=, -1);
+
+    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, recv_sock);
+    g_assert_cmpint(ret, !=, -1);
+
+    qts = qtest_initf(
+        "-netdev socket,id=qtest-bn0,fd=%d "
+        "-device %s,netdev=qtest-bn0,id=qtest-e0 "
+        "-chardev socket,id=mirror0,fd=%d "
+        "-object filter-mirror,id=qtest-f0,netdev=qtest-bn0,queue=tx,outdev=mirror0 "
+        , send_sock[1], devstr, recv_sock[1]);
+
+    struct iovec iov[] = {
+        {
+            .iov_base = &size,
+            .iov_len = sizeof(size),
+        }, {
+            .iov_base = send_buf,
+            .iov_len = sizeof(send_buf),
+        },
+    };
+
+    /* send a qmp command to guarantee that 'connected' is setting to true. */
+    qmp_discard_response(qts, "{ 'execute' : 'query-status'}");
+    ret = iov_send(send_sock[0], iov, 2, 0, sizeof(size) + sizeof(send_buf));
+    g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size));
+    close(send_sock[0]);
+
+    ret = qemu_recv(recv_sock[0], &len, sizeof(len), 0);
+    g_assert_cmpint(ret, ==, sizeof(len));
+    len = ntohl(len);
+
+    g_assert_cmpint(len, ==, sizeof(send_buf));
+    recv_buf = g_malloc(len);
+    ret = qemu_recv(recv_sock[0], recv_buf, len, 0);
+    g_assert_cmpstr(recv_buf, ==, send_buf);
+
+    g_free(recv_buf);
+    close(send_sock[0]);
+    close(send_sock[1]);
+    close(recv_sock[0]);
+    close(recv_sock[1]);
+    qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/netfilter/mirror", test_mirror);
+    ret = g_test_run();
+
+    return ret;
+}
diff --git a/tests/qtest/test-filter-redirector.c b/tests/qtest/test-filter-redirector.c
new file mode 100644 (file)
index 0000000..e4d5322
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * QTest testcase for filter-redirector
+ *
+ * Copyright (c) 2016 FUJITSU LIMITED
+ * Author: Zhang Chen <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later.  See the COPYING file in the top-level directory.
+ *
+ * Case 1, tx traffic flow:
+ *
+ * qemu side              | test side
+ *                        |
+ * +---------+            |  +-------+
+ * | backend <---------------+ sock0 |
+ * +----+----+            |  +-------+
+ *      |                 |
+ * +----v----+  +-------+ |
+ * |  rd0    +->+chardev| |
+ * +---------+  +---+---+ |
+ *                  |     |
+ * +---------+      |     |
+ * |  rd1    <------+     |
+ * +----+----+            |
+ *      |                 |
+ * +----v----+            |  +-------+
+ * |  rd2    +--------------->sock1  |
+ * +---------+            |  +-------+
+ *                        +
+ *
+ * --------------------------------------
+ * Case 2, rx traffic flow
+ * qemu side              | test side
+ *                        |
+ * +---------+            |  +-------+
+ * | backend +---------------> sock1 |
+ * +----^----+            |  +-------+
+ *      |                 |
+ * +----+----+  +-------+ |
+ * |  rd0    +<-+chardev| |
+ * +---------+  +---+---+ |
+ *                  ^     |
+ * +---------+      |     |
+ * |  rd1    +------+     |
+ * +----^----+            |
+ *      |                 |
+ * +----+----+            |  +-------+
+ * |  rd2    <---------------+sock0  |
+ * +---------+            |  +-------+
+ *                        +
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "qemu/iov.h"
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
+
+/* TODO actually test the results and get rid of this */
+#define qmp_discard_response(qs, ...) qobject_unref(qtest_qmp(qs, __VA_ARGS__))
+
+static const char *get_devstr(void)
+{
+    if (g_str_equal(qtest_get_arch(), "s390x")) {
+        return "virtio-net-ccw";
+    }
+
+    return "rtl8139";
+}
+
+
+static void test_redirector_tx(void)
+{
+    int backend_sock[2], recv_sock;
+    uint32_t ret = 0, len = 0;
+    char send_buf[] = "Hello!!";
+    char sock_path0[] = "filter-redirector0.XXXXXX";
+    char sock_path1[] = "filter-redirector1.XXXXXX";
+    char *recv_buf;
+    uint32_t size = sizeof(send_buf);
+    size = htonl(size);
+    QTestState *qts;
+
+    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, backend_sock);
+    g_assert_cmpint(ret, !=, -1);
+
+    ret = mkstemp(sock_path0);
+    g_assert_cmpint(ret, !=, -1);
+    ret = mkstemp(sock_path1);
+    g_assert_cmpint(ret, !=, -1);
+
+    qts = qtest_initf(
+        "-netdev socket,id=qtest-bn0,fd=%d "
+        "-device %s,netdev=qtest-bn0,id=qtest-e0 "
+        "-chardev socket,id=redirector0,path=%s,server,nowait "
+        "-chardev socket,id=redirector1,path=%s,server,nowait "
+        "-chardev socket,id=redirector2,path=%s "
+        "-object filter-redirector,id=qtest-f0,netdev=qtest-bn0,"
+        "queue=tx,outdev=redirector0 "
+        "-object filter-redirector,id=qtest-f1,netdev=qtest-bn0,"
+        "queue=tx,indev=redirector2 "
+        "-object filter-redirector,id=qtest-f2,netdev=qtest-bn0,"
+        "queue=tx,outdev=redirector1 ", backend_sock[1], get_devstr(),
+        sock_path0, sock_path1, sock_path0);
+
+    recv_sock = unix_connect(sock_path1, NULL);
+    g_assert_cmpint(recv_sock, !=, -1);
+
+    /* send a qmp command to guarantee that 'connected' is setting to true. */
+    qmp_discard_response(qts, "{ 'execute' : 'query-status'}");
+
+    struct iovec iov[] = {
+        {
+            .iov_base = &size,
+            .iov_len = sizeof(size),
+        }, {
+            .iov_base = send_buf,
+            .iov_len = sizeof(send_buf),
+        },
+    };
+
+    ret = iov_send(backend_sock[0], iov, 2, 0, sizeof(size) + sizeof(send_buf));
+    g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size));
+    close(backend_sock[0]);
+
+    ret = qemu_recv(recv_sock, &len, sizeof(len), 0);
+    g_assert_cmpint(ret, ==, sizeof(len));
+    len = ntohl(len);
+
+    g_assert_cmpint(len, ==, sizeof(send_buf));
+    recv_buf = g_malloc(len);
+    ret = qemu_recv(recv_sock, recv_buf, len, 0);
+    g_assert_cmpstr(recv_buf, ==, send_buf);
+
+    g_free(recv_buf);
+    close(recv_sock);
+    unlink(sock_path0);
+    unlink(sock_path1);
+    qtest_quit(qts);
+}
+
+static void test_redirector_rx(void)
+{
+    int backend_sock[2], send_sock;
+    uint32_t ret = 0, len = 0;
+    char send_buf[] = "Hello!!";
+    char sock_path0[] = "filter-redirector0.XXXXXX";
+    char sock_path1[] = "filter-redirector1.XXXXXX";
+    char *recv_buf;
+    uint32_t size = sizeof(send_buf);
+    size = htonl(size);
+    QTestState *qts;
+
+    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, backend_sock);
+    g_assert_cmpint(ret, !=, -1);
+
+    ret = mkstemp(sock_path0);
+    g_assert_cmpint(ret, !=, -1);
+    ret = mkstemp(sock_path1);
+    g_assert_cmpint(ret, !=, -1);
+
+    qts = qtest_initf(
+        "-netdev socket,id=qtest-bn0,fd=%d "
+        "-device %s,netdev=qtest-bn0,id=qtest-e0 "
+        "-chardev socket,id=redirector0,path=%s,server,nowait "
+        "-chardev socket,id=redirector1,path=%s,server,nowait "
+        "-chardev socket,id=redirector2,path=%s "
+        "-object filter-redirector,id=qtest-f0,netdev=qtest-bn0,"
+        "queue=rx,indev=redirector0 "
+        "-object filter-redirector,id=qtest-f1,netdev=qtest-bn0,"
+        "queue=rx,outdev=redirector2 "
+        "-object filter-redirector,id=qtest-f2,netdev=qtest-bn0,"
+        "queue=rx,indev=redirector1 ", backend_sock[1], get_devstr(),
+        sock_path0, sock_path1, sock_path0);
+
+    struct iovec iov[] = {
+        {
+            .iov_base = &size,
+            .iov_len = sizeof(size),
+        }, {
+            .iov_base = send_buf,
+            .iov_len = sizeof(send_buf),
+        },
+    };
+
+    send_sock = unix_connect(sock_path1, NULL);
+    g_assert_cmpint(send_sock, !=, -1);
+    /* send a qmp command to guarantee that 'connected' is setting to true. */
+    qmp_discard_response(qts, "{ 'execute' : 'query-status'}");
+
+    ret = iov_send(send_sock, iov, 2, 0, sizeof(size) + sizeof(send_buf));
+    g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size));
+
+    ret = qemu_recv(backend_sock[0], &len, sizeof(len), 0);
+    g_assert_cmpint(ret, ==, sizeof(len));
+    len = ntohl(len);
+
+    g_assert_cmpint(len, ==, sizeof(send_buf));
+    recv_buf = g_malloc(len);
+    ret = qemu_recv(backend_sock[0], recv_buf, len, 0);
+    g_assert_cmpstr(recv_buf, ==, send_buf);
+
+    close(send_sock);
+    g_free(recv_buf);
+    unlink(sock_path0);
+    unlink(sock_path1);
+    qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/netfilter/redirector_tx", test_redirector_tx);
+    qtest_add_func("/netfilter/redirector_rx", test_redirector_rx);
+    return g_test_run();
+}
diff --git a/tests/qtest/test-hmp.c b/tests/qtest/test-hmp.c
new file mode 100644 (file)
index 0000000..5029c4d
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Test HMP commands.
+ *
+ * Copyright (c) 2017 Red Hat Inc.
+ *
+ * Author:
+ *    Thomas Huth <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2
+ * or later. See the COPYING file in the top-level directory.
+ *
+ * This test calls some HMP commands for all machines that the current
+ * QEMU binary provides, to check whether they terminate successfully
+ * (i.e. do not crash QEMU).
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+static int verbose;
+
+static const char *hmp_cmds[] = {
+    "announce_self",
+    "boot_set ndc",
+    "chardev-add null,id=testchardev1",
+    "chardev-send-break testchardev1",
+    "chardev-change testchardev1 ringbuf",
+    "chardev-remove testchardev1",
+    "commit all",
+    "cpu-add 1",
+    "cpu 0",
+    "device_add ?",
+    "device_add usb-mouse,id=mouse1",
+    "drive_add ignored format=help",
+    "mouse_button 7",
+    "mouse_move 10 10",
+    "mouse_button 0",
+    "device_del mouse1",
+    "dump-guest-memory /dev/null 0 4096",
+    "dump-guest-memory /dev/null",
+    "gdbserver",
+    "gva2gpa 0",
+    "hostfwd_add tcp::43210-:43210",
+    "hostfwd_remove tcp::43210-:43210",
+    "i /w 0",
+    "log all",
+    "log none",
+    "memsave 0 4096 \"/dev/null\"",
+    "migrate_set_cache_size 1",
+    "migrate_set_downtime 1",
+    "migrate_set_speed 1",
+    "netdev_add user,id=net1",
+    "set_link net1 off",
+    "set_link net1 on",
+    "netdev_del net1",
+    "nmi",
+    "o /w 0 0x1234",
+    "object_add memory-backend-ram,id=mem1,size=256M",
+    "object_del mem1",
+    "pmemsave 0 4096 \"/dev/null\"",
+    "p $pc + 8",
+    "qom-list /",
+    "qom-set /machine initrd test",
+    "screendump /dev/null",
+    "sendkey x",
+    "singlestep on",
+    "wavcapture /dev/null",
+    "stopcapture 0",
+    "sum 0 512",
+    "x /8i 0x100",
+    "xp /16x 0",
+    NULL
+};
+
+/* Run through the list of pre-defined commands */
+static void test_commands(QTestState *qts)
+{
+    char *response;
+    int i;
+
+    for (i = 0; hmp_cmds[i] != NULL; i++) {
+        response = qtest_hmp(qts, "%s", hmp_cmds[i]);
+        if (verbose) {
+            fprintf(stderr,
+                    "\texecute HMP command: %s\n"
+                    "\tresult             : %s\n",
+                    hmp_cmds[i], response);
+        }
+        g_free(response);
+    }
+
+}
+
+/* Run through all info commands and call them blindly (without arguments) */
+static void test_info_commands(QTestState *qts)
+{
+    char *resp, *info, *info_buf, *endp;
+
+    info_buf = info = qtest_hmp(qts, "help info");
+
+    while (*info) {
+        /* Extract the info command, ignore parameters and description */
+        g_assert(strncmp(info, "info ", 5) == 0);
+        endp = strchr(&info[5], ' ');
+        g_assert(endp != NULL);
+        *endp = '\0';
+        /* Now run the info command */
+        if (verbose) {
+            fprintf(stderr, "\t%s\n", info);
+        }
+        resp = qtest_hmp(qts, "%s", info);
+        g_free(resp);
+        /* And move forward to the next line */
+        info = strchr(endp + 1, '\n');
+        if (!info) {
+            break;
+        }
+        info += 1;
+    }
+
+    g_free(info_buf);
+}
+
+static void test_machine(gconstpointer data)
+{
+    const char *machine = data;
+    char *args;
+    QTestState *qts;
+
+    args = g_strdup_printf("-S -M %s", machine);
+    qts = qtest_init(args);
+
+    test_info_commands(qts);
+    test_commands(qts);
+
+    qtest_quit(qts);
+    g_free(args);
+    g_free((void *)data);
+}
+
+static void add_machine_test_case(const char *mname)
+{
+    char *path;
+
+    /* Ignore blacklisted machines that have known problems */
+    if (!strcmp("xenfv", mname) || !strcmp("xenpv", mname)) {
+        return;
+    }
+
+    path = g_strdup_printf("hmp/%s", mname);
+    qtest_add_data_func(path, g_strdup(mname), test_machine);
+    g_free(path);
+}
+
+int main(int argc, char **argv)
+{
+    char *v_env = getenv("V");
+
+    if (v_env && *v_env >= '2') {
+        verbose = true;
+    }
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_cb_for_every_machine(add_machine_test_case, g_test_quick());
+
+    /* as none machine has no memory by default, add a test case with memory */
+    qtest_add_data_func("hmp/none+2MB", g_strdup("none -m 2"), test_machine);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/test-netfilter.c b/tests/qtest/test-netfilter.c
new file mode 100644 (file)
index 0000000..22927ee
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * QTest testcase for netfilter
+ *
+ * Copyright (c) 2015 FUJITSU LIMITED
+ * Author: Yang Hongyang <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later.  See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "qapi/qmp/qdict.h"
+
+/* add a netfilter to a netdev and then remove it */
+static void add_one_netfilter(void)
+{
+    QDict *response;
+
+    response = qmp("{'execute': 'object-add',"
+                   " 'arguments': {"
+                   "   'qom-type': 'filter-buffer',"
+                   "   'id': 'qtest-f0',"
+                   "   'props': {"
+                   "     'netdev': 'qtest-bn0',"
+                   "     'queue': 'rx',"
+                   "     'interval': 1000"
+                   "}}}");
+
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+
+    response = qmp("{'execute': 'object-del',"
+                   " 'arguments': {"
+                   "   'id': 'qtest-f0'"
+                   "}}");
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+}
+
+/* add a netfilter to a netdev and then remove the netdev */
+static void remove_netdev_with_one_netfilter(void)
+{
+    QDict *response;
+
+    response = qmp("{'execute': 'object-add',"
+                   " 'arguments': {"
+                   "   'qom-type': 'filter-buffer',"
+                   "   'id': 'qtest-f0',"
+                   "   'props': {"
+                   "     'netdev': 'qtest-bn0',"
+                   "     'queue': 'rx',"
+                   "     'interval': 1000"
+                   "}}}");
+
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+
+    response = qmp("{'execute': 'netdev_del',"
+                   " 'arguments': {"
+                   "   'id': 'qtest-bn0'"
+                   "}}");
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+
+    /* add back the netdev */
+    response = qmp("{'execute': 'netdev_add',"
+                   " 'arguments': {"
+                   "   'type': 'user',"
+                   "   'id': 'qtest-bn0'"
+                   "}}");
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+}
+
+/* add multi(2) netfilters to a netdev and then remove them */
+static void add_multi_netfilter(void)
+{
+    QDict *response;
+
+    response = qmp("{'execute': 'object-add',"
+                   " 'arguments': {"
+                   "   'qom-type': 'filter-buffer',"
+                   "   'id': 'qtest-f0',"
+                   "   'props': {"
+                   "     'netdev': 'qtest-bn0',"
+                   "     'queue': 'rx',"
+                   "     'interval': 1000"
+                   "}}}");
+
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+
+    response = qmp("{'execute': 'object-add',"
+                   " 'arguments': {"
+                   "   'qom-type': 'filter-buffer',"
+                   "   'id': 'qtest-f1',"
+                   "   'props': {"
+                   "     'netdev': 'qtest-bn0',"
+                   "     'queue': 'rx',"
+                   "     'interval': 1000"
+                   "}}}");
+
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+
+    response = qmp("{'execute': 'object-del',"
+                   " 'arguments': {"
+                   "   'id': 'qtest-f0'"
+                   "}}");
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+
+    response = qmp("{'execute': 'object-del',"
+                   " 'arguments': {"
+                   "   'id': 'qtest-f1'"
+                   "}}");
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+}
+
+/* add multi(2) netfilters to a netdev and then remove the netdev */
+static void remove_netdev_with_multi_netfilter(void)
+{
+    QDict *response;
+
+    response = qmp("{'execute': 'object-add',"
+                   " 'arguments': {"
+                   "   'qom-type': 'filter-buffer',"
+                   "   'id': 'qtest-f0',"
+                   "   'props': {"
+                   "     'netdev': 'qtest-bn0',"
+                   "     'queue': 'rx',"
+                   "     'interval': 1000"
+                   "}}}");
+
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+
+    response = qmp("{'execute': 'object-add',"
+                   " 'arguments': {"
+                   "   'qom-type': 'filter-buffer',"
+                   "   'id': 'qtest-f1',"
+                   "   'props': {"
+                   "     'netdev': 'qtest-bn0',"
+                   "     'queue': 'rx',"
+                   "     'interval': 1000"
+                   "}}}");
+
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+
+    response = qmp("{'execute': 'netdev_del',"
+                   " 'arguments': {"
+                   "   'id': 'qtest-bn0'"
+                   "}}");
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+
+    /* add back the netdev */
+    response = qmp("{'execute': 'netdev_add',"
+                   " 'arguments': {"
+                   "   'type': 'user',"
+                   "   'id': 'qtest-bn0'"
+                   "}}");
+    g_assert(response);
+    g_assert(!qdict_haskey(response, "error"));
+    qobject_unref(response);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+    char *args;
+    const char *devstr = "e1000";
+
+    if (g_str_equal(qtest_get_arch(), "s390x")) {
+        devstr = "virtio-net-ccw";
+    }
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/netfilter/addremove_one", add_one_netfilter);
+    qtest_add_func("/netfilter/remove_netdev_one",
+                   remove_netdev_with_one_netfilter);
+    qtest_add_func("/netfilter/addremove_multi", add_multi_netfilter);
+    qtest_add_func("/netfilter/remove_netdev_multi",
+                   remove_netdev_with_multi_netfilter);
+
+    args = g_strdup_printf("-netdev user,id=qtest-bn0 "
+                           "-device %s,netdev=qtest-bn0", devstr);
+    qtest_start(args);
+    ret = g_test_run();
+
+    qtest_end();
+    g_free(args);
+
+    return ret;
+}
diff --git a/tests/qtest/test-x86-cpuid-compat.c b/tests/qtest/test-x86-cpuid-compat.c
new file mode 100644 (file)
index 0000000..772287b
--- /dev/null
@@ -0,0 +1,381 @@
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qmp/qnum.h"
+#include "qapi/qmp/qbool.h"
+#include "libqtest-single.h"
+
+static char *get_cpu0_qom_path(void)
+{
+    QDict *resp;
+    QList *ret;
+    QDict *cpu0;
+    char *path;
+
+    resp = qmp("{'execute': 'query-cpus', 'arguments': {}}");
+    g_assert(qdict_haskey(resp, "return"));
+    ret = qdict_get_qlist(resp, "return");
+
+    cpu0 = qobject_to(QDict, qlist_peek(ret));
+    path = g_strdup(qdict_get_str(cpu0, "qom_path"));
+    qobject_unref(resp);
+    return path;
+}
+
+static QObject *qom_get(const char *path, const char *prop)
+{
+    QDict *resp = qmp("{ 'execute': 'qom-get',"
+                      "  'arguments': { 'path': %s,"
+                      "                 'property': %s } }",
+                      path, prop);
+    QObject *ret = qdict_get(resp, "return");
+    qobject_ref(ret);
+    qobject_unref(resp);
+    return ret;
+}
+
+static bool qom_get_bool(const char *path, const char *prop)
+{
+    QBool *value = qobject_to(QBool, qom_get(path, prop));
+    bool b = qbool_get_bool(value);
+
+    qobject_unref(value);
+    return b;
+}
+
+typedef struct CpuidTestArgs {
+    const char *cmdline;
+    const char *property;
+    int64_t expected_value;
+} CpuidTestArgs;
+
+static void test_cpuid_prop(const void *data)
+{
+    const CpuidTestArgs *args = data;
+    char *path;
+    QNum *value;
+    int64_t val;
+
+    qtest_start(args->cmdline);
+    path = get_cpu0_qom_path();
+    value = qobject_to(QNum, qom_get(path, args->property));
+    g_assert(qnum_get_try_int(value, &val));
+    g_assert_cmpint(val, ==, args->expected_value);
+    qtest_end();
+
+    qobject_unref(value);
+    g_free(path);
+}
+
+static void add_cpuid_test(const char *name, const char *cmdline,
+                           const char *property, int64_t expected_value)
+{
+    CpuidTestArgs *args = g_new0(CpuidTestArgs, 1);
+    args->cmdline = cmdline;
+    args->property = property;
+    args->expected_value = expected_value;
+    qtest_add_data_func(name, args, test_cpuid_prop);
+}
+
+
+/* Parameters to a add_feature_test() test case */
+typedef struct FeatureTestArgs {
+    /* cmdline to start QEMU */
+    const char *cmdline;
+    /*
+     * cpuid-input-eax and cpuid-input-ecx values to look for,
+     * in "feature-words" and "filtered-features" properties.
+     */
+    uint32_t in_eax, in_ecx;
+    /* The register name to look for, in the X86CPUFeatureWordInfo array */
+    const char *reg;
+    /* The bit to check in X86CPUFeatureWordInfo.features */
+    int bitnr;
+    /* The expected value for the bit in (X86CPUFeatureWordInfo.features) */
+    bool expected_value;
+} FeatureTestArgs;
+
+/* Get the value for a feature word in a X86CPUFeatureWordInfo list */
+static uint32_t get_feature_word(QList *features, uint32_t eax, uint32_t ecx,
+                                 const char *reg)
+{
+    const QListEntry *e;
+
+    for (e = qlist_first(features); e; e = qlist_next(e)) {
+        QDict *w = qobject_to(QDict, qlist_entry_obj(e));
+        const char *rreg = qdict_get_str(w, "cpuid-register");
+        uint32_t reax = qdict_get_int(w, "cpuid-input-eax");
+        bool has_ecx = qdict_haskey(w, "cpuid-input-ecx");
+        uint32_t recx = 0;
+        int64_t val;
+
+        if (has_ecx) {
+            recx = qdict_get_int(w, "cpuid-input-ecx");
+        }
+        if (eax == reax && (!has_ecx || ecx == recx) && !strcmp(rreg, reg)) {
+            g_assert(qnum_get_try_int(qobject_to(QNum,
+                                                 qdict_get(w, "features")),
+                                      &val));
+            return val;
+        }
+    }
+    return 0;
+}
+
+static void test_feature_flag(const void *data)
+{
+    const FeatureTestArgs *args = data;
+    char *path;
+    QList *present, *filtered;
+    uint32_t value;
+
+    qtest_start(args->cmdline);
+    path = get_cpu0_qom_path();
+    present = qobject_to(QList, qom_get(path, "feature-words"));
+    filtered = qobject_to(QList, qom_get(path, "filtered-features"));
+    value = get_feature_word(present, args->in_eax, args->in_ecx, args->reg);
+    value |= get_feature_word(filtered, args->in_eax, args->in_ecx, args->reg);
+    qtest_end();
+
+    g_assert(!!(value & (1U << args->bitnr)) == args->expected_value);
+
+    qobject_unref(present);
+    qobject_unref(filtered);
+    g_free(path);
+}
+
+/*
+ * Add test case to ensure that a given feature flag is set in
+ * either "feature-words" or "filtered-features", when running QEMU
+ * using cmdline
+ */
+static FeatureTestArgs *add_feature_test(const char *name, const char *cmdline,
+                                         uint32_t eax, uint32_t ecx,
+                                         const char *reg, int bitnr,
+                                         bool expected_value)
+{
+    FeatureTestArgs *args = g_new0(FeatureTestArgs, 1);
+    args->cmdline = cmdline;
+    args->in_eax = eax;
+    args->in_ecx = ecx;
+    args->reg = reg;
+    args->bitnr = bitnr;
+    args->expected_value = expected_value;
+    qtest_add_data_func(name, args, test_feature_flag);
+    return args;
+}
+
+static void test_plus_minus_subprocess(void)
+{
+    char *path;
+
+    /* Rules:
+     * 1)"-foo" overrides "+foo"
+     * 2) "[+-]foo" overrides "foo=..."
+     * 3) Old feature names with underscores (e.g. "sse4_2")
+     *    should keep working
+     *
+     * Note: rules 1 and 2 are planned to be removed soon, and
+     * should generate a warning.
+     */
+    qtest_start("-cpu pentium,-fpu,+fpu,-mce,mce=on,+cx8,cx8=off,+sse4_1,sse4_2=on");
+    path = get_cpu0_qom_path();
+
+    g_assert_false(qom_get_bool(path, "fpu"));
+    g_assert_false(qom_get_bool(path, "mce"));
+    g_assert_true(qom_get_bool(path, "cx8"));
+
+    /* Test both the original and the alias feature names: */
+    g_assert_true(qom_get_bool(path, "sse4-1"));
+    g_assert_true(qom_get_bool(path, "sse4.1"));
+
+    g_assert_true(qom_get_bool(path, "sse4-2"));
+    g_assert_true(qom_get_bool(path, "sse4.2"));
+
+    qtest_end();
+    g_free(path);
+}
+
+static void test_plus_minus(void)
+{
+    g_test_trap_subprocess("/x86/cpuid/parsing-plus-minus/subprocess", 0, 0);
+    g_test_trap_assert_passed();
+    g_test_trap_assert_stderr("*Ambiguous CPU model string. "
+                              "Don't mix both \"-mce\" and \"mce=on\"*");
+    g_test_trap_assert_stderr("*Ambiguous CPU model string. "
+                              "Don't mix both \"+cx8\" and \"cx8=off\"*");
+    g_test_trap_assert_stdout("");
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/x86/cpuid/parsing-plus-minus/subprocess",
+                    test_plus_minus_subprocess);
+    g_test_add_func("/x86/cpuid/parsing-plus-minus", test_plus_minus);
+
+    /* Original level values for CPU models: */
+    add_cpuid_test("x86/cpuid/phenom/level",
+                   "-cpu phenom", "level", 5);
+    add_cpuid_test("x86/cpuid/Conroe/level",
+                   "-cpu Conroe", "level", 10);
+    add_cpuid_test("x86/cpuid/SandyBridge/level",
+                   "-cpu SandyBridge", "level", 0xd);
+    add_cpuid_test("x86/cpuid/486/xlevel",
+                   "-cpu 486", "xlevel", 0);
+    add_cpuid_test("x86/cpuid/core2duo/xlevel",
+                   "-cpu core2duo", "xlevel", 0x80000008);
+    add_cpuid_test("x86/cpuid/phenom/xlevel",
+                   "-cpu phenom", "xlevel", 0x8000001A);
+    add_cpuid_test("x86/cpuid/athlon/xlevel",
+                   "-cpu athlon", "xlevel", 0x80000008);
+
+    /* If level is not large enough, it should increase automatically: */
+    /* CPUID[6].EAX: */
+    add_cpuid_test("x86/cpuid/auto-level/phenom/arat",
+                   "-cpu 486,+arat", "level", 6);
+    /* CPUID[EAX=7,ECX=0].EBX: */
+    add_cpuid_test("x86/cpuid/auto-level/phenom/fsgsbase",
+                   "-cpu phenom,+fsgsbase", "level", 7);
+    /* CPUID[EAX=7,ECX=0].ECX: */
+    add_cpuid_test("x86/cpuid/auto-level/phenom/avx512vbmi",
+                   "-cpu phenom,+avx512vbmi", "level", 7);
+    /* CPUID[EAX=0xd,ECX=1].EAX: */
+    add_cpuid_test("x86/cpuid/auto-level/phenom/xsaveopt",
+                   "-cpu phenom,+xsaveopt", "level", 0xd);
+    /* CPUID[8000_0001].EDX: */
+    add_cpuid_test("x86/cpuid/auto-xlevel/486/3dnow",
+                   "-cpu 486,+3dnow", "xlevel", 0x80000001);
+    /* CPUID[8000_0001].ECX: */
+    add_cpuid_test("x86/cpuid/auto-xlevel/486/sse4a",
+                   "-cpu 486,+sse4a", "xlevel", 0x80000001);
+    /* CPUID[8000_0007].EDX: */
+    add_cpuid_test("x86/cpuid/auto-xlevel/486/invtsc",
+                   "-cpu 486,+invtsc", "xlevel", 0x80000007);
+    /* CPUID[8000_000A].EDX: */
+    add_cpuid_test("x86/cpuid/auto-xlevel/486/npt",
+                   "-cpu 486,+npt", "xlevel", 0x8000000A);
+    /* CPUID[C000_0001].EDX: */
+    add_cpuid_test("x86/cpuid/auto-xlevel2/phenom/xstore",
+                   "-cpu phenom,+xstore", "xlevel2", 0xC0000001);
+    /* SVM needs CPUID[0x8000000A] */
+    add_cpuid_test("x86/cpuid/auto-xlevel/athlon/svm",
+                   "-cpu athlon,+svm", "xlevel", 0x8000000A);
+
+
+    /* If level is already large enough, it shouldn't change: */
+    add_cpuid_test("x86/cpuid/auto-level/SandyBridge/multiple",
+                   "-cpu SandyBridge,+arat,+fsgsbase,+avx512vbmi",
+                   "level", 0xd);
+    /* If level is explicitly set, it shouldn't change: */
+    add_cpuid_test("x86/cpuid/auto-level/486/fixed/0xF",
+                   "-cpu 486,level=0xF,+arat,+fsgsbase,+avx512vbmi,+xsaveopt",
+                   "level", 0xF);
+    add_cpuid_test("x86/cpuid/auto-level/486/fixed/2",
+                   "-cpu 486,level=2,+arat,+fsgsbase,+avx512vbmi,+xsaveopt",
+                   "level", 2);
+    add_cpuid_test("x86/cpuid/auto-level/486/fixed/0",
+                   "-cpu 486,level=0,+arat,+fsgsbase,+avx512vbmi,+xsaveopt",
+                   "level", 0);
+
+    /* if xlevel is already large enough, it shouldn't change: */
+    add_cpuid_test("x86/cpuid/auto-xlevel/phenom/3dnow",
+                   "-cpu phenom,+3dnow,+sse4a,+invtsc,+npt,+svm",
+                   "xlevel", 0x8000001A);
+    /* If xlevel is explicitly set, it shouldn't change: */
+    add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/80000002",
+                   "-cpu 486,xlevel=0x80000002,+3dnow,+sse4a,+invtsc,+npt,+svm",
+                   "xlevel", 0x80000002);
+    add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/8000001A",
+                   "-cpu 486,xlevel=0x8000001A,+3dnow,+sse4a,+invtsc,+npt,+svm",
+                   "xlevel", 0x8000001A);
+    add_cpuid_test("x86/cpuid/auto-xlevel/phenom/fixed/0",
+                   "-cpu 486,xlevel=0,+3dnow,+sse4a,+invtsc,+npt,+svm",
+                   "xlevel", 0);
+
+    /* if xlevel2 is already large enough, it shouldn't change: */
+    add_cpuid_test("x86/cpuid/auto-xlevel2/486/fixed",
+                   "-cpu 486,xlevel2=0xC0000002,+xstore",
+                   "xlevel2", 0xC0000002);
+
+    /* Check compatibility of old machine-types that didn't
+     * auto-increase level/xlevel/xlevel2: */
+
+    add_cpuid_test("x86/cpuid/auto-level/pc-2.7",
+                   "-machine pc-i440fx-2.7 -cpu 486,+arat,+avx512vbmi,+xsaveopt",
+                   "level", 1);
+    add_cpuid_test("x86/cpuid/auto-xlevel/pc-2.7",
+                   "-machine pc-i440fx-2.7 -cpu 486,+3dnow,+sse4a,+invtsc,+npt,+svm",
+                   "xlevel", 0);
+    add_cpuid_test("x86/cpuid/auto-xlevel2/pc-2.7",
+                   "-machine pc-i440fx-2.7 -cpu 486,+xstore",
+                   "xlevel2", 0);
+    /*
+     * QEMU 1.4.0 had auto-level enabled for CPUID[7], already,
+     * and the compat code that sets default level shouldn't
+     * disable the auto-level=7 code:
+     */
+    add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-1.4/off",
+                   "-machine pc-i440fx-1.4 -cpu Nehalem",
+                   "level", 2);
+    add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-1.5/on",
+                   "-machine pc-i440fx-1.4 -cpu Nehalem,+smap",
+                   "level", 7);
+    add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.3/off",
+                   "-machine pc-i440fx-2.3 -cpu Penryn",
+                   "level", 4);
+    add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.3/on",
+                   "-machine pc-i440fx-2.3 -cpu Penryn,+erms",
+                   "level", 7);
+    add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.9/off",
+                   "-machine pc-i440fx-2.9 -cpu Conroe",
+                   "level", 10);
+    add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.9/on",
+                   "-machine pc-i440fx-2.9 -cpu Conroe,+erms",
+                   "level", 10);
+
+    /*
+     * xlevel doesn't have any feature that triggers auto-level
+     * code on old machine-types.  Just check that the compat code
+     * is working correctly:
+     */
+    add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.3",
+                   "-machine pc-i440fx-2.3 -cpu SandyBridge",
+                   "xlevel", 0x8000000a);
+    add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-off",
+                   "-machine pc-i440fx-2.4 -cpu SandyBridge,",
+                   "xlevel", 0x80000008);
+    add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-on",
+                   "-machine pc-i440fx-2.4 -cpu SandyBridge,+npt",
+                   "xlevel", 0x80000008);
+
+    /* Test feature parsing */
+    add_feature_test("x86/cpuid/features/plus",
+                     "-cpu 486,+arat",
+                     6, 0, "EAX", 2, true);
+    add_feature_test("x86/cpuid/features/minus",
+                     "-cpu pentium,-mmx",
+                     1, 0, "EDX", 23, false);
+    add_feature_test("x86/cpuid/features/on",
+                     "-cpu 486,arat=on",
+                     6, 0, "EAX", 2, true);
+    add_feature_test("x86/cpuid/features/off",
+                     "-cpu pentium,mmx=off",
+                     1, 0, "EDX", 23, false);
+    add_feature_test("x86/cpuid/features/max-plus-invtsc",
+                     "-cpu max,+invtsc",
+                     0x80000007, 0, "EDX", 8, true);
+    add_feature_test("x86/cpuid/features/max-invtsc-on",
+                     "-cpu max,invtsc=on",
+                     0x80000007, 0, "EDX", 8, true);
+    add_feature_test("x86/cpuid/features/max-minus-mmx",
+                     "-cpu max,-mmx",
+                     1, 0, "EDX", 23, false);
+    add_feature_test("x86/cpuid/features/max-invtsc-on,mmx=off",
+                     "-cpu max,mmx=off",
+                     1, 0, "EDX", 23, false);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/tmp105-test.c b/tests/qtest/tmp105-test.c
new file mode 100644 (file)
index 0000000..f930a96
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * QTest testcase for the TMP105 temperature sensor
+ *
+ * Copyright (c) 2012 Andreas Färber
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqtest-single.h"
+#include "libqos/qgraph.h"
+#include "libqos/i2c.h"
+#include "qapi/qmp/qdict.h"
+#include "hw/misc/tmp105_regs.h"
+
+#define TMP105_TEST_ID   "tmp105-test"
+#define TMP105_TEST_ADDR 0x49
+
+static int qmp_tmp105_get_temperature(const char *id)
+{
+    QDict *response;
+    int ret;
+
+    response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, "
+                   "'property': 'temperature' } }", id);
+    g_assert(qdict_haskey(response, "return"));
+    ret = qdict_get_int(response, "return");
+    qobject_unref(response);
+    return ret;
+}
+
+static void qmp_tmp105_set_temperature(const char *id, int value)
+{
+    QDict *response;
+
+    response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
+                   "'property': 'temperature', 'value': %d } }", id, value);
+    g_assert(qdict_haskey(response, "return"));
+    qobject_unref(response);
+}
+
+#define TMP105_PRECISION (1000/16)
+static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc)
+{
+    uint16_t value;
+    QI2CDevice *i2cdev = (QI2CDevice *)obj;
+
+    value = qmp_tmp105_get_temperature(TMP105_TEST_ID);
+    g_assert_cmpuint(value, ==, 0);
+
+    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
+    g_assert_cmphex(value, ==, 0);
+
+    qmp_tmp105_set_temperature(TMP105_TEST_ID, 20000);
+    value = qmp_tmp105_get_temperature(TMP105_TEST_ID);
+    g_assert_cmpuint(value, ==, 20000);
+
+    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
+    g_assert_cmphex(value, ==, 0x1400);
+
+    qmp_tmp105_set_temperature(TMP105_TEST_ID, 20938); /* 20 + 15/16 */
+    value = qmp_tmp105_get_temperature(TMP105_TEST_ID);
+    g_assert_cmpuint(value, >=, 20938 - TMP105_PRECISION/2);
+    g_assert_cmpuint(value, <, 20938 + TMP105_PRECISION/2);
+
+    /* Set config */
+    i2c_set8(i2cdev, TMP105_REG_CONFIG, 0x60);
+    value = i2c_get8(i2cdev, TMP105_REG_CONFIG);
+    g_assert_cmphex(value, ==, 0x60);
+
+    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
+    g_assert_cmphex(value, ==, 0x14f0);
+
+    /* Set precision to 9, 10, 11 bits.  */
+    i2c_set8(i2cdev, TMP105_REG_CONFIG, 0x00);
+    g_assert_cmphex(i2c_get8(i2cdev, TMP105_REG_CONFIG), ==, 0x00);
+    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
+    g_assert_cmphex(value, ==, 0x1480);
+
+    i2c_set8(i2cdev, TMP105_REG_CONFIG, 0x20);
+    g_assert_cmphex(i2c_get8(i2cdev, TMP105_REG_CONFIG), ==, 0x20);
+    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
+    g_assert_cmphex(value, ==, 0x14c0);
+
+    i2c_set8(i2cdev, TMP105_REG_CONFIG, 0x40);
+    g_assert_cmphex(i2c_get8(i2cdev, TMP105_REG_CONFIG), ==, 0x40);
+    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
+    g_assert_cmphex(value, ==, 0x14e0);
+
+    /* stored precision remains the same */
+    value = qmp_tmp105_get_temperature(TMP105_TEST_ID);
+    g_assert_cmpuint(value, >=, 20938 - TMP105_PRECISION/2);
+    g_assert_cmpuint(value, <, 20938 + TMP105_PRECISION/2);
+
+    i2c_set8(i2cdev, TMP105_REG_CONFIG, 0x60);
+    g_assert_cmphex(i2c_get8(i2cdev, TMP105_REG_CONFIG), ==, 0x60);
+    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
+    g_assert_cmphex(value, ==, 0x14f0);
+
+    i2c_set16(i2cdev, TMP105_REG_T_LOW, 0x1234);
+    g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_LOW), ==, 0x1234);
+    i2c_set16(i2cdev, TMP105_REG_T_HIGH, 0x4231);
+    g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_HIGH), ==, 0x4231);
+}
+
+static void tmp105_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "id=" TMP105_TEST_ID ",address=0x49"
+    };
+    add_qi2c_address(&opts, &(QI2CAddress) { 0x49 });
+
+    qos_node_create_driver("tmp105", i2c_device_create);
+    qos_node_consumes("tmp105", "i2c-bus", &opts);
+
+    qos_add_test("tx-rx", "tmp105", send_and_receive, NULL);
+}
+libqos_init(tmp105_register_nodes);
diff --git a/tests/qtest/tpm-crb-swtpm-test.c b/tests/qtest/tpm-crb-swtpm-test.c
new file mode 100644 (file)
index 0000000..2c4fb8a
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * QTest testcase for TPM CRB talking to external swtpm and swtpm migration
+ *
+ * Copyright (c) 2018 IBM Corporation
+ *  with parts borrowed from migration-test.c that is:
+ *     Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *   Stefan Berger <[email protected]>
+ *
+ * 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 "libqtest.h"
+#include "qemu/module.h"
+#include "tpm-tests.h"
+
+typedef struct TestState {
+    char *src_tpm_path;
+    char *dst_tpm_path;
+    char *uri;
+} TestState;
+
+static void tpm_crb_swtpm_test(const void *data)
+{
+    const TestState *ts = data;
+
+    tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_transfer, "tpm-crb");
+}
+
+static void tpm_crb_swtpm_migration_test(const void *data)
+{
+    const TestState *ts = data;
+
+    tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri,
+                                  tpm_util_crb_transfer, "tpm-crb");
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+    TestState ts = { 0 };
+
+    ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-crb-swtpm-test.XXXXXX", NULL);
+    ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-crb-swtpm-test.XXXXXX", NULL);
+    ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path);
+
+    module_call_init(MODULE_INIT_QOM);
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_data_func("/tpm/crb-swtpm/test", &ts, tpm_crb_swtpm_test);
+    qtest_add_data_func("/tpm/crb-swtpm-migration/test", &ts,
+                        tpm_crb_swtpm_migration_test);
+    ret = g_test_run();
+
+    g_rmdir(ts.dst_tpm_path);
+    g_free(ts.dst_tpm_path);
+    g_rmdir(ts.src_tpm_path);
+    g_free(ts.src_tpm_path);
+    g_free(ts.uri);
+
+    return ret;
+}
diff --git a/tests/qtest/tpm-crb-test.c b/tests/qtest/tpm-crb-test.c
new file mode 100644 (file)
index 0000000..632fb7f
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * QTest testcase for TPM CRB
+ *
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * Authors:
+ *   Marc-André Lureau <[email protected]>
+ *
+ * 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 "hw/acpi/tpm.h"
+#include "io/channel-socket.h"
+#include "libqtest-single.h"
+#include "qemu/module.h"
+#include "tpm-emu.h"
+
+#define TPM_CMD "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"
+
+static void tpm_crb_test(const void *data)
+{
+    const TestState *s = data;
+    uint32_t intfid = readl(TPM_CRB_ADDR_BASE + A_CRB_INTF_ID);
+    uint32_t csize = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_SIZE);
+    uint64_t caddr = readq(TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR);
+    uint32_t rsize = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_SIZE);
+    uint64_t raddr = readq(TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR);
+    uint8_t locstate = readb(TPM_CRB_ADDR_BASE + A_CRB_LOC_STATE);
+    uint32_t locctrl = readl(TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL);
+    uint32_t locsts = readl(TPM_CRB_ADDR_BASE + A_CRB_LOC_STS);
+    uint32_t sts = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
+
+    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, InterfaceType), ==, 1);
+    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, InterfaceVersion), ==, 1);
+    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapLocality), ==, 0);
+    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapCRBIdleBypass), ==, 0);
+    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapDataXferSizeSupport),
+                    ==, 3);
+    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapFIFO), ==, 0);
+    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapCRB), ==, 1);
+    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, InterfaceSelector), ==, 1);
+    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, RID), ==, 0);
+
+    g_assert_cmpint(csize, >=, 128);
+    g_assert_cmpint(rsize, >=, 128);
+    g_assert_cmpint(caddr, >, TPM_CRB_ADDR_BASE);
+    g_assert_cmpint(raddr, >, TPM_CRB_ADDR_BASE);
+
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmEstablished), ==, 1);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, locAssigned), ==, 0);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, activeLocality), ==, 0);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, reserved), ==, 0);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmRegValidSts), ==, 1);
+
+    g_assert_cmpint(locctrl, ==, 0);
+
+    g_assert_cmpint(FIELD_EX32(locsts, CRB_LOC_STS, Granted), ==, 0);
+    g_assert_cmpint(FIELD_EX32(locsts, CRB_LOC_STS, beenSeized), ==, 0);
+
+    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmIdle), ==, 1);
+    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmSts), ==, 0);
+
+    /* request access to locality 0 */
+    writeb(TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 1);
+
+    /* granted bit must be set now */
+    locsts = readl(TPM_CRB_ADDR_BASE + A_CRB_LOC_STS);
+    g_assert_cmpint(FIELD_EX32(locsts, CRB_LOC_STS, Granted), ==, 1);
+    g_assert_cmpint(FIELD_EX32(locsts, CRB_LOC_STS, beenSeized), ==, 0);
+
+    /* we must have an assigned locality */
+    locstate = readb(TPM_CRB_ADDR_BASE + A_CRB_LOC_STATE);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmEstablished), ==, 1);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, locAssigned), ==, 1);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, activeLocality), ==, 0);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, reserved), ==, 0);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmRegValidSts), ==, 1);
+
+    /* set into ready state */
+    writel(TPM_CRB_ADDR_BASE + A_CRB_CTRL_REQ, 1);
+
+    /* TPM must not be in the idle state */
+    sts = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
+    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmIdle), ==, 0);
+    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmSts), ==, 0);
+
+    memwrite(caddr, TPM_CMD, sizeof(TPM_CMD));
+
+    uint32_t start = 1;
+    uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+    writel(TPM_CRB_ADDR_BASE + A_CRB_CTRL_START, start);
+    do {
+        start = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
+        if ((start & 1) == 0) {
+            break;
+        }
+    } while (g_get_monotonic_time() < end_time);
+    start = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
+    g_assert_cmpint(start & 1, ==, 0);
+
+    /* TPM must still not be in the idle state */
+    sts = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
+    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmIdle), ==, 0);
+    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmSts), ==, 0);
+
+    struct tpm_hdr tpm_msg;
+    memread(raddr, &tpm_msg, sizeof(tpm_msg));
+    g_assert_cmpmem(&tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg));
+
+    /* set TPM into idle state */
+    writel(TPM_CRB_ADDR_BASE + A_CRB_CTRL_REQ, 2);
+
+    /* idle state must be indicated now */
+    sts = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
+    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmIdle), ==, 1);
+    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmSts), ==, 0);
+
+    /* relinquish locality */
+    writel(TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 2);
+
+    /* Granted flag must be cleared */
+    sts = readl(TPM_CRB_ADDR_BASE + A_CRB_LOC_STS);
+    g_assert_cmpint(FIELD_EX32(sts, CRB_LOC_STS, Granted), ==, 0);
+    g_assert_cmpint(FIELD_EX32(sts, CRB_LOC_STS, beenSeized), ==, 0);
+
+    /* no locality may be assigned */
+    locstate = readb(TPM_CRB_ADDR_BASE + A_CRB_LOC_STATE);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmEstablished), ==, 1);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, locAssigned), ==, 0);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, activeLocality), ==, 0);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, reserved), ==, 0);
+    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmRegValidSts), ==, 1);
+
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+    char *args, *tmp_path = g_dir_make_tmp("qemu-tpm-crb-test.XXXXXX", NULL);
+    GThread *thread;
+    TestState test;
+
+    module_call_init(MODULE_INIT_QOM);
+    g_test_init(&argc, &argv, NULL);
+
+    test.addr = g_new0(SocketAddress, 1);
+    test.addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+    test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL);
+    g_mutex_init(&test.data_mutex);
+    g_cond_init(&test.data_cond);
+    test.data_cond_signal = false;
+
+    thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test);
+    tpm_emu_test_wait_cond(&test);
+
+    args = g_strdup_printf(
+        "-chardev socket,id=chr,path=%s "
+        "-tpmdev emulator,id=dev,chardev=chr "
+        "-device tpm-crb,tpmdev=dev",
+        test.addr->u.q_unix.path);
+    qtest_start(args);
+
+    qtest_add_data_func("/tpm-crb/test", &test, tpm_crb_test);
+    ret = g_test_run();
+
+    qtest_end();
+
+    g_thread_join(thread);
+    g_unlink(test.addr->u.q_unix.path);
+    qapi_free_SocketAddress(test.addr);
+    g_rmdir(tmp_path);
+    g_free(tmp_path);
+    g_free(args);
+    return ret;
+}
diff --git a/tests/qtest/tpm-emu.c b/tests/qtest/tpm-emu.c
new file mode 100644 (file)
index 0000000..c43ac4a
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Minimal TPM emulator for TPM test cases
+ *
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * Authors:
+ *   Marc-André Lureau <[email protected]>
+ *
+ * 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 "hw/tpm/tpm_ioctl.h"
+#include "io/channel-socket.h"
+#include "qapi/error.h"
+#include "tpm-emu.h"
+
+void tpm_emu_test_wait_cond(TestState *s)
+{
+    gint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+
+    g_mutex_lock(&s->data_mutex);
+
+    if (!s->data_cond_signal &&
+        !g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
+        g_assert_not_reached();
+    }
+
+    s->data_cond_signal = false;
+
+    g_mutex_unlock(&s->data_mutex);
+}
+
+static void *tpm_emu_tpm_thread(void *data)
+{
+    TestState *s = data;
+    QIOChannel *ioc = s->tpm_ioc;
+
+    s->tpm_msg = g_new(struct tpm_hdr, 1);
+    while (true) {
+        int minhlen = sizeof(s->tpm_msg->tag) + sizeof(s->tpm_msg->len);
+
+        if (!qio_channel_read(ioc, (char *)s->tpm_msg, minhlen, &error_abort)) {
+            break;
+        }
+        s->tpm_msg->tag = be16_to_cpu(s->tpm_msg->tag);
+        s->tpm_msg->len = be32_to_cpu(s->tpm_msg->len);
+        g_assert_cmpint(s->tpm_msg->len, >=, minhlen);
+        g_assert_cmpint(s->tpm_msg->tag, ==, TPM2_ST_NO_SESSIONS);
+
+        s->tpm_msg = g_realloc(s->tpm_msg, s->tpm_msg->len);
+        qio_channel_read(ioc, (char *)&s->tpm_msg->code,
+                         s->tpm_msg->len - minhlen, &error_abort);
+        s->tpm_msg->code = be32_to_cpu(s->tpm_msg->code);
+
+        /* reply error */
+        s->tpm_msg->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
+        s->tpm_msg->len = cpu_to_be32(sizeof(struct tpm_hdr));
+        s->tpm_msg->code = cpu_to_be32(TPM_RC_FAILURE);
+        qio_channel_write(ioc, (char *)s->tpm_msg, be32_to_cpu(s->tpm_msg->len),
+                          &error_abort);
+    }
+
+    g_free(s->tpm_msg);
+    s->tpm_msg = NULL;
+    object_unref(OBJECT(s->tpm_ioc));
+    return NULL;
+}
+
+void *tpm_emu_ctrl_thread(void *data)
+{
+    TestState *s = data;
+    QIOChannelSocket *lioc = qio_channel_socket_new();
+    QIOChannel *ioc;
+
+    qio_channel_socket_listen_sync(lioc, s->addr, 1, &error_abort);
+
+    g_mutex_lock(&s->data_mutex);
+    s->data_cond_signal = true;
+    g_mutex_unlock(&s->data_mutex);
+    g_cond_signal(&s->data_cond);
+
+    qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
+    ioc = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
+    g_assert(ioc);
+
+    {
+        uint32_t cmd = 0;
+        struct iovec iov = { .iov_base = &cmd, .iov_len = sizeof(cmd) };
+        int *pfd = NULL;
+        size_t nfd = 0;
+
+        qio_channel_readv_full(ioc, &iov, 1, &pfd, &nfd, &error_abort);
+        cmd = be32_to_cpu(cmd);
+        g_assert_cmpint(cmd, ==, CMD_SET_DATAFD);
+        g_assert_cmpint(nfd, ==, 1);
+        s->tpm_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(*pfd, &error_abort));
+        g_free(pfd);
+
+        cmd = 0;
+        qio_channel_write(ioc, (char *)&cmd, sizeof(cmd), &error_abort);
+
+        s->emu_tpm_thread = g_thread_new(NULL, tpm_emu_tpm_thread, s);
+    }
+
+    while (true) {
+        uint32_t cmd;
+        ssize_t ret;
+
+        ret = qio_channel_read(ioc, (char *)&cmd, sizeof(cmd), NULL);
+        if (ret <= 0) {
+            break;
+        }
+
+        cmd = be32_to_cpu(cmd);
+        switch (cmd) {
+        case CMD_GET_CAPABILITY: {
+            ptm_cap cap = cpu_to_be64(0x3fff);
+            qio_channel_write(ioc, (char *)&cap, sizeof(cap), &error_abort);
+            break;
+        }
+        case CMD_INIT: {
+            ptm_init init;
+            qio_channel_read(ioc, (char *)&init.u.req, sizeof(init.u.req),
+                              &error_abort);
+            init.u.resp.tpm_result = 0;
+            qio_channel_write(ioc, (char *)&init.u.resp, sizeof(init.u.resp),
+                              &error_abort);
+            break;
+        }
+        case CMD_SHUTDOWN: {
+            ptm_res res = 0;
+            qio_channel_write(ioc, (char *)&res, sizeof(res), &error_abort);
+            /* the tpm data thread is expected to finish now */
+            g_thread_join(s->emu_tpm_thread);
+            break;
+        }
+        case CMD_STOP: {
+            ptm_res res = 0;
+            qio_channel_write(ioc, (char *)&res, sizeof(res), &error_abort);
+            break;
+        }
+        case CMD_SET_BUFFERSIZE: {
+            ptm_setbuffersize sbs;
+            qio_channel_read(ioc, (char *)&sbs.u.req, sizeof(sbs.u.req),
+                             &error_abort);
+            sbs.u.resp.buffersize = sbs.u.req.buffersize ?: cpu_to_be32(4096);
+            sbs.u.resp.tpm_result = 0;
+            sbs.u.resp.minsize = cpu_to_be32(128);
+            sbs.u.resp.maxsize = cpu_to_be32(4096);
+            qio_channel_write(ioc, (char *)&sbs.u.resp, sizeof(sbs.u.resp),
+                              &error_abort);
+            break;
+        }
+        case CMD_SET_LOCALITY: {
+            ptm_loc loc;
+            /* Note: this time it's not u.req / u.resp... */
+            qio_channel_read(ioc, (char *)&loc, sizeof(loc), &error_abort);
+            g_assert_cmpint(loc.u.req.loc, ==, 0);
+            loc.u.resp.tpm_result = 0;
+            qio_channel_write(ioc, (char *)&loc, sizeof(loc), &error_abort);
+            break;
+        }
+        case CMD_GET_TPMESTABLISHED: {
+            ptm_est est = {
+                .u.resp.bit = 0,
+            };
+            qio_channel_write(ioc, (char *)&est, sizeof(est), &error_abort);
+            break;
+        }
+        default:
+            g_debug("unimplemented %u", cmd);
+            g_assert_not_reached();
+        }
+    }
+
+    object_unref(OBJECT(ioc));
+    object_unref(OBJECT(lioc));
+    return NULL;
+}
diff --git a/tests/qtest/tpm-emu.h b/tests/qtest/tpm-emu.h
new file mode 100644 (file)
index 0000000..a4f1d64
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Minimal TPM emulator for TPM test cases
+ *
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * Authors:
+ *   Marc-André Lureau <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TESTS_TPM_EMU_H
+#define TESTS_TPM_EMU_H
+
+#define TPM_RC_FAILURE 0x101
+#define TPM2_ST_NO_SESSIONS 0x8001
+
+struct tpm_hdr {
+    uint16_t tag;
+    uint32_t len;
+    uint32_t code; /*ordinal/error */
+    char buffer[];
+} QEMU_PACKED;
+
+typedef struct TestState {
+    GMutex data_mutex;
+    GCond data_cond;
+    bool data_cond_signal;
+    SocketAddress *addr;
+    QIOChannel *tpm_ioc;
+    GThread *emu_tpm_thread;
+    struct tpm_hdr *tpm_msg;
+} TestState;
+
+void tpm_emu_test_wait_cond(TestState *s);
+void *tpm_emu_ctrl_thread(void *data);
+
+#endif /* TESTS_TPM_EMU_H */
diff --git a/tests/qtest/tpm-tests.c b/tests/qtest/tpm-tests.c
new file mode 100644 (file)
index 0000000..6e45a0b
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * QTest TPM commont test code
+ *
+ * Copyright (c) 2018 IBM Corporation
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * Authors:
+ *   Stefan Berger <[email protected]>
+ *   Marc-André Lureau <[email protected]>
+ *
+ * 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 "libqtest-single.h"
+#include "tpm-tests.h"
+
+static bool
+tpm_test_swtpm_skip(void)
+{
+    if (!tpm_util_swtpm_has_tpm2()) {
+        g_test_skip("swtpm not in PATH or missing --tpm2 support");
+        return true;
+    }
+
+    return false;
+}
+
+void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
+                         const char *ifmodel)
+{
+    char *args = NULL;
+    QTestState *s;
+    SocketAddress *addr = NULL;
+    gboolean succ;
+    GPid swtpm_pid;
+    GError *error = NULL;
+
+    if (tpm_test_swtpm_skip()) {
+        return;
+    }
+
+    succ = tpm_util_swtpm_start(src_tpm_path, &swtpm_pid, &addr, &error);
+    g_assert_true(succ);
+
+    args = g_strdup_printf(
+        "-chardev socket,id=chr,path=%s "
+        "-tpmdev emulator,id=dev,chardev=chr "
+        "-device %s,tpmdev=dev",
+        addr->u.q_unix.path, ifmodel);
+
+    s = qtest_start(args);
+    g_free(args);
+
+    tpm_util_startup(s, tx);
+    tpm_util_pcrextend(s, tx);
+
+    unsigned char tpm_pcrread_resp[] =
+        "\x80\x01\x00\x00\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00"
+        "\x00\x01\x00\x0b\x03\x00\x04\x00\x00\x00\x00\x01\x00\x20\xf6\x85"
+        "\x98\xe5\x86\x8d\xe6\x8b\x97\x29\x99\x60\xf2\x71\x7d\x17\x67\x89"
+        "\xa4\x2f\x9a\xae\xa8\xc7\xb7\xaa\x79\xa8\x62\x56\xc1\xde";
+    tpm_util_pcrread(s, tx, tpm_pcrread_resp,
+                     sizeof(tpm_pcrread_resp));
+
+    qtest_end();
+    tpm_util_swtpm_kill(swtpm_pid);
+
+    if (addr) {
+        g_unlink(addr->u.q_unix.path);
+        qapi_free_SocketAddress(addr);
+    }
+}
+
+void tpm_test_swtpm_migration_test(const char *src_tpm_path,
+                                   const char *dst_tpm_path,
+                                   const char *uri, tx_func *tx,
+                                   const char *ifmodel)
+{
+    gboolean succ;
+    GPid src_tpm_pid, dst_tpm_pid;
+    SocketAddress *src_tpm_addr = NULL, *dst_tpm_addr = NULL;
+    GError *error = NULL;
+    QTestState *src_qemu, *dst_qemu;
+
+    if (tpm_test_swtpm_skip()) {
+        return;
+    }
+
+    succ = tpm_util_swtpm_start(src_tpm_path, &src_tpm_pid,
+                                &src_tpm_addr, &error);
+    g_assert_true(succ);
+
+    succ = tpm_util_swtpm_start(dst_tpm_path, &dst_tpm_pid,
+                                &dst_tpm_addr, &error);
+    g_assert_true(succ);
+
+    tpm_util_migration_start_qemu(&src_qemu, &dst_qemu,
+                                  src_tpm_addr, dst_tpm_addr, uri,
+                                  ifmodel);
+
+    tpm_util_startup(src_qemu, tx);
+    tpm_util_pcrextend(src_qemu, tx);
+
+    unsigned char tpm_pcrread_resp[] =
+        "\x80\x01\x00\x00\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00"
+        "\x00\x01\x00\x0b\x03\x00\x04\x00\x00\x00\x00\x01\x00\x20\xf6\x85"
+        "\x98\xe5\x86\x8d\xe6\x8b\x97\x29\x99\x60\xf2\x71\x7d\x17\x67\x89"
+        "\xa4\x2f\x9a\xae\xa8\xc7\xb7\xaa\x79\xa8\x62\x56\xc1\xde";
+    tpm_util_pcrread(src_qemu, tx, tpm_pcrread_resp,
+                     sizeof(tpm_pcrread_resp));
+
+    tpm_util_migrate(src_qemu, uri);
+    tpm_util_wait_for_migration_complete(src_qemu);
+
+    tpm_util_pcrread(dst_qemu, tx, tpm_pcrread_resp,
+                     sizeof(tpm_pcrread_resp));
+
+    qtest_quit(dst_qemu);
+    qtest_quit(src_qemu);
+
+    tpm_util_swtpm_kill(dst_tpm_pid);
+    if (dst_tpm_addr) {
+        g_unlink(dst_tpm_addr->u.q_unix.path);
+        qapi_free_SocketAddress(dst_tpm_addr);
+    }
+
+    tpm_util_swtpm_kill(src_tpm_pid);
+    if (src_tpm_addr) {
+        g_unlink(src_tpm_addr->u.q_unix.path);
+        qapi_free_SocketAddress(src_tpm_addr);
+    }
+}
diff --git a/tests/qtest/tpm-tests.h b/tests/qtest/tpm-tests.h
new file mode 100644 (file)
index 0000000..b97688f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * QTest TPM commont test code
+ *
+ * Copyright (c) 2018 IBM Corporation
+ *
+ * Authors:
+ *   Stefan Berger <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TESTS_TPM_TESTS_H
+#define TESTS_TPM_TESTS_H
+
+#include "tpm-util.h"
+
+void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
+                         const char *ifmodel);
+
+void tpm_test_swtpm_migration_test(const char *src_tpm_path,
+                                   const char *dst_tpm_path,
+                                   const char *uri, tx_func *tx,
+                                   const char *ifmodel);
+
+#endif /* TESTS_TPM_TESTS_H */
diff --git a/tests/qtest/tpm-tis-swtpm-test.c b/tests/qtest/tpm-tis-swtpm-test.c
new file mode 100644 (file)
index 0000000..9f58a3a
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * QTest testcase for TPM TIS talking to external swtpm and swtpm migration
+ *
+ * Copyright (c) 2018 IBM Corporation
+ *  with parts borrowed from migration-test.c that is:
+ *     Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *   Stefan Berger <[email protected]>
+ *
+ * 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 "libqtest.h"
+#include "qemu/module.h"
+#include "tpm-tests.h"
+
+typedef struct TestState {
+    char *src_tpm_path;
+    char *dst_tpm_path;
+    char *uri;
+} TestState;
+
+static void tpm_tis_swtpm_test(const void *data)
+{
+    const TestState *ts = data;
+
+    tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, "tpm-tis");
+}
+
+static void tpm_tis_swtpm_migration_test(const void *data)
+{
+    const TestState *ts = data;
+
+    tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri,
+                                  tpm_util_tis_transfer, "tpm-tis");
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+    TestState ts = { 0 };
+
+    ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-tis-swtpm-test.XXXXXX", NULL);
+    ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-tis-swtpm-test.XXXXXX", NULL);
+    ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path);
+
+    module_call_init(MODULE_INIT_QOM);
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_data_func("/tpm/tis-swtpm/test", &ts, tpm_tis_swtpm_test);
+    qtest_add_data_func("/tpm/tis-swtpm-migration/test", &ts,
+                        tpm_tis_swtpm_migration_test);
+    ret = g_test_run();
+
+    g_rmdir(ts.dst_tpm_path);
+    g_free(ts.dst_tpm_path);
+    g_rmdir(ts.src_tpm_path);
+    g_free(ts.src_tpm_path);
+    g_free(ts.uri);
+
+    return ret;
+}
diff --git a/tests/qtest/tpm-tis-test.c b/tests/qtest/tpm-tis-test.c
new file mode 100644 (file)
index 0000000..dcf30e0
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * QTest testcase for TPM TIS
+ *
+ * Copyright (c) 2018 Red Hat, Inc.
+ * Copyright (c) 2018 IBM Corporation
+ *
+ * Authors:
+ *   Marc-André Lureau <[email protected]>
+ *   Stefan Berger <[email protected]>
+ *
+ * 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 "hw/acpi/tpm.h"
+#include "io/channel-socket.h"
+#include "libqtest-single.h"
+#include "qemu/module.h"
+#include "tpm-emu.h"
+
+#define TIS_REG(LOCTY, REG) \
+    (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG)
+
+#define DEBUG_TIS_TEST 0
+
+#define DPRINTF(fmt, ...) do { \
+    if (DEBUG_TIS_TEST) { \
+        printf(fmt, ## __VA_ARGS__); \
+    } \
+} while (0)
+
+#define DPRINTF_ACCESS \
+    DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \
+            __func__, __LINE__, locty, l, access, pending_request_flag)
+
+#define DPRINTF_STS \
+    DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts)
+
+static const uint8_t TPM_CMD[12] =
+    "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
+
+static void tpm_tis_test_check_localities(const void *data)
+{
+    uint8_t locty;
+    uint8_t access;
+    uint32_t ifaceid;
+    uint32_t capability;
+    uint32_t didvid;
+    uint32_t rid;
+
+    for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) {
+        access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
+        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+        capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY));
+        g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0);
+
+        ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID));
+        g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0);
+
+        didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID));
+        g_assert_cmpint(didvid, !=, 0);
+        g_assert_cmpint(didvid, !=, 0xffffffff);
+
+        rid = readl(TIS_REG(locty, TPM_TIS_REG_RID));
+        g_assert_cmpint(rid, !=, 0);
+        g_assert_cmpint(rid, !=, 0xffffffff);
+    }
+}
+
+static void tpm_tis_test_check_access_reg(const void *data)
+{
+    uint8_t locty;
+    uint8_t access;
+
+    /* do not test locality 4 (hw only) */
+    for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) {
+        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+        /* request use of locality */
+        writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+
+        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                    TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+        /* release access */
+        writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS),
+               TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+    }
+}
+
+/*
+ * Test case for seizing access by a higher number locality
+ */
+static void tpm_tis_test_check_access_reg_seize(const void *data)
+{
+    int locty, l;
+    uint8_t access;
+    uint8_t pending_request_flag;
+
+    /* do not test locality 4 (hw only) */
+    for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) {
+        pending_request_flag = 0;
+
+        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+        /* request use of locality */
+        writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                    TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+        /* lower localities cannot seize access */
+        for (l = 0; l < locty; l++) {
+            /* lower locality is not active */
+            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+            DPRINTF_ACCESS;
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        pending_request_flag |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+            /* try to request use from 'l' */
+            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+
+            /* requesting use from 'l' was not possible;
+               we must see REQUEST_USE and possibly PENDING_REQUEST */
+            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+            DPRINTF_ACCESS;
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        TPM_TIS_ACCESS_REQUEST_USE |
+                                        pending_request_flag |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+            /* locality 'locty' must be unchanged;
+               we must see PENDING_REQUEST */
+            access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+                                        TPM_TIS_ACCESS_PENDING_REQUEST |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+            /* try to seize from 'l' */
+            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE);
+            /* seize from 'l' was not possible */
+            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+            DPRINTF_ACCESS;
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        TPM_TIS_ACCESS_REQUEST_USE |
+                                        pending_request_flag |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+            /* locality 'locty' must be unchanged */
+            access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+                                        TPM_TIS_ACCESS_PENDING_REQUEST |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+            /* on the next loop we will have a PENDING_REQUEST flag
+               set for locality 'l' */
+            pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST;
+        }
+
+        /* higher localities can 'seize' access but not 'request use';
+           note: this will activate first l+1, then l+2 etc. */
+        for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
+            /* try to 'request use' from 'l' */
+            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+
+            /* requesting use from 'l' was not possible; we should see
+               REQUEST_USE and may see PENDING_REQUEST */
+            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+            DPRINTF_ACCESS;
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        TPM_TIS_ACCESS_REQUEST_USE |
+                                        pending_request_flag |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+            /* locality 'l-1' must be unchanged; we should always
+               see PENDING_REQUEST from 'l' requesting access */
+            access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
+            DPRINTF_ACCESS;
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+                                        TPM_TIS_ACCESS_PENDING_REQUEST |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+            /* try to seize from 'l' */
+            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE);
+
+            /* seize from 'l' was possible */
+            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+            DPRINTF_ACCESS;
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+                                        pending_request_flag |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+            /* l - 1 should show that it has BEEN_SEIZED */
+            access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
+            DPRINTF_ACCESS;
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        TPM_TIS_ACCESS_BEEN_SEIZED |
+                                        pending_request_flag |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+            /* clear the BEEN_SEIZED flag and make sure it's gone */
+            writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS),
+                   TPM_TIS_ACCESS_BEEN_SEIZED);
+
+            access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        pending_request_flag |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+        }
+
+        /* PENDING_REQUEST will not be set if locty = 0 since all localities
+           were active; in case of locty = 1, locality 0 will be active
+           but no PENDING_REQUEST anywhere */
+        if (locty <= 1) {
+            pending_request_flag = 0;
+        }
+
+        /* release access from l - 1; this activates locty - 1 */
+        l--;
+
+        access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+        DPRINTF_ACCESS;
+
+        DPRINTF("%s: %d: relinquishing control on l = %d\n",
+                __func__, __LINE__, l);
+        writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
+               TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+
+        access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+        DPRINTF_ACCESS;
+        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                    pending_request_flag |
+                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+        for (l = locty - 1; l >= 0; l--) {
+            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+            DPRINTF_ACCESS;
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+                                        pending_request_flag |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+            /* release this locality */
+            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
+                   TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+
+            if (l == 1) {
+                pending_request_flag = 0;
+            }
+        }
+
+        /* no locality may be active now */
+        for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
+            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+            DPRINTF_ACCESS;
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+        }
+    }
+}
+
+/*
+ * Test case for getting access when higher number locality relinquishes access
+ */
+static void tpm_tis_test_check_access_reg_release(const void *data)
+{
+    int locty, l;
+    uint8_t access;
+    uint8_t pending_request_flag;
+
+    /* do not test locality 4 (hw only) */
+    for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) {
+        pending_request_flag = 0;
+
+        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+        /* request use of locality */
+        writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                    TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+        /* request use of all other localities */
+        for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
+            if (l == locty) {
+                continue;
+            }
+            /* request use of locality 'l' -- we MUST see REQUEST USE and
+               may see PENDING_REQUEST */
+            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+            DPRINTF_ACCESS;
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        TPM_TIS_ACCESS_REQUEST_USE |
+                                        pending_request_flag |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+            pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST;
+        }
+        /* release locality 'locty' */
+        writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS),
+               TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+        /* highest locality should now be active; release it and make sure the
+           next higest locality is active afterwards */
+        for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) {
+            if (l == locty) {
+                continue;
+            }
+            /* 'l' should be active now */
+            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+            DPRINTF_ACCESS;
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+                                        pending_request_flag |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+            /* 'l' relinquishes access */
+            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
+                   TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+            DPRINTF_ACCESS;
+            if (l == 1 || (locty <= 1 && l == 2)) {
+                pending_request_flag = 0;
+            }
+            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                        pending_request_flag |
+                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+        }
+    }
+}
+
+/*
+ * Test case for transmitting packets
+ */
+static void tpm_tis_test_check_transmit(const void *data)
+{
+    const TestState *s = data;
+    uint8_t access;
+    uint32_t sts;
+    uint16_t bcount;
+    size_t i;
+
+    /* request use of locality 0 */
+    writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+    access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
+    g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+                                TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+                                TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+    sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
+    DPRINTF_STS;
+
+    g_assert_cmpint(sts & 0xff, ==, 0);
+    g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==,
+                    TPM_TIS_STS_TPM_FAMILY2_0);
+
+    bcount = (sts >> 8) & 0xffff;
+    g_assert_cmpint(bcount, >=, 128);
+
+    writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY);
+    sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
+    DPRINTF_STS;
+    g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY);
+
+    /* transmit command */
+    for (i = 0; i < sizeof(TPM_CMD); i++) {
+        writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]);
+        sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
+        DPRINTF_STS;
+        if (i < sizeof(TPM_CMD) - 1) {
+            g_assert_cmpint(sts & 0xff, ==,
+                            TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
+        } else {
+            g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID);
+        }
+        g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount);
+    }
+    /* start processing */
+    writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO);
+
+    uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND;
+    do {
+        sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
+        if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) {
+            break;
+        }
+    } while (g_get_monotonic_time() < end_time);
+
+    sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
+    DPRINTF_STS;
+    g_assert_cmpint(sts & 0xff, == ,
+                    TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
+    bcount = (sts >> 8) & 0xffff;
+
+    /* read response */
+    uint8_t tpm_msg[sizeof(struct tpm_hdr)];
+    g_assert_cmpint(sizeof(tpm_msg), ==, bcount);
+
+    for (i = 0; i < sizeof(tpm_msg); i++) {
+        tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO));
+        sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
+        DPRINTF_STS;
+        if (sts & TPM_TIS_STS_DATA_AVAILABLE) {
+            g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount);
+        }
+    }
+    g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg));
+
+    /* relinquish use of locality 0 */
+    writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+    access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+    char *args, *tmp_path = g_dir_make_tmp("qemu-tpm-tis-test.XXXXXX", NULL);
+    GThread *thread;
+    TestState test;
+
+    module_call_init(MODULE_INIT_QOM);
+    g_test_init(&argc, &argv, NULL);
+
+    test.addr = g_new0(SocketAddress, 1);
+    test.addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+    test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL);
+    g_mutex_init(&test.data_mutex);
+    g_cond_init(&test.data_cond);
+    test.data_cond_signal = false;
+
+    thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test);
+    tpm_emu_test_wait_cond(&test);
+
+    args = g_strdup_printf(
+        "-chardev socket,id=chr,path=%s "
+        "-tpmdev emulator,id=dev,chardev=chr "
+        "-device tpm-tis,tpmdev=dev",
+        test.addr->u.q_unix.path);
+    qtest_start(args);
+
+    qtest_add_data_func("/tpm-tis/test_check_localities", &test,
+                        tpm_tis_test_check_localities);
+
+    qtest_add_data_func("/tpm-tis/test_check_access_reg", &test,
+                        tpm_tis_test_check_access_reg);
+
+    qtest_add_data_func("/tpm-tis/test_check_access_reg_seize", &test,
+                        tpm_tis_test_check_access_reg_seize);
+
+    qtest_add_data_func("/tpm-tis/test_check_access_reg_release", &test,
+                        tpm_tis_test_check_access_reg_release);
+
+    qtest_add_data_func("/tpm-tis/test_check_transmit", &test,
+                        tpm_tis_test_check_transmit);
+
+    ret = g_test_run();
+
+    qtest_end();
+
+    g_thread_join(thread);
+    g_unlink(test.addr->u.q_unix.path);
+    qapi_free_SocketAddress(test.addr);
+    g_rmdir(tmp_path);
+    g_free(tmp_path);
+    g_free(args);
+    return ret;
+}
diff --git a/tests/qtest/tpm-util.c b/tests/qtest/tpm-util.c
new file mode 100644 (file)
index 0000000..e08b137
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * QTest TPM utilities
+ *
+ * Copyright (c) 2018 IBM Corporation
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * Authors:
+ *   Stefan Berger <[email protected]>
+ *   Marc-André Lureau <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/acpi/tpm.h"
+#include "libqtest.h"
+#include "tpm-util.h"
+#include "qapi/qmp/qdict.h"
+
+#define TIS_REG(LOCTY, REG) \
+    (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG)
+
+void tpm_util_crb_transfer(QTestState *s,
+                           const unsigned char *req, size_t req_size,
+                           unsigned char *rsp, size_t rsp_size)
+{
+    uint64_t caddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR);
+    uint64_t raddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR);
+
+    qtest_writeb(s, TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 1);
+
+    qtest_memwrite(s, caddr, req, req_size);
+
+    uint32_t sts, start = 1;
+    uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+    qtest_writel(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START, start);
+    while (true) {
+        start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
+        if ((start & 1) == 0) {
+            break;
+        }
+        if (g_get_monotonic_time() >= end_time) {
+            break;
+        }
+    };
+    start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
+    g_assert_cmpint(start & 1, ==, 0);
+    sts = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
+    g_assert_cmpint(sts & 1, ==, 0);
+
+    qtest_memread(s, raddr, rsp, rsp_size);
+}
+
+void tpm_util_tis_transfer(QTestState *s,
+                           const unsigned char *req, size_t req_size,
+                           unsigned char *rsp, size_t rsp_size)
+{
+    uint32_t sts;
+    uint16_t bcount;
+    size_t i;
+
+    /* request use of locality 0 */
+    qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+    qtest_writel(s, TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY);
+
+    sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
+    bcount = (sts >> 8) & 0xffff;
+    g_assert_cmpint(bcount, >=, req_size);
+
+    /* transmit command */
+    for (i = 0; i < req_size; i++) {
+        qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_DATA_FIFO), req[i]);
+    }
+
+    /* start processing */
+    qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO);
+
+    uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND;
+    do {
+        sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
+        if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) {
+            break;
+        }
+    } while (g_get_monotonic_time() < end_time);
+
+    sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
+    bcount = (sts >> 8) & 0xffff;
+
+    memset(rsp, 0, rsp_size);
+    for (i = 0; i < bcount; i++) {
+        rsp[i] = qtest_readb(s, TIS_REG(0, TPM_TIS_REG_DATA_FIFO));
+    }
+
+    /* relinquish use of locality 0 */
+    qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_ACCESS),
+                 TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+}
+
+void tpm_util_startup(QTestState *s, tx_func *tx)
+{
+    unsigned char buffer[1024];
+    unsigned char tpm_startup[] =
+        "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
+    unsigned char tpm_startup_resp[] =
+        "\x80\x01\x00\x00\x00\x0a\x00\x00\x00\x00";
+
+    tx(s, tpm_startup, sizeof(tpm_startup), buffer, sizeof(buffer));
+
+    g_assert_cmpmem(buffer, sizeof(tpm_startup_resp),
+                    tpm_startup_resp, sizeof(tpm_startup_resp));
+}
+
+void tpm_util_pcrextend(QTestState *s, tx_func *tx)
+{
+    unsigned char buffer[1024];
+    unsigned char tpm_pcrextend[] =
+        "\x80\x02\x00\x00\x00\x41\x00\x00\x01\x82\x00\x00\x00\x0a\x00\x00"
+        "\x00\x09\x40\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00"
+        "\x0b\x74\x65\x73\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+        "\x00";
+
+    unsigned char tpm_pcrextend_resp[] =
+        "\x80\x02\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+        "\x01\x00\x00";
+
+    tx(s, tpm_pcrextend, sizeof(tpm_pcrextend), buffer, sizeof(buffer));
+
+    g_assert_cmpmem(buffer, sizeof(tpm_pcrextend_resp),
+                    tpm_pcrextend_resp, sizeof(tpm_pcrextend_resp));
+}
+
+void tpm_util_pcrread(QTestState *s, tx_func *tx,
+                      const unsigned char *exp_resp, size_t exp_resp_size)
+{
+    unsigned char buffer[1024];
+    unsigned char tpm_pcrread[] =
+        "\x80\x01\x00\x00\x00\x14\x00\x00\x01\x7e\x00\x00\x00\x01\x00\x0b"
+        "\x03\x00\x04\x00";
+
+    tx(s, tpm_pcrread, sizeof(tpm_pcrread), buffer, sizeof(buffer));
+
+    g_assert_cmpmem(buffer, exp_resp_size, exp_resp, exp_resp_size);
+}
+
+bool tpm_util_swtpm_has_tpm2(void)
+{
+    bool has_tpm2 = false;
+    char *out = NULL;
+    static const char *argv[] = {
+        "swtpm", "socket", "--help", NULL
+    };
+
+    if (!g_spawn_sync(NULL /* working_dir */,
+                      (char **)argv,
+                      NULL /* envp */,
+                      G_SPAWN_SEARCH_PATH,
+                      NULL /* child_setup */,
+                      NULL /* user_data */,
+                      &out,
+                      NULL /* err */,
+                      NULL /* exit_status */,
+                      NULL)) {
+        return false;
+    }
+
+    if (strstr(out, "--tpm2")) {
+        has_tpm2 = true;
+    }
+
+    g_free(out);
+    return has_tpm2;
+}
+
+gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
+                              SocketAddress **addr, GError **error)
+{
+    char *swtpm_argv_tpmstate = g_strdup_printf("dir=%s", path);
+    char *swtpm_argv_ctrl = g_strdup_printf("type=unixio,path=%s/sock",
+                                            path);
+    gchar *swtpm_argv[] = {
+        g_strdup("swtpm"), g_strdup("socket"),
+        g_strdup("--tpmstate"), swtpm_argv_tpmstate,
+        g_strdup("--ctrl"), swtpm_argv_ctrl,
+        g_strdup("--tpm2"),
+        NULL
+    };
+    gboolean succ;
+    unsigned i;
+
+    *addr = g_new0(SocketAddress, 1);
+    (*addr)->type = SOCKET_ADDRESS_TYPE_UNIX;
+    (*addr)->u.q_unix.path = g_build_filename(path, "sock", NULL);
+
+    succ = g_spawn_async(NULL, swtpm_argv, NULL, G_SPAWN_SEARCH_PATH,
+                         NULL, NULL, pid, error);
+
+    for (i = 0; swtpm_argv[i]; i++) {
+        g_free(swtpm_argv[i]);
+    }
+
+    return succ;
+}
+
+void tpm_util_swtpm_kill(GPid pid)
+{
+    int n;
+
+    if (!pid) {
+        return;
+    }
+
+    g_spawn_close_pid(pid);
+
+    n = kill(pid, 0);
+    if (n < 0) {
+        return;
+    }
+
+    kill(pid, SIGKILL);
+}
+
+void tpm_util_migrate(QTestState *who, const char *uri)
+{
+    QDict *rsp;
+
+    rsp = qtest_qmp(who,
+                    "{ 'execute': 'migrate', 'arguments': { 'uri': %s } }",
+                    uri);
+    g_assert(qdict_haskey(rsp, "return"));
+    qobject_unref(rsp);
+}
+
+void tpm_util_wait_for_migration_complete(QTestState *who)
+{
+    while (true) {
+        QDict *rsp_return;
+        bool completed;
+        const char *status;
+
+        qtest_qmp_send(who, "{ 'execute': 'query-migrate' }");
+        rsp_return = qtest_qmp_receive_success(who, NULL, NULL);
+        status = qdict_get_str(rsp_return, "status");
+        completed = strcmp(status, "completed") == 0;
+        g_assert_cmpstr(status, !=,  "failed");
+        qobject_unref(rsp_return);
+        if (completed) {
+            return;
+        }
+        usleep(1000);
+    }
+}
+
+void tpm_util_migration_start_qemu(QTestState **src_qemu,
+                                   QTestState **dst_qemu,
+                                   SocketAddress *src_tpm_addr,
+                                   SocketAddress *dst_tpm_addr,
+                                   const char *miguri,
+                                   const char *ifmodel)
+{
+    char *src_qemu_args, *dst_qemu_args;
+
+    src_qemu_args = g_strdup_printf(
+        "-chardev socket,id=chr,path=%s "
+        "-tpmdev emulator,id=dev,chardev=chr "
+        "-device %s,tpmdev=dev ",
+        src_tpm_addr->u.q_unix.path, ifmodel);
+
+    *src_qemu = qtest_init(src_qemu_args);
+
+    dst_qemu_args = g_strdup_printf(
+        "-chardev socket,id=chr,path=%s "
+        "-tpmdev emulator,id=dev,chardev=chr "
+        "-device %s,tpmdev=dev "
+        "-incoming %s",
+        dst_tpm_addr->u.q_unix.path,
+        ifmodel, miguri);
+
+    *dst_qemu = qtest_init(dst_qemu_args);
+
+    free(src_qemu_args);
+    free(dst_qemu_args);
+}
diff --git a/tests/qtest/tpm-util.h b/tests/qtest/tpm-util.h
new file mode 100644 (file)
index 0000000..5755698
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * QTest TPM utilities
+ *
+ * Copyright (c) 2018 IBM Corporation
+ *
+ * Authors:
+ *   Stefan Berger <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TESTS_TPM_UTIL_H
+#define TESTS_TPM_UTIL_H
+
+#include "io/channel-socket.h"
+
+typedef void (tx_func)(QTestState *s,
+                       const unsigned char *req, size_t req_size,
+                       unsigned char *rsp, size_t rsp_size);
+
+void tpm_util_crb_transfer(QTestState *s,
+                           const unsigned char *req, size_t req_size,
+                           unsigned char *rsp, size_t rsp_size);
+void tpm_util_tis_transfer(QTestState *s,
+                           const unsigned char *req, size_t req_size,
+                           unsigned char *rsp, size_t rsp_size);
+
+void tpm_util_startup(QTestState *s, tx_func *tx);
+void tpm_util_pcrextend(QTestState *s, tx_func *tx);
+void tpm_util_pcrread(QTestState *s, tx_func *tx,
+                      const unsigned char *exp_resp, size_t exp_resp_size);
+
+bool tpm_util_swtpm_has_tpm2(void);
+
+gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
+                              SocketAddress **addr, GError **error);
+void tpm_util_swtpm_kill(GPid pid);
+
+void tpm_util_migrate(QTestState *who, const char *uri);
+
+void tpm_util_migration_start_qemu(QTestState **src_qemu,
+                                   QTestState **dst_qemu,
+                                   SocketAddress *src_tpm_addr,
+                                   SocketAddress *dst_tpm_addr,
+                                   const char *miguri,
+                                   const char *ifmodel);
+
+void tpm_util_wait_for_migration_complete(QTestState *who);
+
+#endif /* TESTS_TPM_UTIL_H */
diff --git a/tests/qtest/usb-hcd-ehci-test.c b/tests/qtest/usb-hcd-ehci-test.c
new file mode 100644 (file)
index 0000000..5251d53
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * QTest testcase for USB EHCI
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "libqos/pci-pc.h"
+#include "hw/usb/uhci-regs.h"
+#include "hw/usb/ehci-regs.h"
+#include "libqos/usb.h"
+
+static QPCIBus *pcibus;
+static struct qhc uhci1;
+static struct qhc uhci2;
+static struct qhc uhci3;
+static struct qhc ehci1;
+
+/* helpers */
+
+#if 0
+static void uhci_port_update(struct qhc *hc, int port,
+                             uint16_t set, uint16_t clear)
+{
+    void *addr = hc->base + 0x10 + 2 * port;
+    uint16_t value;
+
+    value = qpci_io_readw(hc->dev, addr);
+    value |= set;
+    value &= ~clear;
+    qpci_io_writew(hc->dev, addr, value);
+}
+#endif
+
+static void ehci_port_test(struct qhc *hc, int port, uint32_t expect)
+{
+    uint32_t value = qpci_io_readl(hc->dev, hc->bar, 0x64 + 4 * port);
+    uint16_t mask = ~(PORTSC_CSC | PORTSC_PEDC | PORTSC_OCC);
+
+#if 0
+    fprintf(stderr, "%s: %d, have 0x%08x, want 0x%08x\n",
+            __func__, port, value & mask, expect & mask);
+#endif
+    g_assert((value & mask) == (expect & mask));
+}
+
+/* tests */
+
+static void test_init(void)
+{
+    pcibus = qpci_new_pc(global_qtest, NULL);
+    g_assert(pcibus != NULL);
+
+    qusb_pci_init_one(pcibus, &uhci1, QPCI_DEVFN(0x1d, 0), 4);
+    qusb_pci_init_one(pcibus, &uhci2, QPCI_DEVFN(0x1d, 1), 4);
+    qusb_pci_init_one(pcibus, &uhci3, QPCI_DEVFN(0x1d, 2), 4);
+    qusb_pci_init_one(pcibus, &ehci1, QPCI_DEVFN(0x1d, 7), 0);
+}
+
+static void test_deinit(void)
+{
+    uhci_deinit(&uhci1);
+    uhci_deinit(&uhci2);
+    uhci_deinit(&uhci3);
+    uhci_deinit(&ehci1);
+    qpci_free_pc(pcibus);
+}
+
+static void pci_uhci_port_1(void)
+{
+    g_assert(pcibus != NULL);
+
+    uhci_port_test(&uhci1, 0, UHCI_PORT_CCS); /* usb-tablet  */
+    uhci_port_test(&uhci1, 1, UHCI_PORT_CCS); /* usb-storage */
+    uhci_port_test(&uhci2, 0, 0);
+    uhci_port_test(&uhci2, 1, 0);
+    uhci_port_test(&uhci3, 0, 0);
+    uhci_port_test(&uhci3, 1, 0);
+}
+
+static void pci_ehci_port_1(void)
+{
+    int i;
+
+    g_assert(pcibus != NULL);
+
+    for (i = 0; i < 6; i++) {
+        ehci_port_test(&ehci1, i, PORTSC_POWNER | PORTSC_PPOWER);
+    }
+}
+
+static void pci_ehci_config(void)
+{
+    /* hands over all ports from companion uhci to ehci */
+    qpci_io_writew(ehci1.dev, ehci1.bar, 0x60, 1);
+}
+
+static void pci_uhci_port_2(void)
+{
+    g_assert(pcibus != NULL);
+
+    uhci_port_test(&uhci1, 0, 0); /* usb-tablet,  @ehci */
+    uhci_port_test(&uhci1, 1, 0); /* usb-storage, @ehci */
+    uhci_port_test(&uhci2, 0, 0);
+    uhci_port_test(&uhci2, 1, 0);
+    uhci_port_test(&uhci3, 0, 0);
+    uhci_port_test(&uhci3, 1, 0);
+}
+
+static void pci_ehci_port_2(void)
+{
+    static uint32_t expect[] = {
+        PORTSC_PPOWER | PORTSC_CONNECT, /* usb-tablet  */
+        PORTSC_PPOWER | PORTSC_CONNECT, /* usb-storage */
+        PORTSC_PPOWER,
+        PORTSC_PPOWER,
+        PORTSC_PPOWER,
+        PORTSC_PPOWER,
+    };
+    int i;
+
+    g_assert(pcibus != NULL);
+
+    for (i = 0; i < 6; i++) {
+        ehci_port_test(&ehci1, i, expect[i]);
+    }
+}
+
+static void pci_ehci_port_3_hotplug(void)
+{
+    /* check for presence of hotplugged usb-tablet */
+    g_assert(pcibus != NULL);
+    ehci_port_test(&ehci1, 2, PORTSC_PPOWER | PORTSC_CONNECT);
+}
+
+static void pci_ehci_port_hotplug(void)
+{
+    usb_test_hotplug(global_qtest, "ich9-ehci-1", "3", pci_ehci_port_3_hotplug);
+}
+
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/ehci/pci/uhci-port-1", pci_uhci_port_1);
+    qtest_add_func("/ehci/pci/ehci-port-1", pci_ehci_port_1);
+    qtest_add_func("/ehci/pci/ehci-config", pci_ehci_config);
+    qtest_add_func("/ehci/pci/uhci-port-2", pci_uhci_port_2);
+    qtest_add_func("/ehci/pci/ehci-port-2", pci_ehci_port_2);
+    qtest_add_func("/ehci/pci/ehci-port-3-hotplug", pci_ehci_port_hotplug);
+
+    qtest_start("-machine q35 -device ich9-usb-ehci1,bus=pcie.0,addr=1d.7,"
+                "multifunction=on,id=ich9-ehci-1 "
+                "-device ich9-usb-uhci1,bus=pcie.0,addr=1d.0,"
+                "multifunction=on,masterbus=ich9-ehci-1.0,firstport=0 "
+                "-device ich9-usb-uhci2,bus=pcie.0,addr=1d.1,"
+                "multifunction=on,masterbus=ich9-ehci-1.0,firstport=2 "
+                "-device ich9-usb-uhci3,bus=pcie.0,addr=1d.2,"
+                "multifunction=on,masterbus=ich9-ehci-1.0,firstport=4 "
+                "-drive if=none,id=usbcdrom,media=cdrom "
+                "-device usb-tablet,bus=ich9-ehci-1.0,port=1,usb_version=1 "
+                "-device usb-storage,bus=ich9-ehci-1.0,port=2,drive=usbcdrom ");
+
+    test_init();
+    ret = g_test_run();
+    test_deinit();
+
+    qtest_end();
+
+    return ret;
+}
diff --git a/tests/qtest/usb-hcd-ohci-test.c b/tests/qtest/usb-hcd-ohci-test.c
new file mode 100644 (file)
index 0000000..19d760f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * QTest testcase for USB OHCI controller
+ *
+ * Copyright (c) 2014 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "qemu/module.h"
+#include "libqos/usb.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
+
+typedef struct QOHCI_PCI QOHCI_PCI;
+
+struct QOHCI_PCI {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void test_ohci_hotplug(void *obj, void *data, QGuestAllocator *alloc)
+{
+    usb_test_hotplug(global_qtest, "ohci", "1", NULL);
+}
+
+static void *ohci_pci_get_driver(void *obj, const char *interface)
+{
+    QOHCI_PCI *ohci_pci = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &ohci_pci->dev;
+    }
+
+    fprintf(stderr, "%s not present in pci-ohci\n", interface);
+    g_assert_not_reached();
+}
+
+static void *ohci_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QOHCI_PCI *ohci_pci = g_new0(QOHCI_PCI, 1);
+    ohci_pci->obj.get_driver = ohci_pci_get_driver;
+
+    return &ohci_pci->obj;
+}
+
+static void ohci_pci_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0,id=ohci",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+
+    qos_node_create_driver("pci-ohci", ohci_pci_create);
+    qos_node_consumes("pci-ohci", "pci-bus", &opts);
+    qos_node_produces("pci-ohci", "pci-device");
+}
+
+libqos_init(ohci_pci_register_nodes);
+
+static void register_ohci_pci_test(void)
+{
+    qos_add_test("ohci_pci-test-hotplug", "pci-ohci", test_ohci_hotplug, NULL);
+}
+
+libqos_init(register_ohci_pci_test);
diff --git a/tests/qtest/usb-hcd-uhci-test.c b/tests/qtest/usb-hcd-uhci-test.c
new file mode 100644 (file)
index 0000000..7a117b6
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * QTest testcase for USB UHCI controller
+ *
+ * Copyright (c) 2014 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "libqos/libqos.h"
+#include "libqos/usb.h"
+#include "libqos/libqos-pc.h"
+#include "libqos/libqos-spapr.h"
+#include "hw/usb/uhci-regs.h"
+
+static QOSState *qs;
+
+static void test_uhci_init(void)
+{
+}
+
+static void test_port(int port)
+{
+    struct qhc uhci;
+
+    g_assert(port > 0);
+    qusb_pci_init_one(qs->pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4);
+    uhci_port_test(&uhci, port - 1, UHCI_PORT_CCS);
+    uhci_deinit(&uhci);
+}
+
+static void test_port_1(void)
+{
+    test_port(1);
+}
+
+static void test_port_2(void)
+{
+    test_port(2);
+}
+
+static void test_uhci_hotplug(void)
+{
+    usb_test_hotplug(global_qtest, "uhci", "2", test_port_2);
+}
+
+static void test_usb_storage_hotplug(void)
+{
+    QTestState *qts = global_qtest;
+
+    qtest_qmp_device_add(qts, "usb-storage", "usbdev0", "{'drive': 'drive0'}");
+
+    qtest_qmp_device_del(qts, "usbdev0");
+}
+
+int main(int argc, char **argv)
+{
+    const char *arch = qtest_get_arch();
+    const char *cmd = "-device piix3-usb-uhci,id=uhci,addr=1d.0"
+                      " -drive id=drive0,if=none,file=null-co://,"
+                      "file.read-zeroes=on,format=raw"
+                      " -device usb-tablet,bus=uhci.0,port=1";
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/uhci/pci/init", test_uhci_init);
+    qtest_add_func("/uhci/pci/port1", test_port_1);
+    qtest_add_func("/uhci/pci/hotplug", test_uhci_hotplug);
+    qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug);
+
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        qs = qtest_pc_boot(cmd);
+    } else if (strcmp(arch, "ppc64") == 0) {
+        qs = qtest_spapr_boot(cmd);
+    } else {
+        g_printerr("usb-hcd-uhci-test tests are only "
+                   "available on x86 or ppc64\n");
+        exit(EXIT_FAILURE);
+    }
+    global_qtest = qs->qts;
+    ret = g_test_run();
+    qtest_shutdown(qs);
+
+    return ret;
+}
diff --git a/tests/qtest/usb-hcd-xhci-test.c b/tests/qtest/usb-hcd-xhci-test.c
new file mode 100644 (file)
index 0000000..10ef9d2
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * QTest testcase for USB xHCI controller
+ *
+ * Copyright (c) 2014 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "libqos/usb.h"
+
+
+static void test_xhci_init(void)
+{
+}
+
+static void test_xhci_hotplug(void)
+{
+    usb_test_hotplug(global_qtest, "xhci", "1", NULL);
+}
+
+static void test_usb_uas_hotplug(void)
+{
+    QTestState *qts = global_qtest;
+
+    qtest_qmp_device_add(qts, "usb-uas", "uas", "{}");
+    qtest_qmp_device_add(qts, "scsi-hd", "scsihd", "{'drive': 'drive0'}");
+
+    /* TODO:
+        UAS HBA driver in libqos, to check that
+        added disk is visible after BUS rescan
+    */
+
+    qtest_qmp_device_del(qts, "scsihd");
+    qtest_qmp_device_del(qts, "uas");
+}
+
+static void test_usb_ccid_hotplug(void)
+{
+    QTestState *qts = global_qtest;
+
+    qtest_qmp_device_add(qts, "usb-ccid", "ccid", "{}");
+    qtest_qmp_device_del(qts, "ccid");
+    /* check the device can be added again */
+    qtest_qmp_device_add(qts, "usb-ccid", "ccid", "{}");
+    qtest_qmp_device_del(qts, "ccid");
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/xhci/pci/init", test_xhci_init);
+    qtest_add_func("/xhci/pci/hotplug", test_xhci_hotplug);
+    qtest_add_func("/xhci/pci/hotplug/usb-uas", test_usb_uas_hotplug);
+    qtest_add_func("/xhci/pci/hotplug/usb-ccid", test_usb_ccid_hotplug);
+
+    qtest_start("-device nec-usb-xhci,id=xhci"
+                " -drive id=drive0,if=none,file=null-co://,"
+                "file.read-zeroes=on,format=raw");
+    ret = g_test_run();
+    qtest_end();
+
+    return ret;
+}
diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c
new file mode 100644 (file)
index 0000000..91ea373
--- /dev/null
@@ -0,0 +1,967 @@
+/*
+ * QTest testcase for the vhost-user
+ *
+ * Copyright (c) 2014 Virtual Open Systems Sarl.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqtest-single.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qdict.h"
+#include "qemu/config-file.h"
+#include "qemu/option.h"
+#include "qemu/range.h"
+#include "qemu/sockets.h"
+#include "chardev/char-fe.h"
+#include "qemu/memfd.h"
+#include "qemu/module.h"
+#include "sysemu/sysemu.h"
+#include "libqos/libqos.h"
+#include "libqos/pci-pc.h"
+#include "libqos/virtio-pci.h"
+
+#include "libqos/malloc-pc.h"
+#include "hw/virtio/virtio-net.h"
+
+#include "standard-headers/linux/vhost_types.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/virtio_net.h"
+
+#ifdef CONFIG_LINUX
+#include <sys/vfs.h>
+#endif
+
+
+#define QEMU_CMD_MEM    " -m %d -object memory-backend-file,id=mem,size=%dM," \
+                        "mem-path=%s,share=on -numa node,memdev=mem"
+#define QEMU_CMD_MEMFD  " -m %d -object memory-backend-memfd,id=mem,size=%dM," \
+                        " -numa node,memdev=mem"
+#define QEMU_CMD_CHR    " -chardev socket,id=%s,path=%s%s"
+#define QEMU_CMD_NETDEV " -netdev vhost-user,id=hs0,chardev=%s,vhostforce"
+
+#define HUGETLBFS_MAGIC       0x958458f6
+
+/*********** FROM hw/virtio/vhost-user.c *************************************/
+
+#define VHOST_MEMORY_MAX_NREGIONS    8
+#define VHOST_MAX_VIRTQUEUES    0x100
+
+#define VHOST_USER_F_PROTOCOL_FEATURES 30
+#define VHOST_USER_PROTOCOL_F_MQ 0
+#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
+#define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN   6
+
+#define VHOST_LOG_PAGE 0x1000
+
+typedef enum VhostUserRequest {
+    VHOST_USER_NONE = 0,
+    VHOST_USER_GET_FEATURES = 1,
+    VHOST_USER_SET_FEATURES = 2,
+    VHOST_USER_SET_OWNER = 3,
+    VHOST_USER_RESET_OWNER = 4,
+    VHOST_USER_SET_MEM_TABLE = 5,
+    VHOST_USER_SET_LOG_BASE = 6,
+    VHOST_USER_SET_LOG_FD = 7,
+    VHOST_USER_SET_VRING_NUM = 8,
+    VHOST_USER_SET_VRING_ADDR = 9,
+    VHOST_USER_SET_VRING_BASE = 10,
+    VHOST_USER_GET_VRING_BASE = 11,
+    VHOST_USER_SET_VRING_KICK = 12,
+    VHOST_USER_SET_VRING_CALL = 13,
+    VHOST_USER_SET_VRING_ERR = 14,
+    VHOST_USER_GET_PROTOCOL_FEATURES = 15,
+    VHOST_USER_SET_PROTOCOL_FEATURES = 16,
+    VHOST_USER_GET_QUEUE_NUM = 17,
+    VHOST_USER_SET_VRING_ENABLE = 18,
+    VHOST_USER_MAX
+} VhostUserRequest;
+
+typedef struct VhostUserMemoryRegion {
+    uint64_t guest_phys_addr;
+    uint64_t memory_size;
+    uint64_t userspace_addr;
+    uint64_t mmap_offset;
+} VhostUserMemoryRegion;
+
+typedef struct VhostUserMemory {
+    uint32_t nregions;
+    uint32_t padding;
+    VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
+} VhostUserMemory;
+
+typedef struct VhostUserLog {
+    uint64_t mmap_size;
+    uint64_t mmap_offset;
+} VhostUserLog;
+
+typedef struct VhostUserMsg {
+    VhostUserRequest request;
+
+#define VHOST_USER_VERSION_MASK     (0x3)
+#define VHOST_USER_REPLY_MASK       (0x1<<2)
+    uint32_t flags;
+    uint32_t size; /* the following payload size */
+    union {
+#define VHOST_USER_VRING_IDX_MASK   (0xff)
+#define VHOST_USER_VRING_NOFD_MASK  (0x1<<8)
+        uint64_t u64;
+        struct vhost_vring_state state;
+        struct vhost_vring_addr addr;
+        VhostUserMemory memory;
+        VhostUserLog log;
+    } payload;
+} QEMU_PACKED VhostUserMsg;
+
+static VhostUserMsg m __attribute__ ((unused));
+#define VHOST_USER_HDR_SIZE (sizeof(m.request) \
+                            + sizeof(m.flags) \
+                            + sizeof(m.size))
+
+#define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
+
+/* The version of the protocol we support */
+#define VHOST_USER_VERSION    (0x1)
+/*****************************************************************************/
+
+enum {
+    TEST_FLAGS_OK,
+    TEST_FLAGS_DISCONNECT,
+    TEST_FLAGS_BAD,
+    TEST_FLAGS_END,
+};
+
+typedef struct TestServer {
+    gchar *socket_path;
+    gchar *mig_path;
+    gchar *chr_name;
+    gchar *tmpfs;
+    CharBackend chr;
+    int fds_num;
+    int fds[VHOST_MEMORY_MAX_NREGIONS];
+    VhostUserMemory memory;
+    GMainContext *context;
+    GMainLoop *loop;
+    GThread *thread;
+    GMutex data_mutex;
+    GCond data_cond;
+    int log_fd;
+    uint64_t rings;
+    bool test_fail;
+    int test_flags;
+    int queues;
+} TestServer;
+
+static const char *init_hugepagefs(void);
+static TestServer *test_server_new(const gchar *name);
+static void test_server_free(TestServer *server);
+static void test_server_listen(TestServer *server);
+
+enum test_memfd {
+    TEST_MEMFD_AUTO,
+    TEST_MEMFD_YES,
+    TEST_MEMFD_NO,
+};
+
+static void append_vhost_opts(TestServer *s, GString *cmd_line,
+                             const char *chr_opts)
+{
+    g_string_append_printf(cmd_line, QEMU_CMD_CHR QEMU_CMD_NETDEV,
+                           s->chr_name, s->socket_path,
+                           chr_opts, s->chr_name);
+}
+
+static void append_mem_opts(TestServer *server, GString *cmd_line,
+                            int size, enum test_memfd memfd)
+{
+    if (memfd == TEST_MEMFD_AUTO) {
+        memfd = qemu_memfd_check(MFD_ALLOW_SEALING) ? TEST_MEMFD_YES
+                                                    : TEST_MEMFD_NO;
+    }
+
+    if (memfd == TEST_MEMFD_YES) {
+        g_string_append_printf(cmd_line, QEMU_CMD_MEMFD, size, size);
+    } else {
+        const char *root = init_hugepagefs() ? : server->tmpfs;
+
+        g_string_append_printf(cmd_line, QEMU_CMD_MEM, size, size, root);
+    }
+}
+
+static bool wait_for_fds(TestServer *s)
+{
+    gint64 end_time;
+    bool got_region;
+    int i;
+
+    g_mutex_lock(&s->data_mutex);
+
+    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+    while (!s->fds_num) {
+        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
+            /* timeout has passed */
+            g_assert(s->fds_num);
+            break;
+        }
+    }
+
+    /* check for sanity */
+    g_assert_cmpint(s->fds_num, >, 0);
+    g_assert_cmpint(s->fds_num, ==, s->memory.nregions);
+
+    g_mutex_unlock(&s->data_mutex);
+
+    got_region = false;
+    for (i = 0; i < s->memory.nregions; ++i) {
+        VhostUserMemoryRegion *reg = &s->memory.regions[i];
+        if (reg->guest_phys_addr == 0) {
+            got_region = true;
+            break;
+        }
+    }
+    if (!got_region) {
+        g_test_skip("No memory at address 0x0");
+    }
+    return got_region;
+}
+
+static void read_guest_mem_server(QTestState *qts, TestServer *s)
+{
+    uint8_t *guest_mem;
+    int i, j;
+    size_t size;
+
+    g_mutex_lock(&s->data_mutex);
+
+    /* iterate all regions */
+    for (i = 0; i < s->fds_num; i++) {
+
+        /* We'll check only the region statring at 0x0*/
+        if (s->memory.regions[i].guest_phys_addr != 0x0) {
+            continue;
+        }
+
+        g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024);
+
+        size = s->memory.regions[i].memory_size +
+            s->memory.regions[i].mmap_offset;
+
+        guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
+                         MAP_SHARED, s->fds[i], 0);
+
+        g_assert(guest_mem != MAP_FAILED);
+        guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
+
+        for (j = 0; j < 1024; j++) {
+            uint32_t a = qtest_readb(qts, s->memory.regions[i].guest_phys_addr + j);
+            uint32_t b = guest_mem[j];
+
+            g_assert_cmpint(a, ==, b);
+        }
+
+        munmap(guest_mem, s->memory.regions[i].memory_size);
+    }
+
+    g_mutex_unlock(&s->data_mutex);
+}
+
+static void *thread_function(void *data)
+{
+    GMainLoop *loop = data;
+    g_main_loop_run(loop);
+    return NULL;
+}
+
+static int chr_can_read(void *opaque)
+{
+    return VHOST_USER_HDR_SIZE;
+}
+
+static void chr_read(void *opaque, const uint8_t *buf, int size)
+{
+    TestServer *s = opaque;
+    CharBackend *chr = &s->chr;
+    VhostUserMsg msg;
+    uint8_t *p = (uint8_t *) &msg;
+    int fd = -1;
+
+    if (s->test_fail) {
+        qemu_chr_fe_disconnect(chr);
+        /* now switch to non-failure */
+        s->test_fail = false;
+    }
+
+    if (size != VHOST_USER_HDR_SIZE) {
+        g_test_message("Wrong message size received %d", size);
+        return;
+    }
+
+    g_mutex_lock(&s->data_mutex);
+    memcpy(p, buf, VHOST_USER_HDR_SIZE);
+
+    if (msg.size) {
+        p += VHOST_USER_HDR_SIZE;
+        size = qemu_chr_fe_read_all(chr, p, msg.size);
+        if (size != msg.size) {
+            g_test_message("Wrong message size received %d != %d",
+                           size, msg.size);
+            return;
+        }
+    }
+
+    switch (msg.request) {
+    case VHOST_USER_GET_FEATURES:
+        /* send back features to qemu */
+        msg.flags |= VHOST_USER_REPLY_MASK;
+        msg.size = sizeof(m.payload.u64);
+        msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL |
+            0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
+        if (s->queues > 1) {
+            msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ;
+        }
+        if (s->test_flags >= TEST_FLAGS_BAD) {
+            msg.payload.u64 = 0;
+            s->test_flags = TEST_FLAGS_END;
+        }
+        p = (uint8_t *) &msg;
+        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
+        break;
+
+    case VHOST_USER_SET_FEATURES:
+        g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
+                        !=, 0ULL);
+        if (s->test_flags == TEST_FLAGS_DISCONNECT) {
+            qemu_chr_fe_disconnect(chr);
+            s->test_flags = TEST_FLAGS_BAD;
+        }
+        break;
+
+    case VHOST_USER_GET_PROTOCOL_FEATURES:
+        /* send back features to qemu */
+        msg.flags |= VHOST_USER_REPLY_MASK;
+        msg.size = sizeof(m.payload.u64);
+        msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD;
+        msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_CROSS_ENDIAN;
+        if (s->queues > 1) {
+            msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
+        }
+        p = (uint8_t *) &msg;
+        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
+        break;
+
+    case VHOST_USER_GET_VRING_BASE:
+        /* send back vring base to qemu */
+        msg.flags |= VHOST_USER_REPLY_MASK;
+        msg.size = sizeof(m.payload.state);
+        msg.payload.state.num = 0;
+        p = (uint8_t *) &msg;
+        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
+
+        assert(msg.payload.state.index < s->queues * 2);
+        s->rings &= ~(0x1ULL << msg.payload.state.index);
+        g_cond_broadcast(&s->data_cond);
+        break;
+
+    case VHOST_USER_SET_MEM_TABLE:
+        /* received the mem table */
+        memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory));
+        s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds,
+                                            G_N_ELEMENTS(s->fds));
+
+        /* signal the test that it can continue */
+        g_cond_broadcast(&s->data_cond);
+        break;
+
+    case VHOST_USER_SET_VRING_KICK:
+    case VHOST_USER_SET_VRING_CALL:
+        /* consume the fd */
+        qemu_chr_fe_get_msgfds(chr, &fd, 1);
+        /*
+         * This is a non-blocking eventfd.
+         * The receive function forces it to be blocking,
+         * so revert it back to non-blocking.
+         */
+        qemu_set_nonblock(fd);
+        break;
+
+    case VHOST_USER_SET_LOG_BASE:
+        if (s->log_fd != -1) {
+            close(s->log_fd);
+            s->log_fd = -1;
+        }
+        qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1);
+        msg.flags |= VHOST_USER_REPLY_MASK;
+        msg.size = 0;
+        p = (uint8_t *) &msg;
+        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE);
+
+        g_cond_broadcast(&s->data_cond);
+        break;
+
+    case VHOST_USER_SET_VRING_BASE:
+        assert(msg.payload.state.index < s->queues * 2);
+        s->rings |= 0x1ULL << msg.payload.state.index;
+        g_cond_broadcast(&s->data_cond);
+        break;
+
+    case VHOST_USER_GET_QUEUE_NUM:
+        msg.flags |= VHOST_USER_REPLY_MASK;
+        msg.size = sizeof(m.payload.u64);
+        msg.payload.u64 = s->queues;
+        p = (uint8_t *) &msg;
+        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
+        break;
+
+    default:
+        break;
+    }
+
+    g_mutex_unlock(&s->data_mutex);
+}
+
+static const char *init_hugepagefs(void)
+{
+#ifdef CONFIG_LINUX
+    static const char *hugepagefs;
+    const char *path = getenv("QTEST_HUGETLBFS_PATH");
+    struct statfs fs;
+    int ret;
+
+    if (hugepagefs) {
+        return hugepagefs;
+    }
+    if (!path) {
+        return NULL;
+    }
+
+    if (access(path, R_OK | W_OK | X_OK)) {
+        g_test_message("access on path (%s): %s", path, strerror(errno));
+        g_test_fail();
+        return NULL;
+    }
+
+    do {
+        ret = statfs(path, &fs);
+    } while (ret != 0 && errno == EINTR);
+
+    if (ret != 0) {
+        g_test_message("statfs on path (%s): %s", path, strerror(errno));
+        g_test_fail();
+        return NULL;
+    }
+
+    if (fs.f_type != HUGETLBFS_MAGIC) {
+        g_test_message("Warning: path not on HugeTLBFS: %s", path);
+        g_test_fail();
+        return NULL;
+    }
+
+    hugepagefs = path;
+    return hugepagefs;
+#else
+    return NULL;
+#endif
+}
+
+static TestServer *test_server_new(const gchar *name)
+{
+    TestServer *server = g_new0(TestServer, 1);
+    char template[] = "/tmp/vhost-test-XXXXXX";
+    const char *tmpfs;
+
+    server->context = g_main_context_new();
+    server->loop = g_main_loop_new(server->context, FALSE);
+
+    /* run the main loop thread so the chardev may operate */
+    server->thread = g_thread_new(NULL, thread_function, server->loop);
+
+    tmpfs = mkdtemp(template);
+    if (!tmpfs) {
+        g_test_message("mkdtemp on path (%s): %s", template, strerror(errno));
+    }
+    g_assert(tmpfs);
+
+    server->tmpfs = g_strdup(tmpfs);
+    server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name);
+    server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name);
+    server->chr_name = g_strdup_printf("chr-%s", name);
+
+    g_mutex_init(&server->data_mutex);
+    g_cond_init(&server->data_cond);
+
+    server->log_fd = -1;
+    server->queues = 1;
+
+    return server;
+}
+
+static void chr_event(void *opaque, int event)
+{
+    TestServer *s = opaque;
+
+    if (s->test_flags == TEST_FLAGS_END &&
+        event == CHR_EVENT_CLOSED) {
+        s->test_flags = TEST_FLAGS_OK;
+    }
+}
+
+static void test_server_create_chr(TestServer *server, const gchar *opt)
+{
+    gchar *chr_path;
+    Chardev *chr;
+
+    chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
+    chr = qemu_chr_new(server->chr_name, chr_path, server->context);
+    g_free(chr_path);
+
+    g_assert_nonnull(chr);
+    qemu_chr_fe_init(&server->chr, chr, &error_abort);
+    qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read,
+                             chr_event, NULL, server, server->context, true);
+}
+
+static void test_server_listen(TestServer *server)
+{
+    test_server_create_chr(server, ",server,nowait");
+}
+
+static void test_server_free(TestServer *server)
+{
+    int i, ret;
+
+    /* finish the helper thread and dispatch pending sources */
+    g_main_loop_quit(server->loop);
+    g_thread_join(server->thread);
+    while (g_main_context_pending(NULL)) {
+        g_main_context_iteration(NULL, TRUE);
+    }
+
+    unlink(server->socket_path);
+    g_free(server->socket_path);
+
+    unlink(server->mig_path);
+    g_free(server->mig_path);
+
+    ret = rmdir(server->tmpfs);
+    if (ret != 0) {
+        g_test_message("unable to rmdir: path (%s): %s",
+                       server->tmpfs, strerror(errno));
+    }
+    g_free(server->tmpfs);
+
+    qemu_chr_fe_deinit(&server->chr, true);
+
+    for (i = 0; i < server->fds_num; i++) {
+        close(server->fds[i]);
+    }
+
+    if (server->log_fd != -1) {
+        close(server->log_fd);
+    }
+
+    g_free(server->chr_name);
+
+    g_main_loop_unref(server->loop);
+    g_main_context_unref(server->context);
+    g_cond_clear(&server->data_cond);
+    g_mutex_clear(&server->data_mutex);
+    g_free(server);
+}
+
+static void wait_for_log_fd(TestServer *s)
+{
+    gint64 end_time;
+
+    g_mutex_lock(&s->data_mutex);
+    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+    while (s->log_fd == -1) {
+        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
+            /* timeout has passed */
+            g_assert(s->log_fd != -1);
+            break;
+        }
+    }
+
+    g_mutex_unlock(&s->data_mutex);
+}
+
+static void write_guest_mem(TestServer *s, uint32_t seed)
+{
+    uint32_t *guest_mem;
+    int i, j;
+    size_t size;
+
+    /* iterate all regions */
+    for (i = 0; i < s->fds_num; i++) {
+
+        /* We'll write only the region statring at 0x0 */
+        if (s->memory.regions[i].guest_phys_addr != 0x0) {
+            continue;
+        }
+
+        g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024);
+
+        size = s->memory.regions[i].memory_size +
+            s->memory.regions[i].mmap_offset;
+
+        guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
+                         MAP_SHARED, s->fds[i], 0);
+
+        g_assert(guest_mem != MAP_FAILED);
+        guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
+
+        for (j = 0; j < 256; j++) {
+            guest_mem[j] = seed + j;
+        }
+
+        munmap(guest_mem, s->memory.regions[i].memory_size);
+        break;
+    }
+}
+
+static guint64 get_log_size(TestServer *s)
+{
+    guint64 log_size = 0;
+    int i;
+
+    for (i = 0; i < s->memory.nregions; ++i) {
+        VhostUserMemoryRegion *reg = &s->memory.regions[i];
+        guint64 last = range_get_last(reg->guest_phys_addr,
+                                       reg->memory_size);
+        log_size = MAX(log_size, last / (8 * VHOST_LOG_PAGE) + 1);
+    }
+
+    return log_size;
+}
+
+typedef struct TestMigrateSource {
+    GSource source;
+    TestServer *src;
+    TestServer *dest;
+} TestMigrateSource;
+
+static gboolean
+test_migrate_source_check(GSource *source)
+{
+    TestMigrateSource *t = (TestMigrateSource *)source;
+    gboolean overlap = t->src->rings && t->dest->rings;
+
+    g_assert(!overlap);
+
+    return FALSE;
+}
+
+GSourceFuncs test_migrate_source_funcs = {
+    .check = test_migrate_source_check,
+};
+
+static void vhost_user_test_cleanup(void *s)
+{
+    TestServer *server = s;
+
+    qos_invalidate_command_line();
+    test_server_free(server);
+}
+
+static void *vhost_user_test_setup(GString *cmd_line, void *arg)
+{
+    TestServer *server = test_server_new("vhost-user-test");
+    test_server_listen(server);
+
+    append_mem_opts(server, cmd_line, 256, TEST_MEMFD_AUTO);
+    append_vhost_opts(server, cmd_line, "");
+
+    g_test_queue_destroy(vhost_user_test_cleanup, server);
+
+    return server;
+}
+
+static void *vhost_user_test_setup_memfd(GString *cmd_line, void *arg)
+{
+    TestServer *server = test_server_new("vhost-user-test");
+    test_server_listen(server);
+
+    append_mem_opts(server, cmd_line, 256, TEST_MEMFD_YES);
+    append_vhost_opts(server, cmd_line, "");
+
+    g_test_queue_destroy(vhost_user_test_cleanup, server);
+
+    return server;
+}
+
+static void test_read_guest_mem(void *obj, void *arg, QGuestAllocator *alloc)
+{
+    TestServer *server = arg;
+
+    if (!wait_for_fds(server)) {
+        return;
+    }
+
+    read_guest_mem_server(global_qtest, server);
+}
+
+static void test_migrate(void *obj, void *arg, QGuestAllocator *alloc)
+{
+    TestServer *s = arg;
+    TestServer *dest = test_server_new("dest");
+    GString *dest_cmdline = g_string_new(qos_get_current_command_line());
+    char *uri = g_strdup_printf("%s%s", "unix:", dest->mig_path);
+    QTestState *to;
+    GSource *source;
+    QDict *rsp;
+    guint8 *log;
+    guint64 size;
+
+    if (!wait_for_fds(s)) {
+        return;
+    }
+
+    size = get_log_size(s);
+    g_assert_cmpint(size, ==, (256 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));
+
+    test_server_listen(dest);
+    g_string_append_printf(dest_cmdline, " -incoming %s", uri);
+    append_mem_opts(dest, dest_cmdline, 256, TEST_MEMFD_AUTO);
+    append_vhost_opts(dest, dest_cmdline, "");
+    to = qtest_init(dest_cmdline->str);
+
+    /* This would be where you call qos_allocate_objects(to, NULL), if you want
+     * to talk to the QVirtioNet object on the destination.
+     */
+
+    source = g_source_new(&test_migrate_source_funcs,
+                          sizeof(TestMigrateSource));
+    ((TestMigrateSource *)source)->src = s;
+    ((TestMigrateSource *)source)->dest = dest;
+    g_source_attach(source, s->context);
+
+    /* slow down migration to have time to fiddle with log */
+    /* TODO: qtest could learn to break on some places */
+    rsp = qmp("{ 'execute': 'migrate_set_speed',"
+              "'arguments': { 'value': 10 } }");
+    g_assert(qdict_haskey(rsp, "return"));
+    qobject_unref(rsp);
+
+    rsp = qmp("{ 'execute': 'migrate', 'arguments': { 'uri': %s } }", uri);
+    g_assert(qdict_haskey(rsp, "return"));
+    qobject_unref(rsp);
+
+    wait_for_log_fd(s);
+
+    log = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, s->log_fd, 0);
+    g_assert(log != MAP_FAILED);
+
+    /* modify first page */
+    write_guest_mem(s, 0x42);
+    log[0] = 1;
+    munmap(log, size);
+
+    /* speed things up */
+    rsp = qmp("{ 'execute': 'migrate_set_speed',"
+              "'arguments': { 'value': 0 } }");
+    g_assert(qdict_haskey(rsp, "return"));
+    qobject_unref(rsp);
+
+    qmp_eventwait("STOP");
+    qtest_qmp_eventwait(to, "RESUME");
+
+    g_assert(wait_for_fds(dest));
+    read_guest_mem_server(to, dest);
+
+    g_source_destroy(source);
+    g_source_unref(source);
+
+    qtest_quit(to);
+    test_server_free(dest);
+    g_free(uri);
+}
+
+static void wait_for_rings_started(TestServer *s, size_t count)
+{
+    gint64 end_time;
+
+    g_mutex_lock(&s->data_mutex);
+    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+    while (ctpop64(s->rings) != count) {
+        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
+            /* timeout has passed */
+            g_assert_cmpint(ctpop64(s->rings), ==, count);
+            break;
+        }
+    }
+
+    g_mutex_unlock(&s->data_mutex);
+}
+
+static inline void test_server_connect(TestServer *server)
+{
+    test_server_create_chr(server, ",reconnect=1");
+}
+
+static gboolean
+reconnect_cb(gpointer user_data)
+{
+    TestServer *s = user_data;
+
+    qemu_chr_fe_disconnect(&s->chr);
+
+    return FALSE;
+}
+
+static gpointer
+connect_thread(gpointer data)
+{
+    TestServer *s = data;
+
+    /* wait for qemu to start before first try, to avoid extra warnings */
+    g_usleep(G_USEC_PER_SEC);
+    test_server_connect(s);
+
+    return NULL;
+}
+
+static void *vhost_user_test_setup_reconnect(GString *cmd_line, void *arg)
+{
+    TestServer *s = test_server_new("reconnect");
+
+    g_thread_new("connect", connect_thread, s);
+    append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO);
+    append_vhost_opts(s, cmd_line, ",server");
+
+    g_test_queue_destroy(vhost_user_test_cleanup, s);
+
+    return s;
+}
+
+static void test_reconnect(void *obj, void *arg, QGuestAllocator *alloc)
+{
+    TestServer *s = arg;
+    GSource *src;
+
+    if (!wait_for_fds(s)) {
+        return;
+    }
+
+    wait_for_rings_started(s, 2);
+
+    /* reconnect */
+    s->fds_num = 0;
+    s->rings = 0;
+    src = g_idle_source_new();
+    g_source_set_callback(src, reconnect_cb, s, NULL);
+    g_source_attach(src, s->context);
+    g_source_unref(src);
+    g_assert(wait_for_fds(s));
+    wait_for_rings_started(s, 2);
+}
+
+static void *vhost_user_test_setup_connect_fail(GString *cmd_line, void *arg)
+{
+    TestServer *s = test_server_new("connect-fail");
+
+    s->test_fail = true;
+
+    g_thread_new("connect", connect_thread, s);
+    append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO);
+    append_vhost_opts(s, cmd_line, ",server");
+
+    g_test_queue_destroy(vhost_user_test_cleanup, s);
+
+    return s;
+}
+
+static void *vhost_user_test_setup_flags_mismatch(GString *cmd_line, void *arg)
+{
+    TestServer *s = test_server_new("flags-mismatch");
+
+    s->test_flags = TEST_FLAGS_DISCONNECT;
+
+    g_thread_new("connect", connect_thread, s);
+    append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO);
+    append_vhost_opts(s, cmd_line, ",server");
+
+    g_test_queue_destroy(vhost_user_test_cleanup, s);
+
+    return s;
+}
+
+static void test_vhost_user_started(void *obj, void *arg, QGuestAllocator *alloc)
+{
+    TestServer *s = arg;
+
+    if (!wait_for_fds(s)) {
+        return;
+    }
+    wait_for_rings_started(s, 2);
+}
+
+static void *vhost_user_test_setup_multiqueue(GString *cmd_line, void *arg)
+{
+    TestServer *s = vhost_user_test_setup(cmd_line, arg);
+
+    s->queues = 2;
+    g_string_append_printf(cmd_line,
+                           " -set netdev.hs0.queues=%d"
+                           " -global virtio-net-pci.vectors=%d",
+                           s->queues, s->queues * 2 + 2);
+
+    return s;
+}
+
+static void test_multiqueue(void *obj, void *arg, QGuestAllocator *alloc)
+{
+    TestServer *s = arg;
+
+    wait_for_rings_started(s, s->queues * 2);
+}
+
+static void register_vhost_user_test(void)
+{
+    QOSGraphTestOptions opts = {
+        .before = vhost_user_test_setup,
+        .subprocess = true,
+    };
+
+    qemu_add_opts(&qemu_chardev_opts);
+
+    qos_add_test("vhost-user/read-guest-mem/memfile",
+                 "virtio-net",
+                 test_read_guest_mem, &opts);
+
+    if (qemu_memfd_check(MFD_ALLOW_SEALING)) {
+        opts.before = vhost_user_test_setup_memfd;
+        qos_add_test("vhost-user/read-guest-mem/memfd",
+                     "virtio-net",
+                     test_read_guest_mem, &opts);
+    }
+
+    qos_add_test("vhost-user/migrate",
+                 "virtio-net",
+                 test_migrate, &opts);
+
+    /* keeps failing on build-system since Aug 15 2017 */
+    if (getenv("QTEST_VHOST_USER_FIXME")) {
+        opts.before = vhost_user_test_setup_reconnect;
+        qos_add_test("vhost-user/reconnect", "virtio-net",
+                     test_reconnect, &opts);
+
+        opts.before = vhost_user_test_setup_connect_fail;
+        qos_add_test("vhost-user/connect-fail", "virtio-net",
+                     test_vhost_user_started, &opts);
+
+        opts.before = vhost_user_test_setup_flags_mismatch;
+        qos_add_test("vhost-user/flags-mismatch", "virtio-net",
+                     test_vhost_user_started, &opts);
+    }
+
+    opts.before = vhost_user_test_setup_multiqueue;
+    opts.edge.extra_device_opts = "mq=on";
+    qos_add_test("vhost-user/multiqueue",
+                 "virtio-net",
+                 test_multiqueue, &opts);
+}
+libqos_init(register_vhost_user_test);
diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
new file mode 100644 (file)
index 0000000..e7b58e3
--- /dev/null
@@ -0,0 +1,662 @@
+/*
+ * QTest testcase for VirtIO 9P
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "qemu/module.h"
+#include "hw/9pfs/9p.h"
+#include "hw/9pfs/9p-synth.h"
+#include "libqos/virtio-9p.h"
+#include "libqos/qgraph.h"
+
+#define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000)
+static QGuestAllocator *alloc;
+
+static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
+    size_t tag_len = qvirtio_config_readw(v9p->vdev, 0);
+    char *tag;
+    int i;
+
+    g_assert_cmpint(tag_len, ==, strlen(MOUNT_TAG));
+
+    tag = g_malloc(tag_len);
+    for (i = 0; i < tag_len; i++) {
+        tag[i] = qvirtio_config_readb(v9p->vdev, i + 2);
+    }
+    g_assert_cmpmem(tag, tag_len, MOUNT_TAG, tag_len);
+    g_free(tag);
+}
+
+#define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */
+
+typedef struct {
+    QTestState *qts;
+    QVirtio9P *v9p;
+    uint16_t tag;
+    uint64_t t_msg;
+    uint32_t t_size;
+    uint64_t r_msg;
+    /* No r_size, it is hardcoded to P9_MAX_SIZE */
+    size_t t_off;
+    size_t r_off;
+    uint32_t free_head;
+} P9Req;
+
+static void v9fs_memwrite(P9Req *req, const void *addr, size_t len)
+{
+    qtest_memwrite(req->qts, req->t_msg + req->t_off, addr, len);
+    req->t_off += len;
+}
+
+static void v9fs_memskip(P9Req *req, size_t len)
+{
+    req->r_off += len;
+}
+
+static void v9fs_memread(P9Req *req, void *addr, size_t len)
+{
+    qtest_memread(req->qts, req->r_msg + req->r_off, addr, len);
+    req->r_off += len;
+}
+
+static void v9fs_uint16_write(P9Req *req, uint16_t val)
+{
+    uint16_t le_val = cpu_to_le16(val);
+
+    v9fs_memwrite(req, &le_val, 2);
+}
+
+static void v9fs_uint16_read(P9Req *req, uint16_t *val)
+{
+    v9fs_memread(req, val, 2);
+    le16_to_cpus(val);
+}
+
+static void v9fs_uint32_write(P9Req *req, uint32_t val)
+{
+    uint32_t le_val = cpu_to_le32(val);
+
+    v9fs_memwrite(req, &le_val, 4);
+}
+
+static void v9fs_uint64_write(P9Req *req, uint64_t val)
+{
+    uint64_t le_val = cpu_to_le64(val);
+
+    v9fs_memwrite(req, &le_val, 8);
+}
+
+static void v9fs_uint32_read(P9Req *req, uint32_t *val)
+{
+    v9fs_memread(req, val, 4);
+    le32_to_cpus(val);
+}
+
+/* len[2] string[len] */
+static uint16_t v9fs_string_size(const char *string)
+{
+    size_t len = strlen(string);
+
+    g_assert_cmpint(len, <=, UINT16_MAX - 2);
+
+    return 2 + len;
+}
+
+static void v9fs_string_write(P9Req *req, const char *string)
+{
+    int len = strlen(string);
+
+    g_assert_cmpint(len, <=, UINT16_MAX);
+
+    v9fs_uint16_write(req, (uint16_t) len);
+    v9fs_memwrite(req, string, len);
+}
+
+static void v9fs_string_read(P9Req *req, uint16_t *len, char **string)
+{
+    uint16_t local_len;
+
+    v9fs_uint16_read(req, &local_len);
+    if (len) {
+        *len = local_len;
+    }
+    if (string) {
+        *string = g_malloc(local_len);
+        v9fs_memread(req, *string, local_len);
+    } else {
+        v9fs_memskip(req, local_len);
+    }
+}
+
+ typedef struct {
+    uint32_t size;
+    uint8_t id;
+    uint16_t tag;
+} QEMU_PACKED P9Hdr;
+
+static P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id,
+                            uint16_t tag)
+{
+    P9Req *req = g_new0(P9Req, 1);
+    uint32_t total_size = 7; /* 9P header has well-known size of 7 bytes */
+    P9Hdr hdr = {
+        .id = id,
+        .tag = cpu_to_le16(tag)
+    };
+
+    g_assert_cmpint(total_size, <=, UINT32_MAX - size);
+    total_size += size;
+    hdr.size = cpu_to_le32(total_size);
+
+    g_assert_cmpint(total_size, <=, P9_MAX_SIZE);
+
+    req->qts = global_qtest;
+    req->v9p = v9p;
+    req->t_size = total_size;
+    req->t_msg = guest_alloc(alloc, req->t_size);
+    v9fs_memwrite(req, &hdr, 7);
+    req->tag = tag;
+    return req;
+}
+
+static void v9fs_req_send(P9Req *req)
+{
+    QVirtio9P *v9p = req->v9p;
+
+    req->r_msg = guest_alloc(alloc, P9_MAX_SIZE);
+    req->free_head = qvirtqueue_add(req->qts, v9p->vq, req->t_msg, req->t_size,
+                                    false, true);
+    qvirtqueue_add(req->qts, v9p->vq, req->r_msg, P9_MAX_SIZE, true, false);
+    qvirtqueue_kick(req->qts, v9p->vdev, v9p->vq, req->free_head);
+    req->t_off = 0;
+}
+
+static const char *rmessage_name(uint8_t id)
+{
+    return
+        id == P9_RLERROR ? "RLERROR" :
+        id == P9_RVERSION ? "RVERSION" :
+        id == P9_RATTACH ? "RATTACH" :
+        id == P9_RWALK ? "RWALK" :
+        id == P9_RLOPEN ? "RLOPEN" :
+        id == P9_RWRITE ? "RWRITE" :
+        id == P9_RFLUSH ? "RFLUSH" :
+        "<unknown>";
+}
+
+static void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len)
+{
+    QVirtio9P *v9p = req->v9p;
+
+    qvirtio_wait_used_elem(req->qts, v9p->vdev, v9p->vq, req->free_head, len,
+                           QVIRTIO_9P_TIMEOUT_US);
+}
+
+static void v9fs_req_recv(P9Req *req, uint8_t id)
+{
+    P9Hdr hdr;
+
+    v9fs_memread(req, &hdr, 7);
+    hdr.size = ldl_le_p(&hdr.size);
+    hdr.tag = lduw_le_p(&hdr.tag);
+
+    g_assert_cmpint(hdr.size, >=, 7);
+    g_assert_cmpint(hdr.size, <=, P9_MAX_SIZE);
+    g_assert_cmpint(hdr.tag, ==, req->tag);
+
+    if (hdr.id != id) {
+        g_printerr("Received response %d (%s) instead of %d (%s)\n",
+                   hdr.id, rmessage_name(hdr.id), id, rmessage_name(id));
+
+        if (hdr.id == P9_RLERROR) {
+            uint32_t err;
+            v9fs_uint32_read(req, &err);
+            g_printerr("Rlerror has errno %d (%s)\n", err, strerror(err));
+        }
+    }
+    g_assert_cmpint(hdr.id, ==, id);
+}
+
+static void v9fs_req_free(P9Req *req)
+{
+    guest_free(alloc, req->t_msg);
+    guest_free(alloc, req->r_msg);
+    g_free(req);
+}
+
+/* size[4] Rlerror tag[2] ecode[4] */
+static void v9fs_rlerror(P9Req *req, uint32_t *err)
+{
+    v9fs_req_recv(req, P9_RLERROR);
+    v9fs_uint32_read(req, err);
+    v9fs_req_free(req);
+}
+
+/* size[4] Tversion tag[2] msize[4] version[s] */
+static P9Req *v9fs_tversion(QVirtio9P *v9p, uint32_t msize, const char *version,
+                            uint16_t tag)
+{
+    P9Req *req;
+    uint32_t body_size = 4;
+    uint16_t string_size = v9fs_string_size(version);
+
+    g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+    body_size += string_size;
+    req = v9fs_req_init(v9p, body_size, P9_TVERSION, tag);
+
+    v9fs_uint32_write(req, msize);
+    v9fs_string_write(req, version);
+    v9fs_req_send(req);
+    return req;
+}
+
+/* size[4] Rversion tag[2] msize[4] version[s] */
+static void v9fs_rversion(P9Req *req, uint16_t *len, char **version)
+{
+    uint32_t msize;
+
+    v9fs_req_recv(req, P9_RVERSION);
+    v9fs_uint32_read(req, &msize);
+
+    g_assert_cmpint(msize, ==, P9_MAX_SIZE);
+
+    if (len || version) {
+        v9fs_string_read(req, len, version);
+    }
+
+    v9fs_req_free(req);
+}
+
+/* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] */
+static P9Req *v9fs_tattach(QVirtio9P *v9p, uint32_t fid, uint32_t n_uname,
+                           uint16_t tag)
+{
+    const char *uname = ""; /* ignored by QEMU */
+    const char *aname = ""; /* ignored by QEMU */
+    P9Req *req = v9fs_req_init(v9p, 4 + 4 + 2 + 2 + 4, P9_TATTACH, tag);
+
+    v9fs_uint32_write(req, fid);
+    v9fs_uint32_write(req, P9_NOFID);
+    v9fs_string_write(req, uname);
+    v9fs_string_write(req, aname);
+    v9fs_uint32_write(req, n_uname);
+    v9fs_req_send(req);
+    return req;
+}
+
+typedef char v9fs_qid[13];
+
+/* size[4] Rattach tag[2] qid[13] */
+static void v9fs_rattach(P9Req *req, v9fs_qid *qid)
+{
+    v9fs_req_recv(req, P9_RATTACH);
+    if (qid) {
+        v9fs_memread(req, qid, 13);
+    }
+    v9fs_req_free(req);
+}
+
+/* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
+static P9Req *v9fs_twalk(QVirtio9P *v9p, uint32_t fid, uint32_t newfid,
+                         uint16_t nwname, char *const wnames[], uint16_t tag)
+{
+    P9Req *req;
+    int i;
+    uint32_t body_size = 4 + 4 + 2;
+
+    for (i = 0; i < nwname; i++) {
+        uint16_t wname_size = v9fs_string_size(wnames[i]);
+
+        g_assert_cmpint(body_size, <=, UINT32_MAX - wname_size);
+        body_size += wname_size;
+    }
+    req = v9fs_req_init(v9p,  body_size, P9_TWALK, tag);
+    v9fs_uint32_write(req, fid);
+    v9fs_uint32_write(req, newfid);
+    v9fs_uint16_write(req, nwname);
+    for (i = 0; i < nwname; i++) {
+        v9fs_string_write(req, wnames[i]);
+    }
+    v9fs_req_send(req);
+    return req;
+}
+
+/* size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) */
+static void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid)
+{
+    uint16_t local_nwqid;
+
+    v9fs_req_recv(req, P9_RWALK);
+    v9fs_uint16_read(req, &local_nwqid);
+    if (nwqid) {
+        *nwqid = local_nwqid;
+    }
+    if (wqid) {
+        *wqid = g_malloc(local_nwqid * 13);
+        v9fs_memread(req, *wqid, local_nwqid * 13);
+    }
+    v9fs_req_free(req);
+}
+
+/* size[4] Tlopen tag[2] fid[4] flags[4] */
+static P9Req *v9fs_tlopen(QVirtio9P *v9p, uint32_t fid, uint32_t flags,
+                          uint16_t tag)
+{
+    P9Req *req;
+
+    req = v9fs_req_init(v9p,  4 + 4, P9_TLOPEN, tag);
+    v9fs_uint32_write(req, fid);
+    v9fs_uint32_write(req, flags);
+    v9fs_req_send(req);
+    return req;
+}
+
+/* size[4] Rlopen tag[2] qid[13] iounit[4] */
+static void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit)
+{
+    v9fs_req_recv(req, P9_RLOPEN);
+    if (qid) {
+        v9fs_memread(req, qid, 13);
+    } else {
+        v9fs_memskip(req, 13);
+    }
+    if (iounit) {
+        v9fs_uint32_read(req, iounit);
+    }
+    v9fs_req_free(req);
+}
+
+/* size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] */
+static P9Req *v9fs_twrite(QVirtio9P *v9p, uint32_t fid, uint64_t offset,
+                          uint32_t count, const void *data, uint16_t tag)
+{
+    P9Req *req;
+    uint32_t body_size = 4 + 8 + 4;
+
+    g_assert_cmpint(body_size, <=, UINT32_MAX - count);
+    body_size += count;
+    req = v9fs_req_init(v9p,  body_size, P9_TWRITE, tag);
+    v9fs_uint32_write(req, fid);
+    v9fs_uint64_write(req, offset);
+    v9fs_uint32_write(req, count);
+    v9fs_memwrite(req, data, count);
+    v9fs_req_send(req);
+    return req;
+}
+
+/* size[4] Rwrite tag[2] count[4] */
+static void v9fs_rwrite(P9Req *req, uint32_t *count)
+{
+    v9fs_req_recv(req, P9_RWRITE);
+    if (count) {
+        v9fs_uint32_read(req, count);
+    }
+    v9fs_req_free(req);
+}
+
+/* size[4] Tflush tag[2] oldtag[2] */
+static P9Req *v9fs_tflush(QVirtio9P *v9p, uint16_t oldtag, uint16_t tag)
+{
+    P9Req *req;
+
+    req = v9fs_req_init(v9p,  2, P9_TFLUSH, tag);
+    v9fs_uint32_write(req, oldtag);
+    v9fs_req_send(req);
+    return req;
+}
+
+/* size[4] Rflush tag[2] */
+static void v9fs_rflush(P9Req *req)
+{
+    v9fs_req_recv(req, P9_RFLUSH);
+    v9fs_req_free(req);
+}
+
+static void fs_version(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
+    const char *version = "9P2000.L";
+    uint16_t server_len;
+    char *server_version;
+    P9Req *req;
+
+    req = v9fs_tversion(v9p, P9_MAX_SIZE, version, P9_NOTAG);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rversion(req, &server_len, &server_version);
+
+    g_assert_cmpmem(server_version, server_len, version, strlen(version));
+
+    g_free(server_version);
+}
+
+static void fs_attach(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
+    P9Req *req;
+
+    fs_version(v9p, NULL, t_alloc);
+    req = v9fs_tattach(v9p, 0, getuid(), 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rattach(req, NULL);
+}
+
+static void fs_walk(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
+    char *wnames[P9_MAXWELEM];
+    uint16_t nwqid;
+    v9fs_qid *wqid;
+    int i;
+    P9Req *req;
+
+    for (i = 0; i < P9_MAXWELEM; i++) {
+        wnames[i] = g_strdup_printf(QTEST_V9FS_SYNTH_WALK_FILE, i);
+    }
+
+    fs_attach(v9p, NULL, t_alloc);
+    req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames, 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rwalk(req, &nwqid, &wqid);
+
+    g_assert_cmpint(nwqid, ==, P9_MAXWELEM);
+
+    for (i = 0; i < P9_MAXWELEM; i++) {
+        g_free(wnames[i]);
+    }
+
+    g_free(wqid);
+}
+
+static void fs_walk_no_slash(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
+    char *const wnames[] = { g_strdup(" /") };
+    P9Req *req;
+    uint32_t err;
+
+    fs_attach(v9p, NULL, t_alloc);
+    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rlerror(req, &err);
+
+    g_assert_cmpint(err, ==, ENOENT);
+
+    g_free(wnames[0]);
+}
+
+static void fs_walk_dotdot(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
+    char *const wnames[] = { g_strdup("..") };
+    v9fs_qid root_qid, *wqid;
+    P9Req *req;
+
+    fs_version(v9p, NULL, t_alloc);
+    req = v9fs_tattach(v9p, 0, getuid(), 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rattach(req, &root_qid);
+
+    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rwalk(req, NULL, &wqid); /* We now we'll get one qid */
+
+    g_assert_cmpmem(&root_qid, 13, wqid[0], 13);
+
+    g_free(wqid);
+    g_free(wnames[0]);
+}
+
+static void fs_lopen(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
+    char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_LOPEN_FILE) };
+    P9Req *req;
+
+    fs_attach(v9p, NULL, t_alloc);
+    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rwalk(req, NULL, NULL);
+
+    req = v9fs_tlopen(v9p, 1, O_WRONLY, 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rlopen(req, NULL, NULL);
+
+    g_free(wnames[0]);
+}
+
+static void fs_write(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
+    static const uint32_t write_count = P9_MAX_SIZE / 2;
+    char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_WRITE_FILE) };
+    char *buf = g_malloc0(write_count);
+    uint32_t count;
+    P9Req *req;
+
+    fs_attach(v9p, NULL, t_alloc);
+    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rwalk(req, NULL, NULL);
+
+    req = v9fs_tlopen(v9p, 1, O_WRONLY, 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rlopen(req, NULL, NULL);
+
+    req = v9fs_twrite(v9p, 1, 0, write_count, buf, 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rwrite(req, &count);
+    g_assert_cmpint(count, ==, write_count);
+
+    g_free(buf);
+    g_free(wnames[0]);
+}
+
+static void fs_flush_success(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
+    char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) };
+    P9Req *req, *flush_req;
+    uint32_t reply_len;
+    uint8_t should_block;
+
+    fs_attach(v9p, NULL, t_alloc);
+    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rwalk(req, NULL, NULL);
+
+    req = v9fs_tlopen(v9p, 1, O_WRONLY, 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rlopen(req, NULL, NULL);
+
+    /* This will cause the 9p server to try to write data to the backend,
+     * until the write request gets cancelled.
+     */
+    should_block = 1;
+    req = v9fs_twrite(v9p, 1, 0, sizeof(should_block), &should_block, 0);
+
+    flush_req = v9fs_tflush(v9p, req->tag, 1);
+
+    /* The write request is supposed to be flushed: the server should just
+     * mark the write request as used and reply to the flush request.
+     */
+    v9fs_req_wait_for_reply(req, &reply_len);
+    g_assert_cmpint(reply_len, ==, 0);
+    v9fs_req_free(req);
+    v9fs_rflush(flush_req);
+
+    g_free(wnames[0]);
+}
+
+static void fs_flush_ignored(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
+    char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) };
+    P9Req *req, *flush_req;
+    uint32_t count;
+    uint8_t should_block;
+
+    fs_attach(v9p, NULL, t_alloc);
+    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rwalk(req, NULL, NULL);
+
+    req = v9fs_tlopen(v9p, 1, O_WRONLY, 0);
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rlopen(req, NULL, NULL);
+
+    /* This will cause the write request to complete right away, before it
+     * could be actually cancelled.
+     */
+    should_block = 0;
+    req = v9fs_twrite(v9p, 1, 0, sizeof(should_block), &should_block, 0);
+
+    flush_req = v9fs_tflush(v9p, req->tag, 1);
+
+    /* The write request is supposed to complete. The server should
+     * reply to the write request and the flush request.
+     */
+    v9fs_req_wait_for_reply(req, NULL);
+    v9fs_rwrite(req, &count);
+    g_assert_cmpint(count, ==, sizeof(should_block));
+    v9fs_rflush(flush_req);
+
+    g_free(wnames[0]);
+}
+
+static void register_virtio_9p_test(void)
+{
+    qos_add_test("config", "virtio-9p", pci_config, NULL);
+    qos_add_test("fs/version/basic", "virtio-9p", fs_version, NULL);
+    qos_add_test("fs/attach/basic", "virtio-9p", fs_attach, NULL);
+    qos_add_test("fs/walk/basic", "virtio-9p", fs_walk, NULL);
+    qos_add_test("fs/walk/no_slash", "virtio-9p", fs_walk_no_slash,
+                 NULL);
+    qos_add_test("fs/walk/dotdot_from_root", "virtio-9p",
+                 fs_walk_dotdot, NULL);
+    qos_add_test("fs/lopen/basic", "virtio-9p", fs_lopen, NULL);
+    qos_add_test("fs/write/basic", "virtio-9p", fs_write, NULL);
+    qos_add_test("fs/flush/success", "virtio-9p", fs_flush_success,
+                 NULL);
+    qos_add_test("fs/flush/ignored", "virtio-9p", fs_flush_ignored,
+                 NULL);
+}
+
+libqos_init(register_virtio_9p_test);
diff --git a/tests/qtest/virtio-blk-test.c b/tests/qtest/virtio-blk-test.c
new file mode 100644 (file)
index 0000000..2a23698
--- /dev/null
@@ -0,0 +1,802 @@
+/*
+ * QTest testcase for VirtIO Block Device
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ * Copyright (c) 2014 Marc Marí
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "qemu/bswap.h"
+#include "qemu/module.h"
+#include "standard-headers/linux/virtio_blk.h"
+#include "standard-headers/linux/virtio_pci.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-blk.h"
+
+/* TODO actually test the results and get rid of this */
+#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
+
+#define TEST_IMAGE_SIZE         (64 * 1024 * 1024)
+#define QVIRTIO_BLK_TIMEOUT_US  (30 * 1000 * 1000)
+#define PCI_SLOT_HP             0x06
+
+typedef struct QVirtioBlkReq {
+    uint32_t type;
+    uint32_t ioprio;
+    uint64_t sector;
+    char *data;
+    uint8_t status;
+} QVirtioBlkReq;
+
+
+#ifdef HOST_WORDS_BIGENDIAN
+const bool host_is_big_endian = true;
+#else
+const bool host_is_big_endian; /* false */
+#endif
+
+static void drive_destroy(void *path)
+{
+    unlink(path);
+    g_free(path);
+    qos_invalidate_command_line();
+}
+
+static char *drive_create(void)
+{
+    int fd, ret;
+    char *t_path = g_strdup("/tmp/qtest.XXXXXX");
+
+    /* Create a temporary raw image */
+    fd = mkstemp(t_path);
+    g_assert_cmpint(fd, >=, 0);
+    ret = ftruncate(fd, TEST_IMAGE_SIZE);
+    g_assert_cmpint(ret, ==, 0);
+    close(fd);
+
+    g_test_queue_destroy(drive_destroy, t_path);
+    return t_path;
+}
+
+static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
+{
+    if (qvirtio_is_big_endian(d) != host_is_big_endian) {
+        req->type = bswap32(req->type);
+        req->ioprio = bswap32(req->ioprio);
+        req->sector = bswap64(req->sector);
+    }
+}
+
+
+static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
+    struct virtio_blk_discard_write_zeroes *dwz_hdr)
+{
+    if (qvirtio_is_big_endian(d) != host_is_big_endian) {
+        dwz_hdr->sector = bswap64(dwz_hdr->sector);
+        dwz_hdr->num_sectors = bswap32(dwz_hdr->num_sectors);
+        dwz_hdr->flags = bswap32(dwz_hdr->flags);
+    }
+}
+
+static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
+                                   QVirtioBlkReq *req, uint64_t data_size)
+{
+    uint64_t addr;
+    uint8_t status = 0xFF;
+
+    switch (req->type) {
+    case VIRTIO_BLK_T_IN:
+    case VIRTIO_BLK_T_OUT:
+        g_assert_cmpuint(data_size % 512, ==, 0);
+        break;
+    case VIRTIO_BLK_T_DISCARD:
+    case VIRTIO_BLK_T_WRITE_ZEROES:
+        g_assert_cmpuint(data_size %
+                         sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
+        break;
+    default:
+        g_assert_cmpuint(data_size, ==, 0);
+    }
+
+    addr = guest_alloc(alloc, sizeof(*req) + data_size);
+
+    virtio_blk_fix_request(d, req);
+
+    memwrite(addr, req, 16);
+    memwrite(addr + 16, req->data, data_size);
+    memwrite(addr + 16 + data_size, &status, sizeof(status));
+
+    return addr;
+}
+
+/* Returns the request virtqueue so the caller can perform further tests */
+static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
+{
+    QVirtioBlkReq req;
+    uint64_t req_addr;
+    uint64_t capacity;
+    uint64_t features;
+    uint32_t free_head;
+    uint8_t status;
+    char *data;
+    QTestState *qts = global_qtest;
+    QVirtQueue *vq;
+
+    features = qvirtio_get_features(dev);
+    features = features & ~(QVIRTIO_F_BAD_FEATURE |
+                    (1u << VIRTIO_RING_F_INDIRECT_DESC) |
+                    (1u << VIRTIO_RING_F_EVENT_IDX) |
+                    (1u << VIRTIO_BLK_F_SCSI));
+    qvirtio_set_features(dev, features);
+
+    capacity = qvirtio_config_readq(dev, 0);
+    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
+
+    vq = qvirtqueue_setup(dev, alloc, 0);
+
+    qvirtio_set_driver_ok(dev);
+
+    /* Write and read with 3 descriptor layout */
+    /* Write request */
+    req.type = VIRTIO_BLK_T_OUT;
+    req.ioprio = 1;
+    req.sector = 0;
+    req.data = g_malloc0(512);
+    strcpy(req.data, "TEST");
+
+    req_addr = virtio_blk_request(alloc, dev, &req, 512);
+
+    g_free(req.data);
+
+    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+    qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
+    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+
+    qvirtqueue_kick(qts, dev, vq, free_head);
+
+    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                           QVIRTIO_BLK_TIMEOUT_US);
+    status = readb(req_addr + 528);
+    g_assert_cmpint(status, ==, 0);
+
+    guest_free(alloc, req_addr);
+
+    /* Read request */
+    req.type = VIRTIO_BLK_T_IN;
+    req.ioprio = 1;
+    req.sector = 0;
+    req.data = g_malloc0(512);
+
+    req_addr = virtio_blk_request(alloc, dev, &req, 512);
+
+    g_free(req.data);
+
+    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+    qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
+    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+
+    qvirtqueue_kick(qts, dev, vq, free_head);
+
+    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                           QVIRTIO_BLK_TIMEOUT_US);
+    status = readb(req_addr + 528);
+    g_assert_cmpint(status, ==, 0);
+
+    data = g_malloc0(512);
+    memread(req_addr + 16, data, 512);
+    g_assert_cmpstr(data, ==, "TEST");
+    g_free(data);
+
+    guest_free(alloc, req_addr);
+
+    if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
+        struct virtio_blk_discard_write_zeroes dwz_hdr;
+        void *expected;
+
+        /*
+         * WRITE_ZEROES request on the same sector of previous test where
+         * we wrote "TEST".
+         */
+        req.type = VIRTIO_BLK_T_WRITE_ZEROES;
+        req.data = (char *) &dwz_hdr;
+        dwz_hdr.sector = 0;
+        dwz_hdr.num_sectors = 1;
+        dwz_hdr.flags = 0;
+
+        virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
+
+        req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
+
+        free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+        qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
+        qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
+                       false);
+
+        qvirtqueue_kick(qts, dev, vq, free_head);
+
+        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                               QVIRTIO_BLK_TIMEOUT_US);
+        status = readb(req_addr + 16 + sizeof(dwz_hdr));
+        g_assert_cmpint(status, ==, 0);
+
+        guest_free(alloc, req_addr);
+
+        /* Read request to check if the sector contains all zeroes */
+        req.type = VIRTIO_BLK_T_IN;
+        req.ioprio = 1;
+        req.sector = 0;
+        req.data = g_malloc0(512);
+
+        req_addr = virtio_blk_request(alloc, dev, &req, 512);
+
+        g_free(req.data);
+
+        free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+        qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
+        qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+
+        qvirtqueue_kick(qts, dev, vq, free_head);
+
+        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                               QVIRTIO_BLK_TIMEOUT_US);
+        status = readb(req_addr + 528);
+        g_assert_cmpint(status, ==, 0);
+
+        data = g_malloc(512);
+        expected = g_malloc0(512);
+        memread(req_addr + 16, data, 512);
+        g_assert_cmpmem(data, 512, expected, 512);
+        g_free(expected);
+        g_free(data);
+
+        guest_free(alloc, req_addr);
+    }
+
+    if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
+        struct virtio_blk_discard_write_zeroes dwz_hdr;
+
+        req.type = VIRTIO_BLK_T_DISCARD;
+        req.data = (char *) &dwz_hdr;
+        dwz_hdr.sector = 0;
+        dwz_hdr.num_sectors = 1;
+        dwz_hdr.flags = 0;
+
+        virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
+
+        req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
+
+        free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+        qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
+        qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false);
+
+        qvirtqueue_kick(qts, dev, vq, free_head);
+
+        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                               QVIRTIO_BLK_TIMEOUT_US);
+        status = readb(req_addr + 16 + sizeof(dwz_hdr));
+        g_assert_cmpint(status, ==, 0);
+
+        guest_free(alloc, req_addr);
+    }
+
+    if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
+        /* Write and read with 2 descriptor layout */
+        /* Write request */
+        req.type = VIRTIO_BLK_T_OUT;
+        req.ioprio = 1;
+        req.sector = 1;
+        req.data = g_malloc0(512);
+        strcpy(req.data, "TEST");
+
+        req_addr = virtio_blk_request(alloc, dev, &req, 512);
+
+        g_free(req.data);
+
+        free_head = qvirtqueue_add(qts, vq, req_addr, 528, false, true);
+        qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+        qvirtqueue_kick(qts, dev, vq, free_head);
+
+        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                               QVIRTIO_BLK_TIMEOUT_US);
+        status = readb(req_addr + 528);
+        g_assert_cmpint(status, ==, 0);
+
+        guest_free(alloc, req_addr);
+
+        /* Read request */
+        req.type = VIRTIO_BLK_T_IN;
+        req.ioprio = 1;
+        req.sector = 1;
+        req.data = g_malloc0(512);
+
+        req_addr = virtio_blk_request(alloc, dev, &req, 512);
+
+        g_free(req.data);
+
+        free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+        qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
+
+        qvirtqueue_kick(qts, dev, vq, free_head);
+
+        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                               QVIRTIO_BLK_TIMEOUT_US);
+        status = readb(req_addr + 528);
+        g_assert_cmpint(status, ==, 0);
+
+        data = g_malloc0(512);
+        memread(req_addr + 16, data, 512);
+        g_assert_cmpstr(data, ==, "TEST");
+        g_free(data);
+
+        guest_free(alloc, req_addr);
+    }
+
+    return vq;
+}
+
+static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtioBlk *blk_if = obj;
+    QVirtQueue *vq;
+
+    vq = test_basic(blk_if->vdev, t_alloc);
+    qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
+
+}
+
+static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
+{
+    QVirtQueue *vq;
+    QVirtioBlk *blk_if = obj;
+    QVirtioDevice *dev = blk_if->vdev;
+    QVirtioBlkReq req;
+    QVRingIndirectDesc *indirect;
+    uint64_t req_addr;
+    uint64_t capacity;
+    uint64_t features;
+    uint32_t free_head;
+    uint8_t status;
+    char *data;
+    QTestState *qts = global_qtest;
+
+    features = qvirtio_get_features(dev);
+    g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
+    features = features & ~(QVIRTIO_F_BAD_FEATURE |
+                            (1u << VIRTIO_RING_F_EVENT_IDX) |
+                            (1u << VIRTIO_BLK_F_SCSI));
+    qvirtio_set_features(dev, features);
+
+    capacity = qvirtio_config_readq(dev, 0);
+    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
+
+    vq = qvirtqueue_setup(dev, t_alloc, 0);
+    qvirtio_set_driver_ok(dev);
+
+    /* Write request */
+    req.type = VIRTIO_BLK_T_OUT;
+    req.ioprio = 1;
+    req.sector = 0;
+    req.data = g_malloc0(512);
+    strcpy(req.data, "TEST");
+
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
+
+    g_free(req.data);
+
+    indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
+    qvring_indirect_desc_add(dev, qts, indirect, req_addr, 528, false);
+    qvring_indirect_desc_add(dev, qts, indirect, req_addr + 528, 1, true);
+    free_head = qvirtqueue_add_indirect(qts, vq, indirect);
+    qvirtqueue_kick(qts, dev, vq, free_head);
+
+    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                           QVIRTIO_BLK_TIMEOUT_US);
+    status = readb(req_addr + 528);
+    g_assert_cmpint(status, ==, 0);
+
+    g_free(indirect);
+    guest_free(t_alloc, req_addr);
+
+    /* Read request */
+    req.type = VIRTIO_BLK_T_IN;
+    req.ioprio = 1;
+    req.sector = 0;
+    req.data = g_malloc0(512);
+    strcpy(req.data, "TEST");
+
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
+
+    g_free(req.data);
+
+    indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
+    qvring_indirect_desc_add(dev, qts, indirect, req_addr, 16, false);
+    qvring_indirect_desc_add(dev, qts, indirect, req_addr + 16, 513, true);
+    free_head = qvirtqueue_add_indirect(qts, vq, indirect);
+    qvirtqueue_kick(qts, dev, vq, free_head);
+
+    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                           QVIRTIO_BLK_TIMEOUT_US);
+    status = readb(req_addr + 528);
+    g_assert_cmpint(status, ==, 0);
+
+    data = g_malloc0(512);
+    memread(req_addr + 16, data, 512);
+    g_assert_cmpstr(data, ==, "TEST");
+    g_free(data);
+
+    g_free(indirect);
+    guest_free(t_alloc, req_addr);
+    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
+}
+
+static void config(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtioBlk *blk_if = obj;
+    QVirtioDevice *dev = blk_if->vdev;
+    int n_size = TEST_IMAGE_SIZE / 2;
+    uint64_t features;
+    uint64_t capacity;
+
+    features = qvirtio_get_features(dev);
+    features = features & ~(QVIRTIO_F_BAD_FEATURE |
+                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
+                            (1u << VIRTIO_RING_F_EVENT_IDX) |
+                            (1u << VIRTIO_BLK_F_SCSI));
+    qvirtio_set_features(dev, features);
+
+    capacity = qvirtio_config_readq(dev, 0);
+    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
+
+    qvirtio_set_driver_ok(dev);
+
+    qmp_discard_response("{ 'execute': 'block_resize', "
+                         " 'arguments': { 'device': 'drive0', "
+                         " 'size': %d } }", n_size);
+    qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
+
+    capacity = qvirtio_config_readq(dev, 0);
+    g_assert_cmpint(capacity, ==, n_size / 512);
+}
+
+static void msix(void *obj, void *u_data, QGuestAllocator *t_alloc)
+{
+    QVirtQueue *vq;
+    QVirtioBlkPCI *blk = obj;
+    QVirtioPCIDevice *pdev = &blk->pci_vdev;
+    QVirtioDevice *dev = &pdev->vdev;
+    QVirtioBlkReq req;
+    int n_size = TEST_IMAGE_SIZE / 2;
+    uint64_t req_addr;
+    uint64_t capacity;
+    uint64_t features;
+    uint32_t free_head;
+    uint8_t status;
+    char *data;
+    QOSGraphObject *blk_object = obj;
+    QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
+    QTestState *qts = global_qtest;
+
+    if (qpci_check_buggy_msi(pci_dev)) {
+        return;
+    }
+
+    qpci_msix_enable(pdev->pdev);
+    qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
+
+    features = qvirtio_get_features(dev);
+    features = features & ~(QVIRTIO_F_BAD_FEATURE |
+                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
+                            (1u << VIRTIO_RING_F_EVENT_IDX) |
+                            (1u << VIRTIO_BLK_F_SCSI));
+    qvirtio_set_features(dev, features);
+
+    capacity = qvirtio_config_readq(dev, 0);
+    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
+
+    vq = qvirtqueue_setup(dev, t_alloc, 0);
+    qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
+
+    qvirtio_set_driver_ok(dev);
+
+    qmp_discard_response("{ 'execute': 'block_resize', "
+                         " 'arguments': { 'device': 'drive0', "
+                         " 'size': %d } }", n_size);
+
+    qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
+
+    capacity = qvirtio_config_readq(dev, 0);
+    g_assert_cmpint(capacity, ==, n_size / 512);
+
+    /* Write request */
+    req.type = VIRTIO_BLK_T_OUT;
+    req.ioprio = 1;
+    req.sector = 0;
+    req.data = g_malloc0(512);
+    strcpy(req.data, "TEST");
+
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
+
+    g_free(req.data);
+
+    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+    qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
+    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+    qvirtqueue_kick(qts, dev, vq, free_head);
+
+    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                           QVIRTIO_BLK_TIMEOUT_US);
+
+    status = readb(req_addr + 528);
+    g_assert_cmpint(status, ==, 0);
+
+    guest_free(t_alloc, req_addr);
+
+    /* Read request */
+    req.type = VIRTIO_BLK_T_IN;
+    req.ioprio = 1;
+    req.sector = 0;
+    req.data = g_malloc0(512);
+
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
+
+    g_free(req.data);
+
+    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+    qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
+    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+
+    qvirtqueue_kick(qts, dev, vq, free_head);
+
+
+    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                           QVIRTIO_BLK_TIMEOUT_US);
+
+    status = readb(req_addr + 528);
+    g_assert_cmpint(status, ==, 0);
+
+    data = g_malloc0(512);
+    memread(req_addr + 16, data, 512);
+    g_assert_cmpstr(data, ==, "TEST");
+    g_free(data);
+
+    guest_free(t_alloc, req_addr);
+
+    /* End test */
+    qpci_msix_disable(pdev->pdev);
+    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
+}
+
+static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
+{
+    QVirtQueue *vq;
+    QVirtioBlkPCI *blk = obj;
+    QVirtioPCIDevice *pdev = &blk->pci_vdev;
+    QVirtioDevice *dev = &pdev->vdev;
+    QVirtioBlkReq req;
+    uint64_t req_addr;
+    uint64_t capacity;
+    uint64_t features;
+    uint32_t free_head;
+    uint32_t write_head;
+    uint32_t desc_idx;
+    uint8_t status;
+    char *data;
+    QOSGraphObject *blk_object = obj;
+    QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
+    QTestState *qts = global_qtest;
+
+    if (qpci_check_buggy_msi(pci_dev)) {
+        return;
+    }
+
+    qpci_msix_enable(pdev->pdev);
+    qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
+
+    features = qvirtio_get_features(dev);
+    features = features & ~(QVIRTIO_F_BAD_FEATURE |
+                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
+                            (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
+                            (1u << VIRTIO_BLK_F_SCSI));
+    qvirtio_set_features(dev, features);
+
+    capacity = qvirtio_config_readq(dev, 0);
+    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
+
+    vq = qvirtqueue_setup(dev, t_alloc, 0);
+    qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
+
+    qvirtio_set_driver_ok(dev);
+
+    /* Write request */
+    req.type = VIRTIO_BLK_T_OUT;
+    req.ioprio = 1;
+    req.sector = 0;
+    req.data = g_malloc0(512);
+    strcpy(req.data, "TEST");
+
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
+
+    g_free(req.data);
+
+    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+    qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
+    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+    qvirtqueue_kick(qts, dev, vq, free_head);
+
+    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                           QVIRTIO_BLK_TIMEOUT_US);
+
+    /* Write request */
+    req.type = VIRTIO_BLK_T_OUT;
+    req.ioprio = 1;
+    req.sector = 1;
+    req.data = g_malloc0(512);
+    strcpy(req.data, "TEST");
+
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
+
+    g_free(req.data);
+
+    /* Notify after processing the third request */
+    qvirtqueue_set_used_event(qts, vq, 2);
+    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+    qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
+    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+    qvirtqueue_kick(qts, dev, vq, free_head);
+    write_head = free_head;
+
+    /* No notification expected */
+    status = qvirtio_wait_status_byte_no_isr(qts, dev,
+                                             vq, req_addr + 528,
+                                             QVIRTIO_BLK_TIMEOUT_US);
+    g_assert_cmpint(status, ==, 0);
+
+    guest_free(t_alloc, req_addr);
+
+    /* Read request */
+    req.type = VIRTIO_BLK_T_IN;
+    req.ioprio = 1;
+    req.sector = 1;
+    req.data = g_malloc0(512);
+
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
+
+    g_free(req.data);
+
+    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+    qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
+    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+
+    qvirtqueue_kick(qts, dev, vq, free_head);
+
+    /* We get just one notification for both requests */
+    qvirtio_wait_used_elem(qts, dev, vq, write_head, NULL,
+                           QVIRTIO_BLK_TIMEOUT_US);
+    g_assert(qvirtqueue_get_buf(qts, vq, &desc_idx, NULL));
+    g_assert_cmpint(desc_idx, ==, free_head);
+
+    status = readb(req_addr + 528);
+    g_assert_cmpint(status, ==, 0);
+
+    data = g_malloc0(512);
+    memread(req_addr + 16, data, 512);
+    g_assert_cmpstr(data, ==, "TEST");
+    g_free(data);
+
+    guest_free(t_alloc, req_addr);
+
+    /* End test */
+    qpci_msix_disable(pdev->pdev);
+
+    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
+}
+
+static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtioPCIDevice *dev1 = obj;
+    QVirtioPCIDevice *dev;
+    QTestState *qts = dev1->pdev->bus->qts;
+
+    /* plug secondary disk */
+    qtest_qmp_device_add(qts, "virtio-blk-pci", "drv1",
+                         "{'addr': %s, 'drive': 'drive1'}",
+                         stringify(PCI_SLOT_HP) ".0");
+
+    dev = virtio_pci_new(dev1->pdev->bus,
+                         &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0) });
+    g_assert_nonnull(dev);
+    g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
+    qvirtio_pci_device_disable(dev);
+    qos_object_destroy((QOSGraphObject *)dev);
+
+    /* unplug secondary disk */
+    qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
+}
+
+/*
+ * Check that setting the vring addr on a non-existent virtqueue does
+ * not crash.
+ */
+static void test_nonexistent_virtqueue(void *obj, void *data,
+                                       QGuestAllocator *t_alloc)
+{
+    QVirtioBlkPCI *blk = obj;
+    QVirtioPCIDevice *pdev = &blk->pci_vdev;
+    QPCIBar bar0;
+    QPCIDevice *dev;
+
+    dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
+    g_assert(dev != NULL);
+    qpci_device_enable(dev);
+
+    bar0 = qpci_iomap(dev, 0, NULL);
+
+    qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
+    qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
+
+
+    g_free(dev);
+}
+
+static void resize(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtioBlk *blk_if = obj;
+    QVirtioDevice *dev = blk_if->vdev;
+    int n_size = TEST_IMAGE_SIZE / 2;
+    uint64_t capacity;
+    QVirtQueue *vq;
+    QTestState *qts = global_qtest;
+
+    vq = test_basic(dev, t_alloc);
+
+    qmp_discard_response("{ 'execute': 'block_resize', "
+                         " 'arguments': { 'device': 'drive0', "
+                         " 'size': %d } }", n_size);
+
+    qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
+
+    capacity = qvirtio_config_readq(dev, 0);
+    g_assert_cmpint(capacity, ==, n_size / 512);
+
+    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
+
+}
+
+static void *virtio_blk_test_setup(GString *cmd_line, void *arg)
+{
+    char *tmp_path = drive_create();
+
+    g_string_append_printf(cmd_line,
+                           " -drive if=none,id=drive0,file=%s,"
+                           "format=raw,auto-read-only=off "
+                           "-drive if=none,id=drive1,file=null-co://,"
+                           "file.read-zeroes=on,format=raw ",
+                           tmp_path);
+
+    return arg;
+}
+
+static void register_virtio_blk_test(void)
+{
+    QOSGraphTestOptions opts = {
+        .before = virtio_blk_test_setup,
+    };
+
+    qos_add_test("indirect", "virtio-blk", indirect, &opts);
+    qos_add_test("config", "virtio-blk", config, &opts);
+    qos_add_test("basic", "virtio-blk", basic, &opts);
+    qos_add_test("resize", "virtio-blk", resize, &opts);
+
+    /* tests just for virtio-blk-pci */
+    qos_add_test("msix", "virtio-blk-pci", msix, &opts);
+    qos_add_test("idx", "virtio-blk-pci", idx, &opts);
+    qos_add_test("nxvirtq", "virtio-blk-pci",
+                      test_nonexistent_virtqueue, &opts);
+    qos_add_test("hotplug", "virtio-blk-pci", pci_hotplug, &opts);
+}
+
+libqos_init(register_virtio_blk_test);
diff --git a/tests/qtest/virtio-ccw-test.c b/tests/qtest/virtio-ccw-test.c
new file mode 100644 (file)
index 0000000..d052364
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * QTest testcase for VirtIO CCW
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+/* Until we have a full libqos implementation of virtio-ccw (which requires
+ * also to add support for I/O channels to qtest), we can only do simple
+ * tests that initialize the devices.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "libqos/virtio.h"
+
+static void virtio_balloon_nop(void)
+{
+    global_qtest = qtest_initf("-device virtio-balloon-ccw");
+    qtest_end();
+}
+
+static void virtconsole_nop(void)
+{
+    global_qtest = qtest_initf("-device virtio-serial-ccw,id=vser0 "
+                                "-device virtconsole,bus=vser0.0");
+    qtest_end();
+}
+
+static void virtserialport_nop(void)
+{
+    global_qtest = qtest_initf("-device virtio-serial-ccw,id=vser0 "
+                                "-device virtserialport,bus=vser0.0");
+    qtest_end();
+}
+
+static void virtio_serial_nop(void)
+{
+    global_qtest = qtest_initf("-device virtio-serial-ccw");
+    qtest_end();
+}
+
+static void virtio_serial_hotplug(void)
+{
+    QTestState *qts = qtest_initf("-device virtio-serial-ccw");
+
+    qtest_qmp_device_add(qts, "virtserialport", "hp-port", "{}");
+    qtest_qmp_device_del(qts, "hp-port");
+
+    qtest_quit(qts);
+}
+
+static void virtio_blk_nop(void)
+{
+    global_qtest = qtest_initf("-drive if=none,id=drv0,file=null-co://,"
+                               "file.read-zeroes=on,format=raw "
+                                "-device virtio-blk-ccw,drive=drv0");
+    qtest_end();
+}
+
+static void virtio_net_nop(void)
+{
+    global_qtest = qtest_initf("-device virtio-net-ccw");
+    qtest_end();
+}
+
+static void virtio_rng_nop(void)
+{
+    global_qtest = qtest_initf("-device virtio-rng-ccw");
+    qtest_end();
+}
+
+static void virtio_scsi_nop(void)
+{
+    global_qtest = qtest_initf("-device virtio-scsi-ccw");
+    qtest_end();
+}
+
+static void virtio_scsi_hotplug(void)
+{
+    QTestState *s = qtest_initf("-drive if=none,id=drv0,file=null-co://,"
+                                "file.read-zeroes=on,format=raw "
+                                "-drive if=none,id=drv1,file=null-co://,"
+                                "file.read-zeroes=on,format=raw "
+                                "-device virtio-scsi-ccw "
+                                "-device scsi-hd,drive=drv0");
+    qtest_qmp_device_add(s, "scsi-hd", "scsihd", "{'drive': 'drv1'}");
+    qtest_qmp_device_del(s, "scsihd");
+
+    qtest_quit(s);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/virtio/balloon/nop", virtio_balloon_nop);
+    qtest_add_func("/virtio/console/nop", virtconsole_nop);
+    qtest_add_func("/virtio/serialport/nop", virtserialport_nop);
+    qtest_add_func("/virtio/serial/nop", virtio_serial_nop);
+    qtest_add_func("/virtio/serial/hotplug", virtio_serial_hotplug);
+    qtest_add_func("/virtio/block/nop", virtio_blk_nop);
+    qtest_add_func("/virtio/net/nop", virtio_net_nop);
+    qtest_add_func("/virtio/rng/nop", virtio_rng_nop);
+    qtest_add_func("/virtio/scsi/nop", virtio_scsi_nop);
+    qtest_add_func("/virtio/scsi/hotplug", virtio_scsi_hotplug);
+
+    ret = g_test_run();
+
+    return ret;
+}
diff --git a/tests/qtest/virtio-net-test.c b/tests/qtest/virtio-net-test.c
new file mode 100644 (file)
index 0000000..a08e2ff
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * QTest testcase for VirtIO NIC
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "libqtest-single.h"
+#include "qemu/iov.h"
+#include "qemu/module.h"
+#include "qapi/qmp/qdict.h"
+#include "hw/virtio/virtio-net.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-net.h"
+
+#ifndef ETH_P_RARP
+#define ETH_P_RARP 0x8035
+#endif
+
+#define PCI_SLOT_HP             0x06
+#define PCI_SLOT                0x04
+
+#define QVIRTIO_NET_TIMEOUT_US (30 * 1000 * 1000)
+#define VNET_HDR_SIZE sizeof(struct virtio_net_hdr_mrg_rxbuf)
+
+#ifndef _WIN32
+
+static void rx_test(QVirtioDevice *dev,
+                    QGuestAllocator *alloc, QVirtQueue *vq,
+                    int socket)
+{
+    QTestState *qts = global_qtest;
+    uint64_t req_addr;
+    uint32_t free_head;
+    char test[] = "TEST";
+    char buffer[64];
+    int len = htonl(sizeof(test));
+    struct iovec iov[] = {
+        {
+            .iov_base = &len,
+            .iov_len = sizeof(len),
+        }, {
+            .iov_base = test,
+            .iov_len = sizeof(test),
+        },
+    };
+    int ret;
+
+    req_addr = guest_alloc(alloc, 64);
+
+    free_head = qvirtqueue_add(qts, vq, req_addr, 64, true, false);
+    qvirtqueue_kick(qts, dev, vq, free_head);
+
+    ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test));
+    g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len));
+
+    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                           QVIRTIO_NET_TIMEOUT_US);
+    memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test));
+    g_assert_cmpstr(buffer, ==, "TEST");
+
+    guest_free(alloc, req_addr);
+}
+
+static void tx_test(QVirtioDevice *dev,
+                    QGuestAllocator *alloc, QVirtQueue *vq,
+                    int socket)
+{
+    QTestState *qts = global_qtest;
+    uint64_t req_addr;
+    uint32_t free_head;
+    uint32_t len;
+    char buffer[64];
+    int ret;
+
+    req_addr = guest_alloc(alloc, 64);
+    memwrite(req_addr + VNET_HDR_SIZE, "TEST", 4);
+
+    free_head = qvirtqueue_add(qts, vq, req_addr, 64, false, false);
+    qvirtqueue_kick(qts, dev, vq, free_head);
+
+    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                           QVIRTIO_NET_TIMEOUT_US);
+    guest_free(alloc, req_addr);
+
+    ret = qemu_recv(socket, &len, sizeof(len), 0);
+    g_assert_cmpint(ret, ==, sizeof(len));
+    len = ntohl(len);
+
+    ret = qemu_recv(socket, buffer, len, 0);
+    g_assert_cmpstr(buffer, ==, "TEST");
+}
+
+static void rx_stop_cont_test(QVirtioDevice *dev,
+                              QGuestAllocator *alloc, QVirtQueue *vq,
+                              int socket)
+{
+    QTestState *qts = global_qtest;
+    uint64_t req_addr;
+    uint32_t free_head;
+    char test[] = "TEST";
+    char buffer[64];
+    int len = htonl(sizeof(test));
+    QDict *rsp;
+    struct iovec iov[] = {
+        {
+            .iov_base = &len,
+            .iov_len = sizeof(len),
+        }, {
+            .iov_base = test,
+            .iov_len = sizeof(test),
+        },
+    };
+    int ret;
+
+    req_addr = guest_alloc(alloc, 64);
+
+    free_head = qvirtqueue_add(qts, vq, req_addr, 64, true, false);
+    qvirtqueue_kick(qts, dev, vq, free_head);
+
+    rsp = qmp("{ 'execute' : 'stop'}");
+    qobject_unref(rsp);
+
+    ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test));
+    g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len));
+
+    /* We could check the status, but this command is more importantly to
+     * ensure the packet data gets queued in QEMU, before we do 'cont'.
+     */
+    rsp = qmp("{ 'execute' : 'query-status'}");
+    qobject_unref(rsp);
+    rsp = qmp("{ 'execute' : 'cont'}");
+    qobject_unref(rsp);
+
+    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+                           QVIRTIO_NET_TIMEOUT_US);
+    memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test));
+    g_assert_cmpstr(buffer, ==, "TEST");
+
+    guest_free(alloc, req_addr);
+}
+
+static void send_recv_test(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtioNet *net_if = obj;
+    QVirtioDevice *dev = net_if->vdev;
+    QVirtQueue *rx = net_if->queues[0];
+    QVirtQueue *tx = net_if->queues[1];
+    int *sv = data;
+
+    rx_test(dev, t_alloc, rx, sv[0]);
+    tx_test(dev, t_alloc, tx, sv[0]);
+}
+
+static void stop_cont_test(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtioNet *net_if = obj;
+    QVirtioDevice *dev = net_if->vdev;
+    QVirtQueue *rx = net_if->queues[0];
+    int *sv = data;
+
+    rx_stop_cont_test(dev, t_alloc, rx, sv[0]);
+}
+
+#endif
+
+static void hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtioPCIDevice *dev = obj;
+    QTestState *qts = dev->pdev->bus->qts;
+    const char *arch = qtest_get_arch();
+
+    qtest_qmp_device_add(qts, "virtio-net-pci", "net1",
+                         "{'addr': %s}", stringify(PCI_SLOT_HP));
+
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        qpci_unplug_acpi_device_test(qts, "net1", PCI_SLOT_HP);
+    }
+}
+
+static void announce_self(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    int *sv = data;
+    char buffer[60];
+    int len;
+    QDict *rsp;
+    int ret;
+    uint16_t *proto = (uint16_t *)&buffer[12];
+    size_t total_received = 0;
+    uint64_t start, now, last_rxt, deadline;
+
+    /* Send a set of packets over a few second period */
+    rsp = qmp("{ 'execute' : 'announce-self', "
+                  " 'arguments': {"
+                      " 'initial': 20, 'max': 100,"
+                      " 'rounds': 300, 'step': 10, 'id': 'bob' } }");
+    assert(!qdict_haskey(rsp, "error"));
+    qobject_unref(rsp);
+
+    /* Catch the first packet and make sure it's a RARP */
+    ret = qemu_recv(sv[0], &len, sizeof(len), 0);
+    g_assert_cmpint(ret, ==,  sizeof(len));
+    len = ntohl(len);
+
+    ret = qemu_recv(sv[0], buffer, len, 0);
+    g_assert_cmpint(*proto, ==, htons(ETH_P_RARP));
+
+    /*
+     * Stop the announcment by settings rounds to 0 on the
+     * existing timer.
+     */
+    rsp = qmp("{ 'execute' : 'announce-self', "
+                  " 'arguments': {"
+                      " 'initial': 20, 'max': 100,"
+                      " 'rounds': 0, 'step': 10, 'id': 'bob' } }");
+    assert(!qdict_haskey(rsp, "error"));
+    qobject_unref(rsp);
+
+    /* Now make sure the packets stop */
+
+    /* Times are in us */
+    start = g_get_monotonic_time();
+    /* 30 packets, max gap 100ms, * 4 for wiggle */
+    deadline = start + 1000 * (100 * 30 * 4);
+    last_rxt = start;
+
+    while (true) {
+        int saved_err;
+        ret = qemu_recv(sv[0], buffer, 60, MSG_DONTWAIT);
+        saved_err = errno;
+        now = g_get_monotonic_time();
+        g_assert_cmpint(now, <, deadline);
+
+        if (ret >= 0) {
+            if (ret) {
+                last_rxt = now;
+            }
+            total_received += ret;
+
+            /* Check it's not spewing loads */
+            g_assert_cmpint(total_received, <, 60 * 30 * 2);
+        } else {
+            g_assert_cmpint(saved_err, ==, EAGAIN);
+
+            /* 400ms, i.e. 4 worst case gaps */
+            if ((now - last_rxt) > (1000 * 100 * 4)) {
+                /* Nothings arrived for a while - must have stopped */
+                break;
+            };
+
+            /* 100ms */
+            g_usleep(1000 * 100);
+        }
+    };
+}
+
+static void virtio_net_test_cleanup(void *sockets)
+{
+    int *sv = sockets;
+
+    close(sv[0]);
+    qos_invalidate_command_line();
+    close(sv[1]);
+    g_free(sv);
+}
+
+static void *virtio_net_test_setup(GString *cmd_line, void *arg)
+{
+    int ret;
+    int *sv = g_new(int, 2);
+
+    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
+    g_assert_cmpint(ret, !=, -1);
+
+    g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ", sv[1]);
+
+    g_test_queue_destroy(virtio_net_test_cleanup, sv);
+    return sv;
+}
+
+static void large_tx(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+    QVirtioNet *dev = obj;
+    QVirtQueue *vq = dev->queues[1];
+    uint64_t req_addr;
+    uint32_t free_head;
+    size_t alloc_size = (size_t)data / 64;
+    QTestState *qts = global_qtest;
+    int i;
+
+    /* Bypass the limitation by pointing several descriptors to a single
+     * smaller area */
+    req_addr = guest_alloc(t_alloc, alloc_size);
+    free_head = qvirtqueue_add(qts, vq, req_addr, alloc_size, false, true);
+
+    for (i = 0; i < 64; i++) {
+        qvirtqueue_add(qts, vq, req_addr, alloc_size, false, i != 63);
+    }
+    qvirtqueue_kick(qts, dev->vdev, vq, free_head);
+
+    qvirtio_wait_used_elem(qts, dev->vdev, vq, free_head, NULL,
+                           QVIRTIO_NET_TIMEOUT_US);
+    guest_free(t_alloc, req_addr);
+}
+
+static void *virtio_net_test_setup_nosocket(GString *cmd_line, void *arg)
+{
+    g_string_append(cmd_line, " -netdev hubport,hubid=0,id=hs0 ");
+    return arg;
+}
+
+static void register_virtio_net_test(void)
+{
+    QOSGraphTestOptions opts = {
+        .before = virtio_net_test_setup,
+    };
+
+    qos_add_test("hotplug", "virtio-pci", hotplug, &opts);
+#ifndef _WIN32
+    qos_add_test("basic", "virtio-net", send_recv_test, &opts);
+    qos_add_test("rx_stop_cont", "virtio-net", stop_cont_test, &opts);
+#endif
+    qos_add_test("announce-self", "virtio-net", announce_self, &opts);
+
+    /* These tests do not need a loopback backend.  */
+    opts.before = virtio_net_test_setup_nosocket;
+    opts.arg = (gpointer)UINT_MAX;
+    qos_add_test("large_tx/uint_max", "virtio-net", large_tx, &opts);
+    opts.arg = (gpointer)NET_BUFSIZE;
+    qos_add_test("large_tx/net_bufsize", "virtio-net", large_tx, &opts);
+}
+
+libqos_init(register_virtio_net_test);
diff --git a/tests/qtest/virtio-rng-test.c b/tests/qtest/virtio-rng-test.c
new file mode 100644 (file)
index 0000000..092ba13
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * QTest testcase for VirtIO RNG
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-rng.h"
+
+#define PCI_SLOT_HP             0x06
+
+static void rng_hotplug(void *obj, void *data, QGuestAllocator *alloc)
+{
+    QVirtioPCIDevice *dev = obj;
+    QTestState *qts = dev->pdev->bus->qts;
+
+    const char *arch = qtest_get_arch();
+
+    qtest_qmp_device_add(qts, "virtio-rng-pci", "rng1",
+                         "{'addr': %s}", stringify(PCI_SLOT_HP));
+
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        qpci_unplug_acpi_device_test(qts, "rng1", PCI_SLOT_HP);
+    }
+}
+
+static void register_virtio_rng_test(void)
+{
+    qos_add_test("hotplug", "virtio-rng-pci", rng_hotplug, NULL);
+}
+
+libqos_init(register_virtio_rng_test);
diff --git a/tests/qtest/virtio-scsi-test.c b/tests/qtest/virtio-scsi-test.c
new file mode 100644 (file)
index 0000000..0415e75
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * QTest testcase for VirtIO SCSI
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ * Copyright (c) 2015 Red Hat Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "qemu/module.h"
+#include "scsi/constants.h"
+#include "libqos/libqos-pc.h"
+#include "libqos/libqos-spapr.h"
+#include "libqos/virtio.h"
+#include "libqos/virtio-pci.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/virtio_pci.h"
+#include "standard-headers/linux/virtio_scsi.h"
+#include "libqos/virtio-scsi.h"
+#include "libqos/qgraph.h"
+
+#define PCI_SLOT                0x02
+#define PCI_FN                  0x00
+#define QVIRTIO_SCSI_TIMEOUT_US (1 * 1000 * 1000)
+
+#define MAX_NUM_QUEUES 64
+
+typedef struct {
+    QVirtioDevice *dev;
+    int num_queues;
+    QVirtQueue *vq[MAX_NUM_QUEUES + 2];
+} QVirtioSCSIQueues;
+
+static QGuestAllocator *alloc;
+
+static void qvirtio_scsi_pci_free(QVirtioSCSIQueues *vs)
+{
+    int i;
+
+    for (i = 0; i < vs->num_queues + 2; i++) {
+        qvirtqueue_cleanup(vs->dev->bus, vs->vq[i], alloc);
+    }
+    g_free(vs);
+}
+
+static uint64_t qvirtio_scsi_alloc(QVirtioSCSIQueues *vs, size_t alloc_size,
+                                   const void *data)
+{
+    uint64_t addr;
+
+    addr = guest_alloc(alloc, alloc_size);
+    if (data) {
+        memwrite(addr, data, alloc_size);
+    }
+
+    return addr;
+}
+
+static uint8_t virtio_scsi_do_command(QVirtioSCSIQueues *vs,
+                                      const uint8_t *cdb,
+                                      const uint8_t *data_in,
+                                      size_t data_in_len,
+                                      uint8_t *data_out, size_t data_out_len,
+                                      struct virtio_scsi_cmd_resp *resp_out)
+{
+    QVirtQueue *vq;
+    struct virtio_scsi_cmd_req req = { { 0 } };
+    struct virtio_scsi_cmd_resp resp = { .response = 0xff, .status = 0xff };
+    uint64_t req_addr, resp_addr, data_in_addr = 0, data_out_addr = 0;
+    uint8_t response;
+    uint32_t free_head;
+    QTestState *qts = global_qtest;
+
+    vq = vs->vq[2];
+
+    req.lun[0] = 1; /* Select LUN */
+    req.lun[1] = 1; /* Select target 1 */
+    memcpy(req.cdb, cdb, VIRTIO_SCSI_CDB_SIZE);
+
+    /* XXX: Fix endian if any multi-byte field in req/resp is used */
+
+    /* Add request header */
+    req_addr = qvirtio_scsi_alloc(vs, sizeof(req), &req);
+    free_head = qvirtqueue_add(qts, vq, req_addr, sizeof(req), false, true);
+
+    if (data_out_len) {
+        data_out_addr = qvirtio_scsi_alloc(vs, data_out_len, data_out);
+        qvirtqueue_add(qts, vq, data_out_addr, data_out_len, false, true);
+    }
+
+    /* Add response header */
+    resp_addr = qvirtio_scsi_alloc(vs, sizeof(resp), &resp);
+    qvirtqueue_add(qts, vq, resp_addr, sizeof(resp), true, !!data_in_len);
+
+    if (data_in_len) {
+        data_in_addr = qvirtio_scsi_alloc(vs, data_in_len, data_in);
+        qvirtqueue_add(qts, vq, data_in_addr, data_in_len, true, false);
+    }
+
+    qvirtqueue_kick(qts, vs->dev, vq, free_head);
+    qvirtio_wait_used_elem(qts, vs->dev, vq, free_head, NULL,
+                           QVIRTIO_SCSI_TIMEOUT_US);
+
+    response = readb(resp_addr +
+                     offsetof(struct virtio_scsi_cmd_resp, response));
+
+    if (resp_out) {
+        memread(resp_addr, resp_out, sizeof(*resp_out));
+    }
+
+    guest_free(alloc, req_addr);
+    guest_free(alloc, resp_addr);
+    guest_free(alloc, data_in_addr);
+    guest_free(alloc, data_out_addr);
+    return response;
+}
+
+static QVirtioSCSIQueues *qvirtio_scsi_init(QVirtioDevice *dev)
+{
+    QVirtioSCSIQueues *vs;
+    const uint8_t test_unit_ready_cdb[VIRTIO_SCSI_CDB_SIZE] = {};
+    struct virtio_scsi_cmd_resp resp;
+    uint64_t features;
+    int i;
+
+    vs = g_new0(QVirtioSCSIQueues, 1);
+    vs->dev = dev;
+
+    features = qvirtio_get_features(dev);
+    features &= ~(QVIRTIO_F_BAD_FEATURE | (1ull << VIRTIO_RING_F_EVENT_IDX));
+    qvirtio_set_features(dev, features);
+
+    vs->num_queues = qvirtio_config_readl(dev, 0);
+
+    g_assert_cmpint(vs->num_queues, <, MAX_NUM_QUEUES);
+
+    for (i = 0; i < vs->num_queues + 2; i++) {
+        vs->vq[i] = qvirtqueue_setup(dev, alloc, i);
+    }
+
+    qvirtio_set_driver_ok(dev);
+
+    /* Clear the POWER ON OCCURRED unit attention */
+    g_assert_cmpint(virtio_scsi_do_command(vs, test_unit_ready_cdb,
+                                           NULL, 0, NULL, 0, &resp),
+                    ==, 0);
+    g_assert_cmpint(resp.status, ==, CHECK_CONDITION);
+    g_assert_cmpint(resp.sense[0], ==, 0x70); /* Fixed format sense buffer */
+    g_assert_cmpint(resp.sense[2], ==, UNIT_ATTENTION);
+    g_assert_cmpint(resp.sense[12], ==, 0x29); /* POWER ON */
+    g_assert_cmpint(resp.sense[13], ==, 0x00);
+
+    return vs;
+}
+
+static void hotplug(void *obj, void *data, QGuestAllocator *alloc)
+{
+    QTestState *qts = global_qtest;
+
+    qtest_qmp_device_add(qts, "scsi-hd", "scsihd", "{'drive': 'drv1'}");
+    qtest_qmp_device_del(qts, "scsihd");
+}
+
+/* Test WRITE SAME with the lba not aligned */
+static void test_unaligned_write_same(void *obj, void *data,
+                                      QGuestAllocator *t_alloc)
+{
+    QVirtioSCSI *scsi = obj;
+    QVirtioSCSIQueues *vs;
+    uint8_t buf1[512] = { 0 };
+    uint8_t buf2[512] = { 1 };
+    const uint8_t write_same_cdb_1[VIRTIO_SCSI_CDB_SIZE] = {
+        0x41, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00
+    };
+    const uint8_t write_same_cdb_2[VIRTIO_SCSI_CDB_SIZE] = {
+        0x41, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x33, 0x00, 0x00
+    };
+    const uint8_t write_same_cdb_ndob[VIRTIO_SCSI_CDB_SIZE] = {
+        0x41, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x33, 0x00, 0x00
+    };
+
+    alloc = t_alloc;
+    vs = qvirtio_scsi_init(scsi->vdev);
+
+    g_assert_cmphex(0, ==,
+        virtio_scsi_do_command(vs, write_same_cdb_1, NULL, 0, buf1, 512,
+                               NULL));
+
+    g_assert_cmphex(0, ==,
+        virtio_scsi_do_command(vs, write_same_cdb_2, NULL, 0, buf2, 512,
+                               NULL));
+
+    g_assert_cmphex(0, ==,
+        virtio_scsi_do_command(vs, write_same_cdb_ndob, NULL, 0, NULL, 0,
+                               NULL));
+
+    qvirtio_scsi_pci_free(vs);
+}
+
+static void test_iothread_attach_node(void *obj, void *data,
+                                      QGuestAllocator *t_alloc)
+{
+    QVirtioSCSIPCI *scsi_pci = obj;
+    QVirtioSCSI *scsi = &scsi_pci->scsi;
+    QVirtioSCSIQueues *vs;
+    char tmp_path[] = "/tmp/qtest.XXXXXX";
+    int fd;
+    int ret;
+
+    uint8_t buf[512] = { 0 };
+    const uint8_t write_cdb[VIRTIO_SCSI_CDB_SIZE] = {
+        /* WRITE(10) to LBA 0, transfer length 1 */
+        0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
+    };
+
+    alloc = t_alloc;
+    vs = qvirtio_scsi_init(scsi->vdev);
+
+    /* Create a temporary qcow2 overlay*/
+    fd = mkstemp(tmp_path);
+    g_assert(fd >= 0);
+    close(fd);
+
+    if (!have_qemu_img()) {
+        g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
+                       "skipping snapshot test");
+        goto fail;
+    }
+
+    mkqcow2(tmp_path, 64);
+
+    /* Attach the overlay to the null0 node */
+    qtest_qmp_assert_success(scsi_pci->pci_vdev.pdev->bus->qts,
+                             "{'execute': 'blockdev-add', 'arguments': {"
+                             "   'driver': 'qcow2', 'node-name': 'overlay',"
+                             "   'backing': 'null0', 'file': {"
+                             "     'driver': 'file', 'filename': %s}}}",
+                             tmp_path);
+
+    /* Send a request to see if the AioContext is still right */
+    ret = virtio_scsi_do_command(vs, write_cdb, NULL, 0, buf, 512, NULL);
+    g_assert_cmphex(ret, ==, 0);
+
+fail:
+    qvirtio_scsi_pci_free(vs);
+    unlink(tmp_path);
+}
+
+static void *virtio_scsi_hotplug_setup(GString *cmd_line, void *arg)
+{
+    g_string_append(cmd_line,
+                    " -drive id=drv1,if=none,file=null-co://,"
+                    "file.read-zeroes=on,format=raw");
+    return arg;
+}
+
+static void *virtio_scsi_setup(GString *cmd_line, void *arg)
+{
+    g_string_append(cmd_line,
+                    " -drive file=blkdebug::null-co://,"
+                    "file.image.read-zeroes=on,"
+                    "if=none,id=dr1,format=raw,file.align=4k "
+                    "-device scsi-hd,drive=dr1,lun=0,scsi-id=1");
+    return arg;
+}
+
+static void *virtio_scsi_setup_iothread(GString *cmd_line, void *arg)
+{
+    g_string_append(cmd_line,
+                    " -object iothread,id=thread0"
+                    " -blockdev driver=null-co,read-zeroes=on,node-name=null0"
+                    " -device scsi-hd,drive=null0");
+    return arg;
+}
+
+static void register_virtio_scsi_test(void)
+{
+    QOSGraphTestOptions opts = { };
+
+    opts.before = virtio_scsi_hotplug_setup;
+    qos_add_test("hotplug", "virtio-scsi", hotplug, &opts);
+
+    opts.before = virtio_scsi_setup;
+    qos_add_test("unaligned-write-same", "virtio-scsi",
+                 test_unaligned_write_same, &opts);
+
+    opts.before = virtio_scsi_setup_iothread;
+    opts.edge = (QOSGraphEdgeOptions) {
+        .extra_device_opts = "iothread=thread0",
+    };
+    qos_add_test("iothread-attach-node", "virtio-scsi-pci",
+                 test_iothread_attach_node, &opts);
+}
+
+libqos_init(register_virtio_scsi_test);
diff --git a/tests/qtest/virtio-serial-test.c b/tests/qtest/virtio-serial-test.c
new file mode 100644 (file)
index 0000000..2541034
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * QTest testcase for VirtIO Serial
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "qemu/module.h"
+#include "libqos/virtio-serial.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void virtio_serial_nop(void *obj, void *data, QGuestAllocator *alloc)
+{
+    /* no operation */
+}
+
+static void serial_hotplug(void *obj, void *data, QGuestAllocator *alloc)
+{
+    qtest_qmp_device_add(global_qtest, "virtserialport", "hp-port", "{}");
+    qtest_qmp_device_del(global_qtest, "hp-port");
+}
+
+static void register_virtio_serial_test(void)
+{
+    QOSGraphTestOptions opts = { };
+
+    opts.edge.before_cmd_line = "-device virtconsole,bus=vser0.0";
+    qos_add_test("console-nop", "virtio-serial", virtio_serial_nop, &opts);
+
+    opts.edge.before_cmd_line = "-device virtserialport,bus=vser0.0";
+    qos_add_test("serialport-nop", "virtio-serial", virtio_serial_nop, &opts);
+
+    qos_add_test("hotplug", "virtio-serial", serial_hotplug, NULL);
+}
+libqos_init(register_virtio_serial_test);
diff --git a/tests/qtest/virtio-test.c b/tests/qtest/virtio-test.c
new file mode 100644 (file)
index 0000000..f7c6afd
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * QTest testcase for virtio
+ *
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void nop(void *obj, void *data, QGuestAllocator *alloc)
+{
+}
+
+static void register_virtio_test(void)
+{
+    qos_add_test("nop", "virtio", nop, NULL);
+}
+
+libqos_init(register_virtio_test);
diff --git a/tests/qtest/vmgenid-test.c b/tests/qtest/vmgenid-test.c
new file mode 100644 (file)
index 0000000..efba76e
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * QTest testcase for VM Generation ID
+ *
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Copyright (c) 2017 Skyport Systems
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bitmap.h"
+#include "qemu/uuid.h"
+#include "hw/acpi/acpi-defs.h"
+#include "boot-sector.h"
+#include "acpi-utils.h"
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+
+#define VGID_GUID "324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87"
+#define VMGENID_GUID_OFFSET 40   /* allow space for
+                                  * OVMF SDT Header Probe Supressor
+                                  */
+#define RSDP_ADDR_INVALID 0x100000 /* RSDP must be below this address */
+
+static uint32_t acpi_find_vgia(QTestState *qts)
+{
+    uint32_t rsdp_offset;
+    uint32_t guid_offset = 0;
+    uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
+    uint32_t rsdt_len, table_length;
+    uint8_t *rsdt, *ent;
+
+    /* Wait for guest firmware to finish and start the payload. */
+    boot_sector_test(qts);
+
+    /* Tables should be initialized now. */
+    rsdp_offset = acpi_find_rsdp_address(qts);
+
+    g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID);
+
+
+    acpi_fetch_rsdp_table(qts, rsdp_offset, rsdp_table);
+    acpi_fetch_table(qts, &rsdt, &rsdt_len, &rsdp_table[16 /* RsdtAddress */],
+                     4, "RSDT", true);
+
+    ACPI_FOREACH_RSDT_ENTRY(rsdt, rsdt_len, ent, 4 /* Entry size */) {
+        uint8_t *table_aml;
+
+        acpi_fetch_table(qts, &table_aml, &table_length, ent, 4, NULL, true);
+        if (!memcmp(table_aml + 16 /* OEM Table ID */, "VMGENID", 7)) {
+            uint32_t vgia_val;
+            uint8_t *aml = &table_aml[36 /* AML byte-code start */];
+            /* the first entry in the table should be VGIA
+             * That's all we need
+             */
+            g_assert(aml[0 /* name_op*/] == 0x08);
+            g_assert(memcmp(&aml[1 /* name */], "VGIA", 4) == 0);
+            g_assert(aml[5 /* value op */] == 0x0C /* dword */);
+            memcpy(&vgia_val, &aml[6 /* value */], 4);
+
+            /* The GUID is written at a fixed offset into the fw_cfg file
+             * in order to implement the "OVMF SDT Header probe suppressor"
+             * see docs/specs/vmgenid.txt for more details
+             */
+            guid_offset = le32_to_cpu(vgia_val) + VMGENID_GUID_OFFSET;
+            g_free(table_aml);
+            break;
+        }
+        g_free(table_aml);
+    }
+    g_free(rsdt);
+    return guid_offset;
+}
+
+static void read_guid_from_memory(QTestState *qts, QemuUUID *guid)
+{
+    uint32_t vmgenid_addr;
+    int i;
+
+    vmgenid_addr = acpi_find_vgia(qts);
+    g_assert(vmgenid_addr);
+
+    /* Read the GUID directly from guest memory */
+    for (i = 0; i < 16; i++) {
+        guid->data[i] = qtest_readb(qts, vmgenid_addr + i);
+    }
+    /* The GUID is in little-endian format in the guest, while QEMU
+     * uses big-endian.  Swap after reading.
+     */
+    *guid = qemu_uuid_bswap(*guid);
+}
+
+static void read_guid_from_monitor(QTestState *qts, QemuUUID *guid)
+{
+    QDict *rsp, *rsp_ret;
+    const char *guid_str;
+
+    rsp = qtest_qmp(qts, "{ 'execute': 'query-vm-generation-id' }");
+    if (qdict_haskey(rsp, "return")) {
+        rsp_ret = qdict_get_qdict(rsp, "return");
+        g_assert(qdict_haskey(rsp_ret, "guid"));
+        guid_str = qdict_get_str(rsp_ret, "guid");
+        g_assert(qemu_uuid_parse(guid_str, guid) == 0);
+    }
+    qobject_unref(rsp);
+}
+
+static char disk[] = "tests/vmgenid-test-disk-XXXXXX";
+
+#define GUID_CMD(guid)                          \
+    "-accel kvm -accel tcg "                    \
+    "-device vmgenid,id=testvgid,guid=%s "      \
+    "-drive id=hd0,if=none,file=%s,format=raw " \
+    "-device ide-hd,drive=hd0 ", guid, disk
+
+static void vmgenid_set_guid_test(void)
+{
+    QemuUUID expected, measured;
+    QTestState *qts;
+
+    g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
+
+    qts = qtest_initf(GUID_CMD(VGID_GUID));
+
+    /* Read the GUID from accessing guest memory */
+    read_guid_from_memory(qts, &measured);
+    g_assert(memcmp(measured.data, expected.data, sizeof(measured.data)) == 0);
+
+    qtest_quit(qts);
+}
+
+static void vmgenid_set_guid_auto_test(void)
+{
+    QemuUUID measured;
+    QTestState *qts;
+
+    qts = qtest_initf(GUID_CMD("auto"));
+
+    read_guid_from_memory(qts, &measured);
+
+    /* Just check that the GUID is non-null */
+    g_assert(!qemu_uuid_is_null(&measured));
+
+    qtest_quit(qts);
+}
+
+static void vmgenid_query_monitor_test(void)
+{
+    QemuUUID expected, measured;
+    QTestState *qts;
+
+    g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
+
+    qts = qtest_initf(GUID_CMD(VGID_GUID));
+
+    /* Read the GUID via the monitor */
+    read_guid_from_monitor(qts, &measured);
+    g_assert(memcmp(measured.data, expected.data, sizeof(measured.data)) == 0);
+
+    qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    ret = boot_sector_init(disk);
+    if (ret) {
+        return ret;
+    }
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/vmgenid/vmgenid/set-guid",
+                   vmgenid_set_guid_test);
+    qtest_add_func("/vmgenid/vmgenid/set-guid-auto",
+                   vmgenid_set_guid_auto_test);
+    qtest_add_func("/vmgenid/vmgenid/query-monitor",
+                   vmgenid_query_monitor_test);
+    ret = g_test_run();
+    boot_sector_cleanup(disk);
+
+    return ret;
+}
diff --git a/tests/qtest/vmxnet3-test.c b/tests/qtest/vmxnet3-test.c
new file mode 100644 (file)
index 0000000..a810252
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * QTest testcase for vmxnet3 NIC
+ *
+ * Copyright (c) 2013-2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
+
+typedef struct QVmxnet3 QVmxnet3;
+
+struct QVmxnet3 {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *vmxnet3_get_driver(void *obj, const char *interface)
+{
+    QVmxnet3 *vmxnet3 = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &vmxnet3->dev;
+    }
+
+    fprintf(stderr, "%s not present in vmxnet3\n", interface);
+    g_assert_not_reached();
+}
+
+static void *vmxnet3_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QVmxnet3 *vmxnet3 = g_new0(QVmxnet3, 1);
+    QPCIBus *bus = pci_bus;
+
+    qpci_device_init(&vmxnet3->dev, bus, addr);
+    vmxnet3->obj.get_driver = vmxnet3_get_driver;
+
+    return &vmxnet3->obj;
+}
+
+static void vmxnet3_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+
+    qos_node_create_driver("vmxnet3", vmxnet3_create);
+    qos_node_consumes("vmxnet3", "pci-bus", &opts);
+    qos_node_produces("vmxnet3", "pci-device");
+}
+
+libqos_init(vmxnet3_register_nodes);
diff --git a/tests/qtest/wdt_ib700-test.c b/tests/qtest/wdt_ib700-test.c
new file mode 100644 (file)
index 0000000..797288d
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * QTest testcase for the IB700 watchdog
+ *
+ * Copyright (c) 2014 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "qemu/timer.h"
+
+static void qmp_check_no_event(QTestState *s)
+{
+    QDict *resp = qtest_qmp(s, "{'execute':'query-status'}");
+    g_assert(qdict_haskey(resp, "return"));
+    qobject_unref(resp);
+}
+
+static QDict *ib700_program_and_wait(QTestState *s)
+{
+    QDict *event, *data;
+
+    qtest_clock_step(s, NANOSECONDS_PER_SECOND * 40);
+    qmp_check_no_event(s);
+
+    /* 2 second limit */
+    qtest_outb(s, 0x443, 14);
+
+    /* Ping */
+    qtest_clock_step(s, NANOSECONDS_PER_SECOND);
+    qmp_check_no_event(s);
+    qtest_outb(s, 0x443, 14);
+
+    /* Disable */
+    qtest_clock_step(s, NANOSECONDS_PER_SECOND);
+    qmp_check_no_event(s);
+    qtest_outb(s, 0x441, 1);
+    qtest_clock_step(s, 3 * NANOSECONDS_PER_SECOND);
+    qmp_check_no_event(s);
+
+    /* Enable and let it fire */
+    qtest_outb(s, 0x443, 13);
+    qtest_clock_step(s, 3 * NANOSECONDS_PER_SECOND);
+    qmp_check_no_event(s);
+    qtest_clock_step(s, 2 * NANOSECONDS_PER_SECOND);
+    event = qtest_qmp_eventwait_ref(s, "WATCHDOG");
+    data = qdict_get_qdict(event, "data");
+    qobject_ref(data);
+    qobject_unref(event);
+    return data;
+}
+
+
+static void ib700_pause(void)
+{
+    QDict *d;
+    QTestState *s = qtest_init("-watchdog-action pause -device ib700");
+
+    qtest_irq_intercept_in(s, "ioapic");
+    d = ib700_program_and_wait(s);
+    g_assert(!strcmp(qdict_get_str(d, "action"), "pause"));
+    qobject_unref(d);
+    qtest_qmp_eventwait(s, "STOP");
+    qtest_quit(s);
+}
+
+static void ib700_reset(void)
+{
+    QDict *d;
+    QTestState *s = qtest_init("-watchdog-action reset -device ib700");
+
+    qtest_irq_intercept_in(s, "ioapic");
+    d = ib700_program_and_wait(s);
+    g_assert(!strcmp(qdict_get_str(d, "action"), "reset"));
+    qobject_unref(d);
+    qtest_qmp_eventwait(s, "RESET");
+    qtest_quit(s);
+}
+
+static void ib700_shutdown(void)
+{
+    QDict *d;
+    QTestState *s;
+
+    s = qtest_init("-watchdog-action reset -no-reboot -device ib700");
+    qtest_irq_intercept_in(s, "ioapic");
+    d = ib700_program_and_wait(s);
+    g_assert(!strcmp(qdict_get_str(d, "action"), "reset"));
+    qobject_unref(d);
+    qtest_qmp_eventwait(s, "SHUTDOWN");
+    qtest_quit(s);
+}
+
+static void ib700_none(void)
+{
+    QDict *d;
+    QTestState *s = qtest_init("-watchdog-action none -device ib700");
+
+    qtest_irq_intercept_in(s, "ioapic");
+    d = ib700_program_and_wait(s);
+    g_assert(!strcmp(qdict_get_str(d, "action"), "none"));
+    qobject_unref(d);
+    qtest_quit(s);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/wdt_ib700/pause", ib700_pause);
+    qtest_add_func("/wdt_ib700/reset", ib700_reset);
+    qtest_add_func("/wdt_ib700/shutdown", ib700_shutdown);
+    qtest_add_func("/wdt_ib700/none", ib700_none);
+
+    return g_test_run();
+}
diff --git a/tests/rtas-test.c b/tests/rtas-test.c
deleted file mode 100644 (file)
index 167b42d..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu/cutils.h"
-#include "libqtest.h"
-
-#include "libqos/libqos-spapr.h"
-#include "libqos/rtas.h"
-
-static void test_rtas_get_time_of_day(void)
-{
-    QOSState *qs;
-    struct tm tm;
-    uint32_t ns;
-    uint64_t ret;
-    time_t t1, t2;
-
-    qs = qtest_spapr_boot("-machine pseries");
-
-    t1 = time(NULL);
-    ret = qrtas_get_time_of_day(qs->qts, &qs->alloc, &tm, &ns);
-    g_assert_cmpint(ret, ==, 0);
-    t2 = mktimegm(&tm);
-    g_assert(t2 - t1 < 5); /* 5 sec max to run the test */
-
-    qtest_shutdown(qs);
-}
-
-int main(int argc, char *argv[])
-{
-    const char *arch = qtest_get_arch();
-
-    g_test_init(&argc, &argv, NULL);
-
-    if (strcmp(arch, "ppc64")) {
-        g_printerr("RTAS requires ppc64-softmmu/qemu-system-ppc64\n");
-        exit(EXIT_FAILURE);
-    }
-    qtest_add_func("rtas/get-time-of-day", test_rtas_get_time_of_day);
-
-    return g_test_run();
-}
diff --git a/tests/rtc-test.c b/tests/rtc-test.c
deleted file mode 100644 (file)
index c7af34f..0000000
+++ /dev/null
@@ -1,720 +0,0 @@
-/*
- * QTest testcase for the MC146818 real-time clock
- *
- * Copyright IBM, Corp. 2012
- *
- * Authors:
- *  Anthony Liguori   <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-
-#include "libqtest-single.h"
-#include "qemu/timer.h"
-#include "hw/rtc/mc146818rtc.h"
-#include "hw/rtc/mc146818rtc_regs.h"
-
-#define UIP_HOLD_LENGTH           (8 * NANOSECONDS_PER_SECOND / 32768)
-
-static uint8_t base = 0x70;
-
-static int bcd2dec(int value)
-{
-    return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
-}
-
-static uint8_t cmos_read(uint8_t reg)
-{
-    outb(base + 0, reg);
-    return inb(base + 1);
-}
-
-static void cmos_write(uint8_t reg, uint8_t val)
-{
-    outb(base + 0, reg);
-    outb(base + 1, val);
-}
-
-static int tm_cmp(struct tm *lhs, struct tm *rhs)
-{
-    time_t a, b;
-    struct tm d1, d2;
-
-    memcpy(&d1, lhs, sizeof(d1));
-    memcpy(&d2, rhs, sizeof(d2));
-
-    a = mktime(&d1);
-    b = mktime(&d2);
-
-    if (a < b) {
-        return -1;
-    } else if (a > b) {
-        return 1;
-    }
-
-    return 0;
-}
-
-#if 0
-static void print_tm(struct tm *tm)
-{
-    printf("%04d-%02d-%02d %02d:%02d:%02d\n",
-           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
-           tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
-}
-#endif
-
-static void cmos_get_date_time(struct tm *date)
-{
-    int base_year = 2000, hour_offset;
-    int sec, min, hour, mday, mon, year;
-    time_t ts;
-    struct tm dummy;
-
-    sec = cmos_read(RTC_SECONDS);
-    min = cmos_read(RTC_MINUTES);
-    hour = cmos_read(RTC_HOURS);
-    mday = cmos_read(RTC_DAY_OF_MONTH);
-    mon = cmos_read(RTC_MONTH);
-    year = cmos_read(RTC_YEAR);
-
-    if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) {
-        sec = bcd2dec(sec);
-        min = bcd2dec(min);
-        hour = bcd2dec(hour);
-        mday = bcd2dec(mday);
-        mon = bcd2dec(mon);
-        year = bcd2dec(year);
-        hour_offset = 80;
-    } else {
-        hour_offset = 0x80;
-    }
-
-    if ((cmos_read(0x0B) & REG_B_24H) == 0) {
-        if (hour >= hour_offset) {
-            hour -= hour_offset;
-            hour += 12;
-        }
-    }
-
-    ts = time(NULL);
-    localtime_r(&ts, &dummy);
-
-    date->tm_isdst = dummy.tm_isdst;
-    date->tm_sec = sec;
-    date->tm_min = min;
-    date->tm_hour = hour;
-    date->tm_mday = mday;
-    date->tm_mon = mon - 1;
-    date->tm_year = base_year + year - 1900;
-#ifndef __sun__
-    date->tm_gmtoff = 0;
-#endif
-
-    ts = mktime(date);
-}
-
-static void check_time(int wiggle)
-{
-    struct tm start, date[4], end;
-    struct tm *datep;
-    time_t ts;
-
-    /*
-     * This check assumes a few things.  First, we cannot guarantee that we get
-     * a consistent reading from the wall clock because we may hit an edge of
-     * the clock while reading.  To work around this, we read four clock readings
-     * such that at least two of them should match.  We need to assume that one
-     * reading is corrupt so we need four readings to ensure that we have at
-     * least two consecutive identical readings
-     *
-     * It's also possible that we'll cross an edge reading the host clock so
-     * simply check to make sure that the clock reading is within the period of
-     * when we expect it to be.
-     */
-
-    ts = time(NULL);
-    gmtime_r(&ts, &start);
-
-    cmos_get_date_time(&date[0]);
-    cmos_get_date_time(&date[1]);
-    cmos_get_date_time(&date[2]);
-    cmos_get_date_time(&date[3]);
-
-    ts = time(NULL);
-    gmtime_r(&ts, &end);
-
-    if (tm_cmp(&date[0], &date[1]) == 0) {
-        datep = &date[0];
-    } else if (tm_cmp(&date[1], &date[2]) == 0) {
-        datep = &date[1];
-    } else if (tm_cmp(&date[2], &date[3]) == 0) {
-        datep = &date[2];
-    } else {
-        g_assert_not_reached();
-    }
-
-    if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
-        long t, s;
-
-        start.tm_isdst = datep->tm_isdst;
-
-        t = (long)mktime(datep);
-        s = (long)mktime(&start);
-        if (t < s) {
-            g_test_message("RTC is %ld second(s) behind wall-clock", (s - t));
-        } else {
-            g_test_message("RTC is %ld second(s) ahead of wall-clock", (t - s));
-        }
-
-        g_assert_cmpint(ABS(t - s), <=, wiggle);
-    }
-}
-
-static int wiggle = 2;
-
-static void set_year_20xx(void)
-{
-    /* Set BCD mode */
-    cmos_write(RTC_REG_B, REG_B_24H);
-    cmos_write(RTC_REG_A, 0x76);
-    cmos_write(RTC_YEAR, 0x11);
-    cmos_write(RTC_CENTURY, 0x20);
-    cmos_write(RTC_MONTH, 0x02);
-    cmos_write(RTC_DAY_OF_MONTH, 0x02);
-    cmos_write(RTC_HOURS, 0x02);
-    cmos_write(RTC_MINUTES, 0x04);
-    cmos_write(RTC_SECONDS, 0x58);
-    cmos_write(RTC_REG_A, 0x26);
-
-    g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
-    g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
-    g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
-    g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
-    g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
-    g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11);
-    g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
-
-    if (sizeof(time_t) == 4) {
-        return;
-    }
-
-    /* Set a date in 2080 to ensure there is no year-2038 overflow.  */
-    cmos_write(RTC_REG_A, 0x76);
-    cmos_write(RTC_YEAR, 0x80);
-    cmos_write(RTC_REG_A, 0x26);
-
-    g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
-    g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
-    g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
-    g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
-    g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
-    g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x80);
-    g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
-
-    cmos_write(RTC_REG_A, 0x76);
-    cmos_write(RTC_YEAR, 0x11);
-    cmos_write(RTC_REG_A, 0x26);
-
-    g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
-    g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
-    g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
-    g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
-    g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
-    g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11);
-    g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
-}
-
-static void set_year_1980(void)
-{
-    /* Set BCD mode */
-    cmos_write(RTC_REG_B, REG_B_24H);
-    cmos_write(RTC_REG_A, 0x76);
-    cmos_write(RTC_YEAR, 0x80);
-    cmos_write(RTC_CENTURY, 0x19);
-    cmos_write(RTC_MONTH, 0x02);
-    cmos_write(RTC_DAY_OF_MONTH, 0x02);
-    cmos_write(RTC_HOURS, 0x02);
-    cmos_write(RTC_MINUTES, 0x04);
-    cmos_write(RTC_SECONDS, 0x58);
-    cmos_write(RTC_REG_A, 0x26);
-
-    g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
-    g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
-    g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
-    g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
-    g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
-    g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x80);
-    g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x19);
-}
-
-static void bcd_check_time(void)
-{
-    /* Set BCD mode */
-    cmos_write(RTC_REG_B, REG_B_24H);
-    check_time(wiggle);
-}
-
-static void dec_check_time(void)
-{
-    /* Set DEC mode */
-    cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM);
-    check_time(wiggle);
-}
-
-static void alarm_time(void)
-{
-    struct tm now;
-    time_t ts;
-    int i;
-
-    ts = time(NULL);
-    gmtime_r(&ts, &now);
-
-    /* set DEC mode */
-    cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM);
-
-    g_assert(!get_irq(RTC_ISA_IRQ));
-    cmos_read(RTC_REG_C);
-
-    now.tm_sec = (now.tm_sec + 2) % 60;
-    cmos_write(RTC_SECONDS_ALARM, now.tm_sec);
-    cmos_write(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE);
-    cmos_write(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE);
-    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
-
-    for (i = 0; i < 2 + wiggle; i++) {
-        if (get_irq(RTC_ISA_IRQ)) {
-            break;
-        }
-
-        clock_step(1000000000);
-    }
-
-    g_assert(get_irq(RTC_ISA_IRQ));
-    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
-    g_assert(cmos_read(RTC_REG_C) == 0);
-}
-
-static void set_time_regs(int h, int m, int s)
-{
-    cmos_write(RTC_HOURS, h);
-    cmos_write(RTC_MINUTES, m);
-    cmos_write(RTC_SECONDS, s);
-}
-
-static void set_time(int mode, int h, int m, int s)
-{
-    cmos_write(RTC_REG_B, mode);
-    cmos_write(RTC_REG_A, 0x76);
-    set_time_regs(h, m, s);
-    cmos_write(RTC_REG_A, 0x26);
-}
-
-static void set_datetime_bcd(int h, int min, int s, int d, int m, int y)
-{
-    cmos_write(RTC_HOURS, h);
-    cmos_write(RTC_MINUTES, min);
-    cmos_write(RTC_SECONDS, s);
-    cmos_write(RTC_YEAR, y & 0xFF);
-    cmos_write(RTC_CENTURY, y >> 8);
-    cmos_write(RTC_MONTH, m);
-    cmos_write(RTC_DAY_OF_MONTH, d);
-}
-
-static void set_datetime_dec(int h, int min, int s, int d, int m, int y)
-{
-    cmos_write(RTC_HOURS, h);
-    cmos_write(RTC_MINUTES, min);
-    cmos_write(RTC_SECONDS, s);
-    cmos_write(RTC_YEAR, y % 100);
-    cmos_write(RTC_CENTURY, y / 100);
-    cmos_write(RTC_MONTH, m);
-    cmos_write(RTC_DAY_OF_MONTH, d);
-}
-
-static void set_datetime(int mode, int h, int min, int s, int d, int m, int y)
-{
-    cmos_write(RTC_REG_B, mode);
-
-    cmos_write(RTC_REG_A, 0x76);
-    if (mode & REG_B_DM) {
-        set_datetime_dec(h, min, s, d, m, y);
-    } else {
-        set_datetime_bcd(h, min, s, d, m, y);
-    }
-    cmos_write(RTC_REG_A, 0x26);
-}
-
-#define assert_time(h, m, s) \
-    do { \
-        g_assert_cmpint(cmos_read(RTC_HOURS), ==, h); \
-        g_assert_cmpint(cmos_read(RTC_MINUTES), ==, m); \
-        g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \
-    } while(0)
-
-#define assert_datetime_bcd(h, min, s, d, m, y) \
-    do { \
-        g_assert_cmpint(cmos_read(RTC_HOURS), ==, h); \
-        g_assert_cmpint(cmos_read(RTC_MINUTES), ==, min); \
-        g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \
-        g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, d); \
-        g_assert_cmpint(cmos_read(RTC_MONTH), ==, m); \
-        g_assert_cmpint(cmos_read(RTC_YEAR), ==, (y & 0xFF)); \
-        g_assert_cmpint(cmos_read(RTC_CENTURY), ==, (y >> 8)); \
-    } while(0)
-
-static void basic_12h_bcd(void)
-{
-    /* set BCD 12 hour mode */
-    set_time(0, 0x81, 0x59, 0x00);
-    clock_step(1000000000LL);
-    assert_time(0x81, 0x59, 0x01);
-    clock_step(59000000000LL);
-    assert_time(0x82, 0x00, 0x00);
-
-    /* test BCD wraparound */
-    set_time(0, 0x09, 0x59, 0x59);
-    clock_step(60000000000LL);
-    assert_time(0x10, 0x00, 0x59);
-
-    /* 12 AM -> 1 AM */
-    set_time(0, 0x12, 0x59, 0x59);
-    clock_step(1000000000LL);
-    assert_time(0x01, 0x00, 0x00);
-
-    /* 12 PM -> 1 PM */
-    set_time(0, 0x92, 0x59, 0x59);
-    clock_step(1000000000LL);
-    assert_time(0x81, 0x00, 0x00);
-
-    /* 11 AM -> 12 PM */
-    set_time(0, 0x11, 0x59, 0x59);
-    clock_step(1000000000LL);
-    assert_time(0x92, 0x00, 0x00);
-    /* TODO: test day wraparound */
-
-    /* 11 PM -> 12 AM */
-    set_time(0, 0x91, 0x59, 0x59);
-    clock_step(1000000000LL);
-    assert_time(0x12, 0x00, 0x00);
-    /* TODO: test day wraparound */
-}
-
-static void basic_12h_dec(void)
-{
-    /* set decimal 12 hour mode */
-    set_time(REG_B_DM, 0x81, 59, 0);
-    clock_step(1000000000LL);
-    assert_time(0x81, 59, 1);
-    clock_step(59000000000LL);
-    assert_time(0x82, 0, 0);
-
-    /* 12 PM -> 1 PM */
-    set_time(REG_B_DM, 0x8c, 59, 59);
-    clock_step(1000000000LL);
-    assert_time(0x81, 0, 0);
-
-    /* 12 AM -> 1 AM */
-    set_time(REG_B_DM, 0x0c, 59, 59);
-    clock_step(1000000000LL);
-    assert_time(0x01, 0, 0);
-
-    /* 11 AM -> 12 PM */
-    set_time(REG_B_DM, 0x0b, 59, 59);
-    clock_step(1000000000LL);
-    assert_time(0x8c, 0, 0);
-
-    /* 11 PM -> 12 AM */
-    set_time(REG_B_DM, 0x8b, 59, 59);
-    clock_step(1000000000LL);
-    assert_time(0x0c, 0, 0);
-    /* TODO: test day wraparound */
-}
-
-static void basic_24h_bcd(void)
-{
-    /* set BCD 24 hour mode */
-    set_time(REG_B_24H, 0x09, 0x59, 0x00);
-    clock_step(1000000000LL);
-    assert_time(0x09, 0x59, 0x01);
-    clock_step(59000000000LL);
-    assert_time(0x10, 0x00, 0x00);
-
-    /* test BCD wraparound */
-    set_time(REG_B_24H, 0x09, 0x59, 0x00);
-    clock_step(60000000000LL);
-    assert_time(0x10, 0x00, 0x00);
-
-    /* TODO: test day wraparound */
-    set_time(REG_B_24H, 0x23, 0x59, 0x00);
-    clock_step(60000000000LL);
-    assert_time(0x00, 0x00, 0x00);
-}
-
-static void basic_24h_dec(void)
-{
-    /* set decimal 24 hour mode */
-    set_time(REG_B_24H | REG_B_DM, 9, 59, 0);
-    clock_step(1000000000LL);
-    assert_time(9, 59, 1);
-    clock_step(59000000000LL);
-    assert_time(10, 0, 0);
-
-    /* test BCD wraparound */
-    set_time(REG_B_24H | REG_B_DM, 9, 59, 0);
-    clock_step(60000000000LL);
-    assert_time(10, 0, 0);
-
-    /* TODO: test day wraparound */
-    set_time(REG_B_24H | REG_B_DM, 23, 59, 0);
-    clock_step(60000000000LL);
-    assert_time(0, 0, 0);
-}
-
-static void am_pm_alarm(void)
-{
-    cmos_write(RTC_MINUTES_ALARM, 0xC0);
-    cmos_write(RTC_SECONDS_ALARM, 0xC0);
-
-    /* set BCD 12 hour mode */
-    cmos_write(RTC_REG_B, 0);
-
-    /* Set time and alarm hour.  */
-    cmos_write(RTC_REG_A, 0x76);
-    cmos_write(RTC_HOURS_ALARM, 0x82);
-    cmos_write(RTC_HOURS, 0x81);
-    cmos_write(RTC_MINUTES, 0x59);
-    cmos_write(RTC_SECONDS, 0x00);
-    cmos_read(RTC_REG_C);
-    cmos_write(RTC_REG_A, 0x26);
-
-    /* Check that alarm triggers when AM/PM is set.  */
-    clock_step(60000000000LL);
-    g_assert(cmos_read(RTC_HOURS) == 0x82);
-    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
-
-    /*
-     * Each of the following two tests takes over 60 seconds due to the time
-     * needed to report the PIT interrupts.  Unfortunately, our PIT device
-     * model keeps counting even when GATE=0, so we cannot simply disable
-     * it in main().
-     */
-    if (g_test_quick()) {
-        return;
-    }
-
-    /* set DEC 12 hour mode */
-    cmos_write(RTC_REG_B, REG_B_DM);
-
-    /* Set time and alarm hour.  */
-    cmos_write(RTC_REG_A, 0x76);
-    cmos_write(RTC_HOURS_ALARM, 0x82);
-    cmos_write(RTC_HOURS, 3);
-    cmos_write(RTC_MINUTES, 0);
-    cmos_write(RTC_SECONDS, 0);
-    cmos_read(RTC_REG_C);
-    cmos_write(RTC_REG_A, 0x26);
-
-    /* Check that alarm triggers.  */
-    clock_step(3600 * 11 * 1000000000LL);
-    g_assert(cmos_read(RTC_HOURS) == 0x82);
-    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
-
-    /* Same as above, with inverted HOURS and HOURS_ALARM.  */
-    cmos_write(RTC_REG_A, 0x76);
-    cmos_write(RTC_HOURS_ALARM, 2);
-    cmos_write(RTC_HOURS, 3);
-    cmos_write(RTC_MINUTES, 0);
-    cmos_write(RTC_SECONDS, 0);
-    cmos_read(RTC_REG_C);
-    cmos_write(RTC_REG_A, 0x26);
-
-    /* Check that alarm does not trigger if hours differ only by AM/PM.  */
-    clock_step(3600 * 11 * 1000000000LL);
-    g_assert(cmos_read(RTC_HOURS) == 0x82);
-    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) == 0);
-}
-
-/* success if no crash or abort */
-static void fuzz_registers(void)
-{
-    unsigned int i;
-
-    for (i = 0; i < 1000; i++) {
-        uint8_t reg, val;
-
-        reg = (uint8_t)g_test_rand_int_range(0, 16);
-        val = (uint8_t)g_test_rand_int_range(0, 256);
-
-        cmos_write(reg, val);
-        cmos_read(reg);
-    }
-}
-
-static void register_b_set_flag(void)
-{
-    if (cmos_read(RTC_REG_A) & REG_A_UIP) {
-        clock_step(UIP_HOLD_LENGTH + NANOSECONDS_PER_SECOND / 5);
-    }
-    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
-
-    /* Enable binary-coded decimal (BCD) mode and SET flag in Register B*/
-    cmos_write(RTC_REG_B, REG_B_24H | REG_B_SET);
-
-    set_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
-
-    assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
-
-    /* Since SET flag is still enabled, time does not advance. */
-    clock_step(1000000000LL);
-    assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
-
-    /* Disable SET flag in Register B */
-    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_SET);
-
-    assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
-
-    /* Since SET flag is disabled, the clock now advances.  */
-    clock_step(1000000000LL);
-    assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011);
-}
-
-static void divider_reset(void)
-{
-    /* Enable binary-coded decimal (BCD) mode in Register B*/
-    cmos_write(RTC_REG_B, REG_B_24H);
-
-    /* Enter divider reset */
-    cmos_write(RTC_REG_A, 0x76);
-    set_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
-
-    assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
-
-    /* Since divider reset flag is still enabled, these are equality checks. */
-    clock_step(1000000000LL);
-    assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
-
-    /* The first update ends 500 ms after divider reset */
-    cmos_write(RTC_REG_A, 0x26);
-    clock_step(500000000LL - UIP_HOLD_LENGTH - 1);
-    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
-    assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
-
-    clock_step(1);
-    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, !=, 0);
-    clock_step(UIP_HOLD_LENGTH);
-    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
-
-    assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011);
-}
-
-static void uip_stuck(void)
-{
-    set_datetime(REG_B_24H, 0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
-
-    /* The first update ends 500 ms after divider reset */
-    (void)cmos_read(RTC_REG_C);
-    clock_step(500000000LL);
-    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
-    assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011);
-
-    /* UF is now set.  */
-    cmos_write(RTC_HOURS_ALARM, 0x02);
-    cmos_write(RTC_MINUTES_ALARM, 0xC0);
-    cmos_write(RTC_SECONDS_ALARM, 0xC0);
-
-    /* Because the alarm will fire soon, reading register A will latch UIP.  */
-    clock_step(1000000000LL - UIP_HOLD_LENGTH / 2);
-    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, !=, 0);
-
-    /* Move the alarm far away.  This must not cause UIP to remain stuck!  */
-    cmos_write(RTC_HOURS_ALARM, 0x03);
-    clock_step(UIP_HOLD_LENGTH);
-    g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
-}
-
-#define RTC_PERIOD_CODE1    13   /* 8 Hz */
-#define RTC_PERIOD_CODE2    15   /* 2 Hz */
-
-#define RTC_PERIOD_TEST_NR  50
-
-static uint64_t wait_periodic_interrupt(uint64_t real_time)
-{
-    while (!get_irq(RTC_ISA_IRQ)) {
-        real_time = clock_step_next();
-    }
-
-    g_assert((cmos_read(RTC_REG_C) & REG_C_PF) != 0);
-    return real_time;
-}
-
-static void periodic_timer(void)
-{
-    int i;
-    uint64_t period_clocks, period_time, start_time, real_time;
-
-    /* disable all interrupts. */
-    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) &
-                                   ~(REG_B_PIE | REG_B_AIE | REG_B_UIE));
-    cmos_write(RTC_REG_A, RTC_PERIOD_CODE1);
-    /* enable periodic interrupt after properly configure the period. */
-    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_PIE);
-
-    start_time = real_time = clock_step_next();
-
-    for (i = 0; i < RTC_PERIOD_TEST_NR; i++) {
-        cmos_write(RTC_REG_A, RTC_PERIOD_CODE1);
-        real_time = wait_periodic_interrupt(real_time);
-        cmos_write(RTC_REG_A, RTC_PERIOD_CODE2);
-        real_time = wait_periodic_interrupt(real_time);
-    }
-
-    period_clocks = periodic_period_to_clock(RTC_PERIOD_CODE1) +
-                       periodic_period_to_clock(RTC_PERIOD_CODE2);
-    period_clocks *= RTC_PERIOD_TEST_NR;
-    period_time = periodic_clock_to_ns(period_clocks);
-
-    real_time -= start_time;
-    g_assert_cmpint(ABS((int64_t)(real_time - period_time)), <=,
-                    NANOSECONDS_PER_SECOND * 0.5);
-}
-
-int main(int argc, char **argv)
-{
-    QTestState *s = NULL;
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-
-    s = qtest_start("-rtc clock=vm");
-    qtest_irq_intercept_in(s, "ioapic");
-
-    qtest_add_func("/rtc/check-time/bcd", bcd_check_time);
-    qtest_add_func("/rtc/check-time/dec", dec_check_time);
-    qtest_add_func("/rtc/alarm/interrupt", alarm_time);
-    qtest_add_func("/rtc/alarm/am-pm", am_pm_alarm);
-    qtest_add_func("/rtc/basic/dec-24h", basic_24h_dec);
-    qtest_add_func("/rtc/basic/bcd-24h", basic_24h_bcd);
-    qtest_add_func("/rtc/basic/dec-12h", basic_12h_dec);
-    qtest_add_func("/rtc/basic/bcd-12h", basic_12h_bcd);
-    qtest_add_func("/rtc/set-year/20xx", set_year_20xx);
-    qtest_add_func("/rtc/set-year/1980", set_year_1980);
-    qtest_add_func("/rtc/update/register_b_set_flag", register_b_set_flag);
-    qtest_add_func("/rtc/update/divider-reset", divider_reset);
-    qtest_add_func("/rtc/update/uip-stuck", uip_stuck);
-    qtest_add_func("/rtc/misc/fuzz-registers", fuzz_registers);
-    qtest_add_func("/rtc/periodic/interrupt", periodic_timer);
-
-    ret = g_test_run();
-
-    if (s) {
-        qtest_quit(s);
-    }
-
-    return ret;
-}
diff --git a/tests/rtl8139-test.c b/tests/rtl8139-test.c
deleted file mode 100644 (file)
index 4506049..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * QTest testcase for Realtek 8139 NIC
- *
- * Copyright (c) 2013-2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-#include "libqos/pci-pc.h"
-#include "qemu/timer.h"
-#include "qemu-common.h"
-
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void nop(void)
-{
-}
-
-#define CLK 33333333
-
-static QPCIBus *pcibus;
-static QPCIDevice *dev;
-static QPCIBar dev_bar;
-
-static void save_fn(QPCIDevice *dev, int devfn, void *data)
-{
-    QPCIDevice **pdev = (QPCIDevice **) data;
-
-    *pdev = dev;
-}
-
-static QPCIDevice *get_device(void)
-{
-    QPCIDevice *dev;
-
-    pcibus = qpci_new_pc(global_qtest, NULL);
-    qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev);
-    g_assert(dev != NULL);
-
-    return dev;
-}
-
-#define PORT(name, len, val) \
-static unsigned __attribute__((unused)) in_##name(void) \
-{ \
-    unsigned res = qpci_io_read##len(dev, dev_bar, (val));     \
-    g_test_message("*%s -> %x", #name, res); \
-    return res; \
-} \
-static void out_##name(unsigned v) \
-{ \
-    g_test_message("%x -> *%s", v, #name); \
-    qpci_io_write##len(dev, dev_bar, (val), v);        \
-}
-
-PORT(Timer, l, 0x48)
-PORT(IntrMask, w, 0x3c)
-PORT(IntrStatus, w, 0x3E)
-PORT(TimerInt, l, 0x54)
-
-#define fatal(...) do { g_test_message(__VA_ARGS__); g_assert(0); } while (0)
-
-static void test_timer(void)
-{
-    const unsigned from = 0.95 * CLK;
-    const unsigned to = 1.6 * CLK;
-    unsigned prev, curr, next;
-    unsigned cnt, diff;
-
-    out_IntrMask(0);
-
-    in_IntrStatus();
-    in_Timer();
-    in_Timer();
-
-    /* Test 1. test counter continue and continue */
-    out_TimerInt(0); /* disable timer */
-    out_IntrStatus(0x4000);
-    out_Timer(12345); /* reset timer to 0 */
-    curr = in_Timer();
-    if (curr > 0.1 * CLK) {
-        fatal("time too big %u\n", curr);
-    }
-    for (cnt = 0; ; ) {
-        clock_step(1 * NANOSECONDS_PER_SECOND);
-        prev = curr;
-        curr = in_Timer();
-
-        /* test skip is in a specific range */
-        diff = (curr-prev) & 0xffffffffu;
-        if (diff < from || diff > to) {
-            fatal("Invalid diff %u (%u-%u)\n", diff, from, to);
-        }
-        if (curr < prev && ++cnt == 3) {
-            break;
-        }
-    }
-
-    /* Test 2. Check we didn't get an interrupt with TimerInt == 0 */
-    if (in_IntrStatus() & 0x4000) {
-        fatal("got an interrupt\n");
-    }
-
-    /* Test 3. Setting TimerInt to 1 and Timer to 0 get interrupt */
-    out_TimerInt(1);
-    out_Timer(0);
-    clock_step(40);
-    if ((in_IntrStatus() & 0x4000) == 0) {
-        fatal("we should have an interrupt here!\n");
-    }
-
-    /* Test 3. Check acknowledge */
-    out_IntrStatus(0x4000);
-    if (in_IntrStatus() & 0x4000) {
-        fatal("got an interrupt\n");
-    }
-
-    /* Test. Status set after Timer reset */
-    out_Timer(0);
-    out_TimerInt(0);
-    out_IntrStatus(0x4000);
-    curr = in_Timer();
-    out_TimerInt(curr + 0.5 * CLK);
-    clock_step(1 * NANOSECONDS_PER_SECOND);
-    out_Timer(0);
-    if ((in_IntrStatus() & 0x4000) == 0) {
-        fatal("we should have an interrupt here!\n");
-    }
-
-    /* Test. Status set after TimerInt reset */
-    out_Timer(0);
-    out_TimerInt(0);
-    out_IntrStatus(0x4000);
-    curr = in_Timer();
-    out_TimerInt(curr + 0.5 * CLK);
-    clock_step(1 * NANOSECONDS_PER_SECOND);
-    out_TimerInt(0);
-    if ((in_IntrStatus() & 0x4000) == 0) {
-        fatal("we should have an interrupt here!\n");
-    }
-
-    /* Test 4. Increment TimerInt we should see an interrupt */
-    curr = in_Timer();
-    next = curr + 5.0 * CLK;
-    out_TimerInt(next);
-    for (cnt = 0; ; ) {
-        clock_step(1 * NANOSECONDS_PER_SECOND);
-        prev = curr;
-        curr = in_Timer();
-        diff = (curr-prev) & 0xffffffffu;
-        if (diff < from || diff > to) {
-            fatal("Invalid diff %u (%u-%u)\n", diff, from, to);
-        }
-        if (cnt < 3 && curr > next) {
-            if ((in_IntrStatus() & 0x4000) == 0) {
-                fatal("we should have an interrupt here!\n");
-            }
-            out_IntrStatus(0x4000);
-            next = curr + 5.0 * CLK;
-            out_TimerInt(next);
-            if (++cnt == 3) {
-                out_TimerInt(1);
-            }
-        /* Test 5. Second time we pass from 0 should see an interrupt */
-        } else if (cnt >= 3 && curr < prev) {
-            /* here we should have an interrupt */
-            if ((in_IntrStatus() & 0x4000) == 0) {
-                fatal("we should have an interrupt here!\n");
-            }
-            out_IntrStatus(0x4000);
-            if (++cnt == 5) {
-                break;
-            }
-        }
-    }
-
-    g_test_message("Everythink is ok!");
-}
-
-
-static void test_init(void)
-{
-    uint64_t barsize;
-
-    dev = get_device();
-
-    dev_bar = qpci_iomap(dev, 0, &barsize);
-
-    qpci_device_enable(dev);
-
-    test_timer();
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-
-    qtest_start("-device rtl8139");
-
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/rtl8139/nop", nop);
-    qtest_add_func("/rtl8139/timer", test_init);
-
-    ret = g_test_run();
-
-    qtest_end();
-
-    return ret;
-}
diff --git a/tests/sdhci-test.c b/tests/sdhci-test.c
deleted file mode 100644 (file)
index 6275e76..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * QTest testcase for SDHCI controllers
- *
- * Written by Philippe Mathieu-Daudé <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include "qemu/osdep.h"
-#include "hw/registerfields.h"
-#include "libqtest.h"
-#include "qemu/module.h"
-#include "libqos/pci-pc.h"
-#include "hw/pci/pci.h"
-#include "libqos/qgraph.h"
-#include "libqos/sdhci.h"
-
-#define SDHC_CAPAB                      0x40
-FIELD(SDHC_CAPAB, BASECLKFREQ,               8, 8); /* since v2 */
-FIELD(SDHC_CAPAB, SDMA,                     22, 1);
-FIELD(SDHC_CAPAB, SDR,                      32, 3); /* since v3 */
-FIELD(SDHC_CAPAB, DRIVER,                   36, 3); /* since v3 */
-#define SDHC_HCVER                      0xFE
-
-static void check_specs_version(QSDHCI *s, uint8_t version)
-{
-    uint32_t v;
-
-    v = s->readw(s, SDHC_HCVER);
-    v &= 0xff;
-    v += 1;
-    g_assert_cmpuint(v, ==, version);
-}
-
-static void check_capab_capareg(QSDHCI *s, uint64_t expec_capab)
-{
-    uint64_t capab;
-
-    capab = s->readq(s, SDHC_CAPAB);
-    g_assert_cmphex(capab, ==, expec_capab);
-}
-
-static void check_capab_readonly(QSDHCI *s)
-{
-    const uint64_t vrand = 0x123456789abcdef;
-    uint64_t capab0, capab1;
-
-    capab0 = s->readq(s, SDHC_CAPAB);
-    g_assert_cmpuint(capab0, !=, vrand);
-
-    s->writeq(s, SDHC_CAPAB, vrand);
-    capab1 = s->readq(s, SDHC_CAPAB);
-    g_assert_cmpuint(capab1, !=, vrand);
-    g_assert_cmpuint(capab1, ==, capab0);
-}
-
-static void check_capab_baseclock(QSDHCI *s, uint8_t expec_freq)
-{
-    uint64_t capab, capab_freq;
-
-    if (!expec_freq) {
-        return;
-    }
-    capab = s->readq(s, SDHC_CAPAB);
-    capab_freq = FIELD_EX64(capab, SDHC_CAPAB, BASECLKFREQ);
-    g_assert_cmpuint(capab_freq, ==, expec_freq);
-}
-
-static void check_capab_sdma(QSDHCI *s, bool supported)
-{
-    uint64_t capab, capab_sdma;
-
-    capab = s->readq(s, SDHC_CAPAB);
-    capab_sdma = FIELD_EX64(capab, SDHC_CAPAB, SDMA);
-    g_assert_cmpuint(capab_sdma, ==, supported);
-}
-
-static void check_capab_v3(QSDHCI *s, uint8_t version)
-{
-    uint64_t capab, capab_v3;
-
-    if (version < 3) {
-        /* before v3 those fields are RESERVED */
-        capab = s->readq(s, SDHC_CAPAB);
-        capab_v3 = FIELD_EX64(capab, SDHC_CAPAB, SDR);
-        g_assert_cmpuint(capab_v3, ==, 0);
-        capab_v3 = FIELD_EX64(capab, SDHC_CAPAB, DRIVER);
-        g_assert_cmpuint(capab_v3, ==, 0);
-    }
-}
-
-static void test_registers(void *obj, void *data, QGuestAllocator *alloc)
-{
-    QSDHCI *s = obj;
-
-    check_specs_version(s, s->props.version);
-    check_capab_capareg(s, s->props.capab.reg);
-    check_capab_readonly(s);
-    check_capab_v3(s, s->props.version);
-    check_capab_sdma(s, s->props.capab.sdma);
-    check_capab_baseclock(s, s->props.baseclock);
-}
-
-static void register_sdhci_test(void)
-{
-    qos_add_test("registers", "sdhci", test_registers, NULL);
-}
-
-libqos_init(register_sdhci_test);
diff --git a/tests/spapr-phb-test.c b/tests/spapr-phb-test.c
deleted file mode 100644 (file)
index 093dc22..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * QTest testcase for SPAPR PHB
- *
- * Authors:
- *  Alexey Kardashevskiy <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qemu/module.h"
-#include "libqos/qgraph.h"
-
-/* Tests only initialization so far. TODO: Replace with functional tests,
- * for example by producing pci-bus.
- */
-static void test_phb_device(void *obj, void *data, QGuestAllocator *alloc)
-{
-}
-
-static void register_phb_test(void)
-{
-    qos_add_test("spapr-phb-test", "ppc64/pseries",
-                 test_phb_device, &(QOSGraphTestOptions) {
-                     .edge.before_cmd_line = "-device spapr-pci-host-bridge"
-                                             ",index=30",
-                 });
-}
-
-libqos_init(register_phb_test);
diff --git a/tests/tco-test.c b/tests/tco-test.c
deleted file mode 100644 (file)
index 254f735..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * QEMU ICH9 TCO emulation tests
- *
- * Copyright (c) 2015 Paulo Alcantara <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-
-#include "libqtest.h"
-#include "libqos/pci.h"
-#include "libqos/pci-pc.h"
-#include "qapi/qmp/qdict.h"
-#include "hw/pci/pci_regs.h"
-#include "hw/i386/ich9.h"
-#include "hw/acpi/ich9.h"
-#include "hw/acpi/tco.h"
-
-#define RCBA_BASE_ADDR    0xfed1c000
-#define PM_IO_BASE_ADDR   0xb000
-
-enum {
-    TCO_RLD_DEFAULT         = 0x0000,
-    TCO_DAT_IN_DEFAULT      = 0x00,
-    TCO_DAT_OUT_DEFAULT     = 0x00,
-    TCO1_STS_DEFAULT        = 0x0000,
-    TCO2_STS_DEFAULT        = 0x0000,
-    TCO1_CNT_DEFAULT        = 0x0000,
-    TCO2_CNT_DEFAULT        = 0x0008,
-    TCO_MESSAGE1_DEFAULT    = 0x00,
-    TCO_MESSAGE2_DEFAULT    = 0x00,
-    TCO_WDCNT_DEFAULT       = 0x00,
-    TCO_TMR_DEFAULT         = 0x0004,
-    SW_IRQ_GEN_DEFAULT      = 0x03,
-};
-
-#define TCO_SECS_TO_TICKS(secs)     (((secs) * 10) / 6)
-#define TCO_TICKS_TO_SECS(ticks)    (((ticks) * 6) / 10)
-
-typedef struct {
-    const char *args;
-    bool noreboot;
-    QPCIDevice *dev;
-    QPCIBar tco_io_bar;
-    QPCIBus *bus;
-    QTestState *qts;
-} TestData;
-
-static void test_end(TestData *d)
-{
-    g_free(d->dev);
-    qpci_free_pc(d->bus);
-    qtest_quit(d->qts);
-}
-
-static void test_init(TestData *d)
-{
-    QTestState *qs;
-
-    qs = qtest_initf("-machine q35 %s %s",
-                     d->noreboot ? "" : "-global ICH9-LPC.noreboot=false",
-                     !d->args ? "" : d->args);
-    qtest_irq_intercept_in(qs, "ioapic");
-
-    d->bus = qpci_new_pc(qs, NULL);
-    d->dev = qpci_device_find(d->bus, QPCI_DEVFN(0x1f, 0x00));
-    g_assert(d->dev != NULL);
-
-    qpci_device_enable(d->dev);
-
-    /* set ACPI PM I/O space base address */
-    qpci_config_writel(d->dev, ICH9_LPC_PMBASE, PM_IO_BASE_ADDR | 0x1);
-    /* enable ACPI I/O */
-    qpci_config_writeb(d->dev, ICH9_LPC_ACPI_CTRL, 0x80);
-    /* set Root Complex BAR */
-    qpci_config_writel(d->dev, ICH9_LPC_RCBA, RCBA_BASE_ADDR | 0x1);
-
-    d->tco_io_bar = qpci_legacy_iomap(d->dev, PM_IO_BASE_ADDR + 0x60);
-    d->qts = qs;
-}
-
-static void stop_tco(const TestData *d)
-{
-    uint32_t val;
-
-    val = qpci_io_readw(d->dev, d->tco_io_bar, TCO1_CNT);
-    val |= TCO_TMR_HLT;
-    qpci_io_writew(d->dev, d->tco_io_bar, TCO1_CNT, val);
-}
-
-static void start_tco(const TestData *d)
-{
-    uint32_t val;
-
-    val = qpci_io_readw(d->dev, d->tco_io_bar, TCO1_CNT);
-    val &= ~TCO_TMR_HLT;
-    qpci_io_writew(d->dev, d->tco_io_bar, TCO1_CNT, val);
-}
-
-static void load_tco(const TestData *d)
-{
-    qpci_io_writew(d->dev, d->tco_io_bar, TCO_RLD, 4);
-}
-
-static void set_tco_timeout(const TestData *d, uint16_t ticks)
-{
-    qpci_io_writew(d->dev, d->tco_io_bar, TCO_TMR, ticks);
-}
-
-static void clear_tco_status(const TestData *d)
-{
-    qpci_io_writew(d->dev, d->tco_io_bar, TCO1_STS, 0x0008);
-    qpci_io_writew(d->dev, d->tco_io_bar, TCO2_STS, 0x0002);
-    qpci_io_writew(d->dev, d->tco_io_bar, TCO2_STS, 0x0004);
-}
-
-static void reset_on_second_timeout(const TestData *td, bool enable)
-{
-    uint32_t val;
-
-    val = qtest_readl(td->qts, RCBA_BASE_ADDR + ICH9_CC_GCS);
-    if (enable) {
-        val &= ~ICH9_CC_GCS_NO_REBOOT;
-    } else {
-        val |= ICH9_CC_GCS_NO_REBOOT;
-    }
-    qtest_writel(td->qts, RCBA_BASE_ADDR + ICH9_CC_GCS, val);
-}
-
-static void test_tco_defaults(void)
-{
-    TestData d;
-
-    d.args = NULL;
-    d.noreboot = true;
-    test_init(&d);
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD), ==,
-                    TCO_RLD_DEFAULT);
-    /* TCO_DAT_IN & TCO_DAT_OUT */
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_DAT_IN), ==,
-                    (TCO_DAT_OUT_DEFAULT << 8) | TCO_DAT_IN_DEFAULT);
-    /* TCO1_STS & TCO2_STS */
-    g_assert_cmpint(qpci_io_readl(d.dev, d.tco_io_bar, TCO1_STS), ==,
-                    (TCO2_STS_DEFAULT << 16) | TCO1_STS_DEFAULT);
-    /* TCO1_CNT & TCO2_CNT */
-    g_assert_cmpint(qpci_io_readl(d.dev, d.tco_io_bar, TCO1_CNT), ==,
-                    (TCO2_CNT_DEFAULT << 16) | TCO1_CNT_DEFAULT);
-    /* TCO_MESSAGE1 & TCO_MESSAGE2 */
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_MESSAGE1), ==,
-                    (TCO_MESSAGE2_DEFAULT << 8) | TCO_MESSAGE1_DEFAULT);
-    g_assert_cmpint(qpci_io_readb(d.dev, d.tco_io_bar, TCO_WDCNT), ==,
-                    TCO_WDCNT_DEFAULT);
-    g_assert_cmpint(qpci_io_readb(d.dev, d.tco_io_bar, SW_IRQ_GEN), ==,
-                    SW_IRQ_GEN_DEFAULT);
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_TMR), ==,
-                    TCO_TMR_DEFAULT);
-    test_end(&d);
-}
-
-static void test_tco_timeout(void)
-{
-    TestData d;
-    const uint16_t ticks = TCO_SECS_TO_TICKS(4);
-    uint32_t val;
-    int ret;
-
-    d.args = NULL;
-    d.noreboot = true;
-    test_init(&d);
-
-    stop_tco(&d);
-    clear_tco_status(&d);
-    reset_on_second_timeout(&d, false);
-    set_tco_timeout(&d, ticks);
-    load_tco(&d);
-    start_tco(&d);
-    qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC);
-
-    /* test first timeout */
-    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
-    ret = val & TCO_TIMEOUT ? 1 : 0;
-    g_assert(ret == 1);
-
-    /* test clearing timeout bit */
-    val |= TCO_TIMEOUT;
-    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_STS, val);
-    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
-    ret = val & TCO_TIMEOUT ? 1 : 0;
-    g_assert(ret == 0);
-
-    /* test second timeout */
-    qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC);
-    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
-    ret = val & TCO_TIMEOUT ? 1 : 0;
-    g_assert(ret == 1);
-    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO2_STS);
-    ret = val & TCO_SECOND_TO_STS ? 1 : 0;
-    g_assert(ret == 1);
-
-    stop_tco(&d);
-    test_end(&d);
-}
-
-static void test_tco_max_timeout(void)
-{
-    TestData d;
-    const uint16_t ticks = 0xffff;
-    uint32_t val;
-    int ret;
-
-    d.args = NULL;
-    d.noreboot = true;
-    test_init(&d);
-
-    stop_tco(&d);
-    clear_tco_status(&d);
-    reset_on_second_timeout(&d, false);
-    set_tco_timeout(&d, ticks);
-    load_tco(&d);
-    start_tco(&d);
-    qtest_clock_step(d.qts, ((ticks & TCO_TMR_MASK) - 1) * TCO_TICK_NSEC);
-
-    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD);
-    g_assert_cmpint(val & TCO_RLD_MASK, ==, 1);
-    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
-    ret = val & TCO_TIMEOUT ? 1 : 0;
-    g_assert(ret == 0);
-    qtest_clock_step(d.qts, TCO_TICK_NSEC);
-    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
-    ret = val & TCO_TIMEOUT ? 1 : 0;
-    g_assert(ret == 1);
-
-    stop_tco(&d);
-    test_end(&d);
-}
-
-static QDict *get_watchdog_action(const TestData *td)
-{
-    QDict *ev = qtest_qmp_eventwait_ref(td->qts, "WATCHDOG");
-    QDict *data;
-
-    data = qdict_get_qdict(ev, "data");
-    qobject_ref(data);
-    qobject_unref(ev);
-    return data;
-}
-
-static void test_tco_second_timeout_pause(void)
-{
-    TestData td;
-    const uint16_t ticks = TCO_SECS_TO_TICKS(32);
-    QDict *ad;
-
-    td.args = "-watchdog-action pause";
-    td.noreboot = false;
-    test_init(&td);
-
-    stop_tco(&td);
-    clear_tco_status(&td);
-    reset_on_second_timeout(&td, true);
-    set_tco_timeout(&td, TCO_SECS_TO_TICKS(16));
-    load_tco(&td);
-    start_tco(&td);
-    qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
-    ad = get_watchdog_action(&td);
-    g_assert(!strcmp(qdict_get_str(ad, "action"), "pause"));
-    qobject_unref(ad);
-
-    stop_tco(&td);
-    test_end(&td);
-}
-
-static void test_tco_second_timeout_reset(void)
-{
-    TestData td;
-    const uint16_t ticks = TCO_SECS_TO_TICKS(16);
-    QDict *ad;
-
-    td.args = "-watchdog-action reset";
-    td.noreboot = false;
-    test_init(&td);
-
-    stop_tco(&td);
-    clear_tco_status(&td);
-    reset_on_second_timeout(&td, true);
-    set_tco_timeout(&td, TCO_SECS_TO_TICKS(16));
-    load_tco(&td);
-    start_tco(&td);
-    qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
-    ad = get_watchdog_action(&td);
-    g_assert(!strcmp(qdict_get_str(ad, "action"), "reset"));
-    qobject_unref(ad);
-
-    stop_tco(&td);
-    test_end(&td);
-}
-
-static void test_tco_second_timeout_shutdown(void)
-{
-    TestData td;
-    const uint16_t ticks = TCO_SECS_TO_TICKS(128);
-    QDict *ad;
-
-    td.args = "-watchdog-action shutdown";
-    td.noreboot = false;
-    test_init(&td);
-
-    stop_tco(&td);
-    clear_tco_status(&td);
-    reset_on_second_timeout(&td, true);
-    set_tco_timeout(&td, ticks);
-    load_tco(&td);
-    start_tco(&td);
-    qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
-    ad = get_watchdog_action(&td);
-    g_assert(!strcmp(qdict_get_str(ad, "action"), "shutdown"));
-    qobject_unref(ad);
-
-    stop_tco(&td);
-    test_end(&td);
-}
-
-static void test_tco_second_timeout_none(void)
-{
-    TestData td;
-    const uint16_t ticks = TCO_SECS_TO_TICKS(256);
-    QDict *ad;
-
-    td.args = "-watchdog-action none";
-    td.noreboot = false;
-    test_init(&td);
-
-    stop_tco(&td);
-    clear_tco_status(&td);
-    reset_on_second_timeout(&td, true);
-    set_tco_timeout(&td, ticks);
-    load_tco(&td);
-    start_tco(&td);
-    qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
-    ad = get_watchdog_action(&td);
-    g_assert(!strcmp(qdict_get_str(ad, "action"), "none"));
-    qobject_unref(ad);
-
-    stop_tco(&td);
-    test_end(&td);
-}
-
-static void test_tco_ticks_counter(void)
-{
-    TestData d;
-    uint16_t ticks = TCO_SECS_TO_TICKS(8);
-    uint16_t rld;
-
-    d.args = NULL;
-    d.noreboot = true;
-    test_init(&d);
-
-    stop_tco(&d);
-    clear_tco_status(&d);
-    reset_on_second_timeout(&d, false);
-    set_tco_timeout(&d, ticks);
-    load_tco(&d);
-    start_tco(&d);
-
-    do {
-        rld = qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD) & TCO_RLD_MASK;
-        g_assert_cmpint(rld, ==, ticks);
-        qtest_clock_step(d.qts, TCO_TICK_NSEC);
-        ticks--;
-    } while (!(qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS) & TCO_TIMEOUT));
-
-    stop_tco(&d);
-    test_end(&d);
-}
-
-static void test_tco1_control_bits(void)
-{
-    TestData d;
-    uint16_t val;
-
-    d.args = NULL;
-    d.noreboot = true;
-    test_init(&d);
-
-    val = TCO_LOCK;
-    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_CNT, val);
-    val &= ~TCO_LOCK;
-    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_CNT, val);
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO1_CNT), ==,
-                    TCO_LOCK);
-    test_end(&d);
-}
-
-static void test_tco1_status_bits(void)
-{
-    TestData d;
-    uint16_t ticks = 8;
-    uint16_t val;
-    int ret;
-
-    d.args = NULL;
-    d.noreboot = true;
-    test_init(&d);
-
-    stop_tco(&d);
-    clear_tco_status(&d);
-    reset_on_second_timeout(&d, false);
-    set_tco_timeout(&d, ticks);
-    load_tco(&d);
-    start_tco(&d);
-    qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC);
-
-    qpci_io_writeb(d.dev, d.tco_io_bar, TCO_DAT_IN, 0);
-    qpci_io_writeb(d.dev, d.tco_io_bar, TCO_DAT_OUT, 0);
-    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
-    ret = val & (TCO_TIMEOUT | SW_TCO_SMI | TCO_INT_STS) ? 1 : 0;
-    g_assert(ret == 1);
-    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_STS, val);
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS), ==, 0);
-    test_end(&d);
-}
-
-static void test_tco2_status_bits(void)
-{
-    TestData d;
-    uint16_t ticks = 8;
-    uint16_t val;
-    int ret;
-
-    d.args = NULL;
-    d.noreboot = true;
-    test_init(&d);
-
-    stop_tco(&d);
-    clear_tco_status(&d);
-    reset_on_second_timeout(&d, true);
-    set_tco_timeout(&d, ticks);
-    load_tco(&d);
-    start_tco(&d);
-    qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC * 2);
-
-    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO2_STS);
-    ret = val & (TCO_SECOND_TO_STS | TCO_BOOT_STS) ? 1 : 0;
-    g_assert(ret == 1);
-    qpci_io_writew(d.dev, d.tco_io_bar, TCO2_STS, val);
-    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO2_STS), ==, 0);
-    test_end(&d);
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("tco/defaults", test_tco_defaults);
-    qtest_add_func("tco/timeout/no_action", test_tco_timeout);
-    qtest_add_func("tco/timeout/no_action/max", test_tco_max_timeout);
-    qtest_add_func("tco/second_timeout/pause", test_tco_second_timeout_pause);
-    qtest_add_func("tco/second_timeout/reset", test_tco_second_timeout_reset);
-    qtest_add_func("tco/second_timeout/shutdown",
-                   test_tco_second_timeout_shutdown);
-    qtest_add_func("tco/second_timeout/none", test_tco_second_timeout_none);
-    qtest_add_func("tco/counter", test_tco_ticks_counter);
-    qtest_add_func("tco/tco1_control/bits", test_tco1_control_bits);
-    qtest_add_func("tco/tco1_status/bits", test_tco1_status_bits);
-    qtest_add_func("tco/tco2_status/bits", test_tco2_status_bits);
-    return g_test_run();
-}
diff --git a/tests/test-arm-mptimer.c b/tests/test-arm-mptimer.c
deleted file mode 100644 (file)
index 7a56d56..0000000
+++ /dev/null
@@ -1,1090 +0,0 @@
-/*
- * QTest testcase for the ARM MPTimer
- *
- * Copyright (c) 2016 Dmitry Osipenko <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/timer.h"
-#include "libqtest-single.h"
-
-#define TIMER_BLOCK_SCALE(s)    ((((s) & 0xff) + 1) * 10)
-
-#define TIMER_BLOCK_STEP(scaler, steps_nb) \
-    clock_step(TIMER_BLOCK_SCALE(scaler) * (int64_t)(steps_nb) + 1)
-
-#define TIMER_BASE_PHYS 0x1e000600
-
-#define TIMER_LOAD      0x00
-#define TIMER_COUNTER   0x04
-#define TIMER_CONTROL   0x08
-#define TIMER_INTSTAT   0x0C
-
-#define TIMER_CONTROL_ENABLE        (1 << 0)
-#define TIMER_CONTROL_PERIODIC      (1 << 1)
-#define TIMER_CONTROL_IT_ENABLE     (1 << 2)
-#define TIMER_CONTROL_PRESCALER(p)  (((p) & 0xff) << 8)
-
-#define PERIODIC     1
-#define ONESHOT      0
-#define NOSCALE      0
-
-static int nonscaled = NOSCALE;
-static int scaled = 122;
-
-static void timer_load(uint32_t load)
-{
-    writel(TIMER_BASE_PHYS + TIMER_LOAD, load);
-}
-
-static void timer_start(int periodic, uint32_t scale)
-{
-    uint32_t ctl = TIMER_CONTROL_ENABLE | TIMER_CONTROL_PRESCALER(scale);
-
-    if (periodic) {
-        ctl |= TIMER_CONTROL_PERIODIC;
-    }
-
-    writel(TIMER_BASE_PHYS + TIMER_CONTROL, ctl);
-}
-
-static void timer_stop(void)
-{
-    writel(TIMER_BASE_PHYS + TIMER_CONTROL, 0);
-}
-
-static void timer_int_clr(void)
-{
-    writel(TIMER_BASE_PHYS + TIMER_INTSTAT, 1);
-}
-
-static void timer_reset(void)
-{
-    timer_stop();
-    timer_load(0);
-    timer_int_clr();
-}
-
-static uint32_t timer_get_and_clr_int_sts(void)
-{
-    uint32_t int_sts = readl(TIMER_BASE_PHYS + TIMER_INTSTAT);
-
-    if (int_sts) {
-        timer_int_clr();
-    }
-
-    return int_sts;
-}
-
-static uint32_t timer_counter(void)
-{
-    return readl(TIMER_BASE_PHYS + TIMER_COUNTER);
-}
-
-static void timer_set_counter(uint32_t value)
-{
-    writel(TIMER_BASE_PHYS + TIMER_COUNTER, value);
-}
-
-static void test_timer_oneshot(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_load(9999999);
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 9999);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-    g_assert_cmpuint(timer_counter(), ==, 9990000);
-
-    TIMER_BLOCK_STEP(scaler, 9990000);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-
-    TIMER_BLOCK_STEP(scaler, 9990000);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_pause(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_load(999999999);
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 999);
-
-    g_assert_cmpuint(timer_counter(), ==, 999999000);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(scaler, 9000);
-
-    g_assert_cmpuint(timer_counter(), ==, 999990000);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_stop();
-
-    g_assert_cmpuint(timer_counter(), ==, 999990000);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(scaler, 90000);
-
-    g_assert_cmpuint(timer_counter(), ==, 999990000);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 999990000);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-    g_assert_cmpuint(timer_counter(), ==, 0);
-
-    TIMER_BLOCK_STEP(scaler, 999990000);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-    g_assert_cmpuint(timer_counter(), ==, 0);
-}
-
-static void test_timer_reload(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_load(UINT32_MAX);
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 90000);
-
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 90000);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_load(UINT32_MAX);
-
-    TIMER_BLOCK_STEP(scaler, 90000);
-
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 90000);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_periodic(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-    int repeat = 10;
-
-    timer_reset();
-    timer_load(100);
-    timer_start(PERIODIC, scaler);
-
-    while (repeat--) {
-        clock_step(TIMER_BLOCK_SCALE(scaler) * (101 + repeat) + 1);
-
-        g_assert_cmpuint(timer_counter(), ==, 100 - repeat);
-        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-
-        clock_step(TIMER_BLOCK_SCALE(scaler) * (101 - repeat) - 1);
-    }
-}
-
-static void test_timer_oneshot_to_periodic(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_load(10000);
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1000);
-
-    g_assert_cmpuint(timer_counter(), ==, 9000);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 14001);
-
-    g_assert_cmpuint(timer_counter(), ==, 5000);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-}
-
-static void test_timer_periodic_to_oneshot(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_load(99999999);
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 999);
-
-    g_assert_cmpuint(timer_counter(), ==, 99999000);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 99999009);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-}
-
-static void test_timer_prescaler(void)
-{
-    timer_reset();
-    timer_load(9999999);
-    timer_start(ONESHOT, NOSCALE);
-
-    TIMER_BLOCK_STEP(NOSCALE, 9999998);
-
-    g_assert_cmpuint(timer_counter(), ==, 1);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(NOSCALE, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-
-    timer_reset();
-    timer_load(9999999);
-    timer_start(ONESHOT, 0xAB);
-
-    TIMER_BLOCK_STEP(0xAB, 9999998);
-
-    g_assert_cmpuint(timer_counter(), ==, 1);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(0xAB, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-}
-
-static void test_timer_prescaler_on_the_fly(void)
-{
-    timer_reset();
-    timer_load(9999999);
-    timer_start(ONESHOT, NOSCALE);
-
-    TIMER_BLOCK_STEP(NOSCALE, 999);
-
-    g_assert_cmpuint(timer_counter(), ==, 9999000);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_start(ONESHOT, 0xAB);
-
-    TIMER_BLOCK_STEP(0xAB, 9000);
-
-    g_assert_cmpuint(timer_counter(), ==, 9990000);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_set_oneshot_counter_to_0(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_load(UINT32_MAX);
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 1);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_set_counter(0);
-
-    TIMER_BLOCK_STEP(scaler, 10);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-}
-
-static void test_timer_set_periodic_counter_to_0(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_load(UINT32_MAX);
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 1);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_set_counter(0);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - (scaler ? 0 : 1));
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    timer_reset();
-    timer_set_counter(UINT32_MAX);
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 1);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_set_counter(0);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-}
-
-static void test_timer_noload_oneshot(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_noload_periodic(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-}
-
-static void test_timer_zero_load_oneshot(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-    g_assert_cmpuint(timer_counter(), ==, 0);
-
-    timer_load(0);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_zero_load_periodic(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-    g_assert_cmpuint(timer_counter(), ==, 0);
-
-    timer_load(0);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-}
-
-static void test_timer_zero_load_oneshot_to_nonzero(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    timer_load(0);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-    g_assert_cmpuint(timer_counter(), ==, 0);
-
-    timer_load(999);
-
-    TIMER_BLOCK_STEP(scaler, 1001);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-}
-
-static void test_timer_zero_load_periodic_to_nonzero(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-    int i;
-
-    timer_reset();
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-    g_assert_cmpuint(timer_counter(), ==, 0);
-
-    timer_load(0);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    timer_load(1999999);
-
-    for (i = 1; i < 10; i++) {
-        TIMER_BLOCK_STEP(scaler, 2000001);
-
-        g_assert_cmpuint(timer_counter(), ==, 1999999 - i);
-        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-    }
-}
-
-static void test_timer_nonzero_load_oneshot_to_zero(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-    g_assert_cmpuint(timer_counter(), ==, 0);
-
-    timer_load(UINT32_MAX);
-    timer_load(0);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-}
-
-static void test_timer_nonzero_load_periodic_to_zero(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    timer_load(UINT32_MAX);
-    timer_load(0);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-}
-
-static void test_timer_set_periodic_counter_on_the_fly(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_load(UINT32_MAX / 2);
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX / 2 - 100);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_set_counter(UINT32_MAX);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_enable_and_set_counter(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    timer_set_counter(UINT32_MAX);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_set_counter_and_enable(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_set_counter(UINT32_MAX);
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_set_counter_disabled(void)
-{
-    timer_reset();
-    timer_set_counter(999999999);
-
-    TIMER_BLOCK_STEP(NOSCALE, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, 999999999);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_load_disabled(void)
-{
-    timer_reset();
-    timer_load(999999999);
-
-    TIMER_BLOCK_STEP(NOSCALE, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, 999999999);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_oneshot_with_counter_0_on_start(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_load(999);
-    timer_set_counter(0);
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_periodic_with_counter_0_on_start(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-    int i;
-
-    timer_reset();
-    timer_load(UINT32_MAX);
-    timer_set_counter(0);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-    g_assert_cmpuint(timer_counter(), ==, 0);
-
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX + (scaler ? 1 : 0) - 100);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX + (scaler ? 1 : 0) - 200);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_reset();
-    timer_load(1999999);
-    timer_set_counter(0);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    for (i = 2 - (!!scaler ? 1 : 0); i < 10; i++) {
-        TIMER_BLOCK_STEP(scaler, 2000001);
-
-        g_assert_cmpuint(timer_counter(), ==, 1999999 - i);
-        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-    }
-}
-
-static void test_periodic_counter(gconstpointer arg)
-{
-    const int test_load = 10;
-    int scaler = *((int *) arg);
-    int test_val;
-
-    timer_reset();
-    timer_load(test_load);
-    timer_start(PERIODIC, scaler);
-
-    clock_step(1);
-
-    for (test_val = 0; test_val <= test_load; test_val++) {
-        clock_step(TIMER_BLOCK_SCALE(scaler) * test_load);
-        g_assert_cmpint(timer_counter(), ==, test_val);
-    }
-}
-
-static void test_timer_set_counter_periodic_with_zero_load(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_start(PERIODIC, scaler);
-    timer_load(0);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    timer_set_counter(999);
-
-    TIMER_BLOCK_STEP(scaler, 999);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-}
-
-static void test_timer_set_oneshot_load_to_0(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_load(UINT32_MAX);
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_load(0);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_set_periodic_load_to_0(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_load(UINT32_MAX);
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_load(0);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    TIMER_BLOCK_STEP(scaler, 100);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-    g_assert_cmpuint(timer_counter(), ==, 0);
-}
-
-static void test_deferred_trigger(void)
-{
-    int mode = ONESHOT;
-
-again:
-    timer_reset();
-    timer_start(mode, 255);
-
-    clock_step(100);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-
-    TIMER_BLOCK_STEP(255, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-
-    timer_reset();
-    timer_load(2);
-    timer_start(mode, 255);
-
-    clock_step(100);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(255, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(255, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-
-    timer_reset();
-    timer_load(UINT32_MAX);
-    timer_start(mode, 255);
-
-    clock_step(100);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_set_counter(0);
-
-    clock_step(100);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(255, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-
-    timer_reset();
-    timer_load(UINT32_MAX);
-    timer_start(mode, 255);
-
-    clock_step(100);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_load(0);
-
-    clock_step(100);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(255, 1);
-
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-
-    if (mode == ONESHOT) {
-        mode = PERIODIC;
-        goto again;
-    }
-}
-
-static void test_timer_zero_load_mode_switch(gconstpointer arg)
-{
-    int scaler = *((int *) arg);
-
-    timer_reset();
-    timer_load(0);
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    timer_start(ONESHOT, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    timer_start(PERIODIC, scaler);
-
-    TIMER_BLOCK_STEP(scaler, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
-}
-
-static void test_timer_zero_load_prescaled_periodic_to_nonscaled_oneshot(void)
-{
-    timer_reset();
-    timer_load(0);
-    timer_start(PERIODIC, 255);
-
-    TIMER_BLOCK_STEP(255, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(255, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(255, 1);
-
-    timer_start(ONESHOT, NOSCALE);
-
-    TIMER_BLOCK_STEP(NOSCALE, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(NOSCALE, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_zero_load_prescaled_oneshot_to_nonscaled_periodic(void)
-{
-    timer_reset();
-    timer_load(0);
-    timer_start(ONESHOT, 255);
-
-    TIMER_BLOCK_STEP(255, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_start(PERIODIC, NOSCALE);
-
-    TIMER_BLOCK_STEP(NOSCALE, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_zero_load_nonscaled_oneshot_to_prescaled_periodic(void)
-{
-    timer_reset();
-    timer_load(0);
-    timer_start(ONESHOT, NOSCALE);
-
-    TIMER_BLOCK_STEP(NOSCALE, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_start(PERIODIC, 255);
-
-    TIMER_BLOCK_STEP(255, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(255, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-static void test_timer_zero_load_nonscaled_periodic_to_prescaled_oneshot(void)
-{
-    timer_reset();
-    timer_load(0);
-    timer_start(PERIODIC, NOSCALE);
-
-    TIMER_BLOCK_STEP(NOSCALE, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    timer_start(ONESHOT, 255);
-
-    TIMER_BLOCK_STEP(255, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-
-    TIMER_BLOCK_STEP(255, 1);
-
-    g_assert_cmpuint(timer_counter(), ==, 0);
-    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
-}
-
-/*
- * Add a qtest test that comes in two versions: one with
- * a timer scaler setting, and one with the timer nonscaled.
- */
-static void add_scaler_test(const char *str, bool scale,
-                            void (*fn)(const void *))
-{
-    char *name;
-    int *scaler = scale ? &scaled : &nonscaled;
-
-    name = g_strdup_printf("%s=%d", str, *scaler);
-    qtest_add_data_func(name, scaler, fn);
-    g_free(name);
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-    int scale;
-
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("mptimer/deferred_trigger", test_deferred_trigger);
-    qtest_add_func("mptimer/load_disabled", test_timer_load_disabled);
-    qtest_add_func("mptimer/set_counter_disabled", test_timer_set_counter_disabled);
-    qtest_add_func("mptimer/zero_load_prescaled_periodic_to_nonscaled_oneshot",
-                   test_timer_zero_load_prescaled_periodic_to_nonscaled_oneshot);
-    qtest_add_func("mptimer/zero_load_prescaled_oneshot_to_nonscaled_periodic",
-                   test_timer_zero_load_prescaled_oneshot_to_nonscaled_periodic);
-    qtest_add_func("mptimer/zero_load_nonscaled_oneshot_to_prescaled_periodic",
-                   test_timer_zero_load_nonscaled_oneshot_to_prescaled_periodic);
-    qtest_add_func("mptimer/zero_load_nonscaled_periodic_to_prescaled_oneshot",
-                   test_timer_zero_load_nonscaled_periodic_to_prescaled_oneshot);
-    qtest_add_func("mptimer/prescaler", test_timer_prescaler);
-    qtest_add_func("mptimer/prescaler_on_the_fly", test_timer_prescaler_on_the_fly);
-
-    for (scale = 0; scale < 2; scale++) {
-        add_scaler_test("mptimer/oneshot scaler",
-                        scale, test_timer_oneshot);
-        add_scaler_test("mptimer/pause scaler",
-                        scale, test_timer_pause);
-        add_scaler_test("mptimer/reload scaler",
-                        scale, test_timer_reload);
-        add_scaler_test("mptimer/periodic scaler",
-                        scale, test_timer_periodic);
-        add_scaler_test("mptimer/oneshot_to_periodic scaler",
-                        scale, test_timer_oneshot_to_periodic);
-        add_scaler_test("mptimer/periodic_to_oneshot scaler",
-                        scale, test_timer_periodic_to_oneshot);
-        add_scaler_test("mptimer/set_oneshot_counter_to_0 scaler",
-                        scale, test_timer_set_oneshot_counter_to_0);
-        add_scaler_test("mptimer/set_periodic_counter_to_0 scaler",
-                        scale, test_timer_set_periodic_counter_to_0);
-        add_scaler_test("mptimer/noload_oneshot scaler",
-                        scale, test_timer_noload_oneshot);
-        add_scaler_test("mptimer/noload_periodic scaler",
-                        scale, test_timer_noload_periodic);
-        add_scaler_test("mptimer/zero_load_oneshot scaler",
-                        scale, test_timer_zero_load_oneshot);
-        add_scaler_test("mptimer/zero_load_periodic scaler",
-                        scale, test_timer_zero_load_periodic);
-        add_scaler_test("mptimer/zero_load_oneshot_to_nonzero scaler",
-                        scale, test_timer_zero_load_oneshot_to_nonzero);
-        add_scaler_test("mptimer/zero_load_periodic_to_nonzero scaler",
-                        scale, test_timer_zero_load_periodic_to_nonzero);
-        add_scaler_test("mptimer/nonzero_load_oneshot_to_zero scaler",
-                        scale, test_timer_nonzero_load_oneshot_to_zero);
-        add_scaler_test("mptimer/nonzero_load_periodic_to_zero scaler",
-                        scale, test_timer_nonzero_load_periodic_to_zero);
-        add_scaler_test("mptimer/set_periodic_counter_on_the_fly scaler",
-                        scale, test_timer_set_periodic_counter_on_the_fly);
-        add_scaler_test("mptimer/enable_and_set_counter scaler",
-                        scale, test_timer_enable_and_set_counter);
-        add_scaler_test("mptimer/set_counter_and_enable scaler",
-                        scale, test_timer_set_counter_and_enable);
-        add_scaler_test("mptimer/oneshot_with_counter_0_on_start scaler",
-                        scale, test_timer_oneshot_with_counter_0_on_start);
-        add_scaler_test("mptimer/periodic_with_counter_0_on_start scaler",
-                        scale, test_timer_periodic_with_counter_0_on_start);
-        add_scaler_test("mptimer/periodic_counter scaler",
-                        scale, test_periodic_counter);
-        add_scaler_test("mptimer/set_counter_periodic_with_zero_load scaler",
-                        scale, test_timer_set_counter_periodic_with_zero_load);
-        add_scaler_test("mptimer/set_oneshot_load_to_0 scaler",
-                        scale, test_timer_set_oneshot_load_to_0);
-        add_scaler_test("mptimer/set_periodic_load_to_0 scaler",
-                        scale, test_timer_set_periodic_load_to_0);
-        add_scaler_test("mptimer/zero_load_mode_switch scaler",
-                        scale, test_timer_zero_load_mode_switch);
-    }
-
-    qtest_start("-machine vexpress-a9");
-    ret = g_test_run();
-    qtest_end();
-
-    return ret;
-}
diff --git a/tests/test-filter-mirror.c b/tests/test-filter-mirror.c
deleted file mode 100644 (file)
index 1e3ced8..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * QTest testcase for filter-mirror
- *
- * Copyright (c) 2016 FUJITSU LIMITED
- * Author: Zhang Chen <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or
- * later.  See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "qemu/iov.h"
-#include "qemu/sockets.h"
-#include "qemu/error-report.h"
-#include "qemu/main-loop.h"
-
-/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(qs, ...) qobject_unref(qtest_qmp(qs, __VA_ARGS__))
-
-static void test_mirror(void)
-{
-    int send_sock[2], recv_sock[2];
-    uint32_t ret = 0, len = 0;
-    char send_buf[] = "Hello! filter-mirror~";
-    char *recv_buf;
-    uint32_t size = sizeof(send_buf);
-    size = htonl(size);
-    const char *devstr = "e1000";
-    QTestState *qts;
-
-    if (g_str_equal(qtest_get_arch(), "s390x")) {
-        devstr = "virtio-net-ccw";
-    }
-
-    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, send_sock);
-    g_assert_cmpint(ret, !=, -1);
-
-    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, recv_sock);
-    g_assert_cmpint(ret, !=, -1);
-
-    qts = qtest_initf(
-        "-netdev socket,id=qtest-bn0,fd=%d "
-        "-device %s,netdev=qtest-bn0,id=qtest-e0 "
-        "-chardev socket,id=mirror0,fd=%d "
-        "-object filter-mirror,id=qtest-f0,netdev=qtest-bn0,queue=tx,outdev=mirror0 "
-        , send_sock[1], devstr, recv_sock[1]);
-
-    struct iovec iov[] = {
-        {
-            .iov_base = &size,
-            .iov_len = sizeof(size),
-        }, {
-            .iov_base = send_buf,
-            .iov_len = sizeof(send_buf),
-        },
-    };
-
-    /* send a qmp command to guarantee that 'connected' is setting to true. */
-    qmp_discard_response(qts, "{ 'execute' : 'query-status'}");
-    ret = iov_send(send_sock[0], iov, 2, 0, sizeof(size) + sizeof(send_buf));
-    g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size));
-    close(send_sock[0]);
-
-    ret = qemu_recv(recv_sock[0], &len, sizeof(len), 0);
-    g_assert_cmpint(ret, ==, sizeof(len));
-    len = ntohl(len);
-
-    g_assert_cmpint(len, ==, sizeof(send_buf));
-    recv_buf = g_malloc(len);
-    ret = qemu_recv(recv_sock[0], recv_buf, len, 0);
-    g_assert_cmpstr(recv_buf, ==, send_buf);
-
-    g_free(recv_buf);
-    close(send_sock[0]);
-    close(send_sock[1]);
-    close(recv_sock[0]);
-    close(recv_sock[1]);
-    qtest_quit(qts);
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("/netfilter/mirror", test_mirror);
-    ret = g_test_run();
-
-    return ret;
-}
diff --git a/tests/test-filter-redirector.c b/tests/test-filter-redirector.c
deleted file mode 100644 (file)
index e4d5322..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * QTest testcase for filter-redirector
- *
- * Copyright (c) 2016 FUJITSU LIMITED
- * Author: Zhang Chen <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or
- * later.  See the COPYING file in the top-level directory.
- *
- * Case 1, tx traffic flow:
- *
- * qemu side              | test side
- *                        |
- * +---------+            |  +-------+
- * | backend <---------------+ sock0 |
- * +----+----+            |  +-------+
- *      |                 |
- * +----v----+  +-------+ |
- * |  rd0    +->+chardev| |
- * +---------+  +---+---+ |
- *                  |     |
- * +---------+      |     |
- * |  rd1    <------+     |
- * +----+----+            |
- *      |                 |
- * +----v----+            |  +-------+
- * |  rd2    +--------------->sock1  |
- * +---------+            |  +-------+
- *                        +
- *
- * --------------------------------------
- * Case 2, rx traffic flow
- * qemu side              | test side
- *                        |
- * +---------+            |  +-------+
- * | backend +---------------> sock1 |
- * +----^----+            |  +-------+
- *      |                 |
- * +----+----+  +-------+ |
- * |  rd0    +<-+chardev| |
- * +---------+  +---+---+ |
- *                  ^     |
- * +---------+      |     |
- * |  rd1    +------+     |
- * +----^----+            |
- *      |                 |
- * +----+----+            |  +-------+
- * |  rd2    <---------------+sock0  |
- * +---------+            |  +-------+
- *                        +
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "qemu/iov.h"
-#include "qemu/sockets.h"
-#include "qemu/error-report.h"
-#include "qemu/main-loop.h"
-
-/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(qs, ...) qobject_unref(qtest_qmp(qs, __VA_ARGS__))
-
-static const char *get_devstr(void)
-{
-    if (g_str_equal(qtest_get_arch(), "s390x")) {
-        return "virtio-net-ccw";
-    }
-
-    return "rtl8139";
-}
-
-
-static void test_redirector_tx(void)
-{
-    int backend_sock[2], recv_sock;
-    uint32_t ret = 0, len = 0;
-    char send_buf[] = "Hello!!";
-    char sock_path0[] = "filter-redirector0.XXXXXX";
-    char sock_path1[] = "filter-redirector1.XXXXXX";
-    char *recv_buf;
-    uint32_t size = sizeof(send_buf);
-    size = htonl(size);
-    QTestState *qts;
-
-    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, backend_sock);
-    g_assert_cmpint(ret, !=, -1);
-
-    ret = mkstemp(sock_path0);
-    g_assert_cmpint(ret, !=, -1);
-    ret = mkstemp(sock_path1);
-    g_assert_cmpint(ret, !=, -1);
-
-    qts = qtest_initf(
-        "-netdev socket,id=qtest-bn0,fd=%d "
-        "-device %s,netdev=qtest-bn0,id=qtest-e0 "
-        "-chardev socket,id=redirector0,path=%s,server,nowait "
-        "-chardev socket,id=redirector1,path=%s,server,nowait "
-        "-chardev socket,id=redirector2,path=%s "
-        "-object filter-redirector,id=qtest-f0,netdev=qtest-bn0,"
-        "queue=tx,outdev=redirector0 "
-        "-object filter-redirector,id=qtest-f1,netdev=qtest-bn0,"
-        "queue=tx,indev=redirector2 "
-        "-object filter-redirector,id=qtest-f2,netdev=qtest-bn0,"
-        "queue=tx,outdev=redirector1 ", backend_sock[1], get_devstr(),
-        sock_path0, sock_path1, sock_path0);
-
-    recv_sock = unix_connect(sock_path1, NULL);
-    g_assert_cmpint(recv_sock, !=, -1);
-
-    /* send a qmp command to guarantee that 'connected' is setting to true. */
-    qmp_discard_response(qts, "{ 'execute' : 'query-status'}");
-
-    struct iovec iov[] = {
-        {
-            .iov_base = &size,
-            .iov_len = sizeof(size),
-        }, {
-            .iov_base = send_buf,
-            .iov_len = sizeof(send_buf),
-        },
-    };
-
-    ret = iov_send(backend_sock[0], iov, 2, 0, sizeof(size) + sizeof(send_buf));
-    g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size));
-    close(backend_sock[0]);
-
-    ret = qemu_recv(recv_sock, &len, sizeof(len), 0);
-    g_assert_cmpint(ret, ==, sizeof(len));
-    len = ntohl(len);
-
-    g_assert_cmpint(len, ==, sizeof(send_buf));
-    recv_buf = g_malloc(len);
-    ret = qemu_recv(recv_sock, recv_buf, len, 0);
-    g_assert_cmpstr(recv_buf, ==, send_buf);
-
-    g_free(recv_buf);
-    close(recv_sock);
-    unlink(sock_path0);
-    unlink(sock_path1);
-    qtest_quit(qts);
-}
-
-static void test_redirector_rx(void)
-{
-    int backend_sock[2], send_sock;
-    uint32_t ret = 0, len = 0;
-    char send_buf[] = "Hello!!";
-    char sock_path0[] = "filter-redirector0.XXXXXX";
-    char sock_path1[] = "filter-redirector1.XXXXXX";
-    char *recv_buf;
-    uint32_t size = sizeof(send_buf);
-    size = htonl(size);
-    QTestState *qts;
-
-    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, backend_sock);
-    g_assert_cmpint(ret, !=, -1);
-
-    ret = mkstemp(sock_path0);
-    g_assert_cmpint(ret, !=, -1);
-    ret = mkstemp(sock_path1);
-    g_assert_cmpint(ret, !=, -1);
-
-    qts = qtest_initf(
-        "-netdev socket,id=qtest-bn0,fd=%d "
-        "-device %s,netdev=qtest-bn0,id=qtest-e0 "
-        "-chardev socket,id=redirector0,path=%s,server,nowait "
-        "-chardev socket,id=redirector1,path=%s,server,nowait "
-        "-chardev socket,id=redirector2,path=%s "
-        "-object filter-redirector,id=qtest-f0,netdev=qtest-bn0,"
-        "queue=rx,indev=redirector0 "
-        "-object filter-redirector,id=qtest-f1,netdev=qtest-bn0,"
-        "queue=rx,outdev=redirector2 "
-        "-object filter-redirector,id=qtest-f2,netdev=qtest-bn0,"
-        "queue=rx,indev=redirector1 ", backend_sock[1], get_devstr(),
-        sock_path0, sock_path1, sock_path0);
-
-    struct iovec iov[] = {
-        {
-            .iov_base = &size,
-            .iov_len = sizeof(size),
-        }, {
-            .iov_base = send_buf,
-            .iov_len = sizeof(send_buf),
-        },
-    };
-
-    send_sock = unix_connect(sock_path1, NULL);
-    g_assert_cmpint(send_sock, !=, -1);
-    /* send a qmp command to guarantee that 'connected' is setting to true. */
-    qmp_discard_response(qts, "{ 'execute' : 'query-status'}");
-
-    ret = iov_send(send_sock, iov, 2, 0, sizeof(size) + sizeof(send_buf));
-    g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size));
-
-    ret = qemu_recv(backend_sock[0], &len, sizeof(len), 0);
-    g_assert_cmpint(ret, ==, sizeof(len));
-    len = ntohl(len);
-
-    g_assert_cmpint(len, ==, sizeof(send_buf));
-    recv_buf = g_malloc(len);
-    ret = qemu_recv(backend_sock[0], recv_buf, len, 0);
-    g_assert_cmpstr(recv_buf, ==, send_buf);
-
-    close(send_sock);
-    g_free(recv_buf);
-    unlink(sock_path0);
-    unlink(sock_path1);
-    qtest_quit(qts);
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/netfilter/redirector_tx", test_redirector_tx);
-    qtest_add_func("/netfilter/redirector_rx", test_redirector_rx);
-    return g_test_run();
-}
diff --git a/tests/test-hmp.c b/tests/test-hmp.c
deleted file mode 100644 (file)
index 5029c4d..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Test HMP commands.
- *
- * Copyright (c) 2017 Red Hat Inc.
- *
- * Author:
- *    Thomas Huth <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2
- * or later. See the COPYING file in the top-level directory.
- *
- * This test calls some HMP commands for all machines that the current
- * QEMU binary provides, to check whether they terminate successfully
- * (i.e. do not crash QEMU).
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-
-static int verbose;
-
-static const char *hmp_cmds[] = {
-    "announce_self",
-    "boot_set ndc",
-    "chardev-add null,id=testchardev1",
-    "chardev-send-break testchardev1",
-    "chardev-change testchardev1 ringbuf",
-    "chardev-remove testchardev1",
-    "commit all",
-    "cpu-add 1",
-    "cpu 0",
-    "device_add ?",
-    "device_add usb-mouse,id=mouse1",
-    "drive_add ignored format=help",
-    "mouse_button 7",
-    "mouse_move 10 10",
-    "mouse_button 0",
-    "device_del mouse1",
-    "dump-guest-memory /dev/null 0 4096",
-    "dump-guest-memory /dev/null",
-    "gdbserver",
-    "gva2gpa 0",
-    "hostfwd_add tcp::43210-:43210",
-    "hostfwd_remove tcp::43210-:43210",
-    "i /w 0",
-    "log all",
-    "log none",
-    "memsave 0 4096 \"/dev/null\"",
-    "migrate_set_cache_size 1",
-    "migrate_set_downtime 1",
-    "migrate_set_speed 1",
-    "netdev_add user,id=net1",
-    "set_link net1 off",
-    "set_link net1 on",
-    "netdev_del net1",
-    "nmi",
-    "o /w 0 0x1234",
-    "object_add memory-backend-ram,id=mem1,size=256M",
-    "object_del mem1",
-    "pmemsave 0 4096 \"/dev/null\"",
-    "p $pc + 8",
-    "qom-list /",
-    "qom-set /machine initrd test",
-    "screendump /dev/null",
-    "sendkey x",
-    "singlestep on",
-    "wavcapture /dev/null",
-    "stopcapture 0",
-    "sum 0 512",
-    "x /8i 0x100",
-    "xp /16x 0",
-    NULL
-};
-
-/* Run through the list of pre-defined commands */
-static void test_commands(QTestState *qts)
-{
-    char *response;
-    int i;
-
-    for (i = 0; hmp_cmds[i] != NULL; i++) {
-        response = qtest_hmp(qts, "%s", hmp_cmds[i]);
-        if (verbose) {
-            fprintf(stderr,
-                    "\texecute HMP command: %s\n"
-                    "\tresult             : %s\n",
-                    hmp_cmds[i], response);
-        }
-        g_free(response);
-    }
-
-}
-
-/* Run through all info commands and call them blindly (without arguments) */
-static void test_info_commands(QTestState *qts)
-{
-    char *resp, *info, *info_buf, *endp;
-
-    info_buf = info = qtest_hmp(qts, "help info");
-
-    while (*info) {
-        /* Extract the info command, ignore parameters and description */
-        g_assert(strncmp(info, "info ", 5) == 0);
-        endp = strchr(&info[5], ' ');
-        g_assert(endp != NULL);
-        *endp = '\0';
-        /* Now run the info command */
-        if (verbose) {
-            fprintf(stderr, "\t%s\n", info);
-        }
-        resp = qtest_hmp(qts, "%s", info);
-        g_free(resp);
-        /* And move forward to the next line */
-        info = strchr(endp + 1, '\n');
-        if (!info) {
-            break;
-        }
-        info += 1;
-    }
-
-    g_free(info_buf);
-}
-
-static void test_machine(gconstpointer data)
-{
-    const char *machine = data;
-    char *args;
-    QTestState *qts;
-
-    args = g_strdup_printf("-S -M %s", machine);
-    qts = qtest_init(args);
-
-    test_info_commands(qts);
-    test_commands(qts);
-
-    qtest_quit(qts);
-    g_free(args);
-    g_free((void *)data);
-}
-
-static void add_machine_test_case(const char *mname)
-{
-    char *path;
-
-    /* Ignore blacklisted machines that have known problems */
-    if (!strcmp("xenfv", mname) || !strcmp("xenpv", mname)) {
-        return;
-    }
-
-    path = g_strdup_printf("hmp/%s", mname);
-    qtest_add_data_func(path, g_strdup(mname), test_machine);
-    g_free(path);
-}
-
-int main(int argc, char **argv)
-{
-    char *v_env = getenv("V");
-
-    if (v_env && *v_env >= '2') {
-        verbose = true;
-    }
-
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_cb_for_every_machine(add_machine_test_case, g_test_quick());
-
-    /* as none machine has no memory by default, add a test case with memory */
-    qtest_add_data_func("hmp/none+2MB", g_strdup("none -m 2"), test_machine);
-
-    return g_test_run();
-}
diff --git a/tests/test-netfilter.c b/tests/test-netfilter.c
deleted file mode 100644 (file)
index 22927ee..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * QTest testcase for netfilter
- *
- * Copyright (c) 2015 FUJITSU LIMITED
- * Author: Yang Hongyang <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or
- * later.  See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-#include "qapi/qmp/qdict.h"
-
-/* add a netfilter to a netdev and then remove it */
-static void add_one_netfilter(void)
-{
-    QDict *response;
-
-    response = qmp("{'execute': 'object-add',"
-                   " 'arguments': {"
-                   "   'qom-type': 'filter-buffer',"
-                   "   'id': 'qtest-f0',"
-                   "   'props': {"
-                   "     'netdev': 'qtest-bn0',"
-                   "     'queue': 'rx',"
-                   "     'interval': 1000"
-                   "}}}");
-
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-
-    response = qmp("{'execute': 'object-del',"
-                   " 'arguments': {"
-                   "   'id': 'qtest-f0'"
-                   "}}");
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-}
-
-/* add a netfilter to a netdev and then remove the netdev */
-static void remove_netdev_with_one_netfilter(void)
-{
-    QDict *response;
-
-    response = qmp("{'execute': 'object-add',"
-                   " 'arguments': {"
-                   "   'qom-type': 'filter-buffer',"
-                   "   'id': 'qtest-f0',"
-                   "   'props': {"
-                   "     'netdev': 'qtest-bn0',"
-                   "     'queue': 'rx',"
-                   "     'interval': 1000"
-                   "}}}");
-
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-
-    response = qmp("{'execute': 'netdev_del',"
-                   " 'arguments': {"
-                   "   'id': 'qtest-bn0'"
-                   "}}");
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-
-    /* add back the netdev */
-    response = qmp("{'execute': 'netdev_add',"
-                   " 'arguments': {"
-                   "   'type': 'user',"
-                   "   'id': 'qtest-bn0'"
-                   "}}");
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-}
-
-/* add multi(2) netfilters to a netdev and then remove them */
-static void add_multi_netfilter(void)
-{
-    QDict *response;
-
-    response = qmp("{'execute': 'object-add',"
-                   " 'arguments': {"
-                   "   'qom-type': 'filter-buffer',"
-                   "   'id': 'qtest-f0',"
-                   "   'props': {"
-                   "     'netdev': 'qtest-bn0',"
-                   "     'queue': 'rx',"
-                   "     'interval': 1000"
-                   "}}}");
-
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-
-    response = qmp("{'execute': 'object-add',"
-                   " 'arguments': {"
-                   "   'qom-type': 'filter-buffer',"
-                   "   'id': 'qtest-f1',"
-                   "   'props': {"
-                   "     'netdev': 'qtest-bn0',"
-                   "     'queue': 'rx',"
-                   "     'interval': 1000"
-                   "}}}");
-
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-
-    response = qmp("{'execute': 'object-del',"
-                   " 'arguments': {"
-                   "   'id': 'qtest-f0'"
-                   "}}");
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-
-    response = qmp("{'execute': 'object-del',"
-                   " 'arguments': {"
-                   "   'id': 'qtest-f1'"
-                   "}}");
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-}
-
-/* add multi(2) netfilters to a netdev and then remove the netdev */
-static void remove_netdev_with_multi_netfilter(void)
-{
-    QDict *response;
-
-    response = qmp("{'execute': 'object-add',"
-                   " 'arguments': {"
-                   "   'qom-type': 'filter-buffer',"
-                   "   'id': 'qtest-f0',"
-                   "   'props': {"
-                   "     'netdev': 'qtest-bn0',"
-                   "     'queue': 'rx',"
-                   "     'interval': 1000"
-                   "}}}");
-
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-
-    response = qmp("{'execute': 'object-add',"
-                   " 'arguments': {"
-                   "   'qom-type': 'filter-buffer',"
-                   "   'id': 'qtest-f1',"
-                   "   'props': {"
-                   "     'netdev': 'qtest-bn0',"
-                   "     'queue': 'rx',"
-                   "     'interval': 1000"
-                   "}}}");
-
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-
-    response = qmp("{'execute': 'netdev_del',"
-                   " 'arguments': {"
-                   "   'id': 'qtest-bn0'"
-                   "}}");
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-
-    /* add back the netdev */
-    response = qmp("{'execute': 'netdev_add',"
-                   " 'arguments': {"
-                   "   'type': 'user',"
-                   "   'id': 'qtest-bn0'"
-                   "}}");
-    g_assert(response);
-    g_assert(!qdict_haskey(response, "error"));
-    qobject_unref(response);
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-    char *args;
-    const char *devstr = "e1000";
-
-    if (g_str_equal(qtest_get_arch(), "s390x")) {
-        devstr = "virtio-net-ccw";
-    }
-
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/netfilter/addremove_one", add_one_netfilter);
-    qtest_add_func("/netfilter/remove_netdev_one",
-                   remove_netdev_with_one_netfilter);
-    qtest_add_func("/netfilter/addremove_multi", add_multi_netfilter);
-    qtest_add_func("/netfilter/remove_netdev_multi",
-                   remove_netdev_with_multi_netfilter);
-
-    args = g_strdup_printf("-netdev user,id=qtest-bn0 "
-                           "-device %s,netdev=qtest-bn0", devstr);
-    qtest_start(args);
-    ret = g_test_run();
-
-    qtest_end();
-    g_free(args);
-
-    return ret;
-}
diff --git a/tests/test-x86-cpuid-compat.c b/tests/test-x86-cpuid-compat.c
deleted file mode 100644 (file)
index 772287b..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qnum.h"
-#include "qapi/qmp/qbool.h"
-#include "libqtest-single.h"
-
-static char *get_cpu0_qom_path(void)
-{
-    QDict *resp;
-    QList *ret;
-    QDict *cpu0;
-    char *path;
-
-    resp = qmp("{'execute': 'query-cpus', 'arguments': {}}");
-    g_assert(qdict_haskey(resp, "return"));
-    ret = qdict_get_qlist(resp, "return");
-
-    cpu0 = qobject_to(QDict, qlist_peek(ret));
-    path = g_strdup(qdict_get_str(cpu0, "qom_path"));
-    qobject_unref(resp);
-    return path;
-}
-
-static QObject *qom_get(const char *path, const char *prop)
-{
-    QDict *resp = qmp("{ 'execute': 'qom-get',"
-                      "  'arguments': { 'path': %s,"
-                      "                 'property': %s } }",
-                      path, prop);
-    QObject *ret = qdict_get(resp, "return");
-    qobject_ref(ret);
-    qobject_unref(resp);
-    return ret;
-}
-
-static bool qom_get_bool(const char *path, const char *prop)
-{
-    QBool *value = qobject_to(QBool, qom_get(path, prop));
-    bool b = qbool_get_bool(value);
-
-    qobject_unref(value);
-    return b;
-}
-
-typedef struct CpuidTestArgs {
-    const char *cmdline;
-    const char *property;
-    int64_t expected_value;
-} CpuidTestArgs;
-
-static void test_cpuid_prop(const void *data)
-{
-    const CpuidTestArgs *args = data;
-    char *path;
-    QNum *value;
-    int64_t val;
-
-    qtest_start(args->cmdline);
-    path = get_cpu0_qom_path();
-    value = qobject_to(QNum, qom_get(path, args->property));
-    g_assert(qnum_get_try_int(value, &val));
-    g_assert_cmpint(val, ==, args->expected_value);
-    qtest_end();
-
-    qobject_unref(value);
-    g_free(path);
-}
-
-static void add_cpuid_test(const char *name, const char *cmdline,
-                           const char *property, int64_t expected_value)
-{
-    CpuidTestArgs *args = g_new0(CpuidTestArgs, 1);
-    args->cmdline = cmdline;
-    args->property = property;
-    args->expected_value = expected_value;
-    qtest_add_data_func(name, args, test_cpuid_prop);
-}
-
-
-/* Parameters to a add_feature_test() test case */
-typedef struct FeatureTestArgs {
-    /* cmdline to start QEMU */
-    const char *cmdline;
-    /*
-     * cpuid-input-eax and cpuid-input-ecx values to look for,
-     * in "feature-words" and "filtered-features" properties.
-     */
-    uint32_t in_eax, in_ecx;
-    /* The register name to look for, in the X86CPUFeatureWordInfo array */
-    const char *reg;
-    /* The bit to check in X86CPUFeatureWordInfo.features */
-    int bitnr;
-    /* The expected value for the bit in (X86CPUFeatureWordInfo.features) */
-    bool expected_value;
-} FeatureTestArgs;
-
-/* Get the value for a feature word in a X86CPUFeatureWordInfo list */
-static uint32_t get_feature_word(QList *features, uint32_t eax, uint32_t ecx,
-                                 const char *reg)
-{
-    const QListEntry *e;
-
-    for (e = qlist_first(features); e; e = qlist_next(e)) {
-        QDict *w = qobject_to(QDict, qlist_entry_obj(e));
-        const char *rreg = qdict_get_str(w, "cpuid-register");
-        uint32_t reax = qdict_get_int(w, "cpuid-input-eax");
-        bool has_ecx = qdict_haskey(w, "cpuid-input-ecx");
-        uint32_t recx = 0;
-        int64_t val;
-
-        if (has_ecx) {
-            recx = qdict_get_int(w, "cpuid-input-ecx");
-        }
-        if (eax == reax && (!has_ecx || ecx == recx) && !strcmp(rreg, reg)) {
-            g_assert(qnum_get_try_int(qobject_to(QNum,
-                                                 qdict_get(w, "features")),
-                                      &val));
-            return val;
-        }
-    }
-    return 0;
-}
-
-static void test_feature_flag(const void *data)
-{
-    const FeatureTestArgs *args = data;
-    char *path;
-    QList *present, *filtered;
-    uint32_t value;
-
-    qtest_start(args->cmdline);
-    path = get_cpu0_qom_path();
-    present = qobject_to(QList, qom_get(path, "feature-words"));
-    filtered = qobject_to(QList, qom_get(path, "filtered-features"));
-    value = get_feature_word(present, args->in_eax, args->in_ecx, args->reg);
-    value |= get_feature_word(filtered, args->in_eax, args->in_ecx, args->reg);
-    qtest_end();
-
-    g_assert(!!(value & (1U << args->bitnr)) == args->expected_value);
-
-    qobject_unref(present);
-    qobject_unref(filtered);
-    g_free(path);
-}
-
-/*
- * Add test case to ensure that a given feature flag is set in
- * either "feature-words" or "filtered-features", when running QEMU
- * using cmdline
- */
-static FeatureTestArgs *add_feature_test(const char *name, const char *cmdline,
-                                         uint32_t eax, uint32_t ecx,
-                                         const char *reg, int bitnr,
-                                         bool expected_value)
-{
-    FeatureTestArgs *args = g_new0(FeatureTestArgs, 1);
-    args->cmdline = cmdline;
-    args->in_eax = eax;
-    args->in_ecx = ecx;
-    args->reg = reg;
-    args->bitnr = bitnr;
-    args->expected_value = expected_value;
-    qtest_add_data_func(name, args, test_feature_flag);
-    return args;
-}
-
-static void test_plus_minus_subprocess(void)
-{
-    char *path;
-
-    /* Rules:
-     * 1)"-foo" overrides "+foo"
-     * 2) "[+-]foo" overrides "foo=..."
-     * 3) Old feature names with underscores (e.g. "sse4_2")
-     *    should keep working
-     *
-     * Note: rules 1 and 2 are planned to be removed soon, and
-     * should generate a warning.
-     */
-    qtest_start("-cpu pentium,-fpu,+fpu,-mce,mce=on,+cx8,cx8=off,+sse4_1,sse4_2=on");
-    path = get_cpu0_qom_path();
-
-    g_assert_false(qom_get_bool(path, "fpu"));
-    g_assert_false(qom_get_bool(path, "mce"));
-    g_assert_true(qom_get_bool(path, "cx8"));
-
-    /* Test both the original and the alias feature names: */
-    g_assert_true(qom_get_bool(path, "sse4-1"));
-    g_assert_true(qom_get_bool(path, "sse4.1"));
-
-    g_assert_true(qom_get_bool(path, "sse4-2"));
-    g_assert_true(qom_get_bool(path, "sse4.2"));
-
-    qtest_end();
-    g_free(path);
-}
-
-static void test_plus_minus(void)
-{
-    g_test_trap_subprocess("/x86/cpuid/parsing-plus-minus/subprocess", 0, 0);
-    g_test_trap_assert_passed();
-    g_test_trap_assert_stderr("*Ambiguous CPU model string. "
-                              "Don't mix both \"-mce\" and \"mce=on\"*");
-    g_test_trap_assert_stderr("*Ambiguous CPU model string. "
-                              "Don't mix both \"+cx8\" and \"cx8=off\"*");
-    g_test_trap_assert_stdout("");
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-
-    g_test_add_func("/x86/cpuid/parsing-plus-minus/subprocess",
-                    test_plus_minus_subprocess);
-    g_test_add_func("/x86/cpuid/parsing-plus-minus", test_plus_minus);
-
-    /* Original level values for CPU models: */
-    add_cpuid_test("x86/cpuid/phenom/level",
-                   "-cpu phenom", "level", 5);
-    add_cpuid_test("x86/cpuid/Conroe/level",
-                   "-cpu Conroe", "level", 10);
-    add_cpuid_test("x86/cpuid/SandyBridge/level",
-                   "-cpu SandyBridge", "level", 0xd);
-    add_cpuid_test("x86/cpuid/486/xlevel",
-                   "-cpu 486", "xlevel", 0);
-    add_cpuid_test("x86/cpuid/core2duo/xlevel",
-                   "-cpu core2duo", "xlevel", 0x80000008);
-    add_cpuid_test("x86/cpuid/phenom/xlevel",
-                   "-cpu phenom", "xlevel", 0x8000001A);
-    add_cpuid_test("x86/cpuid/athlon/xlevel",
-                   "-cpu athlon", "xlevel", 0x80000008);
-
-    /* If level is not large enough, it should increase automatically: */
-    /* CPUID[6].EAX: */
-    add_cpuid_test("x86/cpuid/auto-level/phenom/arat",
-                   "-cpu 486,+arat", "level", 6);
-    /* CPUID[EAX=7,ECX=0].EBX: */
-    add_cpuid_test("x86/cpuid/auto-level/phenom/fsgsbase",
-                   "-cpu phenom,+fsgsbase", "level", 7);
-    /* CPUID[EAX=7,ECX=0].ECX: */
-    add_cpuid_test("x86/cpuid/auto-level/phenom/avx512vbmi",
-                   "-cpu phenom,+avx512vbmi", "level", 7);
-    /* CPUID[EAX=0xd,ECX=1].EAX: */
-    add_cpuid_test("x86/cpuid/auto-level/phenom/xsaveopt",
-                   "-cpu phenom,+xsaveopt", "level", 0xd);
-    /* CPUID[8000_0001].EDX: */
-    add_cpuid_test("x86/cpuid/auto-xlevel/486/3dnow",
-                   "-cpu 486,+3dnow", "xlevel", 0x80000001);
-    /* CPUID[8000_0001].ECX: */
-    add_cpuid_test("x86/cpuid/auto-xlevel/486/sse4a",
-                   "-cpu 486,+sse4a", "xlevel", 0x80000001);
-    /* CPUID[8000_0007].EDX: */
-    add_cpuid_test("x86/cpuid/auto-xlevel/486/invtsc",
-                   "-cpu 486,+invtsc", "xlevel", 0x80000007);
-    /* CPUID[8000_000A].EDX: */
-    add_cpuid_test("x86/cpuid/auto-xlevel/486/npt",
-                   "-cpu 486,+npt", "xlevel", 0x8000000A);
-    /* CPUID[C000_0001].EDX: */
-    add_cpuid_test("x86/cpuid/auto-xlevel2/phenom/xstore",
-                   "-cpu phenom,+xstore", "xlevel2", 0xC0000001);
-    /* SVM needs CPUID[0x8000000A] */
-    add_cpuid_test("x86/cpuid/auto-xlevel/athlon/svm",
-                   "-cpu athlon,+svm", "xlevel", 0x8000000A);
-
-
-    /* If level is already large enough, it shouldn't change: */
-    add_cpuid_test("x86/cpuid/auto-level/SandyBridge/multiple",
-                   "-cpu SandyBridge,+arat,+fsgsbase,+avx512vbmi",
-                   "level", 0xd);
-    /* If level is explicitly set, it shouldn't change: */
-    add_cpuid_test("x86/cpuid/auto-level/486/fixed/0xF",
-                   "-cpu 486,level=0xF,+arat,+fsgsbase,+avx512vbmi,+xsaveopt",
-                   "level", 0xF);
-    add_cpuid_test("x86/cpuid/auto-level/486/fixed/2",
-                   "-cpu 486,level=2,+arat,+fsgsbase,+avx512vbmi,+xsaveopt",
-                   "level", 2);
-    add_cpuid_test("x86/cpuid/auto-level/486/fixed/0",
-                   "-cpu 486,level=0,+arat,+fsgsbase,+avx512vbmi,+xsaveopt",
-                   "level", 0);
-
-    /* if xlevel is already large enough, it shouldn't change: */
-    add_cpuid_test("x86/cpuid/auto-xlevel/phenom/3dnow",
-                   "-cpu phenom,+3dnow,+sse4a,+invtsc,+npt,+svm",
-                   "xlevel", 0x8000001A);
-    /* If xlevel is explicitly set, it shouldn't change: */
-    add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/80000002",
-                   "-cpu 486,xlevel=0x80000002,+3dnow,+sse4a,+invtsc,+npt,+svm",
-                   "xlevel", 0x80000002);
-    add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/8000001A",
-                   "-cpu 486,xlevel=0x8000001A,+3dnow,+sse4a,+invtsc,+npt,+svm",
-                   "xlevel", 0x8000001A);
-    add_cpuid_test("x86/cpuid/auto-xlevel/phenom/fixed/0",
-                   "-cpu 486,xlevel=0,+3dnow,+sse4a,+invtsc,+npt,+svm",
-                   "xlevel", 0);
-
-    /* if xlevel2 is already large enough, it shouldn't change: */
-    add_cpuid_test("x86/cpuid/auto-xlevel2/486/fixed",
-                   "-cpu 486,xlevel2=0xC0000002,+xstore",
-                   "xlevel2", 0xC0000002);
-
-    /* Check compatibility of old machine-types that didn't
-     * auto-increase level/xlevel/xlevel2: */
-
-    add_cpuid_test("x86/cpuid/auto-level/pc-2.7",
-                   "-machine pc-i440fx-2.7 -cpu 486,+arat,+avx512vbmi,+xsaveopt",
-                   "level", 1);
-    add_cpuid_test("x86/cpuid/auto-xlevel/pc-2.7",
-                   "-machine pc-i440fx-2.7 -cpu 486,+3dnow,+sse4a,+invtsc,+npt,+svm",
-                   "xlevel", 0);
-    add_cpuid_test("x86/cpuid/auto-xlevel2/pc-2.7",
-                   "-machine pc-i440fx-2.7 -cpu 486,+xstore",
-                   "xlevel2", 0);
-    /*
-     * QEMU 1.4.0 had auto-level enabled for CPUID[7], already,
-     * and the compat code that sets default level shouldn't
-     * disable the auto-level=7 code:
-     */
-    add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-1.4/off",
-                   "-machine pc-i440fx-1.4 -cpu Nehalem",
-                   "level", 2);
-    add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-1.5/on",
-                   "-machine pc-i440fx-1.4 -cpu Nehalem,+smap",
-                   "level", 7);
-    add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.3/off",
-                   "-machine pc-i440fx-2.3 -cpu Penryn",
-                   "level", 4);
-    add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.3/on",
-                   "-machine pc-i440fx-2.3 -cpu Penryn,+erms",
-                   "level", 7);
-    add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.9/off",
-                   "-machine pc-i440fx-2.9 -cpu Conroe",
-                   "level", 10);
-    add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.9/on",
-                   "-machine pc-i440fx-2.9 -cpu Conroe,+erms",
-                   "level", 10);
-
-    /*
-     * xlevel doesn't have any feature that triggers auto-level
-     * code on old machine-types.  Just check that the compat code
-     * is working correctly:
-     */
-    add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.3",
-                   "-machine pc-i440fx-2.3 -cpu SandyBridge",
-                   "xlevel", 0x8000000a);
-    add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-off",
-                   "-machine pc-i440fx-2.4 -cpu SandyBridge,",
-                   "xlevel", 0x80000008);
-    add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-on",
-                   "-machine pc-i440fx-2.4 -cpu SandyBridge,+npt",
-                   "xlevel", 0x80000008);
-
-    /* Test feature parsing */
-    add_feature_test("x86/cpuid/features/plus",
-                     "-cpu 486,+arat",
-                     6, 0, "EAX", 2, true);
-    add_feature_test("x86/cpuid/features/minus",
-                     "-cpu pentium,-mmx",
-                     1, 0, "EDX", 23, false);
-    add_feature_test("x86/cpuid/features/on",
-                     "-cpu 486,arat=on",
-                     6, 0, "EAX", 2, true);
-    add_feature_test("x86/cpuid/features/off",
-                     "-cpu pentium,mmx=off",
-                     1, 0, "EDX", 23, false);
-    add_feature_test("x86/cpuid/features/max-plus-invtsc",
-                     "-cpu max,+invtsc",
-                     0x80000007, 0, "EDX", 8, true);
-    add_feature_test("x86/cpuid/features/max-invtsc-on",
-                     "-cpu max,invtsc=on",
-                     0x80000007, 0, "EDX", 8, true);
-    add_feature_test("x86/cpuid/features/max-minus-mmx",
-                     "-cpu max,-mmx",
-                     1, 0, "EDX", 23, false);
-    add_feature_test("x86/cpuid/features/max-invtsc-on,mmx=off",
-                     "-cpu max,mmx=off",
-                     1, 0, "EDX", 23, false);
-
-    return g_test_run();
-}
diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c
deleted file mode 100644 (file)
index f930a96..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * QTest testcase for the TMP105 temperature sensor
- *
- * Copyright (c) 2012 Andreas Färber
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-
-#include "libqtest-single.h"
-#include "libqos/qgraph.h"
-#include "libqos/i2c.h"
-#include "qapi/qmp/qdict.h"
-#include "hw/misc/tmp105_regs.h"
-
-#define TMP105_TEST_ID   "tmp105-test"
-#define TMP105_TEST_ADDR 0x49
-
-static int qmp_tmp105_get_temperature(const char *id)
-{
-    QDict *response;
-    int ret;
-
-    response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, "
-                   "'property': 'temperature' } }", id);
-    g_assert(qdict_haskey(response, "return"));
-    ret = qdict_get_int(response, "return");
-    qobject_unref(response);
-    return ret;
-}
-
-static void qmp_tmp105_set_temperature(const char *id, int value)
-{
-    QDict *response;
-
-    response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
-                   "'property': 'temperature', 'value': %d } }", id, value);
-    g_assert(qdict_haskey(response, "return"));
-    qobject_unref(response);
-}
-
-#define TMP105_PRECISION (1000/16)
-static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc)
-{
-    uint16_t value;
-    QI2CDevice *i2cdev = (QI2CDevice *)obj;
-
-    value = qmp_tmp105_get_temperature(TMP105_TEST_ID);
-    g_assert_cmpuint(value, ==, 0);
-
-    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
-    g_assert_cmphex(value, ==, 0);
-
-    qmp_tmp105_set_temperature(TMP105_TEST_ID, 20000);
-    value = qmp_tmp105_get_temperature(TMP105_TEST_ID);
-    g_assert_cmpuint(value, ==, 20000);
-
-    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
-    g_assert_cmphex(value, ==, 0x1400);
-
-    qmp_tmp105_set_temperature(TMP105_TEST_ID, 20938); /* 20 + 15/16 */
-    value = qmp_tmp105_get_temperature(TMP105_TEST_ID);
-    g_assert_cmpuint(value, >=, 20938 - TMP105_PRECISION/2);
-    g_assert_cmpuint(value, <, 20938 + TMP105_PRECISION/2);
-
-    /* Set config */
-    i2c_set8(i2cdev, TMP105_REG_CONFIG, 0x60);
-    value = i2c_get8(i2cdev, TMP105_REG_CONFIG);
-    g_assert_cmphex(value, ==, 0x60);
-
-    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
-    g_assert_cmphex(value, ==, 0x14f0);
-
-    /* Set precision to 9, 10, 11 bits.  */
-    i2c_set8(i2cdev, TMP105_REG_CONFIG, 0x00);
-    g_assert_cmphex(i2c_get8(i2cdev, TMP105_REG_CONFIG), ==, 0x00);
-    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
-    g_assert_cmphex(value, ==, 0x1480);
-
-    i2c_set8(i2cdev, TMP105_REG_CONFIG, 0x20);
-    g_assert_cmphex(i2c_get8(i2cdev, TMP105_REG_CONFIG), ==, 0x20);
-    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
-    g_assert_cmphex(value, ==, 0x14c0);
-
-    i2c_set8(i2cdev, TMP105_REG_CONFIG, 0x40);
-    g_assert_cmphex(i2c_get8(i2cdev, TMP105_REG_CONFIG), ==, 0x40);
-    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
-    g_assert_cmphex(value, ==, 0x14e0);
-
-    /* stored precision remains the same */
-    value = qmp_tmp105_get_temperature(TMP105_TEST_ID);
-    g_assert_cmpuint(value, >=, 20938 - TMP105_PRECISION/2);
-    g_assert_cmpuint(value, <, 20938 + TMP105_PRECISION/2);
-
-    i2c_set8(i2cdev, TMP105_REG_CONFIG, 0x60);
-    g_assert_cmphex(i2c_get8(i2cdev, TMP105_REG_CONFIG), ==, 0x60);
-    value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE);
-    g_assert_cmphex(value, ==, 0x14f0);
-
-    i2c_set16(i2cdev, TMP105_REG_T_LOW, 0x1234);
-    g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_LOW), ==, 0x1234);
-    i2c_set16(i2cdev, TMP105_REG_T_HIGH, 0x4231);
-    g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_HIGH), ==, 0x4231);
-}
-
-static void tmp105_register_nodes(void)
-{
-    QOSGraphEdgeOptions opts = {
-        .extra_device_opts = "id=" TMP105_TEST_ID ",address=0x49"
-    };
-    add_qi2c_address(&opts, &(QI2CAddress) { 0x49 });
-
-    qos_node_create_driver("tmp105", i2c_device_create);
-    qos_node_consumes("tmp105", "i2c-bus", &opts);
-
-    qos_add_test("tx-rx", "tmp105", send_and_receive, NULL);
-}
-libqos_init(tmp105_register_nodes);
diff --git a/tests/tpm-crb-swtpm-test.c b/tests/tpm-crb-swtpm-test.c
deleted file mode 100644 (file)
index 2c4fb8a..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * QTest testcase for TPM CRB talking to external swtpm and swtpm migration
- *
- * Copyright (c) 2018 IBM Corporation
- *  with parts borrowed from migration-test.c that is:
- *     Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
- *
- * Authors:
- *   Stefan Berger <[email protected]>
- *
- * 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 "libqtest.h"
-#include "qemu/module.h"
-#include "tpm-tests.h"
-
-typedef struct TestState {
-    char *src_tpm_path;
-    char *dst_tpm_path;
-    char *uri;
-} TestState;
-
-static void tpm_crb_swtpm_test(const void *data)
-{
-    const TestState *ts = data;
-
-    tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_transfer, "tpm-crb");
-}
-
-static void tpm_crb_swtpm_migration_test(const void *data)
-{
-    const TestState *ts = data;
-
-    tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri,
-                                  tpm_util_crb_transfer, "tpm-crb");
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-    TestState ts = { 0 };
-
-    ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-crb-swtpm-test.XXXXXX", NULL);
-    ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-crb-swtpm-test.XXXXXX", NULL);
-    ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path);
-
-    module_call_init(MODULE_INIT_QOM);
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_data_func("/tpm/crb-swtpm/test", &ts, tpm_crb_swtpm_test);
-    qtest_add_data_func("/tpm/crb-swtpm-migration/test", &ts,
-                        tpm_crb_swtpm_migration_test);
-    ret = g_test_run();
-
-    g_rmdir(ts.dst_tpm_path);
-    g_free(ts.dst_tpm_path);
-    g_rmdir(ts.src_tpm_path);
-    g_free(ts.src_tpm_path);
-    g_free(ts.uri);
-
-    return ret;
-}
diff --git a/tests/tpm-crb-test.c b/tests/tpm-crb-test.c
deleted file mode 100644 (file)
index 632fb7f..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * QTest testcase for TPM CRB
- *
- * Copyright (c) 2018 Red Hat, Inc.
- *
- * Authors:
- *   Marc-André Lureau <[email protected]>
- *
- * 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 "hw/acpi/tpm.h"
-#include "io/channel-socket.h"
-#include "libqtest-single.h"
-#include "qemu/module.h"
-#include "tpm-emu.h"
-
-#define TPM_CMD "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"
-
-static void tpm_crb_test(const void *data)
-{
-    const TestState *s = data;
-    uint32_t intfid = readl(TPM_CRB_ADDR_BASE + A_CRB_INTF_ID);
-    uint32_t csize = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_SIZE);
-    uint64_t caddr = readq(TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR);
-    uint32_t rsize = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_SIZE);
-    uint64_t raddr = readq(TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR);
-    uint8_t locstate = readb(TPM_CRB_ADDR_BASE + A_CRB_LOC_STATE);
-    uint32_t locctrl = readl(TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL);
-    uint32_t locsts = readl(TPM_CRB_ADDR_BASE + A_CRB_LOC_STS);
-    uint32_t sts = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
-
-    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, InterfaceType), ==, 1);
-    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, InterfaceVersion), ==, 1);
-    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapLocality), ==, 0);
-    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapCRBIdleBypass), ==, 0);
-    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapDataXferSizeSupport),
-                    ==, 3);
-    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapFIFO), ==, 0);
-    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapCRB), ==, 1);
-    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, InterfaceSelector), ==, 1);
-    g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, RID), ==, 0);
-
-    g_assert_cmpint(csize, >=, 128);
-    g_assert_cmpint(rsize, >=, 128);
-    g_assert_cmpint(caddr, >, TPM_CRB_ADDR_BASE);
-    g_assert_cmpint(raddr, >, TPM_CRB_ADDR_BASE);
-
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmEstablished), ==, 1);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, locAssigned), ==, 0);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, activeLocality), ==, 0);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, reserved), ==, 0);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmRegValidSts), ==, 1);
-
-    g_assert_cmpint(locctrl, ==, 0);
-
-    g_assert_cmpint(FIELD_EX32(locsts, CRB_LOC_STS, Granted), ==, 0);
-    g_assert_cmpint(FIELD_EX32(locsts, CRB_LOC_STS, beenSeized), ==, 0);
-
-    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmIdle), ==, 1);
-    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmSts), ==, 0);
-
-    /* request access to locality 0 */
-    writeb(TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 1);
-
-    /* granted bit must be set now */
-    locsts = readl(TPM_CRB_ADDR_BASE + A_CRB_LOC_STS);
-    g_assert_cmpint(FIELD_EX32(locsts, CRB_LOC_STS, Granted), ==, 1);
-    g_assert_cmpint(FIELD_EX32(locsts, CRB_LOC_STS, beenSeized), ==, 0);
-
-    /* we must have an assigned locality */
-    locstate = readb(TPM_CRB_ADDR_BASE + A_CRB_LOC_STATE);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmEstablished), ==, 1);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, locAssigned), ==, 1);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, activeLocality), ==, 0);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, reserved), ==, 0);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmRegValidSts), ==, 1);
-
-    /* set into ready state */
-    writel(TPM_CRB_ADDR_BASE + A_CRB_CTRL_REQ, 1);
-
-    /* TPM must not be in the idle state */
-    sts = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
-    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmIdle), ==, 0);
-    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmSts), ==, 0);
-
-    memwrite(caddr, TPM_CMD, sizeof(TPM_CMD));
-
-    uint32_t start = 1;
-    uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
-    writel(TPM_CRB_ADDR_BASE + A_CRB_CTRL_START, start);
-    do {
-        start = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
-        if ((start & 1) == 0) {
-            break;
-        }
-    } while (g_get_monotonic_time() < end_time);
-    start = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
-    g_assert_cmpint(start & 1, ==, 0);
-
-    /* TPM must still not be in the idle state */
-    sts = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
-    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmIdle), ==, 0);
-    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmSts), ==, 0);
-
-    struct tpm_hdr tpm_msg;
-    memread(raddr, &tpm_msg, sizeof(tpm_msg));
-    g_assert_cmpmem(&tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg));
-
-    /* set TPM into idle state */
-    writel(TPM_CRB_ADDR_BASE + A_CRB_CTRL_REQ, 2);
-
-    /* idle state must be indicated now */
-    sts = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
-    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmIdle), ==, 1);
-    g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmSts), ==, 0);
-
-    /* relinquish locality */
-    writel(TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 2);
-
-    /* Granted flag must be cleared */
-    sts = readl(TPM_CRB_ADDR_BASE + A_CRB_LOC_STS);
-    g_assert_cmpint(FIELD_EX32(sts, CRB_LOC_STS, Granted), ==, 0);
-    g_assert_cmpint(FIELD_EX32(sts, CRB_LOC_STS, beenSeized), ==, 0);
-
-    /* no locality may be assigned */
-    locstate = readb(TPM_CRB_ADDR_BASE + A_CRB_LOC_STATE);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmEstablished), ==, 1);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, locAssigned), ==, 0);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, activeLocality), ==, 0);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, reserved), ==, 0);
-    g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmRegValidSts), ==, 1);
-
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-    char *args, *tmp_path = g_dir_make_tmp("qemu-tpm-crb-test.XXXXXX", NULL);
-    GThread *thread;
-    TestState test;
-
-    module_call_init(MODULE_INIT_QOM);
-    g_test_init(&argc, &argv, NULL);
-
-    test.addr = g_new0(SocketAddress, 1);
-    test.addr->type = SOCKET_ADDRESS_TYPE_UNIX;
-    test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL);
-    g_mutex_init(&test.data_mutex);
-    g_cond_init(&test.data_cond);
-    test.data_cond_signal = false;
-
-    thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test);
-    tpm_emu_test_wait_cond(&test);
-
-    args = g_strdup_printf(
-        "-chardev socket,id=chr,path=%s "
-        "-tpmdev emulator,id=dev,chardev=chr "
-        "-device tpm-crb,tpmdev=dev",
-        test.addr->u.q_unix.path);
-    qtest_start(args);
-
-    qtest_add_data_func("/tpm-crb/test", &test, tpm_crb_test);
-    ret = g_test_run();
-
-    qtest_end();
-
-    g_thread_join(thread);
-    g_unlink(test.addr->u.q_unix.path);
-    qapi_free_SocketAddress(test.addr);
-    g_rmdir(tmp_path);
-    g_free(tmp_path);
-    g_free(args);
-    return ret;
-}
diff --git a/tests/tpm-emu.c b/tests/tpm-emu.c
deleted file mode 100644 (file)
index c43ac4a..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Minimal TPM emulator for TPM test cases
- *
- * Copyright (c) 2018 Red Hat, Inc.
- *
- * Authors:
- *   Marc-André Lureau <[email protected]>
- *
- * 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 "hw/tpm/tpm_ioctl.h"
-#include "io/channel-socket.h"
-#include "qapi/error.h"
-#include "tpm-emu.h"
-
-void tpm_emu_test_wait_cond(TestState *s)
-{
-    gint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
-
-    g_mutex_lock(&s->data_mutex);
-
-    if (!s->data_cond_signal &&
-        !g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
-        g_assert_not_reached();
-    }
-
-    s->data_cond_signal = false;
-
-    g_mutex_unlock(&s->data_mutex);
-}
-
-static void *tpm_emu_tpm_thread(void *data)
-{
-    TestState *s = data;
-    QIOChannel *ioc = s->tpm_ioc;
-
-    s->tpm_msg = g_new(struct tpm_hdr, 1);
-    while (true) {
-        int minhlen = sizeof(s->tpm_msg->tag) + sizeof(s->tpm_msg->len);
-
-        if (!qio_channel_read(ioc, (char *)s->tpm_msg, minhlen, &error_abort)) {
-            break;
-        }
-        s->tpm_msg->tag = be16_to_cpu(s->tpm_msg->tag);
-        s->tpm_msg->len = be32_to_cpu(s->tpm_msg->len);
-        g_assert_cmpint(s->tpm_msg->len, >=, minhlen);
-        g_assert_cmpint(s->tpm_msg->tag, ==, TPM2_ST_NO_SESSIONS);
-
-        s->tpm_msg = g_realloc(s->tpm_msg, s->tpm_msg->len);
-        qio_channel_read(ioc, (char *)&s->tpm_msg->code,
-                         s->tpm_msg->len - minhlen, &error_abort);
-        s->tpm_msg->code = be32_to_cpu(s->tpm_msg->code);
-
-        /* reply error */
-        s->tpm_msg->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
-        s->tpm_msg->len = cpu_to_be32(sizeof(struct tpm_hdr));
-        s->tpm_msg->code = cpu_to_be32(TPM_RC_FAILURE);
-        qio_channel_write(ioc, (char *)s->tpm_msg, be32_to_cpu(s->tpm_msg->len),
-                          &error_abort);
-    }
-
-    g_free(s->tpm_msg);
-    s->tpm_msg = NULL;
-    object_unref(OBJECT(s->tpm_ioc));
-    return NULL;
-}
-
-void *tpm_emu_ctrl_thread(void *data)
-{
-    TestState *s = data;
-    QIOChannelSocket *lioc = qio_channel_socket_new();
-    QIOChannel *ioc;
-
-    qio_channel_socket_listen_sync(lioc, s->addr, 1, &error_abort);
-
-    g_mutex_lock(&s->data_mutex);
-    s->data_cond_signal = true;
-    g_mutex_unlock(&s->data_mutex);
-    g_cond_signal(&s->data_cond);
-
-    qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
-    ioc = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
-    g_assert(ioc);
-
-    {
-        uint32_t cmd = 0;
-        struct iovec iov = { .iov_base = &cmd, .iov_len = sizeof(cmd) };
-        int *pfd = NULL;
-        size_t nfd = 0;
-
-        qio_channel_readv_full(ioc, &iov, 1, &pfd, &nfd, &error_abort);
-        cmd = be32_to_cpu(cmd);
-        g_assert_cmpint(cmd, ==, CMD_SET_DATAFD);
-        g_assert_cmpint(nfd, ==, 1);
-        s->tpm_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(*pfd, &error_abort));
-        g_free(pfd);
-
-        cmd = 0;
-        qio_channel_write(ioc, (char *)&cmd, sizeof(cmd), &error_abort);
-
-        s->emu_tpm_thread = g_thread_new(NULL, tpm_emu_tpm_thread, s);
-    }
-
-    while (true) {
-        uint32_t cmd;
-        ssize_t ret;
-
-        ret = qio_channel_read(ioc, (char *)&cmd, sizeof(cmd), NULL);
-        if (ret <= 0) {
-            break;
-        }
-
-        cmd = be32_to_cpu(cmd);
-        switch (cmd) {
-        case CMD_GET_CAPABILITY: {
-            ptm_cap cap = cpu_to_be64(0x3fff);
-            qio_channel_write(ioc, (char *)&cap, sizeof(cap), &error_abort);
-            break;
-        }
-        case CMD_INIT: {
-            ptm_init init;
-            qio_channel_read(ioc, (char *)&init.u.req, sizeof(init.u.req),
-                              &error_abort);
-            init.u.resp.tpm_result = 0;
-            qio_channel_write(ioc, (char *)&init.u.resp, sizeof(init.u.resp),
-                              &error_abort);
-            break;
-        }
-        case CMD_SHUTDOWN: {
-            ptm_res res = 0;
-            qio_channel_write(ioc, (char *)&res, sizeof(res), &error_abort);
-            /* the tpm data thread is expected to finish now */
-            g_thread_join(s->emu_tpm_thread);
-            break;
-        }
-        case CMD_STOP: {
-            ptm_res res = 0;
-            qio_channel_write(ioc, (char *)&res, sizeof(res), &error_abort);
-            break;
-        }
-        case CMD_SET_BUFFERSIZE: {
-            ptm_setbuffersize sbs;
-            qio_channel_read(ioc, (char *)&sbs.u.req, sizeof(sbs.u.req),
-                             &error_abort);
-            sbs.u.resp.buffersize = sbs.u.req.buffersize ?: cpu_to_be32(4096);
-            sbs.u.resp.tpm_result = 0;
-            sbs.u.resp.minsize = cpu_to_be32(128);
-            sbs.u.resp.maxsize = cpu_to_be32(4096);
-            qio_channel_write(ioc, (char *)&sbs.u.resp, sizeof(sbs.u.resp),
-                              &error_abort);
-            break;
-        }
-        case CMD_SET_LOCALITY: {
-            ptm_loc loc;
-            /* Note: this time it's not u.req / u.resp... */
-            qio_channel_read(ioc, (char *)&loc, sizeof(loc), &error_abort);
-            g_assert_cmpint(loc.u.req.loc, ==, 0);
-            loc.u.resp.tpm_result = 0;
-            qio_channel_write(ioc, (char *)&loc, sizeof(loc), &error_abort);
-            break;
-        }
-        case CMD_GET_TPMESTABLISHED: {
-            ptm_est est = {
-                .u.resp.bit = 0,
-            };
-            qio_channel_write(ioc, (char *)&est, sizeof(est), &error_abort);
-            break;
-        }
-        default:
-            g_debug("unimplemented %u", cmd);
-            g_assert_not_reached();
-        }
-    }
-
-    object_unref(OBJECT(ioc));
-    object_unref(OBJECT(lioc));
-    return NULL;
-}
diff --git a/tests/tpm-emu.h b/tests/tpm-emu.h
deleted file mode 100644 (file)
index a4f1d64..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Minimal TPM emulator for TPM test cases
- *
- * Copyright (c) 2018 Red Hat, Inc.
- *
- * Authors:
- *   Marc-André Lureau <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef TESTS_TPM_EMU_H
-#define TESTS_TPM_EMU_H
-
-#define TPM_RC_FAILURE 0x101
-#define TPM2_ST_NO_SESSIONS 0x8001
-
-struct tpm_hdr {
-    uint16_t tag;
-    uint32_t len;
-    uint32_t code; /*ordinal/error */
-    char buffer[];
-} QEMU_PACKED;
-
-typedef struct TestState {
-    GMutex data_mutex;
-    GCond data_cond;
-    bool data_cond_signal;
-    SocketAddress *addr;
-    QIOChannel *tpm_ioc;
-    GThread *emu_tpm_thread;
-    struct tpm_hdr *tpm_msg;
-} TestState;
-
-void tpm_emu_test_wait_cond(TestState *s);
-void *tpm_emu_ctrl_thread(void *data);
-
-#endif /* TESTS_TPM_EMU_H */
diff --git a/tests/tpm-tests.c b/tests/tpm-tests.c
deleted file mode 100644 (file)
index 6e45a0b..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * QTest TPM commont test code
- *
- * Copyright (c) 2018 IBM Corporation
- * Copyright (c) 2018 Red Hat, Inc.
- *
- * Authors:
- *   Stefan Berger <[email protected]>
- *   Marc-André Lureau <[email protected]>
- *
- * 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 "libqtest-single.h"
-#include "tpm-tests.h"
-
-static bool
-tpm_test_swtpm_skip(void)
-{
-    if (!tpm_util_swtpm_has_tpm2()) {
-        g_test_skip("swtpm not in PATH or missing --tpm2 support");
-        return true;
-    }
-
-    return false;
-}
-
-void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
-                         const char *ifmodel)
-{
-    char *args = NULL;
-    QTestState *s;
-    SocketAddress *addr = NULL;
-    gboolean succ;
-    GPid swtpm_pid;
-    GError *error = NULL;
-
-    if (tpm_test_swtpm_skip()) {
-        return;
-    }
-
-    succ = tpm_util_swtpm_start(src_tpm_path, &swtpm_pid, &addr, &error);
-    g_assert_true(succ);
-
-    args = g_strdup_printf(
-        "-chardev socket,id=chr,path=%s "
-        "-tpmdev emulator,id=dev,chardev=chr "
-        "-device %s,tpmdev=dev",
-        addr->u.q_unix.path, ifmodel);
-
-    s = qtest_start(args);
-    g_free(args);
-
-    tpm_util_startup(s, tx);
-    tpm_util_pcrextend(s, tx);
-
-    unsigned char tpm_pcrread_resp[] =
-        "\x80\x01\x00\x00\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00"
-        "\x00\x01\x00\x0b\x03\x00\x04\x00\x00\x00\x00\x01\x00\x20\xf6\x85"
-        "\x98\xe5\x86\x8d\xe6\x8b\x97\x29\x99\x60\xf2\x71\x7d\x17\x67\x89"
-        "\xa4\x2f\x9a\xae\xa8\xc7\xb7\xaa\x79\xa8\x62\x56\xc1\xde";
-    tpm_util_pcrread(s, tx, tpm_pcrread_resp,
-                     sizeof(tpm_pcrread_resp));
-
-    qtest_end();
-    tpm_util_swtpm_kill(swtpm_pid);
-
-    if (addr) {
-        g_unlink(addr->u.q_unix.path);
-        qapi_free_SocketAddress(addr);
-    }
-}
-
-void tpm_test_swtpm_migration_test(const char *src_tpm_path,
-                                   const char *dst_tpm_path,
-                                   const char *uri, tx_func *tx,
-                                   const char *ifmodel)
-{
-    gboolean succ;
-    GPid src_tpm_pid, dst_tpm_pid;
-    SocketAddress *src_tpm_addr = NULL, *dst_tpm_addr = NULL;
-    GError *error = NULL;
-    QTestState *src_qemu, *dst_qemu;
-
-    if (tpm_test_swtpm_skip()) {
-        return;
-    }
-
-    succ = tpm_util_swtpm_start(src_tpm_path, &src_tpm_pid,
-                                &src_tpm_addr, &error);
-    g_assert_true(succ);
-
-    succ = tpm_util_swtpm_start(dst_tpm_path, &dst_tpm_pid,
-                                &dst_tpm_addr, &error);
-    g_assert_true(succ);
-
-    tpm_util_migration_start_qemu(&src_qemu, &dst_qemu,
-                                  src_tpm_addr, dst_tpm_addr, uri,
-                                  ifmodel);
-
-    tpm_util_startup(src_qemu, tx);
-    tpm_util_pcrextend(src_qemu, tx);
-
-    unsigned char tpm_pcrread_resp[] =
-        "\x80\x01\x00\x00\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00"
-        "\x00\x01\x00\x0b\x03\x00\x04\x00\x00\x00\x00\x01\x00\x20\xf6\x85"
-        "\x98\xe5\x86\x8d\xe6\x8b\x97\x29\x99\x60\xf2\x71\x7d\x17\x67\x89"
-        "\xa4\x2f\x9a\xae\xa8\xc7\xb7\xaa\x79\xa8\x62\x56\xc1\xde";
-    tpm_util_pcrread(src_qemu, tx, tpm_pcrread_resp,
-                     sizeof(tpm_pcrread_resp));
-
-    tpm_util_migrate(src_qemu, uri);
-    tpm_util_wait_for_migration_complete(src_qemu);
-
-    tpm_util_pcrread(dst_qemu, tx, tpm_pcrread_resp,
-                     sizeof(tpm_pcrread_resp));
-
-    qtest_quit(dst_qemu);
-    qtest_quit(src_qemu);
-
-    tpm_util_swtpm_kill(dst_tpm_pid);
-    if (dst_tpm_addr) {
-        g_unlink(dst_tpm_addr->u.q_unix.path);
-        qapi_free_SocketAddress(dst_tpm_addr);
-    }
-
-    tpm_util_swtpm_kill(src_tpm_pid);
-    if (src_tpm_addr) {
-        g_unlink(src_tpm_addr->u.q_unix.path);
-        qapi_free_SocketAddress(src_tpm_addr);
-    }
-}
diff --git a/tests/tpm-tests.h b/tests/tpm-tests.h
deleted file mode 100644 (file)
index b97688f..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * QTest TPM commont test code
- *
- * Copyright (c) 2018 IBM Corporation
- *
- * Authors:
- *   Stefan Berger <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef TESTS_TPM_TESTS_H
-#define TESTS_TPM_TESTS_H
-
-#include "tpm-util.h"
-
-void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
-                         const char *ifmodel);
-
-void tpm_test_swtpm_migration_test(const char *src_tpm_path,
-                                   const char *dst_tpm_path,
-                                   const char *uri, tx_func *tx,
-                                   const char *ifmodel);
-
-#endif /* TESTS_TPM_TESTS_H */
diff --git a/tests/tpm-tis-swtpm-test.c b/tests/tpm-tis-swtpm-test.c
deleted file mode 100644 (file)
index 9f58a3a..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * QTest testcase for TPM TIS talking to external swtpm and swtpm migration
- *
- * Copyright (c) 2018 IBM Corporation
- *  with parts borrowed from migration-test.c that is:
- *     Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
- *
- * Authors:
- *   Stefan Berger <[email protected]>
- *
- * 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 "libqtest.h"
-#include "qemu/module.h"
-#include "tpm-tests.h"
-
-typedef struct TestState {
-    char *src_tpm_path;
-    char *dst_tpm_path;
-    char *uri;
-} TestState;
-
-static void tpm_tis_swtpm_test(const void *data)
-{
-    const TestState *ts = data;
-
-    tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, "tpm-tis");
-}
-
-static void tpm_tis_swtpm_migration_test(const void *data)
-{
-    const TestState *ts = data;
-
-    tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri,
-                                  tpm_util_tis_transfer, "tpm-tis");
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-    TestState ts = { 0 };
-
-    ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-tis-swtpm-test.XXXXXX", NULL);
-    ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-tis-swtpm-test.XXXXXX", NULL);
-    ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path);
-
-    module_call_init(MODULE_INIT_QOM);
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_data_func("/tpm/tis-swtpm/test", &ts, tpm_tis_swtpm_test);
-    qtest_add_data_func("/tpm/tis-swtpm-migration/test", &ts,
-                        tpm_tis_swtpm_migration_test);
-    ret = g_test_run();
-
-    g_rmdir(ts.dst_tpm_path);
-    g_free(ts.dst_tpm_path);
-    g_rmdir(ts.src_tpm_path);
-    g_free(ts.src_tpm_path);
-    g_free(ts.uri);
-
-    return ret;
-}
diff --git a/tests/tpm-tis-test.c b/tests/tpm-tis-test.c
deleted file mode 100644 (file)
index dcf30e0..0000000
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * QTest testcase for TPM TIS
- *
- * Copyright (c) 2018 Red Hat, Inc.
- * Copyright (c) 2018 IBM Corporation
- *
- * Authors:
- *   Marc-André Lureau <[email protected]>
- *   Stefan Berger <[email protected]>
- *
- * 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 "hw/acpi/tpm.h"
-#include "io/channel-socket.h"
-#include "libqtest-single.h"
-#include "qemu/module.h"
-#include "tpm-emu.h"
-
-#define TIS_REG(LOCTY, REG) \
-    (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG)
-
-#define DEBUG_TIS_TEST 0
-
-#define DPRINTF(fmt, ...) do { \
-    if (DEBUG_TIS_TEST) { \
-        printf(fmt, ## __VA_ARGS__); \
-    } \
-} while (0)
-
-#define DPRINTF_ACCESS \
-    DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \
-            __func__, __LINE__, locty, l, access, pending_request_flag)
-
-#define DPRINTF_STS \
-    DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts)
-
-static const uint8_t TPM_CMD[12] =
-    "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
-
-static void tpm_tis_test_check_localities(const void *data)
-{
-    uint8_t locty;
-    uint8_t access;
-    uint32_t ifaceid;
-    uint32_t capability;
-    uint32_t didvid;
-    uint32_t rid;
-
-    for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) {
-        access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
-        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-        capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY));
-        g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0);
-
-        ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID));
-        g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0);
-
-        didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID));
-        g_assert_cmpint(didvid, !=, 0);
-        g_assert_cmpint(didvid, !=, 0xffffffff);
-
-        rid = readl(TIS_REG(locty, TPM_TIS_REG_RID));
-        g_assert_cmpint(rid, !=, 0);
-        g_assert_cmpint(rid, !=, 0xffffffff);
-    }
-}
-
-static void tpm_tis_test_check_access_reg(const void *data)
-{
-    uint8_t locty;
-    uint8_t access;
-
-    /* do not test locality 4 (hw only) */
-    for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) {
-        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
-        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-        /* request use of locality */
-        writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
-
-        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
-        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                    TPM_TIS_ACCESS_ACTIVE_LOCALITY |
-                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-        /* release access */
-        writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS),
-               TPM_TIS_ACCESS_ACTIVE_LOCALITY);
-        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
-        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-    }
-}
-
-/*
- * Test case for seizing access by a higher number locality
- */
-static void tpm_tis_test_check_access_reg_seize(const void *data)
-{
-    int locty, l;
-    uint8_t access;
-    uint8_t pending_request_flag;
-
-    /* do not test locality 4 (hw only) */
-    for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) {
-        pending_request_flag = 0;
-
-        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
-        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-        /* request use of locality */
-        writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
-        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
-        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                    TPM_TIS_ACCESS_ACTIVE_LOCALITY |
-                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-        /* lower localities cannot seize access */
-        for (l = 0; l < locty; l++) {
-            /* lower locality is not active */
-            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
-            DPRINTF_ACCESS;
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        pending_request_flag |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-            /* try to request use from 'l' */
-            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
-
-            /* requesting use from 'l' was not possible;
-               we must see REQUEST_USE and possibly PENDING_REQUEST */
-            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
-            DPRINTF_ACCESS;
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        TPM_TIS_ACCESS_REQUEST_USE |
-                                        pending_request_flag |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-            /* locality 'locty' must be unchanged;
-               we must see PENDING_REQUEST */
-            access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        TPM_TIS_ACCESS_ACTIVE_LOCALITY |
-                                        TPM_TIS_ACCESS_PENDING_REQUEST |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-            /* try to seize from 'l' */
-            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE);
-            /* seize from 'l' was not possible */
-            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
-            DPRINTF_ACCESS;
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        TPM_TIS_ACCESS_REQUEST_USE |
-                                        pending_request_flag |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-            /* locality 'locty' must be unchanged */
-            access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        TPM_TIS_ACCESS_ACTIVE_LOCALITY |
-                                        TPM_TIS_ACCESS_PENDING_REQUEST |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-            /* on the next loop we will have a PENDING_REQUEST flag
-               set for locality 'l' */
-            pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST;
-        }
-
-        /* higher localities can 'seize' access but not 'request use';
-           note: this will activate first l+1, then l+2 etc. */
-        for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
-            /* try to 'request use' from 'l' */
-            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
-
-            /* requesting use from 'l' was not possible; we should see
-               REQUEST_USE and may see PENDING_REQUEST */
-            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
-            DPRINTF_ACCESS;
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        TPM_TIS_ACCESS_REQUEST_USE |
-                                        pending_request_flag |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-            /* locality 'l-1' must be unchanged; we should always
-               see PENDING_REQUEST from 'l' requesting access */
-            access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
-            DPRINTF_ACCESS;
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        TPM_TIS_ACCESS_ACTIVE_LOCALITY |
-                                        TPM_TIS_ACCESS_PENDING_REQUEST |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-            /* try to seize from 'l' */
-            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE);
-
-            /* seize from 'l' was possible */
-            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
-            DPRINTF_ACCESS;
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        TPM_TIS_ACCESS_ACTIVE_LOCALITY |
-                                        pending_request_flag |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-            /* l - 1 should show that it has BEEN_SEIZED */
-            access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
-            DPRINTF_ACCESS;
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        TPM_TIS_ACCESS_BEEN_SEIZED |
-                                        pending_request_flag |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-            /* clear the BEEN_SEIZED flag and make sure it's gone */
-            writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS),
-                   TPM_TIS_ACCESS_BEEN_SEIZED);
-
-            access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        pending_request_flag |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-        }
-
-        /* PENDING_REQUEST will not be set if locty = 0 since all localities
-           were active; in case of locty = 1, locality 0 will be active
-           but no PENDING_REQUEST anywhere */
-        if (locty <= 1) {
-            pending_request_flag = 0;
-        }
-
-        /* release access from l - 1; this activates locty - 1 */
-        l--;
-
-        access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
-        DPRINTF_ACCESS;
-
-        DPRINTF("%s: %d: relinquishing control on l = %d\n",
-                __func__, __LINE__, l);
-        writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
-               TPM_TIS_ACCESS_ACTIVE_LOCALITY);
-
-        access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
-        DPRINTF_ACCESS;
-        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                    pending_request_flag |
-                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-        for (l = locty - 1; l >= 0; l--) {
-            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
-            DPRINTF_ACCESS;
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        TPM_TIS_ACCESS_ACTIVE_LOCALITY |
-                                        pending_request_flag |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-            /* release this locality */
-            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
-                   TPM_TIS_ACCESS_ACTIVE_LOCALITY);
-
-            if (l == 1) {
-                pending_request_flag = 0;
-            }
-        }
-
-        /* no locality may be active now */
-        for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
-            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
-            DPRINTF_ACCESS;
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-        }
-    }
-}
-
-/*
- * Test case for getting access when higher number locality relinquishes access
- */
-static void tpm_tis_test_check_access_reg_release(const void *data)
-{
-    int locty, l;
-    uint8_t access;
-    uint8_t pending_request_flag;
-
-    /* do not test locality 4 (hw only) */
-    for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) {
-        pending_request_flag = 0;
-
-        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
-        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-        /* request use of locality */
-        writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
-        access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
-        g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                    TPM_TIS_ACCESS_ACTIVE_LOCALITY |
-                                    TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-        /* request use of all other localities */
-        for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
-            if (l == locty) {
-                continue;
-            }
-            /* request use of locality 'l' -- we MUST see REQUEST USE and
-               may see PENDING_REQUEST */
-            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
-            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
-            DPRINTF_ACCESS;
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        TPM_TIS_ACCESS_REQUEST_USE |
-                                        pending_request_flag |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-            pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST;
-        }
-        /* release locality 'locty' */
-        writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS),
-               TPM_TIS_ACCESS_ACTIVE_LOCALITY);
-        /* highest locality should now be active; release it and make sure the
-           next higest locality is active afterwards */
-        for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) {
-            if (l == locty) {
-                continue;
-            }
-            /* 'l' should be active now */
-            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
-            DPRINTF_ACCESS;
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        TPM_TIS_ACCESS_ACTIVE_LOCALITY |
-                                        pending_request_flag |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-            /* 'l' relinquishes access */
-            writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
-                   TPM_TIS_ACCESS_ACTIVE_LOCALITY);
-            access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
-            DPRINTF_ACCESS;
-            if (l == 1 || (locty <= 1 && l == 2)) {
-                pending_request_flag = 0;
-            }
-            g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                        pending_request_flag |
-                                        TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-        }
-    }
-}
-
-/*
- * Test case for transmitting packets
- */
-static void tpm_tis_test_check_transmit(const void *data)
-{
-    const TestState *s = data;
-    uint8_t access;
-    uint32_t sts;
-    uint16_t bcount;
-    size_t i;
-
-    /* request use of locality 0 */
-    writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
-    access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
-    g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
-                                TPM_TIS_ACCESS_ACTIVE_LOCALITY |
-                                TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
-    sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
-    DPRINTF_STS;
-
-    g_assert_cmpint(sts & 0xff, ==, 0);
-    g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==,
-                    TPM_TIS_STS_TPM_FAMILY2_0);
-
-    bcount = (sts >> 8) & 0xffff;
-    g_assert_cmpint(bcount, >=, 128);
-
-    writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY);
-    sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
-    DPRINTF_STS;
-    g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY);
-
-    /* transmit command */
-    for (i = 0; i < sizeof(TPM_CMD); i++) {
-        writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]);
-        sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
-        DPRINTF_STS;
-        if (i < sizeof(TPM_CMD) - 1) {
-            g_assert_cmpint(sts & 0xff, ==,
-                            TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
-        } else {
-            g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID);
-        }
-        g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount);
-    }
-    /* start processing */
-    writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO);
-
-    uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND;
-    do {
-        sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
-        if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) {
-            break;
-        }
-    } while (g_get_monotonic_time() < end_time);
-
-    sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
-    DPRINTF_STS;
-    g_assert_cmpint(sts & 0xff, == ,
-                    TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
-    bcount = (sts >> 8) & 0xffff;
-
-    /* read response */
-    uint8_t tpm_msg[sizeof(struct tpm_hdr)];
-    g_assert_cmpint(sizeof(tpm_msg), ==, bcount);
-
-    for (i = 0; i < sizeof(tpm_msg); i++) {
-        tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO));
-        sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
-        DPRINTF_STS;
-        if (sts & TPM_TIS_STS_DATA_AVAILABLE) {
-            g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount);
-        }
-    }
-    g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg));
-
-    /* relinquish use of locality 0 */
-    writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY);
-    access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-    char *args, *tmp_path = g_dir_make_tmp("qemu-tpm-tis-test.XXXXXX", NULL);
-    GThread *thread;
-    TestState test;
-
-    module_call_init(MODULE_INIT_QOM);
-    g_test_init(&argc, &argv, NULL);
-
-    test.addr = g_new0(SocketAddress, 1);
-    test.addr->type = SOCKET_ADDRESS_TYPE_UNIX;
-    test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL);
-    g_mutex_init(&test.data_mutex);
-    g_cond_init(&test.data_cond);
-    test.data_cond_signal = false;
-
-    thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test);
-    tpm_emu_test_wait_cond(&test);
-
-    args = g_strdup_printf(
-        "-chardev socket,id=chr,path=%s "
-        "-tpmdev emulator,id=dev,chardev=chr "
-        "-device tpm-tis,tpmdev=dev",
-        test.addr->u.q_unix.path);
-    qtest_start(args);
-
-    qtest_add_data_func("/tpm-tis/test_check_localities", &test,
-                        tpm_tis_test_check_localities);
-
-    qtest_add_data_func("/tpm-tis/test_check_access_reg", &test,
-                        tpm_tis_test_check_access_reg);
-
-    qtest_add_data_func("/tpm-tis/test_check_access_reg_seize", &test,
-                        tpm_tis_test_check_access_reg_seize);
-
-    qtest_add_data_func("/tpm-tis/test_check_access_reg_release", &test,
-                        tpm_tis_test_check_access_reg_release);
-
-    qtest_add_data_func("/tpm-tis/test_check_transmit", &test,
-                        tpm_tis_test_check_transmit);
-
-    ret = g_test_run();
-
-    qtest_end();
-
-    g_thread_join(thread);
-    g_unlink(test.addr->u.q_unix.path);
-    qapi_free_SocketAddress(test.addr);
-    g_rmdir(tmp_path);
-    g_free(tmp_path);
-    g_free(args);
-    return ret;
-}
diff --git a/tests/tpm-util.c b/tests/tpm-util.c
deleted file mode 100644 (file)
index e08b137..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * QTest TPM utilities
- *
- * Copyright (c) 2018 IBM Corporation
- * Copyright (c) 2018 Red Hat, Inc.
- *
- * Authors:
- *   Stefan Berger <[email protected]>
- *   Marc-André Lureau <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-
-#include "hw/acpi/tpm.h"
-#include "libqtest.h"
-#include "tpm-util.h"
-#include "qapi/qmp/qdict.h"
-
-#define TIS_REG(LOCTY, REG) \
-    (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG)
-
-void tpm_util_crb_transfer(QTestState *s,
-                           const unsigned char *req, size_t req_size,
-                           unsigned char *rsp, size_t rsp_size)
-{
-    uint64_t caddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR);
-    uint64_t raddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR);
-
-    qtest_writeb(s, TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 1);
-
-    qtest_memwrite(s, caddr, req, req_size);
-
-    uint32_t sts, start = 1;
-    uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
-    qtest_writel(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START, start);
-    while (true) {
-        start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
-        if ((start & 1) == 0) {
-            break;
-        }
-        if (g_get_monotonic_time() >= end_time) {
-            break;
-        }
-    };
-    start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
-    g_assert_cmpint(start & 1, ==, 0);
-    sts = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
-    g_assert_cmpint(sts & 1, ==, 0);
-
-    qtest_memread(s, raddr, rsp, rsp_size);
-}
-
-void tpm_util_tis_transfer(QTestState *s,
-                           const unsigned char *req, size_t req_size,
-                           unsigned char *rsp, size_t rsp_size)
-{
-    uint32_t sts;
-    uint16_t bcount;
-    size_t i;
-
-    /* request use of locality 0 */
-    qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
-    qtest_writel(s, TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY);
-
-    sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
-    bcount = (sts >> 8) & 0xffff;
-    g_assert_cmpint(bcount, >=, req_size);
-
-    /* transmit command */
-    for (i = 0; i < req_size; i++) {
-        qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_DATA_FIFO), req[i]);
-    }
-
-    /* start processing */
-    qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO);
-
-    uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND;
-    do {
-        sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
-        if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) {
-            break;
-        }
-    } while (g_get_monotonic_time() < end_time);
-
-    sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
-    bcount = (sts >> 8) & 0xffff;
-
-    memset(rsp, 0, rsp_size);
-    for (i = 0; i < bcount; i++) {
-        rsp[i] = qtest_readb(s, TIS_REG(0, TPM_TIS_REG_DATA_FIFO));
-    }
-
-    /* relinquish use of locality 0 */
-    qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_ACCESS),
-                 TPM_TIS_ACCESS_ACTIVE_LOCALITY);
-}
-
-void tpm_util_startup(QTestState *s, tx_func *tx)
-{
-    unsigned char buffer[1024];
-    unsigned char tpm_startup[] =
-        "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
-    unsigned char tpm_startup_resp[] =
-        "\x80\x01\x00\x00\x00\x0a\x00\x00\x00\x00";
-
-    tx(s, tpm_startup, sizeof(tpm_startup), buffer, sizeof(buffer));
-
-    g_assert_cmpmem(buffer, sizeof(tpm_startup_resp),
-                    tpm_startup_resp, sizeof(tpm_startup_resp));
-}
-
-void tpm_util_pcrextend(QTestState *s, tx_func *tx)
-{
-    unsigned char buffer[1024];
-    unsigned char tpm_pcrextend[] =
-        "\x80\x02\x00\x00\x00\x41\x00\x00\x01\x82\x00\x00\x00\x0a\x00\x00"
-        "\x00\x09\x40\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00"
-        "\x0b\x74\x65\x73\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-        "\x00";
-
-    unsigned char tpm_pcrextend_resp[] =
-        "\x80\x02\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-        "\x01\x00\x00";
-
-    tx(s, tpm_pcrextend, sizeof(tpm_pcrextend), buffer, sizeof(buffer));
-
-    g_assert_cmpmem(buffer, sizeof(tpm_pcrextend_resp),
-                    tpm_pcrextend_resp, sizeof(tpm_pcrextend_resp));
-}
-
-void tpm_util_pcrread(QTestState *s, tx_func *tx,
-                      const unsigned char *exp_resp, size_t exp_resp_size)
-{
-    unsigned char buffer[1024];
-    unsigned char tpm_pcrread[] =
-        "\x80\x01\x00\x00\x00\x14\x00\x00\x01\x7e\x00\x00\x00\x01\x00\x0b"
-        "\x03\x00\x04\x00";
-
-    tx(s, tpm_pcrread, sizeof(tpm_pcrread), buffer, sizeof(buffer));
-
-    g_assert_cmpmem(buffer, exp_resp_size, exp_resp, exp_resp_size);
-}
-
-bool tpm_util_swtpm_has_tpm2(void)
-{
-    bool has_tpm2 = false;
-    char *out = NULL;
-    static const char *argv[] = {
-        "swtpm", "socket", "--help", NULL
-    };
-
-    if (!g_spawn_sync(NULL /* working_dir */,
-                      (char **)argv,
-                      NULL /* envp */,
-                      G_SPAWN_SEARCH_PATH,
-                      NULL /* child_setup */,
-                      NULL /* user_data */,
-                      &out,
-                      NULL /* err */,
-                      NULL /* exit_status */,
-                      NULL)) {
-        return false;
-    }
-
-    if (strstr(out, "--tpm2")) {
-        has_tpm2 = true;
-    }
-
-    g_free(out);
-    return has_tpm2;
-}
-
-gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
-                              SocketAddress **addr, GError **error)
-{
-    char *swtpm_argv_tpmstate = g_strdup_printf("dir=%s", path);
-    char *swtpm_argv_ctrl = g_strdup_printf("type=unixio,path=%s/sock",
-                                            path);
-    gchar *swtpm_argv[] = {
-        g_strdup("swtpm"), g_strdup("socket"),
-        g_strdup("--tpmstate"), swtpm_argv_tpmstate,
-        g_strdup("--ctrl"), swtpm_argv_ctrl,
-        g_strdup("--tpm2"),
-        NULL
-    };
-    gboolean succ;
-    unsigned i;
-
-    *addr = g_new0(SocketAddress, 1);
-    (*addr)->type = SOCKET_ADDRESS_TYPE_UNIX;
-    (*addr)->u.q_unix.path = g_build_filename(path, "sock", NULL);
-
-    succ = g_spawn_async(NULL, swtpm_argv, NULL, G_SPAWN_SEARCH_PATH,
-                         NULL, NULL, pid, error);
-
-    for (i = 0; swtpm_argv[i]; i++) {
-        g_free(swtpm_argv[i]);
-    }
-
-    return succ;
-}
-
-void tpm_util_swtpm_kill(GPid pid)
-{
-    int n;
-
-    if (!pid) {
-        return;
-    }
-
-    g_spawn_close_pid(pid);
-
-    n = kill(pid, 0);
-    if (n < 0) {
-        return;
-    }
-
-    kill(pid, SIGKILL);
-}
-
-void tpm_util_migrate(QTestState *who, const char *uri)
-{
-    QDict *rsp;
-
-    rsp = qtest_qmp(who,
-                    "{ 'execute': 'migrate', 'arguments': { 'uri': %s } }",
-                    uri);
-    g_assert(qdict_haskey(rsp, "return"));
-    qobject_unref(rsp);
-}
-
-void tpm_util_wait_for_migration_complete(QTestState *who)
-{
-    while (true) {
-        QDict *rsp_return;
-        bool completed;
-        const char *status;
-
-        qtest_qmp_send(who, "{ 'execute': 'query-migrate' }");
-        rsp_return = qtest_qmp_receive_success(who, NULL, NULL);
-        status = qdict_get_str(rsp_return, "status");
-        completed = strcmp(status, "completed") == 0;
-        g_assert_cmpstr(status, !=,  "failed");
-        qobject_unref(rsp_return);
-        if (completed) {
-            return;
-        }
-        usleep(1000);
-    }
-}
-
-void tpm_util_migration_start_qemu(QTestState **src_qemu,
-                                   QTestState **dst_qemu,
-                                   SocketAddress *src_tpm_addr,
-                                   SocketAddress *dst_tpm_addr,
-                                   const char *miguri,
-                                   const char *ifmodel)
-{
-    char *src_qemu_args, *dst_qemu_args;
-
-    src_qemu_args = g_strdup_printf(
-        "-chardev socket,id=chr,path=%s "
-        "-tpmdev emulator,id=dev,chardev=chr "
-        "-device %s,tpmdev=dev ",
-        src_tpm_addr->u.q_unix.path, ifmodel);
-
-    *src_qemu = qtest_init(src_qemu_args);
-
-    dst_qemu_args = g_strdup_printf(
-        "-chardev socket,id=chr,path=%s "
-        "-tpmdev emulator,id=dev,chardev=chr "
-        "-device %s,tpmdev=dev "
-        "-incoming %s",
-        dst_tpm_addr->u.q_unix.path,
-        ifmodel, miguri);
-
-    *dst_qemu = qtest_init(dst_qemu_args);
-
-    free(src_qemu_args);
-    free(dst_qemu_args);
-}
diff --git a/tests/tpm-util.h b/tests/tpm-util.h
deleted file mode 100644 (file)
index 5755698..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * QTest TPM utilities
- *
- * Copyright (c) 2018 IBM Corporation
- *
- * Authors:
- *   Stefan Berger <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef TESTS_TPM_UTIL_H
-#define TESTS_TPM_UTIL_H
-
-#include "io/channel-socket.h"
-
-typedef void (tx_func)(QTestState *s,
-                       const unsigned char *req, size_t req_size,
-                       unsigned char *rsp, size_t rsp_size);
-
-void tpm_util_crb_transfer(QTestState *s,
-                           const unsigned char *req, size_t req_size,
-                           unsigned char *rsp, size_t rsp_size);
-void tpm_util_tis_transfer(QTestState *s,
-                           const unsigned char *req, size_t req_size,
-                           unsigned char *rsp, size_t rsp_size);
-
-void tpm_util_startup(QTestState *s, tx_func *tx);
-void tpm_util_pcrextend(QTestState *s, tx_func *tx);
-void tpm_util_pcrread(QTestState *s, tx_func *tx,
-                      const unsigned char *exp_resp, size_t exp_resp_size);
-
-bool tpm_util_swtpm_has_tpm2(void);
-
-gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
-                              SocketAddress **addr, GError **error);
-void tpm_util_swtpm_kill(GPid pid);
-
-void tpm_util_migrate(QTestState *who, const char *uri);
-
-void tpm_util_migration_start_qemu(QTestState **src_qemu,
-                                   QTestState **dst_qemu,
-                                   SocketAddress *src_tpm_addr,
-                                   SocketAddress *dst_tpm_addr,
-                                   const char *miguri,
-                                   const char *ifmodel);
-
-void tpm_util_wait_for_migration_complete(QTestState *who);
-
-#endif /* TESTS_TPM_UTIL_H */
diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c
deleted file mode 100644 (file)
index 5251d53..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * QTest testcase for USB EHCI
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-#include "libqos/pci-pc.h"
-#include "hw/usb/uhci-regs.h"
-#include "hw/usb/ehci-regs.h"
-#include "libqos/usb.h"
-
-static QPCIBus *pcibus;
-static struct qhc uhci1;
-static struct qhc uhci2;
-static struct qhc uhci3;
-static struct qhc ehci1;
-
-/* helpers */
-
-#if 0
-static void uhci_port_update(struct qhc *hc, int port,
-                             uint16_t set, uint16_t clear)
-{
-    void *addr = hc->base + 0x10 + 2 * port;
-    uint16_t value;
-
-    value = qpci_io_readw(hc->dev, addr);
-    value |= set;
-    value &= ~clear;
-    qpci_io_writew(hc->dev, addr, value);
-}
-#endif
-
-static void ehci_port_test(struct qhc *hc, int port, uint32_t expect)
-{
-    uint32_t value = qpci_io_readl(hc->dev, hc->bar, 0x64 + 4 * port);
-    uint16_t mask = ~(PORTSC_CSC | PORTSC_PEDC | PORTSC_OCC);
-
-#if 0
-    fprintf(stderr, "%s: %d, have 0x%08x, want 0x%08x\n",
-            __func__, port, value & mask, expect & mask);
-#endif
-    g_assert((value & mask) == (expect & mask));
-}
-
-/* tests */
-
-static void test_init(void)
-{
-    pcibus = qpci_new_pc(global_qtest, NULL);
-    g_assert(pcibus != NULL);
-
-    qusb_pci_init_one(pcibus, &uhci1, QPCI_DEVFN(0x1d, 0), 4);
-    qusb_pci_init_one(pcibus, &uhci2, QPCI_DEVFN(0x1d, 1), 4);
-    qusb_pci_init_one(pcibus, &uhci3, QPCI_DEVFN(0x1d, 2), 4);
-    qusb_pci_init_one(pcibus, &ehci1, QPCI_DEVFN(0x1d, 7), 0);
-}
-
-static void test_deinit(void)
-{
-    uhci_deinit(&uhci1);
-    uhci_deinit(&uhci2);
-    uhci_deinit(&uhci3);
-    uhci_deinit(&ehci1);
-    qpci_free_pc(pcibus);
-}
-
-static void pci_uhci_port_1(void)
-{
-    g_assert(pcibus != NULL);
-
-    uhci_port_test(&uhci1, 0, UHCI_PORT_CCS); /* usb-tablet  */
-    uhci_port_test(&uhci1, 1, UHCI_PORT_CCS); /* usb-storage */
-    uhci_port_test(&uhci2, 0, 0);
-    uhci_port_test(&uhci2, 1, 0);
-    uhci_port_test(&uhci3, 0, 0);
-    uhci_port_test(&uhci3, 1, 0);
-}
-
-static void pci_ehci_port_1(void)
-{
-    int i;
-
-    g_assert(pcibus != NULL);
-
-    for (i = 0; i < 6; i++) {
-        ehci_port_test(&ehci1, i, PORTSC_POWNER | PORTSC_PPOWER);
-    }
-}
-
-static void pci_ehci_config(void)
-{
-    /* hands over all ports from companion uhci to ehci */
-    qpci_io_writew(ehci1.dev, ehci1.bar, 0x60, 1);
-}
-
-static void pci_uhci_port_2(void)
-{
-    g_assert(pcibus != NULL);
-
-    uhci_port_test(&uhci1, 0, 0); /* usb-tablet,  @ehci */
-    uhci_port_test(&uhci1, 1, 0); /* usb-storage, @ehci */
-    uhci_port_test(&uhci2, 0, 0);
-    uhci_port_test(&uhci2, 1, 0);
-    uhci_port_test(&uhci3, 0, 0);
-    uhci_port_test(&uhci3, 1, 0);
-}
-
-static void pci_ehci_port_2(void)
-{
-    static uint32_t expect[] = {
-        PORTSC_PPOWER | PORTSC_CONNECT, /* usb-tablet  */
-        PORTSC_PPOWER | PORTSC_CONNECT, /* usb-storage */
-        PORTSC_PPOWER,
-        PORTSC_PPOWER,
-        PORTSC_PPOWER,
-        PORTSC_PPOWER,
-    };
-    int i;
-
-    g_assert(pcibus != NULL);
-
-    for (i = 0; i < 6; i++) {
-        ehci_port_test(&ehci1, i, expect[i]);
-    }
-}
-
-static void pci_ehci_port_3_hotplug(void)
-{
-    /* check for presence of hotplugged usb-tablet */
-    g_assert(pcibus != NULL);
-    ehci_port_test(&ehci1, 2, PORTSC_PPOWER | PORTSC_CONNECT);
-}
-
-static void pci_ehci_port_hotplug(void)
-{
-    usb_test_hotplug(global_qtest, "ich9-ehci-1", "3", pci_ehci_port_3_hotplug);
-}
-
-
-int main(int argc, char **argv)
-{
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("/ehci/pci/uhci-port-1", pci_uhci_port_1);
-    qtest_add_func("/ehci/pci/ehci-port-1", pci_ehci_port_1);
-    qtest_add_func("/ehci/pci/ehci-config", pci_ehci_config);
-    qtest_add_func("/ehci/pci/uhci-port-2", pci_uhci_port_2);
-    qtest_add_func("/ehci/pci/ehci-port-2", pci_ehci_port_2);
-    qtest_add_func("/ehci/pci/ehci-port-3-hotplug", pci_ehci_port_hotplug);
-
-    qtest_start("-machine q35 -device ich9-usb-ehci1,bus=pcie.0,addr=1d.7,"
-                "multifunction=on,id=ich9-ehci-1 "
-                "-device ich9-usb-uhci1,bus=pcie.0,addr=1d.0,"
-                "multifunction=on,masterbus=ich9-ehci-1.0,firstport=0 "
-                "-device ich9-usb-uhci2,bus=pcie.0,addr=1d.1,"
-                "multifunction=on,masterbus=ich9-ehci-1.0,firstport=2 "
-                "-device ich9-usb-uhci3,bus=pcie.0,addr=1d.2,"
-                "multifunction=on,masterbus=ich9-ehci-1.0,firstport=4 "
-                "-drive if=none,id=usbcdrom,media=cdrom "
-                "-device usb-tablet,bus=ich9-ehci-1.0,port=1,usb_version=1 "
-                "-device usb-storage,bus=ich9-ehci-1.0,port=2,drive=usbcdrom ");
-
-    test_init();
-    ret = g_test_run();
-    test_deinit();
-
-    qtest_end();
-
-    return ret;
-}
diff --git a/tests/usb-hcd-ohci-test.c b/tests/usb-hcd-ohci-test.c
deleted file mode 100644 (file)
index 19d760f..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * QTest testcase for USB OHCI controller
- *
- * Copyright (c) 2014 HUAWEI TECHNOLOGIES CO., LTD.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-#include "qemu/module.h"
-#include "libqos/usb.h"
-#include "libqos/qgraph.h"
-#include "libqos/pci.h"
-
-typedef struct QOHCI_PCI QOHCI_PCI;
-
-struct QOHCI_PCI {
-    QOSGraphObject obj;
-    QPCIDevice dev;
-};
-
-static void test_ohci_hotplug(void *obj, void *data, QGuestAllocator *alloc)
-{
-    usb_test_hotplug(global_qtest, "ohci", "1", NULL);
-}
-
-static void *ohci_pci_get_driver(void *obj, const char *interface)
-{
-    QOHCI_PCI *ohci_pci = obj;
-
-    if (!g_strcmp0(interface, "pci-device")) {
-        return &ohci_pci->dev;
-    }
-
-    fprintf(stderr, "%s not present in pci-ohci\n", interface);
-    g_assert_not_reached();
-}
-
-static void *ohci_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
-{
-    QOHCI_PCI *ohci_pci = g_new0(QOHCI_PCI, 1);
-    ohci_pci->obj.get_driver = ohci_pci_get_driver;
-
-    return &ohci_pci->obj;
-}
-
-static void ohci_pci_register_nodes(void)
-{
-    QOSGraphEdgeOptions opts = {
-        .extra_device_opts = "addr=04.0,id=ohci",
-    };
-    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
-
-    qos_node_create_driver("pci-ohci", ohci_pci_create);
-    qos_node_consumes("pci-ohci", "pci-bus", &opts);
-    qos_node_produces("pci-ohci", "pci-device");
-}
-
-libqos_init(ohci_pci_register_nodes);
-
-static void register_ohci_pci_test(void)
-{
-    qos_add_test("ohci_pci-test-hotplug", "pci-ohci", test_ohci_hotplug, NULL);
-}
-
-libqos_init(register_ohci_pci_test);
diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c
deleted file mode 100644 (file)
index 7a117b6..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * QTest testcase for USB UHCI controller
- *
- * Copyright (c) 2014 HUAWEI TECHNOLOGIES CO., LTD.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-#include "libqos/libqos.h"
-#include "libqos/usb.h"
-#include "libqos/libqos-pc.h"
-#include "libqos/libqos-spapr.h"
-#include "hw/usb/uhci-regs.h"
-
-static QOSState *qs;
-
-static void test_uhci_init(void)
-{
-}
-
-static void test_port(int port)
-{
-    struct qhc uhci;
-
-    g_assert(port > 0);
-    qusb_pci_init_one(qs->pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4);
-    uhci_port_test(&uhci, port - 1, UHCI_PORT_CCS);
-    uhci_deinit(&uhci);
-}
-
-static void test_port_1(void)
-{
-    test_port(1);
-}
-
-static void test_port_2(void)
-{
-    test_port(2);
-}
-
-static void test_uhci_hotplug(void)
-{
-    usb_test_hotplug(global_qtest, "uhci", "2", test_port_2);
-}
-
-static void test_usb_storage_hotplug(void)
-{
-    QTestState *qts = global_qtest;
-
-    qtest_qmp_device_add(qts, "usb-storage", "usbdev0", "{'drive': 'drive0'}");
-
-    qtest_qmp_device_del(qts, "usbdev0");
-}
-
-int main(int argc, char **argv)
-{
-    const char *arch = qtest_get_arch();
-    const char *cmd = "-device piix3-usb-uhci,id=uhci,addr=1d.0"
-                      " -drive id=drive0,if=none,file=null-co://,"
-                      "file.read-zeroes=on,format=raw"
-                      " -device usb-tablet,bus=uhci.0,port=1";
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("/uhci/pci/init", test_uhci_init);
-    qtest_add_func("/uhci/pci/port1", test_port_1);
-    qtest_add_func("/uhci/pci/hotplug", test_uhci_hotplug);
-    qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug);
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        qs = qtest_pc_boot(cmd);
-    } else if (strcmp(arch, "ppc64") == 0) {
-        qs = qtest_spapr_boot(cmd);
-    } else {
-        g_printerr("usb-hcd-uhci-test tests are only "
-                   "available on x86 or ppc64\n");
-        exit(EXIT_FAILURE);
-    }
-    global_qtest = qs->qts;
-    ret = g_test_run();
-    qtest_shutdown(qs);
-
-    return ret;
-}
diff --git a/tests/usb-hcd-xhci-test.c b/tests/usb-hcd-xhci-test.c
deleted file mode 100644 (file)
index 10ef9d2..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * QTest testcase for USB xHCI controller
- *
- * Copyright (c) 2014 HUAWEI TECHNOLOGIES CO., LTD.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-#include "libqos/usb.h"
-
-
-static void test_xhci_init(void)
-{
-}
-
-static void test_xhci_hotplug(void)
-{
-    usb_test_hotplug(global_qtest, "xhci", "1", NULL);
-}
-
-static void test_usb_uas_hotplug(void)
-{
-    QTestState *qts = global_qtest;
-
-    qtest_qmp_device_add(qts, "usb-uas", "uas", "{}");
-    qtest_qmp_device_add(qts, "scsi-hd", "scsihd", "{'drive': 'drive0'}");
-
-    /* TODO:
-        UAS HBA driver in libqos, to check that
-        added disk is visible after BUS rescan
-    */
-
-    qtest_qmp_device_del(qts, "scsihd");
-    qtest_qmp_device_del(qts, "uas");
-}
-
-static void test_usb_ccid_hotplug(void)
-{
-    QTestState *qts = global_qtest;
-
-    qtest_qmp_device_add(qts, "usb-ccid", "ccid", "{}");
-    qtest_qmp_device_del(qts, "ccid");
-    /* check the device can be added again */
-    qtest_qmp_device_add(qts, "usb-ccid", "ccid", "{}");
-    qtest_qmp_device_del(qts, "ccid");
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("/xhci/pci/init", test_xhci_init);
-    qtest_add_func("/xhci/pci/hotplug", test_xhci_hotplug);
-    qtest_add_func("/xhci/pci/hotplug/usb-uas", test_usb_uas_hotplug);
-    qtest_add_func("/xhci/pci/hotplug/usb-ccid", test_usb_ccid_hotplug);
-
-    qtest_start("-device nec-usb-xhci,id=xhci"
-                " -drive id=drive0,if=none,file=null-co://,"
-                "file.read-zeroes=on,format=raw");
-    ret = g_test_run();
-    qtest_end();
-
-    return ret;
-}
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
deleted file mode 100644 (file)
index 91ea373..0000000
+++ /dev/null
@@ -1,967 +0,0 @@
-/*
- * QTest testcase for the vhost-user
- *
- * Copyright (c) 2014 Virtual Open Systems Sarl.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-
-#include "libqtest-single.h"
-#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
-#include "qemu/config-file.h"
-#include "qemu/option.h"
-#include "qemu/range.h"
-#include "qemu/sockets.h"
-#include "chardev/char-fe.h"
-#include "qemu/memfd.h"
-#include "qemu/module.h"
-#include "sysemu/sysemu.h"
-#include "libqos/libqos.h"
-#include "libqos/pci-pc.h"
-#include "libqos/virtio-pci.h"
-
-#include "libqos/malloc-pc.h"
-#include "hw/virtio/virtio-net.h"
-
-#include "standard-headers/linux/vhost_types.h"
-#include "standard-headers/linux/virtio_ids.h"
-#include "standard-headers/linux/virtio_net.h"
-
-#ifdef CONFIG_LINUX
-#include <sys/vfs.h>
-#endif
-
-
-#define QEMU_CMD_MEM    " -m %d -object memory-backend-file,id=mem,size=%dM," \
-                        "mem-path=%s,share=on -numa node,memdev=mem"
-#define QEMU_CMD_MEMFD  " -m %d -object memory-backend-memfd,id=mem,size=%dM," \
-                        " -numa node,memdev=mem"
-#define QEMU_CMD_CHR    " -chardev socket,id=%s,path=%s%s"
-#define QEMU_CMD_NETDEV " -netdev vhost-user,id=hs0,chardev=%s,vhostforce"
-
-#define HUGETLBFS_MAGIC       0x958458f6
-
-/*********** FROM hw/virtio/vhost-user.c *************************************/
-
-#define VHOST_MEMORY_MAX_NREGIONS    8
-#define VHOST_MAX_VIRTQUEUES    0x100
-
-#define VHOST_USER_F_PROTOCOL_FEATURES 30
-#define VHOST_USER_PROTOCOL_F_MQ 0
-#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
-#define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN   6
-
-#define VHOST_LOG_PAGE 0x1000
-
-typedef enum VhostUserRequest {
-    VHOST_USER_NONE = 0,
-    VHOST_USER_GET_FEATURES = 1,
-    VHOST_USER_SET_FEATURES = 2,
-    VHOST_USER_SET_OWNER = 3,
-    VHOST_USER_RESET_OWNER = 4,
-    VHOST_USER_SET_MEM_TABLE = 5,
-    VHOST_USER_SET_LOG_BASE = 6,
-    VHOST_USER_SET_LOG_FD = 7,
-    VHOST_USER_SET_VRING_NUM = 8,
-    VHOST_USER_SET_VRING_ADDR = 9,
-    VHOST_USER_SET_VRING_BASE = 10,
-    VHOST_USER_GET_VRING_BASE = 11,
-    VHOST_USER_SET_VRING_KICK = 12,
-    VHOST_USER_SET_VRING_CALL = 13,
-    VHOST_USER_SET_VRING_ERR = 14,
-    VHOST_USER_GET_PROTOCOL_FEATURES = 15,
-    VHOST_USER_SET_PROTOCOL_FEATURES = 16,
-    VHOST_USER_GET_QUEUE_NUM = 17,
-    VHOST_USER_SET_VRING_ENABLE = 18,
-    VHOST_USER_MAX
-} VhostUserRequest;
-
-typedef struct VhostUserMemoryRegion {
-    uint64_t guest_phys_addr;
-    uint64_t memory_size;
-    uint64_t userspace_addr;
-    uint64_t mmap_offset;
-} VhostUserMemoryRegion;
-
-typedef struct VhostUserMemory {
-    uint32_t nregions;
-    uint32_t padding;
-    VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
-} VhostUserMemory;
-
-typedef struct VhostUserLog {
-    uint64_t mmap_size;
-    uint64_t mmap_offset;
-} VhostUserLog;
-
-typedef struct VhostUserMsg {
-    VhostUserRequest request;
-
-#define VHOST_USER_VERSION_MASK     (0x3)
-#define VHOST_USER_REPLY_MASK       (0x1<<2)
-    uint32_t flags;
-    uint32_t size; /* the following payload size */
-    union {
-#define VHOST_USER_VRING_IDX_MASK   (0xff)
-#define VHOST_USER_VRING_NOFD_MASK  (0x1<<8)
-        uint64_t u64;
-        struct vhost_vring_state state;
-        struct vhost_vring_addr addr;
-        VhostUserMemory memory;
-        VhostUserLog log;
-    } payload;
-} QEMU_PACKED VhostUserMsg;
-
-static VhostUserMsg m __attribute__ ((unused));
-#define VHOST_USER_HDR_SIZE (sizeof(m.request) \
-                            + sizeof(m.flags) \
-                            + sizeof(m.size))
-
-#define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
-
-/* The version of the protocol we support */
-#define VHOST_USER_VERSION    (0x1)
-/*****************************************************************************/
-
-enum {
-    TEST_FLAGS_OK,
-    TEST_FLAGS_DISCONNECT,
-    TEST_FLAGS_BAD,
-    TEST_FLAGS_END,
-};
-
-typedef struct TestServer {
-    gchar *socket_path;
-    gchar *mig_path;
-    gchar *chr_name;
-    gchar *tmpfs;
-    CharBackend chr;
-    int fds_num;
-    int fds[VHOST_MEMORY_MAX_NREGIONS];
-    VhostUserMemory memory;
-    GMainContext *context;
-    GMainLoop *loop;
-    GThread *thread;
-    GMutex data_mutex;
-    GCond data_cond;
-    int log_fd;
-    uint64_t rings;
-    bool test_fail;
-    int test_flags;
-    int queues;
-} TestServer;
-
-static const char *init_hugepagefs(void);
-static TestServer *test_server_new(const gchar *name);
-static void test_server_free(TestServer *server);
-static void test_server_listen(TestServer *server);
-
-enum test_memfd {
-    TEST_MEMFD_AUTO,
-    TEST_MEMFD_YES,
-    TEST_MEMFD_NO,
-};
-
-static void append_vhost_opts(TestServer *s, GString *cmd_line,
-                             const char *chr_opts)
-{
-    g_string_append_printf(cmd_line, QEMU_CMD_CHR QEMU_CMD_NETDEV,
-                           s->chr_name, s->socket_path,
-                           chr_opts, s->chr_name);
-}
-
-static void append_mem_opts(TestServer *server, GString *cmd_line,
-                            int size, enum test_memfd memfd)
-{
-    if (memfd == TEST_MEMFD_AUTO) {
-        memfd = qemu_memfd_check(MFD_ALLOW_SEALING) ? TEST_MEMFD_YES
-                                                    : TEST_MEMFD_NO;
-    }
-
-    if (memfd == TEST_MEMFD_YES) {
-        g_string_append_printf(cmd_line, QEMU_CMD_MEMFD, size, size);
-    } else {
-        const char *root = init_hugepagefs() ? : server->tmpfs;
-
-        g_string_append_printf(cmd_line, QEMU_CMD_MEM, size, size, root);
-    }
-}
-
-static bool wait_for_fds(TestServer *s)
-{
-    gint64 end_time;
-    bool got_region;
-    int i;
-
-    g_mutex_lock(&s->data_mutex);
-
-    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
-    while (!s->fds_num) {
-        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
-            /* timeout has passed */
-            g_assert(s->fds_num);
-            break;
-        }
-    }
-
-    /* check for sanity */
-    g_assert_cmpint(s->fds_num, >, 0);
-    g_assert_cmpint(s->fds_num, ==, s->memory.nregions);
-
-    g_mutex_unlock(&s->data_mutex);
-
-    got_region = false;
-    for (i = 0; i < s->memory.nregions; ++i) {
-        VhostUserMemoryRegion *reg = &s->memory.regions[i];
-        if (reg->guest_phys_addr == 0) {
-            got_region = true;
-            break;
-        }
-    }
-    if (!got_region) {
-        g_test_skip("No memory at address 0x0");
-    }
-    return got_region;
-}
-
-static void read_guest_mem_server(QTestState *qts, TestServer *s)
-{
-    uint8_t *guest_mem;
-    int i, j;
-    size_t size;
-
-    g_mutex_lock(&s->data_mutex);
-
-    /* iterate all regions */
-    for (i = 0; i < s->fds_num; i++) {
-
-        /* We'll check only the region statring at 0x0*/
-        if (s->memory.regions[i].guest_phys_addr != 0x0) {
-            continue;
-        }
-
-        g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024);
-
-        size = s->memory.regions[i].memory_size +
-            s->memory.regions[i].mmap_offset;
-
-        guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
-                         MAP_SHARED, s->fds[i], 0);
-
-        g_assert(guest_mem != MAP_FAILED);
-        guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
-
-        for (j = 0; j < 1024; j++) {
-            uint32_t a = qtest_readb(qts, s->memory.regions[i].guest_phys_addr + j);
-            uint32_t b = guest_mem[j];
-
-            g_assert_cmpint(a, ==, b);
-        }
-
-        munmap(guest_mem, s->memory.regions[i].memory_size);
-    }
-
-    g_mutex_unlock(&s->data_mutex);
-}
-
-static void *thread_function(void *data)
-{
-    GMainLoop *loop = data;
-    g_main_loop_run(loop);
-    return NULL;
-}
-
-static int chr_can_read(void *opaque)
-{
-    return VHOST_USER_HDR_SIZE;
-}
-
-static void chr_read(void *opaque, const uint8_t *buf, int size)
-{
-    TestServer *s = opaque;
-    CharBackend *chr = &s->chr;
-    VhostUserMsg msg;
-    uint8_t *p = (uint8_t *) &msg;
-    int fd = -1;
-
-    if (s->test_fail) {
-        qemu_chr_fe_disconnect(chr);
-        /* now switch to non-failure */
-        s->test_fail = false;
-    }
-
-    if (size != VHOST_USER_HDR_SIZE) {
-        g_test_message("Wrong message size received %d", size);
-        return;
-    }
-
-    g_mutex_lock(&s->data_mutex);
-    memcpy(p, buf, VHOST_USER_HDR_SIZE);
-
-    if (msg.size) {
-        p += VHOST_USER_HDR_SIZE;
-        size = qemu_chr_fe_read_all(chr, p, msg.size);
-        if (size != msg.size) {
-            g_test_message("Wrong message size received %d != %d",
-                           size, msg.size);
-            return;
-        }
-    }
-
-    switch (msg.request) {
-    case VHOST_USER_GET_FEATURES:
-        /* send back features to qemu */
-        msg.flags |= VHOST_USER_REPLY_MASK;
-        msg.size = sizeof(m.payload.u64);
-        msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL |
-            0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
-        if (s->queues > 1) {
-            msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ;
-        }
-        if (s->test_flags >= TEST_FLAGS_BAD) {
-            msg.payload.u64 = 0;
-            s->test_flags = TEST_FLAGS_END;
-        }
-        p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
-        break;
-
-    case VHOST_USER_SET_FEATURES:
-        g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
-                        !=, 0ULL);
-        if (s->test_flags == TEST_FLAGS_DISCONNECT) {
-            qemu_chr_fe_disconnect(chr);
-            s->test_flags = TEST_FLAGS_BAD;
-        }
-        break;
-
-    case VHOST_USER_GET_PROTOCOL_FEATURES:
-        /* send back features to qemu */
-        msg.flags |= VHOST_USER_REPLY_MASK;
-        msg.size = sizeof(m.payload.u64);
-        msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD;
-        msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_CROSS_ENDIAN;
-        if (s->queues > 1) {
-            msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
-        }
-        p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
-        break;
-
-    case VHOST_USER_GET_VRING_BASE:
-        /* send back vring base to qemu */
-        msg.flags |= VHOST_USER_REPLY_MASK;
-        msg.size = sizeof(m.payload.state);
-        msg.payload.state.num = 0;
-        p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
-
-        assert(msg.payload.state.index < s->queues * 2);
-        s->rings &= ~(0x1ULL << msg.payload.state.index);
-        g_cond_broadcast(&s->data_cond);
-        break;
-
-    case VHOST_USER_SET_MEM_TABLE:
-        /* received the mem table */
-        memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory));
-        s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds,
-                                            G_N_ELEMENTS(s->fds));
-
-        /* signal the test that it can continue */
-        g_cond_broadcast(&s->data_cond);
-        break;
-
-    case VHOST_USER_SET_VRING_KICK:
-    case VHOST_USER_SET_VRING_CALL:
-        /* consume the fd */
-        qemu_chr_fe_get_msgfds(chr, &fd, 1);
-        /*
-         * This is a non-blocking eventfd.
-         * The receive function forces it to be blocking,
-         * so revert it back to non-blocking.
-         */
-        qemu_set_nonblock(fd);
-        break;
-
-    case VHOST_USER_SET_LOG_BASE:
-        if (s->log_fd != -1) {
-            close(s->log_fd);
-            s->log_fd = -1;
-        }
-        qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1);
-        msg.flags |= VHOST_USER_REPLY_MASK;
-        msg.size = 0;
-        p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE);
-
-        g_cond_broadcast(&s->data_cond);
-        break;
-
-    case VHOST_USER_SET_VRING_BASE:
-        assert(msg.payload.state.index < s->queues * 2);
-        s->rings |= 0x1ULL << msg.payload.state.index;
-        g_cond_broadcast(&s->data_cond);
-        break;
-
-    case VHOST_USER_GET_QUEUE_NUM:
-        msg.flags |= VHOST_USER_REPLY_MASK;
-        msg.size = sizeof(m.payload.u64);
-        msg.payload.u64 = s->queues;
-        p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
-        break;
-
-    default:
-        break;
-    }
-
-    g_mutex_unlock(&s->data_mutex);
-}
-
-static const char *init_hugepagefs(void)
-{
-#ifdef CONFIG_LINUX
-    static const char *hugepagefs;
-    const char *path = getenv("QTEST_HUGETLBFS_PATH");
-    struct statfs fs;
-    int ret;
-
-    if (hugepagefs) {
-        return hugepagefs;
-    }
-    if (!path) {
-        return NULL;
-    }
-
-    if (access(path, R_OK | W_OK | X_OK)) {
-        g_test_message("access on path (%s): %s", path, strerror(errno));
-        g_test_fail();
-        return NULL;
-    }
-
-    do {
-        ret = statfs(path, &fs);
-    } while (ret != 0 && errno == EINTR);
-
-    if (ret != 0) {
-        g_test_message("statfs on path (%s): %s", path, strerror(errno));
-        g_test_fail();
-        return NULL;
-    }
-
-    if (fs.f_type != HUGETLBFS_MAGIC) {
-        g_test_message("Warning: path not on HugeTLBFS: %s", path);
-        g_test_fail();
-        return NULL;
-    }
-
-    hugepagefs = path;
-    return hugepagefs;
-#else
-    return NULL;
-#endif
-}
-
-static TestServer *test_server_new(const gchar *name)
-{
-    TestServer *server = g_new0(TestServer, 1);
-    char template[] = "/tmp/vhost-test-XXXXXX";
-    const char *tmpfs;
-
-    server->context = g_main_context_new();
-    server->loop = g_main_loop_new(server->context, FALSE);
-
-    /* run the main loop thread so the chardev may operate */
-    server->thread = g_thread_new(NULL, thread_function, server->loop);
-
-    tmpfs = mkdtemp(template);
-    if (!tmpfs) {
-        g_test_message("mkdtemp on path (%s): %s", template, strerror(errno));
-    }
-    g_assert(tmpfs);
-
-    server->tmpfs = g_strdup(tmpfs);
-    server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name);
-    server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name);
-    server->chr_name = g_strdup_printf("chr-%s", name);
-
-    g_mutex_init(&server->data_mutex);
-    g_cond_init(&server->data_cond);
-
-    server->log_fd = -1;
-    server->queues = 1;
-
-    return server;
-}
-
-static void chr_event(void *opaque, int event)
-{
-    TestServer *s = opaque;
-
-    if (s->test_flags == TEST_FLAGS_END &&
-        event == CHR_EVENT_CLOSED) {
-        s->test_flags = TEST_FLAGS_OK;
-    }
-}
-
-static void test_server_create_chr(TestServer *server, const gchar *opt)
-{
-    gchar *chr_path;
-    Chardev *chr;
-
-    chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
-    chr = qemu_chr_new(server->chr_name, chr_path, server->context);
-    g_free(chr_path);
-
-    g_assert_nonnull(chr);
-    qemu_chr_fe_init(&server->chr, chr, &error_abort);
-    qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read,
-                             chr_event, NULL, server, server->context, true);
-}
-
-static void test_server_listen(TestServer *server)
-{
-    test_server_create_chr(server, ",server,nowait");
-}
-
-static void test_server_free(TestServer *server)
-{
-    int i, ret;
-
-    /* finish the helper thread and dispatch pending sources */
-    g_main_loop_quit(server->loop);
-    g_thread_join(server->thread);
-    while (g_main_context_pending(NULL)) {
-        g_main_context_iteration(NULL, TRUE);
-    }
-
-    unlink(server->socket_path);
-    g_free(server->socket_path);
-
-    unlink(server->mig_path);
-    g_free(server->mig_path);
-
-    ret = rmdir(server->tmpfs);
-    if (ret != 0) {
-        g_test_message("unable to rmdir: path (%s): %s",
-                       server->tmpfs, strerror(errno));
-    }
-    g_free(server->tmpfs);
-
-    qemu_chr_fe_deinit(&server->chr, true);
-
-    for (i = 0; i < server->fds_num; i++) {
-        close(server->fds[i]);
-    }
-
-    if (server->log_fd != -1) {
-        close(server->log_fd);
-    }
-
-    g_free(server->chr_name);
-
-    g_main_loop_unref(server->loop);
-    g_main_context_unref(server->context);
-    g_cond_clear(&server->data_cond);
-    g_mutex_clear(&server->data_mutex);
-    g_free(server);
-}
-
-static void wait_for_log_fd(TestServer *s)
-{
-    gint64 end_time;
-
-    g_mutex_lock(&s->data_mutex);
-    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
-    while (s->log_fd == -1) {
-        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
-            /* timeout has passed */
-            g_assert(s->log_fd != -1);
-            break;
-        }
-    }
-
-    g_mutex_unlock(&s->data_mutex);
-}
-
-static void write_guest_mem(TestServer *s, uint32_t seed)
-{
-    uint32_t *guest_mem;
-    int i, j;
-    size_t size;
-
-    /* iterate all regions */
-    for (i = 0; i < s->fds_num; i++) {
-
-        /* We'll write only the region statring at 0x0 */
-        if (s->memory.regions[i].guest_phys_addr != 0x0) {
-            continue;
-        }
-
-        g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024);
-
-        size = s->memory.regions[i].memory_size +
-            s->memory.regions[i].mmap_offset;
-
-        guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
-                         MAP_SHARED, s->fds[i], 0);
-
-        g_assert(guest_mem != MAP_FAILED);
-        guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
-
-        for (j = 0; j < 256; j++) {
-            guest_mem[j] = seed + j;
-        }
-
-        munmap(guest_mem, s->memory.regions[i].memory_size);
-        break;
-    }
-}
-
-static guint64 get_log_size(TestServer *s)
-{
-    guint64 log_size = 0;
-    int i;
-
-    for (i = 0; i < s->memory.nregions; ++i) {
-        VhostUserMemoryRegion *reg = &s->memory.regions[i];
-        guint64 last = range_get_last(reg->guest_phys_addr,
-                                       reg->memory_size);
-        log_size = MAX(log_size, last / (8 * VHOST_LOG_PAGE) + 1);
-    }
-
-    return log_size;
-}
-
-typedef struct TestMigrateSource {
-    GSource source;
-    TestServer *src;
-    TestServer *dest;
-} TestMigrateSource;
-
-static gboolean
-test_migrate_source_check(GSource *source)
-{
-    TestMigrateSource *t = (TestMigrateSource *)source;
-    gboolean overlap = t->src->rings && t->dest->rings;
-
-    g_assert(!overlap);
-
-    return FALSE;
-}
-
-GSourceFuncs test_migrate_source_funcs = {
-    .check = test_migrate_source_check,
-};
-
-static void vhost_user_test_cleanup(void *s)
-{
-    TestServer *server = s;
-
-    qos_invalidate_command_line();
-    test_server_free(server);
-}
-
-static void *vhost_user_test_setup(GString *cmd_line, void *arg)
-{
-    TestServer *server = test_server_new("vhost-user-test");
-    test_server_listen(server);
-
-    append_mem_opts(server, cmd_line, 256, TEST_MEMFD_AUTO);
-    append_vhost_opts(server, cmd_line, "");
-
-    g_test_queue_destroy(vhost_user_test_cleanup, server);
-
-    return server;
-}
-
-static void *vhost_user_test_setup_memfd(GString *cmd_line, void *arg)
-{
-    TestServer *server = test_server_new("vhost-user-test");
-    test_server_listen(server);
-
-    append_mem_opts(server, cmd_line, 256, TEST_MEMFD_YES);
-    append_vhost_opts(server, cmd_line, "");
-
-    g_test_queue_destroy(vhost_user_test_cleanup, server);
-
-    return server;
-}
-
-static void test_read_guest_mem(void *obj, void *arg, QGuestAllocator *alloc)
-{
-    TestServer *server = arg;
-
-    if (!wait_for_fds(server)) {
-        return;
-    }
-
-    read_guest_mem_server(global_qtest, server);
-}
-
-static void test_migrate(void *obj, void *arg, QGuestAllocator *alloc)
-{
-    TestServer *s = arg;
-    TestServer *dest = test_server_new("dest");
-    GString *dest_cmdline = g_string_new(qos_get_current_command_line());
-    char *uri = g_strdup_printf("%s%s", "unix:", dest->mig_path);
-    QTestState *to;
-    GSource *source;
-    QDict *rsp;
-    guint8 *log;
-    guint64 size;
-
-    if (!wait_for_fds(s)) {
-        return;
-    }
-
-    size = get_log_size(s);
-    g_assert_cmpint(size, ==, (256 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));
-
-    test_server_listen(dest);
-    g_string_append_printf(dest_cmdline, " -incoming %s", uri);
-    append_mem_opts(dest, dest_cmdline, 256, TEST_MEMFD_AUTO);
-    append_vhost_opts(dest, dest_cmdline, "");
-    to = qtest_init(dest_cmdline->str);
-
-    /* This would be where you call qos_allocate_objects(to, NULL), if you want
-     * to talk to the QVirtioNet object on the destination.
-     */
-
-    source = g_source_new(&test_migrate_source_funcs,
-                          sizeof(TestMigrateSource));
-    ((TestMigrateSource *)source)->src = s;
-    ((TestMigrateSource *)source)->dest = dest;
-    g_source_attach(source, s->context);
-
-    /* slow down migration to have time to fiddle with log */
-    /* TODO: qtest could learn to break on some places */
-    rsp = qmp("{ 'execute': 'migrate_set_speed',"
-              "'arguments': { 'value': 10 } }");
-    g_assert(qdict_haskey(rsp, "return"));
-    qobject_unref(rsp);
-
-    rsp = qmp("{ 'execute': 'migrate', 'arguments': { 'uri': %s } }", uri);
-    g_assert(qdict_haskey(rsp, "return"));
-    qobject_unref(rsp);
-
-    wait_for_log_fd(s);
-
-    log = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, s->log_fd, 0);
-    g_assert(log != MAP_FAILED);
-
-    /* modify first page */
-    write_guest_mem(s, 0x42);
-    log[0] = 1;
-    munmap(log, size);
-
-    /* speed things up */
-    rsp = qmp("{ 'execute': 'migrate_set_speed',"
-              "'arguments': { 'value': 0 } }");
-    g_assert(qdict_haskey(rsp, "return"));
-    qobject_unref(rsp);
-
-    qmp_eventwait("STOP");
-    qtest_qmp_eventwait(to, "RESUME");
-
-    g_assert(wait_for_fds(dest));
-    read_guest_mem_server(to, dest);
-
-    g_source_destroy(source);
-    g_source_unref(source);
-
-    qtest_quit(to);
-    test_server_free(dest);
-    g_free(uri);
-}
-
-static void wait_for_rings_started(TestServer *s, size_t count)
-{
-    gint64 end_time;
-
-    g_mutex_lock(&s->data_mutex);
-    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
-    while (ctpop64(s->rings) != count) {
-        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
-            /* timeout has passed */
-            g_assert_cmpint(ctpop64(s->rings), ==, count);
-            break;
-        }
-    }
-
-    g_mutex_unlock(&s->data_mutex);
-}
-
-static inline void test_server_connect(TestServer *server)
-{
-    test_server_create_chr(server, ",reconnect=1");
-}
-
-static gboolean
-reconnect_cb(gpointer user_data)
-{
-    TestServer *s = user_data;
-
-    qemu_chr_fe_disconnect(&s->chr);
-
-    return FALSE;
-}
-
-static gpointer
-connect_thread(gpointer data)
-{
-    TestServer *s = data;
-
-    /* wait for qemu to start before first try, to avoid extra warnings */
-    g_usleep(G_USEC_PER_SEC);
-    test_server_connect(s);
-
-    return NULL;
-}
-
-static void *vhost_user_test_setup_reconnect(GString *cmd_line, void *arg)
-{
-    TestServer *s = test_server_new("reconnect");
-
-    g_thread_new("connect", connect_thread, s);
-    append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO);
-    append_vhost_opts(s, cmd_line, ",server");
-
-    g_test_queue_destroy(vhost_user_test_cleanup, s);
-
-    return s;
-}
-
-static void test_reconnect(void *obj, void *arg, QGuestAllocator *alloc)
-{
-    TestServer *s = arg;
-    GSource *src;
-
-    if (!wait_for_fds(s)) {
-        return;
-    }
-
-    wait_for_rings_started(s, 2);
-
-    /* reconnect */
-    s->fds_num = 0;
-    s->rings = 0;
-    src = g_idle_source_new();
-    g_source_set_callback(src, reconnect_cb, s, NULL);
-    g_source_attach(src, s->context);
-    g_source_unref(src);
-    g_assert(wait_for_fds(s));
-    wait_for_rings_started(s, 2);
-}
-
-static void *vhost_user_test_setup_connect_fail(GString *cmd_line, void *arg)
-{
-    TestServer *s = test_server_new("connect-fail");
-
-    s->test_fail = true;
-
-    g_thread_new("connect", connect_thread, s);
-    append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO);
-    append_vhost_opts(s, cmd_line, ",server");
-
-    g_test_queue_destroy(vhost_user_test_cleanup, s);
-
-    return s;
-}
-
-static void *vhost_user_test_setup_flags_mismatch(GString *cmd_line, void *arg)
-{
-    TestServer *s = test_server_new("flags-mismatch");
-
-    s->test_flags = TEST_FLAGS_DISCONNECT;
-
-    g_thread_new("connect", connect_thread, s);
-    append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO);
-    append_vhost_opts(s, cmd_line, ",server");
-
-    g_test_queue_destroy(vhost_user_test_cleanup, s);
-
-    return s;
-}
-
-static void test_vhost_user_started(void *obj, void *arg, QGuestAllocator *alloc)
-{
-    TestServer *s = arg;
-
-    if (!wait_for_fds(s)) {
-        return;
-    }
-    wait_for_rings_started(s, 2);
-}
-
-static void *vhost_user_test_setup_multiqueue(GString *cmd_line, void *arg)
-{
-    TestServer *s = vhost_user_test_setup(cmd_line, arg);
-
-    s->queues = 2;
-    g_string_append_printf(cmd_line,
-                           " -set netdev.hs0.queues=%d"
-                           " -global virtio-net-pci.vectors=%d",
-                           s->queues, s->queues * 2 + 2);
-
-    return s;
-}
-
-static void test_multiqueue(void *obj, void *arg, QGuestAllocator *alloc)
-{
-    TestServer *s = arg;
-
-    wait_for_rings_started(s, s->queues * 2);
-}
-
-static void register_vhost_user_test(void)
-{
-    QOSGraphTestOptions opts = {
-        .before = vhost_user_test_setup,
-        .subprocess = true,
-    };
-
-    qemu_add_opts(&qemu_chardev_opts);
-
-    qos_add_test("vhost-user/read-guest-mem/memfile",
-                 "virtio-net",
-                 test_read_guest_mem, &opts);
-
-    if (qemu_memfd_check(MFD_ALLOW_SEALING)) {
-        opts.before = vhost_user_test_setup_memfd;
-        qos_add_test("vhost-user/read-guest-mem/memfd",
-                     "virtio-net",
-                     test_read_guest_mem, &opts);
-    }
-
-    qos_add_test("vhost-user/migrate",
-                 "virtio-net",
-                 test_migrate, &opts);
-
-    /* keeps failing on build-system since Aug 15 2017 */
-    if (getenv("QTEST_VHOST_USER_FIXME")) {
-        opts.before = vhost_user_test_setup_reconnect;
-        qos_add_test("vhost-user/reconnect", "virtio-net",
-                     test_reconnect, &opts);
-
-        opts.before = vhost_user_test_setup_connect_fail;
-        qos_add_test("vhost-user/connect-fail", "virtio-net",
-                     test_vhost_user_started, &opts);
-
-        opts.before = vhost_user_test_setup_flags_mismatch;
-        qos_add_test("vhost-user/flags-mismatch", "virtio-net",
-                     test_vhost_user_started, &opts);
-    }
-
-    opts.before = vhost_user_test_setup_multiqueue;
-    opts.edge.extra_device_opts = "mq=on";
-    qos_add_test("vhost-user/multiqueue",
-                 "virtio-net",
-                 test_multiqueue, &opts);
-}
-libqos_init(register_vhost_user_test);
diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c
deleted file mode 100644 (file)
index e7b58e3..0000000
+++ /dev/null
@@ -1,662 +0,0 @@
-/*
- * QTest testcase for VirtIO 9P
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-#include "qemu/module.h"
-#include "hw/9pfs/9p.h"
-#include "hw/9pfs/9p-synth.h"
-#include "libqos/virtio-9p.h"
-#include "libqos/qgraph.h"
-
-#define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000)
-static QGuestAllocator *alloc;
-
-static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtio9P *v9p = obj;
-    alloc = t_alloc;
-    size_t tag_len = qvirtio_config_readw(v9p->vdev, 0);
-    char *tag;
-    int i;
-
-    g_assert_cmpint(tag_len, ==, strlen(MOUNT_TAG));
-
-    tag = g_malloc(tag_len);
-    for (i = 0; i < tag_len; i++) {
-        tag[i] = qvirtio_config_readb(v9p->vdev, i + 2);
-    }
-    g_assert_cmpmem(tag, tag_len, MOUNT_TAG, tag_len);
-    g_free(tag);
-}
-
-#define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */
-
-typedef struct {
-    QTestState *qts;
-    QVirtio9P *v9p;
-    uint16_t tag;
-    uint64_t t_msg;
-    uint32_t t_size;
-    uint64_t r_msg;
-    /* No r_size, it is hardcoded to P9_MAX_SIZE */
-    size_t t_off;
-    size_t r_off;
-    uint32_t free_head;
-} P9Req;
-
-static void v9fs_memwrite(P9Req *req, const void *addr, size_t len)
-{
-    qtest_memwrite(req->qts, req->t_msg + req->t_off, addr, len);
-    req->t_off += len;
-}
-
-static void v9fs_memskip(P9Req *req, size_t len)
-{
-    req->r_off += len;
-}
-
-static void v9fs_memread(P9Req *req, void *addr, size_t len)
-{
-    qtest_memread(req->qts, req->r_msg + req->r_off, addr, len);
-    req->r_off += len;
-}
-
-static void v9fs_uint16_write(P9Req *req, uint16_t val)
-{
-    uint16_t le_val = cpu_to_le16(val);
-
-    v9fs_memwrite(req, &le_val, 2);
-}
-
-static void v9fs_uint16_read(P9Req *req, uint16_t *val)
-{
-    v9fs_memread(req, val, 2);
-    le16_to_cpus(val);
-}
-
-static void v9fs_uint32_write(P9Req *req, uint32_t val)
-{
-    uint32_t le_val = cpu_to_le32(val);
-
-    v9fs_memwrite(req, &le_val, 4);
-}
-
-static void v9fs_uint64_write(P9Req *req, uint64_t val)
-{
-    uint64_t le_val = cpu_to_le64(val);
-
-    v9fs_memwrite(req, &le_val, 8);
-}
-
-static void v9fs_uint32_read(P9Req *req, uint32_t *val)
-{
-    v9fs_memread(req, val, 4);
-    le32_to_cpus(val);
-}
-
-/* len[2] string[len] */
-static uint16_t v9fs_string_size(const char *string)
-{
-    size_t len = strlen(string);
-
-    g_assert_cmpint(len, <=, UINT16_MAX - 2);
-
-    return 2 + len;
-}
-
-static void v9fs_string_write(P9Req *req, const char *string)
-{
-    int len = strlen(string);
-
-    g_assert_cmpint(len, <=, UINT16_MAX);
-
-    v9fs_uint16_write(req, (uint16_t) len);
-    v9fs_memwrite(req, string, len);
-}
-
-static void v9fs_string_read(P9Req *req, uint16_t *len, char **string)
-{
-    uint16_t local_len;
-
-    v9fs_uint16_read(req, &local_len);
-    if (len) {
-        *len = local_len;
-    }
-    if (string) {
-        *string = g_malloc(local_len);
-        v9fs_memread(req, *string, local_len);
-    } else {
-        v9fs_memskip(req, local_len);
-    }
-}
-
- typedef struct {
-    uint32_t size;
-    uint8_t id;
-    uint16_t tag;
-} QEMU_PACKED P9Hdr;
-
-static P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id,
-                            uint16_t tag)
-{
-    P9Req *req = g_new0(P9Req, 1);
-    uint32_t total_size = 7; /* 9P header has well-known size of 7 bytes */
-    P9Hdr hdr = {
-        .id = id,
-        .tag = cpu_to_le16(tag)
-    };
-
-    g_assert_cmpint(total_size, <=, UINT32_MAX - size);
-    total_size += size;
-    hdr.size = cpu_to_le32(total_size);
-
-    g_assert_cmpint(total_size, <=, P9_MAX_SIZE);
-
-    req->qts = global_qtest;
-    req->v9p = v9p;
-    req->t_size = total_size;
-    req->t_msg = guest_alloc(alloc, req->t_size);
-    v9fs_memwrite(req, &hdr, 7);
-    req->tag = tag;
-    return req;
-}
-
-static void v9fs_req_send(P9Req *req)
-{
-    QVirtio9P *v9p = req->v9p;
-
-    req->r_msg = guest_alloc(alloc, P9_MAX_SIZE);
-    req->free_head = qvirtqueue_add(req->qts, v9p->vq, req->t_msg, req->t_size,
-                                    false, true);
-    qvirtqueue_add(req->qts, v9p->vq, req->r_msg, P9_MAX_SIZE, true, false);
-    qvirtqueue_kick(req->qts, v9p->vdev, v9p->vq, req->free_head);
-    req->t_off = 0;
-}
-
-static const char *rmessage_name(uint8_t id)
-{
-    return
-        id == P9_RLERROR ? "RLERROR" :
-        id == P9_RVERSION ? "RVERSION" :
-        id == P9_RATTACH ? "RATTACH" :
-        id == P9_RWALK ? "RWALK" :
-        id == P9_RLOPEN ? "RLOPEN" :
-        id == P9_RWRITE ? "RWRITE" :
-        id == P9_RFLUSH ? "RFLUSH" :
-        "<unknown>";
-}
-
-static void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len)
-{
-    QVirtio9P *v9p = req->v9p;
-
-    qvirtio_wait_used_elem(req->qts, v9p->vdev, v9p->vq, req->free_head, len,
-                           QVIRTIO_9P_TIMEOUT_US);
-}
-
-static void v9fs_req_recv(P9Req *req, uint8_t id)
-{
-    P9Hdr hdr;
-
-    v9fs_memread(req, &hdr, 7);
-    hdr.size = ldl_le_p(&hdr.size);
-    hdr.tag = lduw_le_p(&hdr.tag);
-
-    g_assert_cmpint(hdr.size, >=, 7);
-    g_assert_cmpint(hdr.size, <=, P9_MAX_SIZE);
-    g_assert_cmpint(hdr.tag, ==, req->tag);
-
-    if (hdr.id != id) {
-        g_printerr("Received response %d (%s) instead of %d (%s)\n",
-                   hdr.id, rmessage_name(hdr.id), id, rmessage_name(id));
-
-        if (hdr.id == P9_RLERROR) {
-            uint32_t err;
-            v9fs_uint32_read(req, &err);
-            g_printerr("Rlerror has errno %d (%s)\n", err, strerror(err));
-        }
-    }
-    g_assert_cmpint(hdr.id, ==, id);
-}
-
-static void v9fs_req_free(P9Req *req)
-{
-    guest_free(alloc, req->t_msg);
-    guest_free(alloc, req->r_msg);
-    g_free(req);
-}
-
-/* size[4] Rlerror tag[2] ecode[4] */
-static void v9fs_rlerror(P9Req *req, uint32_t *err)
-{
-    v9fs_req_recv(req, P9_RLERROR);
-    v9fs_uint32_read(req, err);
-    v9fs_req_free(req);
-}
-
-/* size[4] Tversion tag[2] msize[4] version[s] */
-static P9Req *v9fs_tversion(QVirtio9P *v9p, uint32_t msize, const char *version,
-                            uint16_t tag)
-{
-    P9Req *req;
-    uint32_t body_size = 4;
-    uint16_t string_size = v9fs_string_size(version);
-
-    g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
-    body_size += string_size;
-    req = v9fs_req_init(v9p, body_size, P9_TVERSION, tag);
-
-    v9fs_uint32_write(req, msize);
-    v9fs_string_write(req, version);
-    v9fs_req_send(req);
-    return req;
-}
-
-/* size[4] Rversion tag[2] msize[4] version[s] */
-static void v9fs_rversion(P9Req *req, uint16_t *len, char **version)
-{
-    uint32_t msize;
-
-    v9fs_req_recv(req, P9_RVERSION);
-    v9fs_uint32_read(req, &msize);
-
-    g_assert_cmpint(msize, ==, P9_MAX_SIZE);
-
-    if (len || version) {
-        v9fs_string_read(req, len, version);
-    }
-
-    v9fs_req_free(req);
-}
-
-/* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] */
-static P9Req *v9fs_tattach(QVirtio9P *v9p, uint32_t fid, uint32_t n_uname,
-                           uint16_t tag)
-{
-    const char *uname = ""; /* ignored by QEMU */
-    const char *aname = ""; /* ignored by QEMU */
-    P9Req *req = v9fs_req_init(v9p, 4 + 4 + 2 + 2 + 4, P9_TATTACH, tag);
-
-    v9fs_uint32_write(req, fid);
-    v9fs_uint32_write(req, P9_NOFID);
-    v9fs_string_write(req, uname);
-    v9fs_string_write(req, aname);
-    v9fs_uint32_write(req, n_uname);
-    v9fs_req_send(req);
-    return req;
-}
-
-typedef char v9fs_qid[13];
-
-/* size[4] Rattach tag[2] qid[13] */
-static void v9fs_rattach(P9Req *req, v9fs_qid *qid)
-{
-    v9fs_req_recv(req, P9_RATTACH);
-    if (qid) {
-        v9fs_memread(req, qid, 13);
-    }
-    v9fs_req_free(req);
-}
-
-/* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
-static P9Req *v9fs_twalk(QVirtio9P *v9p, uint32_t fid, uint32_t newfid,
-                         uint16_t nwname, char *const wnames[], uint16_t tag)
-{
-    P9Req *req;
-    int i;
-    uint32_t body_size = 4 + 4 + 2;
-
-    for (i = 0; i < nwname; i++) {
-        uint16_t wname_size = v9fs_string_size(wnames[i]);
-
-        g_assert_cmpint(body_size, <=, UINT32_MAX - wname_size);
-        body_size += wname_size;
-    }
-    req = v9fs_req_init(v9p,  body_size, P9_TWALK, tag);
-    v9fs_uint32_write(req, fid);
-    v9fs_uint32_write(req, newfid);
-    v9fs_uint16_write(req, nwname);
-    for (i = 0; i < nwname; i++) {
-        v9fs_string_write(req, wnames[i]);
-    }
-    v9fs_req_send(req);
-    return req;
-}
-
-/* size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) */
-static void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid)
-{
-    uint16_t local_nwqid;
-
-    v9fs_req_recv(req, P9_RWALK);
-    v9fs_uint16_read(req, &local_nwqid);
-    if (nwqid) {
-        *nwqid = local_nwqid;
-    }
-    if (wqid) {
-        *wqid = g_malloc(local_nwqid * 13);
-        v9fs_memread(req, *wqid, local_nwqid * 13);
-    }
-    v9fs_req_free(req);
-}
-
-/* size[4] Tlopen tag[2] fid[4] flags[4] */
-static P9Req *v9fs_tlopen(QVirtio9P *v9p, uint32_t fid, uint32_t flags,
-                          uint16_t tag)
-{
-    P9Req *req;
-
-    req = v9fs_req_init(v9p,  4 + 4, P9_TLOPEN, tag);
-    v9fs_uint32_write(req, fid);
-    v9fs_uint32_write(req, flags);
-    v9fs_req_send(req);
-    return req;
-}
-
-/* size[4] Rlopen tag[2] qid[13] iounit[4] */
-static void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit)
-{
-    v9fs_req_recv(req, P9_RLOPEN);
-    if (qid) {
-        v9fs_memread(req, qid, 13);
-    } else {
-        v9fs_memskip(req, 13);
-    }
-    if (iounit) {
-        v9fs_uint32_read(req, iounit);
-    }
-    v9fs_req_free(req);
-}
-
-/* size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] */
-static P9Req *v9fs_twrite(QVirtio9P *v9p, uint32_t fid, uint64_t offset,
-                          uint32_t count, const void *data, uint16_t tag)
-{
-    P9Req *req;
-    uint32_t body_size = 4 + 8 + 4;
-
-    g_assert_cmpint(body_size, <=, UINT32_MAX - count);
-    body_size += count;
-    req = v9fs_req_init(v9p,  body_size, P9_TWRITE, tag);
-    v9fs_uint32_write(req, fid);
-    v9fs_uint64_write(req, offset);
-    v9fs_uint32_write(req, count);
-    v9fs_memwrite(req, data, count);
-    v9fs_req_send(req);
-    return req;
-}
-
-/* size[4] Rwrite tag[2] count[4] */
-static void v9fs_rwrite(P9Req *req, uint32_t *count)
-{
-    v9fs_req_recv(req, P9_RWRITE);
-    if (count) {
-        v9fs_uint32_read(req, count);
-    }
-    v9fs_req_free(req);
-}
-
-/* size[4] Tflush tag[2] oldtag[2] */
-static P9Req *v9fs_tflush(QVirtio9P *v9p, uint16_t oldtag, uint16_t tag)
-{
-    P9Req *req;
-
-    req = v9fs_req_init(v9p,  2, P9_TFLUSH, tag);
-    v9fs_uint32_write(req, oldtag);
-    v9fs_req_send(req);
-    return req;
-}
-
-/* size[4] Rflush tag[2] */
-static void v9fs_rflush(P9Req *req)
-{
-    v9fs_req_recv(req, P9_RFLUSH);
-    v9fs_req_free(req);
-}
-
-static void fs_version(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtio9P *v9p = obj;
-    alloc = t_alloc;
-    const char *version = "9P2000.L";
-    uint16_t server_len;
-    char *server_version;
-    P9Req *req;
-
-    req = v9fs_tversion(v9p, P9_MAX_SIZE, version, P9_NOTAG);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rversion(req, &server_len, &server_version);
-
-    g_assert_cmpmem(server_version, server_len, version, strlen(version));
-
-    g_free(server_version);
-}
-
-static void fs_attach(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtio9P *v9p = obj;
-    alloc = t_alloc;
-    P9Req *req;
-
-    fs_version(v9p, NULL, t_alloc);
-    req = v9fs_tattach(v9p, 0, getuid(), 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rattach(req, NULL);
-}
-
-static void fs_walk(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtio9P *v9p = obj;
-    alloc = t_alloc;
-    char *wnames[P9_MAXWELEM];
-    uint16_t nwqid;
-    v9fs_qid *wqid;
-    int i;
-    P9Req *req;
-
-    for (i = 0; i < P9_MAXWELEM; i++) {
-        wnames[i] = g_strdup_printf(QTEST_V9FS_SYNTH_WALK_FILE, i);
-    }
-
-    fs_attach(v9p, NULL, t_alloc);
-    req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames, 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rwalk(req, &nwqid, &wqid);
-
-    g_assert_cmpint(nwqid, ==, P9_MAXWELEM);
-
-    for (i = 0; i < P9_MAXWELEM; i++) {
-        g_free(wnames[i]);
-    }
-
-    g_free(wqid);
-}
-
-static void fs_walk_no_slash(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtio9P *v9p = obj;
-    alloc = t_alloc;
-    char *const wnames[] = { g_strdup(" /") };
-    P9Req *req;
-    uint32_t err;
-
-    fs_attach(v9p, NULL, t_alloc);
-    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rlerror(req, &err);
-
-    g_assert_cmpint(err, ==, ENOENT);
-
-    g_free(wnames[0]);
-}
-
-static void fs_walk_dotdot(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtio9P *v9p = obj;
-    alloc = t_alloc;
-    char *const wnames[] = { g_strdup("..") };
-    v9fs_qid root_qid, *wqid;
-    P9Req *req;
-
-    fs_version(v9p, NULL, t_alloc);
-    req = v9fs_tattach(v9p, 0, getuid(), 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rattach(req, &root_qid);
-
-    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rwalk(req, NULL, &wqid); /* We now we'll get one qid */
-
-    g_assert_cmpmem(&root_qid, 13, wqid[0], 13);
-
-    g_free(wqid);
-    g_free(wnames[0]);
-}
-
-static void fs_lopen(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtio9P *v9p = obj;
-    alloc = t_alloc;
-    char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_LOPEN_FILE) };
-    P9Req *req;
-
-    fs_attach(v9p, NULL, t_alloc);
-    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rwalk(req, NULL, NULL);
-
-    req = v9fs_tlopen(v9p, 1, O_WRONLY, 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rlopen(req, NULL, NULL);
-
-    g_free(wnames[0]);
-}
-
-static void fs_write(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtio9P *v9p = obj;
-    alloc = t_alloc;
-    static const uint32_t write_count = P9_MAX_SIZE / 2;
-    char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_WRITE_FILE) };
-    char *buf = g_malloc0(write_count);
-    uint32_t count;
-    P9Req *req;
-
-    fs_attach(v9p, NULL, t_alloc);
-    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rwalk(req, NULL, NULL);
-
-    req = v9fs_tlopen(v9p, 1, O_WRONLY, 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rlopen(req, NULL, NULL);
-
-    req = v9fs_twrite(v9p, 1, 0, write_count, buf, 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rwrite(req, &count);
-    g_assert_cmpint(count, ==, write_count);
-
-    g_free(buf);
-    g_free(wnames[0]);
-}
-
-static void fs_flush_success(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtio9P *v9p = obj;
-    alloc = t_alloc;
-    char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) };
-    P9Req *req, *flush_req;
-    uint32_t reply_len;
-    uint8_t should_block;
-
-    fs_attach(v9p, NULL, t_alloc);
-    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rwalk(req, NULL, NULL);
-
-    req = v9fs_tlopen(v9p, 1, O_WRONLY, 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rlopen(req, NULL, NULL);
-
-    /* This will cause the 9p server to try to write data to the backend,
-     * until the write request gets cancelled.
-     */
-    should_block = 1;
-    req = v9fs_twrite(v9p, 1, 0, sizeof(should_block), &should_block, 0);
-
-    flush_req = v9fs_tflush(v9p, req->tag, 1);
-
-    /* The write request is supposed to be flushed: the server should just
-     * mark the write request as used and reply to the flush request.
-     */
-    v9fs_req_wait_for_reply(req, &reply_len);
-    g_assert_cmpint(reply_len, ==, 0);
-    v9fs_req_free(req);
-    v9fs_rflush(flush_req);
-
-    g_free(wnames[0]);
-}
-
-static void fs_flush_ignored(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtio9P *v9p = obj;
-    alloc = t_alloc;
-    char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) };
-    P9Req *req, *flush_req;
-    uint32_t count;
-    uint8_t should_block;
-
-    fs_attach(v9p, NULL, t_alloc);
-    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rwalk(req, NULL, NULL);
-
-    req = v9fs_tlopen(v9p, 1, O_WRONLY, 0);
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rlopen(req, NULL, NULL);
-
-    /* This will cause the write request to complete right away, before it
-     * could be actually cancelled.
-     */
-    should_block = 0;
-    req = v9fs_twrite(v9p, 1, 0, sizeof(should_block), &should_block, 0);
-
-    flush_req = v9fs_tflush(v9p, req->tag, 1);
-
-    /* The write request is supposed to complete. The server should
-     * reply to the write request and the flush request.
-     */
-    v9fs_req_wait_for_reply(req, NULL);
-    v9fs_rwrite(req, &count);
-    g_assert_cmpint(count, ==, sizeof(should_block));
-    v9fs_rflush(flush_req);
-
-    g_free(wnames[0]);
-}
-
-static void register_virtio_9p_test(void)
-{
-    qos_add_test("config", "virtio-9p", pci_config, NULL);
-    qos_add_test("fs/version/basic", "virtio-9p", fs_version, NULL);
-    qos_add_test("fs/attach/basic", "virtio-9p", fs_attach, NULL);
-    qos_add_test("fs/walk/basic", "virtio-9p", fs_walk, NULL);
-    qos_add_test("fs/walk/no_slash", "virtio-9p", fs_walk_no_slash,
-                 NULL);
-    qos_add_test("fs/walk/dotdot_from_root", "virtio-9p",
-                 fs_walk_dotdot, NULL);
-    qos_add_test("fs/lopen/basic", "virtio-9p", fs_lopen, NULL);
-    qos_add_test("fs/write/basic", "virtio-9p", fs_write, NULL);
-    qos_add_test("fs/flush/success", "virtio-9p", fs_flush_success,
-                 NULL);
-    qos_add_test("fs/flush/ignored", "virtio-9p", fs_flush_ignored,
-                 NULL);
-}
-
-libqos_init(register_virtio_9p_test);
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
deleted file mode 100644 (file)
index 2a23698..0000000
+++ /dev/null
@@ -1,802 +0,0 @@
-/*
- * QTest testcase for VirtIO Block Device
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- * Copyright (c) 2014 Marc Marí
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-#include "qemu/bswap.h"
-#include "qemu/module.h"
-#include "standard-headers/linux/virtio_blk.h"
-#include "standard-headers/linux/virtio_pci.h"
-#include "libqos/qgraph.h"
-#include "libqos/virtio-blk.h"
-
-/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
-
-#define TEST_IMAGE_SIZE         (64 * 1024 * 1024)
-#define QVIRTIO_BLK_TIMEOUT_US  (30 * 1000 * 1000)
-#define PCI_SLOT_HP             0x06
-
-typedef struct QVirtioBlkReq {
-    uint32_t type;
-    uint32_t ioprio;
-    uint64_t sector;
-    char *data;
-    uint8_t status;
-} QVirtioBlkReq;
-
-
-#ifdef HOST_WORDS_BIGENDIAN
-const bool host_is_big_endian = true;
-#else
-const bool host_is_big_endian; /* false */
-#endif
-
-static void drive_destroy(void *path)
-{
-    unlink(path);
-    g_free(path);
-    qos_invalidate_command_line();
-}
-
-static char *drive_create(void)
-{
-    int fd, ret;
-    char *t_path = g_strdup("/tmp/qtest.XXXXXX");
-
-    /* Create a temporary raw image */
-    fd = mkstemp(t_path);
-    g_assert_cmpint(fd, >=, 0);
-    ret = ftruncate(fd, TEST_IMAGE_SIZE);
-    g_assert_cmpint(ret, ==, 0);
-    close(fd);
-
-    g_test_queue_destroy(drive_destroy, t_path);
-    return t_path;
-}
-
-static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
-{
-    if (qvirtio_is_big_endian(d) != host_is_big_endian) {
-        req->type = bswap32(req->type);
-        req->ioprio = bswap32(req->ioprio);
-        req->sector = bswap64(req->sector);
-    }
-}
-
-
-static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
-    struct virtio_blk_discard_write_zeroes *dwz_hdr)
-{
-    if (qvirtio_is_big_endian(d) != host_is_big_endian) {
-        dwz_hdr->sector = bswap64(dwz_hdr->sector);
-        dwz_hdr->num_sectors = bswap32(dwz_hdr->num_sectors);
-        dwz_hdr->flags = bswap32(dwz_hdr->flags);
-    }
-}
-
-static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
-                                   QVirtioBlkReq *req, uint64_t data_size)
-{
-    uint64_t addr;
-    uint8_t status = 0xFF;
-
-    switch (req->type) {
-    case VIRTIO_BLK_T_IN:
-    case VIRTIO_BLK_T_OUT:
-        g_assert_cmpuint(data_size % 512, ==, 0);
-        break;
-    case VIRTIO_BLK_T_DISCARD:
-    case VIRTIO_BLK_T_WRITE_ZEROES:
-        g_assert_cmpuint(data_size %
-                         sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
-        break;
-    default:
-        g_assert_cmpuint(data_size, ==, 0);
-    }
-
-    addr = guest_alloc(alloc, sizeof(*req) + data_size);
-
-    virtio_blk_fix_request(d, req);
-
-    memwrite(addr, req, 16);
-    memwrite(addr + 16, req->data, data_size);
-    memwrite(addr + 16 + data_size, &status, sizeof(status));
-
-    return addr;
-}
-
-/* Returns the request virtqueue so the caller can perform further tests */
-static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
-{
-    QVirtioBlkReq req;
-    uint64_t req_addr;
-    uint64_t capacity;
-    uint64_t features;
-    uint32_t free_head;
-    uint8_t status;
-    char *data;
-    QTestState *qts = global_qtest;
-    QVirtQueue *vq;
-
-    features = qvirtio_get_features(dev);
-    features = features & ~(QVIRTIO_F_BAD_FEATURE |
-                    (1u << VIRTIO_RING_F_INDIRECT_DESC) |
-                    (1u << VIRTIO_RING_F_EVENT_IDX) |
-                    (1u << VIRTIO_BLK_F_SCSI));
-    qvirtio_set_features(dev, features);
-
-    capacity = qvirtio_config_readq(dev, 0);
-    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
-
-    vq = qvirtqueue_setup(dev, alloc, 0);
-
-    qvirtio_set_driver_ok(dev);
-
-    /* Write and read with 3 descriptor layout */
-    /* Write request */
-    req.type = VIRTIO_BLK_T_OUT;
-    req.ioprio = 1;
-    req.sector = 0;
-    req.data = g_malloc0(512);
-    strcpy(req.data, "TEST");
-
-    req_addr = virtio_blk_request(alloc, dev, &req, 512);
-
-    g_free(req.data);
-
-    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
-    qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
-    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
-
-    qvirtqueue_kick(qts, dev, vq, free_head);
-
-    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                           QVIRTIO_BLK_TIMEOUT_US);
-    status = readb(req_addr + 528);
-    g_assert_cmpint(status, ==, 0);
-
-    guest_free(alloc, req_addr);
-
-    /* Read request */
-    req.type = VIRTIO_BLK_T_IN;
-    req.ioprio = 1;
-    req.sector = 0;
-    req.data = g_malloc0(512);
-
-    req_addr = virtio_blk_request(alloc, dev, &req, 512);
-
-    g_free(req.data);
-
-    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
-    qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
-    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
-
-    qvirtqueue_kick(qts, dev, vq, free_head);
-
-    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                           QVIRTIO_BLK_TIMEOUT_US);
-    status = readb(req_addr + 528);
-    g_assert_cmpint(status, ==, 0);
-
-    data = g_malloc0(512);
-    memread(req_addr + 16, data, 512);
-    g_assert_cmpstr(data, ==, "TEST");
-    g_free(data);
-
-    guest_free(alloc, req_addr);
-
-    if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
-        struct virtio_blk_discard_write_zeroes dwz_hdr;
-        void *expected;
-
-        /*
-         * WRITE_ZEROES request on the same sector of previous test where
-         * we wrote "TEST".
-         */
-        req.type = VIRTIO_BLK_T_WRITE_ZEROES;
-        req.data = (char *) &dwz_hdr;
-        dwz_hdr.sector = 0;
-        dwz_hdr.num_sectors = 1;
-        dwz_hdr.flags = 0;
-
-        virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
-
-        req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
-
-        free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
-        qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
-        qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
-                       false);
-
-        qvirtqueue_kick(qts, dev, vq, free_head);
-
-        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                               QVIRTIO_BLK_TIMEOUT_US);
-        status = readb(req_addr + 16 + sizeof(dwz_hdr));
-        g_assert_cmpint(status, ==, 0);
-
-        guest_free(alloc, req_addr);
-
-        /* Read request to check if the sector contains all zeroes */
-        req.type = VIRTIO_BLK_T_IN;
-        req.ioprio = 1;
-        req.sector = 0;
-        req.data = g_malloc0(512);
-
-        req_addr = virtio_blk_request(alloc, dev, &req, 512);
-
-        g_free(req.data);
-
-        free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
-        qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
-        qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
-
-        qvirtqueue_kick(qts, dev, vq, free_head);
-
-        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                               QVIRTIO_BLK_TIMEOUT_US);
-        status = readb(req_addr + 528);
-        g_assert_cmpint(status, ==, 0);
-
-        data = g_malloc(512);
-        expected = g_malloc0(512);
-        memread(req_addr + 16, data, 512);
-        g_assert_cmpmem(data, 512, expected, 512);
-        g_free(expected);
-        g_free(data);
-
-        guest_free(alloc, req_addr);
-    }
-
-    if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
-        struct virtio_blk_discard_write_zeroes dwz_hdr;
-
-        req.type = VIRTIO_BLK_T_DISCARD;
-        req.data = (char *) &dwz_hdr;
-        dwz_hdr.sector = 0;
-        dwz_hdr.num_sectors = 1;
-        dwz_hdr.flags = 0;
-
-        virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
-
-        req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
-
-        free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
-        qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
-        qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false);
-
-        qvirtqueue_kick(qts, dev, vq, free_head);
-
-        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                               QVIRTIO_BLK_TIMEOUT_US);
-        status = readb(req_addr + 16 + sizeof(dwz_hdr));
-        g_assert_cmpint(status, ==, 0);
-
-        guest_free(alloc, req_addr);
-    }
-
-    if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
-        /* Write and read with 2 descriptor layout */
-        /* Write request */
-        req.type = VIRTIO_BLK_T_OUT;
-        req.ioprio = 1;
-        req.sector = 1;
-        req.data = g_malloc0(512);
-        strcpy(req.data, "TEST");
-
-        req_addr = virtio_blk_request(alloc, dev, &req, 512);
-
-        g_free(req.data);
-
-        free_head = qvirtqueue_add(qts, vq, req_addr, 528, false, true);
-        qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
-        qvirtqueue_kick(qts, dev, vq, free_head);
-
-        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                               QVIRTIO_BLK_TIMEOUT_US);
-        status = readb(req_addr + 528);
-        g_assert_cmpint(status, ==, 0);
-
-        guest_free(alloc, req_addr);
-
-        /* Read request */
-        req.type = VIRTIO_BLK_T_IN;
-        req.ioprio = 1;
-        req.sector = 1;
-        req.data = g_malloc0(512);
-
-        req_addr = virtio_blk_request(alloc, dev, &req, 512);
-
-        g_free(req.data);
-
-        free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
-        qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
-
-        qvirtqueue_kick(qts, dev, vq, free_head);
-
-        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                               QVIRTIO_BLK_TIMEOUT_US);
-        status = readb(req_addr + 528);
-        g_assert_cmpint(status, ==, 0);
-
-        data = g_malloc0(512);
-        memread(req_addr + 16, data, 512);
-        g_assert_cmpstr(data, ==, "TEST");
-        g_free(data);
-
-        guest_free(alloc, req_addr);
-    }
-
-    return vq;
-}
-
-static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtioBlk *blk_if = obj;
-    QVirtQueue *vq;
-
-    vq = test_basic(blk_if->vdev, t_alloc);
-    qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
-
-}
-
-static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
-{
-    QVirtQueue *vq;
-    QVirtioBlk *blk_if = obj;
-    QVirtioDevice *dev = blk_if->vdev;
-    QVirtioBlkReq req;
-    QVRingIndirectDesc *indirect;
-    uint64_t req_addr;
-    uint64_t capacity;
-    uint64_t features;
-    uint32_t free_head;
-    uint8_t status;
-    char *data;
-    QTestState *qts = global_qtest;
-
-    features = qvirtio_get_features(dev);
-    g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
-    features = features & ~(QVIRTIO_F_BAD_FEATURE |
-                            (1u << VIRTIO_RING_F_EVENT_IDX) |
-                            (1u << VIRTIO_BLK_F_SCSI));
-    qvirtio_set_features(dev, features);
-
-    capacity = qvirtio_config_readq(dev, 0);
-    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
-
-    vq = qvirtqueue_setup(dev, t_alloc, 0);
-    qvirtio_set_driver_ok(dev);
-
-    /* Write request */
-    req.type = VIRTIO_BLK_T_OUT;
-    req.ioprio = 1;
-    req.sector = 0;
-    req.data = g_malloc0(512);
-    strcpy(req.data, "TEST");
-
-    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
-
-    g_free(req.data);
-
-    indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
-    qvring_indirect_desc_add(dev, qts, indirect, req_addr, 528, false);
-    qvring_indirect_desc_add(dev, qts, indirect, req_addr + 528, 1, true);
-    free_head = qvirtqueue_add_indirect(qts, vq, indirect);
-    qvirtqueue_kick(qts, dev, vq, free_head);
-
-    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                           QVIRTIO_BLK_TIMEOUT_US);
-    status = readb(req_addr + 528);
-    g_assert_cmpint(status, ==, 0);
-
-    g_free(indirect);
-    guest_free(t_alloc, req_addr);
-
-    /* Read request */
-    req.type = VIRTIO_BLK_T_IN;
-    req.ioprio = 1;
-    req.sector = 0;
-    req.data = g_malloc0(512);
-    strcpy(req.data, "TEST");
-
-    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
-
-    g_free(req.data);
-
-    indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
-    qvring_indirect_desc_add(dev, qts, indirect, req_addr, 16, false);
-    qvring_indirect_desc_add(dev, qts, indirect, req_addr + 16, 513, true);
-    free_head = qvirtqueue_add_indirect(qts, vq, indirect);
-    qvirtqueue_kick(qts, dev, vq, free_head);
-
-    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                           QVIRTIO_BLK_TIMEOUT_US);
-    status = readb(req_addr + 528);
-    g_assert_cmpint(status, ==, 0);
-
-    data = g_malloc0(512);
-    memread(req_addr + 16, data, 512);
-    g_assert_cmpstr(data, ==, "TEST");
-    g_free(data);
-
-    g_free(indirect);
-    guest_free(t_alloc, req_addr);
-    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
-}
-
-static void config(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtioBlk *blk_if = obj;
-    QVirtioDevice *dev = blk_if->vdev;
-    int n_size = TEST_IMAGE_SIZE / 2;
-    uint64_t features;
-    uint64_t capacity;
-
-    features = qvirtio_get_features(dev);
-    features = features & ~(QVIRTIO_F_BAD_FEATURE |
-                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
-                            (1u << VIRTIO_RING_F_EVENT_IDX) |
-                            (1u << VIRTIO_BLK_F_SCSI));
-    qvirtio_set_features(dev, features);
-
-    capacity = qvirtio_config_readq(dev, 0);
-    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
-
-    qvirtio_set_driver_ok(dev);
-
-    qmp_discard_response("{ 'execute': 'block_resize', "
-                         " 'arguments': { 'device': 'drive0', "
-                         " 'size': %d } }", n_size);
-    qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
-
-    capacity = qvirtio_config_readq(dev, 0);
-    g_assert_cmpint(capacity, ==, n_size / 512);
-}
-
-static void msix(void *obj, void *u_data, QGuestAllocator *t_alloc)
-{
-    QVirtQueue *vq;
-    QVirtioBlkPCI *blk = obj;
-    QVirtioPCIDevice *pdev = &blk->pci_vdev;
-    QVirtioDevice *dev = &pdev->vdev;
-    QVirtioBlkReq req;
-    int n_size = TEST_IMAGE_SIZE / 2;
-    uint64_t req_addr;
-    uint64_t capacity;
-    uint64_t features;
-    uint32_t free_head;
-    uint8_t status;
-    char *data;
-    QOSGraphObject *blk_object = obj;
-    QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
-    QTestState *qts = global_qtest;
-
-    if (qpci_check_buggy_msi(pci_dev)) {
-        return;
-    }
-
-    qpci_msix_enable(pdev->pdev);
-    qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
-
-    features = qvirtio_get_features(dev);
-    features = features & ~(QVIRTIO_F_BAD_FEATURE |
-                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
-                            (1u << VIRTIO_RING_F_EVENT_IDX) |
-                            (1u << VIRTIO_BLK_F_SCSI));
-    qvirtio_set_features(dev, features);
-
-    capacity = qvirtio_config_readq(dev, 0);
-    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
-
-    vq = qvirtqueue_setup(dev, t_alloc, 0);
-    qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
-
-    qvirtio_set_driver_ok(dev);
-
-    qmp_discard_response("{ 'execute': 'block_resize', "
-                         " 'arguments': { 'device': 'drive0', "
-                         " 'size': %d } }", n_size);
-
-    qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
-
-    capacity = qvirtio_config_readq(dev, 0);
-    g_assert_cmpint(capacity, ==, n_size / 512);
-
-    /* Write request */
-    req.type = VIRTIO_BLK_T_OUT;
-    req.ioprio = 1;
-    req.sector = 0;
-    req.data = g_malloc0(512);
-    strcpy(req.data, "TEST");
-
-    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
-
-    g_free(req.data);
-
-    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
-    qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
-    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
-    qvirtqueue_kick(qts, dev, vq, free_head);
-
-    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                           QVIRTIO_BLK_TIMEOUT_US);
-
-    status = readb(req_addr + 528);
-    g_assert_cmpint(status, ==, 0);
-
-    guest_free(t_alloc, req_addr);
-
-    /* Read request */
-    req.type = VIRTIO_BLK_T_IN;
-    req.ioprio = 1;
-    req.sector = 0;
-    req.data = g_malloc0(512);
-
-    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
-
-    g_free(req.data);
-
-    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
-    qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
-    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
-
-    qvirtqueue_kick(qts, dev, vq, free_head);
-
-
-    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                           QVIRTIO_BLK_TIMEOUT_US);
-
-    status = readb(req_addr + 528);
-    g_assert_cmpint(status, ==, 0);
-
-    data = g_malloc0(512);
-    memread(req_addr + 16, data, 512);
-    g_assert_cmpstr(data, ==, "TEST");
-    g_free(data);
-
-    guest_free(t_alloc, req_addr);
-
-    /* End test */
-    qpci_msix_disable(pdev->pdev);
-    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
-}
-
-static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
-{
-    QVirtQueue *vq;
-    QVirtioBlkPCI *blk = obj;
-    QVirtioPCIDevice *pdev = &blk->pci_vdev;
-    QVirtioDevice *dev = &pdev->vdev;
-    QVirtioBlkReq req;
-    uint64_t req_addr;
-    uint64_t capacity;
-    uint64_t features;
-    uint32_t free_head;
-    uint32_t write_head;
-    uint32_t desc_idx;
-    uint8_t status;
-    char *data;
-    QOSGraphObject *blk_object = obj;
-    QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
-    QTestState *qts = global_qtest;
-
-    if (qpci_check_buggy_msi(pci_dev)) {
-        return;
-    }
-
-    qpci_msix_enable(pdev->pdev);
-    qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
-
-    features = qvirtio_get_features(dev);
-    features = features & ~(QVIRTIO_F_BAD_FEATURE |
-                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
-                            (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
-                            (1u << VIRTIO_BLK_F_SCSI));
-    qvirtio_set_features(dev, features);
-
-    capacity = qvirtio_config_readq(dev, 0);
-    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
-
-    vq = qvirtqueue_setup(dev, t_alloc, 0);
-    qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
-
-    qvirtio_set_driver_ok(dev);
-
-    /* Write request */
-    req.type = VIRTIO_BLK_T_OUT;
-    req.ioprio = 1;
-    req.sector = 0;
-    req.data = g_malloc0(512);
-    strcpy(req.data, "TEST");
-
-    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
-
-    g_free(req.data);
-
-    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
-    qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
-    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
-    qvirtqueue_kick(qts, dev, vq, free_head);
-
-    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                           QVIRTIO_BLK_TIMEOUT_US);
-
-    /* Write request */
-    req.type = VIRTIO_BLK_T_OUT;
-    req.ioprio = 1;
-    req.sector = 1;
-    req.data = g_malloc0(512);
-    strcpy(req.data, "TEST");
-
-    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
-
-    g_free(req.data);
-
-    /* Notify after processing the third request */
-    qvirtqueue_set_used_event(qts, vq, 2);
-    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
-    qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
-    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
-    qvirtqueue_kick(qts, dev, vq, free_head);
-    write_head = free_head;
-
-    /* No notification expected */
-    status = qvirtio_wait_status_byte_no_isr(qts, dev,
-                                             vq, req_addr + 528,
-                                             QVIRTIO_BLK_TIMEOUT_US);
-    g_assert_cmpint(status, ==, 0);
-
-    guest_free(t_alloc, req_addr);
-
-    /* Read request */
-    req.type = VIRTIO_BLK_T_IN;
-    req.ioprio = 1;
-    req.sector = 1;
-    req.data = g_malloc0(512);
-
-    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
-
-    g_free(req.data);
-
-    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
-    qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
-    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
-
-    qvirtqueue_kick(qts, dev, vq, free_head);
-
-    /* We get just one notification for both requests */
-    qvirtio_wait_used_elem(qts, dev, vq, write_head, NULL,
-                           QVIRTIO_BLK_TIMEOUT_US);
-    g_assert(qvirtqueue_get_buf(qts, vq, &desc_idx, NULL));
-    g_assert_cmpint(desc_idx, ==, free_head);
-
-    status = readb(req_addr + 528);
-    g_assert_cmpint(status, ==, 0);
-
-    data = g_malloc0(512);
-    memread(req_addr + 16, data, 512);
-    g_assert_cmpstr(data, ==, "TEST");
-    g_free(data);
-
-    guest_free(t_alloc, req_addr);
-
-    /* End test */
-    qpci_msix_disable(pdev->pdev);
-
-    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
-}
-
-static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtioPCIDevice *dev1 = obj;
-    QVirtioPCIDevice *dev;
-    QTestState *qts = dev1->pdev->bus->qts;
-
-    /* plug secondary disk */
-    qtest_qmp_device_add(qts, "virtio-blk-pci", "drv1",
-                         "{'addr': %s, 'drive': 'drive1'}",
-                         stringify(PCI_SLOT_HP) ".0");
-
-    dev = virtio_pci_new(dev1->pdev->bus,
-                         &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0) });
-    g_assert_nonnull(dev);
-    g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
-    qvirtio_pci_device_disable(dev);
-    qos_object_destroy((QOSGraphObject *)dev);
-
-    /* unplug secondary disk */
-    qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
-}
-
-/*
- * Check that setting the vring addr on a non-existent virtqueue does
- * not crash.
- */
-static void test_nonexistent_virtqueue(void *obj, void *data,
-                                       QGuestAllocator *t_alloc)
-{
-    QVirtioBlkPCI *blk = obj;
-    QVirtioPCIDevice *pdev = &blk->pci_vdev;
-    QPCIBar bar0;
-    QPCIDevice *dev;
-
-    dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
-    g_assert(dev != NULL);
-    qpci_device_enable(dev);
-
-    bar0 = qpci_iomap(dev, 0, NULL);
-
-    qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
-    qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
-
-
-    g_free(dev);
-}
-
-static void resize(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtioBlk *blk_if = obj;
-    QVirtioDevice *dev = blk_if->vdev;
-    int n_size = TEST_IMAGE_SIZE / 2;
-    uint64_t capacity;
-    QVirtQueue *vq;
-    QTestState *qts = global_qtest;
-
-    vq = test_basic(dev, t_alloc);
-
-    qmp_discard_response("{ 'execute': 'block_resize', "
-                         " 'arguments': { 'device': 'drive0', "
-                         " 'size': %d } }", n_size);
-
-    qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
-
-    capacity = qvirtio_config_readq(dev, 0);
-    g_assert_cmpint(capacity, ==, n_size / 512);
-
-    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
-
-}
-
-static void *virtio_blk_test_setup(GString *cmd_line, void *arg)
-{
-    char *tmp_path = drive_create();
-
-    g_string_append_printf(cmd_line,
-                           " -drive if=none,id=drive0,file=%s,"
-                           "format=raw,auto-read-only=off "
-                           "-drive if=none,id=drive1,file=null-co://,"
-                           "file.read-zeroes=on,format=raw ",
-                           tmp_path);
-
-    return arg;
-}
-
-static void register_virtio_blk_test(void)
-{
-    QOSGraphTestOptions opts = {
-        .before = virtio_blk_test_setup,
-    };
-
-    qos_add_test("indirect", "virtio-blk", indirect, &opts);
-    qos_add_test("config", "virtio-blk", config, &opts);
-    qos_add_test("basic", "virtio-blk", basic, &opts);
-    qos_add_test("resize", "virtio-blk", resize, &opts);
-
-    /* tests just for virtio-blk-pci */
-    qos_add_test("msix", "virtio-blk-pci", msix, &opts);
-    qos_add_test("idx", "virtio-blk-pci", idx, &opts);
-    qos_add_test("nxvirtq", "virtio-blk-pci",
-                      test_nonexistent_virtqueue, &opts);
-    qos_add_test("hotplug", "virtio-blk-pci", pci_hotplug, &opts);
-}
-
-libqos_init(register_virtio_blk_test);
diff --git a/tests/virtio-ccw-test.c b/tests/virtio-ccw-test.c
deleted file mode 100644 (file)
index d052364..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * QTest testcase for VirtIO CCW
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- * Copyright (c) 2018 Red Hat, Inc.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-/* Until we have a full libqos implementation of virtio-ccw (which requires
- * also to add support for I/O channels to qtest), we can only do simple
- * tests that initialize the devices.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-#include "libqos/virtio.h"
-
-static void virtio_balloon_nop(void)
-{
-    global_qtest = qtest_initf("-device virtio-balloon-ccw");
-    qtest_end();
-}
-
-static void virtconsole_nop(void)
-{
-    global_qtest = qtest_initf("-device virtio-serial-ccw,id=vser0 "
-                                "-device virtconsole,bus=vser0.0");
-    qtest_end();
-}
-
-static void virtserialport_nop(void)
-{
-    global_qtest = qtest_initf("-device virtio-serial-ccw,id=vser0 "
-                                "-device virtserialport,bus=vser0.0");
-    qtest_end();
-}
-
-static void virtio_serial_nop(void)
-{
-    global_qtest = qtest_initf("-device virtio-serial-ccw");
-    qtest_end();
-}
-
-static void virtio_serial_hotplug(void)
-{
-    QTestState *qts = qtest_initf("-device virtio-serial-ccw");
-
-    qtest_qmp_device_add(qts, "virtserialport", "hp-port", "{}");
-    qtest_qmp_device_del(qts, "hp-port");
-
-    qtest_quit(qts);
-}
-
-static void virtio_blk_nop(void)
-{
-    global_qtest = qtest_initf("-drive if=none,id=drv0,file=null-co://,"
-                               "file.read-zeroes=on,format=raw "
-                                "-device virtio-blk-ccw,drive=drv0");
-    qtest_end();
-}
-
-static void virtio_net_nop(void)
-{
-    global_qtest = qtest_initf("-device virtio-net-ccw");
-    qtest_end();
-}
-
-static void virtio_rng_nop(void)
-{
-    global_qtest = qtest_initf("-device virtio-rng-ccw");
-    qtest_end();
-}
-
-static void virtio_scsi_nop(void)
-{
-    global_qtest = qtest_initf("-device virtio-scsi-ccw");
-    qtest_end();
-}
-
-static void virtio_scsi_hotplug(void)
-{
-    QTestState *s = qtest_initf("-drive if=none,id=drv0,file=null-co://,"
-                                "file.read-zeroes=on,format=raw "
-                                "-drive if=none,id=drv1,file=null-co://,"
-                                "file.read-zeroes=on,format=raw "
-                                "-device virtio-scsi-ccw "
-                                "-device scsi-hd,drive=drv0");
-    qtest_qmp_device_add(s, "scsi-hd", "scsihd", "{'drive': 'drv1'}");
-    qtest_qmp_device_del(s, "scsihd");
-
-    qtest_quit(s);
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/virtio/balloon/nop", virtio_balloon_nop);
-    qtest_add_func("/virtio/console/nop", virtconsole_nop);
-    qtest_add_func("/virtio/serialport/nop", virtserialport_nop);
-    qtest_add_func("/virtio/serial/nop", virtio_serial_nop);
-    qtest_add_func("/virtio/serial/hotplug", virtio_serial_hotplug);
-    qtest_add_func("/virtio/block/nop", virtio_blk_nop);
-    qtest_add_func("/virtio/net/nop", virtio_net_nop);
-    qtest_add_func("/virtio/rng/nop", virtio_rng_nop);
-    qtest_add_func("/virtio/scsi/nop", virtio_scsi_nop);
-    qtest_add_func("/virtio/scsi/hotplug", virtio_scsi_hotplug);
-
-    ret = g_test_run();
-
-    return ret;
-}
diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c
deleted file mode 100644 (file)
index a08e2ff..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * QTest testcase for VirtIO NIC
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "libqtest-single.h"
-#include "qemu/iov.h"
-#include "qemu/module.h"
-#include "qapi/qmp/qdict.h"
-#include "hw/virtio/virtio-net.h"
-#include "libqos/qgraph.h"
-#include "libqos/virtio-net.h"
-
-#ifndef ETH_P_RARP
-#define ETH_P_RARP 0x8035
-#endif
-
-#define PCI_SLOT_HP             0x06
-#define PCI_SLOT                0x04
-
-#define QVIRTIO_NET_TIMEOUT_US (30 * 1000 * 1000)
-#define VNET_HDR_SIZE sizeof(struct virtio_net_hdr_mrg_rxbuf)
-
-#ifndef _WIN32
-
-static void rx_test(QVirtioDevice *dev,
-                    QGuestAllocator *alloc, QVirtQueue *vq,
-                    int socket)
-{
-    QTestState *qts = global_qtest;
-    uint64_t req_addr;
-    uint32_t free_head;
-    char test[] = "TEST";
-    char buffer[64];
-    int len = htonl(sizeof(test));
-    struct iovec iov[] = {
-        {
-            .iov_base = &len,
-            .iov_len = sizeof(len),
-        }, {
-            .iov_base = test,
-            .iov_len = sizeof(test),
-        },
-    };
-    int ret;
-
-    req_addr = guest_alloc(alloc, 64);
-
-    free_head = qvirtqueue_add(qts, vq, req_addr, 64, true, false);
-    qvirtqueue_kick(qts, dev, vq, free_head);
-
-    ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test));
-    g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len));
-
-    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                           QVIRTIO_NET_TIMEOUT_US);
-    memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test));
-    g_assert_cmpstr(buffer, ==, "TEST");
-
-    guest_free(alloc, req_addr);
-}
-
-static void tx_test(QVirtioDevice *dev,
-                    QGuestAllocator *alloc, QVirtQueue *vq,
-                    int socket)
-{
-    QTestState *qts = global_qtest;
-    uint64_t req_addr;
-    uint32_t free_head;
-    uint32_t len;
-    char buffer[64];
-    int ret;
-
-    req_addr = guest_alloc(alloc, 64);
-    memwrite(req_addr + VNET_HDR_SIZE, "TEST", 4);
-
-    free_head = qvirtqueue_add(qts, vq, req_addr, 64, false, false);
-    qvirtqueue_kick(qts, dev, vq, free_head);
-
-    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                           QVIRTIO_NET_TIMEOUT_US);
-    guest_free(alloc, req_addr);
-
-    ret = qemu_recv(socket, &len, sizeof(len), 0);
-    g_assert_cmpint(ret, ==, sizeof(len));
-    len = ntohl(len);
-
-    ret = qemu_recv(socket, buffer, len, 0);
-    g_assert_cmpstr(buffer, ==, "TEST");
-}
-
-static void rx_stop_cont_test(QVirtioDevice *dev,
-                              QGuestAllocator *alloc, QVirtQueue *vq,
-                              int socket)
-{
-    QTestState *qts = global_qtest;
-    uint64_t req_addr;
-    uint32_t free_head;
-    char test[] = "TEST";
-    char buffer[64];
-    int len = htonl(sizeof(test));
-    QDict *rsp;
-    struct iovec iov[] = {
-        {
-            .iov_base = &len,
-            .iov_len = sizeof(len),
-        }, {
-            .iov_base = test,
-            .iov_len = sizeof(test),
-        },
-    };
-    int ret;
-
-    req_addr = guest_alloc(alloc, 64);
-
-    free_head = qvirtqueue_add(qts, vq, req_addr, 64, true, false);
-    qvirtqueue_kick(qts, dev, vq, free_head);
-
-    rsp = qmp("{ 'execute' : 'stop'}");
-    qobject_unref(rsp);
-
-    ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test));
-    g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len));
-
-    /* We could check the status, but this command is more importantly to
-     * ensure the packet data gets queued in QEMU, before we do 'cont'.
-     */
-    rsp = qmp("{ 'execute' : 'query-status'}");
-    qobject_unref(rsp);
-    rsp = qmp("{ 'execute' : 'cont'}");
-    qobject_unref(rsp);
-
-    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
-                           QVIRTIO_NET_TIMEOUT_US);
-    memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test));
-    g_assert_cmpstr(buffer, ==, "TEST");
-
-    guest_free(alloc, req_addr);
-}
-
-static void send_recv_test(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtioNet *net_if = obj;
-    QVirtioDevice *dev = net_if->vdev;
-    QVirtQueue *rx = net_if->queues[0];
-    QVirtQueue *tx = net_if->queues[1];
-    int *sv = data;
-
-    rx_test(dev, t_alloc, rx, sv[0]);
-    tx_test(dev, t_alloc, tx, sv[0]);
-}
-
-static void stop_cont_test(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtioNet *net_if = obj;
-    QVirtioDevice *dev = net_if->vdev;
-    QVirtQueue *rx = net_if->queues[0];
-    int *sv = data;
-
-    rx_stop_cont_test(dev, t_alloc, rx, sv[0]);
-}
-
-#endif
-
-static void hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtioPCIDevice *dev = obj;
-    QTestState *qts = dev->pdev->bus->qts;
-    const char *arch = qtest_get_arch();
-
-    qtest_qmp_device_add(qts, "virtio-net-pci", "net1",
-                         "{'addr': %s}", stringify(PCI_SLOT_HP));
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        qpci_unplug_acpi_device_test(qts, "net1", PCI_SLOT_HP);
-    }
-}
-
-static void announce_self(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    int *sv = data;
-    char buffer[60];
-    int len;
-    QDict *rsp;
-    int ret;
-    uint16_t *proto = (uint16_t *)&buffer[12];
-    size_t total_received = 0;
-    uint64_t start, now, last_rxt, deadline;
-
-    /* Send a set of packets over a few second period */
-    rsp = qmp("{ 'execute' : 'announce-self', "
-                  " 'arguments': {"
-                      " 'initial': 20, 'max': 100,"
-                      " 'rounds': 300, 'step': 10, 'id': 'bob' } }");
-    assert(!qdict_haskey(rsp, "error"));
-    qobject_unref(rsp);
-
-    /* Catch the first packet and make sure it's a RARP */
-    ret = qemu_recv(sv[0], &len, sizeof(len), 0);
-    g_assert_cmpint(ret, ==,  sizeof(len));
-    len = ntohl(len);
-
-    ret = qemu_recv(sv[0], buffer, len, 0);
-    g_assert_cmpint(*proto, ==, htons(ETH_P_RARP));
-
-    /*
-     * Stop the announcment by settings rounds to 0 on the
-     * existing timer.
-     */
-    rsp = qmp("{ 'execute' : 'announce-self', "
-                  " 'arguments': {"
-                      " 'initial': 20, 'max': 100,"
-                      " 'rounds': 0, 'step': 10, 'id': 'bob' } }");
-    assert(!qdict_haskey(rsp, "error"));
-    qobject_unref(rsp);
-
-    /* Now make sure the packets stop */
-
-    /* Times are in us */
-    start = g_get_monotonic_time();
-    /* 30 packets, max gap 100ms, * 4 for wiggle */
-    deadline = start + 1000 * (100 * 30 * 4);
-    last_rxt = start;
-
-    while (true) {
-        int saved_err;
-        ret = qemu_recv(sv[0], buffer, 60, MSG_DONTWAIT);
-        saved_err = errno;
-        now = g_get_monotonic_time();
-        g_assert_cmpint(now, <, deadline);
-
-        if (ret >= 0) {
-            if (ret) {
-                last_rxt = now;
-            }
-            total_received += ret;
-
-            /* Check it's not spewing loads */
-            g_assert_cmpint(total_received, <, 60 * 30 * 2);
-        } else {
-            g_assert_cmpint(saved_err, ==, EAGAIN);
-
-            /* 400ms, i.e. 4 worst case gaps */
-            if ((now - last_rxt) > (1000 * 100 * 4)) {
-                /* Nothings arrived for a while - must have stopped */
-                break;
-            };
-
-            /* 100ms */
-            g_usleep(1000 * 100);
-        }
-    };
-}
-
-static void virtio_net_test_cleanup(void *sockets)
-{
-    int *sv = sockets;
-
-    close(sv[0]);
-    qos_invalidate_command_line();
-    close(sv[1]);
-    g_free(sv);
-}
-
-static void *virtio_net_test_setup(GString *cmd_line, void *arg)
-{
-    int ret;
-    int *sv = g_new(int, 2);
-
-    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
-    g_assert_cmpint(ret, !=, -1);
-
-    g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ", sv[1]);
-
-    g_test_queue_destroy(virtio_net_test_cleanup, sv);
-    return sv;
-}
-
-static void large_tx(void *obj, void *data, QGuestAllocator *t_alloc)
-{
-    QVirtioNet *dev = obj;
-    QVirtQueue *vq = dev->queues[1];
-    uint64_t req_addr;
-    uint32_t free_head;
-    size_t alloc_size = (size_t)data / 64;
-    QTestState *qts = global_qtest;
-    int i;
-
-    /* Bypass the limitation by pointing several descriptors to a single
-     * smaller area */
-    req_addr = guest_alloc(t_alloc, alloc_size);
-    free_head = qvirtqueue_add(qts, vq, req_addr, alloc_size, false, true);
-
-    for (i = 0; i < 64; i++) {
-        qvirtqueue_add(qts, vq, req_addr, alloc_size, false, i != 63);
-    }
-    qvirtqueue_kick(qts, dev->vdev, vq, free_head);
-
-    qvirtio_wait_used_elem(qts, dev->vdev, vq, free_head, NULL,
-                           QVIRTIO_NET_TIMEOUT_US);
-    guest_free(t_alloc, req_addr);
-}
-
-static void *virtio_net_test_setup_nosocket(GString *cmd_line, void *arg)
-{
-    g_string_append(cmd_line, " -netdev hubport,hubid=0,id=hs0 ");
-    return arg;
-}
-
-static void register_virtio_net_test(void)
-{
-    QOSGraphTestOptions opts = {
-        .before = virtio_net_test_setup,
-    };
-
-    qos_add_test("hotplug", "virtio-pci", hotplug, &opts);
-#ifndef _WIN32
-    qos_add_test("basic", "virtio-net", send_recv_test, &opts);
-    qos_add_test("rx_stop_cont", "virtio-net", stop_cont_test, &opts);
-#endif
-    qos_add_test("announce-self", "virtio-net", announce_self, &opts);
-
-    /* These tests do not need a loopback backend.  */
-    opts.before = virtio_net_test_setup_nosocket;
-    opts.arg = (gpointer)UINT_MAX;
-    qos_add_test("large_tx/uint_max", "virtio-net", large_tx, &opts);
-    opts.arg = (gpointer)NET_BUFSIZE;
-    qos_add_test("large_tx/net_bufsize", "virtio-net", large_tx, &opts);
-}
-
-libqos_init(register_virtio_net_test);
diff --git a/tests/virtio-rng-test.c b/tests/virtio-rng-test.c
deleted file mode 100644 (file)
index 092ba13..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * QTest testcase for VirtIO RNG
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qemu/module.h"
-#include "libqos/qgraph.h"
-#include "libqos/virtio-rng.h"
-
-#define PCI_SLOT_HP             0x06
-
-static void rng_hotplug(void *obj, void *data, QGuestAllocator *alloc)
-{
-    QVirtioPCIDevice *dev = obj;
-    QTestState *qts = dev->pdev->bus->qts;
-
-    const char *arch = qtest_get_arch();
-
-    qtest_qmp_device_add(qts, "virtio-rng-pci", "rng1",
-                         "{'addr': %s}", stringify(PCI_SLOT_HP));
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        qpci_unplug_acpi_device_test(qts, "rng1", PCI_SLOT_HP);
-    }
-}
-
-static void register_virtio_rng_test(void)
-{
-    qos_add_test("hotplug", "virtio-rng-pci", rng_hotplug, NULL);
-}
-
-libqos_init(register_virtio_rng_test);
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
deleted file mode 100644 (file)
index 0415e75..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * QTest testcase for VirtIO SCSI
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- * Copyright (c) 2015 Red Hat Inc.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-#include "qemu/module.h"
-#include "scsi/constants.h"
-#include "libqos/libqos-pc.h"
-#include "libqos/libqos-spapr.h"
-#include "libqos/virtio.h"
-#include "libqos/virtio-pci.h"
-#include "standard-headers/linux/virtio_ids.h"
-#include "standard-headers/linux/virtio_pci.h"
-#include "standard-headers/linux/virtio_scsi.h"
-#include "libqos/virtio-scsi.h"
-#include "libqos/qgraph.h"
-
-#define PCI_SLOT                0x02
-#define PCI_FN                  0x00
-#define QVIRTIO_SCSI_TIMEOUT_US (1 * 1000 * 1000)
-
-#define MAX_NUM_QUEUES 64
-
-typedef struct {
-    QVirtioDevice *dev;
-    int num_queues;
-    QVirtQueue *vq[MAX_NUM_QUEUES + 2];
-} QVirtioSCSIQueues;
-
-static QGuestAllocator *alloc;
-
-static void qvirtio_scsi_pci_free(QVirtioSCSIQueues *vs)
-{
-    int i;
-
-    for (i = 0; i < vs->num_queues + 2; i++) {
-        qvirtqueue_cleanup(vs->dev->bus, vs->vq[i], alloc);
-    }
-    g_free(vs);
-}
-
-static uint64_t qvirtio_scsi_alloc(QVirtioSCSIQueues *vs, size_t alloc_size,
-                                   const void *data)
-{
-    uint64_t addr;
-
-    addr = guest_alloc(alloc, alloc_size);
-    if (data) {
-        memwrite(addr, data, alloc_size);
-    }
-
-    return addr;
-}
-
-static uint8_t virtio_scsi_do_command(QVirtioSCSIQueues *vs,
-                                      const uint8_t *cdb,
-                                      const uint8_t *data_in,
-                                      size_t data_in_len,
-                                      uint8_t *data_out, size_t data_out_len,
-                                      struct virtio_scsi_cmd_resp *resp_out)
-{
-    QVirtQueue *vq;
-    struct virtio_scsi_cmd_req req = { { 0 } };
-    struct virtio_scsi_cmd_resp resp = { .response = 0xff, .status = 0xff };
-    uint64_t req_addr, resp_addr, data_in_addr = 0, data_out_addr = 0;
-    uint8_t response;
-    uint32_t free_head;
-    QTestState *qts = global_qtest;
-
-    vq = vs->vq[2];
-
-    req.lun[0] = 1; /* Select LUN */
-    req.lun[1] = 1; /* Select target 1 */
-    memcpy(req.cdb, cdb, VIRTIO_SCSI_CDB_SIZE);
-
-    /* XXX: Fix endian if any multi-byte field in req/resp is used */
-
-    /* Add request header */
-    req_addr = qvirtio_scsi_alloc(vs, sizeof(req), &req);
-    free_head = qvirtqueue_add(qts, vq, req_addr, sizeof(req), false, true);
-
-    if (data_out_len) {
-        data_out_addr = qvirtio_scsi_alloc(vs, data_out_len, data_out);
-        qvirtqueue_add(qts, vq, data_out_addr, data_out_len, false, true);
-    }
-
-    /* Add response header */
-    resp_addr = qvirtio_scsi_alloc(vs, sizeof(resp), &resp);
-    qvirtqueue_add(qts, vq, resp_addr, sizeof(resp), true, !!data_in_len);
-
-    if (data_in_len) {
-        data_in_addr = qvirtio_scsi_alloc(vs, data_in_len, data_in);
-        qvirtqueue_add(qts, vq, data_in_addr, data_in_len, true, false);
-    }
-
-    qvirtqueue_kick(qts, vs->dev, vq, free_head);
-    qvirtio_wait_used_elem(qts, vs->dev, vq, free_head, NULL,
-                           QVIRTIO_SCSI_TIMEOUT_US);
-
-    response = readb(resp_addr +
-                     offsetof(struct virtio_scsi_cmd_resp, response));
-
-    if (resp_out) {
-        memread(resp_addr, resp_out, sizeof(*resp_out));
-    }
-
-    guest_free(alloc, req_addr);
-    guest_free(alloc, resp_addr);
-    guest_free(alloc, data_in_addr);
-    guest_free(alloc, data_out_addr);
-    return response;
-}
-
-static QVirtioSCSIQueues *qvirtio_scsi_init(QVirtioDevice *dev)
-{
-    QVirtioSCSIQueues *vs;
-    const uint8_t test_unit_ready_cdb[VIRTIO_SCSI_CDB_SIZE] = {};
-    struct virtio_scsi_cmd_resp resp;
-    uint64_t features;
-    int i;
-
-    vs = g_new0(QVirtioSCSIQueues, 1);
-    vs->dev = dev;
-
-    features = qvirtio_get_features(dev);
-    features &= ~(QVIRTIO_F_BAD_FEATURE | (1ull << VIRTIO_RING_F_EVENT_IDX));
-    qvirtio_set_features(dev, features);
-
-    vs->num_queues = qvirtio_config_readl(dev, 0);
-
-    g_assert_cmpint(vs->num_queues, <, MAX_NUM_QUEUES);
-
-    for (i = 0; i < vs->num_queues + 2; i++) {
-        vs->vq[i] = qvirtqueue_setup(dev, alloc, i);
-    }
-
-    qvirtio_set_driver_ok(dev);
-
-    /* Clear the POWER ON OCCURRED unit attention */
-    g_assert_cmpint(virtio_scsi_do_command(vs, test_unit_ready_cdb,
-                                           NULL, 0, NULL, 0, &resp),
-                    ==, 0);
-    g_assert_cmpint(resp.status, ==, CHECK_CONDITION);
-    g_assert_cmpint(resp.sense[0], ==, 0x70); /* Fixed format sense buffer */
-    g_assert_cmpint(resp.sense[2], ==, UNIT_ATTENTION);
-    g_assert_cmpint(resp.sense[12], ==, 0x29); /* POWER ON */
-    g_assert_cmpint(resp.sense[13], ==, 0x00);
-
-    return vs;
-}
-
-static void hotplug(void *obj, void *data, QGuestAllocator *alloc)
-{
-    QTestState *qts = global_qtest;
-
-    qtest_qmp_device_add(qts, "scsi-hd", "scsihd", "{'drive': 'drv1'}");
-    qtest_qmp_device_del(qts, "scsihd");
-}
-
-/* Test WRITE SAME with the lba not aligned */
-static void test_unaligned_write_same(void *obj, void *data,
-                                      QGuestAllocator *t_alloc)
-{
-    QVirtioSCSI *scsi = obj;
-    QVirtioSCSIQueues *vs;
-    uint8_t buf1[512] = { 0 };
-    uint8_t buf2[512] = { 1 };
-    const uint8_t write_same_cdb_1[VIRTIO_SCSI_CDB_SIZE] = {
-        0x41, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00
-    };
-    const uint8_t write_same_cdb_2[VIRTIO_SCSI_CDB_SIZE] = {
-        0x41, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x33, 0x00, 0x00
-    };
-    const uint8_t write_same_cdb_ndob[VIRTIO_SCSI_CDB_SIZE] = {
-        0x41, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x33, 0x00, 0x00
-    };
-
-    alloc = t_alloc;
-    vs = qvirtio_scsi_init(scsi->vdev);
-
-    g_assert_cmphex(0, ==,
-        virtio_scsi_do_command(vs, write_same_cdb_1, NULL, 0, buf1, 512,
-                               NULL));
-
-    g_assert_cmphex(0, ==,
-        virtio_scsi_do_command(vs, write_same_cdb_2, NULL, 0, buf2, 512,
-                               NULL));
-
-    g_assert_cmphex(0, ==,
-        virtio_scsi_do_command(vs, write_same_cdb_ndob, NULL, 0, NULL, 0,
-                               NULL));
-
-    qvirtio_scsi_pci_free(vs);
-}
-
-static void test_iothread_attach_node(void *obj, void *data,
-                                      QGuestAllocator *t_alloc)
-{
-    QVirtioSCSIPCI *scsi_pci = obj;
-    QVirtioSCSI *scsi = &scsi_pci->scsi;
-    QVirtioSCSIQueues *vs;
-    char tmp_path[] = "/tmp/qtest.XXXXXX";
-    int fd;
-    int ret;
-
-    uint8_t buf[512] = { 0 };
-    const uint8_t write_cdb[VIRTIO_SCSI_CDB_SIZE] = {
-        /* WRITE(10) to LBA 0, transfer length 1 */
-        0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
-    };
-
-    alloc = t_alloc;
-    vs = qvirtio_scsi_init(scsi->vdev);
-
-    /* Create a temporary qcow2 overlay*/
-    fd = mkstemp(tmp_path);
-    g_assert(fd >= 0);
-    close(fd);
-
-    if (!have_qemu_img()) {
-        g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
-                       "skipping snapshot test");
-        goto fail;
-    }
-
-    mkqcow2(tmp_path, 64);
-
-    /* Attach the overlay to the null0 node */
-    qtest_qmp_assert_success(scsi_pci->pci_vdev.pdev->bus->qts,
-                             "{'execute': 'blockdev-add', 'arguments': {"
-                             "   'driver': 'qcow2', 'node-name': 'overlay',"
-                             "   'backing': 'null0', 'file': {"
-                             "     'driver': 'file', 'filename': %s}}}",
-                             tmp_path);
-
-    /* Send a request to see if the AioContext is still right */
-    ret = virtio_scsi_do_command(vs, write_cdb, NULL, 0, buf, 512, NULL);
-    g_assert_cmphex(ret, ==, 0);
-
-fail:
-    qvirtio_scsi_pci_free(vs);
-    unlink(tmp_path);
-}
-
-static void *virtio_scsi_hotplug_setup(GString *cmd_line, void *arg)
-{
-    g_string_append(cmd_line,
-                    " -drive id=drv1,if=none,file=null-co://,"
-                    "file.read-zeroes=on,format=raw");
-    return arg;
-}
-
-static void *virtio_scsi_setup(GString *cmd_line, void *arg)
-{
-    g_string_append(cmd_line,
-                    " -drive file=blkdebug::null-co://,"
-                    "file.image.read-zeroes=on,"
-                    "if=none,id=dr1,format=raw,file.align=4k "
-                    "-device scsi-hd,drive=dr1,lun=0,scsi-id=1");
-    return arg;
-}
-
-static void *virtio_scsi_setup_iothread(GString *cmd_line, void *arg)
-{
-    g_string_append(cmd_line,
-                    " -object iothread,id=thread0"
-                    " -blockdev driver=null-co,read-zeroes=on,node-name=null0"
-                    " -device scsi-hd,drive=null0");
-    return arg;
-}
-
-static void register_virtio_scsi_test(void)
-{
-    QOSGraphTestOptions opts = { };
-
-    opts.before = virtio_scsi_hotplug_setup;
-    qos_add_test("hotplug", "virtio-scsi", hotplug, &opts);
-
-    opts.before = virtio_scsi_setup;
-    qos_add_test("unaligned-write-same", "virtio-scsi",
-                 test_unaligned_write_same, &opts);
-
-    opts.before = virtio_scsi_setup_iothread;
-    opts.edge = (QOSGraphEdgeOptions) {
-        .extra_device_opts = "iothread=thread0",
-    };
-    qos_add_test("iothread-attach-node", "virtio-scsi-pci",
-                 test_iothread_attach_node, &opts);
-}
-
-libqos_init(register_virtio_scsi_test);
diff --git a/tests/virtio-serial-test.c b/tests/virtio-serial-test.c
deleted file mode 100644 (file)
index 2541034..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * QTest testcase for VirtIO Serial
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest-single.h"
-#include "qemu/module.h"
-#include "libqos/virtio-serial.h"
-
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void virtio_serial_nop(void *obj, void *data, QGuestAllocator *alloc)
-{
-    /* no operation */
-}
-
-static void serial_hotplug(void *obj, void *data, QGuestAllocator *alloc)
-{
-    qtest_qmp_device_add(global_qtest, "virtserialport", "hp-port", "{}");
-    qtest_qmp_device_del(global_qtest, "hp-port");
-}
-
-static void register_virtio_serial_test(void)
-{
-    QOSGraphTestOptions opts = { };
-
-    opts.edge.before_cmd_line = "-device virtconsole,bus=vser0.0";
-    qos_add_test("console-nop", "virtio-serial", virtio_serial_nop, &opts);
-
-    opts.edge.before_cmd_line = "-device virtserialport,bus=vser0.0";
-    qos_add_test("serialport-nop", "virtio-serial", virtio_serial_nop, &opts);
-
-    qos_add_test("hotplug", "virtio-serial", serial_hotplug, NULL);
-}
-libqos_init(register_virtio_serial_test);
diff --git a/tests/virtio-test.c b/tests/virtio-test.c
deleted file mode 100644 (file)
index f7c6afd..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * QTest testcase for virtio
- *
- * Copyright (c) 2018 Red Hat, Inc.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qemu/module.h"
-#include "libqos/qgraph.h"
-#include "libqos/pci.h"
-
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void nop(void *obj, void *data, QGuestAllocator *alloc)
-{
-}
-
-static void register_virtio_test(void)
-{
-    qos_add_test("nop", "virtio", nop, NULL);
-}
-
-libqos_init(register_virtio_test);
diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c
deleted file mode 100644 (file)
index efba76e..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * QTest testcase for VM Generation ID
- *
- * Copyright (c) 2016 Red Hat, Inc.
- * Copyright (c) 2017 Skyport Systems
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/bitmap.h"
-#include "qemu/uuid.h"
-#include "hw/acpi/acpi-defs.h"
-#include "boot-sector.h"
-#include "acpi-utils.h"
-#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-
-#define VGID_GUID "324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87"
-#define VMGENID_GUID_OFFSET 40   /* allow space for
-                                  * OVMF SDT Header Probe Supressor
-                                  */
-#define RSDP_ADDR_INVALID 0x100000 /* RSDP must be below this address */
-
-static uint32_t acpi_find_vgia(QTestState *qts)
-{
-    uint32_t rsdp_offset;
-    uint32_t guid_offset = 0;
-    uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
-    uint32_t rsdt_len, table_length;
-    uint8_t *rsdt, *ent;
-
-    /* Wait for guest firmware to finish and start the payload. */
-    boot_sector_test(qts);
-
-    /* Tables should be initialized now. */
-    rsdp_offset = acpi_find_rsdp_address(qts);
-
-    g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID);
-
-
-    acpi_fetch_rsdp_table(qts, rsdp_offset, rsdp_table);
-    acpi_fetch_table(qts, &rsdt, &rsdt_len, &rsdp_table[16 /* RsdtAddress */],
-                     4, "RSDT", true);
-
-    ACPI_FOREACH_RSDT_ENTRY(rsdt, rsdt_len, ent, 4 /* Entry size */) {
-        uint8_t *table_aml;
-
-        acpi_fetch_table(qts, &table_aml, &table_length, ent, 4, NULL, true);
-        if (!memcmp(table_aml + 16 /* OEM Table ID */, "VMGENID", 7)) {
-            uint32_t vgia_val;
-            uint8_t *aml = &table_aml[36 /* AML byte-code start */];
-            /* the first entry in the table should be VGIA
-             * That's all we need
-             */
-            g_assert(aml[0 /* name_op*/] == 0x08);
-            g_assert(memcmp(&aml[1 /* name */], "VGIA", 4) == 0);
-            g_assert(aml[5 /* value op */] == 0x0C /* dword */);
-            memcpy(&vgia_val, &aml[6 /* value */], 4);
-
-            /* The GUID is written at a fixed offset into the fw_cfg file
-             * in order to implement the "OVMF SDT Header probe suppressor"
-             * see docs/specs/vmgenid.txt for more details
-             */
-            guid_offset = le32_to_cpu(vgia_val) + VMGENID_GUID_OFFSET;
-            g_free(table_aml);
-            break;
-        }
-        g_free(table_aml);
-    }
-    g_free(rsdt);
-    return guid_offset;
-}
-
-static void read_guid_from_memory(QTestState *qts, QemuUUID *guid)
-{
-    uint32_t vmgenid_addr;
-    int i;
-
-    vmgenid_addr = acpi_find_vgia(qts);
-    g_assert(vmgenid_addr);
-
-    /* Read the GUID directly from guest memory */
-    for (i = 0; i < 16; i++) {
-        guid->data[i] = qtest_readb(qts, vmgenid_addr + i);
-    }
-    /* The GUID is in little-endian format in the guest, while QEMU
-     * uses big-endian.  Swap after reading.
-     */
-    *guid = qemu_uuid_bswap(*guid);
-}
-
-static void read_guid_from_monitor(QTestState *qts, QemuUUID *guid)
-{
-    QDict *rsp, *rsp_ret;
-    const char *guid_str;
-
-    rsp = qtest_qmp(qts, "{ 'execute': 'query-vm-generation-id' }");
-    if (qdict_haskey(rsp, "return")) {
-        rsp_ret = qdict_get_qdict(rsp, "return");
-        g_assert(qdict_haskey(rsp_ret, "guid"));
-        guid_str = qdict_get_str(rsp_ret, "guid");
-        g_assert(qemu_uuid_parse(guid_str, guid) == 0);
-    }
-    qobject_unref(rsp);
-}
-
-static char disk[] = "tests/vmgenid-test-disk-XXXXXX";
-
-#define GUID_CMD(guid)                          \
-    "-accel kvm -accel tcg "                    \
-    "-device vmgenid,id=testvgid,guid=%s "      \
-    "-drive id=hd0,if=none,file=%s,format=raw " \
-    "-device ide-hd,drive=hd0 ", guid, disk
-
-static void vmgenid_set_guid_test(void)
-{
-    QemuUUID expected, measured;
-    QTestState *qts;
-
-    g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
-
-    qts = qtest_initf(GUID_CMD(VGID_GUID));
-
-    /* Read the GUID from accessing guest memory */
-    read_guid_from_memory(qts, &measured);
-    g_assert(memcmp(measured.data, expected.data, sizeof(measured.data)) == 0);
-
-    qtest_quit(qts);
-}
-
-static void vmgenid_set_guid_auto_test(void)
-{
-    QemuUUID measured;
-    QTestState *qts;
-
-    qts = qtest_initf(GUID_CMD("auto"));
-
-    read_guid_from_memory(qts, &measured);
-
-    /* Just check that the GUID is non-null */
-    g_assert(!qemu_uuid_is_null(&measured));
-
-    qtest_quit(qts);
-}
-
-static void vmgenid_query_monitor_test(void)
-{
-    QemuUUID expected, measured;
-    QTestState *qts;
-
-    g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
-
-    qts = qtest_initf(GUID_CMD(VGID_GUID));
-
-    /* Read the GUID via the monitor */
-    read_guid_from_monitor(qts, &measured);
-    g_assert(memcmp(measured.data, expected.data, sizeof(measured.data)) == 0);
-
-    qtest_quit(qts);
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-
-    ret = boot_sector_init(disk);
-    if (ret) {
-        return ret;
-    }
-
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("/vmgenid/vmgenid/set-guid",
-                   vmgenid_set_guid_test);
-    qtest_add_func("/vmgenid/vmgenid/set-guid-auto",
-                   vmgenid_set_guid_auto_test);
-    qtest_add_func("/vmgenid/vmgenid/query-monitor",
-                   vmgenid_query_monitor_test);
-    ret = g_test_run();
-    boot_sector_cleanup(disk);
-
-    return ret;
-}
diff --git a/tests/vmxnet3-test.c b/tests/vmxnet3-test.c
deleted file mode 100644 (file)
index a810252..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * QTest testcase for vmxnet3 NIC
- *
- * Copyright (c) 2013-2014 SUSE LINUX Products GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qemu/module.h"
-#include "libqos/qgraph.h"
-#include "libqos/pci.h"
-
-typedef struct QVmxnet3 QVmxnet3;
-
-struct QVmxnet3 {
-    QOSGraphObject obj;
-    QPCIDevice dev;
-};
-
-static void *vmxnet3_get_driver(void *obj, const char *interface)
-{
-    QVmxnet3 *vmxnet3 = obj;
-
-    if (!g_strcmp0(interface, "pci-device")) {
-        return &vmxnet3->dev;
-    }
-
-    fprintf(stderr, "%s not present in vmxnet3\n", interface);
-    g_assert_not_reached();
-}
-
-static void *vmxnet3_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
-{
-    QVmxnet3 *vmxnet3 = g_new0(QVmxnet3, 1);
-    QPCIBus *bus = pci_bus;
-
-    qpci_device_init(&vmxnet3->dev, bus, addr);
-    vmxnet3->obj.get_driver = vmxnet3_get_driver;
-
-    return &vmxnet3->obj;
-}
-
-static void vmxnet3_register_nodes(void)
-{
-    QOSGraphEdgeOptions opts = {
-        .extra_device_opts = "addr=04.0",
-    };
-    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
-
-    qos_node_create_driver("vmxnet3", vmxnet3_create);
-    qos_node_consumes("vmxnet3", "pci-bus", &opts);
-    qos_node_produces("vmxnet3", "pci-device");
-}
-
-libqos_init(vmxnet3_register_nodes);
diff --git a/tests/wdt_ib700-test.c b/tests/wdt_ib700-test.c
deleted file mode 100644 (file)
index 797288d..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * QTest testcase for the IB700 watchdog
- *
- * Copyright (c) 2014 Red Hat, Inc.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "qemu/timer.h"
-
-static void qmp_check_no_event(QTestState *s)
-{
-    QDict *resp = qtest_qmp(s, "{'execute':'query-status'}");
-    g_assert(qdict_haskey(resp, "return"));
-    qobject_unref(resp);
-}
-
-static QDict *ib700_program_and_wait(QTestState *s)
-{
-    QDict *event, *data;
-
-    qtest_clock_step(s, NANOSECONDS_PER_SECOND * 40);
-    qmp_check_no_event(s);
-
-    /* 2 second limit */
-    qtest_outb(s, 0x443, 14);
-
-    /* Ping */
-    qtest_clock_step(s, NANOSECONDS_PER_SECOND);
-    qmp_check_no_event(s);
-    qtest_outb(s, 0x443, 14);
-
-    /* Disable */
-    qtest_clock_step(s, NANOSECONDS_PER_SECOND);
-    qmp_check_no_event(s);
-    qtest_outb(s, 0x441, 1);
-    qtest_clock_step(s, 3 * NANOSECONDS_PER_SECOND);
-    qmp_check_no_event(s);
-
-    /* Enable and let it fire */
-    qtest_outb(s, 0x443, 13);
-    qtest_clock_step(s, 3 * NANOSECONDS_PER_SECOND);
-    qmp_check_no_event(s);
-    qtest_clock_step(s, 2 * NANOSECONDS_PER_SECOND);
-    event = qtest_qmp_eventwait_ref(s, "WATCHDOG");
-    data = qdict_get_qdict(event, "data");
-    qobject_ref(data);
-    qobject_unref(event);
-    return data;
-}
-
-
-static void ib700_pause(void)
-{
-    QDict *d;
-    QTestState *s = qtest_init("-watchdog-action pause -device ib700");
-
-    qtest_irq_intercept_in(s, "ioapic");
-    d = ib700_program_and_wait(s);
-    g_assert(!strcmp(qdict_get_str(d, "action"), "pause"));
-    qobject_unref(d);
-    qtest_qmp_eventwait(s, "STOP");
-    qtest_quit(s);
-}
-
-static void ib700_reset(void)
-{
-    QDict *d;
-    QTestState *s = qtest_init("-watchdog-action reset -device ib700");
-
-    qtest_irq_intercept_in(s, "ioapic");
-    d = ib700_program_and_wait(s);
-    g_assert(!strcmp(qdict_get_str(d, "action"), "reset"));
-    qobject_unref(d);
-    qtest_qmp_eventwait(s, "RESET");
-    qtest_quit(s);
-}
-
-static void ib700_shutdown(void)
-{
-    QDict *d;
-    QTestState *s;
-
-    s = qtest_init("-watchdog-action reset -no-reboot -device ib700");
-    qtest_irq_intercept_in(s, "ioapic");
-    d = ib700_program_and_wait(s);
-    g_assert(!strcmp(qdict_get_str(d, "action"), "reset"));
-    qobject_unref(d);
-    qtest_qmp_eventwait(s, "SHUTDOWN");
-    qtest_quit(s);
-}
-
-static void ib700_none(void)
-{
-    QDict *d;
-    QTestState *s = qtest_init("-watchdog-action none -device ib700");
-
-    qtest_irq_intercept_in(s, "ioapic");
-    d = ib700_program_and_wait(s);
-    g_assert(!strcmp(qdict_get_str(d, "action"), "none"));
-    qobject_unref(d);
-    qtest_quit(s);
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/wdt_ib700/pause", ib700_pause);
-    qtest_add_func("/wdt_ib700/reset", ib700_reset);
-    qtest_add_func("/wdt_ib700/shutdown", ib700_shutdown);
-    qtest_add_func("/wdt_ib700/none", ib700_none);
-
-    return g_test_run();
-}
This page took 1.501039 seconds and 4 git commands to generate.