aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.include60
-rw-r--r--tests/avocado/README.rst10
-rw-r--r--tests/avocado/avocado_qemu/__init__.py434
-rw-r--r--tests/avocado/avocado_qemu/linuxtest.py253
-rw-r--r--tests/avocado/boot_linux.py132
-rw-r--r--tests/avocado/boot_linux_console.py1530
-rw-r--r--tests/avocado/boot_xen.py95
-rw-r--r--tests/avocado/hotplug_blk.py69
-rw-r--r--tests/avocado/hotplug_cpu.py37
-rw-r--r--tests/avocado/intel_iommu.py122
-rw-r--r--tests/avocado/linux_ssh_mips_malta.py205
-rwxr-xr-xtests/avocado/machine_arm_n8x0.py49
-rw-r--r--tests/avocado/machine_aspeed.py478
-rw-r--r--tests/avocado/machine_mips_malta.py162
-rw-r--r--tests/avocado/migration.py135
-rw-r--r--tests/avocado/multiprocess.py102
-rw-r--r--tests/avocado/replay_kernel.py577
-rw-r--r--tests/avocado/replay_linux.py206
-rw-r--r--tests/avocado/riscv_opensbi.py63
-rw-r--r--tests/avocado/smmu.py139
-rw-r--r--tests/avocado/tuxrun_baselines.py620
-rw-r--r--tests/bench/benchmark-crypto-akcipher.c30
-rw-r--r--tests/bench/benchmark-crypto-cipher.c22
-rw-r--r--tests/bench/benchmark-crypto-hash.c10
-rw-r--r--tests/bench/benchmark-crypto-hmac.c6
-rw-r--r--tests/bench/test_akcipher_keys.c.inc (renamed from tests/bench/test_akcipher_keys.inc)0
-rw-r--r--tests/data/acpi/aarch64/virt/APIC.its_offbin0 -> 164 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/IORT.its_offbin0 -> 172 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/SSDT.memhpbin1817 -> 1817 bytes
-rwxr-xr-xtests/data/acpi/disassemle-aml.sh2
-rw-r--r--tests/data/acpi/riscv64/virt/RHCTbin332 -> 400 bytes
-rw-r--r--tests/data/acpi/riscv64/virt/SPCRbin80 -> 90 bytes
-rw-r--r--tests/data/acpi/riscv64/virt/SRAT.numamembin0 -> 108 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDTbin6830 -> 8611 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.acpierstbin6741 -> 8522 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.acpihmatbin8155 -> 9936 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.bridgebin13701 -> 15482 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.cphpbin7294 -> 9075 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.dimmpxmbin8484 -> 10265 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.hpbridgebin6781 -> 8562 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.hpbrrootbin3337 -> 5100 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.ipmikcsbin6902 -> 8683 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.memhpbin8189 -> 9970 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.nohpetbin6688 -> 8469 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.numamembin6836 -> 8617 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.roothpbin10623 -> 12404 bytes
-rw-r--r--tests/data/acpi/x86/q35/APIC.acpihmat-generic-xbin0 -> 136 bytes
-rw-r--r--tests/data/acpi/x86/q35/CEDT.acpihmat-generic-xbin0 -> 68 bytes
-rw-r--r--tests/data/acpi/x86/q35/DMAR.dmarbin120 -> 120 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDTbin8355 -> 8440 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.acpierstbin8372 -> 8457 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.acpihmatbin9680 -> 9765 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.acpihmat-generic-xbin0 -> 12650 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiatorbin8634 -> 8719 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.applesmcbin8401 -> 8486 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.bridgebin11968 -> 12053 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.core-countbin12913 -> 12998 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.core-count2bin33770 -> 33855 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.cphpbin8819 -> 8904 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.cxlbin9714 -> 13231 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.dimmpxmbin10009 -> 10094 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.ipmibtbin8430 -> 8515 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.ipmismbusbin8443 -> 8528 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.ivrsbin8372 -> 8457 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.memhpbin9714 -> 9799 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.mmio64bin9485 -> 9570 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.multi-bridgebin13208 -> 13293 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.noacpihpbin8235 -> 8302 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.nohpetbin8213 -> 8298 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.numamembin8361 -> 8446 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.pvpanic-isabin8456 -> 8541 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.thread-countbin12913 -> 12998 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.thread-count2bin33770 -> 33855 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.tis.tpm12bin8961 -> 9046 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.tis.tpm2bin8987 -> 9072 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.type4-countbin18589 -> 18674 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.viotbin9464 -> 14697 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.xapicbin35718 -> 35803 bytes
-rw-r--r--tests/data/acpi/x86/q35/HMAT.acpihmat-generic-xbin0 -> 360 bytes
-rw-r--r--tests/data/acpi/x86/q35/SRAT.acpihmat-generic-xbin0 -> 520 bytes
-rw-r--r--tests/data/qobject/qdict.txt6
-rw-r--r--tests/data/uefi-boot-images/bios-tables-test.loongarch64.iso.qcow2bin0 -> 12800 bytes
-rw-r--r--tests/docker/Makefile.include19
-rw-r--r--tests/docker/dockerfiles/alpine.docker8
-rw-r--r--tests/docker/dockerfiles/centos9.docker3
-rw-r--r--tests/docker/dockerfiles/debian-amd64-cross.docker15
-rw-r--r--tests/docker/dockerfiles/debian-arm64-cross.docker15
-rw-r--r--tests/docker/dockerfiles/debian-armel-cross.docker179
-rw-r--r--tests/docker/dockerfiles/debian-armhf-cross.docker15
-rw-r--r--tests/docker/dockerfiles/debian-i686-cross.docker25
-rw-r--r--tests/docker/dockerfiles/debian-loongarch-cross.docker4
-rwxr-xr-xtests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh8
-rw-r--r--tests/docker/dockerfiles/debian-mips64el-cross.docker25
-rw-r--r--tests/docker/dockerfiles/debian-mipsel-cross.docker25
-rw-r--r--tests/docker/dockerfiles/debian-ppc64el-cross.docker15
-rw-r--r--tests/docker/dockerfiles/debian-riscv64-cross.docker4
-rw-r--r--tests/docker/dockerfiles/debian-s390x-cross.docker15
-rw-r--r--tests/docker/dockerfiles/debian-toolchain.docker7
-rw-r--r--tests/docker/dockerfiles/debian-tricore-cross.docker2
-rw-r--r--tests/docker/dockerfiles/debian.docker6
-rw-r--r--tests/docker/dockerfiles/emsdk-wasm32-cross.docker145
-rw-r--r--tests/docker/dockerfiles/fedora-cris-cross.docker14
-rw-r--r--tests/docker/dockerfiles/fedora-rust-nightly.docker183
-rw-r--r--tests/docker/dockerfiles/fedora-win64-cross.docker7
-rw-r--r--tests/docker/dockerfiles/fedora.docker4
-rw-r--r--tests/docker/dockerfiles/opensuse-leap.docker9
-rw-r--r--tests/docker/dockerfiles/python.docker1
-rw-r--r--tests/docker/dockerfiles/ubuntu2204.docker10
-rwxr-xr-xtests/docker/test-debug4
-rwxr-xr-xtests/docker/test-rust21
-rw-r--r--tests/fp/fp-bench.c10
-rw-r--r--tests/fp/fp-test-log2.c2
-rw-r--r--tests/fp/fp-test.c9
-rw-r--r--tests/fp/meson.build16
-rw-r--r--tests/functional/aspeed.py58
-rw-r--r--tests/functional/meson.build244
-rw-r--r--tests/functional/qemu_test/__init__.py12
-rw-r--r--tests/functional/qemu_test/archive.py117
-rw-r--r--tests/functional/qemu_test/asset.py87
-rw-r--r--tests/functional/qemu_test/cmd.py159
-rw-r--r--tests/functional/qemu_test/config.py12
-rw-r--r--tests/functional/qemu_test/decorators.py151
-rw-r--r--tests/functional/qemu_test/linuxkernel.py52
-rw-r--r--tests/functional/qemu_test/ports.py55
-rw-r--r--tests/functional/qemu_test/tesseract.py20
-rw-r--r--tests/functional/qemu_test/testcase.py272
-rw-r--r--tests/functional/qemu_test/tuxruntest.py136
-rw-r--r--tests/functional/qemu_test/uncompress.py107
-rw-r--r--tests/functional/qemu_test/utils.py65
-rw-r--r--tests/functional/replay_kernel.py84
-rw-r--r--tests/functional/reverse_debugging.py (renamed from tests/avocado/reverse_debugging.py)114
-rwxr-xr-xtests/functional/test_aarch64_aspeed_ast2700.py140
-rwxr-xr-xtests/functional/test_aarch64_aspeed_ast2700fc.py135
-rwxr-xr-xtests/functional/test_aarch64_device_passthrough.py142
-rwxr-xr-xtests/functional/test_aarch64_hotplug_pci.py72
-rwxr-xr-xtests/functional/test_aarch64_imx8mp_evk.py68
-rwxr-xr-xtests/functional/test_aarch64_raspi3.py34
-rwxr-xr-xtests/functional/test_aarch64_raspi4.py96
-rwxr-xr-xtests/functional/test_aarch64_replay.py51
-rwxr-xr-xtests/functional/test_aarch64_reverse_debug.py38
-rwxr-xr-xtests/functional/test_aarch64_rme_sbsaref.py69
-rwxr-xr-xtests/functional/test_aarch64_rme_virt.py101
-rwxr-xr-xtests/functional/test_aarch64_sbsaref.py179
-rwxr-xr-xtests/functional/test_aarch64_sbsaref_alpine.py62
-rwxr-xr-xtests/functional/test_aarch64_sbsaref_freebsd.py63
-rwxr-xr-xtests/functional/test_aarch64_smmu.py211
-rwxr-xr-x[-rw-r--r--]tests/functional/test_aarch64_tcg_plugins.py (renamed from tests/avocado/tcg_plugins.py)56
-rwxr-xr-xtests/functional/test_aarch64_tuxrun.py50
-rwxr-xr-xtests/functional/test_aarch64_virt.py60
-rwxr-xr-xtests/functional/test_aarch64_virt_gpu.py140
-rwxr-xr-xtests/functional/test_aarch64_xen.py91
-rwxr-xr-xtests/functional/test_aarch64_xlnx_versal.py37
-rwxr-xr-xtests/functional/test_acpi_bits.py166
-rwxr-xr-xtests/functional/test_alpha_clipper.py34
-rwxr-xr-xtests/functional/test_alpha_replay.py29
-rwxr-xr-xtests/functional/test_arm_aspeed_ast1030.py73
-rwxr-xr-xtests/functional/test_arm_aspeed_ast2500.py56
-rwxr-xr-xtests/functional/test_arm_aspeed_ast2600.py140
-rw-r--r--tests/functional/test_arm_aspeed_bletchley.py25
-rwxr-xr-xtests/functional/test_arm_aspeed_palmetto.py25
-rwxr-xr-xtests/functional/test_arm_aspeed_rainier.py65
-rwxr-xr-xtests/functional/test_arm_aspeed_romulus.py25
-rw-r--r--tests/functional/test_arm_aspeed_witherspoon.py25
-rwxr-xr-xtests/functional/test_arm_bflt.py13
-rwxr-xr-xtests/functional/test_arm_bpim2u.py180
-rwxr-xr-xtests/functional/test_arm_canona1100.py10
-rwxr-xr-xtests/functional/test_arm_collie.py31
-rwxr-xr-xtests/functional/test_arm_cubieboard.py144
-rwxr-xr-xtests/functional/test_arm_emcraft_sf2.py52
-rwxr-xr-xtests/functional/test_arm_integratorcp.py34
-rwxr-xr-xtests/functional/test_arm_microbit.py31
-rwxr-xr-xtests/functional/test_arm_orangepi.py237
-rwxr-xr-xtests/functional/test_arm_quanta_gsj.py92
-rwxr-xr-xtests/functional/test_arm_raspi2.py92
-rwxr-xr-xtests/functional/test_arm_realview.py47
-rwxr-xr-xtests/functional/test_arm_replay.py69
-rwxr-xr-xtests/functional/test_arm_smdkc210.py51
-rwxr-xr-xtests/functional/test_arm_stellaris.py48
-rwxr-xr-xtests/functional/test_arm_sx1.py73
-rwxr-xr-xtests/functional/test_arm_tuxrun.py70
-rwxr-xr-xtests/functional/test_arm_vexpress.py26
-rwxr-xr-xtests/functional/test_arm_virt.py30
-rwxr-xr-xtests/functional/test_avr_mega2560.py11
-rwxr-xr-xtests/functional/test_avr_uno.py32
-rwxr-xr-xtests/functional/test_hppa_seabios.py35
-rwxr-xr-xtests/functional/test_i386_replay.py28
-rwxr-xr-xtests/functional/test_i386_tuxrun.py35
-rwxr-xr-xtests/functional/test_info_usernet.py8
-rwxr-xr-xtests/functional/test_intel_iommu.py155
-rwxr-xr-xtests/functional/test_linux_initrd.py7
-rwxr-xr-xtests/functional/test_loongarch64_virt.py8
-rwxr-xr-xtests/functional/test_m68k_mcf5208evb.py27
-rwxr-xr-xtests/functional/test_m68k_nextcube.py33
-rwxr-xr-xtests/functional/test_m68k_q800.py37
-rwxr-xr-xtests/functional/test_m68k_replay.py43
-rwxr-xr-xtests/functional/test_m68k_tuxrun.py34
-rwxr-xr-xtests/functional/test_mem_addr_space.py97
-rwxr-xr-xtests/functional/test_memlock.py79
-rwxr-xr-xtests/functional/test_microblaze_replay.py28
-rwxr-xr-xtests/functional/test_microblaze_s3adsp1800.py52
-rwxr-xr-xtests/functional/test_microblazeel_s3adsp1800.py46
-rwxr-xr-xtests/functional/test_migration.py98
-rwxr-xr-xtests/functional/test_mips64_malta.py35
-rwxr-xr-xtests/functional/test_mips64_tuxrun.py35
-rwxr-xr-xtests/functional/test_mips64el_fuloong2e.py29
-rwxr-xr-xtests/functional/test_mips64el_loongson3v.py9
-rwxr-xr-xtests/functional/test_mips64el_malta.py197
-rwxr-xr-xtests/functional/test_mips64el_replay.py56
-rwxr-xr-xtests/functional/test_mips64el_tuxrun.py35
-rwxr-xr-xtests/functional/test_mips_malta.py196
-rwxr-xr-xtests/functional/test_mips_replay.py55
-rwxr-xr-xtests/functional/test_mips_tuxrun.py36
-rwxr-xr-xtests/functional/test_mipsel_malta.py108
-rw-r--r--tests/functional/test_mipsel_replay.py54
-rwxr-xr-xtests/functional/test_mipsel_tuxrun.py36
-rwxr-xr-xtests/functional/test_multiprocess.py100
-rwxr-xr-xtests/functional/test_netdev_ethtool.py2
-rwxr-xr-xtests/functional/test_or1k_replay.py27
-rwxr-xr-xtests/functional/test_or1k_sim.py26
-rwxr-xr-xtests/functional/test_pc_cpu_hotplug_props.py1
-rwxr-xr-xtests/functional/test_ppc64_e500.py44
-rwxr-xr-xtests/functional/test_ppc64_hv.py110
-rwxr-xr-xtests/functional/test_ppc64_mac99.py44
-rwxr-xr-xtests/functional/test_ppc64_powernv.py42
-rwxr-xr-xtests/functional/test_ppc64_pseries.py1
-rwxr-xr-xtests/functional/test_ppc64_replay.py50
-rwxr-xr-xtests/functional/test_ppc64_reverse_debug.py41
-rwxr-xr-xtests/functional/test_ppc64_tuxrun.py113
-rwxr-xr-xtests/functional/test_ppc_405.py37
-rwxr-xr-xtests/functional/test_ppc_40p.py28
-rwxr-xr-xtests/functional/test_ppc_amiga.py20
-rwxr-xr-xtests/functional/test_ppc_bamboo.py15
-rwxr-xr-xtests/functional/test_ppc_mac.py36
-rwxr-xr-xtests/functional/test_ppc_mpc8544ds.py8
-rwxr-xr-xtests/functional/test_ppc_replay.py34
-rw-r--r--tests/functional/test_ppc_sam460ex.py38
-rwxr-xr-xtests/functional/test_ppc_tuxrun.py35
-rwxr-xr-xtests/functional/test_ppc_virtex_ml507.py10
-rwxr-xr-xtests/functional/test_riscv32_tuxrun.py38
-rwxr-xr-xtests/functional/test_riscv64_tuxrun.py51
-rwxr-xr-xtests/functional/test_riscv_opensbi.py36
-rwxr-xr-xtests/functional/test_rx_gdbsim.py24
-rwxr-xr-xtests/functional/test_s390x_ccw_virtio.py6
-rwxr-xr-xtests/functional/test_s390x_replay.py28
-rwxr-xr-xtests/functional/test_s390x_topology.py20
-rwxr-xr-xtests/functional/test_s390x_tuxrun.py35
-rwxr-xr-xtests/functional/test_sh4_r2d.py29
-rwxr-xr-xtests/functional/test_sh4_tuxrun.py49
-rwxr-xr-xtests/functional/test_sh4eb_r2d.py28
-rwxr-xr-xtests/functional/test_sparc64_sun4u.py11
-rwxr-xr-xtests/functional/test_sparc64_tuxrun.py35
-rwxr-xr-xtests/functional/test_sparc_replay.py27
-rwxr-xr-xtests/functional/test_sparc_sun4m.py24
-rwxr-xr-xtests/functional/test_virtio_balloon.py178
-rwxr-xr-xtests/functional/test_virtio_gpu.py19
-rwxr-xr-xtests/functional/test_virtio_version.py4
-rwxr-xr-x[-rw-r--r--]tests/functional/test_vnc.py (renamed from tests/avocado/vnc.py)87
-rwxr-xr-xtests/functional/test_x86_64_hotplug_blk.py85
-rwxr-xr-xtests/functional/test_x86_64_hotplug_cpu.py71
-rwxr-xr-x[-rw-r--r--]tests/functional/test_x86_64_kvm_xen.py (renamed from tests/avocado/kvm_xen_guest.py)120
-rwxr-xr-xtests/functional/test_x86_64_replay.py58
-rwxr-xr-xtests/functional/test_x86_64_reverse_debug.py36
-rwxr-xr-xtests/functional/test_x86_64_tuxrun.py36
-rwxr-xr-xtests/functional/test_xtensa_lx60.py26
-rwxr-xr-xtests/functional/test_xtensa_replay.py28
-rwxr-xr-xtests/guest-debug/run-test.py21
-rw-r--r--tests/guest-debug/test_gdbstub.py17
-rw-r--r--tests/include/meson.build2
m---------tests/lcitool/libvirt-ci0
-rw-r--r--tests/lcitool/mappings.yml15
-rw-r--r--tests/lcitool/projects/qemu.yml4
-rwxr-xr-xtests/lcitool/refresh68
-rw-r--r--tests/meson.build4
-rwxr-xr-xtests/migration-stress/guestperf-batch.py (renamed from tests/migration/guestperf-batch.py)0
-rwxr-xr-xtests/migration-stress/guestperf-plot.py (renamed from tests/migration/guestperf-plot.py)0
-rwxr-xr-xtests/migration-stress/guestperf.py (renamed from tests/migration/guestperf.py)0
-rw-r--r--tests/migration-stress/guestperf/__init__.py (renamed from tests/migration/guestperf/__init__.py)0
-rw-r--r--tests/migration-stress/guestperf/comparison.py (renamed from tests/migration/guestperf/comparison.py)15
-rw-r--r--tests/migration-stress/guestperf/engine.py (renamed from tests/migration/guestperf/engine.py)43
-rw-r--r--tests/migration-stress/guestperf/hardware.py (renamed from tests/migration/guestperf/hardware.py)0
-rw-r--r--tests/migration-stress/guestperf/plot.py (renamed from tests/migration/guestperf/plot.py)0
-rw-r--r--tests/migration-stress/guestperf/progress.py (renamed from tests/migration/guestperf/progress.py)0
-rw-r--r--tests/migration-stress/guestperf/report.py (renamed from tests/migration/guestperf/report.py)20
-rw-r--r--tests/migration-stress/guestperf/scenario.py (renamed from tests/migration/guestperf/scenario.py)7
-rw-r--r--tests/migration-stress/guestperf/shell.py (renamed from tests/migration/guestperf/shell.py)6
-rw-r--r--tests/migration-stress/guestperf/timings.py (renamed from tests/migration/guestperf/timings.py)0
-rwxr-xr-xtests/migration-stress/initrd-stress.sh (renamed from tests/migration/initrd-stress.sh)0
-rw-r--r--tests/migration-stress/meson.build (renamed from tests/migration/meson.build)0
-rw-r--r--tests/migration-stress/stress.c (renamed from tests/migration/stress.c)0
-rw-r--r--tests/qapi-schema/alternate-array.out1
-rw-r--r--tests/qapi-schema/comments.out1
-rw-r--r--tests/qapi-schema/doc-good.json6
-rw-r--r--tests/qapi-schema/doc-good.out16
-rw-r--r--tests/qapi-schema/doc-good.txt2
-rw-r--r--tests/qapi-schema/empty.out1
-rw-r--r--tests/qapi-schema/features-too-many.err2
-rw-r--r--tests/qapi-schema/features-too-many.json13
-rw-r--r--tests/qapi-schema/features-too-many.out0
-rw-r--r--tests/qapi-schema/include-repetition.out1
-rw-r--r--tests/qapi-schema/include-simple.out1
-rw-r--r--tests/qapi-schema/indented-expr.out1
-rw-r--r--tests/qapi-schema/meson.build1
-rw-r--r--tests/qapi-schema/qapi-schema-test.out1
-rwxr-xr-xtests/qapi-schema/test-qapi.py13
-rwxr-xr-xtests/qemu-iotests/0414
-rw-r--r--tests/qemu-iotests/051.pc.out2
-rwxr-xr-xtests/qemu-iotests/1061
-rwxr-xr-xtests/qemu-iotests/1252
-rwxr-xr-xtests/qemu-iotests/1654
-rw-r--r--tests/qemu-iotests/172.out60
-rwxr-xr-xtests/qemu-iotests/1751
-rw-r--r--tests/qemu-iotests/184.out2
-rw-r--r--tests/qemu-iotests/191.out16
-rwxr-xr-xtests/qemu-iotests/1947
-rw-r--r--tests/qemu-iotests/194.out5
-rw-r--r--tests/qemu-iotests/203.out1
-rw-r--r--tests/qemu-iotests/211.out6
-rwxr-xr-xtests/qemu-iotests/2211
-rw-r--r--tests/qemu-iotests/234.out2
-rwxr-xr-xtests/qemu-iotests/2402
-rw-r--r--tests/qemu-iotests/240.out4
-rwxr-xr-xtests/qemu-iotests/2505
-rwxr-xr-xtests/qemu-iotests/2531
-rw-r--r--tests/qemu-iotests/262.out1
-rw-r--r--tests/qemu-iotests/273.out5
-rw-r--r--tests/qemu-iotests/280.out1
-rwxr-xr-xtests/qemu-iotests/30219
-rwxr-xr-xtests/qemu-iotests/3085
-rw-r--r--tests/qemu-iotests/common.rc36
-rw-r--r--tests/qemu-iotests/iotests.py31
-rw-r--r--tests/qemu-iotests/pylintrc1
-rw-r--r--tests/qemu-iotests/testenv.py3
-rwxr-xr-xtests/qemu-iotests/tests/backup-discard-source39
-rwxr-xr-xtests/qemu-iotests/tests/commit-zero-blocks96
-rw-r--r--tests/qemu-iotests/tests/commit-zero-blocks.out54
-rwxr-xr-xtests/qemu-iotests/tests/copy-before-write98
-rw-r--r--tests/qemu-iotests/tests/copy-before-write.out4
-rwxr-xr-xtests/qemu-iotests/tests/graph-changes-while-io102
-rw-r--r--tests/qemu-iotests/tests/graph-changes-while-io.out4
-rwxr-xr-xtests/qemu-iotests/tests/inactive-node-nbd303
-rw-r--r--tests/qemu-iotests/tests/inactive-node-nbd.out239
-rwxr-xr-xtests/qemu-iotests/tests/migrate-bitmaps-test7
-rwxr-xr-xtests/qemu-iotests/tests/mirror-sparse128
-rw-r--r--tests/qemu-iotests/tests/mirror-sparse.out365
-rwxr-xr-xtests/qemu-iotests/tests/qcow2-encryption75
-rw-r--r--tests/qemu-iotests/tests/qcow2-encryption.out32
-rwxr-xr-xtests/qemu-iotests/tests/qsd-migrate140
-rw-r--r--tests/qemu-iotests/tests/qsd-migrate.out59
-rwxr-xr-xtests/qemu-iotests/tests/write-zeroes-unmap1
-rw-r--r--tests/qtest/acpi-utils.c1
-rw-r--r--tests/qtest/adm1266-test.c4
-rw-r--r--tests/qtest/adm1272-test.c4
-rw-r--r--tests/qtest/ahci-test.c3
-rw-r--r--tests/qtest/arm-cpu-features.c19
-rw-r--r--tests/qtest/aspeed-hace-utils.c646
-rw-r--r--tests/qtest/aspeed-hace-utils.h84
-rw-r--r--tests/qtest/aspeed-smc-utils.c686
-rw-r--r--tests/qtest/aspeed-smc-utils.h95
-rw-r--r--tests/qtest/aspeed_gpio-test.c2
-rw-r--r--tests/qtest/aspeed_hace-test.c577
-rw-r--r--tests/qtest/aspeed_smc-test.c778
-rw-r--r--tests/qtest/ast2700-gpio-test.c95
-rw-r--r--tests/qtest/ast2700-hace-test.c98
-rw-r--r--tests/qtest/ast2700-smc-test.c72
-rw-r--r--tests/qtest/bcm2835-i2c-test.c2
-rw-r--r--tests/qtest/bios-tables-test.c169
-rw-r--r--tests/qtest/boot-order-test.c13
-rw-r--r--tests/qtest/boot-serial-test.c25
-rw-r--r--tests/qtest/cdrom-test.c103
-rw-r--r--tests/qtest/cmsdk-apb-watchdog-test.c328
-rw-r--r--tests/qtest/cpu-plug-test.c28
-rw-r--r--tests/qtest/dbus-display-test.c72
-rw-r--r--tests/qtest/device-introspect-test.c6
-rw-r--r--tests/qtest/device-plug-test.c15
-rw-r--r--tests/qtest/drive_del-test.c11
-rw-r--r--tests/qtest/emc141x-test.c2
-rw-r--r--tests/qtest/fdc-test.c4
-rw-r--r--tests/qtest/fuzz/fuzz.c7
-rw-r--r--tests/qtest/fuzz/generic_fuzz.c5
-rw-r--r--tests/qtest/fuzz/qos_fuzz.c2
-rw-r--r--tests/qtest/fuzz/qtest_wrappers.c2
-rw-r--r--tests/qtest/fw_cfg-test.c6
-rw-r--r--tests/qtest/hd-geo-test.c82
-rw-r--r--tests/qtest/ide-test.c2
-rw-r--r--tests/qtest/intel-iommu-test.c64
-rw-r--r--tests/qtest/ipmi-bt-test.c4
-rw-r--r--tests/qtest/ipmi-kcs-test.c4
-rw-r--r--tests/qtest/isl_pmbus_vr-test.c4
-rw-r--r--tests/qtest/libqmp.c4
-rw-r--r--tests/qtest/libqmp.h2
-rw-r--r--tests/qtest/libqos/arm-imx25-pdk-machine.c5
-rw-r--r--tests/qtest/libqos/arm-n800-machine.c92
-rw-r--r--tests/qtest/libqos/fw_cfg.c202
-rw-r--r--tests/qtest/libqos/fw_cfg.h6
-rw-r--r--tests/qtest/libqos/generic-pcihost.c2
-rw-r--r--tests/qtest/libqos/i2c-imx.c4
-rw-r--r--tests/qtest/libqos/igb.c4
-rw-r--r--tests/qtest/libqos/libqos-malloc.c1
-rw-r--r--tests/qtest/libqos/libqos.c5
-rw-r--r--tests/qtest/libqos/meson.build9
-rw-r--r--tests/qtest/libqos/pci-pc.c2
-rw-r--r--tests/qtest/libqos/pci.c2
-rw-r--r--tests/qtest/libqos/qgraph.h2
-rw-r--r--tests/qtest/libqos/qos_external.c8
-rw-r--r--tests/qtest/libqos/riscv-iommu.c76
-rw-r--r--tests/qtest/libqos/riscv-iommu.h101
-rw-r--r--tests/qtest/libqos/virtio-9p-client.c52
-rw-r--r--tests/qtest/libqos/virtio-9p-client.h34
-rw-r--r--tests/qtest/libqos/virtio-pci-modern.c6
-rw-r--r--tests/qtest/libqos/virtio-pci.c6
-rw-r--r--tests/qtest/libqos/virtio-scmi.c2
-rw-r--r--tests/qtest/libqos/virtio.c48
-rw-r--r--tests/qtest/libqtest.c271
-rw-r--r--tests/qtest/libqtest.h76
-rw-r--r--tests/qtest/lsm303dlhc-mag-test.c2
-rw-r--r--tests/qtest/m48t59-test.c5
-rw-r--r--tests/qtest/machine-none-test.c3
-rw-r--r--tests/qtest/max34451-test.c4
-rw-r--r--tests/qtest/meson.build115
-rw-r--r--tests/qtest/migration-helpers.c531
-rw-r--r--tests/qtest/migration-test.c3966
-rw-r--r--tests/qtest/migration/Makefile (renamed from tests/migration/Makefile)0
-rw-r--r--tests/qtest/migration/aarch64/Makefile (renamed from tests/migration/aarch64/Makefile)0
-rw-r--r--tests/qtest/migration/aarch64/a-b-kernel.S (renamed from tests/migration/aarch64/a-b-kernel.S)0
-rw-r--r--tests/qtest/migration/aarch64/a-b-kernel.h (renamed from tests/migration/aarch64/a-b-kernel.h)0
-rw-r--r--tests/qtest/migration/bootfile.c70
-rw-r--r--tests/qtest/migration/bootfile.h (renamed from tests/migration/migration-test.h)9
-rw-r--r--tests/qtest/migration/compression-tests.c226
-rw-r--r--tests/qtest/migration/cpr-tests.c136
-rw-r--r--tests/qtest/migration/file-tests.c341
-rw-r--r--tests/qtest/migration/framework.c1066
-rw-r--r--tests/qtest/migration/framework.h251
-rw-r--r--tests/qtest/migration/i386/Makefile (renamed from tests/migration/i386/Makefile)0
-rw-r--r--tests/qtest/migration/i386/a-b-bootblock.S (renamed from tests/migration/i386/a-b-bootblock.S)0
-rw-r--r--tests/qtest/migration/i386/a-b-bootblock.h (renamed from tests/migration/i386/a-b-bootblock.h)0
-rw-r--r--tests/qtest/migration/migration-qmp.c520
-rw-r--r--tests/qtest/migration/migration-qmp.h48
-rw-r--r--tests/qtest/migration/migration-util.c398
-rw-r--r--tests/qtest/migration/migration-util.h (renamed from tests/qtest/migration-helpers.h)29
-rw-r--r--tests/qtest/migration/misc-tests.c297
-rw-r--r--tests/qtest/migration/postcopy-tests.c149
-rw-r--r--tests/qtest/migration/ppc64/Makefile (renamed from tests/migration/ppc64/Makefile)0
-rw-r--r--tests/qtest/migration/ppc64/a-b-kernel.S (renamed from tests/migration/ppc64/a-b-kernel.S)0
-rw-r--r--tests/qtest/migration/ppc64/a-b-kernel.h (renamed from tests/migration/ppc64/a-b-kernel.h)0
-rw-r--r--tests/qtest/migration/precopy-tests.c1337
-rw-r--r--tests/qtest/migration/s390x/Makefile (renamed from tests/migration/s390x/Makefile)0
-rw-r--r--tests/qtest/migration/s390x/a-b-bios.c (renamed from tests/migration/s390x/a-b-bios.c)0
-rw-r--r--tests/qtest/migration/s390x/a-b-bios.h (renamed from tests/migration/s390x/a-b-bios.h)0
-rw-r--r--tests/qtest/migration/tls-tests.c871
-rw-r--r--tests/qtest/netdev-socket.c4
-rw-r--r--tests/qtest/npcm7xx_adc-test.c2
-rw-r--r--tests/qtest/npcm7xx_emc-test.c4
-rw-r--r--tests/qtest/npcm7xx_pwm-test.c4
-rw-r--r--tests/qtest/npcm7xx_timer-test.c1
-rw-r--r--tests/qtest/npcm7xx_watchdog_timer-test.c2
-rw-r--r--tests/qtest/npcm_gmac-test.c85
-rw-r--r--tests/qtest/numa-test.c14
-rw-r--r--tests/qtest/pnv-host-i2c-test.c4
-rw-r--r--tests/qtest/pnv-spi-seeprom-test.c2
-rw-r--r--tests/qtest/pnv-xive2-common.c190
-rw-r--r--tests/qtest/pnv-xive2-common.h112
-rw-r--r--tests/qtest/pnv-xive2-flush-sync.c205
-rw-r--r--tests/qtest/pnv-xive2-nvpg_bar.c152
-rw-r--r--tests/qtest/pnv-xive2-test.c585
-rw-r--r--tests/qtest/pvpanic-pci-test.c2
-rw-r--r--tests/qtest/pvpanic-test.c2
-rw-r--r--tests/qtest/q35-test.c51
-rw-r--r--tests/qtest/qmp-cmd-test.c3
-rw-r--r--tests/qtest/qmp-test.c6
-rw-r--r--tests/qtest/qom-test.c15
-rw-r--r--tests/qtest/qos-test.c5
-rw-r--r--tests/qtest/readconfig-test.c6
-rw-r--r--tests/qtest/riscv-csr-test.c56
-rw-r--r--tests/qtest/riscv-iommu-test.c210
-rw-r--r--tests/qtest/rs5c372-test.c43
-rw-r--r--tests/qtest/rtl8139-test.c2
-rw-r--r--tests/qtest/stm32l4x5.h42
-rw-r--r--tests/qtest/stm32l4x5_gpio-test.c33
-rw-r--r--tests/qtest/stm32l4x5_syscfg-test.c32
-rw-r--r--tests/qtest/stm32l4x5_usart-test.c70
-rw-r--r--tests/qtest/tco-test.c2
-rw-r--r--tests/qtest/test-filter-mirror.c2
-rw-r--r--tests/qtest/test-filter-redirector.c2
-rw-r--r--tests/qtest/test-netfilter.c2
-rw-r--r--tests/qtest/test-x86-cpuid-compat.c41
-rw-r--r--tests/qtest/tmp105-test.c6
-rw-r--r--tests/qtest/tpm-emu.c4
-rw-r--r--tests/qtest/tpm-emu.h2
-rw-r--r--tests/qtest/tpm-tests.c2
-rw-r--r--tests/qtest/tpm-util.c2
-rw-r--r--tests/qtest/ufs-test.c750
-rw-r--r--tests/qtest/vhost-user-test.c9
-rw-r--r--tests/qtest/virtio-9p-test.c61
-rw-r--r--tests/qtest/virtio-balloon-test.c57
-rw-r--r--tests/qtest/virtio-iommu-test.c4
-rw-r--r--tests/qtest/virtio-net-failover.c17
-rw-r--r--tests/qtest/virtio-net-test.c2
-rw-r--r--tests/qtest/vmcoreinfo-test.c90
-rw-r--r--tests/qtest/vmgenid-test.c4
-rw-r--r--tests/qtest/wdt_ib700-test.c2
-rw-r--r--tests/tcg/Makefile.target30
-rw-r--r--tests/tcg/aarch64/Makefile.softmmu-target55
-rw-r--r--tests/tcg/aarch64/Makefile.target6
-rw-r--r--tests/tcg/aarch64/gdbstub/test-mte.py75
-rw-r--r--tests/tcg/aarch64/system/boot.S188
-rw-r--r--tests/tcg/aarch64/system/feat-xs.c27
-rw-r--r--tests/tcg/aarch64/system/kernel.ld33
-rw-r--r--tests/tcg/aarch64/system/mte.S109
-rw-r--r--tests/tcg/aarch64_be/Makefile.target17
-rw-r--r--tests/tcg/aarch64_be/hello.c35
-rw-r--r--tests/tcg/alpha/Makefile.softmmu-target2
-rw-r--r--tests/tcg/alpha/Makefile.target3
-rw-r--r--tests/tcg/arm/Makefile.target10
-rw-r--r--tests/tcg/arm/README5
-rw-r--r--tests/tcg/arm/test-arm-iwmmxt.S49
-rw-r--r--tests/tcg/cris/.gdbinit11
-rw-r--r--tests/tcg/cris/Makefile.target62
-rw-r--r--tests/tcg/cris/README1
-rw-r--r--tests/tcg/cris/bare/check_addcv17.s65
-rw-r--r--tests/tcg/cris/bare/check_addi.s57
-rw-r--r--tests/tcg/cris/bare/check_addiv32.s62
-rw-r--r--tests/tcg/cris/bare/check_addm.s96
-rw-r--r--tests/tcg/cris/bare/check_addq.s47
-rw-r--r--tests/tcg/cris/bare/check_addr.s96
-rw-r--r--tests/tcg/cris/bare/check_addxc.s91
-rw-r--r--tests/tcg/cris/bare/check_addxm.s106
-rw-r--r--tests/tcg/cris/bare/check_addxr.s96
-rw-r--r--tests/tcg/cris/bare/check_andc.s80
-rw-r--r--tests/tcg/cris/bare/check_andm.s90
-rw-r--r--tests/tcg/cris/bare/check_andq.s46
-rw-r--r--tests/tcg/cris/bare/check_andr.s95
-rw-r--r--tests/tcg/cris/bare/check_asr.s230
-rw-r--r--tests/tcg/cris/bare/check_ba.s93
-rw-r--r--tests/tcg/cris/bare/check_bas.s102
-rw-r--r--tests/tcg/cris/bare/check_bcc.s197
-rw-r--r--tests/tcg/cris/bare/check_boundc.s101
-rw-r--r--tests/tcg/cris/bare/check_boundr.s125
-rw-r--r--tests/tcg/cris/bare/check_btst.s96
-rw-r--r--tests/tcg/cris/bare/check_clearfv32.s19
-rw-r--r--tests/tcg/cris/bare/check_clrjmp1.s36
-rw-r--r--tests/tcg/cris/bare/check_cmp-2.s15
-rw-r--r--tests/tcg/cris/bare/check_cmpc.s86
-rw-r--r--tests/tcg/cris/bare/check_cmpm.s96
-rw-r--r--tests/tcg/cris/bare/check_cmpq.s75
-rw-r--r--tests/tcg/cris/bare/check_cmpr.s102
-rw-r--r--tests/tcg/cris/bare/check_cmpxc.s92
-rw-r--r--tests/tcg/cris/bare/check_cmpxm.s106
-rw-r--r--tests/tcg/cris/bare/check_dstep.s42
-rw-r--r--tests/tcg/cris/bare/check_jsr.s85
-rw-r--r--tests/tcg/cris/bare/check_lapc.s78
-rw-r--r--tests/tcg/cris/bare/check_lsl.s217
-rw-r--r--tests/tcg/cris/bare/check_lsr.s218
-rw-r--r--tests/tcg/cris/bare/check_mcp.s49
-rw-r--r--tests/tcg/cris/bare/check_movdelsr1.s33
-rw-r--r--tests/tcg/cris/bare/check_movecr.s37
-rw-r--r--tests/tcg/cris/bare/check_movei.s50
-rw-r--r--tests/tcg/cris/bare/check_movemr.s78
-rw-r--r--tests/tcg/cris/bare/check_movemrv32.s96
-rw-r--r--tests/tcg/cris/bare/check_mover.s28
-rw-r--r--tests/tcg/cris/bare/check_moverm.s45
-rw-r--r--tests/tcg/cris/bare/check_movmp.s131
-rw-r--r--tests/tcg/cris/bare/check_movpmv32.s35
-rw-r--r--tests/tcg/cris/bare/check_movpr.s28
-rw-r--r--tests/tcg/cris/bare/check_movprv32.s21
-rw-r--r--tests/tcg/cris/bare/check_movscr.s29
-rw-r--r--tests/tcg/cris/bare/check_movsm.s44
-rw-r--r--tests/tcg/cris/bare/check_movsr.s46
-rw-r--r--tests/tcg/cris/bare/check_movucr.s33
-rw-r--r--tests/tcg/cris/bare/check_movum.s40
-rw-r--r--tests/tcg/cris/bare/check_movur.s45
-rw-r--r--tests/tcg/cris/bare/check_mulv32.s51
-rw-r--r--tests/tcg/cris/bare/check_mulx.s257
-rw-r--r--tests/tcg/cris/bare/check_neg.s104
-rw-r--r--tests/tcg/cris/bare/check_not.s31
-rw-r--r--tests/tcg/cris/bare/check_orc.s71
-rw-r--r--tests/tcg/cris/bare/check_orm.s75
-rw-r--r--tests/tcg/cris/bare/check_orq.s41
-rw-r--r--tests/tcg/cris/bare/check_orr.s84
-rw-r--r--tests/tcg/cris/bare/check_ret.s25
-rw-r--r--tests/tcg/cris/bare/check_scc.s95
-rw-r--r--tests/tcg/cris/bare/check_subc.s87
-rw-r--r--tests/tcg/cris/bare/check_subm.s96
-rw-r--r--tests/tcg/cris/bare/check_subq.s52
-rw-r--r--tests/tcg/cris/bare/check_subr.s102
-rw-r--r--tests/tcg/cris/bare/check_xarith.s72
-rw-r--r--tests/tcg/cris/bare/crt.s13
-rw-r--r--tests/tcg/cris/bare/sys.c63
-rw-r--r--tests/tcg/cris/bare/testutils.inc117
-rw-r--r--tests/tcg/cris/libc/check_abs.c40
-rw-r--r--tests/tcg/cris/libc/check_addc.c58
-rw-r--r--tests/tcg/cris/libc/check_addcm.c85
-rw-r--r--tests/tcg/cris/libc/check_addo.c125
-rw-r--r--tests/tcg/cris/libc/check_addoq.c44
-rw-r--r--tests/tcg/cris/libc/check_bound.c142
-rw-r--r--tests/tcg/cris/libc/check_ftag.c37
-rw-r--r--tests/tcg/cris/libc/check_gcctorture_pr28634-1.c15
-rw-r--r--tests/tcg/cris/libc/check_gcctorture_pr28634.c15
-rw-r--r--tests/tcg/cris/libc/check_glibc_kernelversion.c116
-rw-r--r--tests/tcg/cris/libc/check_hello.c7
-rw-r--r--tests/tcg/cris/libc/check_int64.c47
-rw-r--r--tests/tcg/cris/libc/check_lz.c49
-rw-r--r--tests/tcg/cris/libc/check_mapbrk.c39
-rw-r--r--tests/tcg/cris/libc/check_mmap1.c48
-rw-r--r--tests/tcg/cris/libc/check_mmap2.c48
-rw-r--r--tests/tcg/cris/libc/check_mmap3.c33
-rw-r--r--tests/tcg/cris/libc/check_moveq.c51
-rw-r--r--tests/tcg/cris/libc/check_openpf1.c38
-rw-r--r--tests/tcg/cris/libc/check_openpf2.c16
-rw-r--r--tests/tcg/cris/libc/check_openpf3.c49
-rw-r--r--tests/tcg/cris/libc/check_openpf5.c56
-rw-r--r--tests/tcg/cris/libc/check_settls1.c45
-rw-r--r--tests/tcg/cris/libc/check_sigalrm.c26
-rw-r--r--tests/tcg/cris/libc/check_stat1.c16
-rw-r--r--tests/tcg/cris/libc/check_stat2.c20
-rw-r--r--tests/tcg/cris/libc/check_stat3.c25
-rw-r--r--tests/tcg/cris/libc/check_stat4.c27
-rw-r--r--tests/tcg/cris/libc/check_swap.c76
-rw-r--r--tests/tcg/cris/libc/check_time2.c18
-rw-r--r--tests/tcg/cris/libc/crisutils.h76
-rw-r--r--tests/tcg/cris/libc/sys.h18
-rw-r--r--tests/tcg/i386/Makefile.target2
-rw-r--r--tests/tcg/i386/test-avx.c2
-rw-r--r--tests/tcg/i386/test-i386-adcox.c6
-rw-r--r--tests/tcg/loongarch64/system/kernel.ld2
-rw-r--r--tests/tcg/loongarch64/system/regdef.h2
-rw-r--r--tests/tcg/multiarch/Makefile.target31
-rwxr-xr-xtests/tcg/multiarch/check-plugin-output.sh36
-rw-r--r--tests/tcg/multiarch/gdbstub/interrupt.py4
-rw-r--r--tests/tcg/multiarch/gdbstub/late-attach.py28
-rw-r--r--tests/tcg/multiarch/gdbstub/prot-none.py4
-rw-r--r--tests/tcg/multiarch/gdbstub/test-proc-mappings.py19
-rw-r--r--tests/tcg/multiarch/late-attach.c41
-rw-r--r--tests/tcg/multiarch/linux/linux-sigrtminmax.c74
-rw-r--r--tests/tcg/multiarch/linux/test-vma.c (renamed from tests/tcg/multiarch/test-vma.c)0
-rw-r--r--tests/tcg/multiarch/sigreturn-sigmask.c51
-rw-r--r--tests/tcg/multiarch/system/Makefile.softmmu-target6
-rw-r--r--tests/tcg/multiarch/system/memory.c122
-rwxr-xr-xtests/tcg/multiarch/system/validate-memory-counts.py130
-rw-r--r--tests/tcg/multiarch/test-plugin-mem-access.c177
-rw-r--r--tests/tcg/plugins/insn.c4
-rw-r--r--tests/tcg/plugins/mem.c270
-rw-r--r--tests/tcg/plugins/meson.build9
-rw-r--r--tests/tcg/plugins/patch.c251
-rw-r--r--tests/tcg/plugins/reset.c73
-rw-r--r--tests/tcg/plugins/syscall.c126
-rw-r--r--tests/tcg/ppc64/Makefile.target15
-rw-r--r--tests/tcg/s390x/Makefile.softmmu-target14
-rw-r--r--tests/tcg/s390x/Makefile.target6
-rw-r--r--tests/tcg/s390x/console.c3
-rw-r--r--tests/tcg/s390x/ex-smc.c57
-rw-r--r--tests/tcg/s390x/float.h104
-rw-r--r--tests/tcg/s390x/fma.c233
-rw-r--r--tests/tcg/s390x/mvc-smc.c82
-rw-r--r--tests/tcg/s390x/vfminmax.c223
-rw-r--r--tests/tcg/x86_64/Makefile.softmmu-target21
-rw-r--r--tests/tcg/x86_64/Makefile.target5
-rw-r--r--tests/tcg/x86_64/cross-modifying-code.c80
-rw-r--r--tests/tcg/x86_64/fma.c116
-rw-r--r--tests/tcg/x86_64/system/patch-target.c22
-rwxr-xr-xtests/tcg/x86_64/system/validate-patch.py39
-rw-r--r--tests/uefi-test-tools/Makefile5
-rw-r--r--tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc6
-rw-r--r--tests/uefi-test-tools/uefi-test-build.config10
-rw-r--r--tests/unit/check-block-qdict.c4
-rw-r--r--tests/unit/check-qdict.c6
-rw-r--r--tests/unit/check-qjson.c12
-rw-r--r--tests/unit/check-qlist.c4
-rw-r--r--tests/unit/check-qlit.c12
-rw-r--r--tests/unit/check-qnull.c2
-rw-r--r--tests/unit/check-qnum.c2
-rw-r--r--tests/unit/check-qobject.c12
-rw-r--r--tests/unit/check-qom-interface.c4
-rw-r--r--tests/unit/check-qom-proplist.c14
-rw-r--r--tests/unit/check-qstring.c2
-rw-r--r--tests/unit/meson.build3
-rw-r--r--tests/unit/socket-helpers.c1
-rw-r--r--tests/unit/test-aio-multithread.c6
-rw-r--r--tests/unit/test-bdrv-drain.c60
-rw-r--r--tests/unit/test-bdrv-graph-mod.c12
-rw-r--r--tests/unit/test-block-backend.c2
-rw-r--r--tests/unit/test-block-iothread.c8
-rw-r--r--tests/unit/test-blockjob-txn.c4
-rw-r--r--tests/unit/test-blockjob.c4
-rw-r--r--tests/unit/test-char.c437
-rw-r--r--tests/unit/test-crypto-afsplit.c10
-rw-r--r--tests/unit/test-crypto-akcipher.c54
-rw-r--r--tests/unit/test-crypto-block.c65
-rw-r--r--tests/unit/test-crypto-cipher.c79
-rw-r--r--tests/unit/test-crypto-hash.c111
-rw-r--r--tests/unit/test-crypto-hmac.c30
-rw-r--r--tests/unit/test-crypto-ivgen.c38
-rw-r--r--tests/unit/test-crypto-pbkdf.c64
-rw-r--r--tests/unit/test-crypto-secret.c28
-rw-r--r--tests/unit/test-crypto-tlssession.c12
-rw-r--r--tests/unit/test-fifo.c449
-rw-r--r--tests/unit/test-forward-visitor.c4
-rw-r--r--tests/unit/test-image-locking.c4
-rw-r--r--tests/unit/test-io-channel-socket.c6
-rw-r--r--tests/unit/test-keyval.c6
-rw-r--r--tests/unit/test-qdev-global-props.c33
-rw-r--r--tests/unit/test-qemu-opts.c4
-rw-r--r--tests/unit/test-qga.c21
-rw-r--r--tests/unit/test-qgraph.c1
-rw-r--r--tests/unit/test-qmp-cmds.c8
-rw-r--r--tests/unit/test-qmp-event.c10
-rw-r--r--tests/unit/test-qobject-input-visitor.c16
-rw-r--r--tests/unit/test-qobject-output-visitor.c16
-rw-r--r--tests/unit/test-replication.c4
-rw-r--r--tests/unit/test-resv-mem.c2
-rw-r--r--tests/unit/test-seccomp.c2
-rw-r--r--tests/unit/test-smp-parse.c23
-rw-r--r--tests/unit/test-thread-pool.c6
-rw-r--r--tests/unit/test-throttle.c2
-rw-r--r--tests/unit/test-timed-average.c2
-rw-r--r--tests/unit/test-util-sockets.c239
-rw-r--r--tests/unit/test-visitor-serialization.c4
-rw-r--r--tests/unit/test-xs-node.c4
-rw-r--r--tests/unit/test-yank.c2
-rw-r--r--tests/vm/Makefile.include29
-rw-r--r--tests/vm/README2
-rw-r--r--tests/vm/basevm.py14
-rwxr-xr-xtests/vm/freebsd6
-rw-r--r--tests/vm/generated/freebsd.json9
-rwxr-xr-xtests/vm/openbsd5
724 files changed, 27477 insertions, 21452 deletions
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 010369b..23fb722 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -18,7 +18,6 @@ ifneq ($(filter $(all-check-targets), check-softfloat),)
@echo " $(MAKE) check-tcg Run TCG tests"
@echo " $(MAKE) check-softfloat Run FPU emulation tests"
endif
- @echo " $(MAKE) check-avocado Run avocado (integration) tests for currently configured targets"
@echo
@echo " $(MAKE) check-report.junit.xml Generates an aggregated XML test report"
@echo " $(MAKE) check-venv Creates a Python venv for tests"
@@ -26,7 +25,6 @@ endif
@echo
@echo "The following are useful for CI builds"
@echo " $(MAKE) check-build Build most test binaries"
- @echo " $(MAKE) get-vm-images Downloads all images used by avocado tests, according to configured targets (~350 MB each, 1.5 GB max)"
@echo
@echo
@echo "The variable SPEED can be set to control the gtester speed setting."
@@ -86,26 +84,12 @@ distclean-tcg: $(DISTCLEAN_TCG_TARGET_RULES)
# Python venv for running tests
-.PHONY: check-venv check-avocado check-acceptance check-acceptance-deprecated-warning
+.PHONY: check-venv
# Build up our target list from the filtered list of ninja targets
TARGETS=$(patsubst libqemu-%.a, %, $(filter libqemu-%.a, $(ninja-targets)))
TESTS_VENV_TOKEN=$(BUILD_DIR)/pyvenv/tests.group
-TESTS_RESULTS_DIR=$(BUILD_DIR)/tests/results
-ifndef AVOCADO_TESTS
- AVOCADO_TESTS=tests/avocado
-endif
-# Controls the output generated by Avocado when running tests.
-# Any number of command separated loggers are accepted. For more
-# information please refer to "avocado --help".
-AVOCADO_SHOW?=app
-ifndef AVOCADO_TAGS
- AVOCADO_CMDLINE_TAGS=$(patsubst %-softmmu,-t arch:%, \
- $(filter %-softmmu,$(TARGETS)))
-else
- AVOCADO_CMDLINE_TAGS=$(addprefix -t , $(AVOCADO_TAGS))
-endif
quiet-venv-pip = $(quiet-@)$(call quiet-command-run, \
$(PYTHON) -m pip -q --disable-pip-version-check $1, \
@@ -113,47 +97,11 @@ quiet-venv-pip = $(quiet-@)$(call quiet-command-run, \
$(TESTS_VENV_TOKEN): $(SRC_PATH)/pythondeps.toml
$(call quiet-venv-pip,install -e "$(SRC_PATH)/python/")
- $(MKVENV_ENSUREGROUP) $< avocado
+ $(MKVENV_ENSUREGROUP) $< testdeps
$(call quiet-command, touch $@)
-$(TESTS_RESULTS_DIR):
- $(call quiet-command, mkdir -p $@, \
- MKDIR, $@)
-
check-venv: $(TESTS_VENV_TOKEN)
-FEDORA_31_ARCHES_TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGETS)))
-FEDORA_31_ARCHES_CANDIDATES=$(patsubst ppc64,ppc64le,$(FEDORA_31_ARCHES_TARGETS))
-FEDORA_31_ARCHES := x86_64 aarch64 ppc64le s390x
-FEDORA_31_DOWNLOAD=$(filter $(FEDORA_31_ARCHES),$(FEDORA_31_ARCHES_CANDIDATES))
-
-# download one specific Fedora 31 image
-get-vm-image-fedora-31-%: check-venv
- $(call quiet-command, \
- $(PYTHON) -m avocado vmimage get \
- --distro=fedora --distro-version=31 --arch=$*, \
- "AVOCADO", "Downloading avocado tests VM image for $*")
-
-# download all vm images, according to defined targets
-get-vm-images: check-venv $(patsubst %,get-vm-image-fedora-31-%, $(FEDORA_31_DOWNLOAD))
-
-check-avocado: check-venv $(TESTS_RESULTS_DIR) get-vm-images
- $(call quiet-command, \
- $(PYTHON) -m avocado \
- --show=$(AVOCADO_SHOW) run --job-results-dir=$(TESTS_RESULTS_DIR) \
- $(if $(AVOCADO_TAGS),, --filter-by-tags-include-empty \
- --filter-by-tags-include-empty-key) \
- $(AVOCADO_CMDLINE_TAGS) --max-parallel-tasks=1 \
- $(if $(GITLAB_CI),,--failfast) $(AVOCADO_TESTS), \
- "AVOCADO", "tests/avocado")
-
-check-acceptance-deprecated-warning:
- @echo
- @echo "Note '$(MAKE) check-acceptance' is deprecated, use '$(MAKE) check-avocado' instead."
- @echo
-
-check-acceptance: check-acceptance-deprecated-warning | check-avocado
-
FUNCTIONAL_TARGETS=$(patsubst %-softmmu,check-functional-%, $(filter %-softmmu,$(TARGETS)))
.PHONY: $(FUNCTIONAL_TARGETS)
$(FUNCTIONAL_TARGETS):
@@ -166,13 +114,13 @@ check-functional:
# Consolidated targets
-.PHONY: check check-clean get-vm-images
+.PHONY: check check-clean
check:
check-build: run-ninja
check-clean:
- rm -rf $(TESTS_RESULTS_DIR)
+ rm -rf $(BUILD_DIR)/tests/functional
clean: check-clean clean-tcg
distclean: distclean-tcg
diff --git a/tests/avocado/README.rst b/tests/avocado/README.rst
deleted file mode 100644
index 9448837..0000000
--- a/tests/avocado/README.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-=============================================
-Integration tests using the Avocado Framework
-=============================================
-
-This directory contains integration tests. They're usually higher
-level, and may interact with external resources and with various
-guest operating systems.
-
-For more information, please refer to ``docs/devel/testing.rst``,
-section "Integration tests using the Avocado Framework".
diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py
deleted file mode 100644
index 0e4ecea..0000000
--- a/tests/avocado/avocado_qemu/__init__.py
+++ /dev/null
@@ -1,434 +0,0 @@
-# Test class and utilities for functional tests
-#
-# Copyright (c) 2018 Red Hat, Inc.
-#
-# Author:
-# Cleber Rosa <crosa@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import logging
-import os
-import subprocess
-import sys
-import tempfile
-import time
-import uuid
-
-import avocado
-from avocado.utils import ssh
-from avocado.utils.path import find_command
-
-from qemu.machine import QEMUMachine
-from qemu.utils import (get_info_usernet_hostfwd_port, kvm_available,
- tcg_available)
-
-
-#: The QEMU build root directory. It may also be the source directory
-#: if building from the source dir, but it's safer to use BUILD_DIR for
-#: that purpose. Be aware that if this code is moved outside of a source
-#: and build tree, it will not be accurate.
-BUILD_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
-
-
-def has_cmd(name, args=None):
- """
- This function is for use in a @avocado.skipUnless decorator, e.g.:
-
- @skipUnless(*has_cmd('sudo -n', ('sudo', '-n', 'true')))
- def test_something_that_needs_sudo(self):
- ...
- """
-
- if args is None:
- args = ('which', name)
-
- try:
- _, stderr, exitcode = run_cmd(args)
- except Exception as e:
- exitcode = -1
- stderr = str(e)
-
- if exitcode != 0:
- cmd_line = ' '.join(args)
- err = f'{name} required, but "{cmd_line}" failed: {stderr.strip()}'
- return (False, err)
- else:
- return (True, '')
-
-def has_cmds(*cmds):
- """
- This function is for use in a @avocado.skipUnless decorator and
- allows checking for the availability of multiple commands, e.g.:
-
- @skipUnless(*has_cmds(('cmd1', ('cmd1', '--some-parameter')),
- 'cmd2', 'cmd3'))
- def test_something_that_needs_cmd1_and_cmd2(self):
- ...
- """
-
- for cmd in cmds:
- if isinstance(cmd, str):
- cmd = (cmd,)
-
- ok, errstr = has_cmd(*cmd)
- if not ok:
- return (False, errstr)
-
- return (True, '')
-
-def run_cmd(args):
- subp = subprocess.Popen(args,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- universal_newlines=True)
- stdout, stderr = subp.communicate()
- ret = subp.returncode
-
- return (stdout, stderr, ret)
-
-def is_readable_executable_file(path):
- return os.path.isfile(path) and os.access(path, os.R_OK | os.X_OK)
-
-
-def pick_default_qemu_bin(bin_prefix='qemu-system-', arch=None):
- """
- Picks the path of a QEMU binary, starting either in the current working
- directory or in the source tree root directory.
-
- :param arch: the arch to use when looking for a QEMU binary (the target
- will match the arch given). If None (the default), arch
- will be the current host system arch (as given by
- :func:`os.uname`).
- :type arch: str
- :returns: the path to the default QEMU binary or None if one could not
- be found
- :rtype: str or None
- """
- if arch is None:
- arch = os.uname()[4]
- # qemu binary path does not match arch for powerpc, handle it
- if 'ppc64le' in arch:
- arch = 'ppc64'
- qemu_bin_name = bin_prefix + arch
- qemu_bin_paths = [
- os.path.join(".", qemu_bin_name),
- os.path.join(BUILD_DIR, qemu_bin_name),
- os.path.join(BUILD_DIR, "build", qemu_bin_name),
- ]
- for path in qemu_bin_paths:
- if is_readable_executable_file(path):
- return path
- return None
-
-
-def _console_interaction(test, success_message, failure_message,
- send_string, keep_sending=False, vm=None):
- assert not keep_sending or send_string
- if vm is None:
- vm = test.vm
- console = vm.console_file
- console_logger = logging.getLogger('console')
- while True:
- if send_string:
- vm.console_socket.sendall(send_string.encode())
- if not keep_sending:
- send_string = None # send only once
-
- # Only consume console output if waiting for something
- if success_message is None and failure_message is None:
- if send_string is None:
- break
- continue
-
- try:
- msg = console.readline().decode().strip()
- except UnicodeDecodeError:
- msg = None
- if not msg:
- continue
- console_logger.debug(msg)
- if success_message is None or success_message in msg:
- break
- if failure_message and failure_message in msg:
- console.close()
- fail = 'Failure message found in console: "%s". Expected: "%s"' % \
- (failure_message, success_message)
- test.fail(fail)
-
-def interrupt_interactive_console_until_pattern(test, success_message,
- failure_message=None,
- interrupt_string='\r'):
- """
- Keep sending a string to interrupt a console prompt, while logging the
- console output. Typical use case is to break a boot loader prompt, such:
-
- Press a key within 5 seconds to interrupt boot process.
- 5
- 4
- 3
- 2
- 1
- Booting default image...
-
- :param test: an Avocado test containing a VM that will have its console
- read and probed for a success or failure message
- :type test: :class:`avocado_qemu.QemuSystemTest`
- :param success_message: if this message appears, test succeeds
- :param failure_message: if this message appears, test fails
- :param interrupt_string: a string to send to the console before trying
- to read a new line
- """
- _console_interaction(test, success_message, failure_message,
- interrupt_string, True)
-
-def wait_for_console_pattern(test, success_message, failure_message=None,
- vm=None):
- """
- Waits for messages to appear on the console, while logging the content
-
- :param test: an Avocado test containing a VM that will have its console
- read and probed for a success or failure message
- :type test: :class:`avocado_qemu.QemuSystemTest`
- :param success_message: if this message appears, test succeeds
- :param failure_message: if this message appears, test fails
- """
- _console_interaction(test, success_message, failure_message, None, vm=vm)
-
-def exec_command(test, command):
- """
- Send a command to a console (appending CRLF characters), while logging
- the content.
-
- :param test: an Avocado test containing a VM.
- :type test: :class:`avocado_qemu.QemuSystemTest`
- :param command: the command to send
- :type command: str
- """
- _console_interaction(test, None, None, command + '\r')
-
-def exec_command_and_wait_for_pattern(test, command,
- success_message, failure_message=None):
- """
- Send a command to a console (appending CRLF characters), then wait
- for success_message to appear on the console, while logging the.
- content. Mark the test as failed if failure_message is found instead.
-
- :param test: an Avocado test containing a VM that will have its console
- read and probed for a success or failure message
- :type test: :class:`avocado_qemu.QemuSystemTest`
- :param command: the command to send
- :param success_message: if this message appears, test succeeds
- :param failure_message: if this message appears, test fails
- """
- _console_interaction(test, success_message, failure_message, command + '\r')
-
-class QemuBaseTest(avocado.Test):
-
- # default timeout for all tests, can be overridden
- timeout = 120
-
- def _get_unique_tag_val(self, tag_name):
- """
- Gets a tag value, if unique for a key
- """
- vals = self.tags.get(tag_name, [])
- if len(vals) == 1:
- return vals.pop()
- return None
-
- def setUp(self, bin_prefix):
- self.arch = self.params.get('arch',
- default=self._get_unique_tag_val('arch'))
-
- self.cpu = self.params.get('cpu',
- default=self._get_unique_tag_val('cpu'))
-
- default_qemu_bin = pick_default_qemu_bin(bin_prefix, arch=self.arch)
- self.qemu_bin = self.params.get('qemu_bin',
- default=default_qemu_bin)
- if self.qemu_bin is None:
- self.cancel("No QEMU binary defined or found in the build tree")
-
- def fetch_asset(self, name,
- asset_hash, algorithm=None,
- locations=None, expire=None,
- find_only=False, cancel_on_missing=True):
- return super().fetch_asset(name,
- asset_hash=asset_hash,
- algorithm=algorithm,
- locations=locations,
- expire=expire,
- find_only=find_only,
- cancel_on_missing=cancel_on_missing)
-
-
-class QemuSystemTest(QemuBaseTest):
- """Facilitates system emulation tests."""
-
- def setUp(self):
- self._vms = {}
-
- super().setUp('qemu-system-')
-
- accel_required = self._get_unique_tag_val('accel')
- if accel_required:
- self.require_accelerator(accel_required)
-
- self.machine = self.params.get('machine',
- default=self._get_unique_tag_val('machine'))
-
- def require_accelerator(self, accelerator):
- """
- Requires an accelerator to be available for the test to continue
-
- It takes into account the currently set qemu binary.
-
- If the check fails, the test is canceled. If the check itself
- for the given accelerator is not available, the test is also
- canceled.
-
- :param accelerator: name of the accelerator, such as "kvm" or "tcg"
- :type accelerator: str
- """
- checker = {'tcg': tcg_available,
- 'kvm': kvm_available}.get(accelerator)
- if checker is None:
- self.cancel("Don't know how to check for the presence "
- "of accelerator %s" % accelerator)
- if not checker(qemu_bin=self.qemu_bin):
- self.cancel("%s accelerator does not seem to be "
- "available" % accelerator)
-
- def require_netdev(self, netdevname):
- netdevhelp = run_cmd([self.qemu_bin,
- '-M', 'none', '-netdev', 'help'])[0];
- if netdevhelp.find('\n' + netdevname + '\n') < 0:
- self.cancel('no support for user networking')
-
- def require_multiprocess(self):
- """
- Test for the presence of the x-pci-proxy-dev which is required
- to support multiprocess.
- """
- devhelp = run_cmd([self.qemu_bin,
- '-M', 'none', '-device', 'help'])[0];
- if devhelp.find('x-pci-proxy-dev') < 0:
- self.cancel('no support for multiprocess device emulation')
-
- def _new_vm(self, name, *args):
- self._sd = tempfile.TemporaryDirectory(prefix="qemu_")
- vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir,
- log_dir=self.logdir)
- self.log.debug('QEMUMachine "%s" created', name)
- self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir)
- self.log.debug('QEMUMachine "%s" log_dir: %s', name, vm.log_dir)
- if args:
- vm.add_args(*args)
- return vm
-
- def get_qemu_img(self):
- self.log.debug('Looking for and selecting a qemu-img binary')
-
- # If qemu-img has been built, use it, otherwise the system wide one
- # will be used.
- qemu_img = os.path.join(BUILD_DIR, 'qemu-img')
- if not os.path.exists(qemu_img):
- qemu_img = find_command('qemu-img', False)
- if qemu_img is False:
- self.cancel('Could not find "qemu-img"')
-
- return qemu_img
-
- @property
- def vm(self):
- return self.get_vm(name='default')
-
- def get_vm(self, *args, name=None):
- if not name:
- name = str(uuid.uuid4())
- if self._vms.get(name) is None:
- self._vms[name] = self._new_vm(name, *args)
- if self.cpu is not None:
- self._vms[name].add_args('-cpu', self.cpu)
- if self.machine is not None:
- self._vms[name].set_machine(self.machine)
- return self._vms[name]
-
- def set_vm_arg(self, arg, value):
- """
- Set an argument to list of extra arguments to be given to the QEMU
- binary. If the argument already exists then its value is replaced.
-
- :param arg: the QEMU argument, such as "-cpu" in "-cpu host"
- :type arg: str
- :param value: the argument value, such as "host" in "-cpu host"
- :type value: str
- """
- if not arg or not value:
- return
- if arg not in self.vm.args:
- self.vm.args.extend([arg, value])
- else:
- idx = self.vm.args.index(arg) + 1
- if idx < len(self.vm.args):
- self.vm.args[idx] = value
- else:
- self.vm.args.append(value)
-
- def tearDown(self):
- for vm in self._vms.values():
- vm.shutdown()
- self._sd = None
- super().tearDown()
-
-
-class LinuxSSHMixIn:
- """Contains utility methods for interacting with a guest via SSH."""
-
- def ssh_connect(self, username, credential, credential_is_key=True):
- self.ssh_logger = logging.getLogger('ssh')
- res = self.vm.cmd('human-monitor-command',
- command_line='info usernet')
- port = get_info_usernet_hostfwd_port(res)
- self.assertIsNotNone(port)
- self.assertGreater(port, 0)
- self.log.debug('sshd listening on port: %d', port)
- if credential_is_key:
- self.ssh_session = ssh.Session('127.0.0.1', port=port,
- user=username, key=credential)
- else:
- self.ssh_session = ssh.Session('127.0.0.1', port=port,
- user=username, password=credential)
- for i in range(10):
- try:
- self.ssh_session.connect()
- return
- except:
- time.sleep(i)
- self.fail('ssh connection timeout')
-
- def ssh_command(self, command):
- self.ssh_logger.info(command)
- result = self.ssh_session.cmd(command)
- stdout_lines = [line.rstrip() for line
- in result.stdout_text.splitlines()]
- for line in stdout_lines:
- self.ssh_logger.info(line)
- stderr_lines = [line.rstrip() for line
- in result.stderr_text.splitlines()]
- for line in stderr_lines:
- self.ssh_logger.warning(line)
-
- self.assertEqual(result.exit_status, 0,
- f'Guest command failed: {command}')
- return stdout_lines, stderr_lines
-
- def ssh_command_output_contains(self, cmd, exp):
- stdout, _ = self.ssh_command(cmd)
- for line in stdout:
- if exp in line:
- break
- else:
- self.fail('"%s" output does not contain "%s"' % (cmd, exp))
diff --git a/tests/avocado/avocado_qemu/linuxtest.py b/tests/avocado/avocado_qemu/linuxtest.py
deleted file mode 100644
index 66fb9f1..0000000
--- a/tests/avocado/avocado_qemu/linuxtest.py
+++ /dev/null
@@ -1,253 +0,0 @@
-# Test class and utilities for functional Linux-based tests
-#
-# Copyright (c) 2018 Red Hat, Inc.
-#
-# Author:
-# Cleber Rosa <crosa@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import os
-import shutil
-
-from avocado.utils import cloudinit, datadrainer, process, vmimage
-
-from avocado_qemu import LinuxSSHMixIn
-from avocado_qemu import QemuSystemTest
-
-if os.path.islink(os.path.dirname(os.path.dirname(__file__))):
- # The link to the avocado tests dir in the source code directory
- lnk = os.path.dirname(os.path.dirname(__file__))
- #: The QEMU root source directory
- SOURCE_DIR = os.path.dirname(os.path.dirname(os.readlink(lnk)))
-else:
- SOURCE_DIR = BUILD_DIR
-
-class LinuxDistro:
- """Represents a Linux distribution
-
- Holds information of known distros.
- """
- #: A collection of known distros and their respective image checksum
- KNOWN_DISTROS = {
- 'fedora': {
- '31': {
- 'x86_64':
- {'checksum': ('e3c1b309d9203604922d6e255c2c5d09'
- '8a309c2d46215d8fc026954f3c5c27a0'),
- 'pxeboot_url': ('https://archives.fedoraproject.org/'
- 'pub/archive/fedora/linux/releases/31/'
- 'Everything/x86_64/os/images/pxeboot/'),
- 'kernel_params': ('root=UUID=b1438b9b-2cab-4065-a99a-'
- '08a96687f73c ro no_timer_check '
- 'net.ifnames=0 console=tty1 '
- 'console=ttyS0,115200n8'),
- },
- 'aarch64':
- {'checksum': ('1e18d9c0cf734940c4b5d5ec592facae'
- 'd2af0ad0329383d5639c997fdf16fe49'),
- 'pxeboot_url': 'https://archives.fedoraproject.org/'
- 'pub/archive/fedora/linux/releases/31/'
- 'Everything/aarch64/os/images/pxeboot/',
- 'kernel_params': ('root=UUID=b6950a44-9f3c-4076-a9c2-'
- '355e8475b0a7 ro earlyprintk=pl011,0x9000000'
- ' ignore_loglevel no_timer_check'
- ' printk.time=1 rd_NO_PLYMOUTH'
- ' console=ttyAMA0'),
- },
- 'ppc64':
- {'checksum': ('7c3528b85a3df4b2306e892199a9e1e4'
- '3f991c506f2cc390dc4efa2026ad2f58')},
- 's390x':
- {'checksum': ('4caaab5a434fd4d1079149a072fdc789'
- '1e354f834d355069ca982fdcaf5a122d')},
- },
- '32': {
- 'aarch64':
- {'checksum': ('b367755c664a2d7a26955bbfff985855'
- 'adfa2ca15e908baf15b4b176d68d3967'),
- 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
- 'releases/32/Server/aarch64/os/images/'
- 'pxeboot/'),
- 'kernel_params': ('root=UUID=3df75b65-be8d-4db4-8655-'
- '14d95c0e90c5 ro no_timer_check net.ifnames=0'
- ' console=tty1 console=ttyS0,115200n8'),
- },
- },
- '33': {
- 'aarch64':
- {'checksum': ('e7f75cdfd523fe5ac2ca9eeece68edc1'
- 'a81f386a17f969c1d1c7c87031008a6b'),
- 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
- 'releases/33/Server/aarch64/os/images/'
- 'pxeboot/'),
- 'kernel_params': ('root=UUID=d20b3ffa-6397-4a63-a734-'
- '1126a0208f8a ro no_timer_check net.ifnames=0'
- ' console=tty1 console=ttyS0,115200n8'
- ' console=tty0'),
- },
- },
- }
- }
-
- def __init__(self, name, version, arch):
- self.name = name
- self.version = version
- self.arch = arch
- try:
- info = self.KNOWN_DISTROS.get(name).get(version).get(arch)
- except AttributeError:
- # Unknown distro
- info = None
- self._info = info or {}
-
- @property
- def checksum(self):
- """Gets the cloud-image file checksum"""
- return self._info.get('checksum', None)
-
- @checksum.setter
- def checksum(self, value):
- self._info['checksum'] = value
-
- @property
- def pxeboot_url(self):
- """Gets the repository url where pxeboot files can be found"""
- return self._info.get('pxeboot_url', None)
-
- @property
- def default_kernel_params(self):
- """Gets the default kernel parameters"""
- return self._info.get('kernel_params', None)
-
-
-class LinuxTest(LinuxSSHMixIn, QemuSystemTest):
- """Facilitates having a cloud-image Linux based available.
-
- For tests that intend to interact with guests, this is a better choice
- to start with than the more vanilla `QemuSystemTest` class.
- """
-
- distro = None
- username = 'root'
- password = 'password'
- smp = '2'
- memory = '1024'
-
- def _set_distro(self):
- distro_name = self.params.get(
- 'distro',
- default=self._get_unique_tag_val('distro'))
- if not distro_name:
- distro_name = 'fedora'
-
- distro_version = self.params.get(
- 'distro_version',
- default=self._get_unique_tag_val('distro_version'))
- if not distro_version:
- distro_version = '31'
-
- self.distro = LinuxDistro(distro_name, distro_version, self.arch)
-
- # The distro checksum behaves differently than distro name and
- # version. First, it does not respect a tag with the same
- # name, given that it's not expected to be used for filtering
- # (distro name versions are the natural choice). Second, the
- # order of precedence is: parameter, attribute and then value
- # from KNOWN_DISTROS.
- distro_checksum = self.params.get('distro_checksum',
- default=None)
- if distro_checksum:
- self.distro.checksum = distro_checksum
-
- def setUp(self, ssh_pubkey=None, network_device_type='virtio-net'):
- super().setUp()
- self.require_netdev('user')
- self._set_distro()
- self.vm.add_args('-smp', self.smp)
- self.vm.add_args('-m', self.memory)
- # The following network device allows for SSH connections
- self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
- '-device', '%s,netdev=vnet' % network_device_type)
- self.set_up_boot()
- if ssh_pubkey is None:
- ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys()
- self.set_up_cloudinit(ssh_pubkey)
-
- def set_up_existing_ssh_keys(self):
- ssh_public_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa.pub')
- source_private_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa')
- ssh_dir = os.path.join(self.workdir, '.ssh')
- os.mkdir(ssh_dir, mode=0o700)
- ssh_private_key = os.path.join(ssh_dir,
- os.path.basename(source_private_key))
- shutil.copyfile(source_private_key, ssh_private_key)
- os.chmod(ssh_private_key, 0o600)
- return (ssh_public_key, ssh_private_key)
-
- def download_boot(self):
- # Set the qemu-img binary.
- # If none is available, the test will cancel.
- vmimage.QEMU_IMG = super().get_qemu_img()
-
- self.log.info('Downloading/preparing boot image')
- # Fedora 31 only provides ppc64le images
- image_arch = self.arch
- if self.distro.name == 'fedora':
- if image_arch == 'ppc64':
- image_arch = 'ppc64le'
-
- try:
- boot = vmimage.get(
- self.distro.name, arch=image_arch, version=self.distro.version,
- checksum=self.distro.checksum,
- algorithm='sha256',
- cache_dir=self.cache_dirs[0],
- snapshot_dir=self.workdir)
- except:
- self.cancel('Failed to download/prepare boot image')
- return boot.path
-
- def prepare_cloudinit(self, ssh_pubkey=None):
- self.log.info('Preparing cloudinit image')
- try:
- cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso')
- pubkey_content = None
- if ssh_pubkey:
- with open(ssh_pubkey) as pubkey:
- pubkey_content = pubkey.read()
- cloudinit.iso(cloudinit_iso, self.name,
- username=self.username,
- password=self.password,
- # QEMU's hard coded usermode router address
- phone_home_host='10.0.2.2',
- phone_home_port=self.phone_server.server_port,
- authorized_key=pubkey_content)
- except Exception:
- self.cancel('Failed to prepare the cloudinit image')
- return cloudinit_iso
-
- def set_up_boot(self):
- path = self.download_boot()
- self.vm.add_args('-drive', 'file=%s' % path)
-
- def set_up_cloudinit(self, ssh_pubkey=None):
- self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0),
- self.name)
- cloudinit_iso = self.prepare_cloudinit(ssh_pubkey)
- self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
-
- def launch_and_wait(self, set_up_ssh_connection=True):
- self.vm.set_console()
- self.vm.launch()
- console_drainer = datadrainer.LineLogger(self.vm.console_socket.fileno(),
- logger=self.log.getChild('console'))
- console_drainer.start()
- self.log.info('VM launched, waiting for boot confirmation from guest')
- while not self.phone_server.instance_phoned_back:
- self.phone_server.handle_request()
-
- if set_up_ssh_connection:
- self.log.info('Setting up the SSH connection')
- self.ssh_connect(self.username, self.ssh_key)
diff --git a/tests/avocado/boot_linux.py b/tests/avocado/boot_linux.py
deleted file mode 100644
index a029ef4..0000000
--- a/tests/avocado/boot_linux.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# Functional test that boots a complete Linux system via a cloud image
-#
-# Copyright (c) 2018-2020 Red Hat, Inc.
-#
-# Author:
-# Cleber Rosa <crosa@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import os
-
-from avocado_qemu.linuxtest import LinuxTest
-from avocado_qemu import BUILD_DIR
-
-from avocado import skipUnless
-
-
-class BootLinuxX8664(LinuxTest):
- """
- :avocado: tags=arch:x86_64
- """
- timeout = 480
-
- def test_pc_i440fx_tcg(self):
- """
- :avocado: tags=machine:pc
- :avocado: tags=accel:tcg
- """
- self.require_accelerator("tcg")
- self.vm.add_args("-accel", "tcg")
- self.launch_and_wait(set_up_ssh_connection=False)
-
- def test_pc_i440fx_kvm(self):
- """
- :avocado: tags=machine:pc
- :avocado: tags=accel:kvm
- """
- self.require_accelerator("kvm")
- self.vm.add_args("-accel", "kvm")
- self.launch_and_wait(set_up_ssh_connection=False)
-
- def test_pc_q35_tcg(self):
- """
- :avocado: tags=machine:q35
- :avocado: tags=accel:tcg
- """
- self.require_accelerator("tcg")
- self.vm.add_args("-accel", "tcg")
- self.launch_and_wait(set_up_ssh_connection=False)
-
- def test_pc_q35_kvm(self):
- """
- :avocado: tags=machine:q35
- :avocado: tags=accel:kvm
- """
- self.require_accelerator("kvm")
- self.vm.add_args("-accel", "kvm")
- self.launch_and_wait(set_up_ssh_connection=False)
-
-
-# For Aarch64 we only boot KVM tests in CI as booting the current
-# Fedora OS in TCG tests is very heavyweight. There are lighter weight
-# distros which we use in the machine_aarch64_virt.py tests.
-class BootLinuxAarch64(LinuxTest):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:virt
- """
- timeout = 720
-
- def test_virt_kvm(self):
- """
- :avocado: tags=accel:kvm
- :avocado: tags=cpu:host
- """
- self.require_accelerator("kvm")
- self.vm.add_args("-accel", "kvm")
- self.vm.add_args("-machine", "virt,gic-version=host")
- self.vm.add_args('-bios',
- os.path.join(BUILD_DIR, 'pc-bios',
- 'edk2-aarch64-code.fd'))
- self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
- self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom')
- self.launch_and_wait(set_up_ssh_connection=False)
-
-
-# See the tux_baseline.py tests for almost the same coverage in a lot
-# less time.
-class BootLinuxPPC64(LinuxTest):
- """
- :avocado: tags=arch:ppc64
- """
-
- timeout = 360
-
- @skipUnless(os.getenv('SPEED') == 'slow', 'runtime limited')
- def test_pseries_tcg(self):
- """
- :avocado: tags=machine:pseries
- :avocado: tags=accel:tcg
- """
- self.require_accelerator("tcg")
- self.vm.add_args("-accel", "tcg")
- self.launch_and_wait(set_up_ssh_connection=False)
-
- def test_pseries_kvm(self):
- """
- :avocado: tags=machine:pseries
- :avocado: tags=accel:kvm
- """
- self.require_accelerator("kvm")
- self.vm.add_args("-accel", "kvm")
- self.vm.add_args("-machine", "cap-ccf-assist=off")
- self.launch_and_wait(set_up_ssh_connection=False)
-
-class BootLinuxS390X(LinuxTest):
- """
- :avocado: tags=arch:s390x
- """
-
- timeout = 240
-
- @skipUnless(os.getenv('SPEED') == 'slow', 'runtime limited')
- def test_s390_ccw_virtio_tcg(self):
- """
- :avocado: tags=machine:s390-ccw-virtio
- :avocado: tags=accel:tcg
- """
- self.require_accelerator("tcg")
- self.vm.add_args("-accel", "tcg")
- self.launch_and_wait(set_up_ssh_connection=False)
diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py
deleted file mode 100644
index 18c69d6..0000000
--- a/tests/avocado/boot_linux_console.py
+++ /dev/null
@@ -1,1530 +0,0 @@
-# Functional test that boots a Linux kernel and checks the console
-#
-# Copyright (c) 2018 Red Hat, Inc.
-#
-# Author:
-# Cleber Rosa <crosa@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import os
-import lzma
-import gzip
-import shutil
-
-from avocado import skip
-from avocado import skipUnless
-from avocado import skipUnless
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import exec_command
-from avocado_qemu import exec_command_and_wait_for_pattern
-from avocado_qemu import interrupt_interactive_console_until_pattern
-from avocado_qemu import wait_for_console_pattern
-from avocado.utils import process
-from avocado.utils import archive
-
-"""
-Round up to next power of 2
-"""
-def pow2ceil(x):
- return 1 if x == 0 else 2**(x - 1).bit_length()
-
-def file_truncate(path, size):
- if size != os.path.getsize(path):
- with open(path, 'ab+') as fd:
- fd.truncate(size)
-
-"""
-Expand file size to next power of 2
-"""
-def image_pow2ceil_expand(path):
- size = os.path.getsize(path)
- size_aligned = pow2ceil(size)
- if size != size_aligned:
- with open(path, 'ab+') as fd:
- fd.truncate(size_aligned)
-
-class LinuxKernelTest(QemuSystemTest):
- KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
-
- def wait_for_console_pattern(self, success_message, vm=None):
- wait_for_console_pattern(self, success_message,
- failure_message='Kernel panic - not syncing',
- vm=vm)
-
- def extract_from_deb(self, deb, path):
- """
- Extracts a file from a deb package into the test workdir
-
- :param deb: path to the deb archive
- :param path: path within the deb archive of the file to be extracted
- :returns: path of the extracted file
- """
- cwd = os.getcwd()
- os.chdir(self.workdir)
- file_path = process.run("ar t %s" % deb).stdout_text.split()[2]
- process.run("ar x %s %s" % (deb, file_path))
- archive.extract(file_path, self.workdir)
- os.chdir(cwd)
- # Return complete path to extracted file. Because callers to
- # extract_from_deb() specify 'path' with a leading slash, it is
- # necessary to use os.path.relpath() as otherwise os.path.join()
- # interprets it as an absolute path and drops the self.workdir part.
- return os.path.normpath(os.path.join(self.workdir,
- os.path.relpath(path, '/')))
-
- def extract_from_rpm(self, rpm, path):
- """
- Extracts a file from an RPM package into the test workdir.
-
- :param rpm: path to the rpm archive
- :param path: path within the rpm archive of the file to be extracted
- needs to be a relative path (starting with './') because
- cpio(1), which is used to extract the file, expects that.
- :returns: path of the extracted file
- """
- cwd = os.getcwd()
- os.chdir(self.workdir)
- process.run("rpm2cpio %s | cpio -id %s" % (rpm, path), shell=True)
- os.chdir(cwd)
- return os.path.normpath(os.path.join(self.workdir, path))
-
-class BootLinuxConsole(LinuxKernelTest):
- """
- Boots a Linux kernel and checks that the console is operational and the
- kernel command line is properly passed from QEMU to the kernel
- """
- timeout = 90
-
- def test_x86_64_pc(self):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:pc
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/29/Everything/x86_64/os/images/pxeboot'
- '/vmlinuz')
- kernel_hash = '23bebd2680757891cf7adedb033532163a792495'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- self.vm.add_args('-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_mips_malta(self):
- """
- :avocado: tags=arch:mips
- :avocado: tags=machine:malta
- :avocado: tags=endian:big
- """
- deb_url = ('http://snapshot.debian.org/archive/debian/'
- '20130217T032700Z/pool/main/l/linux-2.6/'
- 'linux-image-2.6.32-5-4kc-malta_2.6.32-48_mips.deb')
- deb_hash = 'a8cfc28ad8f45f54811fc6cf74fc43ffcfe0ba04'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-2.6.32-5-4kc-malta')
-
- self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- self.vm.add_args('-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_mips64el_malta(self):
- """
- This test requires the ar tool to extract "data.tar.gz" from
- the Debian package.
-
- The kernel can be rebuilt using this Debian kernel source [1] and
- following the instructions on [2].
-
- [1] http://snapshot.debian.org/package/linux-2.6/2.6.32-48/
- #linux-source-2.6.32_2.6.32-48
- [2] https://kernel-team.pages.debian.net/kernel-handbook/
- ch-common-tasks.html#s-common-official
-
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- """
- deb_url = ('http://snapshot.debian.org/archive/debian/'
- '20130217T032700Z/pool/main/l/linux-2.6/'
- 'linux-image-2.6.32-5-5kc-malta_2.6.32-48_mipsel.deb')
- deb_hash = '1aaec92083bf22fda31e0d27fa8d9a388e5fc3d5'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-2.6.32-5-5kc-malta')
-
- self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- self.vm.add_args('-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_mips64el_fuloong2e(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:fuloong2e
- :avocado: tags=endian:little
- """
- deb_url = ('http://archive.debian.org/debian/pool/main/l/linux/'
- 'linux-image-3.16.0-6-loongson-2e_3.16.56-1+deb8u1_mipsel.deb')
- deb_hash = 'd04d446045deecf7b755ef576551de0c4184dd44'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-3.16.0-6-loongson-2e')
-
- self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- self.vm.add_args('-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_mips_malta_cpio(self):
- """
- :avocado: tags=arch:mips
- :avocado: tags=machine:malta
- :avocado: tags=endian:big
- """
- deb_url = ('http://snapshot.debian.org/archive/debian/'
- '20160601T041800Z/pool/main/l/linux/'
- 'linux-image-4.5.0-2-4kc-malta_4.5.5-1_mips.deb')
- deb_hash = 'a3c84f3e88b54e06107d65a410d1d1e8e0f340f8'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-4.5.0-2-4kc-malta')
- initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
- '8584a59ed9e5eb5ee7ca91f6d74bbb06619205b8/rootfs/'
- 'mips/rootfs.cpio.gz')
- initrd_hash = 'bf806e17009360a866bf537f6de66590de349a99'
- initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- initrd_path = self.workdir + "rootfs.cpio"
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
- + 'console=ttyS0 console=tty '
- + 'rdinit=/sbin/init noreboot')
- self.vm.add_args('-kernel', kernel_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line,
- '-no-reboot')
- self.vm.launch()
- self.wait_for_console_pattern('Boot successful.')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'BogoMIPS')
- exec_command_and_wait_for_pattern(self, 'uname -a',
- 'Debian')
- exec_command_and_wait_for_pattern(self, 'reboot',
- 'reboot: Restarting system')
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
- def test_mips64el_malta_5KEc_cpio(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- :avocado: tags=cpu:5KEc
- """
- kernel_url = ('https://github.com/philmd/qemu-testing-blob/'
- 'raw/9ad2df38/mips/malta/mips64el/'
- 'vmlinux-3.19.3.mtoman.20150408')
- kernel_hash = '00d1d268fb9f7d8beda1de6bebcc46e884d71754'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- initrd_url = ('https://github.com/groeck/linux-build-test/'
- 'raw/8584a59e/rootfs/'
- 'mipsel64/rootfs.mipsel64r1.cpio.gz')
- initrd_hash = '1dbb8a396e916847325284dbe2151167'
- initrd_path_gz = self.fetch_asset(initrd_url, algorithm='md5',
- asset_hash=initrd_hash)
- initrd_path = self.workdir + "rootfs.cpio"
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
- + 'console=ttyS0 console=tty '
- + 'rdinit=/sbin/init noreboot')
- self.vm.add_args('-kernel', kernel_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line,
- '-no-reboot')
- self.vm.launch()
- wait_for_console_pattern(self, 'Boot successful.')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'MIPS 5KE')
- exec_command_and_wait_for_pattern(self, 'uname -a',
- '3.19.3.mtoman.20150408')
- exec_command_and_wait_for_pattern(self, 'reboot',
- 'reboot: Restarting system')
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- def do_test_mips_malta32el_nanomips(self, kernel_path_xz):
- kernel_path = self.workdir + "kernel"
- with lzma.open(kernel_path_xz, 'rb') as f_in:
- with open(kernel_path, 'wb') as f_out:
- shutil.copyfileobj(f_in, f_out)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
- + 'mem=256m@@0x0 '
- + 'console=ttyS0')
- self.vm.add_args('-no-reboot',
- '-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_mips_malta32el_nanomips_4k(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- :avocado: tags=cpu:I7200
- """
- kernel_url = ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
- 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
- 'generic_nano32r6el_page4k.xz')
- kernel_hash = '477456aafd2a0f1ddc9482727f20fe9575565dd6'
- kernel_path_xz = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- self.do_test_mips_malta32el_nanomips(kernel_path_xz)
-
- def test_mips_malta32el_nanomips_16k_up(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- :avocado: tags=cpu:I7200
- """
- kernel_url = ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
- 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
- 'generic_nano32r6el_page16k_up.xz')
- kernel_hash = 'e882868f944c71c816e832e2303b7874d044a7bc'
- kernel_path_xz = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- self.do_test_mips_malta32el_nanomips(kernel_path_xz)
-
- def test_mips_malta32el_nanomips_64k_dbg(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- :avocado: tags=cpu:I7200
- """
- kernel_url = ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
- 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
- 'generic_nano32r6el_page64k_dbg.xz')
- kernel_hash = '18d1c68f2e23429e266ca39ba5349ccd0aeb7180'
- kernel_path_xz = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- self.do_test_mips_malta32el_nanomips(kernel_path_xz)
-
- def test_aarch64_xlnx_versal_virt(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:xlnx-versal-virt
- :avocado: tags=device:pl011
- :avocado: tags=device:arm_gicv3
- :avocado: tags=accel:tcg
- """
- images_url = ('http://ports.ubuntu.com/ubuntu-ports/dists/'
- 'bionic-updates/main/installer-arm64/'
- '20101020ubuntu543.19/images/')
- kernel_url = images_url + 'netboot/ubuntu-installer/arm64/linux'
- kernel_hash = 'e167757620640eb26de0972f578741924abb3a82'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- initrd_url = images_url + 'netboot/ubuntu-installer/arm64/initrd.gz'
- initrd_hash = 'cab5cb3fcefca8408aa5aae57f24574bfce8bdb9'
- initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
-
- self.vm.set_console()
- self.vm.add_args('-m', '2G',
- '-accel', 'tcg',
- '-kernel', kernel_path,
- '-initrd', initrd_path)
- self.vm.launch()
- self.wait_for_console_pattern('Checked W+X mappings: passed')
-
- def test_arm_virt(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:virt
- :avocado: tags=accel:tcg
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/29/Everything/armhfp/os/images/pxeboot'
- '/vmlinuz')
- kernel_hash = 'e9826d741b4fb04cadba8d4824d1ed3b7fb8b4d4'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyAMA0')
- self.vm.add_args('-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_arm_emcraft_sf2(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:emcraft-sf2
- :avocado: tags=endian:little
- :avocado: tags=u-boot
- :avocado: tags=accel:tcg
- """
- self.require_netdev('user')
-
- uboot_url = ('https://raw.githubusercontent.com/'
- 'Subbaraya-Sundeep/qemu-test-binaries/'
- 'fe371d32e50ca682391e1e70ab98c2942aeffb01/u-boot')
- uboot_hash = 'cbb8cbab970f594bf6523b9855be209c08374ae2'
- uboot_path = self.fetch_asset(uboot_url, asset_hash=uboot_hash)
- spi_url = ('https://raw.githubusercontent.com/'
- 'Subbaraya-Sundeep/qemu-test-binaries/'
- 'fe371d32e50ca682391e1e70ab98c2942aeffb01/spi.bin')
- spi_hash = '65523a1835949b6f4553be96dec1b6a38fb05501'
- spi_path = self.fetch_asset(spi_url, asset_hash=spi_hash)
- spi_path_rw = os.path.join(self.workdir, os.path.basename(spi_path))
- shutil.copy(spi_path, spi_path_rw)
-
- file_truncate(spi_path_rw, 16 << 20) # Spansion S25FL128SDPBHICO is 16 MiB
-
- self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE
- self.vm.add_args('-kernel', uboot_path,
- '-append', kernel_command_line,
- '-drive', 'file=' + spi_path_rw + ',if=mtd,format=raw',
- '-no-reboot')
- self.vm.launch()
- self.wait_for_console_pattern('Enter \'help\' for a list')
-
- exec_command_and_wait_for_pattern(self, 'ifconfig eth0 10.0.2.15',
- 'eth0: link becomes ready')
- exec_command_and_wait_for_pattern(self, 'ping -c 3 10.0.2.2',
- '3 packets transmitted, 3 packets received, 0% packet loss')
-
- def do_test_arm_raspi2(self, uart_id):
- """
- :avocado: tags=accel:tcg
-
- The kernel can be rebuilt using the kernel source referenced
- and following the instructions on the on:
- https://www.raspberrypi.org/documentation/linux/kernel/building.md
- """
- serial_kernel_cmdline = {
- 0: 'earlycon=pl011,0x3f201000 console=ttyAMA0',
- }
- deb_url = ('http://archive.raspberrypi.org/debian/'
- 'pool/main/r/raspberrypi-firmware/'
- 'raspberrypi-kernel_1.20190215-1_armhf.deb')
- deb_hash = 'cd284220b32128c5084037553db3c482426f3972'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path, '/boot/kernel7.img')
- dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2709-rpi-2-b.dtb')
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- serial_kernel_cmdline[uart_id] +
- ' root=/dev/mmcblk0p2 rootwait ' +
- 'dwc_otg.fiq_fsm_enable=0')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-append', kernel_command_line,
- '-device', 'usb-kbd')
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
- console_pattern = 'Product: QEMU USB Keyboard'
- self.wait_for_console_pattern(console_pattern)
-
- def test_arm_raspi2_uart0(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:raspi2b
- :avocado: tags=device:pl011
- :avocado: tags=accel:tcg
- """
- self.do_test_arm_raspi2(0)
-
- def test_arm_raspi2_initrd(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:raspi2b
- """
- deb_url = ('http://archive.raspberrypi.org/debian/'
- 'pool/main/r/raspberrypi-firmware/'
- 'raspberrypi-kernel_1.20190215-1_armhf.deb')
- deb_hash = 'cd284220b32128c5084037553db3c482426f3972'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path, '/boot/kernel7.img')
- dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2709-rpi-2-b.dtb')
-
- initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
- '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
- 'arm/rootfs-armv7a.cpio.gz')
- initrd_hash = '604b2e45cdf35045846b8bbfbf2129b1891bdc9c'
- initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'earlycon=pl011,0x3f201000 console=ttyAMA0 '
- 'panic=-1 noreboot ' +
- 'dwc_otg.fiq_fsm_enable=0')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line,
- '-no-reboot')
- self.vm.launch()
- self.wait_for_console_pattern('Boot successful.')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'BCM2835')
- exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
- '/soc/cprman@7e101000')
- exec_command_and_wait_for_pattern(self, 'halt', 'reboot: System halted')
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- def test_arm_raspi4(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:raspi4b
- :avocado: tags=device:pl011
- :avocado: tags=accel:tcg
- :avocado: tags=rpi4b
-
- The kernel can be rebuilt using the kernel source referenced
- and following the instructions on the on:
- https://www.raspberrypi.org/documentation/linux/kernel/building.md
- """
-
- deb_url = ('http://archive.raspberrypi.org/debian/'
- 'pool/main/r/raspberrypi-firmware/'
- 'raspberrypi-kernel_1.20230106-1_arm64.deb')
- deb_hash = '08dc55696535b18a6d4fe6fa10d4c0d905cbb2ed'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path, '/boot/kernel8.img')
- dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2711-rpi-4-b.dtb')
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'earlycon=pl011,mmio32,0xfe201000 ' +
- 'console=ttyAMA0,115200 ' +
- 'root=/dev/mmcblk1p2 rootwait ' +
- 'dwc_otg.fiq_fsm_enable=0')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-append', kernel_command_line)
- # When PCI is supported we can add a USB controller:
- # '-device', 'qemu-xhci,bus=pcie.1,id=xhci',
- # '-device', 'usb-kbd,bus=xhci.0',
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
- # When USB is enabled we can look for this
- # console_pattern = 'Product: QEMU USB Keyboard'
- # self.wait_for_console_pattern(console_pattern)
- console_pattern = 'Waiting for root device'
- self.wait_for_console_pattern(console_pattern)
-
-
- def test_arm_raspi4_initrd(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:raspi4b
- :avocado: tags=device:pl011
- :avocado: tags=accel:tcg
- :avocado: tags=rpi4b
-
- The kernel can be rebuilt using the kernel source referenced
- and following the instructions on the on:
- https://www.raspberrypi.org/documentation/linux/kernel/building.md
- """
- deb_url = ('http://archive.raspberrypi.org/debian/'
- 'pool/main/r/raspberrypi-firmware/'
- 'raspberrypi-kernel_1.20230106-1_arm64.deb')
- deb_hash = '08dc55696535b18a6d4fe6fa10d4c0d905cbb2ed'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path, '/boot/kernel8.img')
- dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2711-rpi-4-b.dtb')
-
- initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
- '86b2be1384d41c8c388e63078a847f1e1c4cb1de/rootfs/'
- 'arm64/rootfs.cpio.gz')
- initrd_hash = 'f3d4f9fa92a49aa542f1b44d34be77bbf8ca5b9d'
- initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'earlycon=pl011,mmio32,0xfe201000 ' +
- 'console=ttyAMA0,115200 ' +
- 'panic=-1 noreboot ' +
- 'dwc_otg.fiq_fsm_enable=0')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line,
- '-no-reboot')
- # When PCI is supported we can add a USB controller:
- # '-device', 'qemu-xhci,bus=pcie.1,id=xhci',
- # '-device', 'usb-kbd,bus=xhci.0',
- self.vm.launch()
- self.wait_for_console_pattern('Boot successful.')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'BCM2835')
- exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
- 'cprman@7e101000')
- exec_command_and_wait_for_pattern(self, 'halt', 'reboot: System halted')
- # TODO: Raspberry Pi4 doesn't shut down properly with recent kernels
- # Wait for VM to shut down gracefully
- #self.vm.wait()
-
- def test_arm_exynos4210_initrd(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:smdkc210
- :avocado: tags=accel:tcg
- """
- deb_url = ('https://snapshot.debian.org/archive/debian/'
- '20190928T224601Z/pool/main/l/linux/'
- 'linux-image-4.19.0-6-armmp_4.19.67-2+deb10u1_armhf.deb')
- deb_hash = 'fa9df4a0d38936cb50084838f2cb933f570d7d82'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-4.19.0-6-armmp')
- dtb_path = '/usr/lib/linux-image-4.19.0-6-armmp/exynos4210-smdkv310.dtb'
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
-
- initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
- '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
- 'arm/rootfs-armv5.cpio.gz')
- initrd_hash = '2b50f1873e113523967806f4da2afe385462ff9b'
- initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'earlycon=exynos4210,0x13800000 earlyprintk ' +
- 'console=ttySAC0,115200n8 ' +
- 'random.trust_cpu=off cryptomgr.notests ' +
- 'cpuidle.off=1 panic=-1 noreboot')
-
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line,
- '-no-reboot')
- self.vm.launch()
-
- self.wait_for_console_pattern('Boot successful.')
- # TODO user command, for now the uart is stuck
-
- def test_arm_cubieboard_initrd(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:cubieboard
- :avocado: tags=accel:tcg
- """
- deb_url = ('https://apt.armbian.com/pool/main/l/'
- 'linux-6.6.16/linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb')
- deb_hash = 'f7c3c8c5432f765445dc6e7eab02f3bbe668256b'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = '/usr/lib/linux-image-6.6.16-current-sunxi/sun4i-a10-cubieboard.dtb'
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
- initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
- '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
- 'arm/rootfs-armv5.cpio.gz')
- initrd_hash = '2b50f1873e113523967806f4da2afe385462ff9b'
- initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0,115200 '
- 'usbcore.nousb '
- 'panic=-1 noreboot')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line,
- '-no-reboot')
- self.vm.launch()
- self.wait_for_console_pattern('Boot successful.')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'Allwinner sun4i/sun5i')
- exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
- 'system-control@1c00000')
- exec_command_and_wait_for_pattern(self, 'reboot',
- 'reboot: Restarting system')
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- def test_arm_cubieboard_sata(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:cubieboard
- :avocado: tags=accel:tcg
- """
- deb_url = ('https://apt.armbian.com/pool/main/l/'
- 'linux-6.6.16/linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb')
- deb_hash = 'f7c3c8c5432f765445dc6e7eab02f3bbe668256b'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = '/usr/lib/linux-image-6.6.16-current-sunxi/sun4i-a10-cubieboard.dtb'
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
- rootfs_url = ('https://github.com/groeck/linux-build-test/raw/'
- '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
- 'arm/rootfs-armv5.ext2.gz')
- rootfs_hash = '093e89d2b4d982234bf528bc9fb2f2f17a9d1f93'
- rootfs_path_gz = self.fetch_asset(rootfs_url, asset_hash=rootfs_hash)
- rootfs_path = os.path.join(self.workdir, 'rootfs.cpio')
- archive.gzip_uncompress(rootfs_path_gz, rootfs_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0,115200 '
- 'usbcore.nousb '
- 'root=/dev/sda ro '
- 'panic=-1 noreboot')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-drive', 'if=none,format=raw,id=disk0,file='
- + rootfs_path,
- '-device', 'ide-hd,bus=ide.0,drive=disk0',
- '-append', kernel_command_line,
- '-no-reboot')
- self.vm.launch()
- self.wait_for_console_pattern('Boot successful.')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'Allwinner sun4i/sun5i')
- exec_command_and_wait_for_pattern(self, 'cat /proc/partitions',
- 'sda')
- exec_command_and_wait_for_pattern(self, 'reboot',
- 'reboot: Restarting system')
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- @skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited')
- def test_arm_cubieboard_openwrt_22_03_2(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:cubieboard
- :avocado: tags=device:sd
- """
-
- # This test download a 7.5 MiB compressed image and expand it
- # to 126 MiB.
- image_url = ('https://downloads.openwrt.org/releases/22.03.2/targets/'
- 'sunxi/cortexa8/openwrt-22.03.2-sunxi-cortexa8-'
- 'cubietech_a10-cubieboard-ext4-sdcard.img.gz')
- image_hash = ('94b5ecbfbc0b3b56276e5146b899eafa'
- '2ac5dc2d08733d6705af9f144f39f554')
- image_path_gz = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
- image_path = archive.extract(image_path_gz, self.workdir)
- image_pow2ceil_expand(image_path)
-
- self.vm.set_console()
- self.vm.add_args('-drive', 'file=' + image_path + ',if=sd,format=raw',
- '-nic', 'user',
- '-no-reboot')
- self.vm.launch()
-
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'usbcore.nousb '
- 'noreboot')
-
- self.wait_for_console_pattern('U-Boot SPL')
-
- interrupt_interactive_console_until_pattern(
- self, 'Hit any key to stop autoboot:', '=>')
- exec_command_and_wait_for_pattern(self, "setenv extraargs '" +
- kernel_command_line + "'", '=>')
- exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...');
-
- self.wait_for_console_pattern(
- 'Please press Enter to activate this console.')
-
- exec_command_and_wait_for_pattern(self, ' ', 'root@')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'Allwinner sun4i/sun5i')
- exec_command_and_wait_for_pattern(self, 'reboot',
- 'reboot: Restarting system')
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
- def test_arm_quanta_gsj(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:quanta-gsj
- :avocado: tags=accel:tcg
- """
- # 25 MiB compressed, 32 MiB uncompressed.
- image_url = (
- 'https://github.com/hskinnemoen/openbmc/releases/download/'
- '20200711-gsj-qemu-0/obmc-phosphor-image-gsj.static.mtd.gz')
- image_hash = '14895e634923345cb5c8776037ff7876df96f6b1'
- image_path_gz = self.fetch_asset(image_url, asset_hash=image_hash)
- image_name = 'obmc.mtd'
- image_path = os.path.join(self.workdir, image_name)
- archive.gzip_uncompress(image_path_gz, image_path)
-
- self.vm.set_console()
- drive_args = 'file=' + image_path + ',if=mtd,bus=0,unit=0'
- self.vm.add_args('-drive', drive_args)
- self.vm.launch()
-
- # Disable drivers and services that stall for a long time during boot,
- # to avoid running past the 90-second timeout. These may be removed
- # as the corresponding device support is added.
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + (
- 'console=${console} '
- 'mem=${mem} '
- 'initcall_blacklist=npcm_i2c_bus_driver_init '
- 'systemd.mask=systemd-random-seed.service '
- 'systemd.mask=dropbearkey.service '
- )
-
- self.wait_for_console_pattern('> BootBlock by Nuvoton')
- self.wait_for_console_pattern('>Device: Poleg BMC NPCM730')
- self.wait_for_console_pattern('>Skip DDR init.')
- self.wait_for_console_pattern('U-Boot ')
- interrupt_interactive_console_until_pattern(
- self, 'Hit any key to stop autoboot:', 'U-Boot>')
- exec_command_and_wait_for_pattern(
- self, "setenv bootargs ${bootargs} " + kernel_command_line,
- 'U-Boot>')
- exec_command_and_wait_for_pattern(
- self, 'run romboot', 'Booting Kernel from flash')
- self.wait_for_console_pattern('Booting Linux on physical CPU 0x0')
- self.wait_for_console_pattern('CPU1: thread -1, cpu 1, socket 0')
- self.wait_for_console_pattern('OpenBMC Project Reference Distro')
- self.wait_for_console_pattern('gsj login:')
-
- def test_arm_quanta_gsj_initrd(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:quanta-gsj
- :avocado: tags=accel:tcg
- """
- initrd_url = (
- 'https://github.com/hskinnemoen/openbmc/releases/download/'
- '20200711-gsj-qemu-0/obmc-phosphor-initramfs-gsj.cpio.xz')
- initrd_hash = '98fefe5d7e56727b1eb17d5c00311b1b5c945300'
- initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- kernel_url = (
- 'https://github.com/hskinnemoen/openbmc/releases/download/'
- '20200711-gsj-qemu-0/uImage-gsj.bin')
- kernel_hash = 'fa67b2f141d56d39b3c54305c0e8a899c99eb2c7'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- dtb_url = (
- 'https://github.com/hskinnemoen/openbmc/releases/download/'
- '20200711-gsj-qemu-0/nuvoton-npcm730-gsj.dtb')
- dtb_hash = '18315f7006d7b688d8312d5c727eecd819aa36a4'
- dtb_path = self.fetch_asset(dtb_url, asset_hash=dtb_hash)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0,115200n8 '
- 'earlycon=uart8250,mmio32,0xf0001000')
- self.vm.add_args('-kernel', kernel_path,
- '-initrd', initrd_path,
- '-dtb', dtb_path,
- '-append', kernel_command_line)
- self.vm.launch()
-
- self.wait_for_console_pattern('Booting Linux on physical CPU 0x0')
- self.wait_for_console_pattern('CPU1: thread -1, cpu 1, socket 0')
- self.wait_for_console_pattern(
- 'Give root password for system maintenance')
-
- def test_arm_bpim2u(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:bpim2u
- :avocado: tags=accel:tcg
- """
- deb_url = ('https://apt.armbian.com/pool/main/l/'
- 'linux-6.6.16/linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb')
- deb_hash = 'f7c3c8c5432f765445dc6e7eab02f3bbe668256b'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = ('/usr/lib/linux-image-6.6.16-current-sunxi/'
- 'sun8i-r40-bananapi-m2-ultra.dtb')
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0,115200n8 '
- 'earlycon=uart,mmio32,0x1c28000')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_arm_bpim2u_initrd(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=accel:tcg
- :avocado: tags=machine:bpim2u
- """
- deb_url = ('https://apt.armbian.com/pool/main/l/'
- 'linux-6.6.16/linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb')
- deb_hash = 'f7c3c8c5432f765445dc6e7eab02f3bbe668256b'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = ('/usr/lib/linux-image-6.6.16-current-sunxi/'
- 'sun8i-r40-bananapi-m2-ultra.dtb')
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
- initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
- '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
- 'arm/rootfs-armv7a.cpio.gz')
- initrd_hash = '604b2e45cdf35045846b8bbfbf2129b1891bdc9c'
- initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0,115200 '
- 'panic=-1 noreboot')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line,
- '-no-reboot')
- self.vm.launch()
- self.wait_for_console_pattern('Boot successful.')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'Allwinner sun8i Family')
- exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
- 'system-control@1c00000')
- exec_command_and_wait_for_pattern(self, 'reboot',
- 'reboot: Restarting system')
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- def test_arm_bpim2u_gmac(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=accel:tcg
- :avocado: tags=machine:bpim2u
- :avocado: tags=device:sd
- """
- self.require_netdev('user')
-
- deb_url = ('https://apt.armbian.com/pool/main/l/'
- 'linux-6.6.16/linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb')
- deb_hash = 'f7c3c8c5432f765445dc6e7eab02f3bbe668256b'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = ('/usr/lib/linux-image-6.6.16-current-sunxi/'
- 'sun8i-r40-bananapi-m2-ultra.dtb')
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
- rootfs_url = ('http://storage.kernelci.org/images/rootfs/buildroot/'
- 'buildroot-baseline/20221116.0/armel/rootfs.ext2.xz')
- rootfs_hash = 'fae32f337c7b87547b10f42599acf109da8b6d9a'
- rootfs_path_xz = self.fetch_asset(rootfs_url, asset_hash=rootfs_hash)
- rootfs_path = os.path.join(self.workdir, 'rootfs.cpio')
- archive.lzma_uncompress(rootfs_path_xz, rootfs_path)
- image_pow2ceil_expand(rootfs_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0,115200 '
- 'root=b300 rootwait rw '
- 'panic=-1 noreboot')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-drive', 'file=' + rootfs_path + ',if=sd,format=raw',
- '-net', 'nic,model=gmac,netdev=host_gmac',
- '-netdev', 'user,id=host_gmac',
- '-append', kernel_command_line,
- '-no-reboot')
- self.vm.launch()
- shell_ready = "/bin/sh: can't access tty; job control turned off"
- self.wait_for_console_pattern(shell_ready)
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'Allwinner sun8i Family')
- exec_command_and_wait_for_pattern(self, 'cat /proc/partitions',
- 'mmcblk')
- exec_command_and_wait_for_pattern(self, 'ifconfig eth0 up',
- 'eth0: Link is Up')
- exec_command_and_wait_for_pattern(self, 'udhcpc eth0',
- 'udhcpc: lease of 10.0.2.15 obtained')
- exec_command_and_wait_for_pattern(self, 'ping -c 3 10.0.2.2',
- '3 packets transmitted, 3 packets received, 0% packet loss')
- exec_command_and_wait_for_pattern(self, 'reboot',
- 'reboot: Restarting system')
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- @skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited')
- def test_arm_bpim2u_openwrt_22_03_3(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:bpim2u
- :avocado: tags=device:sd
- """
-
- # This test download a 8.9 MiB compressed image and expand it
- # to 127 MiB.
- image_url = ('https://downloads.openwrt.org/releases/22.03.3/targets/'
- 'sunxi/cortexa7/openwrt-22.03.3-sunxi-cortexa7-'
- 'sinovoip_bananapi-m2-ultra-ext4-sdcard.img.gz')
- image_hash = ('5b41b4e11423e562c6011640f9a7cd3b'
- 'dd0a3d42b83430f7caa70a432e6cd82c')
- image_path_gz = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
- image_path = archive.extract(image_path_gz, self.workdir)
- image_pow2ceil_expand(image_path)
-
- self.vm.set_console()
- self.vm.add_args('-drive', 'file=' + image_path + ',if=sd,format=raw',
- '-nic', 'user',
- '-no-reboot')
- self.vm.launch()
-
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'usbcore.nousb '
- 'noreboot')
-
- self.wait_for_console_pattern('U-Boot SPL')
-
- interrupt_interactive_console_until_pattern(
- self, 'Hit any key to stop autoboot:', '=>')
- exec_command_and_wait_for_pattern(self, "setenv extraargs '" +
- kernel_command_line + "'", '=>')
- exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...');
-
- self.wait_for_console_pattern(
- 'Please press Enter to activate this console.')
-
- exec_command_and_wait_for_pattern(self, ' ', 'root@')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'Allwinner sun8i Family')
- exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
- 'system-control@1c00000')
-
- def test_arm_orangepi(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:orangepi-pc
- :avocado: tags=accel:tcg
- """
- deb_url = ('https://apt.armbian.com/pool/main/l/'
- 'linux-6.6.16/linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb')
- deb_hash = 'f7c3c8c5432f765445dc6e7eab02f3bbe668256b'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = '/usr/lib/linux-image-6.6.16-current-sunxi/sun8i-h3-orangepi-pc.dtb'
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0,115200n8 '
- 'earlycon=uart,mmio32,0x1c28000')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_arm_orangepi_initrd(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=accel:tcg
- :avocado: tags=machine:orangepi-pc
- """
- deb_url = ('https://apt.armbian.com/pool/main/l/'
- 'linux-6.6.16/linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb')
- deb_hash = 'f7c3c8c5432f765445dc6e7eab02f3bbe668256b'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = '/usr/lib/linux-image-6.6.16-current-sunxi/sun8i-h3-orangepi-pc.dtb'
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
- initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
- '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
- 'arm/rootfs-armv7a.cpio.gz')
- initrd_hash = '604b2e45cdf35045846b8bbfbf2129b1891bdc9c'
- initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0,115200 '
- 'panic=-1 noreboot')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line,
- '-no-reboot')
- self.vm.launch()
- self.wait_for_console_pattern('Boot successful.')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'Allwinner sun8i Family')
- exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
- 'system-control@1c00000')
- exec_command_and_wait_for_pattern(self, 'reboot',
- 'reboot: Restarting system')
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- def test_arm_orangepi_sd(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=accel:tcg
- :avocado: tags=machine:orangepi-pc
- :avocado: tags=device:sd
- """
- self.require_netdev('user')
-
- deb_url = ('https://apt.armbian.com/pool/main/l/'
- 'linux-6.6.16/linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb')
- deb_hash = 'f7c3c8c5432f765445dc6e7eab02f3bbe668256b'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = '/usr/lib/linux-image-6.6.16-current-sunxi/sun8i-h3-orangepi-pc.dtb'
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
- rootfs_url = ('http://storage.kernelci.org/images/rootfs/buildroot/'
- 'buildroot-baseline/20221116.0/armel/rootfs.ext2.xz')
- rootfs_hash = 'fae32f337c7b87547b10f42599acf109da8b6d9a'
- rootfs_path_xz = self.fetch_asset(rootfs_url, asset_hash=rootfs_hash)
- rootfs_path = os.path.join(self.workdir, 'rootfs.cpio')
- archive.lzma_uncompress(rootfs_path_xz, rootfs_path)
- image_pow2ceil_expand(rootfs_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0,115200 '
- 'root=/dev/mmcblk0 rootwait rw '
- 'panic=-1 noreboot')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-drive', 'file=' + rootfs_path + ',if=sd,format=raw',
- '-append', kernel_command_line,
- '-no-reboot')
- self.vm.launch()
- shell_ready = "/bin/sh: can't access tty; job control turned off"
- self.wait_for_console_pattern(shell_ready)
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'Allwinner sun8i Family')
- exec_command_and_wait_for_pattern(self, 'cat /proc/partitions',
- 'mmcblk0')
- exec_command_and_wait_for_pattern(self, 'ifconfig eth0 up',
- 'eth0: Link is Up')
- exec_command_and_wait_for_pattern(self, 'udhcpc eth0',
- 'udhcpc: lease of 10.0.2.15 obtained')
- exec_command_and_wait_for_pattern(self, 'ping -c 3 10.0.2.2',
- '3 packets transmitted, 3 packets received, 0% packet loss')
- exec_command_and_wait_for_pattern(self, 'reboot',
- 'reboot: Restarting system')
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- @skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited')
- def test_arm_orangepi_bionic_20_08(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:orangepi-pc
- :avocado: tags=device:sd
- """
-
- # This test download a 275 MiB compressed image and expand it
- # to 1036 MiB, but the underlying filesystem is 1552 MiB...
- # As we expand it to 2 GiB we are safe.
-
- image_url = ('https://archive.armbian.com/orangepipc/archive/'
- 'Armbian_20.08.1_Orangepipc_bionic_current_5.8.5.img.xz')
- image_hash = ('b4d6775f5673486329e45a0586bf06b6'
- 'dbe792199fd182ac6b9c7bb6c7d3e6dd')
- image_path_xz = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
- image_path = archive.extract(image_path_xz, self.workdir)
- image_pow2ceil_expand(image_path)
-
- self.vm.set_console()
- self.vm.add_args('-drive', 'file=' + image_path + ',if=sd,format=raw',
- '-nic', 'user',
- '-no-reboot')
- self.vm.launch()
-
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0,115200 '
- 'loglevel=7 '
- 'nosmp '
- 'systemd.default_timeout_start_sec=9000 '
- 'systemd.mask=armbian-zram-config.service '
- 'systemd.mask=armbian-ramlog.service')
-
- self.wait_for_console_pattern('U-Boot SPL')
- self.wait_for_console_pattern('Autoboot in ')
- exec_command_and_wait_for_pattern(self, ' ', '=>')
- exec_command_and_wait_for_pattern(self, "setenv extraargs '" +
- kernel_command_line + "'", '=>')
- exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...');
-
- self.wait_for_console_pattern('systemd[1]: Set hostname ' +
- 'to <orangepipc>')
- self.wait_for_console_pattern('Starting Load Kernel Modules...')
-
- @skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited')
- def test_arm_orangepi_uboot_netbsd9(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:orangepi-pc
- :avocado: tags=device:sd
- :avocado: tags=os:netbsd
- """
- # This test download a 304MB compressed image and expand it to 2GB
- deb_url = ('http://snapshot.debian.org/archive/debian/'
- '20200108T145233Z/pool/main/u/u-boot/'
- 'u-boot-sunxi_2020.01%2Bdfsg-1_armhf.deb')
- deb_hash = 'f67f404a80753ca3d1258f13e38f2b060e13db99'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- # We use the common OrangePi PC 'plus' build of U-Boot for our secondary
- # program loader (SPL). We will then set the path to the more specific
- # OrangePi "PC" device tree blob with 'setenv fdtfile' in U-Boot prompt,
- # before to boot NetBSD.
- uboot_path = '/usr/lib/u-boot/orangepi_plus/u-boot-sunxi-with-spl.bin'
- uboot_path = self.extract_from_deb(deb_path, uboot_path)
- image_url = ('https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/'
- 'evbarm-earmv7hf/binary/gzimg/armv7.img.gz')
- image_hash = '2babb29d36d8360adcb39c09e31060945259917a'
- image_path_gz = self.fetch_asset(image_url, asset_hash=image_hash)
- image_path = os.path.join(self.workdir, 'armv7.img')
- archive.gzip_uncompress(image_path_gz, image_path)
- image_pow2ceil_expand(image_path)
- image_drive_args = 'if=sd,format=raw,snapshot=on,file=' + image_path
-
- # dd if=u-boot-sunxi-with-spl.bin of=armv7.img bs=1K seek=8 conv=notrunc
- with open(uboot_path, 'rb') as f_in:
- with open(image_path, 'r+b') as f_out:
- f_out.seek(8 * 1024)
- shutil.copyfileobj(f_in, f_out)
-
- self.vm.set_console()
- self.vm.add_args('-nic', 'user',
- '-drive', image_drive_args,
- '-global', 'allwinner-rtc.base-year=2000',
- '-no-reboot')
- self.vm.launch()
- wait_for_console_pattern(self, 'U-Boot 2020.01+dfsg-1')
- interrupt_interactive_console_until_pattern(self,
- 'Hit any key to stop autoboot:',
- 'switch to partitions #0, OK')
-
- exec_command_and_wait_for_pattern(self, '', '=>')
- cmd = 'setenv bootargs root=ld0a'
- exec_command_and_wait_for_pattern(self, cmd, '=>')
- cmd = 'setenv kernel netbsd-GENERIC.ub'
- exec_command_and_wait_for_pattern(self, cmd, '=>')
- cmd = 'setenv fdtfile dtb/sun8i-h3-orangepi-pc.dtb'
- exec_command_and_wait_for_pattern(self, cmd, '=>')
- cmd = ("setenv bootcmd 'fatload mmc 0:1 ${kernel_addr_r} ${kernel}; "
- "fatload mmc 0:1 ${fdt_addr_r} ${fdtfile}; "
- "fdt addr ${fdt_addr_r}; "
- "bootm ${kernel_addr_r} - ${fdt_addr_r}'")
- exec_command_and_wait_for_pattern(self, cmd, '=>')
-
- exec_command_and_wait_for_pattern(self, 'boot',
- 'Booting kernel from Legacy Image')
- wait_for_console_pattern(self, 'Starting kernel ...')
- wait_for_console_pattern(self, 'NetBSD 9.0 (GENERIC)')
- # Wait for user-space
- wait_for_console_pattern(self, 'Starting root file system check')
-
- def test_aarch64_raspi3_atf(self):
- """
- :avocado: tags=accel:tcg
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:raspi3b
- :avocado: tags=cpu:cortex-a53
- :avocado: tags=device:pl011
- :avocado: tags=atf
- """
- zip_url = ('https://github.com/pbatard/RPi3/releases/download/'
- 'v1.15/RPi3_UEFI_Firmware_v1.15.zip')
- zip_hash = '74b3bd0de92683cadb14e008a7575e1d0c3cafb9'
- zip_path = self.fetch_asset(zip_url, asset_hash=zip_hash)
-
- archive.extract(zip_path, self.workdir)
- efi_fd = os.path.join(self.workdir, 'RPI_EFI.fd')
-
- self.vm.set_console(console_index=1)
- self.vm.add_args('-nodefaults',
- '-device', 'loader,file=%s,force-raw=true' % efi_fd)
- self.vm.launch()
- self.wait_for_console_pattern('version UEFI Firmware v1.15')
-
- def test_alpha_clipper(self):
- """
- :avocado: tags=arch:alpha
- :avocado: tags=machine:clipper
- """
- kernel_url = ('http://archive.debian.org/debian/dists/lenny/main/'
- 'installer-alpha/20090123lenny10/images/cdrom/vmlinuz')
- kernel_hash = '3a943149335529e2ed3e74d0d787b85fb5671ba3'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- uncompressed_kernel = archive.uncompress(kernel_path, self.workdir)
-
- self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- self.vm.add_args('-nodefaults',
- '-kernel', uncompressed_kernel,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_m68k_q800(self):
- """
- :avocado: tags=arch:m68k
- :avocado: tags=machine:q800
- """
- deb_url = ('https://snapshot.debian.org/archive/debian-ports'
- '/20191021T083923Z/pool-m68k/main'
- '/l/linux/kernel-image-5.3.0-1-m68k-di_5.3.7-1_m68k.udeb')
- deb_hash = '044954bb9be4160a3ce81f8bc1b5e856b75cccd1'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-5.3.0-1-m68k')
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0 vga=off')
- self.vm.add_args('-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
- console_pattern = 'No filesystem could mount root'
- self.wait_for_console_pattern(console_pattern)
-
- def do_test_advcal_2018(self, day, tar_hash, kernel_name, console=0):
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day' + day + '.tar.xz')
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(file_path, self.workdir)
- self.vm.set_console(console_index=console)
- self.vm.add_args('-kernel',
- self.workdir + '/day' + day + '/' + kernel_name)
- self.vm.launch()
- self.wait_for_console_pattern('QEMU advent calendar')
-
- def test_arm_vexpressa9(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:vexpress-a9
- """
- tar_hash = '32b7677ce8b6f1471fb0059865f451169934245b'
- self.vm.add_args('-dtb', self.workdir + '/day16/vexpress-v2p-ca9.dtb')
- self.do_test_advcal_2018('16', tar_hash, 'winter.zImage')
-
- def test_arm_ast2600_debian(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:rainier-bmc
- """
- deb_url = ('http://snapshot.debian.org/archive/debian/'
- '20220606T211338Z/'
- 'pool/main/l/linux/'
- 'linux-image-5.17.0-2-armmp_5.17.6-1%2Bb1_armhf.deb')
- deb_hash = '8acb2b4439faedc2f3ed4bdb2847ad4f6e0491f73debaeb7f660c8abe4dcdc0e'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash,
- algorithm='sha256')
- kernel_path = self.extract_from_deb(deb_path, '/boot/vmlinuz-5.17.0-2-armmp')
- dtb_path = self.extract_from_deb(deb_path,
- '/usr/lib/linux-image-5.17.0-2-armmp/aspeed-bmc-ibm-rainier.dtb')
-
- self.vm.set_console()
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-net', 'nic')
- self.vm.launch()
- self.wait_for_console_pattern("Booting Linux on physical CPU 0xf00")
- self.wait_for_console_pattern("SMP: Total of 2 processors activated")
- self.wait_for_console_pattern("No filesystem could mount root")
-
- def test_m68k_mcf5208evb(self):
- """
- :avocado: tags=arch:m68k
- :avocado: tags=machine:mcf5208evb
- """
- tar_hash = 'ac688fd00561a2b6ce1359f9ff6aa2b98c9a570c'
- self.do_test_advcal_2018('07', tar_hash, 'sanity-clause.elf')
-
- def test_or1k_sim(self):
- """
- :avocado: tags=arch:or1k
- :avocado: tags=machine:or1k-sim
- """
- tar_hash = '20334cdaf386108c530ff0badaecc955693027dd'
- self.do_test_advcal_2018('20', tar_hash, 'vmlinux')
-
- def test_ppc64_e500(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:ppce500
- :avocado: tags=cpu:e5500
- :avocado: tags=accel:tcg
- """
- self.require_accelerator("tcg")
- tar_hash = '6951d86d644b302898da2fd701739c9406527fe1'
- self.do_test_advcal_2018('19', tar_hash, 'uImage')
-
- def do_test_ppc64_powernv(self, proc):
- self.require_accelerator("tcg")
- images_url = ('https://github.com/open-power/op-build/releases/download/v2.7/')
-
- kernel_url = images_url + 'zImage.epapr'
- kernel_hash = '0ab237df661727e5392cee97460e8674057a883c5f74381a128fa772588d45cd'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash,
- algorithm='sha256')
- self.vm.set_console()
- self.vm.add_args('-kernel', kernel_path,
- '-append', 'console=tty0 console=hvc0',
- '-device', 'pcie-pci-bridge,id=bridge1,bus=pcie.1,addr=0x0',
- '-device', 'nvme,bus=pcie.2,addr=0x0,serial=1234',
- '-device', 'e1000e,bus=bridge1,addr=0x3',
- '-device', 'nec-usb-xhci,bus=bridge1,addr=0x2')
- self.vm.launch()
-
- self.wait_for_console_pattern("CPU: " + proc + " generation processor")
- self.wait_for_console_pattern("zImage starting: loaded")
- self.wait_for_console_pattern("Run /init as init process")
- # Device detection output driven by udev probing is sometimes cut off
- # from console output, suspect S14silence-console init script.
-
- def test_ppc_powernv8(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv8
- :avocado: tags=accel:tcg
- """
- self.do_test_ppc64_powernv('P8')
-
- def test_ppc_powernv9(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv9
- :avocado: tags=accel:tcg
- """
- self.do_test_ppc64_powernv('P9')
-
- def test_ppc_powernv10(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv10
- :avocado: tags=accel:tcg
- """
- self.do_test_ppc64_powernv('P10')
-
- def test_ppc_g3beige(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:g3beige
- :avocado: tags=accel:tcg
- """
- # TODO: g3beige works with kvm_pr but we don't have a
- # reliable way ATM (e.g. looking at /proc/modules) to detect
- # whether we're running kvm_hv or kvm_pr. For now let's
- # disable this test if we don't have TCG support.
- self.require_accelerator("tcg")
- tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc'
- self.vm.add_args('-M', 'graphics=off')
- self.do_test_advcal_2018('15', tar_hash, 'invaders.elf')
-
- def test_ppc_mac99(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:mac99
- :avocado: tags=accel:tcg
- """
- # TODO: mac99 works with kvm_pr but we don't have a
- # reliable way ATM (e.g. looking at /proc/modules) to detect
- # whether we're running kvm_hv or kvm_pr. For now let's
- # disable this test if we don't have TCG support.
- self.require_accelerator("tcg")
- tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc'
- self.vm.add_args('-M', 'graphics=off')
- self.do_test_advcal_2018('15', tar_hash, 'invaders.elf')
-
- # This test has a 6-10% failure rate on various hosts that look
- # like issues with a buggy kernel. As a result we don't want it
- # gating releases on Gitlab.
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
- def test_sh4_r2d(self):
- """
- :avocado: tags=arch:sh4
- :avocado: tags=machine:r2d
- :avocado: tags=flaky
- """
- tar_hash = 'fe06a4fd8ccbf2e27928d64472939d47829d4c7e'
- self.vm.add_args('-append', 'console=ttySC1')
- self.do_test_advcal_2018('09', tar_hash, 'zImage', console=1)
-
- def test_sparc_ss20(self):
- """
- :avocado: tags=arch:sparc
- :avocado: tags=machine:SS-20
- """
- tar_hash = 'b18550d5d61c7615d989a06edace051017726a9f'
- self.do_test_advcal_2018('11', tar_hash, 'zImage.elf')
-
- def test_xtensa_lx60(self):
- """
- :avocado: tags=arch:xtensa
- :avocado: tags=machine:lx60
- :avocado: tags=cpu:dc233c
- """
- tar_hash = '49e88d9933742f0164b60839886c9739cb7a0d34'
- self.do_test_advcal_2018('02', tar_hash, 'santas-sleigh-ride.elf')
diff --git a/tests/avocado/boot_xen.py b/tests/avocado/boot_xen.py
deleted file mode 100644
index 490a127..0000000
--- a/tests/avocado/boot_xen.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# Functional test that boots a Xen hypervisor with a domU kernel and
-# checks the console output is vaguely sane .
-#
-# Copyright (c) 2020 Linaro
-#
-# Author:
-# Alex Bennée <alex.bennee@linaro.org>
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import os
-
-from avocado_qemu import wait_for_console_pattern
-from boot_linux_console import LinuxKernelTest
-
-
-class BootXen(LinuxKernelTest):
- """
- Boots a Xen hypervisor with a Linux DomU kernel.
-
- :avocado: tags=arch:aarch64
- :avocado: tags=accel:tcg
- :avocado: tags=cpu:cortex-a57
- :avocado: tags=machine:virt
- """
-
- timeout = 90
- XEN_COMMON_COMMAND_LINE = 'dom0_mem=128M loglvl=all guest_loglvl=all'
-
- def setUp(self):
- super(BootXen, self).setUp()
-
- # Using my own built kernel - which works
- kernel_url = ('https://fileserver.linaro.org/'
- 's/JSsewXGZ6mqxPr5/download?path=%2F&files='
- 'linux-5.9.9-arm64-ajb')
- kernel_sha1 = '4f92bc4b9f88d5ab792fa7a43a68555d344e1b83'
- self.kernel_path = self.fetch_asset(kernel_url,
- asset_hash=kernel_sha1)
-
- def launch_xen(self, xen_path):
- """
- Launch Xen with a dom0 guest kernel
- """
- self.log.info("launch with xen_path: %s", xen_path)
-
- self.vm.set_console()
-
- self.vm.add_args('-machine', 'virtualization=on',
- '-m', '768',
- '-kernel', xen_path,
- '-append', self.XEN_COMMON_COMMAND_LINE,
- '-device',
- 'guest-loader,addr=0x47000000,kernel=%s,bootargs=console=hvc0'
- % (self.kernel_path))
-
- self.vm.launch()
-
- console_pattern = 'VFS: Cannot open root device'
- wait_for_console_pattern(self, console_pattern, "Panic on CPU 0:")
-
- def test_arm64_xen_411_and_dom0(self):
- # archive of file from https://deb.debian.org/debian/pool/main/x/xen/
- xen_url = ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/'
- 'download?path=%2F&files='
- 'xen-hypervisor-4.11-arm64_4.11.4%2B37-g3263f257ca-1_arm64.deb')
- xen_sha1 = '034e634d4416adbad1212d59b62bccdcda63e62a'
- xen_deb = self.fetch_asset(xen_url, asset_hash=xen_sha1)
- xen_path = self.extract_from_deb(xen_deb, "/boot/xen-4.11-arm64")
-
- self.launch_xen(xen_path)
-
- def test_arm64_xen_414_and_dom0(self):
- # archive of file from https://deb.debian.org/debian/pool/main/x/xen/
- xen_url = ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/'
- 'download?path=%2F&files='
- 'xen-hypervisor-4.14-arm64_4.14.0%2B80-gd101b417b7-1_arm64.deb')
- xen_sha1 = 'b9d209dd689ed2b393e625303a225badefec1160'
- xen_deb = self.fetch_asset(xen_url, asset_hash=xen_sha1)
- xen_path = self.extract_from_deb(xen_deb, "/boot/xen-4.14-arm64")
-
- self.launch_xen(xen_path)
-
- def test_arm64_xen_415_and_dom0(self):
- xen_url = ('https://fileserver.linaro.org/'
- 's/JSsewXGZ6mqxPr5/download'
- '?path=%2F&files=xen-upstream-4.15-unstable.deb')
- xen_sha1 = 'fc191172b85cf355abb95d275a24cc0f6d6579d8'
- xen_deb = self.fetch_asset(xen_url, asset_hash=xen_sha1)
- xen_path = self.extract_from_deb(xen_deb, "/boot/xen-4.15-unstable")
-
- self.launch_xen(xen_path)
diff --git a/tests/avocado/hotplug_blk.py b/tests/avocado/hotplug_blk.py
deleted file mode 100644
index d55ded1..0000000
--- a/tests/avocado/hotplug_blk.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Functional test that hotplugs a virtio blk disk and checks it on a Linux
-# guest
-#
-# Copyright (c) 2021 Red Hat, Inc.
-# Copyright (c) Yandex
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import time
-
-from avocado_qemu.linuxtest import LinuxTest
-
-
-class HotPlug(LinuxTest):
- def blockdev_add(self) -> None:
- self.vm.cmd('blockdev-add', **{
- 'driver': 'null-co',
- 'size': 1073741824,
- 'node-name': 'disk'
- })
-
- def assert_vda(self) -> None:
- self.ssh_command('test -e /sys/block/vda')
-
- def assert_no_vda(self) -> None:
- with self.assertRaises(AssertionError):
- self.assert_vda()
-
- def plug(self) -> None:
- args = {
- 'driver': 'virtio-blk-pci',
- 'drive': 'disk',
- 'id': 'virtio-disk0',
- 'bus': 'pci.1',
- 'addr': 1
- }
-
- self.assert_no_vda()
- self.vm.cmd('device_add', args)
- try:
- self.assert_vda()
- except AssertionError:
- time.sleep(1)
- self.assert_vda()
-
- def unplug(self) -> None:
- self.vm.cmd('device_del', id='virtio-disk0')
-
- self.vm.event_wait('DEVICE_DELETED', 1.0,
- match={'data': {'device': 'virtio-disk0'}})
-
- self.assert_no_vda()
-
- def test(self) -> None:
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:q35
- :avocado: tags=accel:kvm
- """
- self.require_accelerator('kvm')
- self.vm.add_args('-accel', 'kvm')
- self.vm.add_args('-device', 'pcie-pci-bridge,id=pci.1,bus=pcie.0')
-
- self.launch_and_wait()
- self.blockdev_add()
-
- self.plug()
- self.unplug()
diff --git a/tests/avocado/hotplug_cpu.py b/tests/avocado/hotplug_cpu.py
deleted file mode 100644
index 342c838..0000000
--- a/tests/avocado/hotplug_cpu.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Functional test that hotplugs a CPU and checks it on a Linux guest
-#
-# Copyright (c) 2021 Red Hat, Inc.
-#
-# Author:
-# Cleber Rosa <crosa@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-from avocado_qemu.linuxtest import LinuxTest
-
-
-class HotPlugCPU(LinuxTest):
-
- def test(self):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:q35
- :avocado: tags=accel:kvm
- """
- self.require_accelerator('kvm')
- self.vm.add_args('-accel', 'kvm')
- self.vm.add_args('-cpu', 'Haswell')
- self.vm.add_args('-smp', '1,sockets=1,cores=2,threads=1,maxcpus=2')
- self.launch_and_wait()
-
- self.ssh_command('test -e /sys/devices/system/cpu/cpu0')
- with self.assertRaises(AssertionError):
- self.ssh_command('test -e /sys/devices/system/cpu/cpu1')
-
- self.vm.cmd('device_add',
- driver='Haswell-x86_64-cpu',
- socket_id=0,
- core_id=1,
- thread_id=0)
- self.ssh_command('test -e /sys/devices/system/cpu/cpu1')
diff --git a/tests/avocado/intel_iommu.py b/tests/avocado/intel_iommu.py
deleted file mode 100644
index 992583f..0000000
--- a/tests/avocado/intel_iommu.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# INTEL_IOMMU Functional tests
-#
-# Copyright (c) 2021 Red Hat, Inc.
-#
-# Author:
-# Eric Auger <eric.auger@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-import os
-
-from avocado import skipUnless
-from avocado_qemu.linuxtest import LinuxTest
-
-@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-class IntelIOMMU(LinuxTest):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=distro:fedora
- :avocado: tags=distro_version:31
- :avocado: tags=machine:q35
- :avocado: tags=accel:kvm
- :avocado: tags=intel_iommu
- :avocado: tags=flaky
- """
-
- IOMMU_ADDON = ',iommu_platform=on,disable-modern=off,disable-legacy=on'
- kernel_path = None
- initrd_path = None
- kernel_params = None
-
- def set_up_boot(self):
- path = self.download_boot()
- self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,' +
- 'drive=drv0,id=virtio-disk0,bootindex=1,'
- 'werror=stop,rerror=stop' + self.IOMMU_ADDON)
- self.vm.add_args('-device', 'virtio-gpu-pci' + self.IOMMU_ADDON)
- self.vm.add_args('-drive',
- 'file=%s,if=none,cache=writethrough,id=drv0' % path)
-
- def setUp(self):
- super(IntelIOMMU, self).setUp(None, 'virtio-net-pci' + self.IOMMU_ADDON)
-
- def add_common_args(self):
- self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
- self.vm.add_args('-object',
- 'rng-random,id=rng0,filename=/dev/urandom')
-
- def common_vm_setup(self, custom_kernel=None):
- self.require_accelerator("kvm")
- self.add_common_args()
- self.vm.add_args("-accel", "kvm")
-
- if custom_kernel is None:
- return
-
- kernel_url = self.distro.pxeboot_url + 'vmlinuz'
- kernel_hash = '5b6f6876e1b5bda314f93893271da0d5777b1f3c'
- initrd_url = self.distro.pxeboot_url + 'initrd.img'
- initrd_hash = 'dd0340a1b39bd28f88532babd4581c67649ec5b1'
- self.kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- self.initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
-
- def run_and_check(self):
- if self.kernel_path:
- self.vm.add_args('-kernel', self.kernel_path,
- '-append', self.kernel_params,
- '-initrd', self.initrd_path)
- self.launch_and_wait()
- self.ssh_command('cat /proc/cmdline')
- self.ssh_command('dmesg | grep -e DMAR -e IOMMU')
- self.ssh_command('find /sys/kernel/iommu_groups/ -type l')
- self.ssh_command('dnf -y install numactl-devel')
-
- def test_intel_iommu(self):
- """
- :avocado: tags=intel_iommu_intremap
- """
-
- self.common_vm_setup(True)
- self.vm.add_args('-device', 'intel-iommu,intremap=on')
- self.vm.add_args('-machine', 'kernel_irqchip=split')
-
- self.kernel_params = (self.distro.default_kernel_params +
- ' quiet intel_iommu=on')
- self.run_and_check()
-
- def test_intel_iommu_strict(self):
- """
- :avocado: tags=intel_iommu_strict
- """
-
- self.common_vm_setup(True)
- self.vm.add_args('-device', 'intel-iommu,intremap=on')
- self.vm.add_args('-machine', 'kernel_irqchip=split')
- self.kernel_params = (self.distro.default_kernel_params +
- ' quiet intel_iommu=on,strict')
- self.run_and_check()
-
- def test_intel_iommu_strict_cm(self):
- """
- :avocado: tags=intel_iommu_strict_cm
- """
-
- self.common_vm_setup(True)
- self.vm.add_args('-device', 'intel-iommu,intremap=on,caching-mode=on')
- self.vm.add_args('-machine', 'kernel_irqchip=split')
- self.kernel_params = (self.distro.default_kernel_params +
- ' quiet intel_iommu=on,strict')
- self.run_and_check()
-
- def test_intel_iommu_pt(self):
- """
- :avocado: tags=intel_iommu_pt
- """
-
- self.common_vm_setup(True)
- self.vm.add_args('-device', 'intel-iommu,intremap=on')
- self.vm.add_args('-machine', 'kernel_irqchip=split')
- self.kernel_params = (self.distro.default_kernel_params +
- ' quiet intel_iommu=on iommu=pt')
- self.run_and_check()
diff --git a/tests/avocado/linux_ssh_mips_malta.py b/tests/avocado/linux_ssh_mips_malta.py
deleted file mode 100644
index d9bb525..0000000
--- a/tests/avocado/linux_ssh_mips_malta.py
+++ /dev/null
@@ -1,205 +0,0 @@
-# Functional test that boots a VM and run commands via a SSH session
-#
-# Copyright (c) Philippe Mathieu-Daudé <f4bug@amsat.org>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import os
-import re
-import base64
-import logging
-import time
-
-from avocado import skipUnless
-from avocado_qemu import LinuxSSHMixIn
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-from avocado.utils import process
-from avocado.utils import archive
-from avocado.utils import ssh
-
-
-@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
-@skipUnless(ssh.SSH_CLIENT_BINARY, 'No SSH client available')
-class LinuxSSH(QemuSystemTest, LinuxSSHMixIn):
- """
- :avocado: tags=accel:tcg
- """
-
- timeout = 150 # Not for 'configure --enable-debug --enable-debug-tcg'
-
- KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
- VM_IP = '127.0.0.1'
-
- BASE_URL = 'https://people.debian.org/~aurel32/qemu/'
- IMAGE_INFO = {
- 'be': {'base_url': 'mips',
- 'image_name': 'debian_wheezy_mips_standard.qcow2',
- 'image_hash': '8987a63270df67345b2135a6b7a4885a35e392d5',
- 'kernel_hash': {
- 32: '592e384a4edc16dade52a6cd5c785c637bcbc9ad',
- 64: 'db6eea7de35d36c77d8c165b6bcb222e16eb91db'}
- },
- 'le': {'base_url': 'mipsel',
- 'image_name': 'debian_wheezy_mipsel_standard.qcow2',
- 'image_hash': '7866764d9de3ef536ffca24c9fb9f04ffdb45802',
- 'kernel_hash': {
- 32: 'a66bea5a8adaa2cb3d36a1d4e0ccdb01be8f6c2a',
- 64: '6a7f77245acf231415a0e8b725d91ed2f3487794'}
- }
- }
- CPU_INFO = {
- 32: {'cpu': 'MIPS 24Kc', 'kernel_release': '3.2.0-4-4kc-malta'},
- 64: {'cpu': 'MIPS 20Kc', 'kernel_release': '3.2.0-4-5kc-malta'}
- }
-
- def get_url(self, endianess, path=''):
- qkey = {'le': 'el', 'be': ''}
- return '%s/mips%s/%s' % (self.BASE_URL, qkey[endianess], path)
-
- def get_image_info(self, endianess):
- dinfo = self.IMAGE_INFO[endianess]
- image_url = self.get_url(endianess, dinfo['image_name'])
- image_hash = dinfo['image_hash']
- return (image_url, image_hash)
-
- def get_kernel_info(self, endianess, wordsize):
- minfo = self.CPU_INFO[wordsize]
- kernel_url = self.get_url(endianess,
- 'vmlinux-%s' % minfo['kernel_release'])
- kernel_hash = self.IMAGE_INFO[endianess]['kernel_hash'][wordsize]
- return kernel_url, kernel_hash
-
- def ssh_disconnect_vm(self):
- self.ssh_session.quit()
-
- def boot_debian_wheezy_image_and_ssh_login(self, endianess, kernel_path):
- image_url, image_hash = self.get_image_info(endianess)
- image_path = self.fetch_asset(image_url, asset_hash=image_hash)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
- + 'console=ttyS0 root=/dev/sda1')
- self.vm.add_args('-no-reboot',
- '-kernel', kernel_path,
- '-append', kernel_command_line,
- '-drive', 'file=%s,snapshot=on' % image_path,
- '-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
- '-device', 'pcnet,netdev=vnet')
- self.vm.launch()
-
- self.log.info('VM launched, waiting for sshd')
- console_pattern = 'Starting OpenBSD Secure Shell server: sshd'
- wait_for_console_pattern(self, console_pattern, 'Oops')
- self.log.info('sshd ready')
-
- self.ssh_connect('root', 'root', False)
-
- def shutdown_via_ssh(self):
- self.ssh_command('poweroff')
- self.ssh_disconnect_vm()
- wait_for_console_pattern(self, 'Power down', 'Oops')
-
- def run_common_commands(self, wordsize):
- self.ssh_command_output_contains(
- 'cat /proc/cpuinfo',
- self.CPU_INFO[wordsize]['cpu'])
- self.ssh_command_output_contains(
- 'uname -m',
- 'mips')
- self.ssh_command_output_contains(
- 'uname -r',
- self.CPU_INFO[wordsize]['kernel_release'])
- self.ssh_command_output_contains(
- 'cat /proc/interrupts',
- 'XT-PIC timer')
- self.ssh_command_output_contains(
- 'cat /proc/interrupts',
- 'XT-PIC i8042')
- self.ssh_command_output_contains(
- 'cat /proc/interrupts',
- 'XT-PIC serial')
- self.ssh_command_output_contains(
- 'cat /proc/interrupts',
- 'XT-PIC ata_piix')
- self.ssh_command_output_contains(
- 'cat /proc/interrupts',
- 'XT-PIC eth0')
- self.ssh_command_output_contains(
- 'cat /proc/devices',
- 'input')
- self.ssh_command_output_contains(
- 'cat /proc/devices',
- 'usb')
- self.ssh_command_output_contains(
- 'cat /proc/devices',
- 'fb')
- self.ssh_command_output_contains(
- 'cat /proc/ioports',
- ' : serial')
- self.ssh_command_output_contains(
- 'cat /proc/ioports',
- ' : ata_piix')
- self.ssh_command_output_contains(
- 'cat /proc/ioports',
- ' : piix4_smbus')
- self.ssh_command_output_contains(
- 'lspci -d 11ab:4620',
- 'GT-64120')
- self.ssh_command_output_contains(
- 'cat /sys/bus/i2c/devices/i2c-0/name',
- 'SMBus PIIX4 adapter')
- self.ssh_command_output_contains(
- 'cat /proc/mtd',
- 'YAMON')
- # Empty 'Board Config' (64KB)
- self.ssh_command_output_contains(
- 'md5sum /dev/mtd2ro',
- '0dfbe8aa4c20b52e1b8bf3cb6cbdf193')
-
- def check_mips_malta(self, uname_m, endianess):
- wordsize = 64 if '64' in uname_m else 32
- kernel_url, kernel_hash = self.get_kernel_info(endianess, wordsize)
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- self.boot_debian_wheezy_image_and_ssh_login(endianess, kernel_path)
-
- stdout, _ = self.ssh_command('uname -a')
- self.assertIn(True, [uname_m + " GNU/Linux" in line for line in stdout])
-
- self.run_common_commands(wordsize)
- self.shutdown_via_ssh()
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- def test_mips_malta32eb_kernel3_2_0(self):
- """
- :avocado: tags=arch:mips
- :avocado: tags=endian:big
- :avocado: tags=device:pcnet32
- """
- self.check_mips_malta('mips', 'be')
-
- def test_mips_malta32el_kernel3_2_0(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=endian:little
- :avocado: tags=device:pcnet32
- """
- self.check_mips_malta('mips', 'le')
-
- def test_mips_malta64eb_kernel3_2_0(self):
- """
- :avocado: tags=arch:mips64
- :avocado: tags=endian:big
- :avocado: tags=device:pcnet32
- """
- self.check_mips_malta('mips64', 'be')
-
- def test_mips_malta64el_kernel3_2_0(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=endian:little
- :avocado: tags=device:pcnet32
- """
- self.check_mips_malta('mips64', 'le')
diff --git a/tests/avocado/machine_arm_n8x0.py b/tests/avocado/machine_arm_n8x0.py
deleted file mode 100755
index 12e9a68..0000000
--- a/tests/avocado/machine_arm_n8x0.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Functional test that boots a Linux kernel and checks the console
-#
-# Copyright (c) 2020 Red Hat, Inc.
-#
-# Author:
-# Thomas Huth <thuth@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import os
-
-from avocado import skipUnless
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-
-class N8x0Machine(QemuSystemTest):
- """Boots the Linux kernel and checks that the console is operational"""
-
- timeout = 90
-
- def __do_test_n8x0(self):
- kernel_url = ('http://stskeeps.subnetmask.net/meego-n8x0/'
- 'meego-arm-n8x0-1.0.80.20100712.1431-'
- 'vmlinuz-2.6.35~rc4-129.1-n8x0')
- kernel_hash = 'e9d5ab8d7548923a0061b6fbf601465e479ed269'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- self.vm.set_console(console_index=1)
- self.vm.add_args('-kernel', kernel_path,
- '-append', 'printk.time=0 console=ttyS1')
- self.vm.launch()
- wait_for_console_pattern(self, 'TSC2005 driver initializing')
-
- @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
- def test_n800(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:n800
- """
- self.__do_test_n8x0()
-
- @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
- def test_n810(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:n810
- """
- self.__do_test_n8x0()
diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
deleted file mode 100644
index c0b01e8..0000000
--- a/tests/avocado/machine_aspeed.py
+++ /dev/null
@@ -1,478 +0,0 @@
-# Functional test that boots the ASPEED SoCs with firmware
-#
-# Copyright (C) 2022 ASPEED Technology 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.
-
-import time
-import os
-import tempfile
-import subprocess
-
-from avocado_qemu import LinuxSSHMixIn
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-from avocado_qemu import exec_command
-from avocado_qemu import exec_command_and_wait_for_pattern
-from avocado_qemu import interrupt_interactive_console_until_pattern
-from avocado_qemu import has_cmd
-from avocado.utils import archive
-from avocado import skipUnless
-from avocado import skipUnless
-
-
-class AST1030Machine(QemuSystemTest):
- """Boots the zephyr os and checks that the console is operational"""
-
- timeout = 10
-
- def test_ast1030_zephyros_1_04(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast1030-evb
- :avocado: tags=os:zephyr
- """
- tar_url = ('https://github.com/AspeedTech-BMC'
- '/zephyr/releases/download/v00.01.04/ast1030-evb-demo.zip')
- tar_hash = '4c6a8ce3a8ba76ef1a65dae419ae3409343c4b20'
- tar_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(tar_path, self.workdir)
- kernel_file = self.workdir + "/ast1030-evb-demo/zephyr.elf"
- self.vm.set_console()
- self.vm.add_args('-kernel', kernel_file,
- '-nographic')
- self.vm.launch()
- wait_for_console_pattern(self, "Booting Zephyr OS")
- exec_command_and_wait_for_pattern(self, "help",
- "Available commands")
-
- def test_ast1030_zephyros_1_07(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast1030-evb
- :avocado: tags=os:zephyr
- """
- tar_url = ('https://github.com/AspeedTech-BMC'
- '/zephyr/releases/download/v00.01.07/ast1030-evb-demo.zip')
- tar_hash = '40ac87eabdcd3b3454ce5aad11fedc72a33ecda2'
- tar_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(tar_path, self.workdir)
- kernel_file = self.workdir + "/ast1030-evb-demo/zephyr.bin"
- self.vm.set_console()
- self.vm.add_args('-kernel', kernel_file,
- '-nographic')
- self.vm.launch()
- wait_for_console_pattern(self, "Booting Zephyr OS")
- for shell_cmd in [
- 'kernel stacks',
- 'otp info conf',
- 'otp info scu',
- 'hwinfo devid',
- 'crypto aes256_cbc_vault',
- 'random get',
- 'jtag JTAG1 sw_xfer high TMS',
- 'adc ADC0 resolution 12',
- 'adc ADC0 read 42',
- 'adc ADC1 read 69',
- 'i2c scan I2C_0',
- 'i3c attach I3C_0',
- 'hash test',
- 'kernel uptime',
- 'kernel reboot warm',
- 'kernel uptime',
- 'kernel reboot cold',
- 'kernel uptime',
- ]: exec_command_and_wait_for_pattern(self, shell_cmd, "uart:~$")
-
-class AST2x00Machine(QemuSystemTest):
-
- timeout = 180
-
- def wait_for_console_pattern(self, success_message, vm=None):
- wait_for_console_pattern(self, success_message,
- failure_message='Kernel panic - not syncing',
- vm=vm)
-
- def do_test_arm_aspeed(self, image):
- self.vm.set_console()
- self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
- '-net', 'nic')
- self.vm.launch()
-
- self.wait_for_console_pattern("U-Boot 2016.07")
- self.wait_for_console_pattern("## Loading kernel from FIT Image at 20080000")
- self.wait_for_console_pattern("Starting kernel ...")
- self.wait_for_console_pattern("Booting Linux on physical CPU 0x0")
- wait_for_console_pattern(self,
- "aspeed-smc 1e620000.spi: read control register: 203b0641")
- self.wait_for_console_pattern("ftgmac100 1e660000.ethernet eth0: irq ")
- self.wait_for_console_pattern("systemd[1]: Set hostname to")
-
- def test_arm_ast2400_palmetto_openbmc_v2_9_0(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:palmetto-bmc
- """
-
- image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
- 'obmc-phosphor-image-palmetto.static.mtd')
- image_hash = ('3e13bbbc28e424865dc42f35ad672b10f2e82cdb11846bb28fa625b48beafd0d')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- self.do_test_arm_aspeed(image_path)
-
- def test_arm_ast2500_romulus_openbmc_v2_9_0(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:romulus-bmc
- """
-
- image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
- 'obmc-phosphor-image-romulus.static.mtd')
- image_hash = ('820341076803f1955bc31e647a512c79f9add4f5233d0697678bab4604c7bb25')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- self.do_test_arm_aspeed(image_path)
-
- def do_test_arm_aspeed_buildroot_start(self, image, cpu_id, pattern='Aspeed EVB'):
- self.require_netdev('user')
-
- self.vm.set_console()
- self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
- '-net', 'nic', '-net', 'user')
- self.vm.launch()
-
- self.wait_for_console_pattern('U-Boot 2019.04')
- self.wait_for_console_pattern('## Loading kernel from FIT Image')
- self.wait_for_console_pattern('Starting kernel ...')
- self.wait_for_console_pattern('Booting Linux on physical CPU ' + cpu_id)
- self.wait_for_console_pattern('lease of 10.0.2.15')
- # the line before login:
- self.wait_for_console_pattern(pattern)
- time.sleep(0.1)
- exec_command(self, 'root')
- time.sleep(0.1)
- exec_command(self, "passw0rd")
-
- def do_test_arm_aspeed_buildroot_poweroff(self):
- exec_command_and_wait_for_pattern(self, 'poweroff',
- 'reboot: System halted');
-
- def test_arm_ast2500_evb_buildroot(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast2500-evb
- """
-
- image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
- 'images/ast2500-evb/buildroot-2023.11/flash.img')
- image_hash = ('c23db6160cf77d0258397eb2051162c8473a56c441417c52a91ba217186e715f')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- self.vm.add_args('-device',
- 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test');
- self.do_test_arm_aspeed_buildroot_start(image_path, '0x0', 'Aspeed AST2500 EVB')
-
- exec_command_and_wait_for_pattern(self,
- 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device',
- 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d');
- exec_command_and_wait_for_pattern(self,
- 'cat /sys/class/hwmon/hwmon1/temp1_input', '0')
- self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
- property='temperature', value=18000);
- exec_command_and_wait_for_pattern(self,
- 'cat /sys/class/hwmon/hwmon1/temp1_input', '18000')
-
- self.do_test_arm_aspeed_buildroot_poweroff()
-
- def test_arm_ast2600_evb_buildroot(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast2600-evb
- """
-
- image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
- 'images/ast2600-evb/buildroot-2023.11/flash.img')
- image_hash = ('b62808daef48b438d0728ee07662290490ecfa65987bb91294cafb1bb7ad1a68')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- self.vm.add_args('-device',
- 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test');
- self.vm.add_args('-device',
- 'ds1338,bus=aspeed.i2c.bus.3,address=0x32');
- self.vm.add_args('-device',
- 'i2c-echo,bus=aspeed.i2c.bus.3,address=0x42');
- self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', 'Aspeed AST2600 EVB')
-
- exec_command_and_wait_for_pattern(self,
- 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device',
- 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d');
- exec_command_and_wait_for_pattern(self,
- 'cat /sys/class/hwmon/hwmon1/temp1_input', '0')
- self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
- property='temperature', value=18000);
- exec_command_and_wait_for_pattern(self,
- 'cat /sys/class/hwmon/hwmon1/temp1_input', '18000')
-
- exec_command_and_wait_for_pattern(self,
- 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-3/device/new_device',
- 'i2c i2c-3: new_device: Instantiated device ds1307 at 0x32');
- year = time.strftime("%Y")
- exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year);
-
- exec_command_and_wait_for_pattern(self,
- 'echo slave-24c02 0x1064 > /sys/bus/i2c/devices/i2c-3/new_device',
- 'i2c i2c-3: new_device: Instantiated device slave-24c02 at 0x64');
- exec_command(self, 'i2cset -y 3 0x42 0x64 0x00 0xaa i');
- time.sleep(0.1)
- exec_command_and_wait_for_pattern(self,
- 'hexdump /sys/bus/i2c/devices/3-1064/slave-eeprom',
- '0000000 ffaa ffff ffff ffff ffff ffff ffff ffff');
- self.do_test_arm_aspeed_buildroot_poweroff()
-
- @skipUnless(*has_cmd('swtpm'))
- def test_arm_ast2600_evb_buildroot_tpm(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast2600-evb
- """
-
- image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
- 'images/ast2600-evb/buildroot-2023.02-tpm/flash.img')
- image_hash = ('a46009ae8a5403a0826d607215e731a8c68d27c14c41e55331706b8f9c7bd997')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- # force creation of VM object, which also defines self._sd
- vm = self.vm
-
- socket = os.path.join(self._sd.name, 'swtpm-socket')
-
- subprocess.run(['swtpm', 'socket', '-d', '--tpm2',
- '--tpmstate', f'dir={self.vm.temp_dir}',
- '--ctrl', f'type=unixio,path={socket}'])
-
- self.vm.add_args('-chardev', f'socket,id=chrtpm,path={socket}')
- self.vm.add_args('-tpmdev', 'emulator,id=tpm0,chardev=chrtpm')
- self.vm.add_args('-device',
- 'tpm-tis-i2c,tpmdev=tpm0,bus=aspeed.i2c.bus.12,address=0x2e')
- self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', 'Aspeed AST2600 EVB')
-
- exec_command_and_wait_for_pattern(self,
- 'echo tpm_tis_i2c 0x2e > /sys/bus/i2c/devices/i2c-12/new_device',
- 'tpm_tis_i2c 12-002e: 2.0 TPM (device-id 0x1, rev-id 1)');
- exec_command_and_wait_for_pattern(self,
- 'cat /sys/class/tpm/tpm0/pcr-sha256/0',
- 'B804724EA13F52A9072BA87FE8FDCC497DFC9DF9AA15B9088694639C431688E0');
-
- self.do_test_arm_aspeed_buildroot_poweroff()
-
-class AST2x00MachineSDK(QemuSystemTest, LinuxSSHMixIn):
-
- EXTRA_BOOTARGS = (
- 'quiet '
- 'systemd.mask=org.openbmc.HostIpmi.service '
- 'systemd.mask=xyz.openbmc_project.Chassis.Control.Power@0.service '
- 'systemd.mask=modprobe@fuse.service '
- 'systemd.mask=rngd.service '
- 'systemd.mask=obmc-console@ttyS2.service '
- )
-
- # FIXME: Although these tests boot a whole distro they are still
- # slower than comparable machine models. There may be some
- # optimisations which bring down the runtime. In the meantime they
- # have generous timeouts and are disable for CI which aims for all
- # tests to run in less than 60 seconds.
- timeout = 240
-
- def wait_for_console_pattern(self, success_message, vm=None):
- wait_for_console_pattern(self, success_message,
- failure_message='Kernel panic - not syncing',
- vm=vm)
-
- def do_test_arm_aspeed_sdk_start(self, image):
- self.require_netdev('user')
- self.vm.set_console()
- self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
- '-net', 'nic', '-net', 'user,hostfwd=:127.0.0.1:0-:22')
- self.vm.launch()
-
- self.wait_for_console_pattern('U-Boot 2019.04')
- interrupt_interactive_console_until_pattern(
- self, 'Hit any key to stop autoboot:', 'ast#')
- exec_command_and_wait_for_pattern(
- self, 'setenv bootargs ${bootargs} ' + self.EXTRA_BOOTARGS, 'ast#')
- exec_command_and_wait_for_pattern(
- self, 'boot', '## Loading kernel from FIT Image')
- self.wait_for_console_pattern('Starting kernel ...')
-
- def do_test_aarch64_aspeed_sdk_start(self, image):
- self.vm.set_console()
- self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
- '-net', 'nic', '-net', 'user,hostfwd=:127.0.0.1:0-:22')
-
- self.vm.launch()
-
- self.wait_for_console_pattern('U-Boot 2023.10')
- self.wait_for_console_pattern('## Loading kernel from FIT Image')
- self.wait_for_console_pattern('Starting kernel ...')
-
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
- def test_arm_ast2500_evb_sdk(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast2500-evb
- :avocado: tags=flaky
- """
-
- image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/'
- 'download/v08.06/ast2500-default-obmc.tar.gz')
- image_hash = ('e1755f3cadff69190438c688d52dd0f0d399b70a1e14b1d3d5540fc4851d38ca')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
- archive.extract(image_path, self.workdir)
-
- self.do_test_arm_aspeed_sdk_start(
- self.workdir + '/ast2500-default/image-bmc')
- self.wait_for_console_pattern('nodistro.0 ast2500-default ttyS4')
-
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
- def test_arm_ast2600_evb_sdk(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast2600-evb
- :avocado: tags=flaky
- """
-
- image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/'
- 'download/v08.06/ast2600-a2-obmc.tar.gz')
- image_hash = ('9083506135f622d5e7351fcf7d4e1c7125cee5ba16141220c0ba88931f3681a4')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
- archive.extract(image_path, self.workdir)
-
- self.vm.add_args('-device',
- 'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test');
- self.vm.add_args('-device',
- 'ds1338,bus=aspeed.i2c.bus.5,address=0x32');
- self.do_test_arm_aspeed_sdk_start(
- self.workdir + '/ast2600-a2/image-bmc')
- self.wait_for_console_pattern('nodistro.0 ast2600-a2 ttyS4')
-
- self.ssh_connect('root', '0penBmc', False)
- self.ssh_command('dmesg -c > /dev/null')
-
- self.ssh_command_output_contains(
- 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-5/device/new_device ; '
- 'dmesg -c',
- 'i2c i2c-5: new_device: Instantiated device lm75 at 0x4d');
- self.ssh_command_output_contains(
- 'cat /sys/class/hwmon/hwmon19/temp1_input', '0')
- self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
- property='temperature', value=18000);
- self.ssh_command_output_contains(
- 'cat /sys/class/hwmon/hwmon19/temp1_input', '18000')
-
- self.ssh_command_output_contains(
- 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-5/device/new_device ; '
- 'dmesg -c',
- 'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32');
- year = time.strftime("%Y")
- self.ssh_command_output_contains('/sbin/hwclock -f /dev/rtc1', year);
-
- def test_aarch64_ast2700_evb_sdk_v09_02(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:ast2700-evb
- """
-
- image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/'
- 'download/v09.02/ast2700-default-obmc.tar.gz')
- image_hash = 'ac969c2602f4e6bdb69562ff466b89ae3fe1d86e1f6797bb7969d787f82116a7'
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
- archive.extract(image_path, self.workdir)
-
- num_cpu = 4
- image_dir = self.workdir + '/ast2700-default/'
- uboot_size = os.path.getsize(image_dir + 'u-boot-nodtb.bin')
- uboot_dtb_load_addr = hex(0x400000000 + uboot_size)
-
- load_images_list = [
- {
- 'addr': '0x400000000',
- 'file': image_dir + 'u-boot-nodtb.bin'
- },
- {
- 'addr': str(uboot_dtb_load_addr),
- 'file': image_dir + 'u-boot.dtb'
- },
- {
- 'addr': '0x430000000',
- 'file': image_dir + 'bl31.bin'
- },
- {
- 'addr': '0x430080000',
- 'file': image_dir + 'optee/tee-raw.bin'
- }
- ]
-
- for load_image in load_images_list:
- addr = load_image['addr']
- file = load_image['file']
- self.vm.add_args('-device',
- f'loader,force-raw=on,addr={addr},file={file}')
-
- for i in range(num_cpu):
- self.vm.add_args('-device',
- f'loader,addr=0x430000000,cpu-num={i}')
-
- self.vm.add_args('-smp', str(num_cpu))
- self.do_test_aarch64_aspeed_sdk_start(image_dir + 'image-bmc')
- self.wait_for_console_pattern('nodistro.0 ast2700-default ttyS12')
- self.ssh_connect('root', '0penBmc', False)
-
-class AST2x00MachineMMC(QemuSystemTest):
-
- timeout = 240
-
- def wait_for_console_pattern(self, success_message, vm=None):
- wait_for_console_pattern(self, success_message,
- failure_message='Kernel panic - not syncing',
- vm=vm)
-
- def test_arm_aspeed_emmc_boot(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:rainier-bmc
- :avocado: tags=device:emmc
- """
-
- image_url = ('https://fileserver.linaro.org/s/B6pJTwWEkzSDi36/download/'
- 'mmc-p10bmc-20240617.qcow2')
- image_hash = ('d523fb478d2b84d5adc5658d08502bc64b1486955683814f89c6137518acd90b')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- self.require_netdev('user')
-
- self.vm.set_console()
- self.vm.add_args('-drive',
- 'file=' + image_path + ',if=sd,id=sd2,index=2',
- '-net', 'nic', '-net', 'user')
- self.vm.launch()
-
- self.wait_for_console_pattern('U-Boot SPL 2019.04')
- self.wait_for_console_pattern('Trying to boot from MMC1')
- self.wait_for_console_pattern('U-Boot 2019.04')
- self.wait_for_console_pattern('eMMC 2nd Boot')
- self.wait_for_console_pattern('## Loading kernel from FIT Image')
- self.wait_for_console_pattern('Starting kernel ...')
- self.wait_for_console_pattern('Booting Linux on physical CPU 0xf00')
- self.wait_for_console_pattern('mmcblk0: p1 p2 p3 p4 p5 p6 p7')
- self.wait_for_console_pattern('IBM eBMC (OpenBMC for IBM Enterprise')
diff --git a/tests/avocado/machine_mips_malta.py b/tests/avocado/machine_mips_malta.py
deleted file mode 100644
index 07a8063..0000000
--- a/tests/avocado/machine_mips_malta.py
+++ /dev/null
@@ -1,162 +0,0 @@
-# Functional tests for the MIPS Malta board
-#
-# Copyright (c) Philippe Mathieu-Daudé <f4bug@amsat.org>
-#
-# 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
-
-import os
-import gzip
-import logging
-
-from avocado import skipUnless
-from avocado import skipUnless
-from avocado.utils import archive
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import exec_command_and_wait_for_pattern
-from avocado_qemu import interrupt_interactive_console_until_pattern
-from avocado_qemu import wait_for_console_pattern
-
-
-NUMPY_AVAILABLE = True
-try:
- import numpy as np
-except ImportError:
- NUMPY_AVAILABLE = False
-
-CV2_AVAILABLE = True
-try:
- import cv2
-except ImportError:
- CV2_AVAILABLE = False
-
-
-@skipUnless(NUMPY_AVAILABLE, 'Python NumPy not installed')
-@skipUnless(CV2_AVAILABLE, 'Python OpenCV not installed')
-class MaltaMachineFramebuffer(QemuSystemTest):
-
- timeout = 30
-
- KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
-
- def do_test_i6400_framebuffer_logo(self, cpu_cores_count):
- """
- Boot Linux kernel and check Tux logo is displayed on the framebuffer.
- """
- screendump_path = os.path.join(self.workdir, 'screendump.pbm')
-
- kernel_url = ('https://github.com/philmd/qemu-testing-blob/raw/'
- 'a5966ca4b5/mips/malta/mips64el/'
- 'vmlinux-4.7.0-rc1.I6400.gz')
- kernel_hash = '096f50c377ec5072e6a366943324622c312045f6'
- kernel_path_gz = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- kernel_path = self.workdir + "vmlinux"
- archive.gzip_uncompress(kernel_path_gz, kernel_path)
-
- tuxlogo_url = ('https://github.com/torvalds/linux/raw/v2.6.12/'
- 'drivers/video/logo/logo_linux_vga16.ppm')
- tuxlogo_hash = '3991c2ddbd1ddaecda7601f8aafbcf5b02dc86af'
- tuxlogo_path = self.fetch_asset(tuxlogo_url, asset_hash=tuxlogo_hash)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'clocksource=GIC console=tty0 console=ttyS0')
- self.vm.add_args('-kernel', kernel_path,
- '-smp', '%u' % cpu_cores_count,
- '-vga', 'std',
- '-append', kernel_command_line)
- self.vm.launch()
- framebuffer_ready = 'Console: switching to colour frame buffer device'
- wait_for_console_pattern(self, framebuffer_ready,
- failure_message='Kernel panic - not syncing')
- self.vm.cmd('human-monitor-command', command_line='stop')
- self.vm.cmd('human-monitor-command',
- command_line='screendump %s' % screendump_path)
- logger = logging.getLogger('framebuffer')
-
- match_threshold = 0.95
- screendump_bgr = cv2.imread(screendump_path, cv2.IMREAD_COLOR)
- tuxlogo_bgr = cv2.imread(tuxlogo_path, cv2.IMREAD_COLOR)
- result = cv2.matchTemplate(screendump_bgr, tuxlogo_bgr,
- cv2.TM_CCOEFF_NORMED)
- loc = np.where(result >= match_threshold)
- tuxlogo_count = 0
- h, w = tuxlogo_bgr.shape[:2]
- debug_png = os.getenv('AVOCADO_CV2_SCREENDUMP_PNG_PATH')
- for tuxlogo_count, pt in enumerate(zip(*loc[::-1]), start=1):
- logger.debug('found Tux at position (x, y) = %s', pt)
- cv2.rectangle(screendump_bgr, pt,
- (pt[0] + w, pt[1] + h), (0, 0, 255), 2)
- if debug_png:
- cv2.imwrite(debug_png, screendump_bgr)
- self.assertGreaterEqual(tuxlogo_count, cpu_cores_count)
-
- def test_mips_malta_i6400_framebuffer_logo_1core(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- :avocado: tags=cpu:I6400
- """
- self.do_test_i6400_framebuffer_logo(1)
-
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
- def test_mips_malta_i6400_framebuffer_logo_7cores(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- :avocado: tags=cpu:I6400
- :avocado: tags=mips:smp
- :avocado: tags=flaky
- """
- self.do_test_i6400_framebuffer_logo(7)
-
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
- def test_mips_malta_i6400_framebuffer_logo_8cores(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- :avocado: tags=cpu:I6400
- :avocado: tags=mips:smp
- :avocado: tags=flaky
- """
- self.do_test_i6400_framebuffer_logo(8)
-
-class MaltaMachine(QemuSystemTest):
-
- def do_test_yamon(self):
- rom_url = ('https://s3-eu-west-1.amazonaws.com/'
- 'downloads-mips/mips-downloads/'
- 'YAMON/yamon-bin-02.22.zip')
- rom_hash = '8da7ecddbc5312704b8b324341ee238189bde480'
- zip_path = self.fetch_asset(rom_url, asset_hash=rom_hash)
-
- archive.extract(zip_path, self.workdir)
- yamon_path = os.path.join(self.workdir, 'yamon-02.22.bin')
-
- self.vm.set_console()
- self.vm.add_args('-bios', yamon_path)
- self.vm.launch()
-
- prompt = 'YAMON>'
- pattern = 'YAMON ROM Monitor'
- interrupt_interactive_console_until_pattern(self, pattern, prompt)
- wait_for_console_pattern(self, prompt)
- self.vm.shutdown()
-
- def test_mipsel_malta_yamon(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- """
- self.do_test_yamon()
-
- def test_mips64el_malta_yamon(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- """
- self.do_test_yamon()
diff --git a/tests/avocado/migration.py b/tests/avocado/migration.py
deleted file mode 100644
index be6234b..0000000
--- a/tests/avocado/migration.py
+++ /dev/null
@@ -1,135 +0,0 @@
-# Migration test
-#
-# Copyright (c) 2019 Red Hat, Inc.
-#
-# Authors:
-# Cleber Rosa <crosa@redhat.com>
-# Caio Carrara <ccarrara@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-
-import tempfile
-import os
-
-from avocado_qemu import QemuSystemTest
-from avocado import skipUnless
-
-from avocado.utils.network import ports
-from avocado.utils import wait
-from avocado.utils.path import find_command
-
-
-class MigrationTest(QemuSystemTest):
- """
- :avocado: tags=migration
- """
-
- timeout = 10
-
- @staticmethod
- def migration_finished(vm):
- return vm.cmd('query-migrate')['status'] in ('completed', 'failed')
-
- def assert_migration(self, src_vm, dst_vm):
- wait.wait_for(self.migration_finished,
- timeout=self.timeout,
- step=0.1,
- args=(src_vm,))
- wait.wait_for(self.migration_finished,
- timeout=self.timeout,
- step=0.1,
- args=(dst_vm,))
- self.assertEqual(src_vm.cmd('query-migrate')['status'], 'completed')
- self.assertEqual(dst_vm.cmd('query-migrate')['status'], 'completed')
- self.assertEqual(dst_vm.cmd('query-status')['status'], 'running')
- self.assertEqual(src_vm.cmd('query-status')['status'],'postmigrate')
-
- def do_migrate(self, dest_uri, src_uri=None):
- dest_vm = self.get_vm('-incoming', dest_uri)
- dest_vm.add_args('-nodefaults')
- dest_vm.launch()
- if src_uri is None:
- src_uri = dest_uri
- source_vm = self.get_vm()
- source_vm.add_args('-nodefaults')
- source_vm.launch()
- source_vm.qmp('migrate', uri=src_uri)
- self.assert_migration(source_vm, dest_vm)
-
- def _get_free_port(self):
- port = ports.find_free_port()
- if port is None:
- self.cancel('Failed to find a free port')
- return port
-
- def migration_with_tcp_localhost(self):
- dest_uri = 'tcp:localhost:%u' % self._get_free_port()
- self.do_migrate(dest_uri)
-
- def migration_with_unix(self):
- with tempfile.TemporaryDirectory(prefix='socket_') as socket_path:
- dest_uri = 'unix:%s/qemu-test.sock' % socket_path
- self.do_migrate(dest_uri)
-
- @skipUnless(find_command('nc', default=False), "'nc' command not found")
- def migration_with_exec(self):
- """The test works for both netcat-traditional and netcat-openbsd packages."""
- free_port = self._get_free_port()
- dest_uri = 'exec:nc -l localhost %u' % free_port
- src_uri = 'exec:nc localhost %u' % free_port
- self.do_migrate(dest_uri, src_uri)
-
-
-@skipUnless('aarch64' in os.uname()[4], "host != target")
-class Aarch64(MigrationTest):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:virt
- :avocado: tags=cpu:max
- """
-
- def test_migration_with_tcp_localhost(self):
- self.migration_with_tcp_localhost()
-
- def test_migration_with_unix(self):
- self.migration_with_unix()
-
- def test_migration_with_exec(self):
- self.migration_with_exec()
-
-
-@skipUnless('x86_64' in os.uname()[4], "host != target")
-class X86_64(MigrationTest):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:pc
- :avocado: tags=cpu:qemu64
- """
-
- def test_migration_with_tcp_localhost(self):
- self.migration_with_tcp_localhost()
-
- def test_migration_with_unix(self):
- self.migration_with_unix()
-
- def test_migration_with_exec(self):
- self.migration_with_exec()
-
-
-@skipUnless('ppc64le' in os.uname()[4], "host != target")
-class PPC64(MigrationTest):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- """
-
- def test_migration_with_tcp_localhost(self):
- self.migration_with_tcp_localhost()
-
- def test_migration_with_unix(self):
- self.migration_with_unix()
-
- def test_migration_with_exec(self):
- self.migration_with_exec()
diff --git a/tests/avocado/multiprocess.py b/tests/avocado/multiprocess.py
deleted file mode 100644
index ee7490a..0000000
--- a/tests/avocado/multiprocess.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# Test for multiprocess qemu
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-
-import os
-import socket
-
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-from avocado_qemu import exec_command
-from avocado_qemu import exec_command_and_wait_for_pattern
-
-class Multiprocess(QemuSystemTest):
- """
- :avocado: tags=multiprocess
- """
- KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
-
- def do_test(self, kernel_url, kernel_hash, initrd_url, initrd_hash,
- kernel_command_line, machine_type):
- """Main test method"""
- self.require_accelerator('kvm')
- self.require_multiprocess()
-
- # Create socketpair to connect proxy and remote processes
- proxy_sock, remote_sock = socket.socketpair(socket.AF_UNIX,
- socket.SOCK_STREAM)
- os.set_inheritable(proxy_sock.fileno(), True)
- os.set_inheritable(remote_sock.fileno(), True)
-
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
-
- # Create remote process
- remote_vm = self.get_vm()
- remote_vm.add_args('-machine', 'x-remote')
- remote_vm.add_args('-nodefaults')
- remote_vm.add_args('-device', 'lsi53c895a,id=lsi1')
- remote_vm.add_args('-object', 'x-remote-object,id=robj1,'
- 'devid=lsi1,fd='+str(remote_sock.fileno()))
- remote_vm.launch()
-
- # Create proxy process
- self.vm.set_console()
- self.vm.add_args('-machine', machine_type)
- self.vm.add_args('-accel', 'kvm')
- self.vm.add_args('-cpu', 'host')
- self.vm.add_args('-object',
- 'memory-backend-memfd,id=sysmem-file,size=2G')
- self.vm.add_args('--numa', 'node,memdev=sysmem-file')
- self.vm.add_args('-m', '2048')
- self.vm.add_args('-kernel', kernel_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line)
- self.vm.add_args('-device',
- 'x-pci-proxy-dev,'
- 'id=lsi1,fd='+str(proxy_sock.fileno()))
- self.vm.launch()
- wait_for_console_pattern(self, 'as init process',
- 'Kernel panic - not syncing')
- exec_command(self, 'mount -t sysfs sysfs /sys')
- exec_command_and_wait_for_pattern(self,
- 'cat /sys/bus/pci/devices/*/uevent',
- 'PCI_ID=1000:0012')
-
- def test_multiprocess_x86_64(self):
- """
- :avocado: tags=arch:x86_64
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/31/Everything/x86_64/os/images'
- '/pxeboot/vmlinuz')
- kernel_hash = '5b6f6876e1b5bda314f93893271da0d5777b1f3c'
- initrd_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/31/Everything/x86_64/os/images'
- '/pxeboot/initrd.img')
- initrd_hash = 'dd0340a1b39bd28f88532babd4581c67649ec5b1'
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0 rdinit=/bin/bash')
- machine_type = 'pc'
- self.do_test(kernel_url, kernel_hash, initrd_url, initrd_hash,
- kernel_command_line, machine_type)
-
- def test_multiprocess_aarch64(self):
- """
- :avocado: tags=arch:aarch64
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/31/Everything/aarch64/os/images'
- '/pxeboot/vmlinuz')
- kernel_hash = '3505f2751e2833c681de78cee8dda1e49cabd2e8'
- initrd_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/31/Everything/aarch64/os/images'
- '/pxeboot/initrd.img')
- initrd_hash = '519a1962daf17d67fc3a9c89d45affcb399607db'
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'rdinit=/bin/bash console=ttyAMA0')
- machine_type = 'virt,gic-version=3'
- self.do_test(kernel_url, kernel_hash, initrd_url, initrd_hash,
- kernel_command_line, machine_type)
diff --git a/tests/avocado/replay_kernel.py b/tests/avocado/replay_kernel.py
deleted file mode 100644
index e22c200..0000000
--- a/tests/avocado/replay_kernel.py
+++ /dev/null
@@ -1,577 +0,0 @@
-# Record/replay test that boots a Linux kernel
-#
-# Copyright (c) 2020 ISP RAS
-#
-# Author:
-# Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import os
-import lzma
-import shutil
-import logging
-import time
-import subprocess
-
-from avocado import skip
-from avocado import skipUnless
-from avocado import skipUnless
-from avocado_qemu import wait_for_console_pattern
-from avocado.utils import archive
-from avocado.utils import process
-from boot_linux_console import LinuxKernelTest
-
-class ReplayKernelBase(LinuxKernelTest):
- """
- Boots a Linux kernel in record mode and checks that the console
- is operational and the kernel command line is properly passed
- from QEMU to the kernel.
- Then replays the same scenario and verifies, that QEMU correctly
- terminates.
- """
-
- timeout = 180
- KERNEL_COMMON_COMMAND_LINE = 'printk.time=1 panic=-1 '
-
- def run_vm(self, kernel_path, kernel_command_line, console_pattern,
- record, shift, args, replay_path):
- # icount requires TCG to be available
- self.require_accelerator('tcg')
-
- logger = logging.getLogger('replay')
- start_time = time.time()
- vm = self.get_vm()
- vm.set_console()
- if record:
- logger.info('recording the execution...')
- mode = 'record'
- else:
- logger.info('replaying the execution...')
- mode = 'replay'
- vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' %
- (shift, mode, replay_path),
- '-kernel', kernel_path,
- '-append', kernel_command_line,
- '-net', 'none',
- '-no-reboot')
- if args:
- vm.add_args(*args)
- vm.launch()
- self.wait_for_console_pattern(console_pattern, vm)
- if record:
- vm.shutdown()
- logger.info('finished the recording with log size %s bytes'
- % os.path.getsize(replay_path))
- self.run_replay_dump(replay_path)
- logger.info('successfully tested replay-dump.py')
- else:
- vm.wait()
- logger.info('successfully finished the replay')
- elapsed = time.time() - start_time
- logger.info('elapsed time %.2f sec' % elapsed)
- return elapsed
-
- def run_replay_dump(self, replay_path):
- try:
- subprocess.check_call(["./scripts/replay-dump.py",
- "-f", replay_path],
- stdout=subprocess.DEVNULL)
- except subprocess.CalledProcessError:
- self.fail('replay-dump.py failed')
-
- def run_rr(self, kernel_path, kernel_command_line, console_pattern,
- shift=7, args=None):
- replay_path = os.path.join(self.workdir, 'replay.bin')
- t1 = self.run_vm(kernel_path, kernel_command_line, console_pattern,
- True, shift, args, replay_path)
- t2 = self.run_vm(kernel_path, kernel_command_line, console_pattern,
- False, shift, args, replay_path)
- logger = logging.getLogger('replay')
- logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1))
-
-class ReplayKernelNormal(ReplayKernelBase):
-
- def test_i386_pc(self):
- """
- :avocado: tags=arch:i386
- :avocado: tags=machine:pc
- """
- kernel_url = ('https://storage.tuxboot.com/20230331/i386/bzImage')
- kernel_hash = 'a3e5b32a354729e65910f5a1ffcda7c14a6c12a55e8213fb86e277f1b76ed956'
- kernel_path = self.fetch_asset(kernel_url,
- asset_hash=kernel_hash,
- algorithm = "sha256")
-
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- console_pattern = 'VFS: Cannot open root device'
-
- self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
-
- # See https://gitlab.com/qemu-project/qemu/-/issues/2094
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'pc machine is unstable with replay')
- def test_x86_64_pc(self):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:pc
- :avocado: tags=flaky
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/29/Everything/x86_64/os/images/pxeboot'
- '/vmlinuz')
- kernel_hash = '23bebd2680757891cf7adedb033532163a792495'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- console_pattern = 'VFS: Cannot open root device'
-
- self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
-
- def test_x86_64_q35(self):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:q35
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/29/Everything/x86_64/os/images/pxeboot'
- '/vmlinuz')
- kernel_hash = '23bebd2680757891cf7adedb033532163a792495'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- console_pattern = 'VFS: Cannot open root device'
-
- self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
-
- def test_mips_malta(self):
- """
- :avocado: tags=arch:mips
- :avocado: tags=machine:malta
- :avocado: tags=endian:big
- """
- deb_url = ('http://snapshot.debian.org/archive/debian/'
- '20130217T032700Z/pool/main/l/linux-2.6/'
- 'linux-image-2.6.32-5-4kc-malta_2.6.32-48_mips.deb')
- deb_hash = 'a8cfc28ad8f45f54811fc6cf74fc43ffcfe0ba04'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-2.6.32-5-4kc-malta')
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- console_pattern = 'Kernel command line: %s' % kernel_command_line
-
- self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
-
- def test_mips64el_malta(self):
- """
- This test requires the ar tool to extract "data.tar.gz" from
- the Debian package.
-
- The kernel can be rebuilt using this Debian kernel source [1] and
- following the instructions on [2].
-
- [1] http://snapshot.debian.org/package/linux-2.6/2.6.32-48/
- #linux-source-2.6.32_2.6.32-48
- [2] https://kernel-team.pages.debian.net/kernel-handbook/
- ch-common-tasks.html#s-common-official
-
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- """
- deb_url = ('http://snapshot.debian.org/archive/debian/'
- '20130217T032700Z/pool/main/l/linux-2.6/'
- 'linux-image-2.6.32-5-5kc-malta_2.6.32-48_mipsel.deb')
- deb_hash = '1aaec92083bf22fda31e0d27fa8d9a388e5fc3d5'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-2.6.32-5-5kc-malta')
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
-
- def test_aarch64_virt(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:virt
- :avocado: tags=cpu:cortex-a53
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/29/Everything/aarch64/os/images/pxeboot'
- '/vmlinuz')
- kernel_hash = '8c73e469fc6ea06a58dc83a628fc695b693b8493'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyAMA0')
- console_pattern = 'VFS: Cannot open root device'
-
- self.run_rr(kernel_path, kernel_command_line, console_pattern)
-
- def test_arm_virt(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:virt
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/29/Everything/armhfp/os/images/pxeboot'
- '/vmlinuz')
- kernel_hash = 'e9826d741b4fb04cadba8d4824d1ed3b7fb8b4d4'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyAMA0')
- console_pattern = 'VFS: Cannot open root device'
-
- self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=1)
-
- def test_arm_cubieboard_initrd(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:cubieboard
- """
- deb_url = ('https://apt.armbian.com/pool/main/l/'
- 'linux-6.6.16/linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb')
- deb_hash = 'f7c3c8c5432f765445dc6e7eab02f3bbe668256b'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = '/usr/lib/linux-image-6.6.16-current-sunxi/sun4i-a10-cubieboard.dtb'
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
- initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
- '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
- 'arm/rootfs-armv5.cpio.gz')
- initrd_hash = '2b50f1873e113523967806f4da2afe385462ff9b'
- initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0,115200 '
- 'usbcore.nousb '
- 'panic=-1 noreboot')
- console_pattern = 'Boot successful.'
- self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=1,
- args=('-dtb', dtb_path,
- '-initrd', initrd_path,
- '-no-reboot'))
-
- def test_s390x_s390_ccw_virtio(self):
- """
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive'
- '/fedora-secondary/releases/29/Everything/s390x/os/images'
- '/kernel.img')
- kernel_hash = 'e8e8439103ef8053418ef062644ffd46a7919313'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=sclp0'
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=9)
-
- def test_alpha_clipper(self):
- """
- :avocado: tags=arch:alpha
- :avocado: tags=machine:clipper
- """
- kernel_url = ('http://archive.debian.org/debian/dists/lenny/main/'
- 'installer-alpha/20090123lenny10/images/cdrom/vmlinuz')
- kernel_hash = '3a943149335529e2ed3e74d0d787b85fb5671ba3'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- uncompressed_kernel = archive.uncompress(kernel_path, self.workdir)
-
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.run_rr(uncompressed_kernel, kernel_command_line, console_pattern, shift=9,
- args=('-nodefaults', ))
-
- def test_ppc64_pseries(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- :avocado: tags=accel:tcg
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive'
- '/fedora-secondary/releases/29/Everything/ppc64le/os'
- '/ppc/ppc64/vmlinuz')
- kernel_hash = '3fe04abfc852b66653b8c3c897a59a689270bc77'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=hvc0'
- console_pattern = 'VFS: Cannot open root device'
- self.run_rr(kernel_path, kernel_command_line, console_pattern)
-
- def test_ppc64_powernv(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv
- :avocado: tags=accel:tcg
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive'
- '/fedora-secondary/releases/29/Everything/ppc64le/os'
- '/ppc/ppc64/vmlinuz')
- kernel_hash = '3fe04abfc852b66653b8c3c897a59a689270bc77'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + \
- 'console=tty0 console=hvc0'
- console_pattern = 'VFS: Cannot open root device'
- self.run_rr(kernel_path, kernel_command_line, console_pattern)
-
- def test_m68k_q800(self):
- """
- :avocado: tags=arch:m68k
- :avocado: tags=machine:q800
- """
- deb_url = ('https://snapshot.debian.org/archive/debian-ports'
- '/20191021T083923Z/pool-m68k/main'
- '/l/linux/kernel-image-5.3.0-1-m68k-di_5.3.7-1_m68k.udeb')
- deb_hash = '044954bb9be4160a3ce81f8bc1b5e856b75cccd1'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-5.3.0-1-m68k')
-
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0 vga=off')
- console_pattern = 'No filesystem could mount root'
- self.run_rr(kernel_path, kernel_command_line, console_pattern)
-
- def do_test_advcal_2018(self, file_path, kernel_name, args=None):
- archive.extract(file_path, self.workdir)
-
- for entry in os.scandir(self.workdir):
- if entry.name.startswith('day') and entry.is_dir():
- kernel_path = os.path.join(entry.path, kernel_name)
- break
-
- kernel_command_line = ''
- console_pattern = 'QEMU advent calendar'
- self.run_rr(kernel_path, kernel_command_line, console_pattern,
- args=args)
-
- def test_arm_vexpressa9(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:vexpress-a9
- """
- tar_hash = '32b7677ce8b6f1471fb0059865f451169934245b'
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day16.tar.xz')
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- dtb_path = self.workdir + '/day16/vexpress-v2p-ca9.dtb'
- self.do_test_advcal_2018(file_path, 'winter.zImage',
- args=('-dtb', dtb_path))
-
- def test_m68k_mcf5208evb(self):
- """
- :avocado: tags=arch:m68k
- :avocado: tags=machine:mcf5208evb
- """
- tar_hash = 'ac688fd00561a2b6ce1359f9ff6aa2b98c9a570c'
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day07.tar.xz')
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- self.do_test_advcal_2018(file_path, 'sanity-clause.elf')
-
- def test_microblaze_s3adsp1800(self):
- """
- :avocado: tags=arch:microblaze
- :avocado: tags=machine:petalogix-s3adsp1800
- """
- tar_hash = '08bf3e3bfb6b6c7ce1e54ab65d54e189f2caf13f'
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day17.tar.xz')
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- self.do_test_advcal_2018(file_path, 'ballerina.bin')
-
- def test_ppc64_e500(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:ppce500
- :avocado: tags=cpu:e5500
- """
- tar_hash = '6951d86d644b302898da2fd701739c9406527fe1'
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day19.tar.xz')
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- self.do_test_advcal_2018(file_path, 'uImage')
-
- def test_or1k_sim(self):
- """
- :avocado: tags=arch:or1k
- :avocado: tags=machine:or1k-sim
- """
- tar_hash = '20334cdaf386108c530ff0badaecc955693027dd'
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day20.tar.xz')
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- self.do_test_advcal_2018(file_path, 'vmlinux')
-
- def test_ppc_g3beige(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:g3beige
- """
- tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc'
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day15.tar.xz')
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- self.do_test_advcal_2018(file_path, 'invaders.elf',
- args=('-M', 'graphics=off'))
-
- def test_ppc_mac99(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:mac99
- """
- tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc'
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day15.tar.xz')
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- self.do_test_advcal_2018(file_path, 'invaders.elf',
- args=('-M', 'graphics=off'))
-
- def test_sparc_ss20(self):
- """
- :avocado: tags=arch:sparc
- :avocado: tags=machine:SS-20
- """
- tar_hash = 'b18550d5d61c7615d989a06edace051017726a9f'
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day11.tar.xz')
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- self.do_test_advcal_2018(file_path, 'zImage.elf')
-
- def test_xtensa_lx60(self):
- """
- :avocado: tags=arch:xtensa
- :avocado: tags=machine:lx60
- :avocado: tags=cpu:dc233c
- """
- tar_hash = '49e88d9933742f0164b60839886c9739cb7a0d34'
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day02.tar.xz')
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- self.do_test_advcal_2018(file_path, 'santas-sleigh-ride.elf')
-
-@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
-class ReplayKernelSlow(ReplayKernelBase):
- # Override the timeout, because this kernel includes an inner
- # loop which is executed with TB recompilings during replay,
- # making it very slow.
- timeout = 180
-
- def test_mips_malta_cpio(self):
- """
- :avocado: tags=arch:mips
- :avocado: tags=machine:malta
- :avocado: tags=endian:big
- :avocado: tags=slowness:high
- """
- deb_url = ('http://snapshot.debian.org/archive/debian/'
- '20160601T041800Z/pool/main/l/linux/'
- 'linux-image-4.5.0-2-4kc-malta_4.5.5-1_mips.deb')
- deb_hash = 'a3c84f3e88b54e06107d65a410d1d1e8e0f340f8'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-4.5.0-2-4kc-malta')
- initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
- '8584a59ed9e5eb5ee7ca91f6d74bbb06619205b8/rootfs/'
- 'mips/rootfs.cpio.gz')
- initrd_hash = 'bf806e17009360a866bf537f6de66590de349a99'
- initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- initrd_path = self.workdir + "rootfs.cpio"
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0 console=tty '
- 'rdinit=/sbin/init noreboot')
- console_pattern = 'Boot successful.'
- self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5,
- args=('-initrd', initrd_path))
-
- @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
- def test_mips64el_malta_5KEc_cpio(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- :avocado: tags=slowness:high
- :avocado: tags=cpu:5KEc
- """
- kernel_url = ('https://github.com/philmd/qemu-testing-blob/'
- 'raw/9ad2df38/mips/malta/mips64el/'
- 'vmlinux-3.19.3.mtoman.20150408')
- kernel_hash = '00d1d268fb9f7d8beda1de6bebcc46e884d71754'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- initrd_url = ('https://github.com/groeck/linux-build-test/'
- 'raw/8584a59e/rootfs/'
- 'mipsel64/rootfs.mipsel64r1.cpio.gz')
- initrd_hash = '1dbb8a396e916847325284dbe2151167'
- initrd_path_gz = self.fetch_asset(initrd_url, algorithm='md5',
- asset_hash=initrd_hash)
- initrd_path = self.workdir + "rootfs.cpio"
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0 console=tty '
- 'rdinit=/sbin/init noreboot')
- console_pattern = 'Boot successful.'
- self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5,
- args=('-initrd', initrd_path))
-
- def do_test_mips_malta32el_nanomips(self, kernel_path_xz):
- kernel_path = self.workdir + "kernel"
- with lzma.open(kernel_path_xz, 'rb') as f_in:
- with open(kernel_path, 'wb') as f_out:
- shutil.copyfileobj(f_in, f_out)
-
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'mem=256m@@0x0 '
- 'console=ttyS0')
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
-
- def test_mips_malta32el_nanomips_4k(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- :avocado: tags=cpu:I7200
- """
- kernel_url = ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
- 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
- 'generic_nano32r6el_page4k.xz')
- kernel_hash = '477456aafd2a0f1ddc9482727f20fe9575565dd6'
- kernel_path_xz = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- self.do_test_mips_malta32el_nanomips(kernel_path_xz)
-
- def test_mips_malta32el_nanomips_16k_up(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- :avocado: tags=cpu:I7200
- """
- kernel_url = ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
- 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
- 'generic_nano32r6el_page16k_up.xz')
- kernel_hash = 'e882868f944c71c816e832e2303b7874d044a7bc'
- kernel_path_xz = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- self.do_test_mips_malta32el_nanomips(kernel_path_xz)
-
- def test_mips_malta32el_nanomips_64k_dbg(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- :avocado: tags=cpu:I7200
- """
- kernel_url = ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
- 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
- 'generic_nano32r6el_page64k_dbg.xz')
- kernel_hash = '18d1c68f2e23429e266ca39ba5349ccd0aeb7180'
- kernel_path_xz = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- self.do_test_mips_malta32el_nanomips(kernel_path_xz)
diff --git a/tests/avocado/replay_linux.py b/tests/avocado/replay_linux.py
deleted file mode 100644
index 5916922..0000000
--- a/tests/avocado/replay_linux.py
+++ /dev/null
@@ -1,206 +0,0 @@
-# Record/replay test that boots a complete Linux system via a cloud image
-#
-# Copyright (c) 2020 ISP RAS
-#
-# Author:
-# Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import os
-import logging
-import time
-
-from avocado import skipUnless
-from avocado_qemu import BUILD_DIR
-from avocado.utils import cloudinit
-from avocado.utils import network
-from avocado.utils import vmimage
-from avocado.utils import datadrainer
-from avocado.utils.path import find_command
-from avocado_qemu.linuxtest import LinuxTest
-
-class ReplayLinux(LinuxTest):
- """
- Boots a Linux system, checking for a successful initialization
- """
-
- timeout = 1800
- chksum = None
- hdd = 'ide-hd'
- cd = 'ide-cd'
- bus = 'ide'
-
- def setUp(self):
- # LinuxTest does many replay-incompatible things, but includes
- # useful methods. Do not setup LinuxTest here and just
- # call some functions.
- super(LinuxTest, self).setUp()
- self._set_distro()
- self.boot_path = self.download_boot()
- self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0),
- self.name)
- ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys()
- self.cloudinit_path = self.prepare_cloudinit(ssh_pubkey)
-
- def vm_add_disk(self, vm, path, id, device):
- bus_string = ''
- if self.bus:
- bus_string = ',bus=%s.%d' % (self.bus, id,)
- vm.add_args('-drive', 'file=%s,snapshot=on,id=disk%s,if=none' % (path, id))
- vm.add_args('-drive',
- 'driver=blkreplay,id=disk%s-rr,if=none,image=disk%s' % (id, id))
- vm.add_args('-device',
- '%s,drive=disk%s-rr%s' % (device, id, bus_string))
-
- def vm_add_cdrom(self, vm, path, id, device):
- vm.add_args('-drive', 'file=%s,id=disk%s,if=none,media=cdrom' % (path, id))
-
- def launch_and_wait(self, record, args, shift):
- self.require_netdev('user')
- vm = self.get_vm()
- vm.add_args('-smp', '1')
- vm.add_args('-m', '1024')
- vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
- '-device', 'virtio-net,netdev=vnet')
- vm.add_args('-object', 'filter-replay,id=replay,netdev=vnet')
- if args:
- vm.add_args(*args)
- self.vm_add_disk(vm, self.boot_path, 0, self.hdd)
- self.vm_add_cdrom(vm, self.cloudinit_path, 1, self.cd)
- logger = logging.getLogger('replay')
- if record:
- logger.info('recording the execution...')
- mode = 'record'
- else:
- logger.info('replaying the execution...')
- mode = 'replay'
- replay_path = os.path.join(self.workdir, 'replay.bin')
- vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' %
- (shift, mode, replay_path))
-
- start_time = time.time()
-
- vm.set_console()
- vm.launch()
- console_drainer = datadrainer.LineLogger(vm.console_socket.fileno(),
- logger=self.log.getChild('console'),
- stop_check=(lambda : not vm.is_running()))
- console_drainer.start()
- if record:
- while not self.phone_server.instance_phoned_back:
- self.phone_server.handle_request()
- vm.shutdown()
- logger.info('finished the recording with log size %s bytes'
- % os.path.getsize(replay_path))
- self.run_replay_dump(replay_path)
- logger.info('successfully tested replay-dump.py')
- else:
- vm.event_wait('SHUTDOWN', self.timeout)
- vm.wait()
- logger.info('successfully finished the replay')
- elapsed = time.time() - start_time
- logger.info('elapsed time %.2f sec' % elapsed)
- return elapsed
-
- def run_rr(self, args=None, shift=7):
- t1 = self.launch_and_wait(True, args, shift)
- t2 = self.launch_and_wait(False, args, shift)
- logger = logging.getLogger('replay')
- logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1))
-
- def run_replay_dump(self, replay_path):
- try:
- subprocess.check_call(["./scripts/replay-dump.py",
- "-f", replay_path],
- stdout=subprocess.DEVNULL)
- except subprocess.CalledProcessError:
- self.fail('replay-dump.py failed')
-
-@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
-class ReplayLinuxX8664(ReplayLinux):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=accel:tcg
- """
-
- chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0'
-
- def test_pc_i440fx(self):
- """
- :avocado: tags=machine:pc
- """
- self.run_rr(shift=1)
-
- def test_pc_q35(self):
- """
- :avocado: tags=machine:q35
- """
- self.run_rr(shift=3)
-
-@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
-class ReplayLinuxX8664Virtio(ReplayLinux):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=virtio
- :avocado: tags=accel:tcg
- """
-
- hdd = 'virtio-blk-pci'
- cd = 'virtio-blk-pci'
- bus = None
-
- chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0'
-
- def test_pc_i440fx(self):
- """
- :avocado: tags=machine:pc
- """
- self.run_rr(shift=1)
-
- def test_pc_q35(self):
- """
- :avocado: tags=machine:q35
- """
- self.run_rr(shift=3)
-
-@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
-class ReplayLinuxAarch64(ReplayLinux):
- """
- :avocado: tags=accel:tcg
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:virt
- :avocado: tags=cpu:max
- """
-
- chksum = '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49'
-
- hdd = 'virtio-blk-device'
- cd = 'virtio-blk-device'
- bus = None
-
- def get_common_args(self):
- return ('-bios',
- os.path.join(BUILD_DIR, 'pc-bios', 'edk2-aarch64-code.fd'),
- "-cpu", "max,lpa2=off",
- '-device', 'virtio-rng-pci,rng=rng0',
- '-object', 'rng-builtin,id=rng0')
-
- def test_virt_gicv2(self):
- """
- :avocado: tags=machine:gic-version=2
- """
-
- self.run_rr(shift=3,
- args=(*self.get_common_args(),
- "-machine", "virt,gic-version=2"))
-
- def test_virt_gicv3(self):
- """
- :avocado: tags=machine:gic-version=3
- """
-
- self.run_rr(shift=3,
- args=(*self.get_common_args(),
- "-machine", "virt,gic-version=3"))
diff --git a/tests/avocado/riscv_opensbi.py b/tests/avocado/riscv_opensbi.py
deleted file mode 100644
index bfff9cc..0000000
--- a/tests/avocado/riscv_opensbi.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# OpenSBI boot test for RISC-V machines
-#
-# Copyright (c) 2022, Ventana Micro
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-
-class RiscvOpenSBI(QemuSystemTest):
- """
- :avocado: tags=accel:tcg
- """
- timeout = 5
-
- def boot_opensbi(self):
- self.vm.set_console()
- self.vm.launch()
- wait_for_console_pattern(self, 'Platform Name')
- wait_for_console_pattern(self, 'Boot HART MEDELEG')
-
- def test_riscv32_spike(self):
- """
- :avocado: tags=arch:riscv32
- :avocado: tags=machine:spike
- """
- self.boot_opensbi()
-
- def test_riscv64_spike(self):
- """
- :avocado: tags=arch:riscv64
- :avocado: tags=machine:spike
- """
- self.boot_opensbi()
-
- def test_riscv32_sifive_u(self):
- """
- :avocado: tags=arch:riscv32
- :avocado: tags=machine:sifive_u
- """
- self.boot_opensbi()
-
- def test_riscv64_sifive_u(self):
- """
- :avocado: tags=arch:riscv64
- :avocado: tags=machine:sifive_u
- """
- self.boot_opensbi()
-
- def test_riscv32_virt(self):
- """
- :avocado: tags=arch:riscv32
- :avocado: tags=machine:virt
- """
- self.boot_opensbi()
-
- def test_riscv64_virt(self):
- """
- :avocado: tags=arch:riscv64
- :avocado: tags=machine:virt
- """
- self.boot_opensbi()
diff --git a/tests/avocado/smmu.py b/tests/avocado/smmu.py
deleted file mode 100644
index 83fd79e..0000000
--- a/tests/avocado/smmu.py
+++ /dev/null
@@ -1,139 +0,0 @@
-# SMMUv3 Functional tests
-#
-# Copyright (c) 2021 Red Hat, Inc.
-#
-# Author:
-# Eric Auger <eric.auger@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-import os
-
-from avocado import skipUnless
-from avocado_qemu import BUILD_DIR
-from avocado_qemu.linuxtest import LinuxTest
-
-@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-class SMMU(LinuxTest):
- """
- :avocado: tags=accel:kvm
- :avocado: tags=cpu:host
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:virt
- :avocado: tags=distro:fedora
- :avocado: tags=smmu
- :avocado: tags=flaky
- """
-
- IOMMU_ADDON = ',iommu_platform=on,disable-modern=off,disable-legacy=on'
- kernel_path = None
- initrd_path = None
- kernel_params = None
-
- def set_up_boot(self):
- path = self.download_boot()
- self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,' +
- 'drive=drv0,id=virtio-disk0,bootindex=1,'
- 'werror=stop,rerror=stop' + self.IOMMU_ADDON)
- self.vm.add_args('-drive',
- 'file=%s,if=none,cache=writethrough,id=drv0' % path)
-
- def setUp(self):
- super(SMMU, self).setUp(None, 'virtio-net-pci' + self.IOMMU_ADDON)
-
- def common_vm_setup(self, custom_kernel=False):
- self.require_accelerator("kvm")
- self.vm.add_args("-accel", "kvm")
- self.vm.add_args("-cpu", "host")
- self.vm.add_args("-machine", "iommu=smmuv3")
- self.vm.add_args("-d", "guest_errors")
- self.vm.add_args('-bios', os.path.join(BUILD_DIR, 'pc-bios',
- 'edk2-aarch64-code.fd'))
- self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
- self.vm.add_args('-object',
- 'rng-random,id=rng0,filename=/dev/urandom')
-
- if custom_kernel is False:
- return
-
- kernel_url = self.distro.pxeboot_url + 'vmlinuz'
- initrd_url = self.distro.pxeboot_url + 'initrd.img'
- self.kernel_path = self.fetch_asset(kernel_url)
- self.initrd_path = self.fetch_asset(initrd_url)
-
- def run_and_check(self):
- if self.kernel_path:
- self.vm.add_args('-kernel', self.kernel_path,
- '-append', self.kernel_params,
- '-initrd', self.initrd_path)
- self.launch_and_wait()
- self.ssh_command('cat /proc/cmdline')
- self.ssh_command('dnf -y install numactl-devel')
-
-
- # 5.3 kernel without RIL #
-
- def test_smmu_noril(self):
- """
- :avocado: tags=smmu_noril
- :avocado: tags=smmu_noril_tests
- :avocado: tags=distro_version:31
- """
- self.common_vm_setup()
- self.run_and_check()
-
- def test_smmu_noril_passthrough(self):
- """
- :avocado: tags=smmu_noril_passthrough
- :avocado: tags=smmu_noril_tests
- :avocado: tags=distro_version:31
- """
- self.common_vm_setup(True)
- self.kernel_params = (self.distro.default_kernel_params +
- ' iommu.passthrough=on')
- self.run_and_check()
-
- def test_smmu_noril_nostrict(self):
- """
- :avocado: tags=smmu_noril_nostrict
- :avocado: tags=smmu_noril_tests
- :avocado: tags=distro_version:31
- """
- self.common_vm_setup(True)
- self.kernel_params = (self.distro.default_kernel_params +
- ' iommu.strict=0')
- self.run_and_check()
-
- # 5.8 kernel featuring range invalidation
- # >= v5.7 kernel
-
- def test_smmu_ril(self):
- """
- :avocado: tags=smmu_ril
- :avocado: tags=smmu_ril_tests
- :avocado: tags=distro_version:33
- """
- self.common_vm_setup()
- self.run_and_check()
-
- def test_smmu_ril_passthrough(self):
- """
- :avocado: tags=smmu_ril_passthrough
- :avocado: tags=smmu_ril_tests
- :avocado: tags=distro_version:33
- """
- self.common_vm_setup(True)
- self.kernel_params = (self.distro.default_kernel_params +
- ' iommu.passthrough=on')
- self.run_and_check()
-
- def test_smmu_ril_nostrict(self):
- """
- :avocado: tags=smmu_ril_nostrict
- :avocado: tags=smmu_ril_tests
- :avocado: tags=distro_version:33
- """
- self.common_vm_setup(True)
- self.kernel_params = (self.distro.default_kernel_params +
- ' iommu.strict=0')
- self.run_and_check()
diff --git a/tests/avocado/tuxrun_baselines.py b/tests/avocado/tuxrun_baselines.py
deleted file mode 100644
index 736e4aa..0000000
--- a/tests/avocado/tuxrun_baselines.py
+++ /dev/null
@@ -1,620 +0,0 @@
-# Functional test that boots known good tuxboot images the same way
-# that tuxrun (www.tuxrun.org) does. This tool is used by things like
-# the LKFT project to run regression tests on kernels.
-#
-# Copyright (c) 2023 Linaro Ltd.
-#
-# Author:
-# Alex Bennée <alex.bennee@linaro.org>
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-import os
-import time
-import tempfile
-
-from avocado import skip, skipUnless
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import exec_command, exec_command_and_wait_for_pattern
-from avocado_qemu import wait_for_console_pattern
-from avocado.utils import process
-from avocado.utils.path import find_command
-
-class TuxRunBaselineTest(QemuSystemTest):
- """
- :avocado: tags=accel:tcg
- """
-
- KERNEL_COMMON_COMMAND_LINE = 'printk.time=0'
- # Tests are ~10-40s, allow for --debug/--enable-gcov overhead
- timeout = 100
-
- def get_tag(self, tagname, default=None):
- """
- Get the metadata tag or return the default.
- """
- utag = self._get_unique_tag_val(tagname)
- print(f"{tagname}/{default} -> {utag}")
- if utag:
- return utag
-
- return default
-
- def setUp(self):
- super().setUp()
-
- # We need zstd for all the tuxrun tests
- # See https://github.com/avocado-framework/avocado/issues/5609
- zstd = find_command('zstd', False)
- if zstd is False:
- self.cancel('Could not find "zstd", which is required to '
- 'decompress rootfs')
- self.zstd = zstd
-
- # Process the TuxRun specific tags, most machines work with
- # reasonable defaults but we sometimes need to tweak the
- # config. To avoid open coding everything we store all these
- # details in the metadata for each test.
-
- # The tuxboot tag matches the root directory
- self.tuxboot = self.get_tag('tuxboot')
-
- # Most Linux's use ttyS0 for their serial port
- self.console = self.get_tag('console', "ttyS0")
-
- # Does the machine shutdown QEMU nicely on "halt"
- self.shutdown = self.get_tag('shutdown')
-
- # The name of the kernel Image file
- self.image = self.get_tag('image', "Image")
-
- self.root = self.get_tag('root', "vda")
-
- # Occasionally we need extra devices to hook things up
- self.extradev = self.get_tag('extradev')
-
- self.qemu_img = super().get_qemu_img()
-
- def wait_for_console_pattern(self, success_message, vm=None):
- wait_for_console_pattern(self, success_message,
- failure_message='Kernel panic - not syncing',
- vm=vm)
-
- def fetch_tuxrun_assets(self, csums=None, dt=None):
- """
- Fetch the TuxBoot assets. They are stored in a standard way so we
- use the per-test tags to fetch details.
- """
- base_url = f"https://storage.tuxboot.com/20230331/{self.tuxboot}/"
-
- # empty hash if we weren't passed one
- csums = {} if csums is None else csums
- ksum = csums.get(self.image, None)
- isum = csums.get("rootfs.ext4.zst", None)
-
- kernel_image = self.fetch_asset(base_url + self.image,
- asset_hash = ksum,
- algorithm = "sha256")
- disk_image_zst = self.fetch_asset(base_url + "rootfs.ext4.zst",
- asset_hash = isum,
- algorithm = "sha256")
-
- cmd = f"{self.zstd} -d {disk_image_zst} -o {self.workdir}/rootfs.ext4"
- process.run(cmd)
-
- if dt:
- dsum = csums.get(dt, None)
- dtb = self.fetch_asset(base_url + dt,
- asset_hash = dsum,
- algorithm = "sha256")
- else:
- dtb = None
-
- return (kernel_image, self.workdir + "/rootfs.ext4", dtb)
-
- def prepare_run(self, kernel, disk, drive, dtb=None, console_index=0):
- """
- Setup to run and add the common parameters to the system
- """
- self.vm.set_console(console_index=console_index)
-
- # all block devices are raw ext4's
- blockdev = "driver=raw,file.driver=file," \
- + f"file.filename={disk},node-name=hd0"
-
- kcmd_line = self.KERNEL_COMMON_COMMAND_LINE
- kcmd_line += f" root=/dev/{self.root}"
- kcmd_line += f" console={self.console}"
-
- self.vm.add_args('-kernel', kernel,
- '-append', kcmd_line,
- '-blockdev', blockdev)
-
- # Sometimes we need extra devices attached
- if self.extradev:
- self.vm.add_args('-device', self.extradev)
-
- self.vm.add_args('-device',
- f"{drive},drive=hd0")
-
- # Some machines need an explicit DTB
- if dtb:
- self.vm.add_args('-dtb', dtb)
-
- def run_tuxtest_tests(self, haltmsg):
- """
- Wait for the system to boot up, wait for the login prompt and
- then do a few things on the console. Trigger a shutdown and
- wait to exit cleanly.
- """
- self.wait_for_console_pattern("Welcome to TuxTest")
- time.sleep(0.2)
- exec_command(self, 'root')
- time.sleep(0.2)
- exec_command(self, 'cat /proc/interrupts')
- time.sleep(0.1)
- exec_command(self, 'cat /proc/self/maps')
- time.sleep(0.1)
- exec_command(self, 'uname -a')
- time.sleep(0.1)
- exec_command_and_wait_for_pattern(self, 'halt', haltmsg)
-
- # Wait for VM to shut down gracefully if it can
- if self.shutdown == "nowait":
- self.vm.shutdown()
- else:
- self.vm.wait()
-
- def common_tuxrun(self,
- csums=None,
- dt=None,
- drive="virtio-blk-device",
- haltmsg="reboot: System halted",
- console_index=0):
- """
- Common path for LKFT tests. Unless we need to do something
- special with the command line we can process most things using
- the tag metadata.
- """
- (kernel, disk, dtb) = self.fetch_tuxrun_assets(csums, dt)
-
- self.prepare_run(kernel, disk, drive, dtb, console_index)
- self.vm.launch()
- self.run_tuxtest_tests(haltmsg)
-
- def ppc64_common_tuxrun(self, sums, prefix):
- # add device args to command line.
- self.require_netdev('user')
- self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
- '-device', 'virtio-net,netdev=vnet')
- self.vm.add_args('-netdev', '{"type":"user","id":"hostnet0"}',
- '-device', '{"driver":"virtio-net-pci","netdev":'
- '"hostnet0","id":"net0","mac":"52:54:00:4c:e3:86",'
- '"bus":"pci.0","addr":"0x9"}')
- self.vm.add_args('-device', '{"driver":"qemu-xhci","p2":15,"p3":15,'
- '"id":"usb","bus":"pci.0","addr":"0x2"}')
- self.vm.add_args('-device', '{"driver":"virtio-scsi-pci","id":"scsi0"'
- ',"bus":"pci.0","addr":"0x3"}')
- self.vm.add_args('-device', '{"driver":"virtio-serial-pci","id":'
- '"virtio-serial0","bus":"pci.0","addr":"0x4"}')
- self.vm.add_args('-device', '{"driver":"scsi-cd","bus":"scsi0.0"'
- ',"channel":0,"scsi-id":0,"lun":0,"device_id":'
- '"drive-scsi0-0-0-0","id":"scsi0-0-0-0"}')
- self.vm.add_args('-device', '{"driver":"virtio-balloon-pci",'
- '"id":"balloon0","bus":"pci.0","addr":"0x6"}')
- self.vm.add_args('-audiodev', '{"id":"audio1","driver":"none"}')
- self.vm.add_args('-device', '{"driver":"usb-tablet","id":"input0"'
- ',"bus":"usb.0","port":"1"}')
- self.vm.add_args('-device', '{"driver":"usb-kbd","id":"input1"'
- ',"bus":"usb.0","port":"2"}')
- self.vm.add_args('-device', '{"driver":"VGA","id":"video0",'
- '"vgamem_mb":16,"bus":"pci.0","addr":"0x7"}')
- self.vm.add_args('-object', '{"qom-type":"rng-random","id":"objrng0"'
- ',"filename":"/dev/urandom"}',
- '-device', '{"driver":"virtio-rng-pci","rng":"objrng0"'
- ',"id":"rng0","bus":"pci.0","addr":"0x8"}')
- self.vm.add_args('-object', '{"qom-type":"cryptodev-backend-builtin",'
- '"id":"objcrypto0","queues":1}',
- '-device', '{"driver":"virtio-crypto-pci",'
- '"cryptodev":"objcrypto0","id":"crypto0","bus"'
- ':"pci.0","addr":"0xa"}')
- self.vm.add_args('-device', '{"driver":"spapr-pci-host-bridge"'
- ',"index":1,"id":"pci.1"}')
- self.vm.add_args('-device', '{"driver":"spapr-vscsi","id":"scsi1"'
- ',"reg":12288}')
- self.vm.add_args('-m', '2G,slots=32,maxmem=4G',
- '-object', 'memory-backend-ram,id=ram1,size=1G',
- '-device', 'pc-dimm,id=dimm1,memdev=ram1')
-
- # Create a temporary qcow2 and launch the test-case
- with tempfile.NamedTemporaryFile(prefix=prefix,
- suffix='.qcow2') as qcow2:
- process.run(self.qemu_img + ' create -f qcow2 ' +
- qcow2.name + ' 1G')
-
- self.vm.add_args('-drive', 'file=' + qcow2.name +
- ',format=qcow2,if=none,id='
- 'drive-virtio-disk1',
- '-device', 'virtio-blk-pci,bus=pci.0,'
- 'addr=0xb,drive=drive-virtio-disk1,id=virtio-disk1'
- ',bootindex=2')
- self.common_tuxrun(csums=sums, drive="scsi-hd")
-
- #
- # The tests themselves. The configuration is derived from how
- # tuxrun invokes qemu (with minor tweaks like using -blockdev
- # consistently). The tuxrun equivalent is something like:
- #
- # tuxrun --device qemu-{ARCH} \
- # --kernel https://storage.tuxboot.com/{TUXBOOT}/{IMAGE}
- #
-
- def test_arm64(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=cpu:cortex-a57
- :avocado: tags=machine:virt
- :avocado: tags=tuxboot:arm64
- :avocado: tags=console:ttyAMA0
- :avocado: tags=shutdown:nowait
- """
- sums = {"Image" :
- "ce95a7101a5fecebe0fe630deee6bd97b32ba41bc8754090e9ad8961ea8674c7",
- "rootfs.ext4.zst" :
- "bbd5ed4b9c7d3f4ca19ba71a323a843c6b585e880115df3b7765769dbd9dd061"}
- self.common_tuxrun(csums=sums)
-
- def test_arm64be(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=cpu:cortex-a57
- :avocado: tags=endian:big
- :avocado: tags=machine:virt
- :avocado: tags=tuxboot:arm64be
- :avocado: tags=console:ttyAMA0
- :avocado: tags=shutdown:nowait
- """
- sums = { "Image" :
- "e0df4425eb2cd9ea9a283e808037f805641c65d8fcecc8f6407d8f4f339561b4",
- "rootfs.ext4.zst" :
- "e6ffd8813c8a335bc15728f2835f90539c84be7f8f5f691a8b01451b47fb4bd7"}
- self.common_tuxrun(csums=sums)
-
- def test_armv5(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=cpu:arm926
- :avocado: tags=machine:versatilepb
- :avocado: tags=tuxboot:armv5
- :avocado: tags=image:zImage
- :avocado: tags=console:ttyAMA0
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "17177afa74e7294da0642861f08c88ca3c836764299a54bf6d1ce276cb9712a5",
- "versatile-pb.dtb" :
- "0bc0c0b0858cefd3c32b385c0d66d97142ded29472a496f4f490e42fc7615b25",
- "zImage" :
- "c95af2f27647c12265d75e9df44c22ff5228c59855f54aaa70f41ec2842e3a4d" }
-
- self.common_tuxrun(csums=sums,
- drive="virtio-blk-pci",
- dt="versatile-pb.dtb")
-
- def test_armv7(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=cpu:cortex-a15
- :avocado: tags=machine:virt
- :avocado: tags=tuxboot:armv7
- :avocado: tags=image:zImage
- :avocado: tags=console:ttyAMA0
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "ab1fbbeaddda1ffdd45c9405a28cd5370c20f23a7cbc809cc90dc9f243a8eb5a",
- "zImage" :
- "4c7a22e9f15875bec06bd2a29d822496571eb297d4f22694099ffcdb19077572" }
-
- self.common_tuxrun(csums=sums)
-
- def test_armv7be(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=cpu:cortex-a15
- :avocado: tags=endian:big
- :avocado: tags=machine:virt
- :avocado: tags=tuxboot:armv7be
- :avocado: tags=image:zImage
- :avocado: tags=console:ttyAMA0
- :avocado: tags=shutdown:nowait
- """
- sums = {"rootfs.ext4.zst" :
- "42ed46dd2d59986206c5b1f6cf35eab58fe3fd20c96b41aaa16b32f3f90a9835",
- "zImage" :
- "7facc62082b57af12015b08f7fdbaf2f123ba07a478367853ae12b219afc9f2f" }
-
- self.common_tuxrun(csums=sums)
-
- def test_i386(self):
- """
- :avocado: tags=arch:i386
- :avocado: tags=cpu:coreduo
- :avocado: tags=machine:q35
- :avocado: tags=tuxboot:i386
- :avocado: tags=image:bzImage
- :avocado: tags=shutdown:nowait
- """
- sums = {"bzImage" :
- "a3e5b32a354729e65910f5a1ffcda7c14a6c12a55e8213fb86e277f1b76ed956",
- "rootfs.ext4.zst" :
- "f15e66b2bf673a210ec2a4b2e744a80530b36289e04f5388aab812b97f69754a" }
-
- self.common_tuxrun(csums=sums, drive="virtio-blk-pci")
-
- def test_mips32(self):
- """
- :avocado: tags=arch:mips
- :avocado: tags=machine:malta
- :avocado: tags=cpu:mips32r6-generic
- :avocado: tags=endian:big
- :avocado: tags=tuxboot:mips32
- :avocado: tags=image:vmlinux
- :avocado: tags=root:sda
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "fc3da0b4c2f38d74c6d705123bb0f633c76ed953128f9d0859378c328a6d11a0",
- "vmlinux" :
- "bfd2172f8b17fb32970ca0c8c58f59c5a4ca38aa5855d920be3a69b5d16e52f0" }
-
- self.common_tuxrun(csums=sums, drive="driver=ide-hd,bus=ide.0,unit=0")
-
- def test_mips32el(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=machine:malta
- :avocado: tags=cpu:mips32r6-generic
- :avocado: tags=tuxboot:mips32el
- :avocado: tags=image:vmlinux
- :avocado: tags=root:sda
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "e799768e289fd69209c21f4dacffa11baea7543d5db101e8ce27e3bc2c41d90e",
- "vmlinux" :
- "8573867c68a8443db8de6d08bb33fb291c189ca2ca671471d3973a3e712096a3" }
-
- self.common_tuxrun(csums=sums, drive="driver=ide-hd,bus=ide.0,unit=0")
-
- def test_mips64(self):
- """
- :avocado: tags=arch:mips64
- :avocado: tags=machine:malta
- :avocado: tags=tuxboot:mips64
- :avocado: tags=endian:big
- :avocado: tags=image:vmlinux
- :avocado: tags=root:sda
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "69d91eeb04df3d8d172922c6993bb37d4deeb6496def75d8580f6f9de3e431da",
- "vmlinux" :
- "09010e51e4b8bcbbd2494786ffb48eca78f228e96e5c5438344b0eac4029dc61" }
-
- self.common_tuxrun(csums=sums, drive="driver=ide-hd,bus=ide.0,unit=0")
-
- def test_mips64el(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- :avocado: tags=tuxboot:mips64el
- :avocado: tags=image:vmlinux
- :avocado: tags=root:sda
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "fba585368f5915b1498ed081863474b2d7ec4e97cdd46d21bdcb2f9698f83de4",
- "vmlinux" :
- "d4e08965e2155c4cccce7c5f34d18fe34c636cda2f2c9844387d614950155266" }
-
- self.common_tuxrun(csums=sums, drive="driver=ide-hd,bus=ide.0,unit=0")
-
- def test_ppc32(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:ppce500
- :avocado: tags=cpu:e500mc
- :avocado: tags=tuxboot:ppc32
- :avocado: tags=image:uImage
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "8885b9d999cc24d679542a02e9b6aaf48f718f2050ece6b8347074b6ee41dd09",
- "uImage" :
- "1a68f74b860fda022fb12e03c5efece8c2b8b590d96cca37a8481a3ae0b3f81f" }
-
- self.common_tuxrun(csums=sums, drive="virtio-blk-pci")
-
- def test_ppc64(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- :avocado: tags=cpu:POWER10
- :avocado: tags=endian:big
- :avocado: tags=console:hvc0
- :avocado: tags=tuxboot:ppc64
- :avocado: tags=image:vmlinux
- :avocado: tags=extradev:driver=spapr-vscsi
- :avocado: tags=root:sda
- """
- sums = { "rootfs.ext4.zst" :
- "1d953e81a4379e537fc8e41e05a0a59d9b453eef97aa03d47866c6c45b00bdff",
- "vmlinux" :
- "f22a9b9e924174a4c199f4c7e5d91a2339fcfe51c6eafd0907dc3e09b64ab728" }
- self.ppc64_common_tuxrun(sums, prefix='tuxrun_ppc64_')
-
- def test_ppc64le(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- :avocado: tags=cpu:POWER10
- :avocado: tags=console:hvc0
- :avocado: tags=tuxboot:ppc64le
- :avocado: tags=image:vmlinux
- :avocado: tags=extradev:driver=spapr-vscsi
- :avocado: tags=root:sda
- """
- sums = { "rootfs.ext4.zst" :
- "b442678c93fb8abe1f7d3bfa20556488de6b475c22c8fed363f42cf81a0a3906",
- "vmlinux" :
- "979eb61b445a010fb13e2b927126991f8ceef9c590fa2be0996c00e293e80cf2" }
- self.ppc64_common_tuxrun(sums, prefix='tuxrun_ppc64le_')
-
- def test_riscv32(self):
- """
- :avocado: tags=arch:riscv32
- :avocado: tags=machine:virt
- :avocado: tags=tuxboot:riscv32
- """
- sums = { "Image" :
- "89599407d7334de629a40e7ad6503c73670359eb5f5ae9d686353a3d6deccbd5",
- "fw_jump.elf" :
- "f2ef28a0b77826f79d085d3e4aa686f1159b315eff9099a37046b18936676985",
- "rootfs.ext4.zst" :
- "7168d296d0283238ea73cd5a775b3dd608e55e04c7b92b76ecce31bb13108cba" }
-
- self.common_tuxrun(csums=sums)
-
- def test_riscv64(self):
- """
- :avocado: tags=arch:riscv64
- :avocado: tags=machine:virt
- :avocado: tags=tuxboot:riscv64
- """
- sums = { "Image" :
- "cd634badc65e52fb63465ec99e309c0de0369f0841b7d9486f9729e119bac25e",
- "fw_jump.elf" :
- "6e3373abcab4305fe151b564a4c71110d833c21f2c0a1753b7935459e36aedcf",
- "rootfs.ext4.zst" :
- "b18e3a3bdf27be03da0b285e84cb71bf09eca071c3a087b42884b6982ed679eb" }
-
- self.common_tuxrun(csums=sums)
-
- def test_riscv32_maxcpu(self):
- """
- :avocado: tags=arch:riscv32
- :avocado: tags=machine:virt
- :avocado: tags=cpu:max
- :avocado: tags=tuxboot:riscv32
- """
- sums = { "Image" :
- "89599407d7334de629a40e7ad6503c73670359eb5f5ae9d686353a3d6deccbd5",
- "fw_jump.elf" :
- "f2ef28a0b77826f79d085d3e4aa686f1159b315eff9099a37046b18936676985",
- "rootfs.ext4.zst" :
- "7168d296d0283238ea73cd5a775b3dd608e55e04c7b92b76ecce31bb13108cba" }
-
- self.common_tuxrun(csums=sums)
-
- def test_riscv64_maxcpu(self):
- """
- :avocado: tags=arch:riscv64
- :avocado: tags=machine:virt
- :avocado: tags=cpu:max
- :avocado: tags=tuxboot:riscv64
- """
- sums = { "Image" :
- "cd634badc65e52fb63465ec99e309c0de0369f0841b7d9486f9729e119bac25e",
- "fw_jump.elf" :
- "6e3373abcab4305fe151b564a4c71110d833c21f2c0a1753b7935459e36aedcf",
- "rootfs.ext4.zst" :
- "b18e3a3bdf27be03da0b285e84cb71bf09eca071c3a087b42884b6982ed679eb" }
-
- self.common_tuxrun(csums=sums)
-
- def test_s390(self):
- """
- :avocado: tags=arch:s390x
- :avocado: tags=endian:big
- :avocado: tags=tuxboot:s390
- :avocado: tags=image:bzImage
- :avocado: tags=shutdown:nowait
- """
- sums = { "bzImage" :
- "0414e98dd1c3dafff8496c9cd9c28a5f8d04553bb5ba37e906a812b48d442ef0",
- "rootfs.ext4.zst" :
- "88c37c32276677f873a25ab9ec6247895b8e3e6f8259134de2a616080b8ab3fc" }
-
- self.common_tuxrun(csums=sums,
- drive="virtio-blk-ccw",
- haltmsg="Requesting system halt")
-
- # Note: some segfaults caused by unaligned userspace access
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
- def test_sh4(self):
- """
- :avocado: tags=arch:sh4
- :avocado: tags=machine:r2d
- :avocado: tags=cpu:sh7785
- :avocado: tags=tuxboot:sh4
- :avocado: tags=image:zImage
- :avocado: tags=root:sda
- :avocado: tags=console:ttySC1
- :avocado: tags=flaky
- """
- sums = { "rootfs.ext4.zst" :
- "3592a7a3d5a641e8b9821449e77bc43c9904a56c30d45da0694349cfd86743fd",
- "zImage" :
- "29d9b2aba604a0f53a5dc3b5d0f2b8e35d497de1129f8ee5139eb6fdf0db692f" }
-
- # The test is currently too unstable to do much in userspace
- # so we skip common_tuxrun and do a minimal boot and shutdown.
- (kernel, disk, dtb) = self.fetch_tuxrun_assets(csums=sums)
-
- # the console comes on the second serial port
- self.prepare_run(kernel, disk,
- "driver=ide-hd,bus=ide.0,unit=0",
- console_index=1)
- self.vm.launch()
-
- self.wait_for_console_pattern("Welcome to TuxTest")
- time.sleep(0.1)
- exec_command(self, 'root')
- time.sleep(0.1)
- exec_command_and_wait_for_pattern(self, 'halt',
- "reboot: System halted")
-
- def test_sparc64(self):
- """
- :avocado: tags=arch:sparc64
- :avocado: tags=tuxboot:sparc64
- :avocado: tags=image:vmlinux
- :avocado: tags=root:sda
- :avocado: tags=shutdown:nowait
- """
-
- sums = { "rootfs.ext4.zst" :
- "ad2f1dc436ab51583543d25d2c210cab478645d47078d30d129a66ab0e281d76",
- "vmlinux" :
- "e34313e4325ff21deaa3d38a502aa09a373ef62b9bd4d7f8f29388b688225c55" }
-
- self.common_tuxrun(csums=sums, drive="driver=ide-hd,bus=ide.0,unit=0")
-
- def test_x86_64(self):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:q35
- :avocado: tags=cpu:Nehalem
- :avocado: tags=tuxboot:x86_64
- :avocado: tags=image:bzImage
- :avocado: tags=root:sda
- :avocado: tags=shutdown:nowait
- """
- sums = { "bzImage" :
- "2bc7480a669ee9b6b82500a236aba0c54233debe98cb968268fa230f52f03461",
- "rootfs.ext4.zst" :
- "b72ac729769b8f51c6dffb221113c9a063c774dbe1d66af30eb593c4e9999b4b" }
-
- self.common_tuxrun(csums=sums,
- drive="driver=ide-hd,bus=ide.0,unit=0")
diff --git a/tests/bench/benchmark-crypto-akcipher.c b/tests/bench/benchmark-crypto-akcipher.c
index 5e68cb0..0a6e5db 100644
--- a/tests/bench/benchmark-crypto-akcipher.c
+++ b/tests/bench/benchmark-crypto-akcipher.c
@@ -16,19 +16,19 @@
#include "crypto/akcipher.h"
#include "standard-headers/linux/virtio_crypto.h"
-#include "test_akcipher_keys.inc"
+#include "test_akcipher_keys.c.inc"
static QCryptoAkCipher *create_rsa_akcipher(const uint8_t *priv_key,
size_t keylen,
- QCryptoRSAPaddingAlgorithm padding,
- QCryptoHashAlgorithm hash)
+ QCryptoRSAPaddingAlgo padding,
+ QCryptoHashAlgo hash)
{
QCryptoAkCipherOptions opt;
- opt.alg = QCRYPTO_AKCIPHER_ALG_RSA;
+ opt.alg = QCRYPTO_AK_CIPHER_ALGO_RSA;
opt.u.rsa.padding_alg = padding;
opt.u.rsa.hash_alg = hash;
- return qcrypto_akcipher_new(&opt, QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ return qcrypto_akcipher_new(&opt, QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
priv_key, keylen, &error_abort);
}
@@ -39,8 +39,8 @@ static void test_rsa_speed(const uint8_t *priv_key, size_t keylen,
#define SHA1_DGST_LEN 20
#define SIGN_TIMES 10000
#define VERIFY_TIMES 100000
-#define PADDING QCRYPTO_RSA_PADDING_ALG_PKCS1
-#define HASH QCRYPTO_HASH_ALG_SHA1
+#define PADDING QCRYPTO_RSA_PADDING_ALGO_PKCS1
+#define HASH QCRYPTO_HASH_ALGO_SHA1
g_autoptr(QCryptoAkCipher) rsa =
create_rsa_akcipher(priv_key, keylen, PADDING, HASH);
@@ -53,8 +53,8 @@ static void test_rsa_speed(const uint8_t *priv_key, size_t keylen,
signature = g_new0(uint8_t, key_size / BYTE);
g_test_message("benchmark rsa%zu (%s-%s) sign...", key_size,
- QCryptoRSAPaddingAlgorithm_str(PADDING),
- QCryptoHashAlgorithm_str(HASH));
+ QCryptoRSAPaddingAlgo_str(PADDING),
+ QCryptoHashAlgo_str(HASH));
g_test_timer_start();
for (count = 0; count < SIGN_TIMES; ++count) {
g_assert(qcrypto_akcipher_sign(rsa, dgst, SHA1_DGST_LEN,
@@ -64,14 +64,14 @@ static void test_rsa_speed(const uint8_t *priv_key, size_t keylen,
g_test_timer_elapsed();
g_test_message("rsa%zu (%s-%s) sign %zu times in %.2f seconds,"
" %.2f times/sec ",
- key_size, QCryptoRSAPaddingAlgorithm_str(PADDING),
- QCryptoHashAlgorithm_str(HASH),
+ key_size, QCryptoRSAPaddingAlgo_str(PADDING),
+ QCryptoHashAlgo_str(HASH),
count, g_test_timer_last(),
(double)count / g_test_timer_last());
g_test_message("benchmark rsa%zu (%s-%s) verification...", key_size,
- QCryptoRSAPaddingAlgorithm_str(PADDING),
- QCryptoHashAlgorithm_str(HASH));
+ QCryptoRSAPaddingAlgo_str(PADDING),
+ QCryptoHashAlgo_str(HASH));
g_test_timer_start();
for (count = 0; count < VERIFY_TIMES; ++count) {
g_assert(qcrypto_akcipher_verify(rsa, signature, key_size / BYTE,
@@ -81,8 +81,8 @@ static void test_rsa_speed(const uint8_t *priv_key, size_t keylen,
g_test_timer_elapsed();
g_test_message("rsa%zu (%s-%s) verify %zu times in %.2f seconds,"
" %.2f times/sec ",
- key_size, QCryptoRSAPaddingAlgorithm_str(PADDING),
- QCryptoHashAlgorithm_str(HASH),
+ key_size, QCryptoRSAPaddingAlgo_str(PADDING),
+ QCryptoHashAlgo_str(HASH),
count, g_test_timer_last(),
(double)count / g_test_timer_last());
}
diff --git a/tests/bench/benchmark-crypto-cipher.c b/tests/bench/benchmark-crypto-cipher.c
index c04f0a0..889a29b 100644
--- a/tests/bench/benchmark-crypto-cipher.c
+++ b/tests/bench/benchmark-crypto-cipher.c
@@ -17,7 +17,7 @@
static void test_cipher_speed(size_t chunk_size,
QCryptoCipherMode mode,
- QCryptoCipherAlgorithm alg)
+ QCryptoCipherAlgo alg)
{
QCryptoCipher *cipher;
Error *err = NULL;
@@ -71,7 +71,7 @@ static void test_cipher_speed(size_t chunk_size,
g_test_timer_elapsed();
g_test_message("enc(%s-%s) chunk %zu bytes %.2f MB/sec ",
- QCryptoCipherAlgorithm_str(alg),
+ QCryptoCipherAlgo_str(alg),
QCryptoCipherMode_str(mode),
chunk_size, (double)total / MiB / g_test_timer_last());
@@ -88,7 +88,7 @@ static void test_cipher_speed(size_t chunk_size,
g_test_timer_elapsed();
g_test_message("dec(%s-%s) chunk %zu bytes %.2f MB/sec ",
- QCryptoCipherAlgorithm_str(alg),
+ QCryptoCipherAlgo_str(alg),
QCryptoCipherMode_str(mode),
chunk_size, (double)total / MiB / g_test_timer_last());
@@ -105,7 +105,7 @@ static void test_cipher_speed_ecb_aes_128(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_ECB,
- QCRYPTO_CIPHER_ALG_AES_128);
+ QCRYPTO_CIPHER_ALGO_AES_128);
}
static void test_cipher_speed_ecb_aes_256(const void *opaque)
@@ -113,7 +113,7 @@ static void test_cipher_speed_ecb_aes_256(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_ECB,
- QCRYPTO_CIPHER_ALG_AES_256);
+ QCRYPTO_CIPHER_ALGO_AES_256);
}
static void test_cipher_speed_cbc_aes_128(const void *opaque)
@@ -121,7 +121,7 @@ static void test_cipher_speed_cbc_aes_128(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_CBC,
- QCRYPTO_CIPHER_ALG_AES_128);
+ QCRYPTO_CIPHER_ALGO_AES_128);
}
static void test_cipher_speed_cbc_aes_256(const void *opaque)
@@ -129,7 +129,7 @@ static void test_cipher_speed_cbc_aes_256(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_CBC,
- QCRYPTO_CIPHER_ALG_AES_256);
+ QCRYPTO_CIPHER_ALGO_AES_256);
}
static void test_cipher_speed_ctr_aes_128(const void *opaque)
@@ -137,7 +137,7 @@ static void test_cipher_speed_ctr_aes_128(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_CTR,
- QCRYPTO_CIPHER_ALG_AES_128);
+ QCRYPTO_CIPHER_ALGO_AES_128);
}
static void test_cipher_speed_ctr_aes_256(const void *opaque)
@@ -145,7 +145,7 @@ static void test_cipher_speed_ctr_aes_256(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_CTR,
- QCRYPTO_CIPHER_ALG_AES_256);
+ QCRYPTO_CIPHER_ALGO_AES_256);
}
static void test_cipher_speed_xts_aes_128(const void *opaque)
@@ -153,7 +153,7 @@ static void test_cipher_speed_xts_aes_128(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_XTS,
- QCRYPTO_CIPHER_ALG_AES_128);
+ QCRYPTO_CIPHER_ALGO_AES_128);
}
static void test_cipher_speed_xts_aes_256(const void *opaque)
@@ -161,7 +161,7 @@ static void test_cipher_speed_xts_aes_256(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_XTS,
- QCRYPTO_CIPHER_ALG_AES_256);
+ QCRYPTO_CIPHER_ALGO_AES_256);
}
diff --git a/tests/bench/benchmark-crypto-hash.c b/tests/bench/benchmark-crypto-hash.c
index 927b00b..252098a 100644
--- a/tests/bench/benchmark-crypto-hash.c
+++ b/tests/bench/benchmark-crypto-hash.c
@@ -17,7 +17,7 @@
typedef struct QCryptoHashOpts {
size_t chunk_size;
- QCryptoHashAlgorithm alg;
+ QCryptoHashAlgo alg;
} QCryptoHashOpts;
static void test_hash_speed(const void *opaque)
@@ -49,7 +49,7 @@ static void test_hash_speed(const void *opaque)
g_test_timer_elapsed();
g_test_message("hash(%s): chunk %zu bytes %.2f MB/sec",
- QCryptoHashAlgorithm_str(opts->alg),
+ QCryptoHashAlgo_str(opts->alg),
opts->chunk_size, total / g_test_timer_last());
g_free(out);
@@ -65,14 +65,14 @@ int main(int argc, char **argv)
#define TEST_ONE(a, c) \
QCryptoHashOpts opts ## a ## c = { \
- .alg = QCRYPTO_HASH_ALG_ ## a, .chunk_size = c, \
+ .alg = QCRYPTO_HASH_ALGO_ ## a, .chunk_size = c, \
}; \
memset(name, 0 , sizeof(name)); \
snprintf(name, sizeof(name), \
"/crypto/benchmark/hash/%s/bufsize-%d", \
- QCryptoHashAlgorithm_str(QCRYPTO_HASH_ALG_ ## a), \
+ QCryptoHashAlgo_str(QCRYPTO_HASH_ALGO_ ## a), \
c); \
- if (qcrypto_hash_supports(QCRYPTO_HASH_ALG_ ## a)) \
+ if (qcrypto_hash_supports(QCRYPTO_HASH_ALGO_ ## a)) \
g_test_add_data_func(name, \
&opts ## a ## c, \
test_hash_speed);
diff --git a/tests/bench/benchmark-crypto-hmac.c b/tests/bench/benchmark-crypto-hmac.c
index 5cca636..d51de98 100644
--- a/tests/bench/benchmark-crypto-hmac.c
+++ b/tests/bench/benchmark-crypto-hmac.c
@@ -28,7 +28,7 @@ static void test_hmac_speed(const void *opaque)
Error *err = NULL;
int ret;
- if (!qcrypto_hmac_supports(QCRYPTO_HASH_ALG_SHA256)) {
+ if (!qcrypto_hmac_supports(QCRYPTO_HASH_ALGO_SHA256)) {
return;
}
@@ -40,7 +40,7 @@ static void test_hmac_speed(const void *opaque)
g_test_timer_start();
do {
- hmac = qcrypto_hmac_new(QCRYPTO_HASH_ALG_SHA256,
+ hmac = qcrypto_hmac_new(QCRYPTO_HASH_ALGO_SHA256,
(const uint8_t *)KEY, strlen(KEY), &err);
g_assert(err == NULL);
g_assert(hmac != NULL);
@@ -56,7 +56,7 @@ static void test_hmac_speed(const void *opaque)
total /= MiB;
g_test_message("hmac(%s): chunk %zu bytes %.2f MB/sec",
- QCryptoHashAlgorithm_str(QCRYPTO_HASH_ALG_SHA256),
+ QCryptoHashAlgo_str(QCRYPTO_HASH_ALGO_SHA256),
chunk_size, total / g_test_timer_last());
g_free(out);
diff --git a/tests/bench/test_akcipher_keys.inc b/tests/bench/test_akcipher_keys.c.inc
index df3eccb..df3eccb 100644
--- a/tests/bench/test_akcipher_keys.inc
+++ b/tests/bench/test_akcipher_keys.c.inc
diff --git a/tests/data/acpi/aarch64/virt/APIC.its_off b/tests/data/acpi/aarch64/virt/APIC.its_off
new file mode 100644
index 0000000..6130cb7
--- /dev/null
+++ b/tests/data/acpi/aarch64/virt/APIC.its_off
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/IORT.its_off b/tests/data/acpi/aarch64/virt/IORT.its_off
new file mode 100644
index 0000000..c10da4e
--- /dev/null
+++ b/tests/data/acpi/aarch64/virt/IORT.its_off
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/SSDT.memhp b/tests/data/acpi/aarch64/virt/SSDT.memhp
index fb3dcde..1deb1d2 100644
--- a/tests/data/acpi/aarch64/virt/SSDT.memhp
+++ b/tests/data/acpi/aarch64/virt/SSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/disassemle-aml.sh b/tests/data/acpi/disassemle-aml.sh
index 253b762..89561d2 100755
--- a/tests/data/acpi/disassemle-aml.sh
+++ b/tests/data/acpi/disassemle-aml.sh
@@ -14,7 +14,7 @@ while getopts "o:" arg; do
esac
done
-for machine in tests/data/acpi/*
+for machine in tests/data/acpi/*/*
do
if [[ ! -d "$machine" ]];
then
diff --git a/tests/data/acpi/riscv64/virt/RHCT b/tests/data/acpi/riscv64/virt/RHCT
index 4f23173..13c8025 100644
--- a/tests/data/acpi/riscv64/virt/RHCT
+++ b/tests/data/acpi/riscv64/virt/RHCT
Binary files differ
diff --git a/tests/data/acpi/riscv64/virt/SPCR b/tests/data/acpi/riscv64/virt/SPCR
index 4da9daf..09617f8 100644
--- a/tests/data/acpi/riscv64/virt/SPCR
+++ b/tests/data/acpi/riscv64/virt/SPCR
Binary files differ
diff --git a/tests/data/acpi/riscv64/virt/SRAT.numamem b/tests/data/acpi/riscv64/virt/SRAT.numamem
new file mode 100644
index 0000000..2b64673
--- /dev/null
+++ b/tests/data/acpi/riscv64/virt/SRAT.numamem
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT b/tests/data/acpi/x86/pc/DSDT
index c93ad6b..4beb519 100644
--- a/tests/data/acpi/x86/pc/DSDT
+++ b/tests/data/acpi/x86/pc/DSDT
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.acpierst b/tests/data/acpi/x86/pc/DSDT.acpierst
index f643fa2..abda686 100644
--- a/tests/data/acpi/x86/pc/DSDT.acpierst
+++ b/tests/data/acpi/x86/pc/DSDT.acpierst
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.acpihmat b/tests/data/acpi/x86/pc/DSDT.acpihmat
index 9d3695f..d081db2 100644
--- a/tests/data/acpi/x86/pc/DSDT.acpihmat
+++ b/tests/data/acpi/x86/pc/DSDT.acpihmat
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.bridge b/tests/data/acpi/x86/pc/DSDT.bridge
index 840b45f..e16897d 100644
--- a/tests/data/acpi/x86/pc/DSDT.bridge
+++ b/tests/data/acpi/x86/pc/DSDT.bridge
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.cphp b/tests/data/acpi/x86/pc/DSDT.cphp
index dbc0141..e95711c 100644
--- a/tests/data/acpi/x86/pc/DSDT.cphp
+++ b/tests/data/acpi/x86/pc/DSDT.cphp
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.dimmpxm b/tests/data/acpi/x86/pc/DSDT.dimmpxm
index 1294f65..90ba66b 100644
--- a/tests/data/acpi/x86/pc/DSDT.dimmpxm
+++ b/tests/data/acpi/x86/pc/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.hpbridge b/tests/data/acpi/x86/pc/DSDT.hpbridge
index 8012b5e..0eafe5f 100644
--- a/tests/data/acpi/x86/pc/DSDT.hpbridge
+++ b/tests/data/acpi/x86/pc/DSDT.hpbridge
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.hpbrroot b/tests/data/acpi/x86/pc/DSDT.hpbrroot
index 4fa0c6f..077a4cc 100644
--- a/tests/data/acpi/x86/pc/DSDT.hpbrroot
+++ b/tests/data/acpi/x86/pc/DSDT.hpbrroot
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.ipmikcs b/tests/data/acpi/x86/pc/DSDT.ipmikcs
index 0a891ba..8d465f0 100644
--- a/tests/data/acpi/x86/pc/DSDT.ipmikcs
+++ b/tests/data/acpi/x86/pc/DSDT.ipmikcs
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.memhp b/tests/data/acpi/x86/pc/DSDT.memhp
index 9b442a6..e3b4975 100644
--- a/tests/data/acpi/x86/pc/DSDT.memhp
+++ b/tests/data/acpi/x86/pc/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.nohpet b/tests/data/acpi/x86/pc/DSDT.nohpet
index 1754c68..9e772c1 100644
--- a/tests/data/acpi/x86/pc/DSDT.nohpet
+++ b/tests/data/acpi/x86/pc/DSDT.nohpet
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.numamem b/tests/data/acpi/x86/pc/DSDT.numamem
index 9fc731d..9bfbfc2 100644
--- a/tests/data/acpi/x86/pc/DSDT.numamem
+++ b/tests/data/acpi/x86/pc/DSDT.numamem
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.roothp b/tests/data/acpi/x86/pc/DSDT.roothp
index e654c83..efbee6d 100644
--- a/tests/data/acpi/x86/pc/DSDT.roothp
+++ b/tests/data/acpi/x86/pc/DSDT.roothp
Binary files differ
diff --git a/tests/data/acpi/x86/q35/APIC.acpihmat-generic-x b/tests/data/acpi/x86/q35/APIC.acpihmat-generic-x
new file mode 100644
index 0000000..317ddb3
--- /dev/null
+++ b/tests/data/acpi/x86/q35/APIC.acpihmat-generic-x
Binary files differ
diff --git a/tests/data/acpi/x86/q35/CEDT.acpihmat-generic-x b/tests/data/acpi/x86/q35/CEDT.acpihmat-generic-x
new file mode 100644
index 0000000..31c9011
--- /dev/null
+++ b/tests/data/acpi/x86/q35/CEDT.acpihmat-generic-x
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DMAR.dmar b/tests/data/acpi/x86/q35/DMAR.dmar
index 0dca6e6..0c05976 100644
--- a/tests/data/acpi/x86/q35/DMAR.dmar
+++ b/tests/data/acpi/x86/q35/DMAR.dmar
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT b/tests/data/acpi/x86/q35/DSDT
index fb89ae0..e5e8d1e 100644
--- a/tests/data/acpi/x86/q35/DSDT
+++ b/tests/data/acpi/x86/q35/DSDT
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.acpierst b/tests/data/acpi/x86/q35/DSDT.acpierst
index 46fd254..072a3fe 100644
--- a/tests/data/acpi/x86/q35/DSDT.acpierst
+++ b/tests/data/acpi/x86/q35/DSDT.acpierst
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.acpihmat b/tests/data/acpi/x86/q35/DSDT.acpihmat
index 61c5bd5..2a4f2fc 100644
--- a/tests/data/acpi/x86/q35/DSDT.acpihmat
+++ b/tests/data/acpi/x86/q35/DSDT.acpihmat
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.acpihmat-generic-x b/tests/data/acpi/x86/q35/DSDT.acpihmat-generic-x
new file mode 100644
index 0000000..7911c05
--- /dev/null
+++ b/tests/data/acpi/x86/q35/DSDT.acpihmat-generic-x
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator b/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator
index 3aaa2bb..580b4a4 100644
--- a/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator
+++ b/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.applesmc b/tests/data/acpi/x86/q35/DSDT.applesmc
index 944209a..5e8220e 100644
--- a/tests/data/acpi/x86/q35/DSDT.applesmc
+++ b/tests/data/acpi/x86/q35/DSDT.applesmc
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.bridge b/tests/data/acpi/x86/q35/DSDT.bridge
index d9938db..ee03945 100644
--- a/tests/data/acpi/x86/q35/DSDT.bridge
+++ b/tests/data/acpi/x86/q35/DSDT.bridge
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.core-count b/tests/data/acpi/x86/q35/DSDT.core-count
index a24b04c..7ebfcee 100644
--- a/tests/data/acpi/x86/q35/DSDT.core-count
+++ b/tests/data/acpi/x86/q35/DSDT.core-count
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.core-count2 b/tests/data/acpi/x86/q35/DSDT.core-count2
index 3a0cb8c..d039455 100644
--- a/tests/data/acpi/x86/q35/DSDT.core-count2
+++ b/tests/data/acpi/x86/q35/DSDT.core-count2
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.cphp b/tests/data/acpi/x86/q35/DSDT.cphp
index 20955d0..a055c2e 100644
--- a/tests/data/acpi/x86/q35/DSDT.cphp
+++ b/tests/data/acpi/x86/q35/DSDT.cphp
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.cxl b/tests/data/acpi/x86/q35/DSDT.cxl
index afcdc0d..2084354 100644
--- a/tests/data/acpi/x86/q35/DSDT.cxl
+++ b/tests/data/acpi/x86/q35/DSDT.cxl
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.dimmpxm b/tests/data/acpi/x86/q35/DSDT.dimmpxm
index 228374b..664e926 100644
--- a/tests/data/acpi/x86/q35/DSDT.dimmpxm
+++ b/tests/data/acpi/x86/q35/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.ipmibt b/tests/data/acpi/x86/q35/DSDT.ipmibt
index 45f911a..4066a76 100644
--- a/tests/data/acpi/x86/q35/DSDT.ipmibt
+++ b/tests/data/acpi/x86/q35/DSDT.ipmibt
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.ipmismbus b/tests/data/acpi/x86/q35/DSDT.ipmismbus
index e5d6811..6d0b6b9 100644
--- a/tests/data/acpi/x86/q35/DSDT.ipmismbus
+++ b/tests/data/acpi/x86/q35/DSDT.ipmismbus
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.ivrs b/tests/data/acpi/x86/q35/DSDT.ivrs
index 46fd254..072a3fe 100644
--- a/tests/data/acpi/x86/q35/DSDT.ivrs
+++ b/tests/data/acpi/x86/q35/DSDT.ivrs
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.memhp b/tests/data/acpi/x86/q35/DSDT.memhp
index 5ce0811..4f2f9bc 100644
--- a/tests/data/acpi/x86/q35/DSDT.memhp
+++ b/tests/data/acpi/x86/q35/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.mmio64 b/tests/data/acpi/x86/q35/DSDT.mmio64
index bdf36c4..0fb6aab 100644
--- a/tests/data/acpi/x86/q35/DSDT.mmio64
+++ b/tests/data/acpi/x86/q35/DSDT.mmio64
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.multi-bridge b/tests/data/acpi/x86/q35/DSDT.multi-bridge
index 1db43a6..f6afa6d 100644
--- a/tests/data/acpi/x86/q35/DSDT.multi-bridge
+++ b/tests/data/acpi/x86/q35/DSDT.multi-bridge
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.noacpihp b/tests/data/acpi/x86/q35/DSDT.noacpihp
index 8bc1688..9f7261d 100644
--- a/tests/data/acpi/x86/q35/DSDT.noacpihp
+++ b/tests/data/acpi/x86/q35/DSDT.noacpihp
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.nohpet b/tests/data/acpi/x86/q35/DSDT.nohpet
index c13e45e..99ad629 100644
--- a/tests/data/acpi/x86/q35/DSDT.nohpet
+++ b/tests/data/acpi/x86/q35/DSDT.nohpet
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.numamem b/tests/data/acpi/x86/q35/DSDT.numamem
index ba66694..fd1d8a7 100644
--- a/tests/data/acpi/x86/q35/DSDT.numamem
+++ b/tests/data/acpi/x86/q35/DSDT.numamem
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.pvpanic-isa b/tests/data/acpi/x86/q35/DSDT.pvpanic-isa
index 6ad4287..89032fa 100644
--- a/tests/data/acpi/x86/q35/DSDT.pvpanic-isa
+++ b/tests/data/acpi/x86/q35/DSDT.pvpanic-isa
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.thread-count b/tests/data/acpi/x86/q35/DSDT.thread-count
index a24b04c..7ebfcee 100644
--- a/tests/data/acpi/x86/q35/DSDT.thread-count
+++ b/tests/data/acpi/x86/q35/DSDT.thread-count
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.thread-count2 b/tests/data/acpi/x86/q35/DSDT.thread-count2
index 3a0cb8c..d039455 100644
--- a/tests/data/acpi/x86/q35/DSDT.thread-count2
+++ b/tests/data/acpi/x86/q35/DSDT.thread-count2
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.tis.tpm12 b/tests/data/acpi/x86/q35/DSDT.tis.tpm12
index e381ce4..f2ed40c 100644
--- a/tests/data/acpi/x86/q35/DSDT.tis.tpm12
+++ b/tests/data/acpi/x86/q35/DSDT.tis.tpm12
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.tis.tpm2 b/tests/data/acpi/x86/q35/DSDT.tis.tpm2
index a092530..5c975d2 100644
--- a/tests/data/acpi/x86/q35/DSDT.tis.tpm2
+++ b/tests/data/acpi/x86/q35/DSDT.tis.tpm2
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.type4-count b/tests/data/acpi/x86/q35/DSDT.type4-count
index edc2319..3194a82 100644
--- a/tests/data/acpi/x86/q35/DSDT.type4-count
+++ b/tests/data/acpi/x86/q35/DSDT.type4-count
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.viot b/tests/data/acpi/x86/q35/DSDT.viot
index 64e81f5..129d43e 100644
--- a/tests/data/acpi/x86/q35/DSDT.viot
+++ b/tests/data/acpi/x86/q35/DSDT.viot
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.xapic b/tests/data/acpi/x86/q35/DSDT.xapic
index d4acd85..b37ab59 100644
--- a/tests/data/acpi/x86/q35/DSDT.xapic
+++ b/tests/data/acpi/x86/q35/DSDT.xapic
Binary files differ
diff --git a/tests/data/acpi/x86/q35/HMAT.acpihmat-generic-x b/tests/data/acpi/x86/q35/HMAT.acpihmat-generic-x
new file mode 100644
index 0000000..0e5765f
--- /dev/null
+++ b/tests/data/acpi/x86/q35/HMAT.acpihmat-generic-x
Binary files differ
diff --git a/tests/data/acpi/x86/q35/SRAT.acpihmat-generic-x b/tests/data/acpi/x86/q35/SRAT.acpihmat-generic-x
new file mode 100644
index 0000000..b45838a
--- /dev/null
+++ b/tests/data/acpi/x86/q35/SRAT.acpihmat-generic-x
Binary files differ
diff --git a/tests/data/qobject/qdict.txt b/tests/data/qobject/qdict.txt
index e2edc88..888f343 100644
--- a/tests/data/qobject/qdict.txt
+++ b/tests/data/qobject/qdict.txt
@@ -3487,12 +3487,6 @@ cred-internals.h: 559
CREDITS: 603
crime.c: 2833
crime.h: 5271
-cris: 4096
-cris_defs_asm.h: 3805
-crisksyms.c: 472
-cris_supp_reg.h: 198
-crisv10.c: 129158
-crisv10.h: 4289
crm_regs.h: 1700
cr_pll.c: 4842
crt0_ram.S: 2152
diff --git a/tests/data/uefi-boot-images/bios-tables-test.loongarch64.iso.qcow2 b/tests/data/uefi-boot-images/bios-tables-test.loongarch64.iso.qcow2
new file mode 100644
index 0000000..18daee0
--- /dev/null
+++ b/tests/data/uefi-boot-images/bios-tables-test.loongarch64.iso.qcow2
Binary files differ
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
index 708e3a7..3959d8a 100644
--- a/tests/docker/Makefile.include
+++ b/tests/docker/Makefile.include
@@ -92,10 +92,10 @@ endif
docker-image-alpine: NOUSER=1
debian-toolchain-run = \
- $(if $(NOCACHE), \
+ $(if $(NOCACHE)$(NOFETCH), \
$(call quiet-command, \
$(DOCKER_SCRIPT) build -t qemu/$1 -f $< \
- $(if $V,,--quiet) --no-cache \
+ $(if $V,,--quiet) $(if $(NOCACHE),--no-cache) \
--registry $(DOCKER_REGISTRY) --extra-files \
$(DOCKER_FILES_DIR)/$1.d/build-toolchain.sh, \
"BUILD", $1), \
@@ -117,7 +117,6 @@ docker-image-debian-microblaze-cross: $(DOCKER_FILES_DIR)/debian-toolchain.docke
# These images may be good enough for building tests but not for test builds
DOCKER_PARTIAL_IMAGES += debian-microblaze-cross
DOCKER_PARTIAL_IMAGES += debian-xtensa-cross
-DOCKER_PARTIAL_IMAGES += fedora-cris-cross
# images that are only used to build other images
DOCKER_VIRTUAL_IMAGES := debian-bootstrap debian-toolchain
@@ -178,6 +177,7 @@ docker:
@echo ' NETWORK=$$BACKEND Enable virtual network interface with $$BACKEND.'
@echo ' NOUSER=1 Define to disable adding current user to containers passwd.'
@echo ' NOCACHE=1 Ignore cache when build images.'
+ @echo ' NOFETCH=1 Do not fetch from the registry.'
@echo ' EXECUTABLE=<path> Include executable in image.'
@echo ' EXTRA_FILES="<path> [... <path>]"'
@echo ' Include extra files in image.'
@@ -185,8 +185,10 @@ docker:
docker-help: docker
+# Where QEMU caches build artefacts
+DOCKER_QEMU_CACHE_DIR := $$HOME/.cache/qemu
# Use a global constant ccache directory to speed up repetitive builds
-DOCKER_CCACHE_DIR := $$HOME/.cache/qemu-docker-ccache
+DOCKER_QEMU_CCACHE_DIR := DOCKER_QEMU_CACHE_DIR/docker-ccache
# This rule if for directly running against an arbitrary docker target.
# It is called by the expanded docker targets (e.g. make
@@ -195,7 +197,7 @@ DOCKER_CCACHE_DIR := $$HOME/.cache/qemu-docker-ccache
# For example: make docker-run TEST="test-quick" IMAGE="debian:arm64" EXECUTABLE=./aarch64-linux-user/qemu-aarch64
#
docker-run: docker-qemu-src
- @mkdir -p "$(DOCKER_CCACHE_DIR)"
+ @mkdir -p "$(DOCKER_QEMU_CCACHE_DIR)"
@if test -z "$(IMAGE)" || test -z "$(TEST)"; \
then echo "Invalid target $(IMAGE)/$(TEST)"; exit 1; \
fi
@@ -222,8 +224,8 @@ docker-run: docker-qemu-src
-e V=$V -e J=$J -e DEBUG=$(DEBUG) \
-e SHOW_ENV=$(SHOW_ENV) \
$(if $(NOUSER),, \
- -e CCACHE_DIR=/var/tmp/ccache \
- -v $(DOCKER_CCACHE_DIR):/var/tmp/ccache:z \
+ -v $(DOCKER_QEMU_CACHE_DIR):$(DOCKER_QEMU_CACHE_DIR) \
+ -e CCACHE_DIR=$(DOCKER_QEMU_CCACHE_DIR) \
) \
-v $$(readlink -e $(DOCKER_SRC_COPY)):/var/tmp/qemu:z$(COMMA)ro \
$(IMAGE) \
@@ -236,3 +238,6 @@ docker-image: ${DOCKER_IMAGES:%=docker-image-%}
docker-clean:
$(call quiet-command, $(DOCKER_SCRIPT) clean)
+
+# Overrides
+docker-test-rust%: NETWORK=1
diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker
index 54b9721..bf3bd5a 100644
--- a/tests/docker/dockerfiles/alpine.docker
+++ b/tests/docker/dockerfiles/alpine.docker
@@ -1,10 +1,10 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile --layers all alpine-319 qemu
+# $ lcitool dockerfile --layers all alpine-321 qemu
#
# https://gitlab.com/libvirt/libvirt-ci
-FROM docker.io/library/alpine:3.19
+FROM docker.io/library/alpine:3.21
RUN apk update && \
apk upgrade && \
@@ -45,6 +45,7 @@ RUN apk update && \
libaio-dev \
libbpf-dev \
libcap-ng-dev \
+ libcbor-dev \
libdrm-dev \
libepoxy-dev \
libffi-dev \
@@ -90,6 +91,8 @@ RUN apk update && \
py3-yaml \
python3 \
rpm2cpio \
+ rust \
+ rust-bindgen \
samurai \
sdl2-dev \
sdl2_image-dev \
@@ -108,6 +111,7 @@ RUN apk update && \
vde2-dev \
virglrenderer-dev \
vte3-dev \
+ vulkan-tools \
which \
xen-dev \
xorriso \
diff --git a/tests/docker/dockerfiles/centos9.docker b/tests/docker/dockerfiles/centos9.docker
index 0256865..a942835 100644
--- a/tests/docker/dockerfiles/centos9.docker
+++ b/tests/docker/dockerfiles/centos9.docker
@@ -16,6 +16,7 @@ RUN dnf distro-sync -y && \
alsa-lib-devel \
bash \
bc \
+ bindgen-cli \
bison \
brlapi-devel \
bzip2 \
@@ -102,6 +103,7 @@ RUN dnf distro-sync -y && \
python3-sphinx_rtd_theme \
python3-tomli \
rdma-core-devel \
+ rust \
sed \
snappy-devel \
socat \
@@ -113,6 +115,7 @@ RUN dnf distro-sync -y && \
usbredir-devel \
util-linux \
vte291-devel \
+ vulkan-tools \
which \
xorriso \
zlib-devel \
diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker
index 136c3a7..081f3e0 100644
--- a/tests/docker/dockerfiles/debian-amd64-cross.docker
+++ b/tests/docker/dockerfiles/debian-amd64-cross.docker
@@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
eatmydata apt-get install --no-install-recommends -y \
bash \
bc \
+ bindgen \
bison \
bsdextrautils \
bzip2 \
@@ -30,10 +31,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
- libgtk-vnc-2.0-dev \
- libpcre2-dev \
- libsndio-dev \
- libspice-protocol-dev \
llvm \
locales \
make \
@@ -53,6 +50,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3-venv \
python3-yaml \
rpm2cpio \
+ rustc-web \
sed \
socat \
sparse \
@@ -60,6 +58,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
tar \
tesseract-ocr \
tesseract-ocr-eng \
+ vulkan-tools \
xorriso \
zstd && \
eatmydata apt-get autoremove -y && \
@@ -92,6 +91,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libcacard-dev:amd64 \
libcap-ng-dev:amd64 \
libcapstone-dev:amd64 \
+ libcbor-dev:amd64 \
libcmocka-dev:amd64 \
libcurl4-gnutls-dev:amd64 \
libdaxctl-dev:amd64 \
@@ -106,6 +106,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libglusterfs-dev:amd64 \
libgnutls28-dev:amd64 \
libgtk-3-dev:amd64 \
+ libgtk-vnc-2.0-dev:amd64 \
libibverbs-dev:amd64 \
libiscsi-dev:amd64 \
libjemalloc-dev:amd64 \
@@ -117,6 +118,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libnfs-dev:amd64 \
libnuma-dev:amd64 \
libpam0g-dev:amd64 \
+ libpcre2-dev:amd64 \
libpipewire-0.3-dev:amd64 \
libpixman-1-dev:amd64 \
libpmem-dev:amd64 \
@@ -131,8 +133,10 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libselinux1-dev:amd64 \
libslirp-dev:amd64 \
libsnappy-dev:amd64 \
+ libsndio-dev:amd64 \
+ libspice-protocol-dev:amd64 \
libspice-server-dev:amd64 \
- libssh-gcrypt-dev:amd64 \
+ libssh-dev:amd64 \
libsystemd-dev:amd64 \
libtasn1-6-dev:amd64 \
libubsan1:amd64 \
@@ -170,6 +174,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/x86_64-linux-gnu && \
ENV ABI "x86_64-linux-gnu"
ENV MESON_OPTS "--cross-file=x86_64-linux-gnu"
+ENV RUST_TARGET "x86_64-unknown-linux-gnu"
ENV QEMU_CONFIGURE_OPTS --cross-prefix=x86_64-linux-gnu-
ENV DEF_TARGET_LIST x86_64-softmmu,x86_64-linux-user,i386-softmmu,i386-linux-user
# As a final step configure the user (if env is defined)
diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker
index 233f6ee..91c555a 100644
--- a/tests/docker/dockerfiles/debian-arm64-cross.docker
+++ b/tests/docker/dockerfiles/debian-arm64-cross.docker
@@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
eatmydata apt-get install --no-install-recommends -y \
bash \
bc \
+ bindgen \
bison \
bsdextrautils \
bzip2 \
@@ -30,10 +31,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
- libgtk-vnc-2.0-dev \
- libpcre2-dev \
- libsndio-dev \
- libspice-protocol-dev \
llvm \
locales \
make \
@@ -53,6 +50,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3-venv \
python3-yaml \
rpm2cpio \
+ rustc-web \
sed \
socat \
sparse \
@@ -60,6 +58,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
tar \
tesseract-ocr \
tesseract-ocr-eng \
+ vulkan-tools \
xorriso \
zstd && \
eatmydata apt-get autoremove -y && \
@@ -92,6 +91,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libcacard-dev:arm64 \
libcap-ng-dev:arm64 \
libcapstone-dev:arm64 \
+ libcbor-dev:arm64 \
libcmocka-dev:arm64 \
libcurl4-gnutls-dev:arm64 \
libdaxctl-dev:arm64 \
@@ -106,6 +106,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libglusterfs-dev:arm64 \
libgnutls28-dev:arm64 \
libgtk-3-dev:arm64 \
+ libgtk-vnc-2.0-dev:arm64 \
libibverbs-dev:arm64 \
libiscsi-dev:arm64 \
libjemalloc-dev:arm64 \
@@ -117,6 +118,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libnfs-dev:arm64 \
libnuma-dev:arm64 \
libpam0g-dev:arm64 \
+ libpcre2-dev:arm64 \
libpipewire-0.3-dev:arm64 \
libpixman-1-dev:arm64 \
libpng-dev:arm64 \
@@ -130,8 +132,10 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libselinux1-dev:arm64 \
libslirp-dev:arm64 \
libsnappy-dev:arm64 \
+ libsndio-dev:arm64 \
+ libspice-protocol-dev:arm64 \
libspice-server-dev:arm64 \
- libssh-gcrypt-dev:arm64 \
+ libssh-dev:arm64 \
libsystemd-dev:arm64 \
libtasn1-6-dev:arm64 \
libubsan1:arm64 \
@@ -169,6 +173,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/aarch64-linux-gnu && \
ENV ABI "aarch64-linux-gnu"
ENV MESON_OPTS "--cross-file=aarch64-linux-gnu"
+ENV RUST_TARGET "aarch64-unknown-linux-gnu"
ENV QEMU_CONFIGURE_OPTS --cross-prefix=aarch64-linux-gnu-
ENV DEF_TARGET_LIST aarch64-softmmu,aarch64-linux-user
# As a final step configure the user (if env is defined)
diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker
deleted file mode 100644
index 8476fc8..0000000
--- a/tests/docker/dockerfiles/debian-armel-cross.docker
+++ /dev/null
@@ -1,179 +0,0 @@
-# THIS FILE WAS AUTO-GENERATED
-#
-# $ lcitool dockerfile --layers all --cross-arch armv6l debian-11 qemu
-#
-# https://gitlab.com/libvirt/libvirt-ci
-
-FROM docker.io/library/debian:11-slim
-
-RUN export DEBIAN_FRONTEND=noninteractive && \
- apt-get update && \
- apt-get install -y eatmydata && \
- eatmydata apt-get dist-upgrade -y && \
- eatmydata apt-get install --no-install-recommends -y \
- bash \
- bc \
- bison \
- bsdextrautils \
- bzip2 \
- ca-certificates \
- ccache \
- dbus \
- debianutils \
- diffutils \
- exuberant-ctags \
- findutils \
- flex \
- gcc \
- gcovr \
- gettext \
- git \
- hostname \
- libglib2.0-dev \
- libgtk-vnc-2.0-dev \
- libpcre2-dev \
- libsndio-dev \
- libspice-protocol-dev \
- llvm \
- locales \
- make \
- meson \
- mtools \
- ncat \
- ninja-build \
- openssh-client \
- pkgconf \
- python3 \
- python3-numpy \
- python3-opencv \
- python3-pillow \
- python3-pip \
- python3-setuptools \
- python3-sphinx \
- python3-sphinx-rtd-theme \
- python3-venv \
- python3-wheel \
- python3-yaml \
- rpm2cpio \
- sed \
- socat \
- sparse \
- tar \
- tesseract-ocr \
- tesseract-ocr-eng \
- xorriso \
- zstd && \
- eatmydata apt-get autoremove -y && \
- eatmydata apt-get autoclean -y && \
- sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \
- dpkg-reconfigure locales && \
- rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED
-
-RUN /usr/bin/pip3 install tomli
-
-ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
-ENV LANG "en_US.UTF-8"
-ENV MAKE "/usr/bin/make"
-ENV NINJA "/usr/bin/ninja"
-ENV PYTHON "/usr/bin/python3"
-
-RUN export DEBIAN_FRONTEND=noninteractive && \
- dpkg --add-architecture armel && \
- eatmydata apt-get update && \
- eatmydata apt-get dist-upgrade -y && \
- eatmydata apt-get install --no-install-recommends -y dpkg-dev && \
- eatmydata apt-get install --no-install-recommends -y \
- gcc-arm-linux-gnueabi \
- libaio-dev:armel \
- libasan6:armel \
- libasound2-dev:armel \
- libattr1-dev:armel \
- libbpf-dev:armel \
- libbrlapi-dev:armel \
- libbz2-dev:armel \
- libc6-dev:armel \
- libcacard-dev:armel \
- libcap-ng-dev:armel \
- libcapstone-dev:armel \
- libcmocka-dev:armel \
- libcurl4-gnutls-dev:armel \
- libdaxctl-dev:armel \
- libdrm-dev:armel \
- libepoxy-dev:armel \
- libfdt-dev:armel \
- libffi-dev:armel \
- libfuse3-dev:armel \
- libgbm-dev:armel \
- libgcrypt20-dev:armel \
- libglib2.0-dev:armel \
- libglusterfs-dev:armel \
- libgnutls28-dev:armel \
- libgtk-3-dev:armel \
- libibverbs-dev:armel \
- libiscsi-dev:armel \
- libjemalloc-dev:armel \
- libjpeg62-turbo-dev:armel \
- libjson-c-dev:armel \
- liblttng-ust-dev:armel \
- liblzo2-dev:armel \
- libncursesw5-dev:armel \
- libnfs-dev:armel \
- libnuma-dev:armel \
- libpam0g-dev:armel \
- libpipewire-0.3-dev:armel \
- libpixman-1-dev:armel \
- libpng-dev:armel \
- libpulse-dev:armel \
- librbd-dev:armel \
- librdmacm-dev:armel \
- libsasl2-dev:armel \
- libsdl2-dev:armel \
- libsdl2-image-dev:armel \
- libseccomp-dev:armel \
- libselinux1-dev:armel \
- libslirp-dev:armel \
- libsnappy-dev:armel \
- libspice-server-dev:armel \
- libssh-gcrypt-dev:armel \
- libsystemd-dev:armel \
- libtasn1-6-dev:armel \
- libubsan1:armel \
- libudev-dev:armel \
- liburing-dev:armel \
- libusb-1.0-0-dev:armel \
- libusbredirhost-dev:armel \
- libvdeplug-dev:armel \
- libvirglrenderer-dev:armel \
- libvte-2.91-dev:armel \
- libzstd-dev:armel \
- nettle-dev:armel \
- systemtap-sdt-dev:armel \
- zlib1g-dev:armel && \
- eatmydata apt-get autoremove -y && \
- eatmydata apt-get autoclean -y && \
- mkdir -p /usr/local/share/meson/cross && \
- printf "[binaries]\n\
-c = '/usr/bin/arm-linux-gnueabi-gcc'\n\
-ar = '/usr/bin/arm-linux-gnueabi-gcc-ar'\n\
-strip = '/usr/bin/arm-linux-gnueabi-strip'\n\
-pkgconfig = '/usr/bin/arm-linux-gnueabi-pkg-config'\n\
-\n\
-[host_machine]\n\
-system = 'linux'\n\
-cpu_family = 'arm'\n\
-cpu = 'arm'\n\
-endian = 'little'\n" > /usr/local/share/meson/cross/arm-linux-gnueabi && \
- dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \
- mkdir -p /usr/libexec/ccache-wrappers && \
- ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-cc && \
- ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-gcc
-
-ENV ABI "arm-linux-gnueabi"
-ENV MESON_OPTS "--cross-file=arm-linux-gnueabi"
-ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabi-
-ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user,armeb-linux-user
-# As a final step configure the user (if env is defined)
-ARG USER
-ARG UID
-RUN if [ "${USER}" ]; then \
- id ${USER} 2>/dev/null || useradd -u ${UID} -U ${USER}; fi
diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker
index f26385e..f0e2efc 100644
--- a/tests/docker/dockerfiles/debian-armhf-cross.docker
+++ b/tests/docker/dockerfiles/debian-armhf-cross.docker
@@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
eatmydata apt-get install --no-install-recommends -y \
bash \
bc \
+ bindgen \
bison \
bsdextrautils \
bzip2 \
@@ -30,10 +31,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
- libgtk-vnc-2.0-dev \
- libpcre2-dev \
- libsndio-dev \
- libspice-protocol-dev \
llvm \
locales \
make \
@@ -53,6 +50,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3-venv \
python3-yaml \
rpm2cpio \
+ rustc-web \
sed \
socat \
sparse \
@@ -60,6 +58,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
tar \
tesseract-ocr \
tesseract-ocr-eng \
+ vulkan-tools \
xorriso \
zstd && \
eatmydata apt-get autoremove -y && \
@@ -92,6 +91,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libcacard-dev:armhf \
libcap-ng-dev:armhf \
libcapstone-dev:armhf \
+ libcbor-dev:armhf \
libcmocka-dev:armhf \
libcurl4-gnutls-dev:armhf \
libdaxctl-dev:armhf \
@@ -106,6 +106,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libglusterfs-dev:armhf \
libgnutls28-dev:armhf \
libgtk-3-dev:armhf \
+ libgtk-vnc-2.0-dev:armhf \
libibverbs-dev:armhf \
libiscsi-dev:armhf \
libjemalloc-dev:armhf \
@@ -117,6 +118,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libnfs-dev:armhf \
libnuma-dev:armhf \
libpam0g-dev:armhf \
+ libpcre2-dev:armhf \
libpipewire-0.3-dev:armhf \
libpixman-1-dev:armhf \
libpng-dev:armhf \
@@ -130,8 +132,10 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libselinux1-dev:armhf \
libslirp-dev:armhf \
libsnappy-dev:armhf \
+ libsndio-dev:armhf \
+ libspice-protocol-dev:armhf \
libspice-server-dev:armhf \
- libssh-gcrypt-dev:armhf \
+ libssh-dev:armhf \
libsystemd-dev:armhf \
libtasn1-6-dev:armhf \
libubsan1:armhf \
@@ -169,6 +173,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/arm-linux-gnueabihf && \
ENV ABI "arm-linux-gnueabihf"
ENV MESON_OPTS "--cross-file=arm-linux-gnueabihf"
+ENV RUST_TARGET "armv7-unknown-linux-gnueabihf"
ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabihf-
ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user
# As a final step configure the user (if env is defined)
diff --git a/tests/docker/dockerfiles/debian-i686-cross.docker b/tests/docker/dockerfiles/debian-i686-cross.docker
index 3fe8ee6..025beb1 100644
--- a/tests/docker/dockerfiles/debian-i686-cross.docker
+++ b/tests/docker/dockerfiles/debian-i686-cross.docker
@@ -1,10 +1,10 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile --layers all --cross-arch i686 debian-11 qemu
+# $ lcitool dockerfile --layers all --cross-arch i686 debian-12 qemu
#
# https://gitlab.com/libvirt/libvirt-ci
-FROM docker.io/library/debian:11-slim
+FROM docker.io/library/debian:12-slim
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
@@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
eatmydata apt-get install --no-install-recommends -y \
bash \
bc \
+ bindgen \
bison \
bsdextrautils \
bzip2 \
@@ -30,10 +31,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
- libgtk-vnc-2.0-dev \
- libpcre2-dev \
- libsndio-dev \
- libspice-protocol-dev \
llvm \
locales \
make \
@@ -48,19 +45,20 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3-opencv \
python3-pillow \
python3-pip \
- python3-setuptools \
python3-sphinx \
python3-sphinx-rtd-theme \
python3-venv \
- python3-wheel \
python3-yaml \
rpm2cpio \
+ rustc-web \
sed \
socat \
sparse \
+ swtpm \
tar \
tesseract-ocr \
tesseract-ocr-eng \
+ vulkan-tools \
xorriso \
zstd && \
eatmydata apt-get autoremove -y && \
@@ -69,8 +67,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
dpkg-reconfigure locales && \
rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED
-RUN /usr/bin/pip3 install tomli
-
ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
ENV LANG "en_US.UTF-8"
ENV MAKE "/usr/bin/make"
@@ -95,6 +91,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libcacard-dev:i386 \
libcap-ng-dev:i386 \
libcapstone-dev:i386 \
+ libcbor-dev:i386 \
libcmocka-dev:i386 \
libcurl4-gnutls-dev:i386 \
libdaxctl-dev:i386 \
@@ -109,6 +106,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libglusterfs-dev:i386 \
libgnutls28-dev:i386 \
libgtk-3-dev:i386 \
+ libgtk-vnc-2.0-dev:i386 \
libibverbs-dev:i386 \
libiscsi-dev:i386 \
libjemalloc-dev:i386 \
@@ -120,6 +118,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libnfs-dev:i386 \
libnuma-dev:i386 \
libpam0g-dev:i386 \
+ libpcre2-dev:i386 \
libpipewire-0.3-dev:i386 \
libpixman-1-dev:i386 \
libpng-dev:i386 \
@@ -133,8 +132,10 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libselinux1-dev:i386 \
libslirp-dev:i386 \
libsnappy-dev:i386 \
+ libsndio-dev:i386 \
+ libspice-protocol-dev:i386 \
libspice-server-dev:i386 \
- libssh-gcrypt-dev:i386 \
+ libssh-dev:i386 \
libsystemd-dev:i386 \
libtasn1-6-dev:i386 \
libubsan1:i386 \
@@ -145,6 +146,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libvdeplug-dev:i386 \
libvirglrenderer-dev:i386 \
libvte-2.91-dev:i386 \
+ libxdp-dev:i386 \
libzstd-dev:i386 \
nettle-dev:i386 \
systemtap-sdt-dev:i386 \
@@ -170,6 +172,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/i686-linux-gnu && \
ENV ABI "i686-linux-gnu"
ENV MESON_OPTS "--cross-file=i686-linux-gnu"
+ENV RUST_TARGET "i686-unknown-linux-gnu"
ENV QEMU_CONFIGURE_OPTS --cross-prefix=i686-linux-gnu-
ENV DEF_TARGET_LIST x86_64-softmmu,x86_64-linux-user,i386-softmmu,i386-linux-user
# As a final step configure the user (if env is defined)
diff --git a/tests/docker/dockerfiles/debian-loongarch-cross.docker b/tests/docker/dockerfiles/debian-loongarch-cross.docker
index 79eab56..538ab53 100644
--- a/tests/docker/dockerfiles/debian-loongarch-cross.docker
+++ b/tests/docker/dockerfiles/debian-loongarch-cross.docker
@@ -43,8 +43,8 @@ RUN curl -#SL https://github.com/loongson/build-tools/releases/download/2023.08.
ENV PATH $PATH:/opt/cross-tools/bin
ENV LD_LIBRARY_PATH /opt/cross-tools/lib:/opt/cross-tools/loongarch64-unknown-linux-gnu/lib:$LD_LIBRARY_PATH
-ENV QEMU_CONFIGURE_OPTS --disable-system --disable-docs --disable-tools
-ENV DEF_TARGET_LIST loongarch64-linux-user,loongarch-softmmu
+ENV QEMU_CONFIGURE_OPTS --disable-docs --disable-tools
+ENV DEF_TARGET_LIST loongarch64-linux-user,loongarch64-softmmu
ENV MAKE /usr/bin/make
# As a final step configure the user (if env is defined)
diff --git a/tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh b/tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh
index 23ec0aa..c5cd0aa 100755
--- a/tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh
+++ b/tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh
@@ -10,6 +10,8 @@ TOOLCHAIN_INSTALL=/usr/local
TOOLCHAIN_BIN=${TOOLCHAIN_INSTALL}/bin
CROSS_SYSROOT=${TOOLCHAIN_INSTALL}/$TARGET/sys-root
+GCC_PATCH0_URL=https://raw.githubusercontent.com/Xilinx/meta-xilinx/refs/tags/xlnx-rel-v2024.1/meta-microblaze/recipes-devtools/gcc/gcc-12/0009-Patch-microblaze-Fix-atomic-boolean-return-value.patch
+
export PATH=${TOOLCHAIN_BIN}:$PATH
#
@@ -31,6 +33,12 @@ mv gcc-11.2.0 src-gcc
mv musl-1.2.2 src-musl
mv linux-5.10.70 src-linux
+#
+# Patch gcc
+#
+
+wget -O - ${GCC_PATCH0_URL} | patch -d src-gcc -p1
+
mkdir -p bld-hdr bld-binu bld-gcc bld-musl
mkdir -p ${CROSS_SYSROOT}/usr/include
diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker
index 2862785..4a941dd 100644
--- a/tests/docker/dockerfiles/debian-mips64el-cross.docker
+++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker
@@ -1,10 +1,10 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile --layers all --cross-arch mips64el debian-11 qemu
+# $ lcitool dockerfile --layers all --cross-arch mips64el debian-12 qemu
#
# https://gitlab.com/libvirt/libvirt-ci
-FROM docker.io/library/debian:11-slim
+FROM docker.io/library/debian:12-slim
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
@@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
eatmydata apt-get install --no-install-recommends -y \
bash \
bc \
+ bindgen \
bison \
bsdextrautils \
bzip2 \
@@ -30,10 +31,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
- libgtk-vnc-2.0-dev \
- libpcre2-dev \
- libsndio-dev \
- libspice-protocol-dev \
llvm \
locales \
make \
@@ -48,19 +45,20 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3-opencv \
python3-pillow \
python3-pip \
- python3-setuptools \
python3-sphinx \
python3-sphinx-rtd-theme \
python3-venv \
- python3-wheel \
python3-yaml \
rpm2cpio \
+ rustc-web \
sed \
socat \
sparse \
+ swtpm \
tar \
tesseract-ocr \
tesseract-ocr-eng \
+ vulkan-tools \
xorriso \
zstd && \
eatmydata apt-get autoremove -y && \
@@ -69,8 +67,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
dpkg-reconfigure locales && \
rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED
-RUN /usr/bin/pip3 install tomli
-
ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
ENV LANG "en_US.UTF-8"
ENV MAKE "/usr/bin/make"
@@ -94,6 +90,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libcacard-dev:mips64el \
libcap-ng-dev:mips64el \
libcapstone-dev:mips64el \
+ libcbor-dev:mips64el \
libcmocka-dev:mips64el \
libcurl4-gnutls-dev:mips64el \
libdaxctl-dev:mips64el \
@@ -108,6 +105,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libglusterfs-dev:mips64el \
libgnutls28-dev:mips64el \
libgtk-3-dev:mips64el \
+ libgtk-vnc-2.0-dev:mips64el \
libibverbs-dev:mips64el \
libiscsi-dev:mips64el \
libjemalloc-dev:mips64el \
@@ -119,6 +117,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libnfs-dev:mips64el \
libnuma-dev:mips64el \
libpam0g-dev:mips64el \
+ libpcre2-dev:mips64el \
libpipewire-0.3-dev:mips64el \
libpixman-1-dev:mips64el \
libpng-dev:mips64el \
@@ -132,8 +131,10 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libselinux1-dev:mips64el \
libslirp-dev:mips64el \
libsnappy-dev:mips64el \
+ libsndio-dev:mips64el \
+ libspice-protocol-dev:mips64el \
libspice-server-dev:mips64el \
- libssh-gcrypt-dev:mips64el \
+ libssh-dev:mips64el \
libsystemd-dev:mips64el \
libtasn1-6-dev:mips64el \
libudev-dev:mips64el \
@@ -143,6 +144,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libvdeplug-dev:mips64el \
libvirglrenderer-dev:mips64el \
libvte-2.91-dev:mips64el \
+ libxdp-dev:mips64el \
libzstd-dev:mips64el \
nettle-dev:mips64el \
systemtap-sdt-dev:mips64el \
@@ -168,6 +170,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/mips64el-linux-gnuabi64 && \
ENV ABI "mips64el-linux-gnuabi64"
ENV MESON_OPTS "--cross-file=mips64el-linux-gnuabi64"
+ENV RUST_TARGET "mips64el-unknown-linux-gnuabi64"
ENV QEMU_CONFIGURE_OPTS --cross-prefix=mips64el-linux-gnuabi64-
ENV DEF_TARGET_LIST mips64el-softmmu,mips64el-linux-user
# As a final step configure the user (if env is defined)
diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker
index 0d559ae..4d3e5d7 100644
--- a/tests/docker/dockerfiles/debian-mipsel-cross.docker
+++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker
@@ -1,10 +1,10 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile --layers all --cross-arch mipsel debian-11 qemu
+# $ lcitool dockerfile --layers all --cross-arch mipsel debian-12 qemu
#
# https://gitlab.com/libvirt/libvirt-ci
-FROM docker.io/library/debian:11-slim
+FROM docker.io/library/debian:12-slim
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
@@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
eatmydata apt-get install --no-install-recommends -y \
bash \
bc \
+ bindgen \
bison \
bsdextrautils \
bzip2 \
@@ -30,10 +31,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
- libgtk-vnc-2.0-dev \
- libpcre2-dev \
- libsndio-dev \
- libspice-protocol-dev \
llvm \
locales \
make \
@@ -48,19 +45,20 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3-opencv \
python3-pillow \
python3-pip \
- python3-setuptools \
python3-sphinx \
python3-sphinx-rtd-theme \
python3-venv \
- python3-wheel \
python3-yaml \
rpm2cpio \
+ rustc-web \
sed \
socat \
sparse \
+ swtpm \
tar \
tesseract-ocr \
tesseract-ocr-eng \
+ vulkan-tools \
xorriso \
zstd && \
eatmydata apt-get autoremove -y && \
@@ -69,8 +67,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
dpkg-reconfigure locales && \
rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED
-RUN /usr/bin/pip3 install tomli
-
ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
ENV LANG "en_US.UTF-8"
ENV MAKE "/usr/bin/make"
@@ -94,6 +90,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libcacard-dev:mipsel \
libcap-ng-dev:mipsel \
libcapstone-dev:mipsel \
+ libcbor-dev:mipsel \
libcmocka-dev:mipsel \
libcurl4-gnutls-dev:mipsel \
libdaxctl-dev:mipsel \
@@ -108,6 +105,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libglusterfs-dev:mipsel \
libgnutls28-dev:mipsel \
libgtk-3-dev:mipsel \
+ libgtk-vnc-2.0-dev:mipsel \
libibverbs-dev:mipsel \
libiscsi-dev:mipsel \
libjemalloc-dev:mipsel \
@@ -119,6 +117,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libnfs-dev:mipsel \
libnuma-dev:mipsel \
libpam0g-dev:mipsel \
+ libpcre2-dev:mipsel \
libpipewire-0.3-dev:mipsel \
libpixman-1-dev:mipsel \
libpng-dev:mipsel \
@@ -132,8 +131,10 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libselinux1-dev:mipsel \
libslirp-dev:mipsel \
libsnappy-dev:mipsel \
+ libsndio-dev:mipsel \
+ libspice-protocol-dev:mipsel \
libspice-server-dev:mipsel \
- libssh-gcrypt-dev:mipsel \
+ libssh-dev:mipsel \
libsystemd-dev:mipsel \
libtasn1-6-dev:mipsel \
libudev-dev:mipsel \
@@ -143,6 +144,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libvdeplug-dev:mipsel \
libvirglrenderer-dev:mipsel \
libvte-2.91-dev:mipsel \
+ libxdp-dev:mipsel \
libzstd-dev:mipsel \
nettle-dev:mipsel \
systemtap-sdt-dev:mipsel \
@@ -168,6 +170,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/mipsel-linux-gnu && \
ENV ABI "mipsel-linux-gnu"
ENV MESON_OPTS "--cross-file=mipsel-linux-gnu"
+ENV RUST_TARGET "mipsel-unknown-linux-gnu"
ENV QEMU_CONFIGURE_OPTS --cross-prefix=mipsel-linux-gnu-
ENV DEF_TARGET_LIST mipsel-softmmu,mipsel-linux-user
# As a final step configure the user (if env is defined)
diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker
index 8c1dcec..22b4457 100644
--- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker
+++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker
@@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
eatmydata apt-get install --no-install-recommends -y \
bash \
bc \
+ bindgen \
bison \
bsdextrautils \
bzip2 \
@@ -30,10 +31,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
- libgtk-vnc-2.0-dev \
- libpcre2-dev \
- libsndio-dev \
- libspice-protocol-dev \
llvm \
locales \
make \
@@ -53,6 +50,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3-venv \
python3-yaml \
rpm2cpio \
+ rustc-web \
sed \
socat \
sparse \
@@ -60,6 +58,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
tar \
tesseract-ocr \
tesseract-ocr-eng \
+ vulkan-tools \
xorriso \
zstd && \
eatmydata apt-get autoremove -y && \
@@ -92,6 +91,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libcacard-dev:ppc64el \
libcap-ng-dev:ppc64el \
libcapstone-dev:ppc64el \
+ libcbor-dev:ppc64el \
libcmocka-dev:ppc64el \
libcurl4-gnutls-dev:ppc64el \
libdaxctl-dev:ppc64el \
@@ -106,6 +106,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libglusterfs-dev:ppc64el \
libgnutls28-dev:ppc64el \
libgtk-3-dev:ppc64el \
+ libgtk-vnc-2.0-dev:ppc64el \
libibverbs-dev:ppc64el \
libiscsi-dev:ppc64el \
libjemalloc-dev:ppc64el \
@@ -117,6 +118,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libnfs-dev:ppc64el \
libnuma-dev:ppc64el \
libpam0g-dev:ppc64el \
+ libpcre2-dev:ppc64el \
libpipewire-0.3-dev:ppc64el \
libpixman-1-dev:ppc64el \
libpng-dev:ppc64el \
@@ -130,8 +132,10 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libselinux1-dev:ppc64el \
libslirp-dev:ppc64el \
libsnappy-dev:ppc64el \
+ libsndio-dev:ppc64el \
+ libspice-protocol-dev:ppc64el \
libspice-server-dev:ppc64el \
- libssh-gcrypt-dev:ppc64el \
+ libssh-dev:ppc64el \
libsystemd-dev:ppc64el \
libtasn1-6-dev:ppc64el \
libubsan1:ppc64el \
@@ -168,6 +172,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/powerpc64le-linux-gnu && \
ENV ABI "powerpc64le-linux-gnu"
ENV MESON_OPTS "--cross-file=powerpc64le-linux-gnu"
+ENV RUST_TARGET "powerpc64le-unknown-linux-gnu"
ENV QEMU_CONFIGURE_OPTS --cross-prefix=powerpc64le-linux-gnu-
ENV DEF_TARGET_LIST ppc64-softmmu,ppc64-linux-user
# As a final step configure the user (if env is defined)
diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker
index 4d8ca83..b0386cd 100644
--- a/tests/docker/dockerfiles/debian-riscv64-cross.docker
+++ b/tests/docker/dockerfiles/debian-riscv64-cross.docker
@@ -1,10 +1,10 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile --layers all --cross-arch riscv64 debian-sid qemu-minimal
+# $ lcitool dockerfile --layers all --cross-arch riscv64 debian-13 qemu-minimal
#
# https://gitlab.com/libvirt/libvirt-ci
-FROM docker.io/library/debian:sid-slim
+FROM docker.io/library/debian:trixie-slim
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker
index 72668e0..13ec52c 100644
--- a/tests/docker/dockerfiles/debian-s390x-cross.docker
+++ b/tests/docker/dockerfiles/debian-s390x-cross.docker
@@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
eatmydata apt-get install --no-install-recommends -y \
bash \
bc \
+ bindgen \
bison \
bsdextrautils \
bzip2 \
@@ -30,10 +31,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
- libgtk-vnc-2.0-dev \
- libpcre2-dev \
- libsndio-dev \
- libspice-protocol-dev \
llvm \
locales \
make \
@@ -53,6 +50,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3-venv \
python3-yaml \
rpm2cpio \
+ rustc-web \
sed \
socat \
sparse \
@@ -60,6 +58,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
tar \
tesseract-ocr \
tesseract-ocr-eng \
+ vulkan-tools \
xorriso \
zstd && \
eatmydata apt-get autoremove -y && \
@@ -92,6 +91,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libcacard-dev:s390x \
libcap-ng-dev:s390x \
libcapstone-dev:s390x \
+ libcbor-dev:s390x \
libcmocka-dev:s390x \
libcurl4-gnutls-dev:s390x \
libdaxctl-dev:s390x \
@@ -106,6 +106,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libglusterfs-dev:s390x \
libgnutls28-dev:s390x \
libgtk-3-dev:s390x \
+ libgtk-vnc-2.0-dev:s390x \
libibverbs-dev:s390x \
libiscsi-dev:s390x \
libjemalloc-dev:s390x \
@@ -117,6 +118,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libnfs-dev:s390x \
libnuma-dev:s390x \
libpam0g-dev:s390x \
+ libpcre2-dev:s390x \
libpipewire-0.3-dev:s390x \
libpixman-1-dev:s390x \
libpng-dev:s390x \
@@ -130,7 +132,9 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libselinux1-dev:s390x \
libslirp-dev:s390x \
libsnappy-dev:s390x \
- libssh-gcrypt-dev:s390x \
+ libsndio-dev:s390x \
+ libspice-protocol-dev:s390x \
+ libssh-dev:s390x \
libsystemd-dev:s390x \
libtasn1-6-dev:s390x \
libubsan1:s390x \
@@ -167,6 +171,7 @@ endian = 'big'\n" > /usr/local/share/meson/cross/s390x-linux-gnu && \
ENV ABI "s390x-linux-gnu"
ENV MESON_OPTS "--cross-file=s390x-linux-gnu"
+ENV RUST_TARGET "s390x-unknown-linux-gnu"
ENV QEMU_CONFIGURE_OPTS --cross-prefix=s390x-linux-gnu-
ENV DEF_TARGET_LIST s390x-softmmu,s390x-linux-user
# As a final step configure the user (if env is defined)
diff --git a/tests/docker/dockerfiles/debian-toolchain.docker b/tests/docker/dockerfiles/debian-toolchain.docker
index 687a97f..ab4ce29 100644
--- a/tests/docker/dockerfiles/debian-toolchain.docker
+++ b/tests/docker/dockerfiles/debian-toolchain.docker
@@ -10,6 +10,8 @@ FROM docker.io/library/debian:11-slim
# ??? The build-dep isn't working, missing a number of
# minimal build dependiencies, e.g. libmpc.
+RUN sed 's/^deb /deb-src /' </etc/apt/sources.list >/etc/apt/sources.list.d/deb-src.list
+
RUN apt update && \
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
DEBIAN_FRONTEND=noninteractive eatmydata \
@@ -33,6 +35,11 @@ RUN cd /root && ./build-toolchain.sh
# and the build trees by restoring the original image,
# then copying the built toolchain from stage 0.
FROM docker.io/library/debian:11-slim
+RUN apt update && \
+ DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
+ DEBIAN_FRONTEND=noninteractive eatmydata \
+ apt install -y --no-install-recommends \
+ libmpc3
COPY --from=0 /usr/local /usr/local
# As a final step configure the user (if env is defined)
ARG USER
diff --git a/tests/docker/dockerfiles/debian-tricore-cross.docker b/tests/docker/dockerfiles/debian-tricore-cross.docker
index 479b4d6..7e00e87 100644
--- a/tests/docker/dockerfiles/debian-tricore-cross.docker
+++ b/tests/docker/dockerfiles/debian-tricore-cross.docker
@@ -11,8 +11,6 @@
#
FROM docker.io/library/debian:11-slim
-MAINTAINER Philippe Mathieu-Daudé <f4bug@amsat.org>
-
RUN apt update && \
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
DEBIAN_FRONTEND=noninteractive eatmydata apt install -yy \
diff --git a/tests/docker/dockerfiles/debian.docker b/tests/docker/dockerfiles/debian.docker
index 42bd006..0a57c1a 100644
--- a/tests/docker/dockerfiles/debian.docker
+++ b/tests/docker/dockerfiles/debian.docker
@@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
eatmydata apt-get install --no-install-recommends -y \
bash \
bc \
+ bindgen \
bison \
bsdextrautils \
bzip2 \
@@ -41,6 +42,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libcacard-dev \
libcap-ng-dev \
libcapstone-dev \
+ libcbor-dev \
libcmocka-dev \
libcurl4-gnutls-dev \
libdaxctl-dev \
@@ -85,7 +87,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libsndio-dev \
libspice-protocol-dev \
libspice-server-dev \
- libssh-gcrypt-dev \
+ libssh-dev \
libsystemd-dev \
libtasn1-6-dev \
libubsan1 \
@@ -120,6 +122,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3-venv \
python3-yaml \
rpm2cpio \
+ rustc-web \
sed \
socat \
sparse \
@@ -128,6 +131,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
tar \
tesseract-ocr \
tesseract-ocr-eng \
+ vulkan-tools \
xorriso \
zlib1g-dev \
zstd && \
diff --git a/tests/docker/dockerfiles/emsdk-wasm32-cross.docker b/tests/docker/dockerfiles/emsdk-wasm32-cross.docker
new file mode 100644
index 0000000..60a7d02
--- /dev/null
+++ b/tests/docker/dockerfiles/emsdk-wasm32-cross.docker
@@ -0,0 +1,145 @@
+# syntax = docker/dockerfile:1.5
+
+ARG EMSDK_VERSION_QEMU=3.1.50
+ARG ZLIB_VERSION=1.3.1
+ARG GLIB_MINOR_VERSION=2.84
+ARG GLIB_VERSION=${GLIB_MINOR_VERSION}.0
+ARG PIXMAN_VERSION=0.44.2
+ARG FFI_VERSION=v3.4.7
+ARG MESON_VERSION=1.5.0
+
+FROM emscripten/emsdk:$EMSDK_VERSION_QEMU AS build-base
+ARG MESON_VERSION
+ENV TARGET=/builddeps/target
+ENV CPATH="$TARGET/include"
+ENV PKG_CONFIG_PATH="$TARGET/lib/pkgconfig"
+ENV EM_PKG_CONFIG_PATH="$PKG_CONFIG_PATH"
+ENV CFLAGS="-O3 -pthread -DWASM_BIGINT"
+ENV CXXFLAGS="$CFLAGS"
+ENV LDFLAGS="-sWASM_BIGINT -sASYNCIFY=1 -L$TARGET/lib"
+RUN apt-get update && apt-get install -y \
+ autoconf \
+ build-essential \
+ libglib2.0-dev \
+ libtool \
+ pkgconf \
+ ninja-build \
+ python3-pip
+RUN pip3 install meson==${MESON_VERSION} tomli
+RUN mkdir /build
+WORKDIR /build
+RUN mkdir -p $TARGET
+RUN <<EOF
+cat <<EOT > /cross.meson
+[host_machine]
+system = 'emscripten'
+cpu_family = 'wasm32'
+cpu = 'wasm32'
+endian = 'little'
+
+[binaries]
+c = 'emcc'
+cpp = 'em++'
+ar = 'emar'
+ranlib = 'emranlib'
+pkgconfig = ['pkg-config', '--static']
+EOT
+EOF
+
+FROM build-base AS zlib-dev
+ARG ZLIB_VERSION
+RUN mkdir -p /zlib
+RUN curl -Ls https://zlib.net/zlib-$ZLIB_VERSION.tar.xz | \
+ tar xJC /zlib --strip-components=1
+WORKDIR /zlib
+RUN emconfigure ./configure --prefix=$TARGET --static
+RUN emmake make install -j$(nproc)
+
+FROM build-base AS libffi-dev
+ARG FFI_VERSION
+RUN mkdir -p /libffi
+RUN git clone https://github.com/libffi/libffi /libffi
+WORKDIR /libffi
+RUN git checkout $FFI_VERSION
+RUN autoreconf -fiv
+RUN emconfigure ./configure --host=wasm32-unknown-linux \
+ --prefix=$TARGET --enable-static \
+ --disable-shared --disable-dependency-tracking \
+ --disable-builddir --disable-multi-os-directory \
+ --disable-raw-api --disable-docs
+RUN emmake make install SUBDIRS='include' -j$(nproc)
+
+FROM build-base AS pixman-dev
+ARG PIXMAN_VERSION
+RUN mkdir /pixman/
+RUN git clone https://gitlab.freedesktop.org/pixman/pixman /pixman/
+WORKDIR /pixman
+RUN git checkout pixman-$PIXMAN_VERSION
+RUN <<EOF
+cat <<EOT >> /cross.meson
+[built-in options]
+c_args = [$(printf "'%s', " $CFLAGS | sed 's/, $//')]
+cpp_args = [$(printf "'%s', " $CFLAGS | sed 's/, $//')]
+objc_args = [$(printf "'%s', " $CFLAGS | sed 's/, $//')]
+c_link_args = [$(printf "'%s', " $LDFLAGS | sed 's/, $//')]
+cpp_link_args = [$(printf "'%s', " $LDFLAGS | sed 's/, $//')]
+EOT
+EOF
+RUN meson setup _build --prefix=$TARGET --cross-file=/cross.meson \
+ --default-library=static \
+ --buildtype=release -Dtests=disabled -Ddemos=disabled
+RUN meson install -C _build
+
+FROM build-base AS glib-dev
+ARG GLIB_VERSION
+ARG GLIB_MINOR_VERSION
+RUN mkdir -p /stub
+WORKDIR /stub
+RUN <<EOF
+cat <<'EOT' > res_query.c
+#include <netdb.h>
+int res_query(const char *name, int class,
+ int type, unsigned char *dest, int len)
+{
+ h_errno = HOST_NOT_FOUND;
+ return -1;
+}
+EOT
+EOF
+RUN emcc ${CFLAGS} -c res_query.c -fPIC -o libresolv.o
+RUN ar rcs libresolv.a libresolv.o
+RUN mkdir -p $TARGET/lib/
+RUN cp libresolv.a $TARGET/lib/
+
+RUN mkdir -p /glib
+RUN curl -Lks https://download.gnome.org/sources/glib/${GLIB_MINOR_VERSION}/glib-$GLIB_VERSION.tar.xz | \
+ tar xJC /glib --strip-components=1
+
+COPY --link --from=zlib-dev /builddeps/ /builddeps/
+COPY --link --from=libffi-dev /builddeps/ /builddeps/
+
+WORKDIR /glib
+RUN <<EOF
+CFLAGS="$CFLAGS -Wno-incompatible-function-pointer-types" ;
+cat <<EOT >> /cross.meson
+[built-in options]
+c_args = [$(printf "'%s', " $CFLAGS | sed 's/, $//')]
+cpp_args = [$(printf "'%s', " $CFLAGS | sed 's/, $//')]
+objc_args = [$(printf "'%s', " $CFLAGS | sed 's/, $//')]
+c_link_args = [$(printf "'%s', " $LDFLAGS | sed 's/, $//')]
+cpp_link_args = [$(printf "'%s', " $LDFLAGS | sed 's/, $//')]
+EOT
+EOF
+RUN meson setup _build --prefix=$TARGET --cross-file=/cross.meson \
+ --default-library=static --buildtype=release --force-fallback-for=pcre2 \
+ -Dselinux=disabled -Dxattr=false -Dlibmount=disabled -Dnls=disabled \
+ -Dtests=false -Dglib_debug=disabled -Dglib_assert=false -Dglib_checks=false
+# FIXME: emscripten doesn't provide some pthread functions in the final link,
+# which isn't detected during meson setup.
+RUN sed -i -E "/#define HAVE_POSIX_SPAWN 1/d" ./_build/config.h
+RUN sed -i -E "/#define HAVE_PTHREAD_GETNAME_NP 1/d" ./_build/config.h
+RUN meson install -C _build
+
+FROM build-base
+COPY --link --from=glib-dev /builddeps/ /builddeps/
+COPY --link --from=pixman-dev /builddeps/ /builddeps/
diff --git a/tests/docker/dockerfiles/fedora-cris-cross.docker b/tests/docker/dockerfiles/fedora-cris-cross.docker
deleted file mode 100644
index 97c9d37..0000000
--- a/tests/docker/dockerfiles/fedora-cris-cross.docker
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Cross compiler for cris system tests
-#
-
-FROM registry.fedoraproject.org/fedora:33
-ENV PACKAGES gcc-cris-linux-gnu
-ENV MAKE /usr/bin/make
-RUN dnf install -y $PACKAGES
-RUN rpm -q $PACKAGES | sort > /packages.txt
-# As a final step configure the user (if env is defined)
-ARG USER
-ARG UID
-RUN if [ "${USER}" ]; then \
- id ${USER} 2>/dev/null || useradd -u ${UID} -U ${USER}; fi
diff --git a/tests/docker/dockerfiles/fedora-rust-nightly.docker b/tests/docker/dockerfiles/fedora-rust-nightly.docker
new file mode 100644
index 0000000..4a03330
--- /dev/null
+++ b/tests/docker/dockerfiles/fedora-rust-nightly.docker
@@ -0,0 +1,183 @@
+# THIS FILE WAS AUTO-GENERATED
+#
+# $ lcitool dockerfile --layers all fedora-40 qemu
+#
+# https://gitlab.com/libvirt/libvirt-ci
+
+FROM registry.fedoraproject.org/fedora:40
+
+RUN dnf install -y nosync && \
+ printf '#!/bin/sh\n\
+if test -d /usr/lib64\n\
+then\n\
+ export LD_PRELOAD=/usr/lib64/nosync/nosync.so\n\
+else\n\
+ export LD_PRELOAD=/usr/lib/nosync/nosync.so\n\
+fi\n\
+exec "$@"\n' > /usr/bin/nosync && \
+ chmod +x /usr/bin/nosync && \
+ nosync dnf update -y && \
+ nosync dnf install -y \
+ SDL2-devel \
+ SDL2_image-devel \
+ alsa-lib-devel \
+ bash \
+ bc \
+ bindgen-cli \
+ bison \
+ brlapi-devel \
+ bzip2 \
+ bzip2-devel \
+ ca-certificates \
+ capstone-devel \
+ ccache \
+ clang \
+ ctags \
+ cyrus-sasl-devel \
+ daxctl-devel \
+ dbus-daemon \
+ device-mapper-multipath-devel \
+ diffutils \
+ findutils \
+ flex \
+ fuse3-devel \
+ gcc \
+ gcovr \
+ gettext \
+ git \
+ glib2-devel \
+ glib2-static \
+ glibc-langpack-en \
+ glibc-static \
+ glusterfs-api-devel \
+ gnutls-devel \
+ gtk-vnc2-devel \
+ gtk3-devel \
+ hostname \
+ jemalloc-devel \
+ json-c-devel \
+ libaio-devel \
+ libasan \
+ libattr-devel \
+ libbpf-devel \
+ libcacard-devel \
+ libcap-ng-devel \
+ libcbor-devel \
+ libcmocka-devel \
+ libcurl-devel \
+ libdrm-devel \
+ libepoxy-devel \
+ libfdt-devel \
+ libffi-devel \
+ libgcrypt-devel \
+ libiscsi-devel \
+ libjpeg-devel \
+ libnfs-devel \
+ libpmem-devel \
+ libpng-devel \
+ librbd-devel \
+ libseccomp-devel \
+ libselinux-devel \
+ libslirp-devel \
+ libssh-devel \
+ libtasn1-devel \
+ libubsan \
+ liburing-devel \
+ libusbx-devel \
+ libxdp-devel \
+ libzstd-devel \
+ llvm \
+ lttng-ust-devel \
+ lzo-devel \
+ make \
+ mesa-libgbm-devel \
+ meson \
+ mtools \
+ ncurses-devel \
+ nettle-devel \
+ ninja-build \
+ nmap-ncat \
+ numactl-devel \
+ openssh-clients \
+ pam-devel \
+ pcre-static \
+ pipewire-devel \
+ pixman-devel \
+ pkgconfig \
+ pulseaudio-libs-devel \
+ python3 \
+ python3-PyYAML \
+ python3-numpy \
+ python3-opencv \
+ python3-pillow \
+ python3-pip \
+ python3-sphinx \
+ python3-sphinx_rtd_theme \
+ python3-zombie-imp \
+ rdma-core-devel \
+ rust \
+ sed \
+ snappy-devel \
+ socat \
+ sparse \
+ spice-protocol \
+ spice-server-devel \
+ swtpm \
+ systemd-devel \
+ systemtap-sdt-devel \
+ tar \
+ tesseract \
+ tesseract-langpack-eng \
+ usbredir-devel \
+ util-linux \
+ virglrenderer-devel \
+ vte291-devel \
+ vulkan-tools \
+ which \
+ xen-devel \
+ xorriso \
+ zlib-devel \
+ zlib-static \
+ zstd && \
+ nosync dnf autoremove -y && \
+ nosync dnf clean all -y && \
+ rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED && \
+ rpm -qa | sort > /packages.txt && \
+ mkdir -p /usr/libexec/ccache-wrappers && \
+ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \
+ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \
+ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
+
+ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
+ENV LANG "en_US.UTF-8"
+ENV MAKE "/usr/bin/make"
+ENV NINJA "/usr/bin/ninja"
+ENV PYTHON "/usr/bin/python3"
+RUN dnf install -y wget
+ENV RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo
+ENV RUSTC=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc
+ENV RUSTDOC=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustdoc
+ENV CARGO=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo
+RUN set -eux && \
+ rustArch='x86_64-unknown-linux-gnu' && \
+ rustupSha256='6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d' && \
+ url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" && \
+ wget "$url" && \
+ echo "${rustupSha256} *rustup-init" | sha256sum -c - && \
+ chmod +x rustup-init && \
+ ./rustup-init -y --no-modify-path --profile default --default-toolchain nightly --default-host ${rustArch} && \
+ chmod -R a+w $RUSTUP_HOME $CARGO_HOME && \
+ /usr/local/cargo/bin/rustup --version && \
+ /usr/local/cargo/bin/rustup run nightly cargo --version && \
+ /usr/local/cargo/bin/rustup run nightly rustc --version && \
+ test "$CARGO" = "$(/usr/local/cargo/bin/rustup +nightly which cargo)" && \
+ test "$RUSTDOC" = "$(/usr/local/cargo/bin/rustup +nightly which rustdoc)" && \
+ test "$RUSTC" = "$(/usr/local/cargo/bin/rustup +nightly which rustc)"
+ENV PATH=$CARGO_HOME/bin:$PATH
+RUN /usr/local/cargo/bin/rustup run nightly cargo install bindgen-cli
+RUN $CARGO --list
+# As a final step configure the user (if env is defined)
+ARG USER
+ARG UID
+RUN if [ "${USER}" ]; then \
+ id ${USER} 2>/dev/null || useradd -u ${UID} -U ${USER}; fi
diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker
index 6b264d9..a950344 100644
--- a/tests/docker/dockerfiles/fedora-win64-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win64-cross.docker
@@ -20,6 +20,7 @@ exec "$@"\n' > /usr/bin/nosync && \
nosync dnf install -y \
bash \
bc \
+ bindgen-cli \
bison \
bzip2 \
ca-certificates \
@@ -34,7 +35,6 @@ exec "$@"\n' > /usr/bin/nosync && \
git \
glib2-devel \
glibc-langpack-en \
- gtk-vnc2-devel \
hostname \
llvm \
make \
@@ -43,7 +43,6 @@ exec "$@"\n' > /usr/bin/nosync && \
ninja-build \
nmap-ncat \
openssh-clients \
- pcre-static \
python3 \
python3-PyYAML \
python3-numpy \
@@ -53,15 +52,16 @@ exec "$@"\n' > /usr/bin/nosync && \
python3-sphinx \
python3-sphinx_rtd_theme \
python3-zombie-imp \
+ rust \
sed \
socat \
sparse \
- spice-protocol \
swtpm \
tar \
tesseract \
tesseract-langpack-eng \
util-linux \
+ vulkan-tools \
which \
xorriso \
zstd && \
@@ -87,6 +87,7 @@ RUN nosync dnf install -y \
mingw64-gettext \
mingw64-glib2 \
mingw64-gnutls \
+ mingw64-gtk-vnc2 \
mingw64-gtk3 \
mingw64-libepoxy \
mingw64-libgcrypt \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index ecdefaf..014e3cc 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -23,6 +23,7 @@ exec "$@"\n' > /usr/bin/nosync && \
alsa-lib-devel \
bash \
bc \
+ bindgen-cli \
bison \
brlapi-devel \
bzip2 \
@@ -61,6 +62,7 @@ exec "$@"\n' > /usr/bin/nosync && \
libbpf-devel \
libcacard-devel \
libcap-ng-devel \
+ libcbor-devel \
libcmocka-devel \
libcurl-devel \
libdrm-devel \
@@ -113,6 +115,7 @@ exec "$@"\n' > /usr/bin/nosync && \
python3-sphinx_rtd_theme \
python3-zombie-imp \
rdma-core-devel \
+ rust \
sed \
snappy-devel \
socat \
@@ -129,6 +132,7 @@ exec "$@"\n' > /usr/bin/nosync && \
util-linux \
virglrenderer-devel \
vte291-devel \
+ vulkan-tools \
which \
xen-devel \
xorriso \
diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker
index 6614362..e90225d 100644
--- a/tests/docker/dockerfiles/opensuse-leap.docker
+++ b/tests/docker/dockerfiles/opensuse-leap.docker
@@ -4,9 +4,10 @@
#
# https://gitlab.com/libvirt/libvirt-ci
-FROM registry.opensuse.org/opensuse/leap:15.5
+FROM registry.opensuse.org/opensuse/leap:15.6
RUN zypper update -y && \
+ zypper addrepo -fc https://download.opensuse.org/update/leap/15.6/backports/openSUSE:Backports:SLE-15-SP6:Update.repo && \
zypper install -y \
Mesa-devel \
alsa-lib-devel \
@@ -46,6 +47,7 @@ RUN zypper update -y && \
libbz2-devel \
libcacard-devel \
libcap-ng-devel \
+ libcbor-devel \
libcmocka-devel \
libcurl-devel \
libdrm-devel \
@@ -95,6 +97,8 @@ RUN zypper update -y && \
python311-pip \
python311-setuptools \
rdma-core-devel \
+ rust \
+ rust-bindgen \
sed \
snappy-devel \
sndio-devel \
@@ -111,6 +115,7 @@ RUN zypper update -y && \
util-linux \
virglrenderer-devel \
vte-devel \
+ vulkan-tools \
which \
xen-devel \
xorriso \
@@ -127,7 +132,7 @@ RUN zypper update -y && \
RUN /usr/bin/pip3.11 install \
PyYAML \
- meson==0.63.2 \
+ meson==1.5.0 \
pillow \
sphinx \
sphinx-rtd-theme
diff --git a/tests/docker/dockerfiles/python.docker b/tests/docker/dockerfiles/python.docker
index 8f0af9e..59e70a0 100644
--- a/tests/docker/dockerfiles/python.docker
+++ b/tests/docker/dockerfiles/python.docker
@@ -15,7 +15,6 @@ ENV PACKAGES \
python3.11 \
python3.12 \
python3.13 \
- python3.8 \
python3.9
RUN dnf install -y $PACKAGES
diff --git a/tests/docker/dockerfiles/ubuntu2204.docker b/tests/docker/dockerfiles/ubuntu2204.docker
index 3a7de6a..28a6f93 100644
--- a/tests/docker/dockerfiles/ubuntu2204.docker
+++ b/tests/docker/dockerfiles/ubuntu2204.docker
@@ -41,6 +41,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libcacard-dev \
libcap-ng-dev \
libcapstone-dev \
+ libcbor-dev \
libcmocka-dev \
libcurl4-gnutls-dev \
libdaxctl-dev \
@@ -120,6 +121,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3-venv \
python3-yaml \
rpm2cpio \
+ rustc-1.77 \
sed \
socat \
sparse \
@@ -128,6 +130,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
tar \
tesseract-ocr \
tesseract-ocr-eng \
+ vulkan-tools \
xorriso \
zlib1g-dev \
zstd && \
@@ -147,6 +150,13 @@ ENV LANG "en_US.UTF-8"
ENV MAKE "/usr/bin/make"
ENV NINJA "/usr/bin/ninja"
ENV PYTHON "/usr/bin/python3"
+ENV RUSTC=/usr/bin/rustc-1.77
+ENV RUSTDOC=/usr/bin/rustdoc-1.77
+ENV CARGO_HOME=/usr/local/cargo
+ENV PATH=$CARGO_HOME/bin:$PATH
+RUN DEBIAN_FRONTEND=noninteractive eatmydata \
+ apt install -y --no-install-recommends cargo
+RUN cargo install bindgen-cli
# As a final step configure the user (if env is defined)
ARG USER
ARG UID
diff --git a/tests/docker/test-debug b/tests/docker/test-debug
index f52f163..678cecc 100755
--- a/tests/docker/test-debug
+++ b/tests/docker/test-debug
@@ -1,6 +1,6 @@
#!/bin/bash -e
#
-# Compile and check with clang & --enable-debug --enable-sanitizers.
+# Compile and check with clang & debug & sanitizers
#
# Copyright (c) 2016-2018 Red Hat Inc.
#
@@ -19,7 +19,7 @@ requires_binary clang
cd "$BUILD_DIR"
OPTS="--cxx=clang++ --cc=clang --host-cc=clang"
-OPTS="--enable-debug --enable-sanitizers $OPTS"
+OPTS="--enable-debug --enable-asan --enable-ubsan $OPTS"
export ASAN_OPTIONS=detect_leaks=0
build_qemu $OPTS
diff --git a/tests/docker/test-rust b/tests/docker/test-rust
new file mode 100755
index 0000000..e7e3e94
--- /dev/null
+++ b/tests/docker/test-rust
@@ -0,0 +1,21 @@
+#!/bin/bash -e
+#
+# Run the rust code checks (a.k.a. check-rust-tools-nightly)
+#
+# Copyright (c) 2025 Linaro Ltd
+#
+# Authors:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# This work is licensed under the terms of the GNU GPL, version 2
+# or (at your option) any later version. See the COPYING file in
+# the top-level directory.
+
+. common.rc
+
+cd "$BUILD_DIR"
+
+configure_qemu --disable-user --disable-docs --enable-rust
+pyvenv/bin/meson devenv -w $QEMU_SRC/rust ${CARGO-cargo} fmt --check
+make clippy
+make rustdoc
diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c
index 8ce0ca1..d90f542 100644
--- a/tests/fp/fp-bench.c
+++ b/tests/fp/fp-bench.c
@@ -488,6 +488,16 @@ static void run_bench(void)
{
bench_func_t f;
+ /*
+ * These implementation-defined choices for various things IEEE
+ * doesn't specify match those used by the Arm architecture.
+ */
+ set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status);
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, &soft_status);
+ set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &soft_status);
+ set_float_default_nan_pattern(0b01000000, &soft_status);
+ set_float_ftz_detection(float_ftz_before_rounding, &soft_status);
+
f = bench_funcs[operation][precision];
g_assert(f);
f();
diff --git a/tests/fp/fp-test-log2.c b/tests/fp/fp-test-log2.c
index 4eae93e..79f619c 100644
--- a/tests/fp/fp-test-log2.c
+++ b/tests/fp/fp-test-log2.c
@@ -70,6 +70,8 @@ int main(int ac, char **av)
float_status qsf = {0};
int i;
+ set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
+ set_float_default_nan_pattern(0b01000000, &qsf);
set_float_rounding_mode(float_round_nearest_even, &qsf);
test.d = 0.0;
diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
index 36b5712..c619e5d 100644
--- a/tests/fp/fp-test.c
+++ b/tests/fp/fp-test.c
@@ -935,6 +935,15 @@ void run_test(void)
{
unsigned int i;
+ /*
+ * These implementation-defined choices for various things IEEE
+ * doesn't specify match those used by the Arm architecture.
+ */
+ set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, &qsf);
+ set_float_default_nan_pattern(0b01000000, &qsf);
+ set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &qsf);
+
genCases_setLevel(test_level);
verCases_maxErrorCount = n_max_errors;
diff --git a/tests/fp/meson.build b/tests/fp/meson.build
index 114b4b4..9059a24 100644
--- a/tests/fp/meson.build
+++ b/tests/fp/meson.build
@@ -7,6 +7,16 @@ if host_os == 'windows'
subdir_done()
endif
+# By default tests run with the usual 30s timeout; particularly
+# slow tests can have that overridden here. The keys here are
+# the testnames without their fp-test- prefix.
+slow_fp_tests = {
+ 'rem': 60,
+ 'div': 60,
+ 'mul': 60,
+ 'mulAdd': 180,
+}
+
sfcflags = [
# softfloat defines
'-DSOFTFLOAT_ROUND_ODD',
@@ -109,6 +119,7 @@ fptest_rounding_args = ['-r', 'all']
foreach k, v : softfloat_conv_tests
test('fp-test-' + k, fptest,
args: fptest_args + fptest_rounding_args + v.split(),
+ timeout: slow_fp_tests.get(k, 30),
suite: ['softfloat', 'softfloat-conv'])
endforeach
@@ -116,6 +127,7 @@ foreach k, v : softfloat_tests
test('fp-test-' + k, fptest,
args: fptest_args + fptest_rounding_args +
['f16_' + k, 'f32_' + k, 'f64_' + k, 'f128_' + k, 'extF80_' + k],
+ timeout: slow_fp_tests.get(k, 30),
suite: ['softfloat', 'softfloat-' + v])
endforeach
@@ -124,7 +136,8 @@ test('fp-test-mulAdd', fptest,
# no fptest_rounding_args
args: fptest_args +
['f16_mulAdd', 'f32_mulAdd', 'f64_mulAdd', 'f128_mulAdd'],
- suite: ['softfloat-slow', 'softfloat-ops-slow', 'slow'], timeout: 180)
+ timeout: slow_fp_tests.get('mulAdd', 30),
+ suite: ['softfloat-slow', 'softfloat-ops-slow', 'slow'])
executable(
'fp-bench',
@@ -140,4 +153,5 @@ fptestlog2 = executable(
c_args: fpcflags,
)
test('fp-test-log2', fptestlog2,
+ timeout: slow_fp_tests.get('log2', 30),
suite: ['softfloat', 'softfloat-ops'])
diff --git a/tests/functional/aspeed.py b/tests/functional/aspeed.py
new file mode 100644
index 0000000..7a40d5d
--- /dev/null
+++ b/tests/functional/aspeed.py
@@ -0,0 +1,58 @@
+# Test class to boot aspeed machines
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test import LinuxKernelTest
+
+class AspeedTest(LinuxKernelTest):
+
+ def do_test_arm_aspeed_openbmc(self, machine, image, uboot='2019.04',
+ cpu_id='0x0', soc='AST2500 rev A1'):
+ hostname = machine.removesuffix('-bmc')
+
+ self.set_machine(machine)
+ self.vm.set_console()
+ self.vm.add_args('-drive', f'file={image},if=mtd,format=raw',
+ '-snapshot')
+ self.vm.launch()
+
+ self.wait_for_console_pattern(f'U-Boot {uboot}')
+ self.wait_for_console_pattern('## Loading kernel from FIT Image')
+ self.wait_for_console_pattern('Starting kernel ...')
+ self.wait_for_console_pattern(f'Booting Linux on physical CPU {cpu_id}')
+ self.wait_for_console_pattern(f'ASPEED {soc}')
+ self.wait_for_console_pattern('/init as init process')
+ self.wait_for_console_pattern(f'systemd[1]: Hostname set to <{hostname}>.')
+
+ def do_test_arm_aspeed_buildroot_start(self, image, cpu_id, pattern='Aspeed EVB'):
+ self.require_netdev('user')
+ self.vm.set_console()
+ self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw,read-only=true',
+ '-net', 'nic', '-net', 'user')
+ self.vm.launch()
+
+ self.wait_for_console_pattern('U-Boot 2019.04')
+ self.wait_for_console_pattern('## Loading kernel from FIT Image')
+ self.wait_for_console_pattern('Starting kernel ...')
+ self.wait_for_console_pattern('Booting Linux on physical CPU ' + cpu_id)
+ self.wait_for_console_pattern('lease of 10.0.2.15')
+ # the line before login:
+ self.wait_for_console_pattern(pattern)
+ exec_command_and_wait_for_pattern(self, 'root', 'Password:')
+ exec_command_and_wait_for_pattern(self, 'passw0rd', '#')
+
+ def do_test_arm_aspeed_buildroot_poweroff(self):
+ exec_command_and_wait_for_pattern(self, 'poweroff',
+ 'System halted')
+
+ def do_test_arm_aspeed_sdk_start(self, image):
+ self.require_netdev('user')
+ self.vm.set_console()
+ self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
+ '-net', 'nic', '-net', 'user', '-snapshot')
+ self.vm.launch()
+
+ self.wait_for_console_pattern('U-Boot 2019.04')
+ self.wait_for_console_pattern('## Loading kernel from FIT Image')
+ self.wait_for_console_pattern('Starting kernel ...')
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
index cda89c4..b542b3a 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -11,15 +11,58 @@ endif
# Timeouts for individual tests that can be slow e.g. with debugging enabled
test_timeouts = {
- 'aarch64_sbsaref' : 600,
+ 'aarch64_aspeed_ast2700' : 600,
+ 'aarch64_aspeed_ast2700fc' : 600,
+ 'aarch64_device_passthrough' : 720,
+ 'aarch64_imx8mp_evk' : 240,
+ 'aarch64_raspi4' : 480,
+ 'aarch64_reverse_debug' : 180,
+ 'aarch64_rme_virt' : 1200,
+ 'aarch64_rme_sbsaref' : 1200,
+ 'aarch64_sbsaref_alpine' : 1200,
+ 'aarch64_sbsaref_freebsd' : 720,
+ 'aarch64_smmu' : 720,
+ 'aarch64_tuxrun' : 240,
'aarch64_virt' : 360,
- 'acpi_bits' : 240,
+ 'aarch64_virt_gpu' : 480,
+ 'acpi_bits' : 420,
+ 'arm_aspeed_palmetto' : 120,
+ 'arm_aspeed_romulus' : 120,
+ 'arm_aspeed_witherspoon' : 120,
+ 'arm_aspeed_ast2500' : 720,
+ 'arm_aspeed_ast2600' : 1200,
+ 'arm_aspeed_bletchley' : 480,
+ 'arm_aspeed_rainier' : 480,
+ 'arm_bpim2u' : 500,
+ 'arm_collie' : 180,
+ 'arm_cubieboard' : 360,
+ 'arm_orangepi' : 540,
+ 'arm_quanta_gsj' : 240,
+ 'arm_raspi2' : 120,
+ 'arm_replay' : 240,
+ 'arm_tuxrun' : 240,
+ 'arm_sx1' : 360,
+ 'intel_iommu': 300,
+ 'mips_malta' : 480,
+ 'mipsel_malta' : 420,
+ 'mipsel_replay' : 480,
+ 'mips64_malta' : 240,
+ 'mips64el_malta' : 420,
+ 'mips64el_replay' : 180,
'netdev_ethtool' : 180,
'ppc_40p' : 240,
'ppc64_hv' : 1000,
- 'ppc64_powernv' : 120,
- 'ppc64_pseries' : 120,
- 's390x_ccw_virtio' : 180,
+ 'ppc64_powernv' : 480,
+ 'ppc64_pseries' : 480,
+ 'ppc64_replay' : 210,
+ 'ppc64_tuxrun' : 420,
+ 'ppc64_mac99' : 120,
+ 'riscv64_tuxrun' : 120,
+ 's390x_ccw_virtio' : 420,
+ 'sh4_tuxrun' : 240,
+ 'virtio_balloon': 120,
+ 'x86_64_kvm_xen' : 180,
+ 'x86_64_replay' : 480,
}
tests_generic_system = [
@@ -34,14 +77,75 @@ tests_generic_linuxuser = [
tests_generic_bsduser = [
]
+tests_aarch64_system_quick = [
+ 'migration',
+]
+
tests_aarch64_system_thorough = [
+ 'aarch64_aspeed_ast2700',
+ 'aarch64_aspeed_ast2700fc',
+ 'aarch64_device_passthrough',
+ 'aarch64_hotplug_pci',
+ 'aarch64_imx8mp_evk',
+ 'aarch64_raspi3',
+ 'aarch64_raspi4',
+ 'aarch64_replay',
+ 'aarch64_reverse_debug',
+ 'aarch64_rme_virt',
+ 'aarch64_rme_sbsaref',
'aarch64_sbsaref',
+ 'aarch64_sbsaref_alpine',
+ 'aarch64_sbsaref_freebsd',
+ 'aarch64_smmu',
+ 'aarch64_tcg_plugins',
+ 'aarch64_tuxrun',
'aarch64_virt',
+ 'aarch64_virt_gpu',
+ 'aarch64_xen',
+ 'aarch64_xlnx_versal',
+ 'multiprocess',
+]
+
+tests_alpha_system_quick = [
+ 'migration',
+]
+
+tests_alpha_system_thorough = [
+ 'alpha_clipper',
+ 'alpha_replay',
+]
+
+tests_arm_system_quick = [
+ 'migration',
]
tests_arm_system_thorough = [
+ 'arm_aspeed_ast1030',
+ 'arm_aspeed_palmetto',
+ 'arm_aspeed_romulus',
+ 'arm_aspeed_witherspoon',
+ 'arm_aspeed_ast2500',
+ 'arm_aspeed_ast2600',
+ 'arm_aspeed_bletchley',
+ 'arm_aspeed_rainier',
+ 'arm_bpim2u',
'arm_canona1100',
+ 'arm_collie',
+ 'arm_cubieboard',
+ 'arm_emcraft_sf2',
'arm_integratorcp',
+ 'arm_microbit',
+ 'arm_orangepi',
+ 'arm_quanta_gsj',
+ 'arm_raspi2',
+ 'arm_realview',
+ 'arm_replay',
+ 'arm_smdkc210',
+ 'arm_stellaris',
+ 'arm_sx1',
+ 'arm_vexpress',
+ 'arm_virt',
+ 'arm_tuxrun',
]
tests_arm_linuxuser_thorough = [
@@ -50,6 +154,20 @@ tests_arm_linuxuser_thorough = [
tests_avr_system_thorough = [
'avr_mega2560',
+ 'avr_uno',
+]
+
+tests_hppa_system_quick = [
+ 'hppa_seabios',
+]
+
+tests_i386_system_quick = [
+ 'migration',
+]
+
+tests_i386_system_thorough = [
+ 'i386_replay',
+ 'i386_tuxrun',
]
tests_loongarch64_system_thorough = [
@@ -57,10 +175,15 @@ tests_loongarch64_system_thorough = [
]
tests_m68k_system_thorough = [
- 'm68k_nextcube'
+ 'm68k_mcf5208evb',
+ 'm68k_nextcube',
+ 'm68k_replay',
+ 'm68k_q800',
+ 'm68k_tuxrun',
]
tests_microblaze_system_thorough = [
+ 'microblaze_replay',
'microblaze_s3adsp1800'
]
@@ -68,31 +191,84 @@ tests_microblazeel_system_thorough = [
'microblazeel_s3adsp1800'
]
-tests_mips64el_system_quick = [
- 'mips64el_fuloong2e',
+tests_mips_system_thorough = [
+ 'mips_malta',
+ 'mips_replay',
+ 'mips_tuxrun',
+]
+
+tests_mipsel_system_thorough = [
+ 'mipsel_malta',
+ 'mipsel_replay',
+ 'mipsel_tuxrun',
+]
+
+tests_mips64_system_thorough = [
+ 'mips64_malta',
+ 'mips64_tuxrun',
]
tests_mips64el_system_thorough = [
+ 'mips64el_fuloong2e',
'mips64el_loongson3v',
+ 'mips64el_malta',
+ 'mips64el_replay',
+ 'mips64el_tuxrun',
+]
+
+tests_or1k_system_thorough = [
+ 'or1k_replay',
+ 'or1k_sim',
]
tests_ppc_system_quick = [
+ 'migration',
'ppc_74xx',
]
tests_ppc_system_thorough = [
- 'ppc_405',
'ppc_40p',
'ppc_amiga',
'ppc_bamboo',
+ 'ppc_mac',
'ppc_mpc8544ds',
+ 'ppc_replay',
+ 'ppc_sam460ex',
+ 'ppc_tuxrun',
'ppc_virtex_ml507',
]
+tests_ppc64_system_quick = [
+ 'migration',
+]
+
tests_ppc64_system_thorough = [
+ 'ppc64_e500',
'ppc64_hv',
'ppc64_powernv',
'ppc64_pseries',
+ 'ppc64_replay',
+ 'ppc64_reverse_debug',
+ 'ppc64_tuxrun',
+ 'ppc64_mac99',
+]
+
+tests_riscv32_system_quick = [
+ 'migration',
+ 'riscv_opensbi',
+]
+
+tests_riscv32_system_thorough = [
+ 'riscv32_tuxrun',
+]
+
+tests_riscv64_system_quick = [
+ 'migration',
+ 'riscv_opensbi',
+]
+
+tests_riscv64_system_thorough = [
+ 'riscv64_tuxrun',
]
tests_rx_system_thorough = [
@@ -101,26 +277,68 @@ tests_rx_system_thorough = [
tests_s390x_system_thorough = [
's390x_ccw_virtio',
+ 's390x_replay',
's390x_topology',
+ 's390x_tuxrun',
+]
+
+tests_sh4_system_thorough = [
+ 'sh4_r2d',
+ 'sh4_tuxrun',
+]
+
+tests_sh4eb_system_thorough = [
+ 'sh4eb_r2d',
+]
+
+tests_sparc_system_quick = [
+ 'migration',
+]
+
+tests_sparc_system_thorough = [
+ 'sparc_replay',
+ 'sparc_sun4m',
+]
+
+tests_sparc64_system_quick = [
+ 'migration',
]
tests_sparc64_system_thorough = [
'sparc64_sun4u',
+ 'sparc64_tuxrun',
]
tests_x86_64_system_quick = [
'cpu_queries',
'mem_addr_space',
+ 'migration',
'pc_cpu_hotplug_props',
'virtio_version',
'x86_cpu_model_versions',
+ 'vnc',
+ 'memlock',
]
tests_x86_64_system_thorough = [
'acpi_bits',
+ 'intel_iommu',
'linux_initrd',
+ 'multiprocess',
'netdev_ethtool',
+ 'virtio_balloon',
'virtio_gpu',
+ 'x86_64_hotplug_blk',
+ 'x86_64_hotplug_cpu',
+ 'x86_64_kvm_xen',
+ 'x86_64_replay',
+ 'x86_64_reverse_debug',
+ 'x86_64_tuxrun',
+]
+
+tests_xtensa_system_thorough = [
+ 'xtensa_lx60',
+ 'xtensa_replay',
]
precache_all = []
@@ -189,12 +407,12 @@ foreach speed : ['quick', 'thorough']
# 'run_target' logic below & in Makefile.include
test('func-' + testname,
python,
- depends: [test_deps, test_emulator, emulator_modules],
+ depends: [test_deps, test_emulator, emulator_modules, plugin_modules],
env: test_env,
args: [testpath],
protocol: 'tap',
- timeout: test_timeouts.get(test, 60),
- priority: test_timeouts.get(test, 60),
+ timeout: test_timeouts.get(test, 90),
+ priority: test_timeouts.get(test, 90),
suite: suites)
endforeach
endforeach
@@ -202,4 +420,4 @@ endforeach
run_target('precache-functional',
depends: precache_all,
- command: ['true'])
+ command: [python, '-c', ''])
diff --git a/tests/functional/qemu_test/__init__.py b/tests/functional/qemu_test/__init__.py
index f33282e..6e666a0 100644
--- a/tests/functional/qemu_test/__init__.py
+++ b/tests/functional/qemu_test/__init__.py
@@ -7,8 +7,14 @@
from .asset import Asset
-from .config import BUILD_DIR
-from .cmd import has_cmd, has_cmds, run_cmd, is_readable_executable_file, \
+from .config import BUILD_DIR, dso_suffix
+from .cmd import is_readable_executable_file, \
interrupt_interactive_console_until_pattern, wait_for_console_pattern, \
- exec_command, exec_command_and_wait_for_pattern, get_qemu_img
+ exec_command, exec_command_and_wait_for_pattern, get_qemu_img, which
from .testcase import QemuBaseTest, QemuUserTest, QemuSystemTest
+from .linuxkernel import LinuxKernelTest
+from .decorators import skipIfMissingCommands, skipIfNotMachine, \
+ skipFlakyTest, skipUntrustedTest, skipBigDataTest, skipSlowTest, \
+ skipIfMissingImports, skipIfOperatingSystem, skipLockedMemoryTest
+from .archive import archive_extract
+from .uncompress import uncompress
diff --git a/tests/functional/qemu_test/archive.py b/tests/functional/qemu_test/archive.py
new file mode 100644
index 0000000..c803fda
--- /dev/null
+++ b/tests/functional/qemu_test/archive.py
@@ -0,0 +1,117 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Utilities for python-based QEMU tests
+#
+# Copyright 2024 Red Hat, Inc.
+#
+# Authors:
+# Thomas Huth <thuth@redhat.com>
+
+import os
+from subprocess import check_call, run, DEVNULL
+import tarfile
+from urllib.parse import urlparse
+import zipfile
+
+from .asset import Asset
+
+
+def tar_extract(archive, dest_dir, member=None):
+ with tarfile.open(archive) as tf:
+ if hasattr(tarfile, 'data_filter'):
+ tf.extraction_filter = getattr(tarfile, 'data_filter',
+ (lambda member, path: member))
+ if member:
+ tf.extract(member=member, path=dest_dir)
+ else:
+ tf.extractall(path=dest_dir)
+
+def cpio_extract(archive, output_path):
+ cwd = os.getcwd()
+ os.chdir(output_path)
+ # Not passing 'check=True' as cpio exits with non-zero
+ # status if the archive contains any device nodes :-(
+ if type(archive) == str:
+ run(['cpio', '-i', '-F', archive],
+ stdout=DEVNULL, stderr=DEVNULL)
+ else:
+ run(['cpio', '-i'],
+ input=archive.read(),
+ stdout=DEVNULL, stderr=DEVNULL)
+ os.chdir(cwd)
+
+def zip_extract(archive, dest_dir, member=None):
+ with zipfile.ZipFile(archive, 'r') as zf:
+ if member:
+ zf.extract(member=member, path=dest_dir)
+ else:
+ zf.extractall(path=dest_dir)
+
+def deb_extract(archive, dest_dir, member=None):
+ cwd = os.getcwd()
+ os.chdir(dest_dir)
+ try:
+ proc = run(['ar', 't', archive],
+ check=True, capture_output=True, encoding='utf8')
+ file_path = proc.stdout.split()[2]
+ check_call(['ar', 'x', archive, file_path],
+ stdout=DEVNULL, stderr=DEVNULL)
+ tar_extract(file_path, dest_dir, member)
+ finally:
+ os.chdir(cwd)
+
+'''
+@params archive: filename, Asset, or file-like object to extract
+@params dest_dir: target directory to extract into
+@params member: optional member file to limit extraction to
+
+Extracts @archive into @dest_dir. All files are extracted
+unless @member specifies a limit.
+
+If @format is None, heuristics will be applied to guess the format
+from the filename or Asset URL. @format must be non-None if @archive
+is a file-like object.
+'''
+def archive_extract(archive, dest_dir, format=None, member=None):
+ if format is None:
+ format = guess_archive_format(archive)
+ if type(archive) == Asset:
+ archive = str(archive)
+
+ if format == "tar":
+ tar_extract(archive, dest_dir, member)
+ elif format == "zip":
+ zip_extract(archive, dest_dir, member)
+ elif format == "cpio":
+ if member is not None:
+ raise Exception("Unable to filter cpio extraction")
+ cpio_extract(archive, dest_dir)
+ elif format == "deb":
+ if type(archive) != str:
+ raise Exception("Unable to use file-like object with deb archives")
+ deb_extract(archive, dest_dir, "./" + member)
+ else:
+ raise Exception(f"Unknown archive format {format}")
+
+'''
+@params archive: filename, or Asset to guess
+
+Guess the format of @compressed, raising an exception if
+no format can be determined
+'''
+def guess_archive_format(archive):
+ if type(archive) == Asset:
+ archive = urlparse(archive.url).path
+ elif type(archive) != str:
+ raise Exception(f"Unable to guess archive format for {archive}")
+
+ if ".tar." in archive or archive.endswith("tgz"):
+ return "tar"
+ elif archive.endswith(".zip"):
+ return "zip"
+ elif archive.endswith(".cpio"):
+ return "cpio"
+ elif archive.endswith(".deb") or archive.endswith(".udeb"):
+ return "deb"
+ else:
+ raise Exception(f"Unknown archive format for {archive}")
diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py
index d3be2af..704b84d 100644
--- a/tests/functional/qemu_test/asset.py
+++ b/tests/functional/qemu_test/asset.py
@@ -8,14 +8,23 @@
import hashlib
import logging
import os
-import subprocess
+import stat
import sys
import unittest
import urllib.request
from time import sleep
from pathlib import Path
from shutil import copyfileobj
+from urllib.error import HTTPError
+class AssetError(Exception):
+ def __init__(self, asset, msg, transient=False):
+ self.url = asset.url
+ self.msg = msg
+ self.transient = transient
+
+ def __str__(self):
+ return "%s: %s" % (self.url, self.msg)
# Instances of this class must be declared as class level variables
# starting with a name "ASSET_". This enables the pre-caching logic
@@ -39,23 +48,38 @@ class Asset:
return "Asset: url=%s hash=%s cache=%s" % (
self.url, self.hash, self.cache_file)
+ def __str__(self):
+ return str(self.cache_file)
+
def _check(self, cache_file):
if self.hash is None:
return True
if len(self.hash) == 64:
- sum_prog = 'sha256sum'
+ hl = hashlib.sha256()
elif len(self.hash) == 128:
- sum_prog = 'sha512sum'
+ hl = hashlib.sha512()
else:
- raise Exception("unknown hash type")
+ raise AssetError(self, "unknown hash type")
- checksum = subprocess.check_output(
- [sum_prog, str(cache_file)]).split()[0]
- return self.hash == checksum.decode("utf-8")
+ # Calculate the hash of the file:
+ with open(cache_file, 'rb') as file:
+ while True:
+ chunk = file.read(1 << 20)
+ if not chunk:
+ break
+ hl.update(chunk)
+
+ return self.hash == hl.hexdigest()
def valid(self):
return self.cache_file.exists() and self._check(self.cache_file)
+ def fetchable(self):
+ return not os.environ.get("QEMU_TEST_NO_DOWNLOAD", False)
+
+ def available(self):
+ return self.valid() or self.fetchable()
+
def _wait_for_other_download(self, tmp_cache_file):
# Another thread already seems to download the asset, so wait until
# it is done, while also checking the size to see whether it is stuck
@@ -94,8 +118,9 @@ class Asset:
self.cache_file, self.url)
return str(self.cache_file)
- if os.environ.get("QEMU_TEST_NO_DOWNLOAD", False):
- raise Exception("Asset cache is invalid and downloads disabled")
+ if not self.fetchable():
+ raise AssetError(self,
+ "Asset cache is invalid and downloads disabled")
self.log.info("Downloading %s to %s...", self.url, self.cache_file)
tmp_cache_file = self.cache_file.with_suffix(".download")
@@ -105,6 +130,20 @@ class Asset:
with tmp_cache_file.open("xb") as dst:
with urllib.request.urlopen(self.url) as resp:
copyfileobj(resp, dst)
+ length_hdr = resp.getheader("Content-Length")
+
+ # Verify downloaded file size against length metadata, if
+ # available.
+ if length_hdr is not None:
+ length = int(length_hdr)
+ fsize = tmp_cache_file.stat().st_size
+ if fsize != length:
+ self.log.error("Unable to download %s: "
+ "connection closed before "
+ "transfer complete (%d/%d)",
+ self.url, fsize, length)
+ tmp_cache_file.unlink()
+ continue
break
except FileExistsError:
self.log.debug("%s already exists, "
@@ -117,10 +156,23 @@ class Asset:
tmp_cache_file)
tmp_cache_file.unlink()
continue
+ except HTTPError as e:
+ tmp_cache_file.unlink()
+ self.log.error("Unable to download %s: HTTP error %d",
+ self.url, e.code)
+ # Treat 404 as fatal, since it is highly likely to
+ # indicate a broken test rather than a transient
+ # server or networking problem
+ if e.code == 404:
+ raise AssetError(self, "Unable to download: "
+ "HTTP error %d" % e.code)
+ continue
except Exception as e:
- self.log.error("Unable to download %s: %s", self.url, e)
tmp_cache_file.unlink()
- raise
+ raise AssetError(self, "Unable to download: " % e)
+
+ if not os.path.exists(tmp_cache_file):
+ raise AssetError(self, "Download retries exceeded", transient=True)
try:
# Set these just for informational purposes
@@ -134,9 +186,10 @@ class Asset:
if not self._check(tmp_cache_file):
tmp_cache_file.unlink()
- raise Exception("Hash of %s does not match %s" %
- (self.url, self.hash))
+ raise AssetError(self, "Hash does not match %s" % self.hash)
tmp_cache_file.replace(self.cache_file)
+ # Remove write perms to stop tests accidentally modifying them
+ os.chmod(self.cache_file, stat.S_IRUSR | stat.S_IRGRP)
self.log.info("Cached %s at %s" % (self.url, self.cache_file))
return str(self.cache_file)
@@ -153,7 +206,13 @@ class Asset:
for name, asset in vars(test.__class__).items():
if name.startswith("ASSET_") and type(asset) == Asset:
log.info("Attempting to cache '%s'" % asset)
- asset.fetch()
+ try:
+ asset.fetch()
+ except AssetError as e:
+ if not e.transient:
+ raise
+ log.error("%s: skipping asset precache" % e)
+
log.removeHandler(handler)
def precache_suite(suite):
diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py
index 3acd617..dc5f422 100644
--- a/tests/functional/qemu_test/cmd.py
+++ b/tests/functional/qemu_test/cmd.py
@@ -14,77 +14,93 @@
import logging
import os
import os.path
-import subprocess
-from .config import BUILD_DIR
-
-def has_cmd(name, args=None):
- """
- This function is for use in a @skipUnless decorator, e.g.:
-
- @skipUnless(*has_cmd('sudo -n', ('sudo', '-n', 'true')))
- def test_something_that_needs_sudo(self):
- ...
- """
-
- if args is None:
- args = ('which', name)
-
- try:
- _, stderr, exitcode = run_cmd(args)
- except Exception as e:
- exitcode = -1
- stderr = str(e)
-
- if exitcode != 0:
- cmd_line = ' '.join(args)
- err = f'{name} required, but "{cmd_line}" failed: {stderr.strip()}'
- return (False, err)
- else:
- return (True, '')
-
-def has_cmds(*cmds):
- """
- This function is for use in a @skipUnless decorator and
- allows checking for the availability of multiple commands, e.g.:
-
- @skipUnless(*has_cmds(('cmd1', ('cmd1', '--some-parameter')),
- 'cmd2', 'cmd3'))
- def test_something_that_needs_cmd1_and_cmd2(self):
- ...
+def which(tool):
+ """ looks up the full path for @tool, returns None if not found
+ or if @tool does not have executable permissions.
"""
+ paths=os.getenv('PATH')
+ for p in paths.split(os.path.pathsep):
+ p = os.path.join(p, tool)
+ if os.access(p, os.X_OK):
+ return p
+ return None
- for cmd in cmds:
- if isinstance(cmd, str):
- cmd = (cmd,)
+def is_readable_executable_file(path):
+ return os.path.isfile(path) and os.access(path, os.R_OK | os.X_OK)
- ok, errstr = has_cmd(*cmd)
- if not ok:
- return (False, errstr)
+# @test: functional test to fail if @failure is seen
+# @vm: the VM whose console to process
+# @success: a non-None string to look for
+# @failure: a string to look for that triggers test failure, or None
+#
+# Read up to 1 line of text from @vm, looking for @success
+# and optionally @failure.
+#
+# If @success or @failure are seen, immediately return True,
+# even if end of line is not yet seen. ie remainder of the
+# line is left unread.
+#
+# If end of line is seen, with neither @success or @failure
+# return False
+#
+# If @failure is seen, then mark @test as failed
+def _console_read_line_until_match(test, vm, success, failure):
+ msg = bytes([])
+ done = False
+ while True:
+ c = vm.console_socket.recv(1)
+ if c is None:
+ done = True
+ test.fail(
+ f"EOF in console, expected '{success}'")
+ break
+ msg += c
- return (True, '')
+ if success in msg:
+ done = True
+ break
+ if failure and failure in msg:
+ done = True
+ vm.console_socket.close()
+ test.fail(
+ f"'{failure}' found in console, expected '{success}'")
-def run_cmd(args):
- subp = subprocess.Popen(args,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- universal_newlines=True)
- stdout, stderr = subp.communicate()
- ret = subp.returncode
+ if c == b'\n':
+ break
- return (stdout, stderr, ret)
+ console_logger = logging.getLogger('console')
+ try:
+ console_logger.debug(msg.decode().strip())
+ except:
+ console_logger.debug(msg)
-def is_readable_executable_file(path):
- return os.path.isfile(path) and os.access(path, os.R_OK | os.X_OK)
+ return done
def _console_interaction(test, success_message, failure_message,
send_string, keep_sending=False, vm=None):
assert not keep_sending or send_string
+ assert success_message or send_string
+
if vm is None:
vm = test.vm
- console = vm.console_file
- console_logger = logging.getLogger('console')
+
+ test.log.debug(
+ f"Console interaction: success_msg='{success_message}' " +
+ f"failure_msg='{failure_message}' send_string='{send_string}'")
+
+ # We'll process console in bytes, to avoid having to
+ # deal with unicode decode errors from receiving
+ # partial utf8 byte sequences
+ success_message_b = None
+ if success_message is not None:
+ success_message_b = success_message.encode()
+
+ failure_message_b = None
+ if failure_message is not None:
+ failure_message_b = failure_message.encode()
+
while True:
if send_string:
vm.console_socket.sendall(send_string.encode())
@@ -92,25 +108,15 @@ def _console_interaction(test, success_message, failure_message,
send_string = None # send only once
# Only consume console output if waiting for something
- if success_message is None and failure_message is None:
+ if success_message is None:
if send_string is None:
break
continue
- try:
- msg = console.readline().decode().strip()
- except UnicodeDecodeError:
- msg = None
- if not msg:
- continue
- console_logger.debug(msg)
- if success_message is None or success_message in msg:
+ if _console_read_line_until_match(test, vm,
+ success_message_b,
+ failure_message_b):
break
- if failure_message and failure_message in msg:
- console.close()
- fail = 'Failure message found in console: "%s". Expected: "%s"' % \
- (failure_message, success_message)
- test.fail(fail)
def interrupt_interactive_console_until_pattern(test, success_message,
failure_message=None,
@@ -135,6 +141,7 @@ def interrupt_interactive_console_until_pattern(test, success_message,
:param interrupt_string: a string to send to the console before trying
to read a new line
"""
+ assert success_message
_console_interaction(test, success_message, failure_message,
interrupt_string, True)
@@ -149,6 +156,7 @@ def wait_for_console_pattern(test, success_message, failure_message=None,
:param success_message: if this message appears, test succeeds
:param failure_message: if this message appears, test fails
"""
+ assert success_message
_console_interaction(test, success_message, failure_message, None, vm=vm)
def exec_command(test, command):
@@ -177,6 +185,7 @@ def exec_command_and_wait_for_pattern(test, command,
:param success_message: if this message appears, test succeeds
:param failure_message: if this message appears, test fails
"""
+ assert success_message
_console_interaction(test, success_message, failure_message, command + '\r')
def get_qemu_img(test):
@@ -184,10 +193,10 @@ def get_qemu_img(test):
# If qemu-img has been built, use it, otherwise the system wide one
# will be used.
- qemu_img = os.path.join(BUILD_DIR, 'qemu-img')
+ qemu_img = test.build_file('qemu-img')
if os.path.exists(qemu_img):
return qemu_img
- if has_cmd('qemu-img'):
- return 'qemu-img'
- test.skipTest('Could not find "qemu-img", which is required to '
- 'create temporary images')
+ qemu_img = which('qemu-img')
+ if qemu_img is not None:
+ return qemu_img
+ test.skipTest(f"qemu-img not found in build dir or '$PATH'")
diff --git a/tests/functional/qemu_test/config.py b/tests/functional/qemu_test/config.py
index edd75b7..6d4c9c3 100644
--- a/tests/functional/qemu_test/config.py
+++ b/tests/functional/qemu_test/config.py
@@ -13,6 +13,7 @@
import os
from pathlib import Path
+import platform
def _source_dir():
@@ -34,3 +35,14 @@ def _build_dir():
raise Exception("Cannot identify build dir, set QEMU_BUILD_ROOT")
BUILD_DIR = _build_dir()
+
+def dso_suffix():
+ '''Return the dynamic libraries suffix for the current platform'''
+
+ if platform.system() == "Darwin":
+ return "dylib"
+
+ if platform.system() == "Windows":
+ return "dll"
+
+ return "so"
diff --git a/tests/functional/qemu_test/decorators.py b/tests/functional/qemu_test/decorators.py
new file mode 100644
index 0000000..c0d1567
--- /dev/null
+++ b/tests/functional/qemu_test/decorators.py
@@ -0,0 +1,151 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Decorators useful in functional tests
+
+import importlib
+import os
+import platform
+import resource
+from unittest import skipIf, skipUnless
+
+from .cmd import which
+
+'''
+Decorator to skip execution of a test if the list
+of command binaries is not available in $PATH.
+Example:
+
+ @skipIfMissingCommands("mkisofs", "losetup")
+'''
+def skipIfMissingCommands(*args):
+ has_cmds = True
+ for cmd in args:
+ if not which(cmd):
+ has_cmds = False
+ break
+
+ return skipUnless(has_cmds, 'required command(s) "%s" not installed' %
+ ", ".join(args))
+
+'''
+Decorator to skip execution of a test if the current
+host operating system does match one of the prohibited
+ones.
+Example
+
+ @skipIfOperatingSystem("Linux", "Darwin")
+'''
+def skipIfOperatingSystem(*args):
+ return skipIf(platform.system() in args,
+ 'running on an OS (%s) that is not able to run this test' %
+ ", ".join(args))
+
+'''
+Decorator to skip execution of a test if the current
+host machine does not match one of the permitted
+machines.
+Example
+
+ @skipIfNotMachine("x86_64", "aarch64")
+'''
+def skipIfNotMachine(*args):
+ return skipUnless(platform.machine() in args,
+ 'not running on one of the required machine(s) "%s"' %
+ ", ".join(args))
+
+'''
+Decorator to skip execution of flaky tests, unless
+the $QEMU_TEST_FLAKY_TESTS environment variable is set.
+A bug URL must be provided that documents the observed
+failure behaviour, so it can be tracked & re-evaluated
+in future.
+
+Historical tests may be providing "None" as the bug_url
+but this should not be done for new test.
+
+Example:
+
+ @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/NNN")
+'''
+def skipFlakyTest(bug_url):
+ if bug_url is None:
+ bug_url = "FIXME: reproduce flaky test and file bug report or remove"
+ return skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'),
+ f'Test is unstable: {bug_url}')
+
+'''
+Decorator to skip execution of tests which are likely
+to execute untrusted commands on the host, or commands
+which process untrusted code, unless the
+$QEMU_TEST_ALLOW_UNTRUSTED_CODE env var is set.
+Example:
+
+ @skipUntrustedTest()
+'''
+def skipUntrustedTest():
+ return skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'),
+ 'Test runs untrusted code / processes untrusted data')
+
+'''
+Decorator to skip execution of tests which need large
+data storage (over around 500MB-1GB mark) on the host,
+unless the $QEMU_TEST_ALLOW_LARGE_STORAGE environment
+variable is set
+
+Example:
+
+ @skipBigDataTest()
+'''
+def skipBigDataTest():
+ return skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'),
+ 'Test requires large host storage space')
+
+'''
+Decorator to skip execution of tests which have a really long
+runtime (and might e.g. time out if QEMU has been compiled with
+debugging enabled) unless the $QEMU_TEST_ALLOW_SLOW
+environment variable is set
+
+Example:
+
+ @skipSlowTest()
+'''
+def skipSlowTest():
+ return skipUnless(os.getenv('QEMU_TEST_ALLOW_SLOW'),
+ 'Test has a very long runtime and might time out')
+
+'''
+Decorator to skip execution of a test if the list
+of python imports is not available.
+Example:
+
+ @skipIfMissingImports("numpy", "cv2")
+'''
+def skipIfMissingImports(*args):
+ has_imports = True
+ for impname in args:
+ try:
+ importlib.import_module(impname)
+ except ImportError:
+ has_imports = False
+ break
+
+ return skipUnless(has_imports, 'required import(s) "%s" not installed' %
+ ", ".join(args))
+
+'''
+Decorator to skip execution of a test if the system's
+locked memory limit is below the required threshold.
+Takes required locked memory threshold in kB.
+Example:
+
+ @skipLockedMemoryTest(2_097_152)
+'''
+def skipLockedMemoryTest(locked_memory):
+ # get memlock hard limit in bytes
+ _, ulimit_memory = resource.getrlimit(resource.RLIMIT_MEMLOCK)
+
+ return skipUnless(
+ ulimit_memory == resource.RLIM_INFINITY or ulimit_memory >= locked_memory * 1024,
+ f'Test required {locked_memory} kB of available locked memory',
+ )
diff --git a/tests/functional/qemu_test/linuxkernel.py b/tests/functional/qemu_test/linuxkernel.py
new file mode 100644
index 0000000..2aca0ee
--- /dev/null
+++ b/tests/functional/qemu_test/linuxkernel.py
@@ -0,0 +1,52 @@
+# Test class for testing the boot process of a Linux kernel
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import hashlib
+import urllib.request
+
+from .cmd import wait_for_console_pattern, exec_command_and_wait_for_pattern
+from .testcase import QemuSystemTest
+from .utils import get_usernet_hostfwd_port
+
+
+class LinuxKernelTest(QemuSystemTest):
+ KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
+
+ def wait_for_console_pattern(self, success_message, vm=None):
+ wait_for_console_pattern(self, success_message,
+ failure_message='Kernel panic - not syncing',
+ vm=vm)
+
+ def launch_kernel(self, kernel, initrd=None, dtb=None, console_index=0,
+ wait_for=None):
+ self.vm.set_console(console_index=console_index)
+ self.vm.add_args('-kernel', kernel)
+ if initrd:
+ self.vm.add_args('-initrd', initrd)
+ if dtb:
+ self.vm.add_args('-dtb', dtb)
+ self.vm.launch()
+ if wait_for:
+ self.wait_for_console_pattern(wait_for)
+
+ def check_http_download(self, filename, hashsum, guestport=8080,
+ pythoncmd='python3 -m http.server'):
+ exec_command_and_wait_for_pattern(self,
+ f'{pythoncmd} {guestport} & sleep 1',
+ f'Serving HTTP on 0.0.0.0 port {guestport}')
+ hl = hashlib.sha256()
+ hostport = get_usernet_hostfwd_port(self.vm)
+ url = f'http://localhost:{hostport}{filename}'
+ self.log.info(f'Downloading {url} ...')
+ with urllib.request.urlopen(url) as response:
+ while True:
+ chunk = response.read(1 << 20)
+ if not chunk:
+ break
+ hl.update(chunk)
+
+ digest = hl.hexdigest()
+ self.log.info(f'sha256sum of download is {digest}.')
+ self.assertEqual(digest, hashsum)
diff --git a/tests/functional/qemu_test/ports.py b/tests/functional/qemu_test/ports.py
new file mode 100644
index 0000000..631b77a
--- /dev/null
+++ b/tests/functional/qemu_test/ports.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+#
+# Simple functional tests for VNC functionality
+#
+# Copyright 2018, 2024 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.
+
+import fcntl
+import os
+import socket
+
+from .config import BUILD_DIR
+from typing import List
+
+
+class Ports():
+
+ PORTS_ADDR = '127.0.0.1'
+ PORTS_RANGE_SIZE = 1024
+ PORTS_START = 49152 + ((os.getpid() * PORTS_RANGE_SIZE) % 16384)
+ PORTS_END = PORTS_START + PORTS_RANGE_SIZE
+
+ def __enter__(self):
+ lock_file = os.path.join(BUILD_DIR, "tests", "functional", "port_lock")
+ self.lock_fh = os.open(lock_file, os.O_CREAT)
+ fcntl.flock(self.lock_fh, fcntl.LOCK_EX)
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ fcntl.flock(self.lock_fh, fcntl.LOCK_UN)
+ os.close(self.lock_fh)
+
+ def check_bind(self, port: int) -> bool:
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
+ try:
+ sock.bind((self.PORTS_ADDR, port))
+ except OSError:
+ return False
+
+ return True
+
+ def find_free_ports(self, count: int) -> List[int]:
+ result = []
+ for port in range(self.PORTS_START, self.PORTS_END):
+ if self.check_bind(port):
+ result.append(port)
+ if len(result) >= count:
+ break
+ assert len(result) == count
+ return result
+
+ def find_free_port(self) -> int:
+ return self.find_free_ports(1)[0]
diff --git a/tests/functional/qemu_test/tesseract.py b/tests/functional/qemu_test/tesseract.py
index c4087b7..ede6c65 100644
--- a/tests/functional/qemu_test/tesseract.py
+++ b/tests/functional/qemu_test/tesseract.py
@@ -5,29 +5,19 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-import re
import logging
+from subprocess import run
-from . import has_cmd, run_cmd
-
-def tesseract_available(expected_version):
- if not has_cmd('tesseract'):
- return False
- (stdout, stderr, ret) = run_cmd([ 'tesseract', '--version'])
- if ret:
- return False
- version = stdout.split()[1]
- return int(version.split('.')[0]) >= expected_version
def tesseract_ocr(image_path, tesseract_args=''):
console_logger = logging.getLogger('console')
console_logger.debug(image_path)
- (stdout, stderr, ret) = run_cmd(['tesseract', image_path,
- 'stdout'])
- if ret:
+ proc = run(['tesseract', image_path, 'stdout'],
+ capture_output=True, encoding='utf8')
+ if proc.returncode:
return None
lines = []
- for line in stdout.split('\n'):
+ for line in proc.stdout.split('\n'):
sline = line.strip()
if len(sline):
console_logger.debug(sline)
diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py
index aa01462..2082c6f 100644
--- a/tests/functional/qemu_test/testcase.py
+++ b/tests/functional/qemu_test/testcase.py
@@ -13,49 +13,224 @@
import logging
import os
-import subprocess
+from pathlib import Path
import pycotap
+import shutil
+from subprocess import run
import sys
+import tempfile
import unittest
import uuid
from qemu.machine import QEMUMachine
-from qemu.utils import kvm_available, tcg_available
+from qemu.utils import hvf_available, kvm_available, tcg_available
+from .archive import archive_extract
from .asset import Asset
-from .cmd import run_cmd
-from .config import BUILD_DIR
+from .config import BUILD_DIR, dso_suffix
+from .uncompress import uncompress
class QemuBaseTest(unittest.TestCase):
- qemu_bin = os.getenv('QEMU_TEST_QEMU_BINARY')
- arch = None
-
- workdir = None
- log = None
- logdir = None
+ '''
+ @params compressed: filename, Asset, or file-like object to uncompress
+ @params format: optional compression format (gzip, lzma)
+
+ Uncompresses @compressed into the scratch directory.
+
+ If @format is None, heuristics will be applied to guess the format
+ from the filename or Asset URL. @format must be non-None if @uncompressed
+ is a file-like object.
+
+ Returns the fully qualified path to the uncompressed file
+ '''
+ def uncompress(self, compressed, format=None):
+ self.log.debug(f"Uncompress {compressed} format={format}")
+ if type(compressed) == Asset:
+ compressed.fetch()
+
+ (name, ext) = os.path.splitext(str(compressed))
+ uncompressed = self.scratch_file(os.path.basename(name))
+
+ uncompress(compressed, uncompressed, format)
+
+ return uncompressed
+
+ '''
+ @params archive: filename, Asset, or file-like object to extract
+ @params format: optional archive format (tar, zip, deb, cpio)
+ @params sub_dir: optional sub-directory to extract into
+ @params member: optional member file to limit extraction to
+
+ Extracts @archive into the scratch directory, or a directory beneath
+ named by @sub_dir. All files are extracted unless @member specifies
+ a limit.
+
+ If @format is None, heuristics will be applied to guess the format
+ from the filename or Asset URL. @format must be non-None if @archive
+ is a file-like object.
+
+ If @member is non-None, returns the fully qualified path to @member
+ '''
+ def archive_extract(self, archive, format=None, sub_dir=None, member=None):
+ self.log.debug(f"Extract {archive} format={format}" +
+ f"sub_dir={sub_dir} member={member}")
+ if type(archive) == Asset:
+ archive.fetch()
+ if sub_dir is None:
+ archive_extract(archive, self.scratch_file(), format, member)
+ else:
+ archive_extract(archive, self.scratch_file(sub_dir),
+ format, member)
+
+ if member is not None:
+ return self.scratch_file(member)
+ return None
+
+ '''
+ Create a temporary directory suitable for storing UNIX
+ socket paths.
+
+ Returns: a tempfile.TemporaryDirectory instance
+ '''
+ def socket_dir(self):
+ if self.socketdir is None:
+ self.socketdir = tempfile.TemporaryDirectory(
+ prefix="qemu_func_test_sock_")
+ return self.socketdir
+
+ '''
+ @params args list of zero or more subdirectories or file
+
+ Construct a path for accessing a data file located
+ relative to the source directory that is the root for
+ functional tests.
+
+ @args may be an empty list to reference the root dir
+ itself, may be a single element to reference a file in
+ the root directory, or may be multiple elements to
+ reference a file nested below. The path components
+ will be joined using the platform appropriate path
+ separator.
+
+ Returns: string representing a file path
+ '''
+ def data_file(self, *args):
+ return str(Path(Path(__file__).parent.parent, *args))
+
+ '''
+ @params args list of zero or more subdirectories or file
+
+ Construct a path for accessing a data file located
+ relative to the build directory root.
+
+ @args may be an empty list to reference the build dir
+ itself, may be a single element to reference a file in
+ the build directory, or may be multiple elements to
+ reference a file nested below. The path components
+ will be joined using the platform appropriate path
+ separator.
+
+ Returns: string representing a file path
+ '''
+ def build_file(self, *args):
+ return str(Path(BUILD_DIR, *args))
+
+ '''
+ @params args list of zero or more subdirectories or file
+
+ Construct a path for accessing/creating a scratch file
+ located relative to a temporary directory dedicated to
+ this test case. The directory and its contents will be
+ purged upon completion of the test.
+
+ @args may be an empty list to reference the scratch dir
+ itself, may be a single element to reference a file in
+ the scratch directory, or may be multiple elements to
+ reference a file nested below. The path components
+ will be joined using the platform appropriate path
+ separator.
+
+ Returns: string representing a file path
+ '''
+ def scratch_file(self, *args):
+ return str(Path(self.workdir, *args))
+
+ '''
+ @params args list of zero or more subdirectories or file
+
+ Construct a path for accessing/creating a log file
+ located relative to a temporary directory dedicated to
+ this test case. The directory and its log files will be
+ preserved upon completion of the test.
+
+ @args may be an empty list to reference the log dir
+ itself, may be a single element to reference a file in
+ the log directory, or may be multiple elements to
+ reference a file nested below. The path components
+ will be joined using the platform appropriate path
+ separator.
+
+ Returns: string representing a file path
+ '''
+ def log_file(self, *args):
+ return str(Path(self.outputdir, *args))
+
+ '''
+ @params plugin name
+
+ Return the full path to the plugin taking into account any host OS
+ specific suffixes.
+ '''
+ def plugin_file(self, plugin_name):
+ sfx = dso_suffix()
+ return os.path.join('tests', 'tcg', 'plugins', f'{plugin_name}.{sfx}')
+
+ def assets_available(self):
+ for name, asset in vars(self.__class__).items():
+ if name.startswith("ASSET_") and type(asset) == Asset:
+ if not asset.available():
+ self.log.debug(f"Asset {asset.url} not available")
+ return False
+ return True
- def setUp(self, bin_prefix):
+ def setUp(self):
+ self.qemu_bin = os.getenv('QEMU_TEST_QEMU_BINARY')
self.assertIsNotNone(self.qemu_bin, 'QEMU_TEST_QEMU_BINARY must be set')
self.arch = self.qemu_bin.split('-')[-1]
+ self.socketdir = None
- self.workdir = os.path.join(BUILD_DIR, 'tests/functional', self.arch,
- self.id())
+ self.outputdir = self.build_file('tests', 'functional',
+ self.arch, self.id())
+ self.workdir = os.path.join(self.outputdir, 'scratch')
os.makedirs(self.workdir, exist_ok=True)
- self.logdir = self.workdir
+ self.log_filename = self.log_file('base.log')
self.log = logging.getLogger('qemu-test')
self.log.setLevel(logging.DEBUG)
- self._log_fh = logging.FileHandler(os.path.join(self.logdir,
- 'base.log'), mode='w')
+ self._log_fh = logging.FileHandler(self.log_filename, mode='w')
self._log_fh.setLevel(logging.DEBUG)
fileFormatter = logging.Formatter(
'%(asctime)s - %(levelname)s: %(message)s')
self._log_fh.setFormatter(fileFormatter)
self.log.addHandler(self._log_fh)
+ # Capture QEMUMachine logging
+ self.machinelog = logging.getLogger('qemu.machine')
+ self.machinelog.setLevel(logging.DEBUG)
+ self.machinelog.addHandler(self._log_fh)
+
+ if not self.assets_available():
+ self.skipTest('One or more assets is not available')
+
def tearDown(self):
+ if "QEMU_TEST_KEEP_SCRATCH" not in os.environ:
+ shutil.rmtree(self.workdir)
+ if self.socketdir is not None:
+ shutil.rmtree(self.socketdir.name)
+ self.socketdir = None
+ self.machinelog.removeHandler(self._log_fh)
self.log.removeHandler(self._log_fh)
def main():
@@ -68,24 +243,33 @@ class QemuBaseTest(unittest.TestCase):
tr = pycotap.TAPTestRunner(message_log = pycotap.LogMode.LogToError,
test_output_log = pycotap.LogMode.LogToError)
- unittest.main(module = None, testRunner = tr, argv=["__dummy__", path])
+ res = unittest.main(module = None, testRunner = tr, exit = False,
+ argv=["__dummy__", path])
+ for (test, message) in res.result.errors + res.result.failures:
+
+ if hasattr(test, "log_filename"):
+ print('More information on ' + test.id() + ' could be found here:'
+ '\n %s' % test.log_filename, file=sys.stderr)
+ if hasattr(test, 'console_log_name'):
+ print(' %s' % test.console_log_name, file=sys.stderr)
+ sys.exit(not res.result.wasSuccessful())
class QemuUserTest(QemuBaseTest):
def setUp(self):
- super().setUp('qemu-')
+ super().setUp()
self._ldpath = []
def add_ldpath(self, ldpath):
self._ldpath.append(os.path.abspath(ldpath))
def run_cmd(self, bin_path, args=[]):
- return subprocess.run([self.qemu_bin]
- + ["-L %s" % ldpath for ldpath in self._ldpath]
- + [bin_path]
- + args,
- text=True, capture_output=True)
+ return run([self.qemu_bin]
+ + ["-L %s" % ldpath for ldpath in self._ldpath]
+ + [bin_path]
+ + args,
+ text=True, capture_output=True)
class QemuSystemTest(QemuBaseTest):
"""Facilitates system emulation tests."""
@@ -97,12 +281,13 @@ class QemuSystemTest(QemuBaseTest):
def setUp(self):
self._vms = {}
- super().setUp('qemu-system-')
+ super().setUp()
console_log = logging.getLogger('console')
console_log.setLevel(logging.DEBUG)
- self._console_log_fh = logging.FileHandler(os.path.join(self.workdir,
- 'console.log'), mode='w')
+ self.console_log_name = self.log_file('console.log')
+ self._console_log_fh = logging.FileHandler(self.console_log_name,
+ mode='w')
self._console_log_fh.setLevel(logging.DEBUG)
fileFormatter = logging.Formatter('%(asctime)s: %(message)s')
self._console_log_fh.setFormatter(fileFormatter)
@@ -111,7 +296,9 @@ class QemuSystemTest(QemuBaseTest):
def set_machine(self, machinename):
# TODO: We should use QMP to get the list of available machines
if not self._machinehelp:
- self._machinehelp = run_cmd([self.qemu_bin, '-M', 'help'])[0];
+ self._machinehelp = run(
+ [self.qemu_bin, '-M', 'help'],
+ capture_output=True, check=True, encoding='utf8').stdout
if self._machinehelp.find(machinename) < 0:
self.skipTest('no support for machine ' + machinename)
self.machine = machinename
@@ -130,7 +317,9 @@ class QemuSystemTest(QemuBaseTest):
:type accelerator: str
"""
checker = {'tcg': tcg_available,
- 'kvm': kvm_available}.get(accelerator)
+ 'kvm': kvm_available,
+ 'hvf': hvf_available,
+ }.get(accelerator)
if checker is None:
self.skipTest("Don't know how to check for the presence "
"of accelerator %s" % accelerator)
@@ -139,22 +328,33 @@ class QemuSystemTest(QemuBaseTest):
"available" % accelerator)
def require_netdev(self, netdevname):
- netdevhelp = run_cmd([self.qemu_bin,
- '-M', 'none', '-netdev', 'help'])[0];
- if netdevhelp.find('\n' + netdevname + '\n') < 0:
+ help = run([self.qemu_bin,
+ '-M', 'none', '-netdev', 'help'],
+ capture_output=True, check=True, encoding='utf8').stdout;
+ if help.find('\n' + netdevname + '\n') < 0:
self.skipTest('no support for " + netdevname + " networking')
def require_device(self, devicename):
- devhelp = run_cmd([self.qemu_bin,
- '-M', 'none', '-device', 'help'])[0];
- if devhelp.find(devicename) < 0:
+ help = run([self.qemu_bin,
+ '-M', 'none', '-device', 'help'],
+ capture_output=True, check=True, encoding='utf8').stdout;
+ if help.find(devicename) < 0:
self.skipTest('no support for device ' + devicename)
def _new_vm(self, name, *args):
- vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir)
+ vm = QEMUMachine(self.qemu_bin,
+ name=name,
+ base_temp_dir=self.workdir,
+ log_dir=self.log_file())
self.log.debug('QEMUMachine "%s" created', name)
self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir)
- self.log.debug('QEMUMachine "%s" log_dir: %s', name, vm.log_dir)
+
+ sockpath = os.environ.get("QEMU_TEST_QMP_BACKDOOR", None)
+ if sockpath is not None:
+ vm.add_args("-chardev",
+ f"socket,id=backdoor,path={sockpath},server=on,wait=off",
+ "-mon", "chardev=backdoor,mode=control")
+
if args:
vm.add_args(*args)
return vm
diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py
new file mode 100644
index 0000000..6c442ff
--- /dev/null
+++ b/tests/functional/qemu_test/tuxruntest.py
@@ -0,0 +1,136 @@
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import QemuSystemTest
+from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test import wait_for_console_pattern
+from qemu_test import which, get_qemu_img
+
+class TuxRunBaselineTest(QemuSystemTest):
+
+ KERNEL_COMMON_COMMAND_LINE = 'printk.time=0'
+ # Tests are ~10-40s, allow for --debug/--enable-gcov overhead
+ timeout = 100
+
+ def setUp(self):
+ super().setUp()
+
+ # We need zstd for all the tuxrun tests
+ if which('zstd') is None:
+ self.skipTest("zstd not found in $PATH")
+
+ # Pre-init TuxRun specific settings: Most machines work with
+ # reasonable defaults but we sometimes need to tweak the
+ # config. To avoid open coding everything we store all these
+ # details in the metadata for each test.
+
+ # The tuxboot tag matches the root directory
+ self.tuxboot = self.arch
+
+ # Most Linux's use ttyS0 for their serial port
+ self.console = "ttyS0"
+
+ # Does the machine shutdown QEMU nicely on "halt"
+ self.wait_for_shutdown = True
+
+ self.root = "vda"
+
+ # Occasionally we need extra devices to hook things up
+ self.extradev = None
+
+ self.qemu_img = get_qemu_img(self)
+
+ def wait_for_console_pattern(self, success_message, vm=None):
+ wait_for_console_pattern(self, success_message,
+ failure_message='Kernel panic - not syncing',
+ vm=vm)
+
+ def fetch_tuxrun_assets(self, kernel_asset, rootfs_asset, dtb_asset=None):
+ """
+ Fetch the TuxBoot assets.
+ """
+ kernel_image = kernel_asset.fetch()
+ disk_image = self.uncompress(rootfs_asset)
+ dtb = dtb_asset.fetch() if dtb_asset is not None else None
+
+ return (kernel_image, disk_image, dtb)
+
+ def prepare_run(self, kernel, disk, drive, dtb=None, console_index=0):
+ """
+ Setup to run and add the common parameters to the system
+ """
+ self.vm.set_console(console_index=console_index)
+
+ # all block devices are raw ext4's
+ blockdev = "driver=raw,file.driver=file," \
+ + f"file.filename={disk},node-name=hd0"
+
+ self.kcmd_line = self.KERNEL_COMMON_COMMAND_LINE
+ self.kcmd_line += f" root=/dev/{self.root}"
+ self.kcmd_line += f" console={self.console}"
+
+ self.vm.add_args('-kernel', kernel,
+ '-append', self.kcmd_line,
+ '-blockdev', blockdev)
+
+ # Sometimes we need extra devices attached
+ if self.extradev:
+ self.vm.add_args('-device', self.extradev)
+
+ self.vm.add_args('-device',
+ f"{drive},drive=hd0")
+
+ # Some machines need an explicit DTB
+ if dtb:
+ self.vm.add_args('-dtb', dtb)
+
+ def run_tuxtest_tests(self, haltmsg):
+ """
+ Wait for the system to boot up, wait for the login prompt and
+ then do a few things on the console. Trigger a shutdown and
+ wait to exit cleanly.
+ """
+ ps1='root@tuxtest:~#'
+ self.wait_for_console_pattern(self.kcmd_line)
+ self.wait_for_console_pattern('tuxtest login:')
+ exec_command_and_wait_for_pattern(self, 'root', ps1)
+ exec_command_and_wait_for_pattern(self, 'cat /proc/interrupts', ps1)
+ exec_command_and_wait_for_pattern(self, 'cat /proc/self/maps', ps1)
+ exec_command_and_wait_for_pattern(self, 'uname -a', ps1)
+ exec_command_and_wait_for_pattern(self, 'halt', haltmsg)
+
+ # Wait for VM to shut down gracefully if it can
+ if self.wait_for_shutdown:
+ self.vm.wait()
+ else:
+ self.vm.shutdown()
+
+ def common_tuxrun(self,
+ kernel_asset,
+ rootfs_asset,
+ dtb_asset=None,
+ drive="virtio-blk-device",
+ haltmsg="reboot: System halted",
+ console_index=0):
+ """
+ Common path for LKFT tests. Unless we need to do something
+ special with the command line we can process most things using
+ the tag metadata.
+ """
+ (kernel, disk, dtb) = self.fetch_tuxrun_assets(kernel_asset, rootfs_asset,
+ dtb_asset)
+
+ self.prepare_run(kernel, disk, drive, dtb, console_index)
+ self.vm.launch()
+ self.run_tuxtest_tests(haltmsg)
+ os.remove(disk)
diff --git a/tests/functional/qemu_test/uncompress.py b/tests/functional/qemu_test/uncompress.py
new file mode 100644
index 0000000..b7ef8f7
--- /dev/null
+++ b/tests/functional/qemu_test/uncompress.py
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Utilities for python-based QEMU tests
+#
+# Copyright 2024 Red Hat, Inc.
+#
+# Authors:
+# Thomas Huth <thuth@redhat.com>
+
+import gzip
+import lzma
+import os
+import stat
+import shutil
+from urllib.parse import urlparse
+from subprocess import run, CalledProcessError
+
+from .asset import Asset
+
+
+def gzip_uncompress(gz_path, output_path):
+ if os.path.exists(output_path):
+ return
+ with gzip.open(gz_path, 'rb') as gz_in:
+ try:
+ with open(output_path, 'wb') as raw_out:
+ shutil.copyfileobj(gz_in, raw_out)
+ except:
+ os.remove(output_path)
+ raise
+
+def lzma_uncompress(xz_path, output_path):
+ if os.path.exists(output_path):
+ return
+ with lzma.open(xz_path, 'rb') as lzma_in:
+ try:
+ with open(output_path, 'wb') as raw_out:
+ shutil.copyfileobj(lzma_in, raw_out)
+ except:
+ os.remove(output_path)
+ raise
+
+
+def zstd_uncompress(zstd_path, output_path):
+ if os.path.exists(output_path):
+ return
+
+ try:
+ run(['zstd', "-f", "-d", zstd_path,
+ "-o", output_path], capture_output=True, check=True)
+ except CalledProcessError as e:
+ os.remove(output_path)
+ raise Exception(
+ f"Unable to decompress zstd file {zstd_path} with {e}") from e
+
+ # zstd copies source archive permissions for the output
+ # file, so must make this writable for QEMU
+ os.chmod(output_path, stat.S_IRUSR | stat.S_IWUSR)
+
+
+'''
+@params compressed: filename, Asset, or file-like object to uncompress
+@params uncompressed: filename to uncompress into
+@params format: optional compression format (gzip, lzma)
+
+Uncompresses @compressed into @uncompressed
+
+If @format is None, heuristics will be applied to guess the format
+from the filename or Asset URL. @format must be non-None if @uncompressed
+is a file-like object.
+
+Returns the fully qualified path to the uncompessed file
+'''
+def uncompress(compressed, uncompressed, format=None):
+ if format is None:
+ format = guess_uncompress_format(compressed)
+
+ if format == "xz":
+ lzma_uncompress(str(compressed), uncompressed)
+ elif format == "gz":
+ gzip_uncompress(str(compressed), uncompressed)
+ elif format == "zstd":
+ zstd_uncompress(str(compressed), uncompressed)
+ else:
+ raise Exception(f"Unknown compression format {format}")
+
+'''
+@params compressed: filename, Asset, or file-like object to guess
+
+Guess the format of @compressed, raising an exception if
+no format can be determined
+'''
+def guess_uncompress_format(compressed):
+ if type(compressed) == Asset:
+ compressed = urlparse(compressed.url).path
+ elif type(compressed) != str:
+ raise Exception(f"Unable to guess compression cformat for {compressed}")
+
+ (name, ext) = os.path.splitext(compressed)
+ if ext == ".xz":
+ return "xz"
+ elif ext == ".gz":
+ return "gz"
+ elif ext in [".zstd", ".zst"]:
+ return 'zstd'
+ else:
+ raise Exception(f"Unknown compression format for {compressed}")
diff --git a/tests/functional/qemu_test/utils.py b/tests/functional/qemu_test/utils.py
index 2a1cb60..e7c8de8 100644
--- a/tests/functional/qemu_test/utils.py
+++ b/tests/functional/qemu_test/utils.py
@@ -8,49 +8,32 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-import gzip
-import lzma
import os
-import shutil
-import subprocess
-import tarfile
-def archive_extract(archive, dest_dir, member=None):
- with tarfile.open(archive) as tf:
- if hasattr(tarfile, 'data_filter'):
- tf.extraction_filter = getattr(tarfile, 'data_filter',
- (lambda member, path: member))
- if member:
- tf.extract(member=member, path=dest_dir)
- else:
- tf.extractall(path=dest_dir)
+from qemu.utils import get_info_usernet_hostfwd_port
-def gzip_uncompress(gz_path, output_path):
- if os.path.exists(output_path):
- return
- with gzip.open(gz_path, 'rb') as gz_in:
- try:
- with open(output_path, 'wb') as raw_out:
- shutil.copyfileobj(gz_in, raw_out)
- except:
- os.remove(output_path)
- raise
-def lzma_uncompress(xz_path, output_path):
- if os.path.exists(output_path):
- return
- with lzma.open(xz_path, 'rb') as lzma_in:
- try:
- with open(output_path, 'wb') as raw_out:
- shutil.copyfileobj(lzma_in, raw_out)
- except:
- os.remove(output_path)
- raise
+def get_usernet_hostfwd_port(vm):
+ res = vm.cmd('human-monitor-command', command_line='info usernet')
+ return get_info_usernet_hostfwd_port(res)
-def cpio_extract(cpio_handle, output_path):
- cwd = os.getcwd()
- os.chdir(output_path)
- subprocess.run(['cpio', '-i'],
- input=cpio_handle.read(),
- stderr=subprocess.DEVNULL)
- os.chdir(cwd)
+"""
+Round up to next power of 2
+"""
+def pow2ceil(x):
+ return 1 if x == 0 else 2**(x - 1).bit_length()
+
+def file_truncate(path, size):
+ if size != os.path.getsize(path):
+ with open(path, 'ab+') as fd:
+ fd.truncate(size)
+
+"""
+Expand file size to next power of 2
+"""
+def image_pow2ceil_expand(path):
+ size = os.path.getsize(path)
+ size_aligned = pow2ceil(size)
+ if size != size_aligned:
+ with open(path, 'ab+') as fd:
+ fd.truncate(size_aligned)
diff --git a/tests/functional/replay_kernel.py b/tests/functional/replay_kernel.py
new file mode 100644
index 0000000..80795eb
--- /dev/null
+++ b/tests/functional/replay_kernel.py
@@ -0,0 +1,84 @@
+# Record/replay test that boots a Linux kernel
+#
+# Copyright (c) 2020 ISP RAS
+#
+# Author:
+# Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import os
+import logging
+import time
+import subprocess
+
+from qemu_test.linuxkernel import LinuxKernelTest
+
+class ReplayKernelBase(LinuxKernelTest):
+ """
+ Boots a Linux kernel in record mode and checks that the console
+ is operational and the kernel command line is properly passed
+ from QEMU to the kernel.
+ Then replays the same scenario and verifies, that QEMU correctly
+ terminates.
+ """
+
+ timeout = 180
+ REPLAY_KERNEL_COMMAND_LINE = 'printk.time=1 panic=-1 '
+
+ def run_vm(self, kernel_path, kernel_command_line, console_pattern,
+ record, shift, args, replay_path):
+ # icount requires TCG to be available
+ self.require_accelerator('tcg')
+
+ logger = logging.getLogger('replay')
+ start_time = time.time()
+ vm = self.get_vm(name='recording' if record else 'replay')
+ vm.set_console()
+ if record:
+ logger.info('recording the execution...')
+ mode = 'record'
+ else:
+ logger.info('replaying the execution...')
+ mode = 'replay'
+ vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' %
+ (shift, mode, replay_path),
+ '-kernel', kernel_path,
+ '-append', kernel_command_line,
+ '-net', 'none',
+ '-no-reboot')
+ if args:
+ vm.add_args(*args)
+ vm.launch()
+ self.wait_for_console_pattern(console_pattern, vm)
+ if record:
+ vm.shutdown()
+ logger.info('finished the recording with log size %s bytes'
+ % os.path.getsize(replay_path))
+ self.run_replay_dump(replay_path)
+ logger.info('successfully tested replay-dump.py')
+ else:
+ vm.wait()
+ logger.info('successfully finished the replay')
+ elapsed = time.time() - start_time
+ logger.info('elapsed time %.2f sec' % elapsed)
+ return elapsed
+
+ def run_replay_dump(self, replay_path):
+ try:
+ subprocess.check_call(["./scripts/replay-dump.py",
+ "-f", replay_path],
+ stdout=subprocess.DEVNULL)
+ except subprocess.CalledProcessError:
+ self.fail('replay-dump.py failed')
+
+ def run_rr(self, kernel_path, kernel_command_line, console_pattern,
+ shift=7, args=None):
+ replay_path = os.path.join(self.workdir, 'replay.bin')
+ t1 = self.run_vm(kernel_path, kernel_command_line, console_pattern,
+ True, shift, args, replay_path)
+ t2 = self.run_vm(kernel_path, kernel_command_line, console_pattern,
+ False, shift, args, replay_path)
+ logger = logging.getLogger('replay')
+ logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1))
diff --git a/tests/avocado/reverse_debugging.py b/tests/functional/reverse_debugging.py
index f24287c..f9a1d39 100644
--- a/tests/avocado/reverse_debugging.py
+++ b/tests/functional/reverse_debugging.py
@@ -1,5 +1,7 @@
# Reverse debugging test
#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
# Copyright (c) 2020 ISP RAS
#
# Author:
@@ -10,14 +12,9 @@
import os
import logging
-from avocado import skipUnless
-from avocado_qemu import BUILD_DIR
-from avocado.utils import datadrainer
-from avocado.utils import gdb
-from avocado.utils import process
-from avocado.utils.network.ports import find_free_port
-from avocado.utils.path import find_command
-from boot_linux_console import LinuxKernelTest
+from qemu_test import LinuxKernelTest, get_qemu_img
+from qemu_test.ports import Ports
+
class ReverseDebugging(LinuxKernelTest):
"""
@@ -36,8 +33,10 @@ class ReverseDebugging(LinuxKernelTest):
endian_is_le = True
def run_vm(self, record, shift, args, replay_path, image_path, port):
+ from avocado.utils import datadrainer
+
logger = logging.getLogger('replay')
- vm = self.get_vm()
+ vm = self.get_vm(name='record' if record else 'replay')
vm.set_console()
if record:
logger.info('recording the execution...')
@@ -100,25 +99,25 @@ class ReverseDebugging(LinuxKernelTest):
return vm.qmp('query-replay')['return']['icount']
def reverse_debugging(self, shift=7, args=None):
+ from avocado.utils import gdb
+ from avocado.utils import process
+
logger = logging.getLogger('replay')
# create qcow2 for snapshots
logger.info('creating qcow2 image for VM snapshots')
image_path = os.path.join(self.workdir, 'disk.qcow2')
- qemu_img = os.path.join(BUILD_DIR, 'qemu-img')
- if not os.path.exists(qemu_img):
- qemu_img = find_command('qemu-img', False)
- if qemu_img is False:
- self.cancel('Could not find "qemu-img", which is required to '
- 'create the temporary qcow2 image')
+ qemu_img = get_qemu_img(self)
+ if qemu_img is None:
+ self.skipTest('Could not find "qemu-img", which is required to '
+ 'create the temporary qcow2 image')
cmd = '%s create -f qcow2 %s 128M' % (qemu_img, image_path)
process.run(cmd)
replay_path = os.path.join(self.workdir, 'replay.bin')
- port = find_free_port()
# record the log
- vm = self.run_vm(True, shift, args, replay_path, image_path, port)
+ vm = self.run_vm(True, shift, args, replay_path, image_path, -1)
while self.vm_get_icount(vm) <= self.STEPS:
pass
last_icount = self.vm_get_icount(vm)
@@ -127,7 +126,9 @@ class ReverseDebugging(LinuxKernelTest):
logger.info("recorded log with %s+ steps" % last_icount)
# replay and run debug commands
- vm = self.run_vm(False, shift, args, replay_path, image_path, port)
+ with Ports() as ports:
+ port = ports.find_free_port()
+ vm = self.run_vm(False, shift, args, replay_path, image_path, port)
logger.info('connecting to gdbstub')
g = gdb.GDBRemote('127.0.0.1', port, False, False)
g.connect()
@@ -193,80 +194,3 @@ class ReverseDebugging(LinuxKernelTest):
logger.info('exiting gdb and qemu')
vm.shutdown()
-
-class ReverseDebugging_X86_64(ReverseDebugging):
- """
- :avocado: tags=accel:tcg
- """
-
- REG_PC = 0x10
- REG_CS = 0x12
- def get_pc(self, g):
- return self.get_reg_le(g, self.REG_PC) \
- + self.get_reg_le(g, self.REG_CS) * 0x10
-
- # unidentified gitlab timeout problem
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
- def test_x86_64_pc(self):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:pc
- """
- # start with BIOS only
- self.reverse_debugging()
-
-class ReverseDebugging_AArch64(ReverseDebugging):
- """
- :avocado: tags=accel:tcg
- """
-
- REG_PC = 32
-
- # unidentified gitlab timeout problem
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
- def test_aarch64_virt(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:virt
- :avocado: tags=cpu:cortex-a53
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/29/Everything/aarch64/os/images/pxeboot'
- '/vmlinuz')
- kernel_hash = '8c73e469fc6ea06a58dc83a628fc695b693b8493'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- self.reverse_debugging(
- args=('-kernel', kernel_path))
-
-class ReverseDebugging_ppc64(ReverseDebugging):
- """
- :avocado: tags=accel:tcg
- """
-
- REG_PC = 0x40
-
- # unidentified gitlab timeout problem
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
- def test_ppc64_pseries(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- :avocado: tags=flaky
- """
- # SLOF branches back to its entry point, which causes this test
- # to take the 'hit a breakpoint again' path. That's not a problem,
- # just slightly different than the other machines.
- self.endian_is_le = False
- self.reverse_debugging()
-
- # See https://gitlab.com/qemu-project/qemu/-/issues/1992
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
- def test_ppc64_powernv(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv
- :avocado: tags=flaky
- """
- self.endian_is_le = False
- self.reverse_debugging()
diff --git a/tests/functional/test_aarch64_aspeed_ast2700.py b/tests/functional/test_aarch64_aspeed_ast2700.py
new file mode 100755
index 0000000..d02dc79
--- /dev/null
+++ b/tests/functional/test_aarch64_aspeed_ast2700.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots the ASPEED SoCs with firmware
+#
+# Copyright (C) 2022 ASPEED Technology Inc
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+from qemu_test import exec_command_and_wait_for_pattern
+
+
+class AST2x00MachineSDK(QemuSystemTest):
+
+ def do_test_aarch64_aspeed_sdk_start(self, image):
+ self.require_netdev('user')
+ self.vm.set_console()
+ self.vm.add_args('-device',
+ 'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test')
+ self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
+ '-net', 'nic', '-net', 'user', '-snapshot')
+
+ self.vm.launch()
+
+ def verify_vbootrom_firmware_flow(self):
+ wait_for_console_pattern(self, 'Found valid FIT image')
+ wait_for_console_pattern(self, '[uboot] loading')
+ wait_for_console_pattern(self, 'done')
+ wait_for_console_pattern(self, '[fdt] loading')
+ wait_for_console_pattern(self, 'done')
+ wait_for_console_pattern(self, '[tee] loading')
+ wait_for_console_pattern(self, 'done')
+ wait_for_console_pattern(self, '[atf] loading')
+ wait_for_console_pattern(self, 'done')
+ wait_for_console_pattern(self, 'Jumping to BL31 (Trusted Firmware-A)')
+
+ def verify_openbmc_boot_and_login(self, name):
+ wait_for_console_pattern(self, 'U-Boot 2023.10')
+ wait_for_console_pattern(self, '## Loading kernel from FIT Image')
+ wait_for_console_pattern(self, 'Starting kernel ...')
+
+ wait_for_console_pattern(self, f'{name} login:')
+ exec_command_and_wait_for_pattern(self, 'root', 'Password:')
+ exec_command_and_wait_for_pattern(self, '0penBmc', f'root@{name}:~#')
+
+ ASSET_SDK_V906_AST2700 = Asset(
+ 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.06/ast2700-a0-default-obmc.tar.gz',
+ '7247b6f19dbfb700686f8d9f723ac23f3eb229226c0589cb9b06b80d1b61f3cb')
+
+ ASSET_SDK_V906_AST2700A1 = Asset(
+ 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.06/ast2700-default-obmc.tar.gz',
+ 'f1d53e0be8a404ecce3e105f72bc50fa4e090ad13160ffa91b10a6e0233a9dc6')
+
+ def do_ast2700_i2c_test(self):
+ exec_command_and_wait_for_pattern(self,
+ 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-1/device/new_device ',
+ 'i2c i2c-1: new_device: Instantiated device lm75 at 0x4d')
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/bus/i2c/devices/1-004d/hwmon/hwmon*/temp1_input', '0')
+ self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
+ property='temperature', value=18000)
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/bus/i2c/devices/1-004d/hwmon/hwmon*/temp1_input', '18000')
+
+ def start_ast2700_test(self, name):
+ num_cpu = 4
+ uboot_size = os.path.getsize(self.scratch_file(name,
+ 'u-boot-nodtb.bin'))
+ uboot_dtb_load_addr = hex(0x400000000 + uboot_size)
+
+ load_images_list = [
+ {
+ 'addr': '0x400000000',
+ 'file': self.scratch_file(name,
+ 'u-boot-nodtb.bin')
+ },
+ {
+ 'addr': str(uboot_dtb_load_addr),
+ 'file': self.scratch_file(name, 'u-boot.dtb')
+ },
+ {
+ 'addr': '0x430000000',
+ 'file': self.scratch_file(name, 'bl31.bin')
+ },
+ {
+ 'addr': '0x430080000',
+ 'file': self.scratch_file(name, 'optee',
+ 'tee-raw.bin')
+ }
+ ]
+
+ for load_image in load_images_list:
+ addr = load_image['addr']
+ file = load_image['file']
+ self.vm.add_args('-device',
+ f'loader,force-raw=on,addr={addr},file={file}')
+
+ for i in range(num_cpu):
+ self.vm.add_args('-device',
+ f'loader,addr=0x430000000,cpu-num={i}')
+
+ self.vm.add_args('-smp', str(num_cpu))
+ self.do_test_aarch64_aspeed_sdk_start(
+ self.scratch_file(name, 'image-bmc'))
+
+ def start_ast2700_test_vbootrom(self, name):
+ self.vm.add_args('-bios', 'ast27x0_bootrom.bin')
+ self.do_test_aarch64_aspeed_sdk_start(
+ self.scratch_file(name, 'image-bmc'))
+
+ def test_aarch64_ast2700_evb_sdk_v09_06(self):
+ self.set_machine('ast2700-evb')
+
+ self.archive_extract(self.ASSET_SDK_V906_AST2700)
+ self.start_ast2700_test('ast2700-a0-default')
+ self.verify_openbmc_boot_and_login('ast2700-a0-default')
+ self.do_ast2700_i2c_test()
+
+ def test_aarch64_ast2700a1_evb_sdk_v09_06(self):
+ self.set_machine('ast2700a1-evb')
+
+ self.archive_extract(self.ASSET_SDK_V906_AST2700A1)
+ self.start_ast2700_test('ast2700-default')
+ self.verify_openbmc_boot_and_login('ast2700-default')
+ self.do_ast2700_i2c_test()
+
+ def test_aarch64_ast2700a1_evb_sdk_vbootrom_v09_06(self):
+ self.set_machine('ast2700a1-evb')
+
+ self.archive_extract(self.ASSET_SDK_V906_AST2700A1)
+ self.start_ast2700_test_vbootrom('ast2700-default')
+ self.verify_vbootrom_firmware_flow()
+ self.verify_openbmc_boot_and_login('ast2700-default')
+ self.do_ast2700_i2c_test()
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_aarch64_aspeed_ast2700fc.py b/tests/functional/test_aarch64_aspeed_ast2700fc.py
new file mode 100755
index 0000000..b85370e
--- /dev/null
+++ b/tests/functional/test_aarch64_aspeed_ast2700fc.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots the ASPEED SoCs with firmware
+#
+# Copyright (C) 2022 ASPEED Technology Inc
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+from qemu_test import exec_command_and_wait_for_pattern
+
+
+class AST2x00MachineSDK(QemuSystemTest):
+
+ def do_test_aarch64_aspeed_sdk_start(self, image):
+ self.require_netdev('user')
+ self.vm.set_console()
+ self.vm.add_args('-device',
+ 'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test')
+ self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
+ '-net', 'nic', '-net', 'user', '-snapshot')
+
+ self.vm.launch()
+
+ def verify_openbmc_boot_and_login(self, name):
+ wait_for_console_pattern(self, 'U-Boot 2023.10')
+ wait_for_console_pattern(self, '## Loading kernel from FIT Image')
+ wait_for_console_pattern(self, 'Starting kernel ...')
+
+ wait_for_console_pattern(self, f'{name} login:')
+ exec_command_and_wait_for_pattern(self, 'root', 'Password:')
+ exec_command_and_wait_for_pattern(self, '0penBmc', f'root@{name}:~#')
+
+ ASSET_SDK_V906_AST2700 = Asset(
+ 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.06/ast2700-default-obmc.tar.gz',
+ 'f1d53e0be8a404ecce3e105f72bc50fa4e090ad13160ffa91b10a6e0233a9dc6')
+
+ def do_ast2700_i2c_test(self):
+ exec_command_and_wait_for_pattern(self,
+ 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-1/device/new_device ',
+ 'i2c i2c-1: new_device: Instantiated device lm75 at 0x4d')
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/bus/i2c/devices/1-004d/hwmon/hwmon*/temp1_input', '0')
+ self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
+ property='temperature', value=18000)
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/bus/i2c/devices/1-004d/hwmon/hwmon*/temp1_input', '18000')
+
+ def do_ast2700fc_ssp_test(self):
+ self.vm.shutdown()
+ self.vm.set_console(console_index=1)
+ self.vm.launch()
+
+ exec_command_and_wait_for_pattern(self, '\012', 'ssp:~$')
+ exec_command_and_wait_for_pattern(self, 'version',
+ 'Zephyr version 3.7.1')
+ exec_command_and_wait_for_pattern(self, 'md 72c02000 1',
+ '[72c02000] 06010103')
+
+ def do_ast2700fc_tsp_test(self):
+ self.vm.shutdown()
+ self.vm.set_console(console_index=2)
+ self.vm.launch()
+
+ exec_command_and_wait_for_pattern(self, '\012', 'tsp:~$')
+ exec_command_and_wait_for_pattern(self, 'version',
+ 'Zephyr version 3.7.1')
+ exec_command_and_wait_for_pattern(self, 'md 72c02000 1',
+ '[72c02000] 06010103')
+
+ def start_ast2700fc_test(self, name):
+ ca35_core = 4
+ uboot_size = os.path.getsize(self.scratch_file(name,
+ 'u-boot-nodtb.bin'))
+ uboot_dtb_load_addr = hex(0x400000000 + uboot_size)
+
+ load_images_list = [
+ {
+ 'addr': '0x400000000',
+ 'file': self.scratch_file(name,
+ 'u-boot-nodtb.bin')
+ },
+ {
+ 'addr': str(uboot_dtb_load_addr),
+ 'file': self.scratch_file(name, 'u-boot.dtb')
+ },
+ {
+ 'addr': '0x430000000',
+ 'file': self.scratch_file(name, 'bl31.bin')
+ },
+ {
+ 'addr': '0x430080000',
+ 'file': self.scratch_file(name, 'optee',
+ 'tee-raw.bin')
+ }
+ ]
+
+ for load_image in load_images_list:
+ addr = load_image['addr']
+ file = load_image['file']
+ self.vm.add_args('-device',
+ f'loader,force-raw=on,addr={addr},file={file}')
+
+ for i in range(ca35_core):
+ self.vm.add_args('-device',
+ f'loader,addr=0x430000000,cpu-num={i}')
+
+ load_elf_list = {
+ 'ssp': self.scratch_file(name, 'zephyr-aspeed-ssp.elf'),
+ 'tsp': self.scratch_file(name, 'zephyr-aspeed-tsp.elf')
+ }
+
+ for cpu_num, key in enumerate(load_elf_list, start=4):
+ file = load_elf_list[key]
+ self.vm.add_args('-device',
+ f'loader,file={file},cpu-num={cpu_num}')
+
+ self.do_test_aarch64_aspeed_sdk_start(
+ self.scratch_file(name, 'image-bmc'))
+
+ def test_aarch64_ast2700fc_sdk_v09_06(self):
+ self.set_machine('ast2700fc')
+
+ self.archive_extract(self.ASSET_SDK_V906_AST2700)
+ self.start_ast2700fc_test('ast2700-default')
+ self.verify_openbmc_boot_and_login('ast2700-default')
+ self.do_ast2700_i2c_test()
+ self.do_ast2700fc_ssp_test()
+ self.do_ast2700fc_tsp_test()
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_aarch64_device_passthrough.py b/tests/functional/test_aarch64_device_passthrough.py
new file mode 100755
index 0000000..1f3f158
--- /dev/null
+++ b/tests/functional/test_aarch64_device_passthrough.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python3
+#
+# Boots a nested guest and compare content of a device (passthrough) to a
+# reference image. Both vfio group and iommufd passthrough methods are tested.
+#
+# Copyright (c) 2025 Linaro Ltd.
+#
+# Author: Pierrick Bouvier <pierrick.bouvier@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import exec_command, wait_for_console_pattern
+from qemu_test import exec_command_and_wait_for_pattern
+from random import randbytes
+
+guest_script = '''
+#!/usr/bin/env bash
+
+set -euo pipefail
+set -x
+
+# find disks from nvme serial
+dev_vfio=$(lsblk --nvme | grep vfio | cut -f 1 -d ' ')
+dev_iommufd=$(lsblk --nvme | grep iommufd | cut -f 1 -d ' ')
+pci_vfio=$(basename $(readlink -f /sys/block/$dev_vfio/../../../))
+pci_iommufd=$(basename $(readlink -f /sys/block/$dev_iommufd/../../../))
+
+# bind disks to vfio
+for p in "$pci_vfio" "$pci_iommufd"; do
+ if [ "$(cat /sys/bus/pci/devices/$p/driver_override)" == vfio-pci ]; then
+ continue
+ fi
+ echo $p > /sys/bus/pci/drivers/nvme/unbind
+ echo vfio-pci > /sys/bus/pci/devices/$p/driver_override
+ echo $p > /sys/bus/pci/drivers/vfio-pci/bind
+done
+
+# boot nested guest and execute /host/nested_guest.sh
+# one disk is passed through vfio group, the other, through iommufd
+qemu-system-aarch64 \
+-M virt \
+-display none \
+-serial stdio \
+-cpu host \
+-enable-kvm \
+-m 1G \
+-kernel /host/Image.gz \
+-drive format=raw,file=/host/guest.ext4,if=virtio \
+-append "root=/dev/vda init=/init -- bash /host/nested_guest.sh" \
+-virtfs local,path=/host,mount_tag=host,security_model=mapped,readonly=off \
+-device vfio-pci,host=$pci_vfio \
+-object iommufd,id=iommufd0 \
+-device vfio-pci,host=$pci_iommufd,iommufd=iommufd0
+'''
+
+nested_guest_script = '''
+#!/usr/bin/env bash
+
+set -euo pipefail
+set -x
+
+image_vfio=/host/disk_vfio
+image_iommufd=/host/disk_iommufd
+
+dev_vfio=$(lsblk --nvme | grep vfio | cut -f 1 -d ' ')
+dev_iommufd=$(lsblk --nvme | grep iommufd | cut -f 1 -d ' ')
+
+# compare if devices are identical to original images
+diff $image_vfio /dev/$dev_vfio
+diff $image_iommufd /dev/$dev_iommufd
+
+echo device_passthrough_test_ok
+'''
+
+class Aarch64DevicePassthrough(QemuSystemTest):
+
+ # https://github.com/pbo-linaro/qemu-linux-stack
+ #
+ # Linux kernel is compiled with defconfig +
+ # IOMMUFD + VFIO_DEVICE_CDEV + ARM_SMMU_V3_IOMMUFD
+ # https://docs.kernel.org/driver-api/vfio.html#vfio-device-cde
+ ASSET_DEVICE_PASSTHROUGH_STACK = Asset(
+ ('https://fileserver.linaro.org/s/fx5DXxBYme8dw2G/'
+ 'download/device_passthrough.tar.xz'),
+ '812750b664d61c2986f2b149939ae28cafbd60d53e9c7e4b16e97143845e196d')
+
+ # This tests the device passthrough implementation, by booting a VM
+ # supporting it with two nvme disks attached, and launching a nested VM
+ # reading their content.
+ def test_aarch64_device_passthrough(self):
+ self.set_machine('virt')
+ self.require_accelerator('tcg')
+
+ self.vm.set_console()
+
+ stack_path_tar_gz = self.ASSET_DEVICE_PASSTHROUGH_STACK.fetch()
+ self.archive_extract(stack_path_tar_gz, format="tar")
+
+ stack = self.scratch_file('out')
+ kernel = os.path.join(stack, 'Image.gz')
+ rootfs_host = os.path.join(stack, 'host.ext4')
+ disk_vfio = os.path.join(stack, 'disk_vfio')
+ disk_iommufd = os.path.join(stack, 'disk_iommufd')
+ guest_cmd = os.path.join(stack, 'guest.sh')
+ nested_guest_cmd = os.path.join(stack, 'nested_guest.sh')
+ # we generate two random disks
+ with open(disk_vfio, "wb") as d: d.write(randbytes(512))
+ with open(disk_iommufd, "wb") as d: d.write(randbytes(1024))
+ with open(guest_cmd, 'w') as s: s.write(guest_script)
+ with open(nested_guest_cmd, 'w') as s: s.write(nested_guest_script)
+
+ self.vm.add_args('-cpu', 'max')
+ self.vm.add_args('-m', '2G')
+ self.vm.add_args('-M', 'virt,'
+ 'virtualization=on,'
+ 'gic-version=max,'
+ 'iommu=smmuv3')
+ self.vm.add_args('-kernel', kernel)
+ self.vm.add_args('-drive', f'format=raw,file={rootfs_host}')
+ self.vm.add_args('-drive',
+ f'file={disk_vfio},if=none,id=vfio,format=raw')
+ self.vm.add_args('-device', 'nvme,serial=vfio,drive=vfio')
+ self.vm.add_args('-drive',
+ f'file={disk_iommufd},if=none,id=iommufd,format=raw')
+ self.vm.add_args('-device', 'nvme,serial=iommufd,drive=iommufd')
+ self.vm.add_args('-virtfs',
+ f'local,path={stack}/,mount_tag=host,'
+ 'security_model=mapped,readonly=off')
+ # boot and execute guest script
+ # init will trigger a kernel panic if script fails
+ self.vm.add_args('-append',
+ 'root=/dev/vda init=/init -- bash /host/guest.sh')
+
+ self.vm.launch()
+ wait_for_console_pattern(self, 'device_passthrough_test_ok',
+ failure_message='Kernel panic')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_aarch64_hotplug_pci.py b/tests/functional/test_aarch64_hotplug_pci.py
new file mode 100755
index 0000000..c9bb7f1
--- /dev/null
+++ b/tests/functional/test_aarch64_hotplug_pci.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+#
+# The test hotplugs a PCI device and checks it on a Linux guest.
+#
+# Copyright (c) 2025 Linaro Ltd.
+#
+# Author:
+# Gustavo Romero <gustavo.romero@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern
+from qemu_test import BUILD_DIR
+
+class HotplugPCI(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ ('https://ftp.debian.org/debian/dists/stable/main/installer-arm64/'
+ '20230607+deb12u11/images/netboot/debian-installer/arm64/linux'),
+ 'd92a60392ce1e379ca198a1a820899f8f0d39a62d047c41ab79492f81541a9d9')
+
+ ASSET_INITRD = Asset(
+ ('https://ftp.debian.org/debian/dists/stable/main/installer-arm64/'
+ '20230607+deb12u11/images/netboot/debian-installer/arm64/initrd.gz'),
+ '9f817f76951f3237bca8216bee35267bfb826815687f4b2fcdd5e6c2a917790c')
+
+ def test_hotplug_pci(self):
+
+ self.set_machine('virt')
+
+ self.vm.add_args('-m', '512M',
+ '-cpu', 'cortex-a57',
+ '-append',
+ 'console=ttyAMA0,115200 init=/bin/sh',
+ '-device',
+ 'pcie-root-port,bus=pcie.0,chassis=1,slot=1,id=pcie.1',
+ '-bios',
+ self.build_file('pc-bios', 'edk2-aarch64-code.fd'))
+
+ # BusyBox prompt
+ prompt = "~ #"
+ self.launch_kernel(self.ASSET_KERNEL.fetch(),
+ self.ASSET_INITRD.fetch(),
+ wait_for=prompt)
+
+ # Check for initial state: 2 network adapters, lo and enp0s1.
+ exec_command_and_wait_for_pattern(self,
+ 'ls /sys/class/net | wc -l',
+ '2')
+
+ # Hotplug one network adapter to the root port, i.e. pcie.1 bus.
+ self.vm.cmd('device_add',
+ driver='virtio-net-pci',
+ bus='pcie.1',
+ addr=0,
+ id='na')
+ # Wait for the kernel to recognize the new device.
+ self.wait_for_console_pattern('virtio-pci')
+ self.wait_for_console_pattern('virtio_net')
+
+ # Check if there is a new network adapter.
+ exec_command_and_wait_for_pattern(self,
+ 'ls /sys/class/net | wc -l',
+ '3')
+
+ self.vm.cmd('device_del', id='na')
+ exec_command_and_wait_for_pattern(self,
+ 'ls /sys/class/net | wc -l',
+ '2')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_aarch64_imx8mp_evk.py b/tests/functional/test_aarch64_imx8mp_evk.py
new file mode 100755
index 0000000..99ddcde
--- /dev/null
+++ b/tests/functional/test_aarch64_imx8mp_evk.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class Imx8mpEvkMachine(LinuxKernelTest):
+
+ ASSET_IMAGE = Asset(
+ ('https://cloud.debian.org/images/cloud/bookworm/20231210-1590/'
+ 'debian-12-generic-arm64-20231210-1590.tar.xz'),
+ '7ebf1577b32d5af6204df74b54ca2e4675de9b5a9fa14f3ff70b88eeb7b3b359')
+
+ KERNEL_OFFSET = 0x51000000
+ KERNEL_SIZE = 32622528
+ INITRD_OFFSET = 0x76000000
+ INITRD_SIZE = 30987766
+ DTB_OFFSET = 0x64F51000
+ DTB_SIZE = 45 * 1024
+
+ def extract(self, in_path, out_path, offset, size):
+ try:
+ with open(in_path, "rb") as source:
+ source.seek(offset)
+ data = source.read(size)
+ with open(out_path, "wb") as target:
+ target.write(data)
+ except (IOError, ValueError) as e:
+ self.log.error(f"Failed to extract {out_path}: {e}")
+ raise
+
+ def setUp(self):
+ super().setUp()
+
+ self.image_path = self.scratch_file("disk.raw")
+ self.kernel_path = self.scratch_file("linux")
+ self.initrd_path = self.scratch_file("initrd.zstd")
+ self.dtb_path = self.scratch_file("imx8mp-evk.dtb")
+
+ self.archive_extract(self.ASSET_IMAGE)
+ self.extract(self.image_path, self.kernel_path,
+ self.KERNEL_OFFSET, self.KERNEL_SIZE)
+ self.extract(self.image_path, self.initrd_path,
+ self.INITRD_OFFSET, self.INITRD_SIZE)
+ self.extract(self.image_path, self.dtb_path,
+ self.DTB_OFFSET, self.DTB_SIZE)
+
+ def test_aarch64_imx8mp_evk_usdhc(self):
+ self.require_accelerator("tcg")
+ self.set_machine('imx8mp-evk')
+ self.vm.set_console(console_index=1)
+ self.vm.add_args('-m', '2G',
+ '-smp', '4',
+ '-kernel', self.kernel_path,
+ '-initrd', self.initrd_path,
+ '-dtb', self.dtb_path,
+ '-append', 'root=/dev/mmcblk2p1',
+ '-drive', f'file={self.image_path},if=sd,bus=2,'
+ 'format=raw,id=mmcblk2,snapshot=on')
+
+ self.vm.launch()
+ self.wait_for_console_pattern('Welcome to ')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_aarch64_raspi3.py b/tests/functional/test_aarch64_raspi3.py
new file mode 100755
index 0000000..74f6630
--- /dev/null
+++ b/tests/functional/test_aarch64_raspi3.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on a Raspberry Pi machine
+# and checks the console
+#
+# Copyright (c) 2020 Philippe Mathieu-Daudé <f4bug@amsat.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class Aarch64Raspi3Machine(LinuxKernelTest):
+
+ ASSET_RPI3_UEFI = Asset(
+ ('https://github.com/pbatard/RPi3/releases/download/'
+ 'v1.15/RPi3_UEFI_Firmware_v1.15.zip'),
+ '8cff2e979560048b4c84921f41a91893240b9fb71a88f0b5c5d6c8edd994bd5b')
+
+ def test_aarch64_raspi3_atf(self):
+ efi_name = 'RPI_EFI.fd'
+ efi_fd = self.archive_extract(self.ASSET_RPI3_UEFI, member=efi_name)
+
+ self.set_machine('raspi3b')
+ self.vm.set_console(console_index=1)
+ self.vm.add_args('-cpu', 'cortex-a53',
+ '-nodefaults',
+ '-device', f'loader,file={efi_fd},force-raw=true')
+ self.vm.launch()
+ self.wait_for_console_pattern('version UEFI Firmware v1.15')
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_aarch64_raspi4.py b/tests/functional/test_aarch64_raspi4.py
new file mode 100755
index 0000000..7a4302b
--- /dev/null
+++ b/tests/functional/test_aarch64_raspi4.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on a Raspberry Pi machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+
+
+class Aarch64Raspi4Machine(LinuxKernelTest):
+
+ """
+ The kernel can be rebuilt using the kernel source referenced
+ and following the instructions on the on:
+ https://www.raspberrypi.org/documentation/linux/kernel/building.md
+ """
+ ASSET_KERNEL_20190215 = Asset(
+ ('http://archive.raspberrypi.org/debian/'
+ 'pool/main/r/raspberrypi-firmware/'
+ 'raspberrypi-kernel_1.20230106-1_arm64.deb'),
+ '56d5713c8f6eee8a0d3f0e73600ec11391144fef318b08943e9abd94c0a9baf7')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/groeck/linux-build-test/raw/'
+ '86b2be1384d41c8c388e63078a847f1e1c4cb1de/rootfs/'
+ 'arm64/rootfs.cpio.gz'),
+ '7c0b16d1853772f6f4c3ca63e789b3b9ff4936efac9c8a01fb0c98c05c7a7648')
+
+ def test_arm_raspi4(self):
+ kernel_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/kernel8.img')
+ dtb_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/bcm2711-rpi-4-b.dtb')
+
+ self.set_machine('raspi4b')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'earlycon=pl011,mmio32,0xfe201000 ' +
+ 'console=ttyAMA0,115200 ' +
+ 'root=/dev/mmcblk1p2 rootwait ' +
+ 'dwc_otg.fiq_fsm_enable=0')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-append', kernel_command_line)
+ # When PCI is supported we can add a USB controller:
+ # '-device', 'qemu-xhci,bus=pcie.1,id=xhci',
+ # '-device', 'usb-kbd,bus=xhci.0',
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+ # When USB is enabled we can look for this
+ # console_pattern = 'Product: QEMU USB Keyboard'
+ # self.wait_for_console_pattern(console_pattern)
+ console_pattern = 'Waiting for root device'
+ self.wait_for_console_pattern(console_pattern)
+
+
+ def test_arm_raspi4_initrd(self):
+ kernel_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/kernel8.img')
+ dtb_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/bcm2711-rpi-4-b.dtb')
+ initrd_path = self.uncompress(self.ASSET_INITRD)
+
+ self.set_machine('raspi4b')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'earlycon=pl011,mmio32,0xfe201000 ' +
+ 'console=ttyAMA0,115200 ' +
+ 'panic=-1 noreboot ' +
+ 'dwc_otg.fiq_fsm_enable=0')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line,
+ '-no-reboot')
+ # When PCI is supported we can add a USB controller:
+ # '-device', 'qemu-xhci,bus=pcie.1,id=xhci',
+ # '-device', 'usb-kbd,bus=xhci.0',
+ self.vm.launch()
+ self.wait_for_console_pattern('Boot successful.')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'BCM2835')
+ exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
+ 'cprman@7e101000')
+ exec_command_and_wait_for_pattern(self, 'halt', 'reboot: System halted')
+ # TODO: Raspberry Pi4 doesn't shut down properly with recent kernels
+ # Wait for VM to shut down gracefully
+ #self.vm.wait()
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_aarch64_replay.py b/tests/functional/test_aarch64_replay.py
new file mode 100755
index 0000000..db12e76
--- /dev/null
+++ b/tests/functional/test_aarch64_replay.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+#
+# Replay test that boots a Linux kernel on an aarch64 machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from subprocess import check_call, DEVNULL
+
+from qemu_test import Asset, skipIfOperatingSystem, get_qemu_img
+from replay_kernel import ReplayKernelBase
+
+
+class Aarch64Replay(ReplayKernelBase):
+
+ ASSET_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/arm64/Image',
+ 'b74743c5e89e1cea0f73368d24ae0ae85c5204ff84be3b5e9610417417d2f235')
+
+ ASSET_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/arm64/rootfs.ext4.zst',
+ 'a1acaaae2068df4648d04ff75f532aaa8c5edcd6b936122b6f0db4848a07b465')
+
+ def test_aarch64_virt(self):
+ self.require_netdev('user')
+ self.set_machine('virt')
+ self.cpu = 'cortex-a57'
+ kernel_path = self.ASSET_KERNEL.fetch()
+
+ raw_disk = self.uncompress(self.ASSET_ROOTFS)
+ disk = self.scratch_file('scratch.qcow2')
+ qemu_img = get_qemu_img(self)
+ check_call([qemu_img, 'create', '-f', 'qcow2', '-b', raw_disk,
+ '-F', 'raw', disk], stdout=DEVNULL, stderr=DEVNULL)
+
+ args = ('-drive', 'file=%s,snapshot=on,id=hd0,if=none' % disk,
+ '-drive', 'driver=blkreplay,id=hd0-rr,if=none,image=hd0',
+ '-device', 'virtio-blk-device,drive=hd0-rr',
+ '-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
+ '-device', 'virtio-net,netdev=vnet',
+ '-object', 'filter-replay,id=replay,netdev=vnet')
+
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyAMA0 root=/dev/vda')
+ console_pattern = 'Welcome to TuxTest'
+ self.run_rr(kernel_path, kernel_command_line, console_pattern,
+ args=args)
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_aarch64_reverse_debug.py b/tests/functional/test_aarch64_reverse_debug.py
new file mode 100755
index 0000000..58d4532
--- /dev/null
+++ b/tests/functional/test_aarch64_reverse_debug.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Reverse debugging test
+#
+# Copyright (c) 2020 ISP RAS
+#
+# Author:
+# Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from qemu_test import Asset, skipIfMissingImports, skipFlakyTest
+from reverse_debugging import ReverseDebugging
+
+
+@skipIfMissingImports('avocado.utils')
+class ReverseDebugging_AArch64(ReverseDebugging):
+
+ REG_PC = 32
+
+ KERNEL_ASSET = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/'
+ 'releases/29/Everything/aarch64/os/images/pxeboot/vmlinuz'),
+ '7e1430b81c26bdd0da025eeb8fbd77b5dc961da4364af26e771bd39f379cbbf7')
+
+ @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/2921")
+ def test_aarch64_virt(self):
+ self.set_machine('virt')
+ self.cpu = 'cortex-a53'
+ kernel_path = self.KERNEL_ASSET.fetch()
+ self.reverse_debugging(args=('-kernel', kernel_path))
+
+
+if __name__ == '__main__':
+ ReverseDebugging.main()
diff --git a/tests/functional/test_aarch64_rme_sbsaref.py b/tests/functional/test_aarch64_rme_sbsaref.py
new file mode 100755
index 0000000..746770e
--- /dev/null
+++ b/tests/functional/test_aarch64_rme_sbsaref.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Realms environment on sbsa-ref machine and a
+# nested guest VM using it.
+#
+# Copyright (c) 2024 Linaro Ltd.
+#
+# Author: Pierrick Bouvier <pierrick.bouvier@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern
+from qemu_test import exec_command_and_wait_for_pattern
+from test_aarch64_rme_virt import test_realms_guest
+
+
+class Aarch64RMESbsaRefMachine(QemuSystemTest):
+
+ # Stack is built with OP-TEE build environment from those instructions:
+ # https://linaro.atlassian.net/wiki/spaces/QEMU/pages/29051027459/
+ # https://github.com/pbo-linaro/qemu-rme-stack
+ ASSET_RME_STACK_SBSA = Asset(
+ ('https://fileserver.linaro.org/s/KJyeBxL82mz2r7F/'
+ 'download/rme-stack-op-tee-4.2.0-cca-v4-sbsa.tar.gz'),
+ 'dd9ab28ec869bdf3b5376116cb3689103b43433fd5c4bca0f4a8d8b3c104999e')
+
+ # This tests the FEAT_RME cpu implementation, by booting a VM supporting it,
+ # and launching a nested VM using it.
+ def test_aarch64_rme_sbsaref(self):
+ self.set_machine('sbsa-ref')
+ self.require_accelerator('tcg')
+ self.require_netdev('user')
+
+ self.vm.set_console()
+
+ stack_path_tar_gz = self.ASSET_RME_STACK_SBSA.fetch()
+ self.archive_extract(stack_path_tar_gz, format="tar")
+
+ rme_stack = self.scratch_file('rme-stack-op-tee-4.2.0-cca-v4-sbsa')
+ pflash0 = os.path.join(rme_stack, 'images', 'SBSA_FLASH0.fd')
+ pflash1 = os.path.join(rme_stack, 'images', 'SBSA_FLASH1.fd')
+ virtual = os.path.join(rme_stack, 'images', 'disks', 'virtual')
+ drive = os.path.join(rme_stack, 'out-br', 'images', 'rootfs.ext4')
+
+ self.vm.add_args('-cpu', 'max,x-rme=on,pauth-impdef=on')
+ self.vm.add_args('-m', '2G')
+ self.vm.add_args('-M', 'sbsa-ref')
+ self.vm.add_args('-drive', f'file={pflash0},format=raw,if=pflash')
+ self.vm.add_args('-drive', f'file={pflash1},format=raw,if=pflash')
+ self.vm.add_args('-drive', f'file=fat:rw:{virtual},format=raw')
+ self.vm.add_args('-drive', f'format=raw,if=none,file={drive},id=hd0')
+ self.vm.add_args('-device', 'virtio-blk-pci,drive=hd0')
+ self.vm.add_args('-device', 'virtio-9p-pci,fsdev=shr0,mount_tag=shr0')
+ self.vm.add_args('-fsdev', f'local,security_model=none,path={rme_stack},id=shr0')
+ self.vm.add_args('-device', 'virtio-net-pci,netdev=net0')
+ self.vm.add_args('-netdev', 'user,id=net0')
+
+ self.vm.launch()
+ # Wait for host VM boot to complete.
+ wait_for_console_pattern(self, 'Welcome to Buildroot',
+ failure_message='Synchronous Exception at')
+ exec_command_and_wait_for_pattern(self, 'root', '#')
+
+ test_realms_guest(self)
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_aarch64_rme_virt.py b/tests/functional/test_aarch64_rme_virt.py
new file mode 100755
index 0000000..8452d27
--- /dev/null
+++ b/tests/functional/test_aarch64_rme_virt.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Realms environment on virt machine and a nested
+# guest VM using it.
+#
+# Copyright (c) 2024 Linaro Ltd.
+#
+# Author: Pierrick Bouvier <pierrick.bouvier@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import exec_command, wait_for_console_pattern
+from qemu_test import exec_command_and_wait_for_pattern
+
+def test_realms_guest(test_rme_instance):
+
+ # Boot the (nested) guest VM
+ exec_command(test_rme_instance,
+ 'qemu-system-aarch64 -M virt,gic-version=3 '
+ '-cpu host -enable-kvm -m 512M '
+ '-M confidential-guest-support=rme0 '
+ '-object rme-guest,id=rme0 '
+ '-device virtio-net-pci,netdev=net0,romfile= '
+ '-netdev user,id=net0 '
+ '-kernel /mnt/out/bin/Image '
+ '-initrd /mnt/out-br/images/rootfs.cpio '
+ '-serial stdio')
+ # Detect Realm activation during (nested) guest boot.
+ wait_for_console_pattern(test_rme_instance,
+ 'SMC_RMI_REALM_ACTIVATE')
+ # Wait for (nested) guest boot to complete.
+ wait_for_console_pattern(test_rme_instance,
+ 'Welcome to Buildroot')
+ exec_command_and_wait_for_pattern(test_rme_instance, 'root', '#')
+ # query (nested) guest cca report
+ exec_command(test_rme_instance, 'cca-workload-attestation report')
+ wait_for_console_pattern(test_rme_instance,
+ '"cca-platform-hash-algo-id": "sha-256"')
+ wait_for_console_pattern(test_rme_instance,
+ '"cca-realm-hash-algo-id": "sha-512"')
+ wait_for_console_pattern(test_rme_instance,
+ '"cca-realm-public-key-hash-algo-id": "sha-256"')
+
+class Aarch64RMEVirtMachine(QemuSystemTest):
+
+ # Stack is built with OP-TEE build environment from those instructions:
+ # https://linaro.atlassian.net/wiki/spaces/QEMU/pages/29051027459/
+ # https://github.com/pbo-linaro/qemu-rme-stack
+ ASSET_RME_STACK_VIRT = Asset(
+ ('https://fileserver.linaro.org/s/iaRsNDJp2CXHMSJ/'
+ 'download/rme-stack-op-tee-4.2.0-cca-v4-qemu_v8.tar.gz'),
+ '1851adc232b094384d8b879b9a2cfff07ef3d6205032b85e9b3a4a9ae6b0b7ad')
+
+ # This tests the FEAT_RME cpu implementation, by booting a VM supporting it,
+ # and launching a nested VM using it.
+ def test_aarch64_rme_virt(self):
+ self.set_machine('virt')
+ self.require_accelerator('tcg')
+ self.require_netdev('user')
+
+ self.vm.set_console()
+
+ stack_path_tar_gz = self.ASSET_RME_STACK_VIRT.fetch()
+ self.archive_extract(stack_path_tar_gz, format="tar")
+
+ rme_stack = self.scratch_file('rme-stack-op-tee-4.2.0-cca-v4-qemu_v8')
+ kernel = os.path.join(rme_stack, 'out', 'bin', 'Image')
+ bios = os.path.join(rme_stack, 'out', 'bin', 'flash.bin')
+ drive = os.path.join(rme_stack, 'out-br', 'images', 'rootfs.ext4')
+
+ self.vm.add_args('-cpu', 'max,x-rme=on,pauth-impdef=on')
+ self.vm.add_args('-m', '2G')
+ self.vm.add_args('-M', 'virt,acpi=off,'
+ 'virtualization=on,'
+ 'secure=on,'
+ 'gic-version=3')
+ self.vm.add_args('-bios', bios)
+ self.vm.add_args('-kernel', kernel)
+ self.vm.add_args('-drive', f'format=raw,if=none,file={drive},id=hd0')
+ self.vm.add_args('-device', 'virtio-blk-pci,drive=hd0')
+ self.vm.add_args('-device', 'virtio-9p-device,fsdev=shr0,mount_tag=shr0')
+ self.vm.add_args('-fsdev', f'local,security_model=none,path={rme_stack},id=shr0')
+ self.vm.add_args('-device', 'virtio-net-pci,netdev=net0')
+ self.vm.add_args('-netdev', 'user,id=net0')
+ # We need to add nokaslr to avoid triggering this sporadic bug:
+ # https://gitlab.com/qemu-project/qemu/-/issues/2823
+ self.vm.add_args('-append', 'root=/dev/vda nokaslr')
+
+ self.vm.launch()
+ # Wait for host VM boot to complete.
+ wait_for_console_pattern(self, 'Welcome to Buildroot',
+ failure_message='Synchronous Exception at')
+ exec_command_and_wait_for_pattern(self, 'root', '#')
+
+ test_realms_guest(self)
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_aarch64_sbsaref.py b/tests/functional/test_aarch64_sbsaref.py
index f31c2a6..d3402f5 100755
--- a/tests/functional/test_aarch64_sbsaref.py
+++ b/tests/functional/test_aarch64_sbsaref.py
@@ -1,20 +1,49 @@
#!/usr/bin/env python3
#
-# Functional test that boots a Linux kernel and checks the console
+# Functional test that boots a kernel and checks the console
#
-# SPDX-FileCopyrightText: 2023-2024 Linaro Ltd.
-# SPDX-FileContributor: Philippe Mathieu-Daudé <philmd@linaro.org>
-# SPDX-FileContributor: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
+# Copyright (c) 2023-2024 Linaro Ltd.
+#
+# Authors:
+# Philippe Mathieu-Daudé
+# Marcin Juszkiewicz
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
-
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
from qemu_test import interrupt_interactive_console_until_pattern
-from qemu_test.utils import lzma_uncompress
-from unittest import skipUnless
+
+
+def fetch_firmware(test):
+ """
+ Flash volumes generated using:
+
+ Toolchain from Debian:
+ aarch64-linux-gnu-gcc (Debian 12.2.0-14) 12.2.0
+
+ Used components:
+
+ - Trusted Firmware v2.12.0
+ - Tianocore EDK2 edk2-stable202411
+ - Tianocore EDK2-platforms 4b3530d
+
+ """
+
+ # Secure BootRom (TF-A code)
+ fs0_path = test.uncompress(Aarch64SbsarefMachine.ASSET_FLASH0)
+
+ # Non-secure rom (UEFI and EFI variables)
+ fs1_path = test.uncompress(Aarch64SbsarefMachine.ASSET_FLASH1)
+
+ for path in [fs0_path, fs1_path]:
+ with open(path, "ab+") as fd:
+ fd.truncate(256 << 20) # Expand volumes to 256MiB
+
+ test.vm.add_args(
+ "-drive", f"if=pflash,file={fs0_path},format=raw",
+ "-drive", f"if=pflash,file={fs1_path},format=raw",
+ )
class Aarch64SbsarefMachine(QemuSystemTest):
@@ -27,54 +56,21 @@ class Aarch64SbsarefMachine(QemuSystemTest):
ASSET_FLASH0 = Asset(
('https://artifacts.codelinaro.org/artifactory/linaro-419-sbsa-ref/'
- '20240619-148232/edk2/SBSA_FLASH0.fd.xz'),
- '0c954842a590988f526984de22e21ae0ab9cb351a0c99a8a58e928f0c7359cf7')
+ '20241122-189881/edk2/SBSA_FLASH0.fd.xz'),
+ '76eb89d42eebe324e4395329f47447cda9ac920aabcf99aca85424609c3384a5')
ASSET_FLASH1 = Asset(
('https://artifacts.codelinaro.org/artifactory/linaro-419-sbsa-ref/'
- '20240619-148232/edk2/SBSA_FLASH1.fd.xz'),
- 'c6ec39374c4d79bb9e9cdeeb6db44732d90bb4a334cec92002b3f4b9cac4b5ee')
+ '20241122-189881/edk2/SBSA_FLASH1.fd.xz'),
+ 'f850f243bd8dbd49c51e061e0f79f1697546938f454aeb59ab7d93e5f0d412fc')
- def fetch_firmware(self):
- """
- Flash volumes generated using:
-
- Toolchain from Debian:
- aarch64-linux-gnu-gcc (Debian 12.2.0-14) 12.2.0
-
- Used components:
-
- - Trusted Firmware v2.11.0
- - Tianocore EDK2 4d4f569924
- - Tianocore EDK2-platforms 3f08401
-
- """
-
- # Secure BootRom (TF-A code)
- fs0_xz_path = self.ASSET_FLASH0.fetch()
- fs0_path = os.path.join(self.workdir, "SBSA_FLASH0.fd")
- lzma_uncompress(fs0_xz_path, fs0_path)
-
- # Non-secure rom (UEFI and EFI variables)
- fs1_xz_path = self.ASSET_FLASH1.fetch()
- fs1_path = os.path.join(self.workdir, "SBSA_FLASH1.fd")
- lzma_uncompress(fs1_xz_path, fs1_path)
-
- for path in [fs0_path, fs1_path]:
- with open(path, "ab+") as fd:
- fd.truncate(256 << 20) # Expand volumes to 256MiB
+ def test_sbsaref_edk2_firmware(self):
self.set_machine('sbsa-ref')
- self.vm.set_console()
- self.vm.add_args(
- "-drive", f"if=pflash,file={fs0_path},format=raw",
- "-drive", f"if=pflash,file={fs1_path},format=raw",
- )
-
- def test_sbsaref_edk2_firmware(self):
- self.fetch_firmware()
+ fetch_firmware(self)
+ self.vm.set_console()
self.vm.add_args('-cpu', 'cortex-a57')
self.vm.launch()
@@ -87,100 +83,19 @@ class Aarch64SbsarefMachine(QemuSystemTest):
# AP Trusted ROM
wait_for_console_pattern(self, "Booting Trusted Firmware")
- wait_for_console_pattern(self, "BL1: v2.11.0(release):")
+ wait_for_console_pattern(self, "BL1: v2.12.0(release):")
wait_for_console_pattern(self, "BL1: Booting BL2")
# Trusted Boot Firmware
- wait_for_console_pattern(self, "BL2: v2.11.0(release)")
+ wait_for_console_pattern(self, "BL2: v2.12.0(release)")
wait_for_console_pattern(self, "Booting BL31")
# EL3 Runtime Software
- wait_for_console_pattern(self, "BL31: v2.11.0(release)")
+ wait_for_console_pattern(self, "BL31: v2.12.0(release)")
# Non-trusted Firmware
wait_for_console_pattern(self, "UEFI firmware (version 1.0")
interrupt_interactive_console_until_pattern(self, "QEMU SBSA-REF Machine")
-
- ASSET_ALPINE_ISO = Asset(
- ('https://dl-cdn.alpinelinux.org/'
- 'alpine/v3.17/releases/aarch64/alpine-standard-3.17.2-aarch64.iso'),
- '5a36304ecf039292082d92b48152a9ec21009d3a62f459de623e19c4bd9dc027')
-
- # This tests the whole boot chain from EFI to Userspace
- # We only boot a whole OS for the current top level CPU and GIC
- # Other test profiles should use more minimal boots
- def boot_alpine_linux(self, cpu):
- self.fetch_firmware()
-
- iso_path = self.ASSET_ALPINE_ISO.fetch()
-
- self.vm.set_console()
- self.vm.add_args(
- "-cpu", cpu,
- "-drive", f"file={iso_path},media=cdrom,format=raw",
- )
-
- self.vm.launch()
- wait_for_console_pattern(self, "Welcome to Alpine Linux 3.17")
-
- def test_sbsaref_alpine_linux_cortex_a57(self):
- self.boot_alpine_linux("cortex-a57")
-
- def test_sbsaref_alpine_linux_neoverse_n1(self):
- self.boot_alpine_linux("neoverse-n1")
-
- def test_sbsaref_alpine_linux_max_pauth_off(self):
- self.boot_alpine_linux("max,pauth=off")
-
- def test_sbsaref_alpine_linux_max_pauth_impdef(self):
- self.boot_alpine_linux("max,pauth-impdef=on")
-
- @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), 'Test might timeout')
- def test_sbsaref_alpine_linux_max(self):
- self.boot_alpine_linux("max")
-
-
- ASSET_OPENBSD_ISO = Asset(
- ('https://cdn.openbsd.org/pub/OpenBSD/7.3/arm64/miniroot73.img'),
- '7fc2c75401d6f01fbfa25f4953f72ad7d7c18650056d30755c44b9c129b707e5')
-
- # This tests the whole boot chain from EFI to Userspace
- # We only boot a whole OS for the current top level CPU and GIC
- # Other test profiles should use more minimal boots
- def boot_openbsd73(self, cpu):
- self.fetch_firmware()
-
- img_path = self.ASSET_OPENBSD_ISO.fetch()
-
- self.vm.set_console()
- self.vm.add_args(
- "-cpu", cpu,
- "-drive", f"file={img_path},format=raw,snapshot=on",
- )
-
- self.vm.launch()
- wait_for_console_pattern(self,
- "Welcome to the OpenBSD/arm64"
- " 7.3 installation program.")
-
- def test_sbsaref_openbsd73_cortex_a57(self):
- self.boot_openbsd73("cortex-a57")
-
- def test_sbsaref_openbsd73_neoverse_n1(self):
- self.boot_openbsd73("neoverse-n1")
-
- def test_sbsaref_openbsd73_max_pauth_off(self):
- self.boot_openbsd73("max,pauth=off")
-
- @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), 'Test might timeout')
- def test_sbsaref_openbsd73_max_pauth_impdef(self):
- self.boot_openbsd73("max,pauth-impdef=on")
-
- @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), 'Test might timeout')
- def test_sbsaref_openbsd73_max(self):
- self.boot_openbsd73("max")
-
-
if __name__ == '__main__':
QemuSystemTest.main()
diff --git a/tests/functional/test_aarch64_sbsaref_alpine.py b/tests/functional/test_aarch64_sbsaref_alpine.py
new file mode 100755
index 0000000..8776999
--- /dev/null
+++ b/tests/functional/test_aarch64_sbsaref_alpine.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a kernel and checks the console
+#
+# Copyright (c) 2023-2024 Linaro Ltd.
+#
+# Authors:
+# Philippe Mathieu-Daudé
+# Marcin Juszkiewicz
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import QemuSystemTest, Asset, skipSlowTest
+from qemu_test import wait_for_console_pattern
+from test_aarch64_sbsaref import fetch_firmware
+
+
+class Aarch64SbsarefAlpine(QemuSystemTest):
+
+ ASSET_ALPINE_ISO = Asset(
+ ('https://dl-cdn.alpinelinux.org/'
+ 'alpine/v3.17/releases/aarch64/alpine-standard-3.17.2-aarch64.iso'),
+ '5a36304ecf039292082d92b48152a9ec21009d3a62f459de623e19c4bd9dc027')
+
+ # This tests the whole boot chain from EFI to Userspace
+ # We only boot a whole OS for the current top level CPU and GIC
+ # Other test profiles should use more minimal boots
+ def boot_alpine_linux(self, cpu=None):
+ self.set_machine('sbsa-ref')
+
+ fetch_firmware(self)
+ iso_path = self.ASSET_ALPINE_ISO.fetch()
+
+ self.vm.set_console()
+ self.vm.add_args(
+ "-drive", f"file={iso_path},media=cdrom,format=raw",
+ )
+ if cpu:
+ self.vm.add_args("-cpu", cpu)
+
+ self.vm.launch()
+ wait_for_console_pattern(self, "Welcome to Alpine Linux 3.17")
+
+ def test_sbsaref_alpine_linux_cortex_a57(self):
+ self.boot_alpine_linux("cortex-a57")
+
+ def test_sbsaref_alpine_linux_default_cpu(self):
+ self.boot_alpine_linux()
+
+ def test_sbsaref_alpine_linux_max_pauth_off(self):
+ self.boot_alpine_linux("max,pauth=off")
+
+ def test_sbsaref_alpine_linux_max_pauth_impdef(self):
+ self.boot_alpine_linux("max,pauth-impdef=on")
+
+ @skipSlowTest() # Test might timeout due to PAuth emulation
+ def test_sbsaref_alpine_linux_max(self):
+ self.boot_alpine_linux("max")
+
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_aarch64_sbsaref_freebsd.py b/tests/functional/test_aarch64_sbsaref_freebsd.py
new file mode 100755
index 0000000..7ef016f
--- /dev/null
+++ b/tests/functional/test_aarch64_sbsaref_freebsd.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a kernel and checks the console
+#
+# Copyright (c) 2023-2024 Linaro Ltd.
+#
+# Authors:
+# Philippe Mathieu-Daudé
+# Marcin Juszkiewicz
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import QemuSystemTest, Asset, skipSlowTest
+from qemu_test import wait_for_console_pattern
+from test_aarch64_sbsaref import fetch_firmware
+
+
+class Aarch64SbsarefFreeBSD(QemuSystemTest):
+
+ ASSET_FREEBSD_ISO = Asset(
+ ('http://ftp-archive.freebsd.org/pub/FreeBSD-Archive/old-releases/arm64'
+ '/aarch64/ISO-IMAGES/14.1/FreeBSD-14.1-RELEASE-arm64-aarch64-bootonly.iso.xz'),
+ '7313a4495ffd71ab77b49b1e83f571521c32756e1d75bf48bd890e0ab0f75827')
+
+ # This tests the whole boot chain from EFI to Userspace
+ # We only boot a whole OS for the current top level CPU and GIC
+ # Other test profiles should use more minimal boots
+ def boot_freebsd14(self, cpu=None):
+ self.set_machine('sbsa-ref')
+
+ fetch_firmware(self)
+ img_path = self.uncompress(self.ASSET_FREEBSD_ISO)
+
+ self.vm.set_console()
+ self.vm.add_args(
+ "-drive", f"file={img_path},format=raw,snapshot=on",
+ )
+ if cpu:
+ self.vm.add_args("-cpu", cpu)
+
+ self.vm.launch()
+ wait_for_console_pattern(self, 'Welcome to FreeBSD!')
+
+ def test_sbsaref_freebsd14_cortex_a57(self):
+ self.boot_freebsd14("cortex-a57")
+
+ def test_sbsaref_freebsd14_default_cpu(self):
+ self.boot_freebsd14()
+
+ def test_sbsaref_freebsd14_max_pauth_off(self):
+ self.boot_freebsd14("max,pauth=off")
+
+ @skipSlowTest() # Test might timeout due to PAuth emulation
+ def test_sbsaref_freebsd14_max_pauth_impdef(self):
+ self.boot_freebsd14("max,pauth-impdef=on")
+
+ @skipSlowTest() # Test might timeout due to PAuth emulation
+ def test_sbsaref_freebsd14_max(self):
+ self.boot_freebsd14("max")
+
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_aarch64_smmu.py b/tests/functional/test_aarch64_smmu.py
new file mode 100755
index 0000000..e0f4a92
--- /dev/null
+++ b/tests/functional/test_aarch64_smmu.py
@@ -0,0 +1,211 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# SMMUv3 Functional tests
+#
+# Copyright (c) 2021 Red Hat, Inc.
+#
+# Author:
+# Eric Auger <eric.auger@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import os
+import time
+
+from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern
+from qemu_test import BUILD_DIR
+from qemu.utils import kvm_available, hvf_available
+
+
+class SMMU(LinuxKernelTest):
+
+ default_kernel_params = ('earlyprintk=pl011,0x9000000 no_timer_check '
+ 'printk.time=1 rd_NO_PLYMOUTH net.ifnames=0 '
+ 'console=ttyAMA0 rd.rescue')
+ IOMMU_ADDON = ',iommu_platform=on,disable-modern=off,disable-legacy=on'
+ kernel_path = None
+ initrd_path = None
+ kernel_params = None
+
+ GUEST_PORT = 8080
+
+ def set_up_boot(self, path):
+ self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,' +
+ 'drive=drv0,id=virtio-disk0,bootindex=1,'
+ 'werror=stop,rerror=stop' + self.IOMMU_ADDON)
+ self.vm.add_args('-drive',
+ f'file={path},if=none,cache=writethrough,id=drv0,snapshot=on')
+
+ self.vm.add_args('-netdev',
+ 'user,id=n1,hostfwd=tcp:127.0.0.1:0-:%d' %
+ self.GUEST_PORT)
+ self.vm.add_args('-device', 'virtio-net,netdev=n1' + self.IOMMU_ADDON)
+
+ def common_vm_setup(self, kernel, initrd, disk):
+ if hvf_available(self.qemu_bin):
+ accel = "hvf"
+ elif kvm_available(self.qemu_bin):
+ accel = "kvm"
+ else:
+ self.skipTest("Neither HVF nor KVM accelerator is available")
+ self.require_accelerator(accel)
+ self.require_netdev('user')
+ self.set_machine("virt")
+ self.vm.add_args('-m', '1G')
+ self.vm.add_args("-accel", accel)
+ self.vm.add_args("-cpu", "host")
+ self.vm.add_args("-machine", "iommu=smmuv3")
+ self.vm.add_args("-d", "guest_errors")
+ self.vm.add_args('-bios', os.path.join(BUILD_DIR, 'pc-bios',
+ 'edk2-aarch64-code.fd'))
+ self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
+ self.vm.add_args('-object',
+ 'rng-random,id=rng0,filename=/dev/urandom')
+
+ self.kernel_path = kernel.fetch()
+ self.initrd_path = initrd.fetch()
+ self.set_up_boot(disk.fetch())
+
+ def run_and_check(self, filename, hashsum):
+ self.vm.add_args('-initrd', self.initrd_path)
+ self.vm.add_args('-append', self.kernel_params)
+ self.launch_kernel(self.kernel_path, initrd=self.initrd_path,
+ wait_for='attach it to a bug report.')
+ prompt = '# '
+ # Fedora 33 requires 'return' to be pressed to enter the shell.
+ # There seems to be a small race between detecting the previous ':'
+ # and sending the newline, so we need to add a small delay here.
+ self.wait_for_console_pattern(':')
+ time.sleep(0.2)
+ exec_command_and_wait_for_pattern(self, '\n', prompt)
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cmdline',
+ self.kernel_params)
+
+ # Checking for SMMU enablement:
+ self.log.info("Checking whether SMMU has been enabled...")
+ exec_command_and_wait_for_pattern(self, 'dmesg | grep smmu',
+ 'arm-smmu-v3')
+ self.wait_for_console_pattern(prompt)
+ exec_command_and_wait_for_pattern(self,
+ 'find /sys/kernel/iommu_groups/ -type l',
+ 'devices/0000:00:')
+ self.wait_for_console_pattern(prompt)
+
+ # Copy a file (checked later), umount afterwards to drop disk cache:
+ self.log.info("Checking hard disk...")
+ exec_command_and_wait_for_pattern(self,
+ "while ! (dmesg -c | grep vda:) ; do sleep 1 ; done",
+ "vda2")
+ exec_command_and_wait_for_pattern(self, 'mount /dev/vda2 /sysroot',
+ 'mounted filesystem')
+ exec_command_and_wait_for_pattern(self, 'cp /bin/vi /sysroot/root/vi',
+ prompt)
+ exec_command_and_wait_for_pattern(self, 'umount /sysroot', prompt)
+ # Switch from initrd to the cloud image filesystem:
+ exec_command_and_wait_for_pattern(self, 'mount /dev/vda2 /sysroot',
+ prompt)
+ exec_command_and_wait_for_pattern(self,
+ ('for d in dev proc sys run ; do '
+ 'mount -o bind /$d /sysroot/$d ; done'), prompt)
+ exec_command_and_wait_for_pattern(self, 'chroot /sysroot', prompt)
+ # Check files on the hard disk:
+ exec_command_and_wait_for_pattern(self,
+ ('if diff -q /root/vi /usr/bin/vi ; then echo "file" "ok" ; '
+ 'else echo "files differ"; fi'), 'file ok')
+ self.wait_for_console_pattern(prompt)
+ exec_command_and_wait_for_pattern(self, f'sha256sum {filename}',
+ hashsum)
+
+ # Check virtio-net via HTTP:
+ exec_command_and_wait_for_pattern(self, 'dhclient eth0', prompt)
+ self.check_http_download(filename, hashsum, self.GUEST_PORT)
+
+
+ # 5.3 kernel without RIL #
+
+ ASSET_KERNEL_F31 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/'
+ 'releases/31/Server/aarch64/os/images/pxeboot/vmlinuz'),
+ '3ae07fcafbfc8e4abeb693035a74fe10698faae15e9ccd48882a9167800c1527')
+
+ ASSET_INITRD_F31 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/'
+ 'releases/31/Server/aarch64/os/images/pxeboot/initrd.img'),
+ '9f3146b28bc531c689f3c5f114cb74e4bd7bd548e0ba19fa77921d8bd256755a')
+
+ ASSET_DISK_F31 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Cloud/aarch64/images/Fedora-Cloud-Base-31-1.9.aarch64.qcow2'),
+ '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49')
+
+ F31_FILENAME = '/boot/initramfs-5.3.7-301.fc31.aarch64.img'
+ F31_HSUM = '1a4beec6607d94df73d9dd1b4985c9c23dd0fdcf4e6ca1351d477f190df7bef9'
+
+ def test_smmu_noril(self):
+ self.common_vm_setup(self.ASSET_KERNEL_F31, self.ASSET_INITRD_F31,
+ self.ASSET_DISK_F31)
+ self.kernel_params = self.default_kernel_params
+ self.run_and_check(self.F31_FILENAME, self.F31_HSUM)
+
+ def test_smmu_noril_passthrough(self):
+ self.common_vm_setup(self.ASSET_KERNEL_F31, self.ASSET_INITRD_F31,
+ self.ASSET_DISK_F31)
+ self.kernel_params = (self.default_kernel_params +
+ ' iommu.passthrough=on')
+ self.run_and_check(self.F31_FILENAME, self.F31_HSUM)
+
+ def test_smmu_noril_nostrict(self):
+ self.common_vm_setup(self.ASSET_KERNEL_F31, self.ASSET_INITRD_F31,
+ self.ASSET_DISK_F31)
+ self.kernel_params = (self.default_kernel_params +
+ ' iommu.strict=0')
+ self.run_and_check(self.F31_FILENAME, self.F31_HSUM)
+
+
+ # 5.8 kernel featuring range invalidation
+ # >= v5.7 kernel
+
+ ASSET_KERNEL_F33 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/'
+ 'releases/33/Server/aarch64/os/images/pxeboot/vmlinuz'),
+ 'd8b1e6f7241f339d8e7609c456cf0461ffa4583ed07e0b55c7d1d8a0c154aa89')
+
+ ASSET_INITRD_F33 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/'
+ 'releases/33/Server/aarch64/os/images/pxeboot/initrd.img'),
+ '92513f55295c2c16a777f7b6c35ccd70a438e9e1e40b6ba39e0e60900615b3df')
+
+ ASSET_DISK_F33 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/33/Cloud/aarch64/images/Fedora-Cloud-Base-33-1.2.aarch64.qcow2'),
+ 'e7f75cdfd523fe5ac2ca9eeece68edc1a81f386a17f969c1d1c7c87031008a6b')
+
+ F33_FILENAME = '/boot/initramfs-5.8.15-301.fc33.aarch64.img'
+ F33_HSUM = '079cfad0caa82e84c8ca1fb0897a4999dd769f262216099f518619e807a550d9'
+
+ def test_smmu_ril(self):
+ self.common_vm_setup(self.ASSET_KERNEL_F33, self.ASSET_INITRD_F33,
+ self.ASSET_DISK_F33)
+ self.kernel_params = self.default_kernel_params
+ self.run_and_check(self.F33_FILENAME, self.F33_HSUM)
+
+ def test_smmu_ril_passthrough(self):
+ self.common_vm_setup(self.ASSET_KERNEL_F33, self.ASSET_INITRD_F33,
+ self.ASSET_DISK_F33)
+ self.kernel_params = (self.default_kernel_params +
+ ' iommu.passthrough=on')
+ self.run_and_check(self.F33_FILENAME, self.F33_HSUM)
+
+ def test_smmu_ril_nostrict(self):
+ self.common_vm_setup(self.ASSET_KERNEL_F33, self.ASSET_INITRD_F33,
+ self.ASSET_DISK_F33)
+ self.kernel_params = (self.default_kernel_params +
+ ' iommu.strict=0')
+ self.run_and_check(self.F33_FILENAME, self.F33_HSUM)
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/avocado/tcg_plugins.py b/tests/functional/test_aarch64_tcg_plugins.py
index a6ff457..cb7e929 100644..100755
--- a/tests/avocado/tcg_plugins.py
+++ b/tests/functional/test_aarch64_tcg_plugins.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# TCG Plugins tests
#
# These are a little more involved than the basic tests run by check-tcg.
@@ -13,7 +15,8 @@ import tempfile
import mmap
import re
-from boot_linux_console import LinuxKernelTest
+from qemu.machine.machine import VMLaunchFailure
+from qemu_test import LinuxKernelTest, Asset
class PluginKernelBase(LinuxKernelTest):
@@ -41,10 +44,12 @@ class PluginKernelBase(LinuxKernelTest):
try:
vm.launch()
- except:
- # TODO: probably fails because plugins not enabled but we
- # can't currently probe for the feature.
- self.cancel("TCG Plugins not enabled?")
+ except VMLaunchFailure as excp:
+ if "plugin interface not enabled in this build" in excp.output:
+ self.skipTest("TCG plugins not enabled")
+ else:
+ self.log.info(f"unhandled launch failure: {excp.output}")
+ raise excp
self.wait_for_console_pattern(console_pattern, vm)
# ensure logs are flushed
@@ -53,31 +58,23 @@ class PluginKernelBase(LinuxKernelTest):
class PluginKernelNormal(PluginKernelBase):
- def _grab_aarch64_kernel(self):
- kernel_url = ('https://storage.tuxboot.com/20230331/arm64/Image')
- kernel_sha256 = 'ce95a7101a5fecebe0fe630deee6bd97b32ba41bc8754090e9ad8961ea8674c7'
- kernel_path = self.fetch_asset(kernel_url,
- asset_hash=kernel_sha256,
- algorithm = "sha256")
- return kernel_path
+ ASSET_KERNEL = Asset(
+ ('https://storage.tuxboot.com/20230331/arm64/Image'),
+ 'ce95a7101a5fecebe0fe630deee6bd97b32ba41bc8754090e9ad8961ea8674c7')
def test_aarch64_virt_insn(self):
- """
- :avocado: tags=accel:tcg
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:virt
- :avocado: tags=cpu:cortex-a53
- """
- kernel_path = self._grab_aarch64_kernel()
+ self.set_machine('virt')
+ self.cpu='cortex-a53'
+ kernel_path = self.ASSET_KERNEL.fetch()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'console=ttyAMA0')
- console_pattern = 'Kernel panic - not syncing: VFS:'
+ console_pattern = 'Please append a correct "root=" boot option'
plugin_log = tempfile.NamedTemporaryFile(mode="r+t", prefix="plugin",
suffix=".log")
self.run_vm(kernel_path, kernel_command_line,
- "tests/tcg/plugins/libinsn.so", plugin_log.name,
+ self.plugin_file('libinsn'), plugin_log.name,
console_pattern)
with plugin_log as lf, \
@@ -92,22 +89,18 @@ class PluginKernelNormal(PluginKernelBase):
def test_aarch64_virt_insn_icount(self):
- """
- :avocado: tags=accel:tcg
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:virt
- :avocado: tags=cpu:cortex-a53
- """
- kernel_path = self._grab_aarch64_kernel()
+ self.set_machine('virt')
+ self.cpu='cortex-a53'
+ kernel_path = self.ASSET_KERNEL.fetch()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'console=ttyAMA0')
- console_pattern = 'Kernel panic - not syncing: VFS:'
+ console_pattern = 'Please append a correct "root=" boot option'
plugin_log = tempfile.NamedTemporaryFile(mode="r+t", prefix="plugin",
suffix=".log")
self.run_vm(kernel_path, kernel_command_line,
- "tests/tcg/plugins/libinsn.so", plugin_log.name,
+ self.plugin_file('libinsn'), plugin_log.name,
console_pattern,
args=('-icount', 'shift=1'))
@@ -120,3 +113,6 @@ class PluginKernelNormal(PluginKernelBase):
else:
count = int(m.group("count"))
self.log.info(f"Counted: {count} instructions")
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_aarch64_tuxrun.py b/tests/functional/test_aarch64_tuxrun.py
new file mode 100755
index 0000000..75adc8a
--- /dev/null
+++ b/tests/functional/test_aarch64_tuxrun.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunAarch64Test(TuxRunBaselineTest):
+
+ ASSET_ARM64_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/arm64/Image',
+ 'b74743c5e89e1cea0f73368d24ae0ae85c5204ff84be3b5e9610417417d2f235')
+ ASSET_ARM64_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/arm64/rootfs.ext4.zst',
+ 'a1acaaae2068df4648d04ff75f532aaa8c5edcd6b936122b6f0db4848a07b465')
+
+ def test_arm64(self):
+ self.set_machine('virt')
+ self.cpu='cortex-a57'
+ self.console='ttyAMA0'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_ARM64_KERNEL,
+ rootfs_asset=self.ASSET_ARM64_ROOTFS)
+
+ ASSET_ARM64BE_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/arm64be/Image',
+ 'fd6af4f16689d17a2c24fe0053cc212edcdf77abdcaf301800b8d38fa9f6e109')
+ ASSET_ARM64BE_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/arm64be/rootfs.ext4.zst',
+ 'f5e9371b62701aab8dead52592ca7488c8a9e255c9be8d7635c7f30f477c2c21')
+
+ def test_arm64be(self):
+ self.set_machine('virt')
+ self.cpu='cortex-a57'
+ self.console='ttyAMA0'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_ARM64BE_KERNEL,
+ rootfs_asset=self.ASSET_ARM64BE_ROOTFS)
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_aarch64_virt.py b/tests/functional/test_aarch64_virt.py
index c967da4..4d0ad90 100755
--- a/tests/functional/test_aarch64_virt.py
+++ b/tests/functional/test_aarch64_virt.py
@@ -10,14 +10,11 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import time
-import os
import logging
+from subprocess import check_call, DEVNULL
-from qemu_test import BUILD_DIR
-from qemu_test import QemuSystemTest, Asset
-from qemu_test import exec_command, wait_for_console_pattern
-from qemu_test import get_qemu_img, run_cmd
+from qemu_test import QemuSystemTest, Asset, exec_command_and_wait_for_pattern
+from qemu_test import wait_for_console_pattern, get_qemu_img
class Aarch64VirtMachine(QemuSystemTest):
@@ -41,11 +38,9 @@ class Aarch64VirtMachine(QemuSystemTest):
iso_path = self.ASSET_ALPINE_ISO.fetch()
self.set_machine('virt')
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyAMA0')
self.require_accelerator("tcg")
+ self.vm.set_console()
self.vm.add_args("-accel", "tcg")
self.vm.add_args("-cpu", "max,pauth-impdef=on")
self.vm.add_args("-machine",
@@ -54,8 +49,8 @@ class Aarch64VirtMachine(QemuSystemTest):
"mte=on,"
"gic-version=max,iommu=smmuv3")
self.vm.add_args("-smp", "2", "-m", "1024")
- self.vm.add_args('-bios', os.path.join(BUILD_DIR, 'pc-bios',
- 'edk2-aarch64-code.fd'))
+ self.vm.add_args('-bios', self.build_file('pc-bios',
+ 'edk2-aarch64-code.fd'))
self.vm.add_args("-drive", f"file={iso_path},media=cdrom,format=raw")
self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom')
@@ -74,15 +69,16 @@ class Aarch64VirtMachine(QemuSystemTest):
Common code to launch basic virt machine with kernel+initrd
and a scratch disk.
"""
+ self.set_machine('virt')
+ self.require_accelerator("tcg")
+
logger = logging.getLogger('aarch64_virt')
kernel_path = self.ASSET_KERNEL.fetch()
- self.set_machine('virt')
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'console=ttyAMA0')
- self.require_accelerator("tcg")
self.vm.add_args('-cpu', 'max,pauth-impdef=on',
'-machine', machine,
'-accel', 'tcg',
@@ -96,29 +92,36 @@ class Aarch64VirtMachine(QemuSystemTest):
# Also add a scratch block device
logger.info('creating scratch qcow2 image')
- image_path = os.path.join(self.workdir, 'scratch.qcow2')
+ image_path = self.scratch_file('scratch.qcow2')
qemu_img = get_qemu_img(self)
- run_cmd([qemu_img, 'create', '-f', 'qcow2', image_path, '8M'])
+ check_call([qemu_img, 'create', '-f', 'qcow2', image_path, '8M'],
+ stdout=DEVNULL, stderr=DEVNULL)
# Add the device
self.vm.add_args('-blockdev',
- f"driver=qcow2,file.driver=file,file.filename={image_path},node-name=scratch")
+ "driver=qcow2,"
+ "file.driver=file,"
+ f"file.filename={image_path},node-name=scratch")
self.vm.add_args('-device',
'virtio-blk-device,drive=scratch')
self.vm.launch()
- self.wait_for_console_pattern('Welcome to Buildroot')
- time.sleep(0.1)
- exec_command(self, 'root')
- time.sleep(0.1)
- exec_command(self, 'dd if=/dev/hwrng of=/dev/vda bs=512 count=4')
- time.sleep(0.1)
- exec_command(self, 'md5sum /dev/vda')
- time.sleep(0.1)
- exec_command(self, 'cat /proc/interrupts')
- time.sleep(0.1)
- exec_command(self, 'cat /proc/self/maps')
- time.sleep(0.1)
+
+ ps1='#'
+ self.wait_for_console_pattern('login:')
+
+ commands = [
+ ('root', ps1),
+ ('cat /proc/interrupts', ps1),
+ ('cat /proc/self/maps', ps1),
+ ('uname -a', ps1),
+ ('dd if=/dev/hwrng of=/dev/vda bs=512 count=4', ps1),
+ ('md5sum /dev/vda', ps1),
+ ('halt -n', 'reboot: System halted')
+ ]
+
+ for cmd, pattern in commands:
+ exec_command_and_wait_for_pattern(self, cmd, pattern)
def test_aarch64_virt_gicv3(self):
self.common_aarch64_virt("virt,gic_version=3")
@@ -127,5 +130,6 @@ class Aarch64VirtMachine(QemuSystemTest):
self.common_aarch64_virt("virt,gic-version=2")
+
if __name__ == '__main__':
QemuSystemTest.main()
diff --git a/tests/functional/test_aarch64_virt_gpu.py b/tests/functional/test_aarch64_virt_gpu.py
new file mode 100755
index 0000000..3844727
--- /dev/null
+++ b/tests/functional/test_aarch64_virt_gpu.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python3
+#
+# Functional tests for the various graphics modes we can support.
+#
+# Copyright (c) 2024, 2025 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu.machine.machine import VMLaunchFailure
+
+from qemu_test import Asset
+from qemu_test import exec_command_and_wait_for_pattern as ec_and_wait
+from qemu_test import skipIfMissingCommands
+
+from qemu_test.linuxkernel import LinuxKernelTest
+
+from re import search
+from subprocess import check_output, CalledProcessError
+
+class Aarch64VirtGPUMachine(LinuxKernelTest):
+
+ ASSET_VIRT_GPU_KERNEL = Asset(
+ 'https://fileserver.linaro.org/s/ce5jXBFinPxtEdx/'
+ 'download?path=%2F&files='
+ 'Image.6.12.16.aarch64',
+ '7888c51c55d37e86bbbdeb5acea9f08c34e6b0f03c1f5b2463285f6a6f6eec8b')
+
+ ASSET_VIRT_GPU_ROOTFS = Asset(
+ 'https://fileserver.linaro.org/s/ce5jXBFinPxtEdx/'
+ 'download?path=%2F&files='
+ 'rootfs.aarch64.ext2.zstd',
+ 'd45118c899420b7e673f1539a37a35480134b3e36e3a59e2cb69b1781cbb14ef')
+
+ def _launch_virt_gpu(self, gpu_device):
+
+ self.set_machine('virt')
+ self.require_accelerator("tcg")
+
+ kernel_path = self.ASSET_VIRT_GPU_KERNEL.fetch()
+ image_path = self.uncompress(self.ASSET_VIRT_GPU_ROOTFS, format="zstd")
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyAMA0 root=/dev/vda')
+
+ self.vm.add_args("-accel", "tcg")
+ self.vm.add_args("-cpu", "cortex-a72")
+ self.vm.add_args("-machine", "virt,gic-version=max",
+ '-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.add_args("-smp", "2", "-m", "2048")
+ self.vm.add_args("-device", gpu_device)
+ self.vm.add_args("-display", "egl-headless")
+ self.vm.add_args("-display", "dbus,gl=on")
+
+ self.vm.add_args("-device", "virtio-blk-device,drive=hd0")
+ self.vm.add_args("-blockdev",
+ "driver=raw,file.driver=file,"
+ "node-name=hd0,read-only=on,"
+ f"file.filename={image_path}")
+ self.vm.add_args("-snapshot")
+
+ try:
+ self.vm.launch()
+ except VMLaunchFailure as excp:
+ if "old virglrenderer, blob resources unsupported" in excp.output:
+ self.skipTest("No blob support for virtio-gpu")
+ elif "old virglrenderer, venus unsupported" in excp.output:
+ self.skipTest("No venus support for virtio-gpu")
+ elif "egl: no drm render node available" in excp.output:
+ self.skipTest("Can't access host DRM render node")
+ elif "'type' does not accept value 'egl-headless'" in excp.output:
+ self.skipTest("egl-headless support is not available")
+ elif "'type' does not accept value 'dbus'" in excp.output:
+ self.skipTest("dbus display support is not available")
+ else:
+ self.log.info("unhandled launch failure: %s", excp.output)
+ raise excp
+
+ self.wait_for_console_pattern('buildroot login:')
+ ec_and_wait(self, 'root', '#')
+
+ def _run_virt_weston_test(self, cmd, fail = None):
+
+ # make it easier to detect successful return to shell
+ PS1 = 'RES=[$?] # '
+ OK_CMD = 'RES=[0] # '
+
+ ec_and_wait(self, 'export XDG_RUNTIME_DIR=/tmp', '#')
+ ec_and_wait(self, f"export PS1='{PS1}'", OK_CMD)
+ full_cmd = f"weston -B headless --renderer gl --shell kiosk -- {cmd}"
+ ec_and_wait(self, full_cmd, OK_CMD, fail)
+
+ @skipIfMissingCommands('zstd')
+ def test_aarch64_virt_with_virgl_gpu(self):
+
+ self.require_device('virtio-gpu-gl-pci')
+
+ self._launch_virt_gpu("virtio-gpu-gl-pci")
+
+ # subset of the glmark tests
+ tests = " ".join([f"-b {test}" for test in
+ ["build", "texture", "shading",
+ "bump", "desktop", "buffer"]])
+
+ self._run_virt_weston_test("glmark2-wayland --validate " + tests)
+
+ @skipIfMissingCommands('zstd')
+ def test_aarch64_virt_with_virgl_blobs_gpu(self):
+
+ self.require_device('virtio-gpu-gl-pci')
+
+ self._launch_virt_gpu("virtio-gpu-gl-pci,hostmem=4G,blob=on")
+ self._run_virt_weston_test("glmark2-wayland -b:duration=1.0")
+
+ @skipIfMissingCommands('zstd')
+ @skipIfMissingCommands('vulkaninfo')
+ def test_aarch64_virt_with_vulkan_gpu(self):
+
+ self.require_device('virtio-gpu-gl-pci')
+
+ try:
+ vk_info = check_output(["vulkaninfo", "--summary"],
+ encoding="utf-8")
+ except CalledProcessError as excp:
+ self.skipTest(f"Miss-configured host Vulkan: {excp.output}")
+
+ if search(r"driverID\s+=\s+DRIVER_ID_NVIDIA_PROPRIETARY", vk_info):
+ self.skipTest("Test skipped on NVIDIA proprietary driver")
+
+ self._launch_virt_gpu("virtio-gpu-gl-pci,hostmem=4G,blob=on,venus=on")
+ self._run_virt_weston_test("vkmark -b:duration=1.0",
+ "debug: stuck in fence wait with iter at")
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_aarch64_xen.py b/tests/functional/test_aarch64_xen.py
new file mode 100755
index 0000000..261d796
--- /dev/null
+++ b/tests/functional/test_aarch64_xen.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Xen hypervisor with a domU kernel and
+# checks the console output is vaguely sane .
+#
+# Copyright (c) 2020 Linaro
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from qemu_test import Asset, LinuxKernelTest, wait_for_console_pattern
+
+
+class BootXen(LinuxKernelTest):
+ """
+ Boots a Xen hypervisor with a Linux DomU kernel.
+ """
+
+ timeout = 90
+ XEN_COMMON_COMMAND_LINE = 'dom0_mem=128M loglvl=all guest_loglvl=all'
+
+ ASSET_KERNEL = Asset(
+ ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/'
+ 'download?path=%2F&files=linux-5.9.9-arm64-ajb'),
+ '00366fa51ea957c19462d2e2aefd480bef80ce727120e714ae48e0c88f261edb')
+
+ def launch_xen(self, xen_path):
+ """
+ Launch Xen with a dom0 guest kernel
+ """
+ self.require_accelerator("tcg") # virtualization=on
+ self.set_machine('virt')
+ self.cpu = "cortex-a57"
+ self.kernel_path = self.ASSET_KERNEL.fetch()
+ self.log.info("launch with xen_path: %s", xen_path)
+
+ self.vm.set_console()
+
+ self.vm.add_args('-machine', 'virtualization=on',
+ '-m', '768',
+ '-kernel', xen_path,
+ '-append', self.XEN_COMMON_COMMAND_LINE,
+ '-device',
+ 'guest-loader,addr=0x47000000,kernel=%s,bootargs=console=hvc0'
+ % (self.kernel_path))
+
+ self.vm.launch()
+
+ console_pattern = 'VFS: Cannot open root device'
+ wait_for_console_pattern(self, console_pattern, "Panic on CPU 0:")
+
+ ASSET_XEN_4_11 = Asset(
+ ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/download?path=%2F&'
+ 'files=xen-hypervisor-4.11-arm64_4.11.4%2B37-g3263f257ca-1_arm64.deb'),
+ 'b745c2631342f9fcc0147ddc364edb62c20ecfebd430e5a3546e7d7c6891c0bc')
+
+ def test_arm64_xen_411_and_dom0(self):
+ # archive of file from https://deb.debian.org/debian/pool/main/x/xen/
+ xen_path = self.archive_extract(self.ASSET_XEN_4_11, format='deb',
+ member="boot/xen-4.11-arm64")
+ self.launch_xen(xen_path)
+
+ ASSET_XEN_4_14 = Asset(
+ ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/download?path=%2F&'
+ 'files=xen-hypervisor-4.14-arm64_4.14.0%2B80-gd101b417b7-1_arm64.deb'),
+ 'e930a3293248edabd367d5b4b3b6448b9c99c057096ea8b47228a7870661d5cb')
+
+ def test_arm64_xen_414_and_dom0(self):
+ # archive of file from https://deb.debian.org/debian/pool/main/x/xen/
+ xen_path = self.archive_extract(self.ASSET_XEN_4_14, format='deb',
+ member="boot/xen-4.14-arm64")
+ self.launch_xen(xen_path)
+
+ ASSET_XEN_4_15 = Asset(
+ ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/download?path=%2F&'
+ 'files=xen-upstream-4.15-unstable.deb'),
+ '2a9a8af8acf0231844657cc28baab95bd918b0ee2d493ee4ee6f8846e1358bc9')
+
+ def test_arm64_xen_415_and_dom0(self):
+ xen_path = self.archive_extract(self.ASSET_XEN_4_15, format='deb',
+ member="boot/xen-4.15-unstable")
+ self.launch_xen(xen_path)
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_aarch64_xlnx_versal.py b/tests/functional/test_aarch64_xlnx_versal.py
new file mode 100755
index 0000000..4b9c49e
--- /dev/null
+++ b/tests/functional/test_aarch64_xlnx_versal.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+class XlnxVersalVirtMachine(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ ('http://ports.ubuntu.com/ubuntu-ports/dists/bionic-updates/main/'
+ 'installer-arm64/20101020ubuntu543.19/images/netboot/'
+ 'ubuntu-installer/arm64/linux'),
+ 'ce54f74ab0b15cfd13d1a293f2d27ffd79d8a85b7bb9bf21093ae9513864ac79')
+
+ ASSET_INITRD = Asset(
+ ('http://ports.ubuntu.com/ubuntu-ports/dists/bionic-updates/main/'
+ 'installer-arm64/20101020ubuntu543.19/images/netboot/'
+ '/ubuntu-installer/arm64/initrd.gz'),
+ 'e7a5e716b6f516d8be315c06e7331aaf16994fe4222e0e7cfb34bc015698929e')
+
+ def test_aarch64_xlnx_versal_virt(self):
+ self.set_machine('xlnx-versal-virt')
+ kernel_path = self.ASSET_KERNEL.fetch()
+ initrd_path = self.ASSET_INITRD.fetch()
+
+ self.vm.set_console()
+ self.vm.add_args('-m', '2G',
+ '-accel', 'tcg',
+ '-kernel', kernel_path,
+ '-initrd', initrd_path)
+ self.vm.launch()
+ self.wait_for_console_pattern('Checked W+X mappings: passed')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_acpi_bits.py b/tests/functional/test_acpi_bits.py
index ee40647..8e0563a 100755
--- a/tests/functional/test_acpi_bits.py
+++ b/tests/functional/test_acpi_bits.py
@@ -31,57 +31,24 @@ including an upgraded acpica. The fork is located here:
https://gitlab.com/qemu-project/biosbits-bits .
"""
-import logging
import os
-import platform
import re
import shutil
import subprocess
-import tarfile
-import tempfile
-import time
-import zipfile
-from pathlib import Path
from typing import (
List,
Optional,
Sequence,
)
from qemu.machine import QEMUMachine
-from unittest import skipIf
-from qemu_test import QemuBaseTest, Asset
+from qemu_test import (QemuSystemTest, Asset, skipIfMissingCommands,
+ skipIfNotMachine)
-deps = ["xorriso", "mformat"] # dependent tools needed in the test setup/box.
-supported_platforms = ['x86_64'] # supported test platforms.
# default timeout of 120 secs is sometimes not enough for bits test.
BITS_TIMEOUT = 200
-def which(tool):
- """ looks up the full path for @tool, returns None if not found
- or if @tool does not have executable permissions.
- """
- paths=os.getenv('PATH')
- for p in paths.split(os.path.pathsep):
- p = os.path.join(p, tool)
- if os.path.exists(p) and os.access(p, os.X_OK):
- return p
- return None
-
-def missing_deps():
- """ returns True if any of the test dependent tools are absent.
- """
- for dep in deps:
- if which(dep) is None:
- return True
- return False
-
-def supported_platform():
- """ checks if the test is running on a supported platform.
- """
- return platform.machine() in supported_platforms
-
class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods
"""
A QEMU VM, with isa-debugcon enabled and bits iso passed
@@ -124,10 +91,9 @@ class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods
"""return the base argument to QEMU binary"""
return self._base_args
-@skipIf(not supported_platform() or missing_deps(),
- 'unsupported platform or dependencies (%s) not installed' \
- % ','.join(deps))
-class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
+@skipIfMissingCommands("xorriso", "mformat")
+@skipIfNotMachine("x86_64")
+class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attributes
"""
ACPI and SMBIOS tests using biosbits.
"""
@@ -150,12 +116,9 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._vm = None
- self._workDir = None
- self._baseDir = None
self._debugcon_addr = '0x403'
self._debugcon_log = 'debugcon-log.txt'
- self.logger = self.log
def _print_log(self, log):
self.logger.info('\nlogs from biosbits follows:')
@@ -166,29 +129,24 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
def copy_bits_config(self):
""" copies the bios bits config file into bits.
"""
- config_file = 'bits-cfg.txt'
- bits_config_dir = os.path.join(self._baseDir, 'acpi-bits',
- 'bits-config')
- target_config_dir = os.path.join(self._workDir,
- 'bits-%d' %self.BITS_INTERNAL_VER,
- 'boot')
- self.assertTrue(os.path.exists(bits_config_dir))
+ bits_config_file = self.data_file('acpi-bits',
+ 'bits-config',
+ 'bits-cfg.txt')
+ target_config_dir = self.scratch_file('bits-%d' %
+ self.BITS_INTERNAL_VER,
+ 'boot')
+ self.assertTrue(os.path.exists(bits_config_file))
self.assertTrue(os.path.exists(target_config_dir))
- self.assertTrue(os.access(os.path.join(bits_config_dir,
- config_file), os.R_OK))
- shutil.copy2(os.path.join(bits_config_dir, config_file),
- target_config_dir)
+ shutil.copy2(bits_config_file, target_config_dir)
self.logger.info('copied config file %s to %s',
- config_file, target_config_dir)
+ bits_config_file, target_config_dir)
def copy_test_scripts(self):
"""copies the python test scripts into bits. """
- bits_test_dir = os.path.join(self._baseDir, 'acpi-bits',
- 'bits-tests')
- target_test_dir = os.path.join(self._workDir,
- 'bits-%d' %self.BITS_INTERNAL_VER,
- 'boot', 'python')
+ bits_test_dir = self.data_file('acpi-bits', 'bits-tests')
+ target_test_dir = self.scratch_file('bits-%d' % self.BITS_INTERNAL_VER,
+ 'boot', 'python')
self.assertTrue(os.path.exists(bits_test_dir))
self.assertTrue(os.path.exists(target_test_dir))
@@ -196,11 +154,12 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
for filename in os.listdir(bits_test_dir):
if os.path.isfile(os.path.join(bits_test_dir, filename)) and \
filename.endswith('.py2'):
- # all test scripts are named with extension .py2 so that
- # avocado does not try to load them. These scripts are
- # written for python 2.7 not python 3 and hence if avocado
- # loaded them, it would complain about python 3 specific
- # syntaxes.
+ # All test scripts are named with extension .py2 so that
+ # they are not run by accident.
+ #
+ # These scripts are intended to run inside the test VM
+ # and are written for python 2.7 not python 3, hence
+ # would cause syntax errors if loaded ouside the VM.
newfilename = os.path.splitext(filename)[0] + '.py'
shutil.copy2(os.path.join(bits_test_dir, filename),
os.path.join(target_test_dir, newfilename))
@@ -224,8 +183,8 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
the directory where we have extracted our pre-built bits grub
tarball.
"""
- grub_x86_64_mods = os.path.join(self._workDir, 'grub-inst-x86_64-efi')
- grub_i386_mods = os.path.join(self._workDir, 'grub-inst')
+ grub_x86_64_mods = self.scratch_file('grub-inst-x86_64-efi')
+ grub_i386_mods = self.scratch_file('grub-inst')
self.assertTrue(os.path.exists(grub_x86_64_mods))
self.assertTrue(os.path.exists(grub_i386_mods))
@@ -246,13 +205,11 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
""" Uses grub-mkrescue to generate a fresh bits iso with the python
test scripts
"""
- bits_dir = os.path.join(self._workDir,
- 'bits-%d' %self.BITS_INTERNAL_VER)
- iso_file = os.path.join(self._workDir,
- 'bits-%d.iso' %self.BITS_INTERNAL_VER)
- mkrescue_script = os.path.join(self._workDir,
- 'grub-inst-x86_64-efi', 'bin',
- 'grub-mkrescue')
+ bits_dir = self.scratch_file('bits-%d' % self.BITS_INTERNAL_VER)
+ iso_file = self.scratch_file('bits-%d.iso' % self.BITS_INTERNAL_VER)
+ mkrescue_script = self.scratch_file('grub-inst-x86_64-efi',
+ 'bin',
+ 'grub-mkrescue')
self.assertTrue(os.access(mkrescue_script,
os.R_OK | os.W_OK | os.X_OK))
@@ -284,46 +241,28 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
self.logger.info('iso file %s successfully generated.', iso_file)
def setUp(self): # pylint: disable=arguments-differ
- super().setUp('qemu-system-')
+ super().setUp()
self.logger = self.log
- self._baseDir = Path(__file__).parent
-
- # workdir could also be avocado's own workdir in self.workdir.
- # At present, I prefer to maintain my own temporary working
- # directory. It gives us more control over the generated bits
- # log files and also for debugging, we may chose not to remove
- # this working directory so that the logs and iso can be
- # inspected manually and archived if needed.
- self._workDir = tempfile.mkdtemp(prefix='acpi-bits-',
- suffix='.tmp')
- self.logger.info('working dir: %s', self._workDir)
-
- prebuiltDir = os.path.join(self._workDir, 'prebuilt')
+ prebuiltDir = self.scratch_file('prebuilt')
if not os.path.isdir(prebuiltDir):
os.mkdir(prebuiltDir, mode=0o775)
- bits_zip_file = os.path.join(prebuiltDir, 'bits-%d-%s.zip'
- %(self.BITS_INTERNAL_VER,
- self.BITS_COMMIT_HASH))
- grub_tar_file = os.path.join(prebuiltDir,
- 'bits-%d-%s-grub.tar.gz'
- %(self.BITS_INTERNAL_VER,
- self.BITS_COMMIT_HASH))
-
- bitsLocalArtLoc = self.ASSET_BITS.fetch()
- self.logger.info("downloaded bits artifacts to %s", bitsLocalArtLoc)
+ bits_zip_file = self.scratch_file('prebuilt',
+ 'bits-%d-%s.zip'
+ %(self.BITS_INTERNAL_VER,
+ self.BITS_COMMIT_HASH))
+ grub_tar_file = self.scratch_file('prebuilt',
+ 'bits-%d-%s-grub.tar.gz'
+ %(self.BITS_INTERNAL_VER,
+ self.BITS_COMMIT_HASH))
# extract the bits artifact in the temp working directory
- with zipfile.ZipFile(bitsLocalArtLoc, 'r') as zref:
- zref.extractall(prebuiltDir)
+ self.archive_extract(self.ASSET_BITS, sub_dir='prebuilt', format='zip')
# extract the bits software in the temp working directory
- with zipfile.ZipFile(bits_zip_file, 'r') as zref:
- zref.extractall(self._workDir)
-
- with tarfile.open(grub_tar_file, 'r', encoding='utf-8') as tarball:
- tarball.extractall(self._workDir)
+ self.archive_extract(bits_zip_file)
+ self.archive_extract(grub_tar_file)
self.copy_test_scripts()
self.copy_bits_config()
@@ -333,7 +272,7 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
"""parse the log generated by running bits tests and
check for failures.
"""
- debugconf = os.path.join(self._workDir, self._debugcon_log)
+ debugconf = self.scratch_file(self._debugcon_log)
log = ""
with open(debugconf, 'r', encoding='utf-8') as filehandle:
log = filehandle.read()
@@ -359,25 +298,18 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
"""
if self._vm:
self.assertFalse(not self._vm.is_running)
- if not os.getenv('BITS_DEBUG') and self._workDir:
- self.logger.info('removing the work directory %s', self._workDir)
- shutil.rmtree(self._workDir)
- else:
- self.logger.info('not removing the work directory %s ' \
- 'as BITS_DEBUG is ' \
- 'passed in the environment', self._workDir)
super().tearDown()
def test_acpi_smbios_bits(self):
"""The main test case implementation."""
- iso_file = os.path.join(self._workDir,
- 'bits-%d.iso' %self.BITS_INTERNAL_VER)
+ self.set_machine('pc')
+ iso_file = self.scratch_file('bits-%d.iso' % self.BITS_INTERNAL_VER)
self.assertTrue(os.access(iso_file, os.R_OK))
self._vm = QEMUBitsMachine(binary=self.qemu_bin,
- base_temp_dir=self._workDir,
+ base_temp_dir=self.workdir,
debugcon_log=self._debugcon_log,
debugcon_addr=self._debugcon_addr)
@@ -399,12 +331,10 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
# biosbits has been configured to run all the specified test suites
# in batch mode and then automatically initiate a vm shutdown.
- # Set timeout to BITS_TIMEOUT for SHUTDOWN event from bits VM at par
- # with the avocado test timeout.
self._vm.event_wait('SHUTDOWN', timeout=BITS_TIMEOUT)
self._vm.wait(timeout=None)
self.logger.debug("Checking console output ...")
self.parse_log()
if __name__ == '__main__':
- QemuBaseTest.main()
+ QemuSystemTest.main()
diff --git a/tests/functional/test_alpha_clipper.py b/tests/functional/test_alpha_clipper.py
new file mode 100755
index 0000000..c5d7181
--- /dev/null
+++ b/tests/functional/test_alpha_clipper.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on an Alpha Clipper machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class AlphaClipperTest(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ ('http://archive.debian.org/debian/dists/lenny/main/'
+ 'installer-alpha/20090123lenny10/images/cdrom/vmlinuz'),
+ '34f53da3fa32212e4f00b03cb944b2ad81c06bc8faaf9b7193b2e544ceeca576')
+
+ def test_alpha_clipper(self):
+ self.set_machine('clipper')
+ kernel_path = self.ASSET_KERNEL.fetch()
+
+ uncompressed_kernel = self.uncompress(self.ASSET_KERNEL, format="gz")
+
+ self.vm.set_console()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
+ self.vm.add_args('-nodefaults',
+ '-kernel', uncompressed_kernel,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_alpha_replay.py b/tests/functional/test_alpha_replay.py
new file mode 100755
index 0000000..24a17ef
--- /dev/null
+++ b/tests/functional/test_alpha_replay.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+#
+# Replay test that boots a Linux kernel on an Alpha machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from replay_kernel import ReplayKernelBase
+
+
+class AlphaReplay(ReplayKernelBase):
+
+ ASSET_KERNEL = Asset(
+ ('http://archive.debian.org/debian/dists/lenny/main/installer-alpha/'
+ '20090123lenny10/images/cdrom/vmlinuz'),
+ '34f53da3fa32212e4f00b03cb944b2ad81c06bc8faaf9b7193b2e544ceeca576')
+
+ def test_clipper(self):
+ self.set_machine('clipper')
+ kernel_path = self.uncompress(self.ASSET_KERNEL, format='gz')
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=9,
+ args=('-nodefaults', ))
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_arm_aspeed_ast1030.py b/tests/functional/test_arm_aspeed_ast1030.py
new file mode 100755
index 0000000..77037f0
--- /dev/null
+++ b/tests/functional/test_arm_aspeed_ast1030.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots the ASPEED SoCs with firmware
+#
+# Copyright (C) 2022 ASPEED Technology Inc
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+
+
+class AST1030Machine(LinuxKernelTest):
+
+ ASSET_ZEPHYR_3_00 = Asset(
+ ('https://github.com/AspeedTech-BMC'
+ '/zephyr/releases/download/v00.03.00/ast1030-evb-demo.zip'),
+ '37fe3ecd4a1b9d620971a15b96492a81093435396eeac69b6f3e384262ff555f')
+
+ def test_ast1030_zephyros_3_00(self):
+ self.set_machine('ast1030-evb')
+
+ kernel_name = "ast1030-evb-demo/zephyr.elf"
+ kernel_file = self.archive_extract(
+ self.ASSET_ZEPHYR_3_00, member=kernel_name)
+
+ self.vm.set_console()
+ self.vm.add_args('-kernel', kernel_file, '-nographic')
+ self.vm.launch()
+ self.wait_for_console_pattern("Booting Zephyr OS")
+ exec_command_and_wait_for_pattern(self, "help",
+ "Available commands")
+
+ ASSET_ZEPHYR_1_07 = Asset(
+ ('https://github.com/AspeedTech-BMC'
+ '/zephyr/releases/download/v00.01.07/ast1030-evb-demo.zip'),
+ 'ad52e27959746988afaed8429bf4e12ab988c05c4d07c9d90e13ec6f7be4574c')
+
+ def test_ast1030_zephyros_1_07(self):
+ self.set_machine('ast1030-evb')
+
+ kernel_name = "ast1030-evb-demo/zephyr.bin"
+ kernel_file = self.archive_extract(
+ self.ASSET_ZEPHYR_1_07, member=kernel_name)
+
+ self.vm.set_console()
+ self.vm.add_args('-kernel', kernel_file, '-nographic')
+ self.vm.launch()
+ self.wait_for_console_pattern("Booting Zephyr OS")
+ for shell_cmd in [
+ 'kernel stacks',
+ 'otp info conf',
+ 'otp info scu',
+ 'hwinfo devid',
+ 'crypto aes256_cbc_vault',
+ 'random get',
+ 'jtag JTAG1 sw_xfer high TMS',
+ 'adc ADC0 resolution 12',
+ 'adc ADC0 read 42',
+ 'adc ADC1 read 69',
+ 'i2c scan I2C_0',
+ 'i3c attach I3C_0',
+ 'hash test',
+ 'kernel uptime',
+ 'kernel reboot warm',
+ 'kernel uptime',
+ 'kernel reboot cold',
+ 'kernel uptime',
+ ]: exec_command_and_wait_for_pattern(self, shell_cmd, "uart:~$")
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_aspeed_ast2500.py b/tests/functional/test_arm_aspeed_ast2500.py
new file mode 100755
index 0000000..6923fe8
--- /dev/null
+++ b/tests/functional/test_arm_aspeed_ast2500.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots the ASPEED machines
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset, exec_command_and_wait_for_pattern
+from aspeed import AspeedTest
+
+
+class AST2500Machine(AspeedTest):
+
+ ASSET_BR2_202411_AST2500_FLASH = Asset(
+ ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
+ 'images/ast2500-evb/buildroot-2024.11/flash.img'),
+ '641e6906c18c0f19a2aeb48099d66d4771929c361001d554d0d45c667413e13a')
+
+ def test_arm_ast2500_evb_buildroot(self):
+ self.set_machine('ast2500-evb')
+
+ image_path = self.ASSET_BR2_202411_AST2500_FLASH.fetch()
+
+ self.vm.add_args('-device',
+ 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test')
+ self.do_test_arm_aspeed_buildroot_start(image_path, '0x0',
+ 'ast2500-evb login:')
+
+ exec_command_and_wait_for_pattern(self,
+ 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device',
+ 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d')
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/class/hwmon/hwmon1/temp1_input', '0')
+ self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
+ property='temperature', value=18000)
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/class/hwmon/hwmon1/temp1_input', '18000')
+
+ self.do_test_arm_aspeed_buildroot_poweroff()
+
+ ASSET_SDK_V906_AST2500 = Asset(
+ 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.06/ast2500-default-obmc.tar.gz',
+ '542db84645b4efd8aed50385d7f4dd1caff379a987032311cfa7b563a3addb2a')
+
+ def test_arm_ast2500_evb_sdk(self):
+ self.set_machine('ast2500-evb')
+
+ self.archive_extract(self.ASSET_SDK_V906_AST2500)
+
+ self.do_test_arm_aspeed_sdk_start(
+ self.scratch_file("ast2500-default", "image-bmc"))
+
+ self.wait_for_console_pattern('ast2500-default login:')
+
+
+if __name__ == '__main__':
+ AspeedTest.main()
diff --git a/tests/functional/test_arm_aspeed_ast2600.py b/tests/functional/test_arm_aspeed_ast2600.py
new file mode 100755
index 0000000..fdae4c9
--- /dev/null
+++ b/tests/functional/test_arm_aspeed_ast2600.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots the ASPEED machines
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import time
+import tempfile
+import subprocess
+
+from qemu_test import Asset
+from aspeed import AspeedTest
+from qemu_test import exec_command_and_wait_for_pattern, skipIfMissingCommands
+
+
+class AST2600Machine(AspeedTest):
+
+ ASSET_BR2_202411_AST2600_FLASH = Asset(
+ ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
+ 'images/ast2600-evb/buildroot-2024.11/flash.img'),
+ '4bb2f3dfdea31199b51d66b42f686dc5374c144a7346fdc650194a5578b73609')
+
+ def test_arm_ast2600_evb_buildroot(self):
+ self.set_machine('ast2600-evb')
+
+ image_path = self.ASSET_BR2_202411_AST2600_FLASH.fetch()
+
+ self.vm.add_args('-device',
+ 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test')
+ self.vm.add_args('-device',
+ 'ds1338,bus=aspeed.i2c.bus.3,address=0x32')
+ self.vm.add_args('-device',
+ 'i2c-echo,bus=aspeed.i2c.bus.3,address=0x42')
+ self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00',
+ 'ast2600-evb login:')
+
+ exec_command_and_wait_for_pattern(self,
+ 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device',
+ 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d')
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/class/hwmon/hwmon1/temp1_input', '0')
+ self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
+ property='temperature', value=18000)
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/class/hwmon/hwmon1/temp1_input', '18000')
+
+ exec_command_and_wait_for_pattern(self,
+ 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-3/device/new_device',
+ 'i2c i2c-3: new_device: Instantiated device ds1307 at 0x32')
+ year = time.strftime("%Y")
+ exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year)
+
+ exec_command_and_wait_for_pattern(self,
+ 'echo slave-24c02 0x1064 > /sys/bus/i2c/devices/i2c-3/new_device',
+ 'i2c i2c-3: new_device: Instantiated device slave-24c02 at 0x64')
+ exec_command_and_wait_for_pattern(self,
+ 'i2cset -y 3 0x42 0x64 0x00 0xaa i', '#')
+ exec_command_and_wait_for_pattern(self,
+ 'hexdump /sys/bus/i2c/devices/3-1064/slave-eeprom',
+ '0000000 ffaa ffff ffff ffff ffff ffff ffff ffff')
+ self.do_test_arm_aspeed_buildroot_poweroff()
+
+ ASSET_BR2_202302_AST2600_TPM_FLASH = Asset(
+ ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
+ 'images/ast2600-evb/buildroot-2023.02-tpm/flash.img'),
+ 'a46009ae8a5403a0826d607215e731a8c68d27c14c41e55331706b8f9c7bd997')
+
+ @skipIfMissingCommands('swtpm')
+ def test_arm_ast2600_evb_buildroot_tpm(self):
+ self.set_machine('ast2600-evb')
+
+ image_path = self.ASSET_BR2_202302_AST2600_TPM_FLASH.fetch()
+
+ tpmstate_dir = tempfile.TemporaryDirectory(prefix="qemu_")
+ socket = os.path.join(tpmstate_dir.name, 'swtpm-socket')
+
+ # We must put the TPM state dir in /tmp/, not the build dir,
+ # because some distros use AppArmor to lock down swtpm and
+ # restrict the set of locations it can access files in.
+ subprocess.run(['swtpm', 'socket', '-d', '--tpm2',
+ '--tpmstate', f'dir={tpmstate_dir.name}',
+ '--ctrl', f'type=unixio,path={socket}'])
+
+ self.vm.add_args('-chardev', f'socket,id=chrtpm,path={socket}')
+ self.vm.add_args('-tpmdev', 'emulator,id=tpm0,chardev=chrtpm')
+ self.vm.add_args('-device',
+ 'tpm-tis-i2c,tpmdev=tpm0,bus=aspeed.i2c.bus.12,address=0x2e')
+ self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', 'Aspeed AST2600 EVB')
+
+ exec_command_and_wait_for_pattern(self,
+ 'echo tpm_tis_i2c 0x2e > /sys/bus/i2c/devices/i2c-12/new_device',
+ 'tpm_tis_i2c 12-002e: 2.0 TPM (device-id 0x1, rev-id 1)')
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/class/tpm/tpm0/pcr-sha256/0',
+ 'B804724EA13F52A9072BA87FE8FDCC497DFC9DF9AA15B9088694639C431688E0')
+
+ self.do_test_arm_aspeed_buildroot_poweroff()
+
+ ASSET_SDK_V906_AST2600 = Asset(
+ 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.06/ast2600-default-obmc.tar.gz',
+ '768d76e247896ad78c154b9cff4f766da2ce65f217d620b286a4a03a8a4f68f5')
+
+ def test_arm_ast2600_evb_sdk(self):
+ self.set_machine('ast2600-evb')
+
+ self.archive_extract(self.ASSET_SDK_V906_AST2600)
+
+ self.vm.add_args('-device',
+ 'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test')
+ self.vm.add_args('-device',
+ 'ds1338,bus=aspeed.i2c.bus.5,address=0x32')
+ self.do_test_arm_aspeed_sdk_start(
+ self.scratch_file("ast2600-default", "image-bmc"))
+
+ self.wait_for_console_pattern('ast2600-default login:')
+
+ exec_command_and_wait_for_pattern(self, 'root', 'Password:')
+ exec_command_and_wait_for_pattern(self, '0penBmc',
+ 'root@ast2600-default:~#')
+
+ exec_command_and_wait_for_pattern(self,
+ 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-5/device/new_device',
+ 'i2c i2c-5: new_device: Instantiated device lm75 at 0x4d')
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/class/hwmon/hwmon19/temp1_input', '0')
+ self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
+ property='temperature', value=18000)
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/class/hwmon/hwmon19/temp1_input', '18000')
+
+ exec_command_and_wait_for_pattern(self,
+ 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-5/device/new_device',
+ 'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32')
+ year = time.strftime("%Y")
+ exec_command_and_wait_for_pattern(self,
+ '/sbin/hwclock -f /dev/rtc1', year)
+
+if __name__ == '__main__':
+ AspeedTest.main()
diff --git a/tests/functional/test_arm_aspeed_bletchley.py b/tests/functional/test_arm_aspeed_bletchley.py
new file mode 100644
index 0000000..5a60b24
--- /dev/null
+++ b/tests/functional/test_arm_aspeed_bletchley.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots the ASPEED machines
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from aspeed import AspeedTest
+
+
+class BletchleyMachine(AspeedTest):
+
+ ASSET_BLETCHLEY_FLASH = Asset(
+ 'https://github.com/legoater/qemu-aspeed-boot/raw/master/images/bletchley-bmc/openbmc-20250128071329/obmc-phosphor-image-bletchley-20250128071329.static.mtd.xz',
+ 'db21d04d47d7bb2a276f59d308614b4dfb70b9c7c81facbbca40a3977a2d8844')
+
+ def test_arm_ast2600_bletchley_openbmc(self):
+ image_path = self.uncompress(self.ASSET_BLETCHLEY_FLASH)
+
+ self.do_test_arm_aspeed_openbmc('bletchley-bmc', image=image_path,
+ uboot='2019.04', cpu_id='0xf00',
+ soc='AST2600 rev A3')
+
+if __name__ == '__main__':
+ AspeedTest.main()
diff --git a/tests/functional/test_arm_aspeed_palmetto.py b/tests/functional/test_arm_aspeed_palmetto.py
new file mode 100755
index 0000000..ff0b821
--- /dev/null
+++ b/tests/functional/test_arm_aspeed_palmetto.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots the ASPEED machines
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from aspeed import AspeedTest
+
+
+class PalmettoMachine(AspeedTest):
+
+ ASSET_PALMETTO_FLASH = Asset(
+ 'https://github.com/legoater/qemu-aspeed-boot/raw/master/images/palmetto-bmc/openbmc-20250128071432/obmc-phosphor-image-palmetto-20250128071432.static.mtd',
+ 'bce7c392eec75c707a91cfc8fad7ca9a69d7e4f10df936930d65c1cb9897ac81')
+
+ def test_arm_ast2400_palmetto_openbmc(self):
+ image_path = self.ASSET_PALMETTO_FLASH.fetch()
+
+ self.do_test_arm_aspeed_openbmc('palmetto-bmc', image=image_path,
+ uboot='2019.04', cpu_id='0x0',
+ soc='AST2400 rev A1')
+
+if __name__ == '__main__':
+ AspeedTest.main()
diff --git a/tests/functional/test_arm_aspeed_rainier.py b/tests/functional/test_arm_aspeed_rainier.py
new file mode 100755
index 0000000..602d619
--- /dev/null
+++ b/tests/functional/test_arm_aspeed_rainier.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots the ASPEED machines
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from aspeed import AspeedTest
+
+class RainierMachine(AspeedTest):
+
+ ASSET_RAINIER_EMMC = Asset(
+ ('https://fileserver.linaro.org/s/B6pJTwWEkzSDi36/download/'
+ 'mmc-p10bmc-20240617.qcow2'),
+ 'd523fb478d2b84d5adc5658d08502bc64b1486955683814f89c6137518acd90b')
+
+ def test_arm_aspeed_emmc_boot(self):
+ self.set_machine('rainier-bmc')
+ self.require_netdev('user')
+
+ image_path = self.ASSET_RAINIER_EMMC.fetch()
+
+ self.vm.set_console()
+ self.vm.add_args('-drive',
+ 'file=' + image_path + ',if=sd,id=sd2,index=2',
+ '-net', 'nic', '-net', 'user', '-snapshot')
+ self.vm.launch()
+
+ self.wait_for_console_pattern('U-Boot SPL 2019.04')
+ self.wait_for_console_pattern('Trying to boot from MMC1')
+ self.wait_for_console_pattern('U-Boot 2019.04')
+ self.wait_for_console_pattern('eMMC 2nd Boot')
+ self.wait_for_console_pattern('## Loading kernel from FIT Image')
+ self.wait_for_console_pattern('Starting kernel ...')
+ self.wait_for_console_pattern('Booting Linux on physical CPU 0xf00')
+ self.wait_for_console_pattern('mmcblk0: p1 p2 p3 p4 p5 p6 p7')
+ self.wait_for_console_pattern('IBM eBMC (OpenBMC for IBM Enterprise')
+
+ ASSET_DEBIAN_LINUX_ARMHF_DEB = Asset(
+ ('http://snapshot.debian.org/archive/debian/20220606T211338Z/pool/main/l/linux/linux-image-5.17.0-2-armmp_5.17.6-1%2Bb1_armhf.deb'),
+ '8acb2b4439faedc2f3ed4bdb2847ad4f6e0491f73debaeb7f660c8abe4dcdc0e')
+
+ def test_arm_debian_kernel_boot(self):
+ self.set_machine('rainier-bmc')
+
+ kernel_path = self.archive_extract(
+ self.ASSET_DEBIAN_LINUX_ARMHF_DEB,
+ member='boot/vmlinuz-5.17.0-2-armmp')
+ dtb_path = self.archive_extract(
+ self.ASSET_DEBIAN_LINUX_ARMHF_DEB,
+ member='usr/lib/linux-image-5.17.0-2-armmp/aspeed-bmc-ibm-rainier.dtb')
+
+ self.vm.set_console()
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-net', 'nic')
+ self.vm.launch()
+
+ self.wait_for_console_pattern("Booting Linux on physical CPU 0xf00")
+ self.wait_for_console_pattern("SMP: Total of 2 processors activated")
+ self.wait_for_console_pattern("No filesystem could mount root")
+
+
+if __name__ == '__main__':
+ AspeedTest.main()
diff --git a/tests/functional/test_arm_aspeed_romulus.py b/tests/functional/test_arm_aspeed_romulus.py
new file mode 100755
index 0000000..0447212
--- /dev/null
+++ b/tests/functional/test_arm_aspeed_romulus.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots the ASPEED machines
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from aspeed import AspeedTest
+
+
+class RomulusMachine(AspeedTest):
+
+ ASSET_ROMULUS_FLASH = Asset(
+ 'https://github.com/legoater/qemu-aspeed-boot/raw/master/images/romulus-bmc/openbmc-20250128071340/obmc-phosphor-image-romulus-20250128071340.static.mtd',
+ '6d031376440c82ed9d087d25e9fa76aea75b42f80daa252ec402c0bc3cf6cf5b')
+
+ def test_arm_ast2500_romulus_openbmc(self):
+ image_path = self.ASSET_ROMULUS_FLASH.fetch()
+
+ self.do_test_arm_aspeed_openbmc('romulus-bmc', image=image_path,
+ uboot='2019.04', cpu_id='0x0',
+ soc='AST2500 rev A1')
+
+if __name__ == '__main__':
+ AspeedTest.main()
diff --git a/tests/functional/test_arm_aspeed_witherspoon.py b/tests/functional/test_arm_aspeed_witherspoon.py
new file mode 100644
index 0000000..51a2d47
--- /dev/null
+++ b/tests/functional/test_arm_aspeed_witherspoon.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots the ASPEED machines
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from aspeed import AspeedTest
+
+
+class WitherspoonMachine(AspeedTest):
+
+ ASSET_WITHERSPOON_FLASH = Asset(
+ 'https://github.com/legoater/qemu-aspeed-boot/raw/master/images/witherspoon-bmc/openbmc-20240618035022/obmc-phosphor-image-witherspoon-20240618035022.ubi.mtd',
+ '937d9ed449ea6c6cbed983519088a42d0cafe276bcfe4fce07772ca6673f9213')
+
+ def test_arm_ast2500_witherspoon_openbmc(self):
+ image_path = self.ASSET_WITHERSPOON_FLASH.fetch()
+
+ self.do_test_arm_aspeed_openbmc('witherspoon-bmc', image=image_path,
+ uboot='2016.07', cpu_id='0x0',
+ soc='AST2500 rev A1')
+
+if __name__ == '__main__':
+ AspeedTest.main()
diff --git a/tests/functional/test_arm_bflt.py b/tests/functional/test_arm_bflt.py
index 281925d..f273fc8 100755
--- a/tests/functional/test_arm_bflt.py
+++ b/tests/functional/test_arm_bflt.py
@@ -6,13 +6,10 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
import bz2
from qemu_test import QemuUserTest, Asset
-from qemu_test import has_cmd
-from qemu_test.utils import cpio_extract
-from unittest import skipUnless
+from qemu_test import skipIfMissingCommands, skipUntrustedTest
class LoadBFLT(QemuUserTest):
@@ -21,15 +18,15 @@ class LoadBFLT(QemuUserTest):
('https://elinux.org/images/5/51/Stm32_mini_rootfs.cpio.bz2'),
'eefb788e4980c9e8d6c9d60ce7d15d4da6bf4fbc6a80f487673824600d5ba9cc')
- @skipUnless(*has_cmd('cpio'))
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipIfMissingCommands('cpio')
+ @skipUntrustedTest()
def test_stm32(self):
# See https://elinux.org/STM32#User_Space
rootfs_path_bz2 = self.ASSET_ROOTFS.fetch()
- busybox_path = os.path.join(self.workdir, "bin/busybox")
+ busybox_path = self.scratch_file("bin", "busybox")
with bz2.open(rootfs_path_bz2, 'rb') as cpio_handle:
- cpio_extract(cpio_handle, self.workdir)
+ self.archive_extract(cpio_handle, format="cpio")
res = self.run_cmd(busybox_path)
ver = 'BusyBox v1.24.0.git (2015-02-03 22:17:13 CET) multi-call binary.'
diff --git a/tests/functional/test_arm_bpim2u.py b/tests/functional/test_arm_bpim2u.py
new file mode 100755
index 0000000..8bed64b
--- /dev/null
+++ b/tests/functional/test_arm_bpim2u.py
@@ -0,0 +1,180 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on a Banana Pi machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import LinuxKernelTest, exec_command_and_wait_for_pattern
+from qemu_test import Asset, interrupt_interactive_console_until_pattern
+from qemu_test import skipBigDataTest
+from qemu_test.utils import image_pow2ceil_expand
+
+
+class BananaPiMachine(LinuxKernelTest):
+
+ ASSET_DEB = Asset(
+ ('https://apt.armbian.com/pool/main/l/linux-6.6.16/'
+ 'linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb'),
+ '3d968c15b121ede871dce49d13ee7644d6f74b6b121b84c9a40f51b0c80d6d22')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/groeck/linux-build-test/raw/'
+ '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
+ 'arm/rootfs-armv7a.cpio.gz'),
+ '2c8dbdb16ea7af2dfbcbea96044dde639fb07d09fd3c4fb31f2027ef71e55ddd')
+
+ ASSET_ROOTFS = Asset(
+ ('http://storage.kernelci.org/images/rootfs/buildroot/'
+ 'buildroot-baseline/20230703.0/armel/rootfs.ext2.xz'),
+ '42b44a12965ac0afe9a88378527fb698a7dc76af50495efc2361ee1595b4e5c6')
+
+ ASSET_SD_IMAGE = Asset(
+ ('https://downloads.openwrt.org/releases/22.03.3/targets/sunxi/cortexa7/'
+ 'openwrt-22.03.3-sunxi-cortexa7-sinovoip_bananapi-m2-ultra-ext4-sdcard.img.gz'),
+ '5b41b4e11423e562c6011640f9a7cd3bdd0a3d42b83430f7caa70a432e6cd82c')
+
+ def test_arm_bpim2u(self):
+ self.set_machine('bpim2u')
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/'
+ 'sun8i-r40-bananapi-m2-ultra.dtb')
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0,115200n8 '
+ 'earlycon=uart,mmio32,0x1c28000')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+ os.remove(kernel_path)
+ os.remove(dtb_path)
+
+ def test_arm_bpim2u_initrd(self):
+ self.set_machine('bpim2u')
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/'
+ 'sun8i-r40-bananapi-m2-ultra.dtb')
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+ initrd_path = self.uncompress(self.ASSET_INITRD)
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0,115200 '
+ 'panic=-1 noreboot')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line,
+ '-no-reboot')
+ self.vm.launch()
+ self.wait_for_console_pattern('Boot successful.')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'Allwinner sun8i Family')
+ exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
+ 'system-control@1c00000')
+ exec_command_and_wait_for_pattern(self, 'reboot',
+ 'reboot: Restarting system')
+ # Wait for VM to shut down gracefully
+ self.vm.wait()
+ os.remove(kernel_path)
+ os.remove(dtb_path)
+ os.remove(initrd_path)
+
+ def test_arm_bpim2u_gmac(self):
+ self.set_machine('bpim2u')
+ self.require_netdev('user')
+
+ deb_path = self.ASSET_DEB.fetch()
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/'
+ 'sun8i-r40-bananapi-m2-ultra.dtb')
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+ rootfs_path = self.uncompress(self.ASSET_ROOTFS)
+ image_pow2ceil_expand(rootfs_path)
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0,115200 '
+ 'root=b300 rootwait rw '
+ 'panic=-1 noreboot')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-drive', 'file=' + rootfs_path + ',if=sd,format=raw',
+ '-net', 'nic,model=gmac,netdev=host_gmac',
+ '-netdev', 'user,id=host_gmac',
+ '-append', kernel_command_line,
+ '-no-reboot')
+ self.vm.launch()
+ shell_ready = "/bin/sh: can't access tty; job control turned off"
+ self.wait_for_console_pattern(shell_ready)
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'Allwinner sun8i Family')
+ exec_command_and_wait_for_pattern(self, 'cat /proc/partitions',
+ 'mmcblk')
+ exec_command_and_wait_for_pattern(self, 'ifconfig eth0 up',
+ 'eth0: Link is Up')
+ exec_command_and_wait_for_pattern(self, 'udhcpc eth0',
+ 'udhcpc: lease of 10.0.2.15 obtained')
+ exec_command_and_wait_for_pattern(self, 'ping -c 3 10.0.2.2',
+ '3 packets transmitted, 3 packets received, 0% packet loss')
+ exec_command_and_wait_for_pattern(self, 'reboot',
+ 'reboot: Restarting system')
+ # Wait for VM to shut down gracefully
+ self.vm.wait()
+ os.remove(kernel_path)
+ os.remove(dtb_path)
+ os.remove(rootfs_path)
+
+ @skipBigDataTest()
+ def test_arm_bpim2u_openwrt_22_03_3(self):
+ self.set_machine('bpim2u')
+ self.require_netdev('user')
+
+ # This test download a 8.9 MiB compressed image and expand it
+ # to 127 MiB.
+ image_path = self.uncompress(self.ASSET_SD_IMAGE)
+ image_pow2ceil_expand(image_path)
+
+ self.vm.set_console()
+ self.vm.add_args('-drive', 'file=' + image_path + ',if=sd,format=raw',
+ '-nic', 'user',
+ '-no-reboot')
+ self.vm.launch()
+
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'usbcore.nousb '
+ 'noreboot')
+
+ self.wait_for_console_pattern('U-Boot SPL')
+
+ interrupt_interactive_console_until_pattern(
+ self, 'Hit any key to stop autoboot:', '=>')
+ exec_command_and_wait_for_pattern(self, "setenv extraargs '" +
+ kernel_command_line + "'", '=>')
+ exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...')
+
+ self.wait_for_console_pattern(
+ 'Please press Enter to activate this console.')
+
+ exec_command_and_wait_for_pattern(self, ' ', 'root@')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'Allwinner sun8i Family')
+ exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
+ 'system-control@1c00000')
+ os.remove(image_path)
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_canona1100.py b/tests/functional/test_arm_canona1100.py
index 65f1228..21a1a59 100755
--- a/tests/functional/test_arm_canona1100.py
+++ b/tests/functional/test_arm_canona1100.py
@@ -12,7 +12,7 @@
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
-from qemu_test.utils import archive_extract
+
class CanonA1100Machine(QemuSystemTest):
"""Boots the barebox firmware and checks that the console is operational"""
@@ -26,12 +26,10 @@ class CanonA1100Machine(QemuSystemTest):
def test_arm_canona1100(self):
self.set_machine('canon-a1100')
- file_path = self.ASSET_BIOS.fetch()
- archive_extract(file_path, dest_dir=self.workdir,
- member="day18/barebox.canon-a1100.bin")
+ bios = self.archive_extract(self.ASSET_BIOS,
+ member="day18/barebox.canon-a1100.bin")
self.vm.set_console()
- self.vm.add_args('-bios',
- self.workdir + '/day18/barebox.canon-a1100.bin')
+ self.vm.add_args('-bios', bios)
self.vm.launch()
wait_for_console_pattern(self, 'running /env/bin/init')
diff --git a/tests/functional/test_arm_collie.py b/tests/functional/test_arm_collie.py
new file mode 100755
index 0000000..fe1be3d
--- /dev/null
+++ b/tests/functional/test_arm_collie.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on a collie machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class CollieTest(LinuxKernelTest):
+
+ ASSET_ZIMAGE = Asset(
+ 'https://github.com/groeck/linux-test-downloads/raw/225223f2ad7d637b34426810bf6c3b727b76a718/collie/zImage',
+ '10ace8abf9e0875ef8a83b8829cc3b5b50bc6d7bc3ca29f19f49f5673a43c13b')
+
+ ASSET_ROOTFS = Asset(
+ 'https://github.com/groeck/linux-test-downloads/raw/225223f2ad7d637b34426810bf6c3b727b76a718/collie/rootfs-sa110.cpio',
+ '89ccaaa5c6b33331887047e1618ffe81b0f55909173944347d5d2426f3bcc1f2')
+
+ def test_arm_collie(self):
+ self.set_machine('collie')
+ zimage_path = self.ASSET_ZIMAGE.fetch()
+ rootfs_path = self.ASSET_ROOTFS.fetch()
+ self.vm.add_args('-append', 'rdinit=/sbin/init console=ttySA1')
+ self.launch_kernel(zimage_path,
+ initrd=rootfs_path,
+ wait_for='reboot: Restarting system')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_cubieboard.py b/tests/functional/test_arm_cubieboard.py
new file mode 100755
index 0000000..b536c2f
--- /dev/null
+++ b/tests/functional/test_arm_cubieboard.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern
+from qemu_test import interrupt_interactive_console_until_pattern
+from qemu_test import skipBigDataTest
+from qemu_test.utils import image_pow2ceil_expand
+
+
+class CubieboardMachine(LinuxKernelTest):
+
+ ASSET_DEB = Asset(
+ ('https://apt.armbian.com/pool/main/l/linux-6.6.16/'
+ 'linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb'),
+ '3d968c15b121ede871dce49d13ee7644d6f74b6b121b84c9a40f51b0c80d6d22')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/groeck/linux-build-test/raw/'
+ '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
+ 'arm/rootfs-armv5.cpio.gz'),
+ '334b8d256db67a3f2b3ad070aa08b5ade39624e0e7e35b02f4359a577bc8f39b')
+
+ ASSET_SATA_ROOTFS = Asset(
+ ('https://github.com/groeck/linux-build-test/raw/'
+ '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
+ 'arm/rootfs-armv5.ext2.gz'),
+ '17fc750da568580b39372133051ef2f0a963c0c0b369b845614442d025701745')
+
+ ASSET_OPENWRT = Asset(
+ ('https://downloads.openwrt.org/releases/22.03.2/targets/sunxi/cortexa8/'
+ 'openwrt-22.03.2-sunxi-cortexa8-cubietech_a10-cubieboard-ext4-sdcard.img.gz'),
+ '94b5ecbfbc0b3b56276e5146b899eafa2ac5dc2d08733d6705af9f144f39f554')
+
+ def test_arm_cubieboard_initrd(self):
+ self.set_machine('cubieboard')
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/' +
+ 'sun4i-a10-cubieboard.dtb')
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+ initrd_path = self.uncompress(self.ASSET_INITRD)
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0,115200 '
+ 'usbcore.nousb '
+ 'panic=-1 noreboot')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line,
+ '-no-reboot')
+ self.vm.launch()
+ self.wait_for_console_pattern('Boot successful.')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'Allwinner sun4i/sun5i')
+ exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
+ 'system-control@1c00000')
+ exec_command_and_wait_for_pattern(self, 'reboot',
+ 'reboot: Restarting system')
+ # Wait for VM to shut down gracefully
+ self.vm.wait()
+
+ def test_arm_cubieboard_sata(self):
+ self.set_machine('cubieboard')
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/' +
+ 'sun4i-a10-cubieboard.dtb')
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+
+ rootfs_path = self.uncompress(self.ASSET_SATA_ROOTFS)
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0,115200 '
+ 'usbcore.nousb '
+ 'root=/dev/sda ro '
+ 'panic=-1 noreboot')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-drive', 'if=none,format=raw,id=disk0,file='
+ + rootfs_path,
+ '-device', 'ide-hd,bus=ide.0,drive=disk0',
+ '-append', kernel_command_line,
+ '-no-reboot')
+ self.vm.launch()
+ self.wait_for_console_pattern('Boot successful.')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'Allwinner sun4i/sun5i')
+ exec_command_and_wait_for_pattern(self, 'cat /proc/partitions',
+ 'sda')
+ exec_command_and_wait_for_pattern(self, 'reboot',
+ 'reboot: Restarting system')
+ # Wait for VM to shut down gracefully
+ self.vm.wait()
+
+ @skipBigDataTest()
+ def test_arm_cubieboard_openwrt_22_03_2(self):
+ # This test download a 7.5 MiB compressed image and expand it
+ # to 126 MiB.
+ self.set_machine('cubieboard')
+ self.require_netdev('user')
+
+ image_path = self.uncompress(self.ASSET_OPENWRT)
+ image_pow2ceil_expand(image_path)
+
+ self.vm.set_console()
+ self.vm.add_args('-drive', 'file=' + image_path + ',if=sd,format=raw',
+ '-nic', 'user',
+ '-no-reboot')
+ self.vm.launch()
+
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'usbcore.nousb '
+ 'noreboot')
+
+ self.wait_for_console_pattern('U-Boot SPL')
+
+ interrupt_interactive_console_until_pattern(
+ self, 'Hit any key to stop autoboot:', '=>')
+ exec_command_and_wait_for_pattern(self, "setenv extraargs '" +
+ kernel_command_line + "'", '=>')
+ exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...')
+
+ self.wait_for_console_pattern(
+ 'Please press Enter to activate this console.')
+
+ exec_command_and_wait_for_pattern(self, ' ', 'root@')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'Allwinner sun4i/sun5i')
+ exec_command_and_wait_for_pattern(self, 'reboot',
+ 'reboot: Restarting system')
+ # Wait for VM to shut down gracefully
+ self.vm.wait()
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_emcraft_sf2.py b/tests/functional/test_arm_emcraft_sf2.py
new file mode 100755
index 0000000..f9f3f06
--- /dev/null
+++ b/tests/functional/test_arm_emcraft_sf2.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import shutil
+
+from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern
+from qemu_test.utils import file_truncate
+
+class EmcraftSf2Machine(LinuxKernelTest):
+
+ ASSET_UBOOT = Asset(
+ ('https://raw.githubusercontent.com/Subbaraya-Sundeep/qemu-test-binaries/'
+ 'fe371d32e50ca682391e1e70ab98c2942aeffb01/u-boot'),
+ '5c6a15103375db11b21f2236473679a9dbbed6d89652bfcdd501c263d68ab725')
+
+ ASSET_SPI = Asset(
+ ('https://raw.githubusercontent.com/Subbaraya-Sundeep/qemu-test-binaries/'
+ 'fe371d32e50ca682391e1e70ab98c2942aeffb01/spi.bin'),
+ 'cd9bdd2c4cb55a59c3adb6bcf74881667c4500dde0570a43aa3be2b17eecfdb6')
+
+ def test_arm_emcraft_sf2(self):
+ self.set_machine('emcraft-sf2')
+ self.require_netdev('user')
+
+ uboot_path = self.ASSET_UBOOT.fetch()
+ spi_path = self.ASSET_SPI.fetch()
+ spi_path_rw = self.scratch_file('spi.bin')
+ shutil.copy(spi_path, spi_path_rw)
+ os.chmod(spi_path_rw, 0o600)
+
+ file_truncate(spi_path_rw, 16 << 20) # Spansion S25FL128SDPBHICO is 16 MiB
+
+ self.vm.set_console()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE
+ self.vm.add_args('-kernel', uboot_path,
+ '-append', kernel_command_line,
+ '-drive', 'file=' + spi_path_rw + ',if=mtd,format=raw',
+ '-no-reboot')
+ self.vm.launch()
+ self.wait_for_console_pattern('Enter \'help\' for a list')
+
+ exec_command_and_wait_for_pattern(self, 'ifconfig eth0 10.0.2.15',
+ 'eth0: link becomes ready')
+ exec_command_and_wait_for_pattern(self, 'ping -c 3 10.0.2.2',
+ '3 packets transmitted, 3 packets received, 0% packet loss')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_integratorcp.py b/tests/functional/test_arm_integratorcp.py
index 0fe083f..4f00924 100755
--- a/tests/functional/test_arm_integratorcp.py
+++ b/tests/functional/test_arm_integratorcp.py
@@ -12,25 +12,11 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
import logging
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
-from unittest import skipUnless
-
-
-NUMPY_AVAILABLE = True
-try:
- import numpy as np
-except ImportError:
- NUMPY_AVAILABLE = False
-
-CV2_AVAILABLE = True
-try:
- import cv2
-except ImportError:
- CV2_AVAILABLE = False
+from qemu_test import skipIfMissingImports, skipUntrustedTest
class IntegratorMachine(QemuSystemTest):
@@ -63,7 +49,7 @@ class IntegratorMachine(QemuSystemTest):
'-append', 'printk.time=0 console=ttyAMA0')
self.vm.launch()
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipUntrustedTest()
def test_integratorcp_console(self):
"""
Boots the Linux kernel and checks that the console is operational
@@ -71,22 +57,26 @@ class IntegratorMachine(QemuSystemTest):
self.boot_integratorcp()
wait_for_console_pattern(self, 'Log in as root')
- @skipUnless(NUMPY_AVAILABLE, 'Python NumPy not installed')
- @skipUnless(CV2_AVAILABLE, 'Python OpenCV not installed')
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipIfMissingImports("numpy", "cv2")
+ @skipUntrustedTest()
def test_framebuffer_tux_logo(self):
"""
Boot Linux and verify the Tux logo is displayed on the framebuffer.
"""
- screendump_path = os.path.join(self.workdir, "screendump.pbm")
+ import numpy as np
+ import cv2
+
+ screendump_path = self.scratch_file("screendump.pbm")
tuxlogo_path = self.ASSET_TUXLOGO.fetch()
self.boot_integratorcp()
framebuffer_ready = 'Console: switching to colour frame buffer device'
wait_for_console_pattern(self, framebuffer_ready)
self.vm.cmd('human-monitor-command', command_line='stop')
- self.vm.cmd('human-monitor-command',
- command_line='screendump %s' % screendump_path)
+ res = self.vm.cmd('human-monitor-command',
+ command_line='screendump %s' % screendump_path)
+ if 'unknown command' in res:
+ self.skipTest('screendump not available')
logger = logging.getLogger('framebuffer')
cpu_count = 1
diff --git a/tests/functional/test_arm_microbit.py b/tests/functional/test_arm_microbit.py
new file mode 100755
index 0000000..68ea4e7
--- /dev/null
+++ b/tests/functional/test_arm_microbit.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright 2025, The QEMU Project Developers.
+#
+# A functional test that runs MicroPython on the arm microbit machine.
+
+from qemu_test import QemuSystemTest, Asset, exec_command_and_wait_for_pattern
+from qemu_test import wait_for_console_pattern
+
+
+class MicrobitMachine(QemuSystemTest):
+
+ ASSET_MICRO = Asset('https://ozlabs.org/~joel/microbit-micropython.hex',
+ '021641f93dfb11767d4978dbb3ca7f475d1b13c69e7f4aec3382f212636bffd6')
+
+ def test_arm_microbit(self):
+ self.set_machine('microbit')
+
+ micropython = self.ASSET_MICRO.fetch()
+ self.vm.set_console()
+ self.vm.add_args('-device', f'loader,file={micropython}')
+ self.vm.launch()
+ wait_for_console_pattern(self, 'Type "help()" for more information.')
+ exec_command_and_wait_for_pattern(self, 'import machine as mch', '>>>')
+ exec_command_and_wait_for_pattern(self, 'mch.reset()', 'MicroPython')
+ wait_for_console_pattern(self, '>>>')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_arm_orangepi.py b/tests/functional/test_arm_orangepi.py
new file mode 100755
index 0000000..f9bfa8c
--- /dev/null
+++ b/tests/functional/test_arm_orangepi.py
@@ -0,0 +1,237 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on an Orange Pi machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import shutil
+
+from qemu_test import LinuxKernelTest, exec_command_and_wait_for_pattern
+from qemu_test import Asset, interrupt_interactive_console_until_pattern
+from qemu_test import wait_for_console_pattern, skipBigDataTest
+from qemu_test.utils import image_pow2ceil_expand
+
+
+class OrangePiMachine(LinuxKernelTest):
+
+ ASSET_DEB = Asset(
+ ('https://apt.armbian.com/pool/main/l/linux-6.6.16/'
+ 'linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb'),
+ '3d968c15b121ede871dce49d13ee7644d6f74b6b121b84c9a40f51b0c80d6d22')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/groeck/linux-build-test/raw/'
+ '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
+ 'arm/rootfs-armv7a.cpio.gz'),
+ '2c8dbdb16ea7af2dfbcbea96044dde639fb07d09fd3c4fb31f2027ef71e55ddd')
+
+ ASSET_ROOTFS = Asset(
+ ('http://storage.kernelci.org/images/rootfs/buildroot/'
+ 'buildroot-baseline/20230703.0/armel/rootfs.ext2.xz'),
+ '42b44a12965ac0afe9a88378527fb698a7dc76af50495efc2361ee1595b4e5c6')
+
+ ASSET_ARMBIAN = Asset(
+ ('https://k-space.ee.armbian.com/archive/orangepipc/archive/'
+ 'Armbian_23.8.1_Orangepipc_jammy_current_6.1.47.img.xz'),
+ 'b386dff6552513b5f164ea00f94814a6b0f1da9fb90b83725e949cf797e11afb')
+
+ ASSET_UBOOT = Asset(
+ ('http://snapshot.debian.org/archive/debian/20200108T145233Z/pool/'
+ 'main/u/u-boot/u-boot-sunxi_2020.01%2Bdfsg-1_armhf.deb'),
+ '9223d94dc283ab54df41ce9d6f69025a5b47fece29fb67a714e23aa0cdf3bdfa')
+
+ ASSET_NETBSD = Asset(
+ ('https://archive.netbsd.org/pub/NetBSD-archive/NetBSD-9.0/'
+ 'evbarm-earmv7hf/binary/gzimg/armv7.img.gz'),
+ '20d3e07dc057e15c12452620e90ecab2047f0f7940d9cba8182ebc795927177f')
+
+ def test_arm_orangepi(self):
+ self.set_machine('orangepi-pc')
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/' +
+ 'sun8i-h3-orangepi-pc.dtb')
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0,115200n8 '
+ 'earlycon=uart,mmio32,0x1c28000')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+ os.remove(kernel_path)
+ os.remove(dtb_path)
+
+ def test_arm_orangepi_initrd(self):
+ self.set_machine('orangepi-pc')
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/' +
+ 'sun8i-h3-orangepi-pc.dtb')
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+ initrd_path = self.uncompress(self.ASSET_INITRD)
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0,115200 '
+ 'panic=-1 noreboot')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line,
+ '-no-reboot')
+ self.vm.launch()
+ self.wait_for_console_pattern('Boot successful.')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'Allwinner sun8i Family')
+ exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
+ 'system-control@1c00000')
+ exec_command_and_wait_for_pattern(self, 'reboot',
+ 'reboot: Restarting system')
+ # Wait for VM to shut down gracefully
+ self.vm.wait()
+ os.remove(kernel_path)
+ os.remove(dtb_path)
+ os.remove(initrd_path)
+
+ def test_arm_orangepi_sd(self):
+ self.set_machine('orangepi-pc')
+ self.require_netdev('user')
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/' +
+ 'sun8i-h3-orangepi-pc.dtb')
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+ rootfs_path = self.uncompress(self.ASSET_ROOTFS)
+ image_pow2ceil_expand(rootfs_path)
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0,115200 '
+ 'root=/dev/mmcblk0 rootwait rw '
+ 'panic=-1 noreboot')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-drive', 'file=' + rootfs_path + ',if=sd,format=raw',
+ '-append', kernel_command_line,
+ '-no-reboot')
+ self.vm.launch()
+ shell_ready = "/bin/sh: can't access tty; job control turned off"
+ self.wait_for_console_pattern(shell_ready)
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'Allwinner sun8i Family')
+ exec_command_and_wait_for_pattern(self, 'cat /proc/partitions',
+ 'mmcblk0')
+ exec_command_and_wait_for_pattern(self, 'ifconfig eth0 up',
+ 'eth0: Link is Up')
+ exec_command_and_wait_for_pattern(self, 'udhcpc eth0',
+ 'udhcpc: lease of 10.0.2.15 obtained')
+ exec_command_and_wait_for_pattern(self, 'ping -c 3 10.0.2.2',
+ '3 packets transmitted, 3 packets received, 0% packet loss')
+ exec_command_and_wait_for_pattern(self, 'reboot',
+ 'reboot: Restarting system')
+ # Wait for VM to shut down gracefully
+ self.vm.wait()
+ os.remove(kernel_path)
+ os.remove(dtb_path)
+ os.remove(rootfs_path)
+
+ @skipBigDataTest()
+ def test_arm_orangepi_armbian(self):
+ self.set_machine('orangepi-pc')
+ self.require_netdev('user')
+
+ # This test download a 275 MiB compressed image and expand it
+ # to 1036 MiB, but the underlying filesystem is 1552 MiB...
+ # As we expand it to 2 GiB we are safe.
+ image_path = self.uncompress(self.ASSET_ARMBIAN)
+ image_pow2ceil_expand(image_path)
+
+ self.vm.set_console()
+ self.vm.add_args('-drive', 'file=' + image_path + ',if=sd,format=raw',
+ '-nic', 'user',
+ '-no-reboot')
+ self.vm.launch()
+
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0,115200 '
+ 'loglevel=7 '
+ 'nosmp '
+ 'systemd.default_timeout_start_sec=9000 '
+ 'systemd.mask=armbian-zram-config.service '
+ 'systemd.mask=armbian-ramlog.service')
+
+ self.wait_for_console_pattern('U-Boot SPL')
+ self.wait_for_console_pattern('Autoboot in ')
+ exec_command_and_wait_for_pattern(self, ' ', '=>')
+ exec_command_and_wait_for_pattern(self, "setenv extraargs '" +
+ kernel_command_line + "'", '=>')
+ exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...')
+
+ self.wait_for_console_pattern('systemd[1]: Hostname set ' +
+ 'to <orangepipc>')
+ self.wait_for_console_pattern('Starting Load Kernel Modules...')
+
+ @skipBigDataTest()
+ def test_arm_orangepi_uboot_netbsd9(self):
+ self.set_machine('orangepi-pc')
+ self.require_netdev('user')
+
+ # This test download a 304MB compressed image and expand it to 2GB
+ # We use the common OrangePi PC 'plus' build of U-Boot for our secondary
+ # program loader (SPL). We will then set the path to the more specific
+ # OrangePi "PC" device tree blob with 'setenv fdtfile' in U-Boot prompt,
+ # before to boot NetBSD.
+ uboot_path = 'usr/lib/u-boot/orangepi_plus/u-boot-sunxi-with-spl.bin'
+ uboot_path = self.archive_extract(self.ASSET_UBOOT, member=uboot_path)
+ image_path = self.uncompress(self.ASSET_NETBSD)
+ image_pow2ceil_expand(image_path)
+ image_drive_args = 'if=sd,format=raw,snapshot=on,file=' + image_path
+
+ # dd if=u-boot-sunxi-with-spl.bin of=armv7.img bs=1K seek=8 conv=notrunc
+ with open(uboot_path, 'rb') as f_in:
+ with open(image_path, 'r+b') as f_out:
+ f_out.seek(8 * 1024)
+ shutil.copyfileobj(f_in, f_out)
+
+ self.vm.set_console()
+ self.vm.add_args('-nic', 'user',
+ '-drive', image_drive_args,
+ '-global', 'allwinner-rtc.base-year=2000',
+ '-no-reboot')
+ self.vm.launch()
+ wait_for_console_pattern(self, 'U-Boot 2020.01+dfsg-1')
+ interrupt_interactive_console_until_pattern(self,
+ 'Hit any key to stop autoboot:',
+ 'switch to partitions #0, OK')
+
+ exec_command_and_wait_for_pattern(self, '', '=>')
+ cmd = 'setenv bootargs root=ld0a'
+ exec_command_and_wait_for_pattern(self, cmd, '=>')
+ cmd = 'setenv kernel netbsd-GENERIC.ub'
+ exec_command_and_wait_for_pattern(self, cmd, '=>')
+ cmd = 'setenv fdtfile dtb/sun8i-h3-orangepi-pc.dtb'
+ exec_command_and_wait_for_pattern(self, cmd, '=>')
+ cmd = ("setenv bootcmd 'fatload mmc 0:1 ${kernel_addr_r} ${kernel}; "
+ "fatload mmc 0:1 ${fdt_addr_r} ${fdtfile}; "
+ "fdt addr ${fdt_addr_r}; "
+ "bootm ${kernel_addr_r} - ${fdt_addr_r}'")
+ exec_command_and_wait_for_pattern(self, cmd, '=>')
+
+ exec_command_and_wait_for_pattern(self, 'boot',
+ 'Booting kernel from Legacy Image')
+ wait_for_console_pattern(self, 'Starting kernel ...')
+ wait_for_console_pattern(self, 'NetBSD 9.0 (GENERIC)')
+ # Wait for user-space
+ wait_for_console_pattern(self, 'Starting root file system check')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_quanta_gsj.py b/tests/functional/test_arm_quanta_gsj.py
new file mode 100755
index 0000000..cb0545f
--- /dev/null
+++ b/tests/functional/test_arm_quanta_gsj.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern
+from qemu_test import interrupt_interactive_console_until_pattern, skipSlowTest
+
+
+class EmcraftSf2Machine(LinuxKernelTest):
+
+ ASSET_IMAGE = Asset(
+ ('https://github.com/hskinnemoen/openbmc/releases/download/'
+ '20200711-gsj-qemu-0/obmc-phosphor-image-gsj.static.mtd.gz'),
+ 'eccd4e375cde53034c84aece5c511932cacf838d9fd3f63da368a511757da72b')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/hskinnemoen/openbmc/releases/download/'
+ '20200711-gsj-qemu-0/obmc-phosphor-initramfs-gsj.cpio.xz'),
+ '37b05009fc54db1434beac12bd7ff99a2e751a2f032ee18d9042f991dd0cdeaa')
+
+ ASSET_KERNEL = Asset(
+ ('https://github.com/hskinnemoen/openbmc/releases/download/'
+ '20200711-gsj-qemu-0/uImage-gsj.bin'),
+ 'ce6d6b37bff46c74fc7b1e90da10a431cc37a62cdb35ec199fa73473d0790110')
+
+ ASSET_DTB = Asset(
+ ('https://github.com/hskinnemoen/openbmc/releases/download/'
+ '20200711-gsj-qemu-0/nuvoton-npcm730-gsj.dtb'),
+ '3249b2da787d4b9ad4e61f315b160abfceb87b5e1895a7ce898ce7f40c8d4045')
+
+ @skipSlowTest()
+ def test_arm_quanta_gsj(self):
+ self.set_machine('quanta-gsj')
+ image_path = self.uncompress(self.ASSET_IMAGE, format='gz')
+
+ self.vm.set_console()
+ drive_args = 'file=' + image_path + ',if=mtd,bus=0,unit=0'
+ self.vm.add_args('-drive', drive_args)
+ self.vm.launch()
+
+ # Disable drivers and services that stall for a long time during boot,
+ # to avoid running past the 90-second timeout. These may be removed
+ # as the corresponding device support is added.
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + (
+ 'console=${console} '
+ 'mem=${mem} '
+ 'initcall_blacklist=npcm_i2c_bus_driver_init '
+ 'systemd.mask=systemd-random-seed.service '
+ 'systemd.mask=dropbearkey.service '
+ )
+
+ self.wait_for_console_pattern('> BootBlock by Nuvoton')
+ self.wait_for_console_pattern('>Device: Poleg BMC NPCM730')
+ self.wait_for_console_pattern('>Skip DDR init.')
+ self.wait_for_console_pattern('U-Boot ')
+ interrupt_interactive_console_until_pattern(
+ self, 'Hit any key to stop autoboot:', 'U-Boot>')
+ exec_command_and_wait_for_pattern(
+ self, "setenv bootargs ${bootargs} " + kernel_command_line,
+ 'U-Boot>')
+ exec_command_and_wait_for_pattern(
+ self, 'run romboot', 'Booting Kernel from flash')
+ self.wait_for_console_pattern('Booting Linux on physical CPU 0x0')
+ self.wait_for_console_pattern('CPU1: thread -1, cpu 1, socket 0')
+ self.wait_for_console_pattern('OpenBMC Project Reference Distro')
+ self.wait_for_console_pattern('gsj login:')
+
+ def test_arm_quanta_gsj_initrd(self):
+ self.set_machine('quanta-gsj')
+ initrd_path = self.ASSET_INITRD.fetch()
+ kernel_path = self.ASSET_KERNEL.fetch()
+ dtb_path = self.ASSET_DTB.fetch()
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0,115200n8 '
+ 'earlycon=uart8250,mmio32,0xf0001000')
+ self.vm.add_args('-kernel', kernel_path,
+ '-initrd', initrd_path,
+ '-dtb', dtb_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+
+ self.wait_for_console_pattern('Booting Linux on physical CPU 0x0')
+ self.wait_for_console_pattern('CPU1: thread -1, cpu 1, socket 0')
+ self.wait_for_console_pattern(
+ 'Give root password for system maintenance')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_raspi2.py b/tests/functional/test_arm_raspi2.py
new file mode 100755
index 0000000..d3c7aaa
--- /dev/null
+++ b/tests/functional/test_arm_raspi2.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on a Raspberry Pi machine
+# and checks the console
+#
+# Copyright (c) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+
+
+class ArmRaspi2Machine(LinuxKernelTest):
+
+ ASSET_KERNEL_20190215 = Asset(
+ ('http://archive.raspberrypi.org/debian/'
+ 'pool/main/r/raspberrypi-firmware/'
+ 'raspberrypi-kernel_1.20190215-1_armhf.deb'),
+ '9f1759f7228113da24f5ee2aa6312946ec09a83e076aba9406c46ff776dfb291')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/groeck/linux-build-test/raw/'
+ '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
+ 'arm/rootfs-armv7a.cpio.gz'),
+ '2c8dbdb16ea7af2dfbcbea96044dde639fb07d09fd3c4fb31f2027ef71e55ddd')
+
+ def do_test_arm_raspi2(self, uart_id):
+ """
+ The kernel can be rebuilt using the kernel source referenced
+ and following the instructions on the on:
+ https://www.raspberrypi.org/documentation/linux/kernel/building.md
+ """
+ serial_kernel_cmdline = {
+ 0: 'earlycon=pl011,0x3f201000 console=ttyAMA0',
+ }
+ kernel_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/kernel7.img')
+ dtb_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/bcm2709-rpi-2-b.dtb')
+
+ self.set_machine('raspi2b')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ serial_kernel_cmdline[uart_id] +
+ ' root=/dev/mmcblk0p2 rootwait ' +
+ 'dwc_otg.fiq_fsm_enable=0')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-append', kernel_command_line,
+ '-device', 'usb-kbd')
+ self.vm.launch()
+
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+ self.wait_for_console_pattern('Product: QEMU USB Keyboard')
+
+ def test_arm_raspi2_uart0(self):
+ self.do_test_arm_raspi2(0)
+
+ def test_arm_raspi2_initrd(self):
+ kernel_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/kernel7.img')
+ dtb_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/bcm2709-rpi-2-b.dtb')
+ initrd_path = self.uncompress(self.ASSET_INITRD)
+
+ self.set_machine('raspi2b')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'earlycon=pl011,0x3f201000 console=ttyAMA0 '
+ 'panic=-1 noreboot ' +
+ 'dwc_otg.fiq_fsm_enable=0')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line,
+ '-no-reboot')
+ self.vm.launch()
+ self.wait_for_console_pattern('Boot successful.')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'BCM2835')
+ exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
+ '/soc/cprman@7e101000')
+ exec_command_and_wait_for_pattern(self, 'halt', 'reboot: System halted')
+ # Wait for VM to shut down gracefully
+ self.vm.wait()
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_realview.py b/tests/functional/test_arm_realview.py
new file mode 100755
index 0000000..82cc964
--- /dev/null
+++ b/tests/functional/test_arm_realview.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on a realview arm machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, exec_command_and_wait_for_pattern
+from qemu_test import Asset
+
+
+class RealviewMachine(LinuxKernelTest):
+
+ ASSET_REALVIEW_MPCORE = Asset(
+ ('https://archive.openwrt.org/chaos_calmer/15.05.1/realview/generic/'
+ 'openwrt-15.05.1-realview-vmlinux-initramfs.elf'),
+ 'd3a01037f33e7512d46d50975588d5c3a0e0cbf25f37afab44775c2a2be523e6')
+
+ def test_realview_ep_mpcore(self):
+ self.require_netdev('user')
+ self.set_machine('realview-eb-mpcore')
+ kernel_path = self.ASSET_REALVIEW_MPCORE.fetch()
+ self.vm.set_console()
+ kernel_param = 'console=ttyAMA0 mem=128M quiet'
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_param)
+ self.vm.launch()
+ self.wait_for_console_pattern('Please press Enter to activate')
+ prompt = ':/#'
+ exec_command_and_wait_for_pattern(self, '', prompt)
+ exec_command_and_wait_for_pattern(self, 'dmesg', kernel_param)
+ self.wait_for_console_pattern(prompt)
+ exec_command_and_wait_for_pattern(self,
+ ('while ! dmesg | grep "br-lan: port 1(eth0) entered" ;'
+ ' do sleep 1 ; done'),
+ 'entered forwarding state')
+ self.wait_for_console_pattern(prompt)
+ exec_command_and_wait_for_pattern(self,
+ 'while ! ifconfig | grep "10.0.2.15" ; do sleep 1 ; done',
+ 'addr:10.0.2.15')
+ self.wait_for_console_pattern(prompt)
+ exec_command_and_wait_for_pattern(self, 'ping -c 1 10.0.2.2',
+ '1 packets received, 0% packet loss')
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_replay.py b/tests/functional/test_arm_replay.py
new file mode 100755
index 0000000..e002e6a
--- /dev/null
+++ b/tests/functional/test_arm_replay.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python3
+#
+# Replay test that boots a Linux kernel on arm machines and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from replay_kernel import ReplayKernelBase
+
+
+class ArmReplay(ReplayKernelBase):
+
+ ASSET_VIRT = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/'
+ 'releases/29/Everything/armhfp/os/images/pxeboot/vmlinuz'),
+ '18dd5f1a9a28bd539f9d047f7c0677211bae528e8712b40ca5a229a4ad8e2591')
+
+ def test_virt(self):
+ self.set_machine('virt')
+ kernel_path = self.ASSET_VIRT.fetch()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyAMA0')
+ console_pattern = 'VFS: Cannot open root device'
+ self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=1)
+
+ ASSET_CUBIE_KERNEL = Asset(
+ ('https://apt.armbian.com/pool/main/l/linux-6.6.16/'
+ 'linux-image-current-sunxi_24.2.1_armhf_'
+ '_6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb'),
+ '3d968c15b121ede871dce49d13ee7644d6f74b6b121b84c9a40f51b0c80d6d22')
+
+ ASSET_CUBIE_INITRD = Asset(
+ ('https://github.com/groeck/linux-build-test/raw/'
+ '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/arm/rootfs-armv5.cpio.gz'),
+ '334b8d256db67a3f2b3ad070aa08b5ade39624e0e7e35b02f4359a577bc8f39b')
+
+ def test_cubieboard(self):
+ self.set_machine('cubieboard')
+ kernel_path = self.archive_extract(self.ASSET_CUBIE_KERNEL,
+ member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = self.archive_extract(self.ASSET_CUBIE_KERNEL,
+ member='usr/lib/linux-image-6.6.16-current-sunxi/sun4i-a10-cubieboard.dtb')
+ initrd_path = self.uncompress(self.ASSET_CUBIE_INITRD)
+
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0,115200 '
+ 'usbcore.nousb '
+ 'panic=-1 noreboot')
+ console_pattern = 'Boot successful.'
+ self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=1,
+ args=('-dtb', dtb_path,
+ '-initrd', initrd_path,
+ '-no-reboot'))
+
+ ASSET_DAY16 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day16.tar.xz',
+ '63311adb2d4c4e7a73214a86d29988add87266a909719c56acfadd026b4110a7')
+
+ def test_vexpressa9(self):
+ self.set_machine('vexpress-a9')
+ self.archive_extract(self.ASSET_DAY16)
+ kernel_path = self.scratch_file('day16', 'winter.zImage')
+ dtb_path = self.scratch_file('day16', 'vexpress-v2p-ca9.dtb')
+ self.run_rr(kernel_path, self.REPLAY_KERNEL_COMMAND_LINE,
+ 'QEMU advent calendar', args=('-dtb', dtb_path))
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_arm_smdkc210.py b/tests/functional/test_arm_smdkc210.py
new file mode 100755
index 0000000..3154e7f
--- /dev/null
+++ b/tests/functional/test_arm_smdkc210.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class Smdkc210Machine(LinuxKernelTest):
+
+ ASSET_DEB = Asset(
+ ('https://snapshot.debian.org/archive/debian/20190928T224601Z/pool/'
+ 'main/l/linux/linux-image-4.19.0-6-armmp_4.19.67-2+deb10u1_armhf.deb'),
+ '421804e7579ef40d554c962850dbdf1bfc79f7fa7faec9d391397170dc806c3e')
+
+ ASSET_ROOTFS = Asset(
+ ('https://github.com/groeck/linux-build-test/raw/'
+ '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/arm/'
+ 'rootfs-armv5.cpio.gz'),
+ '334b8d256db67a3f2b3ad070aa08b5ade39624e0e7e35b02f4359a577bc8f39b')
+
+ def test_arm_exynos4210_initrd(self):
+ self.set_machine('smdkc210')
+
+ kernel_path = self.archive_extract(self.ASSET_DEB,
+ member='boot/vmlinuz-4.19.0-6-armmp')
+ dtb_path = 'usr/lib/linux-image-4.19.0-6-armmp/exynos4210-smdkv310.dtb'
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+
+ initrd_path = self.uncompress(self.ASSET_ROOTFS)
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'earlycon=exynos4210,0x13800000 earlyprintk ' +
+ 'console=ttySAC0,115200n8 ' +
+ 'random.trust_cpu=off cryptomgr.notests ' +
+ 'cpuidle.off=1 panic=-1 noreboot')
+
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line,
+ '-no-reboot')
+ self.vm.launch()
+
+ self.wait_for_console_pattern('Boot successful.')
+ # TODO user command, for now the uart is stuck
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_stellaris.py b/tests/functional/test_arm_stellaris.py
new file mode 100755
index 0000000..cbd21cb
--- /dev/null
+++ b/tests/functional/test_arm_stellaris.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+#
+# Functional test that checks the serial console of the stellaris machines
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import QemuSystemTest, Asset, exec_command_and_wait_for_pattern
+from qemu_test import wait_for_console_pattern
+
+
+class StellarisMachine(QemuSystemTest):
+
+ ASSET_DAY22 = Asset(
+ 'https://www.qemu-advent-calendar.org/2023/download/day22.tar.gz',
+ 'ae3a63ef4b7a22c21bfc7fc0d85e402fe95e223308ed23ac854405016431ff51')
+
+ def test_lm3s6965evb(self):
+ self.set_machine('lm3s6965evb')
+ kernel_path = self.archive_extract(self.ASSET_DAY22,
+ member='day22/day22.bin')
+ self.vm.set_console()
+ self.vm.add_args('-kernel', kernel_path)
+ self.vm.launch()
+
+ wait_for_console_pattern(self, 'In a one horse open')
+
+ ASSET_NOTMAIN = Asset(
+ 'https://github.com/Ahelion/QemuArmM4FDemoSw/raw/master/build/notmain.bin',
+ '6ceda031aa081a420fca2fca9e137fa681d6e3820d820ad1917736cb265e611a')
+
+ def test_lm3s811evb(self):
+ self.set_machine('lm3s811evb')
+ kernel_path = self.ASSET_NOTMAIN.fetch()
+
+ self.vm.set_console()
+ self.vm.add_args('-cpu', 'cortex-m4')
+ self.vm.add_args('-kernel', kernel_path)
+ self.vm.launch()
+
+ # The test kernel emits an initial '!' and then waits for input.
+ # For each character that we send it responds with a certain
+ # other ASCII character.
+ wait_for_console_pattern(self, '!')
+ exec_command_and_wait_for_pattern(self, '789', 'cdf')
+
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_arm_sx1.py b/tests/functional/test_arm_sx1.py
new file mode 100755
index 0000000..25800b3
--- /dev/null
+++ b/tests/functional/test_arm_sx1.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2024 Linaro Ltd.
+#
+# Functional test that boots a Linux kernel on an sx1 machine
+# and checks the console. We have three variants:
+# * just boot initrd
+# * boot with filesystem on SD card
+# * boot from flash
+# In all cases these images have a userspace that is configured
+# to immediately reboot the system on successful boot, so we
+# only need to wait for QEMU to exit (via -no-reboot).
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class SX1Test(LinuxKernelTest):
+
+ ASSET_ZIMAGE = Asset(
+ 'https://github.com/groeck/linux-test-downloads/raw/225223f2ad7d637b34426810bf6c3b727b76a718/sx1/zImage',
+ 'a0271899a8dc2165f9e0adb2d0a57fc839ae3a469722ffc56c77e108a8887615')
+
+ ASSET_INITRD = Asset(
+ 'https://github.com/groeck/linux-test-downloads/raw/225223f2ad7d637b34426810bf6c3b727b76a718/sx1/rootfs-armv4.cpio',
+ '35b0721249821aa544cd85b85d3cb8901db4c6d128eed86ab261e5d9e37d58f8')
+
+ ASSET_SD_FS = Asset(
+ 'https://github.com/groeck/linux-test-downloads/raw/225223f2ad7d637b34426810bf6c3b727b76a718/sx1/rootfs-armv4.ext2',
+ 'c1db7f43ef92469ebc8605013728c8950e7608439f01d13678994f0ce101c3a8')
+
+ ASSET_FLASH = Asset(
+ 'https://github.com/groeck/linux-test-downloads/raw/225223f2ad7d637b34426810bf6c3b727b76a718/sx1/flash',
+ '17e6a2758fa38efd2666be0879d4751fd37d194f25168a8deede420df519b676')
+
+ CONSOLE_ARGS = 'console=ttyS0,115200 earlycon=uart8250,mmio32,0xfffb0000,115200n8'
+
+ def test_arm_sx1_initrd(self):
+ self.set_machine('sx1')
+ zimage_path = self.ASSET_ZIMAGE.fetch()
+ initrd_path = self.ASSET_INITRD.fetch()
+ self.vm.add_args('-append', f'kunit.enable=0 rdinit=/sbin/init {self.CONSOLE_ARGS}')
+ self.vm.add_args('-no-reboot')
+ self.launch_kernel(zimage_path,
+ initrd=initrd_path,
+ wait_for='Boot successful')
+ self.vm.wait(timeout=120)
+
+ def test_arm_sx1_sd(self):
+ self.set_machine('sx1')
+ zimage_path = self.ASSET_ZIMAGE.fetch()
+ sd_fs_path = self.ASSET_SD_FS.fetch()
+ self.vm.add_args('-append', f'kunit.enable=0 root=/dev/mmcblk0 rootwait {self.CONSOLE_ARGS}')
+ self.vm.add_args('-no-reboot')
+ self.vm.add_args('-snapshot')
+ self.vm.add_args('-drive', f'format=raw,if=sd,file={sd_fs_path}')
+ self.launch_kernel(zimage_path, wait_for='Boot successful')
+ self.vm.wait(timeout=120)
+
+ def test_arm_sx1_flash(self):
+ self.set_machine('sx1')
+ zimage_path = self.ASSET_ZIMAGE.fetch()
+ flash_path = self.ASSET_FLASH.fetch()
+ self.vm.add_args('-append', f'kunit.enable=0 root=/dev/mtdblock3 rootwait {self.CONSOLE_ARGS}')
+ self.vm.add_args('-no-reboot')
+ self.vm.add_args('-snapshot')
+ self.vm.add_args('-drive', f'format=raw,if=pflash,file={flash_path}')
+ self.launch_kernel(zimage_path, wait_for='Boot successful')
+ self.vm.wait(timeout=120)
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_tuxrun.py b/tests/functional/test_arm_tuxrun.py
new file mode 100755
index 0000000..4ac85f4
--- /dev/null
+++ b/tests/functional/test_arm_tuxrun.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunArmTest(TuxRunBaselineTest):
+
+ ASSET_ARMV5_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/armv5/zImage',
+ '3931a3908dbcf0ec0fe292d035ffc4dfed95f797dedd4a59ccfcf7a46e6f92d4')
+ ASSET_ARMV5_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/armv5/rootfs.ext4.zst',
+ '60ff78b68c7021df378e4fc2d66d3b016484d1acc7e07fb8920c1d8e30f4571f')
+ ASSET_ARMV5_DTB = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/armv5/versatile-pb.dtb',
+ '50988e69ef3f3b08bfb9146e8fe414129990029e8dfbed444953b7e14809530a')
+
+ def test_armv5(self):
+ self.set_machine('versatilepb')
+ self.cpu='arm926'
+ self.console='ttyAMA0'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_ARMV5_KERNEL,
+ rootfs_asset=self.ASSET_ARMV5_ROOTFS,
+ dtb_asset=self.ASSET_ARMV5_DTB,
+ drive="virtio-blk-pci")
+
+ ASSET_ARMV7_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/armv7/zImage',
+ '1377bc3d90de5ce57ab17cd67429fe8b15c2e9964248c775c682b67e6299b991')
+ ASSET_ARMV7_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/armv7/rootfs.ext4.zst',
+ 'ed2cbc69bd6b3fbd5cafb5ee961393c7cfbe726446f14301c67d6b1f28bfdb51')
+
+ def test_armv7(self):
+ self.set_machine('virt')
+ self.cpu='cortex-a15'
+ self.console='ttyAMA0'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_ARMV7_KERNEL,
+ rootfs_asset=self.ASSET_ARMV7_ROOTFS)
+
+ ASSET_ARMV7BE_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/armv7be/zImage',
+ 'a244e6da99f1bbd254827ec7681bd4aac9eb1aa05aaebc6b15e5d289ebb683f3')
+ ASSET_ARMV7BE_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/armv7be/rootfs.ext4.zst',
+ 'd4f9c57860a512163f30ecc69b2174d1a1bdeb853a43dc49a09cfcfe84e428ea')
+
+ def test_armv7be(self):
+ self.set_machine('virt')
+ self.cpu='cortex-a15'
+ self.console='ttyAMA0'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_ARMV7BE_KERNEL,
+ rootfs_asset=self.ASSET_ARMV7BE_ROOTFS)
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_arm_vexpress.py b/tests/functional/test_arm_vexpress.py
new file mode 100755
index 0000000..6b11552
--- /dev/null
+++ b/tests/functional/test_arm_vexpress.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on an versatile express machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class VExpressTest(LinuxKernelTest):
+
+ ASSET_DAY16 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day16.tar.xz',
+ '63311adb2d4c4e7a73214a86d29988add87266a909719c56acfadd026b4110a7')
+
+ def test_arm_vexpressa9(self):
+ self.set_machine('vexpress-a9')
+ self.archive_extract(self.ASSET_DAY16)
+ self.launch_kernel(self.scratch_file('day16', 'winter.zImage'),
+ dtb=self.scratch_file('day16',
+ 'vexpress-v2p-ca9.dtb'),
+ wait_for='QEMU advent calendar')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_virt.py b/tests/functional/test_arm_virt.py
new file mode 100755
index 0000000..7b65491
--- /dev/null
+++ b/tests/functional/test_arm_virt.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+class ArmVirtMachine(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/'
+ 'releases/29/Everything/armhfp/os/images/pxeboot/vmlinuz'),
+ '18dd5f1a9a28bd539f9d047f7c0677211bae528e8712b40ca5a229a4ad8e2591')
+
+ def test_arm_virt(self):
+ self.set_machine('virt')
+ kernel_path = self.ASSET_KERNEL.fetch()
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyAMA0')
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_avr_mega2560.py b/tests/functional/test_avr_mega2560.py
index 8e47b42..6359b72 100755
--- a/tests/functional/test_avr_mega2560.py
+++ b/tests/functional/test_avr_mega2560.py
@@ -18,12 +18,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-import time
+from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern
-from qemu_test import QemuSystemTest, Asset
class AVR6Machine(QemuSystemTest):
- timeout = 5
ASSET_ROM = Asset(('https://github.com/seharris/qemu-avr-tests'
'/raw/36c3e67b8755dcf/free-rtos/Demo'
@@ -40,13 +38,12 @@ class AVR6Machine(QemuSystemTest):
self.set_machine('arduino-mega-2560-v3')
self.vm.add_args('-bios', rom_path)
self.vm.add_args('-nographic')
+ self.vm.set_console()
self.vm.launch()
- time.sleep(2)
- self.vm.shutdown()
+ wait_for_console_pattern(self,
+ 'XABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXA')
- self.assertIn('ABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWX',
- self.vm.get_log())
if __name__ == '__main__':
QemuSystemTest.main()
diff --git a/tests/functional/test_avr_uno.py b/tests/functional/test_avr_uno.py
new file mode 100755
index 0000000..adb3b73
--- /dev/null
+++ b/tests/functional/test_avr_uno.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python3
+#
+# QEMU AVR Arduino UNO functional test
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern
+
+
+class UnoMachine(QemuSystemTest):
+
+ ASSET_UNO = Asset(
+ ('https://github.com/RahulRNandan/LED_Blink_AVR/raw/'
+ 'c6d602cbb974a193/build/main.elf'),
+ '3009a4e2cf5c5b65142f538abdf66d4dc6bc6beab7e552fff9ae314583761b72')
+
+ def test_uno(self):
+ """
+ The binary constantly prints out 'LED Blink'
+ """
+ self.set_machine('arduino-uno')
+ rom_path = self.ASSET_UNO.fetch()
+
+ self.vm.add_args('-bios', rom_path)
+ self.vm.set_console()
+ self.vm.launch()
+
+ wait_for_console_pattern(self, 'LED Blink')
+
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_hppa_seabios.py b/tests/functional/test_hppa_seabios.py
new file mode 100755
index 0000000..661b246
--- /dev/null
+++ b/tests/functional/test_hppa_seabios.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+#
+# SeaBIOS boot test for HPPA machines
+#
+# Copyright (c) 2024 Linaro, Ltd
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import QemuSystemTest
+from qemu_test import wait_for_console_pattern
+
+class HppaSeabios(QemuSystemTest):
+
+ timeout = 5
+ MACH_BITS = {'B160L': 32, 'C3700': 64}
+
+ def boot_seabios(self):
+ mach = self.machine
+ bits = self.MACH_BITS[mach]
+ self.vm.add_args('-no-shutdown')
+ self.vm.set_console()
+ self.vm.launch()
+ wait_for_console_pattern(self, f'SeaBIOS PA-RISC {bits}-bit Firmware')
+ wait_for_console_pattern(self, f'Emulated machine: HP {mach} ({bits}-bit')
+
+ def test_hppa_32(self):
+ self.set_machine('B160L')
+ self.boot_seabios()
+
+ def test_hppa_64(self):
+ self.set_machine('C3700')
+ self.boot_seabios()
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_i386_replay.py b/tests/functional/test_i386_replay.py
new file mode 100755
index 0000000..7c4c260
--- /dev/null
+++ b/tests/functional/test_i386_replay.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+#
+# Replay test that boots a Linux kernel on a i386 machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from replay_kernel import ReplayKernelBase
+
+
+class I386Replay(ReplayKernelBase):
+
+ ASSET_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/i386/bzImage',
+ 'a3e5b32a354729e65910f5a1ffcda7c14a6c12a55e8213fb86e277f1b76ed956')
+
+ def test_pc(self):
+ self.set_machine('pc')
+ kernel_url = ()
+ kernel_path = self.ASSET_KERNEL.fetch()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
+ console_pattern = 'VFS: Cannot open root device'
+ self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_i386_tuxrun.py b/tests/functional/test_i386_tuxrun.py
new file mode 100755
index 0000000..f3ccf11
--- /dev/null
+++ b/tests/functional/test_i386_tuxrun.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunI386Test(TuxRunBaselineTest):
+
+ ASSET_I386_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/i386/bzImage',
+ '47fb44e38e34101eb0f71a2a01742b959d40ed5fd67cefb5608a39be11d3b74e')
+ ASSET_I386_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/i386/rootfs.ext4.zst',
+ 'a1a3b3b4c9dccd6475b58db95c107b468b736b700f6620985a8ed050a73d51c8')
+
+ def test_i386(self):
+ self.set_machine('q35')
+ self.cpu="coreduo"
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_I386_KERNEL,
+ rootfs_asset=self.ASSET_I386_ROOTFS,
+ drive="virtio-blk-pci")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_info_usernet.py b/tests/functional/test_info_usernet.py
index cd37524..e8cbc37 100755
--- a/tests/functional/test_info_usernet.py
+++ b/tests/functional/test_info_usernet.py
@@ -11,8 +11,7 @@
# later. See the COPYING file in the top-level directory.
from qemu_test import QemuSystemTest
-
-from qemu.utils import get_info_usernet_hostfwd_port
+from qemu_test.utils import get_usernet_hostfwd_port
class InfoUsernet(QemuSystemTest):
@@ -22,9 +21,8 @@ class InfoUsernet(QemuSystemTest):
self.set_machine('none')
self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22')
self.vm.launch()
- res = self.vm.cmd('human-monitor-command',
- command_line='info usernet')
- port = get_info_usernet_hostfwd_port(res)
+
+ port = get_usernet_hostfwd_port(self.vm)
self.assertIsNotNone(port,
('"info usernet" output content does not seem to '
'contain the redirected port'))
diff --git a/tests/functional/test_intel_iommu.py b/tests/functional/test_intel_iommu.py
new file mode 100755
index 0000000..62268d6
--- /dev/null
+++ b/tests/functional/test_intel_iommu.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python3
+#
+# INTEL_IOMMU Functional tests
+#
+# Copyright (c) 2021 Red Hat, Inc.
+#
+# Author:
+# Eric Auger <eric.auger@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern
+
+
+class IntelIOMMU(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Server/x86_64/os/images/pxeboot/vmlinuz'),
+ 'd4738d03dbbe083ca610d0821d0a8f1488bebbdccef54ce33e3adb35fda00129')
+
+ ASSET_INITRD = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Server/x86_64/os/images/pxeboot/initrd.img'),
+ '277cd6c7adf77c7e63d73bbb2cded8ef9e2d3a2f100000e92ff1f8396513cd8b')
+
+ ASSET_DISKIMAGE = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Cloud/x86_64/images/Fedora-Cloud-Base-31-1.9.x86_64.qcow2'),
+ 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0')
+
+ DEFAULT_KERNEL_PARAMS = ('root=/dev/vda1 console=ttyS0 net.ifnames=0 '
+ 'quiet rd.rescue ')
+ GUEST_PORT = 8080
+ IOMMU_ADDON = ',iommu_platform=on,disable-modern=off,disable-legacy=on'
+ kernel_path = None
+ initrd_path = None
+ kernel_params = None
+
+ def add_common_args(self, path):
+ self.vm.add_args('-drive', f'file={path},if=none,id=drv0,snapshot=on')
+ self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,' +
+ 'drive=drv0,id=virtio-disk0,bootindex=1,'
+ 'werror=stop,rerror=stop' + self.IOMMU_ADDON)
+ self.vm.add_args('-device', 'virtio-gpu-pci' + self.IOMMU_ADDON)
+
+ self.vm.add_args('-netdev',
+ 'user,id=n1,hostfwd=tcp:127.0.0.1:0-:%d' %
+ self.GUEST_PORT)
+ self.vm.add_args('-device',
+ 'virtio-net-pci,netdev=n1' + self.IOMMU_ADDON)
+
+ self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
+ self.vm.add_args('-object',
+ 'rng-random,id=rng0,filename=/dev/urandom')
+ self.vm.add_args("-m", "1G")
+ self.vm.add_args("-accel", "kvm")
+
+ def common_vm_setup(self):
+ self.set_machine('q35')
+ self.require_accelerator("kvm")
+ self.require_netdev('user')
+
+ self.kernel_path = self.ASSET_KERNEL.fetch()
+ self.initrd_path = self.ASSET_INITRD.fetch()
+ image_path = self.ASSET_DISKIMAGE.fetch()
+ self.add_common_args(image_path)
+ self.kernel_params = self.DEFAULT_KERNEL_PARAMS
+
+ def run_and_check(self):
+ if self.kernel_path:
+ self.vm.add_args('-kernel', self.kernel_path,
+ '-append', self.kernel_params,
+ '-initrd', self.initrd_path)
+ self.vm.set_console()
+ self.vm.launch()
+ self.wait_for_console_pattern('Entering emergency mode.')
+ prompt = '# '
+ self.wait_for_console_pattern(prompt)
+
+ # Copy a file (checked later), umount afterwards to drop disk cache:
+ exec_command_and_wait_for_pattern(self, 'mount /dev/vda1 /sysroot',
+ prompt)
+ filename = '/boot/initramfs-5.3.7-301.fc31.x86_64.img'
+ exec_command_and_wait_for_pattern(self, (f'cp /sysroot{filename}'
+ ' /sysroot/root/data'),
+ prompt)
+ exec_command_and_wait_for_pattern(self, 'umount /sysroot', prompt)
+
+ # Switch from initrd to the cloud image filesystem:
+ exec_command_and_wait_for_pattern(self, 'mount /dev/vda1 /sysroot',
+ prompt)
+ exec_command_and_wait_for_pattern(self,
+ ('for d in dev proc sys run ; do '
+ 'mount -o bind /$d /sysroot/$d ; done'), prompt)
+ exec_command_and_wait_for_pattern(self, 'chroot /sysroot', prompt)
+
+ # Checking for IOMMU enablement:
+ self.log.info("Checking whether IOMMU has been enabled...")
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cmdline',
+ 'intel_iommu=on')
+ self.wait_for_console_pattern(prompt)
+ exec_command_and_wait_for_pattern(self, 'dmesg | grep DMAR:',
+ 'IOMMU enabled')
+ self.wait_for_console_pattern(prompt)
+ exec_command_and_wait_for_pattern(self,
+ 'find /sys/kernel/iommu_groups/ -type l',
+ 'devices/0000:00:')
+ self.wait_for_console_pattern(prompt)
+
+ # Check hard disk device via sha256sum:
+ self.log.info("Checking hard disk...")
+ hashsum = '0dc7472f879be70b2f3daae279e3ae47175ffe249691e7d97f47222b65b8a720'
+ exec_command_and_wait_for_pattern(self, 'sha256sum ' + filename,
+ hashsum)
+ self.wait_for_console_pattern(prompt)
+ exec_command_and_wait_for_pattern(self, 'sha256sum /root/data',
+ hashsum)
+ self.wait_for_console_pattern(prompt)
+
+ # Check virtio-net via HTTP:
+ exec_command_and_wait_for_pattern(self, 'dhclient eth0', prompt)
+ self.check_http_download(filename, hashsum, self.GUEST_PORT)
+
+ def test_intel_iommu(self):
+ self.common_vm_setup()
+ self.vm.add_args('-device', 'intel-iommu,intremap=on')
+ self.vm.add_args('-machine', 'kernel_irqchip=split')
+ self.kernel_params += 'intel_iommu=on'
+ self.run_and_check()
+
+ def test_intel_iommu_strict(self):
+ self.common_vm_setup()
+ self.vm.add_args('-device', 'intel-iommu,intremap=on')
+ self.vm.add_args('-machine', 'kernel_irqchip=split')
+ self.kernel_params += 'intel_iommu=on,strict'
+ self.run_and_check()
+
+ def test_intel_iommu_strict_cm(self):
+ self.common_vm_setup()
+ self.vm.add_args('-device', 'intel-iommu,intremap=on,caching-mode=on')
+ self.vm.add_args('-machine', 'kernel_irqchip=split')
+ self.kernel_params += 'intel_iommu=on,strict'
+ self.run_and_check()
+
+ def test_intel_iommu_pt(self):
+ self.common_vm_setup()
+ self.vm.add_args('-device', 'intel-iommu,intremap=on')
+ self.vm.add_args('-machine', 'kernel_irqchip=split')
+ self.kernel_params += 'intel_iommu=on iommu=pt'
+ self.run_and_check()
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_linux_initrd.py b/tests/functional/test_linux_initrd.py
index c71a59d..2207f83 100755
--- a/tests/functional/test_linux_initrd.py
+++ b/tests/functional/test_linux_initrd.py
@@ -10,12 +10,10 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-import os
import logging
import tempfile
-from qemu_test import QemuSystemTest, Asset
-from unittest import skipUnless
+from qemu_test import QemuSystemTest, Asset, skipFlakyTest
class LinuxInitrd(QemuSystemTest):
@@ -60,7 +58,8 @@ class LinuxInitrd(QemuSystemTest):
max_size + 1)
self.assertRegex(self.vm.get_log(), expected_msg)
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
+ # XXX file tracking bug
+ @skipFlakyTest(bug_url=None)
def test_with_2gib_file_should_work_with_linux_v4_16(self):
"""
QEMU has supported up to 4 GiB initrd for recent kernel
diff --git a/tests/functional/test_loongarch64_virt.py b/tests/functional/test_loongarch64_virt.py
index 2b8baa2..b7d9abf 100755
--- a/tests/functional/test_loongarch64_virt.py
+++ b/tests/functional/test_loongarch64_virt.py
@@ -18,16 +18,16 @@ class LoongArchMachine(QemuSystemTest):
ASSET_KERNEL = Asset(
('https://github.com/yangxiaojuan-loongson/qemu-binary/'
- 'releases/download/2024-05-30/vmlinuz.efi'),
+ 'releases/download/2024-11-26/vmlinuz.efi'),
'08b88a45f48a5fd92260bae895be4e5175be2397481a6f7821b9f39b2965b79e')
ASSET_INITRD = Asset(
('https://github.com/yangxiaojuan-loongson/qemu-binary/'
- 'releases/download/2024-05-30/ramdisk'),
+ 'releases/download/2024-11-26/ramdisk'),
'03d6fb6f8ee64ecac961120a0bdacf741f17b3bee2141f17fa01908c8baf176a')
ASSET_BIOS = Asset(
('https://github.com/yangxiaojuan-loongson/qemu-binary/'
- 'releases/download/2024-05-30/QEMU_EFI.fd'),
- '937c1e7815e2340150c194a9f8f0474259038a3d7b8845ed62cc08163c46bea1')
+ 'releases/download/2024-11-26/QEMU_EFI.fd'),
+ 'f55fbf5d92e885844631ae9bfa8887f659bbb4f6ef2beea9e9ff8bc0603b6697')
def wait_for_console_pattern(self, success_message, vm=None):
wait_for_console_pattern(self, success_message,
diff --git a/tests/functional/test_m68k_mcf5208evb.py b/tests/functional/test_m68k_mcf5208evb.py
new file mode 100755
index 0000000..c7d1998
--- /dev/null
+++ b/tests/functional/test_m68k_mcf5208evb.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on an MCF5208EVB machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class Mcf5208EvbTest(LinuxKernelTest):
+
+ ASSET_DAY07 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day07.tar.xz',
+ '753c2f3837126b7c6ba92d0b1e0b156e8a2c5131d2d576bb0b9a763fae73c08a')
+
+ def test_m68k_mcf5208evb(self):
+ self.set_machine('mcf5208evb')
+ self.archive_extract(self.ASSET_DAY07)
+ self.vm.set_console()
+ self.vm.add_args('-kernel',
+ self.scratch_file('day07', 'sanity-clause.elf'))
+ self.vm.launch()
+ self.wait_for_console_pattern('QEMU advent calendar')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_m68k_nextcube.py b/tests/functional/test_m68k_nextcube.py
index 89385a1..13c72bd 100755
--- a/tests/functional/test_m68k_nextcube.py
+++ b/tests/functional/test_m68k_nextcube.py
@@ -7,19 +7,11 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-import os
import time
from qemu_test import QemuSystemTest, Asset
-from unittest import skipUnless
-
-from qemu_test.tesseract import tesseract_available, tesseract_ocr
-
-PIL_AVAILABLE = True
-try:
- from PIL import Image
-except ImportError:
- PIL_AVAILABLE = False
+from qemu_test import skipIfMissingImports, skipIfMissingCommands
+from qemu_test.tesseract import tesseract_ocr
class NextCubeMachine(QemuSystemTest):
@@ -37,30 +29,29 @@ class NextCubeMachine(QemuSystemTest):
self.vm.launch()
self.log.info('VM launched, waiting for display')
- # TODO: Use avocado.utils.wait.wait_for to catch the
- # 'displaysurface_create 1120x832' trace-event.
+ # TODO: wait for the 'displaysurface_create 1120x832' trace-event.
time.sleep(2)
- self.vm.cmd('human-monitor-command',
- command_line='screendump %s' % screenshot_path)
+ res = self.vm.cmd('human-monitor-command',
+ command_line='screendump %s' % screenshot_path)
+ if 'unknown command' in res:
+ self.skipTest('screendump not available')
- @skipUnless(PIL_AVAILABLE, 'Python PIL not installed')
+ @skipIfMissingImports("PIL")
def test_bootrom_framebuffer_size(self):
self.set_machine('next-cube')
- screenshot_path = os.path.join(self.workdir, "dump.ppm")
+ screenshot_path = self.scratch_file("dump.ppm")
self.check_bootrom_framebuffer(screenshot_path)
+ from PIL import Image
width, height = Image.open(screenshot_path).size
self.assertEqual(width, 1120)
self.assertEqual(height, 832)
- # Tesseract 4 adds a new OCR engine based on LSTM neural networks. The
- # new version is faster and more accurate than version 3. The drawback is
- # that it is still alpha-level software.
- @skipUnless(tesseract_available(4), 'tesseract OCR tool not available')
+ @skipIfMissingCommands('tesseract')
def test_bootrom_framebuffer_ocr_with_tesseract(self):
self.set_machine('next-cube')
- screenshot_path = os.path.join(self.workdir, "dump.ppm")
+ screenshot_path = self.scratch_file("dump.ppm")
self.check_bootrom_framebuffer(screenshot_path)
lines = tesseract_ocr(screenshot_path)
text = '\n'.join(lines)
diff --git a/tests/functional/test_m68k_q800.py b/tests/functional/test_m68k_q800.py
new file mode 100755
index 0000000..b3e6553
--- /dev/null
+++ b/tests/functional/test_m68k_q800.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3
+#
+# Functional test for testing the q800 m68k machine
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from qemu_test import LinuxKernelTest, Asset
+
+class Q800MachineTest(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ ('https://snapshot.debian.org/'
+ 'archive/debian-ports/20191021T083923Z/pool-m68k/main/l/linux/'
+ 'kernel-image-5.3.0-1-m68k-di_5.3.7-1_m68k.udeb'),
+ '949e50d74d4b9bc15d26c06d402717b7a4c0e32ff8100014f5930d8024de7b73')
+
+ def test_m68k_q800(self):
+ self.set_machine('q800')
+
+ kernel_path = self.archive_extract(self.ASSET_KERNEL,
+ member='boot/vmlinux-5.3.0-1-m68k')
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0 vga=off')
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line,
+ '-audio', 'none')
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+ console_pattern = 'No filesystem could mount root'
+ self.wait_for_console_pattern(console_pattern)
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_m68k_replay.py b/tests/functional/test_m68k_replay.py
new file mode 100755
index 0000000..213d6ae
--- /dev/null
+++ b/tests/functional/test_m68k_replay.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+#
+# Replay test that boots a Linux kernel on an m68k machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from replay_kernel import ReplayKernelBase
+
+
+class M68kReplay(ReplayKernelBase):
+
+ ASSET_Q800 = Asset(
+ ('https://snapshot.debian.org/'
+ 'archive/debian-ports/20191021T083923Z/pool-m68k/main/l/linux/'
+ 'kernel-image-5.3.0-1-m68k-di_5.3.7-1_m68k.udeb'),
+ '949e50d74d4b9bc15d26c06d402717b7a4c0e32ff8100014f5930d8024de7b73')
+
+ def test_q800(self):
+ self.set_machine('q800')
+ kernel_path = self.archive_extract(self.ASSET_Q800,
+ member='boot/vmlinux-5.3.0-1-m68k')
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0 vga=off')
+ console_pattern = 'No filesystem could mount root'
+ self.run_rr(kernel_path, kernel_command_line, console_pattern,
+ args=('-audio', 'none'))
+
+ ASSET_MCF5208 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day07.tar.xz',
+ '753c2f3837126b7c6ba92d0b1e0b156e8a2c5131d2d576bb0b9a763fae73c08a')
+
+ def test_mcf5208evb(self):
+ self.set_machine('mcf5208evb')
+ kernel_path = self.archive_extract(self.ASSET_MCF5208,
+ member='day07/sanity-clause.elf')
+ self.run_rr(kernel_path, self.KERNEL_COMMON_COMMAND_LINE,
+ 'QEMU advent calendar')
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_m68k_tuxrun.py b/tests/functional/test_m68k_tuxrun.py
new file mode 100755
index 0000000..7eacba1
--- /dev/null
+++ b/tests/functional/test_m68k_tuxrun.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2024 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunM68KTest(TuxRunBaselineTest):
+
+ ASSET_M68K_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/m68k/vmlinux',
+ '7754e1d5cec753ccf1dc6894729a7f54c1a4965631ebf56df8e4ce1163ad19d8')
+ ASSET_M68K_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/m68k/rootfs.ext4.zst',
+ '557962ffff265607912e82232cf21adbe0e4e5a88e1e1d411ce848c37f0213e9')
+
+ def test_m68k(self):
+ self.set_machine('virt')
+ self.cpu="m68040"
+ self.common_tuxrun(kernel_asset=self.ASSET_M68K_KERNEL,
+ rootfs_asset=self.ASSET_M68K_ROOTFS,
+ drive="virtio-blk-device")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_mem_addr_space.py b/tests/functional/test_mem_addr_space.py
index bb0cf06..61b4a19 100755
--- a/tests/functional/test_mem_addr_space.py
+++ b/tests/functional/test_mem_addr_space.py
@@ -20,6 +20,25 @@ class MemAddrCheck(QemuSystemTest):
# this reason.
DELAY_Q35_BOOT_SEQUENCE = 1
+ # This helper can go away when the 32-bit host deprecation
+ # turns into full & final removal of support.
+ def ensure_64bit_binary(self):
+ with open(self.qemu_bin, "rb") as fh:
+ ident = fh.read(4)
+
+ # "\x7fELF"
+ if ident != bytes([0x7f, 0x45, 0x4C, 0x46]):
+ # Non-ELF file implies macOS or Windows which
+ # we already assume to be 64-bit only
+ return
+
+ # bits == 1 -> 32-bit; bits == 2 -> 64-bit
+ bits = int.from_bytes(fh.read(1), byteorder='little')
+ if bits != 2:
+ # 32-bit ELF builds won't be able to address sufficient
+ # RAM to run the tests
+ self.skipTest("64-bit build host is required")
+
# first, lets test some 32-bit processors.
# for all 32-bit cases, pci64_hole_size is 0.
def test_phybits_low_pse36(self):
@@ -38,8 +57,9 @@ class MemAddrCheck(QemuSystemTest):
If maxmem is set to 59.5G with all other QEMU parameters identical, QEMU
should start fine.
"""
- self.vm.add_args('-S', '-machine', 'q35', '-m',
- '512,slots=1,maxmem=59.6G',
+ self.ensure_64bit_binary()
+ self.set_machine('q35')
+ self.vm.add_args('-S', '-m', '512,slots=1,maxmem=59.6G',
'-cpu', 'pentium,pse36=on', '-display', 'none',
'-object', 'memory-backend-ram,id=mem1,size=1G',
'-device', 'pc-dimm,id=vm0,memdev=mem1')
@@ -55,8 +75,9 @@ class MemAddrCheck(QemuSystemTest):
access up to a maximum of 64GiB of memory. Rest is the same as the case
with pse36 above.
"""
- self.vm.add_args('-S', '-machine', 'q35', '-m',
- '512,slots=1,maxmem=59.6G',
+ self.ensure_64bit_binary()
+ self.set_machine('q35')
+ self.vm.add_args('-S', '-m', '512,slots=1,maxmem=59.6G',
'-cpu', 'pentium,pae=on', '-display', 'none',
'-object', 'memory-backend-ram,id=mem1,size=1G',
'-device', 'pc-dimm,id=vm0,memdev=mem1')
@@ -71,8 +92,9 @@ class MemAddrCheck(QemuSystemTest):
Setting maxmem to 59.5G and making sure that QEMU can start with the
same options as the failing case above with pse36 cpu feature.
"""
- self.vm.add_args('-machine', 'q35', '-m',
- '512,slots=1,maxmem=59.5G',
+ self.ensure_64bit_binary()
+ self.set_machine('q35')
+ self.vm.add_args('-m', '512,slots=1,maxmem=59.5G',
'-cpu', 'pentium,pse36=on', '-display', 'none',
'-object', 'memory-backend-ram,id=mem1,size=1G',
'-device', 'pc-dimm,id=vm0,memdev=mem1')
@@ -88,8 +110,9 @@ class MemAddrCheck(QemuSystemTest):
Setting maxmem to 59.5G and making sure that QEMU can start fine
with the same options as the case above.
"""
- self.vm.add_args('-machine', 'q35', '-m',
- '512,slots=1,maxmem=59.5G',
+ self.ensure_64bit_binary()
+ self.set_machine('q35')
+ self.vm.add_args('-m', '512,slots=1,maxmem=59.5G',
'-cpu', 'pentium,pae=on', '-display', 'none',
'-object', 'memory-backend-ram,id=mem1,size=1G',
'-device', 'pc-dimm,id=vm0,memdev=mem1')
@@ -104,8 +127,9 @@ class MemAddrCheck(QemuSystemTest):
Pentium2 has 36 bits of addressing, so its same as pentium
with pse36 ON.
"""
- self.vm.add_args('-machine', 'q35', '-m',
- '512,slots=1,maxmem=59.5G',
+ self.ensure_64bit_binary()
+ self.set_machine('q35')
+ self.vm.add_args('-m', '512,slots=1,maxmem=59.5G',
'-cpu', 'pentium2', '-display', 'none',
'-object', 'memory-backend-ram,id=mem1,size=1G',
'-device', 'pc-dimm,id=vm0,memdev=mem1')
@@ -123,8 +147,9 @@ class MemAddrCheck(QemuSystemTest):
message because the region for memory hotplug is always placed
above 4 GiB due to the PCI hole and simplicity.
"""
- self.vm.add_args('-S', '-machine', 'q35', '-m',
- '512,slots=1,maxmem=4G',
+ self.ensure_64bit_binary()
+ self.set_machine('q35')
+ self.vm.add_args('-S', '-m', '512,slots=1,maxmem=4G',
'-cpu', 'pentium', '-display', 'none',
'-object', 'memory-backend-ram,id=mem1,size=1G',
'-device', 'pc-dimm,id=vm0,memdev=mem1')
@@ -150,8 +175,9 @@ class MemAddrCheck(QemuSystemTest):
which is equal to 987.5 GiB. Setting the value to 988 GiB should
make QEMU fail with the error message.
"""
- self.vm.add_args('-S', '-machine', 'pc-q35-7.0', '-m',
- '512,slots=1,maxmem=988G',
+ self.ensure_64bit_binary()
+ self.set_machine('pc-q35-7.0')
+ self.vm.add_args('-S', '-m', '512,slots=1,maxmem=988G',
'-display', 'none',
'-object', 'memory-backend-ram,id=mem1,size=1G',
'-device', 'pc-dimm,id=vm0,memdev=mem1')
@@ -170,8 +196,9 @@ class MemAddrCheck(QemuSystemTest):
Make sure QEMU fails when maxmem size is 976 GiB (12 GiB less
than 988 GiB).
"""
- self.vm.add_args('-S', '-machine', 'pc-q35-7.1', '-m',
- '512,slots=1,maxmem=976G',
+ self.ensure_64bit_binary()
+ self.set_machine('pc-q35-7.1')
+ self.vm.add_args('-S', '-m', '512,slots=1,maxmem=976G',
'-display', 'none',
'-object', 'memory-backend-ram,id=mem1,size=1G',
'-device', 'pc-dimm,id=vm0,memdev=mem1')
@@ -186,8 +213,9 @@ class MemAddrCheck(QemuSystemTest):
Same as q35-7.0 AMD case except that here we check that QEMU can
successfully start when maxmem is < 988G.
"""
- self.vm.add_args('-S', '-machine', 'pc-q35-7.0', '-m',
- '512,slots=1,maxmem=987.5G',
+ self.ensure_64bit_binary()
+ self.set_machine('pc-q35-7.0')
+ self.vm.add_args('-S', '-m', '512,slots=1,maxmem=987.5G',
'-display', 'none',
'-object', 'memory-backend-ram,id=mem1,size=1G',
'-device', 'pc-dimm,id=vm0,memdev=mem1')
@@ -202,8 +230,9 @@ class MemAddrCheck(QemuSystemTest):
Same as q35-7.1 AMD case except that here we check that QEMU can
successfully start when maxmem is < 976G.
"""
- self.vm.add_args('-S', '-machine', 'pc-q35-7.1', '-m',
- '512,slots=1,maxmem=975.5G',
+ self.ensure_64bit_binary()
+ self.set_machine('pc-q35-7.1')
+ self.vm.add_args('-S', '-m', '512,slots=1,maxmem=975.5G',
'-display', 'none',
'-object', 'memory-backend-ram,id=mem1,size=1G',
'-device', 'pc-dimm,id=vm0,memdev=mem1')
@@ -219,9 +248,10 @@ class MemAddrCheck(QemuSystemTest):
Intel cpu instead. QEMU should start fine in this case as
"above_4G" memory starts at 4G.
"""
+ self.ensure_64bit_binary()
+ self.set_machine('pc-q35-7.1')
self.vm.add_args('-S', '-cpu', 'Skylake-Server',
- '-machine', 'pc-q35-7.1', '-m',
- '512,slots=1,maxmem=976G',
+ '-m', '512,slots=1,maxmem=976G',
'-display', 'none',
'-object', 'memory-backend-ram,id=mem1,size=1G',
'-device', 'pc-dimm,id=vm0,memdev=mem1')
@@ -243,9 +273,10 @@ class MemAddrCheck(QemuSystemTest):
memory for the VM (1024 - 32 - 1 + 0.5). With 992 GiB, QEMU should
fail to start.
"""
+ self.ensure_64bit_binary()
+ self.set_machine('pc-q35-7.1')
self.vm.add_args('-S', '-cpu', 'EPYC-v4,phys-bits=41',
- '-machine', 'pc-q35-7.1', '-m',
- '512,slots=1,maxmem=992G',
+ '-m', '512,slots=1,maxmem=992G',
'-display', 'none',
'-object', 'memory-backend-ram,id=mem1,size=1G',
'-device', 'pc-dimm,id=vm0,memdev=mem1')
@@ -261,9 +292,10 @@ class MemAddrCheck(QemuSystemTest):
Same as above but by setting maxram between 976 GiB and 992 Gib,
QEMU should start fine.
"""
+ self.ensure_64bit_binary()
+ self.set_machine('pc-q35-7.1')
self.vm.add_args('-S', '-cpu', 'EPYC-v4,phys-bits=41',
- '-machine', 'pc-q35-7.1', '-m',
- '512,slots=1,maxmem=990G',
+ '-m', '512,slots=1,maxmem=990G',
'-display', 'none',
'-object', 'memory-backend-ram,id=mem1,size=1G',
'-device', 'pc-dimm,id=vm0,memdev=mem1')
@@ -281,12 +313,13 @@ class MemAddrCheck(QemuSystemTest):
So maxmem here should be at most 986 GiB considering all memory boundary
alignment constraints with 40 bits (1 TiB) of processor physical bits.
"""
+ self.ensure_64bit_binary()
+ self.set_machine('q35')
self.vm.add_args('-S', '-cpu', 'Skylake-Server,phys-bits=40',
- '-machine', 'q35,cxl=on', '-m',
- '512,slots=1,maxmem=987G',
+ '-m', '512,slots=1,maxmem=987G',
'-display', 'none',
'-device', 'pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1',
- '-M', 'cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=1G')
+ '-M', 'cxl=on,cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=1G')
self.vm.set_qmp_monitor(enabled=False)
self.vm.launch()
self.vm.wait()
@@ -299,9 +332,11 @@ class MemAddrCheck(QemuSystemTest):
with the exact same parameters as above, QEMU should start fine even
with cxl enabled.
"""
+ self.ensure_64bit_binary()
+ self.set_machine('q35')
self.vm.add_args('-S', '-cpu', 'Skylake-Server,phys-bits=40',
- '-machine', 'q35,cxl=on', '-m',
- '512,slots=1,maxmem=987G',
+ '-machine', 'cxl=on',
+ '-m', '512,slots=1,maxmem=987G',
'-display', 'none',
'-device', 'pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1')
self.vm.set_qmp_monitor(enabled=False)
diff --git a/tests/functional/test_memlock.py b/tests/functional/test_memlock.py
new file mode 100755
index 0000000..2b515ff
--- /dev/null
+++ b/tests/functional/test_memlock.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+#
+# Functional test that check overcommit memlock options
+#
+# Copyright (c) Yandex Technologies LLC, 2025
+#
+# Author:
+# Alexandr Moshkov <dtalexundeer@yandex-team.ru>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import re
+
+from typing import Dict
+
+from qemu_test import QemuSystemTest
+from qemu_test import skipLockedMemoryTest
+
+
+STATUS_VALUE_PATTERN = re.compile(r'^(\w+):\s+(\d+) kB', re.MULTILINE)
+
+
+@skipLockedMemoryTest(2_097_152) # 2GB
+class MemlockTest(QemuSystemTest):
+ """
+ Runs a guest with memlock options.
+ Then verify, that this options is working correctly
+ by checking the status file of the QEMU process.
+ """
+
+ def common_vm_setup_with_memlock(self, memlock):
+ self.vm.add_args('-overcommit', f'mem-lock={memlock}')
+ self.vm.launch()
+
+ def test_memlock_off(self):
+ self.common_vm_setup_with_memlock('off')
+
+ status = self.get_process_status_values(self.vm.get_pid())
+
+ self.assertTrue(status['VmLck'] == 0)
+
+ def test_memlock_on(self):
+ self.common_vm_setup_with_memlock('on')
+
+ status = self.get_process_status_values(self.vm.get_pid())
+
+ # VmLck > 0 kB and almost all memory is resident
+ self.assertTrue(status['VmLck'] > 0)
+ self.assertTrue(status['VmRSS'] >= status['VmSize'] * 0.70)
+
+ def test_memlock_onfault(self):
+ self.common_vm_setup_with_memlock('on-fault')
+
+ status = self.get_process_status_values(self.vm.get_pid())
+
+ # VmLck > 0 kB and only few memory is resident
+ self.assertTrue(status['VmLck'] > 0)
+ self.assertTrue(status['VmRSS'] <= status['VmSize'] * 0.30)
+
+ def get_process_status_values(self, pid: int) -> Dict[str, int]:
+ result = {}
+ raw_status = self._get_raw_process_status(pid)
+
+ for line in raw_status.split('\n'):
+ if m := STATUS_VALUE_PATTERN.match(line):
+ result[m.group(1)] = int(m.group(2))
+
+ return result
+
+ def _get_raw_process_status(self, pid: int) -> str:
+ try:
+ with open(f'/proc/{pid}/status', 'r') as f:
+ return f.read()
+ except FileNotFoundError:
+ self.skipTest("Can't open status file of the process")
+
+
+if __name__ == '__main__':
+ MemlockTest.main()
diff --git a/tests/functional/test_microblaze_replay.py b/tests/functional/test_microblaze_replay.py
new file mode 100755
index 0000000..7484c41
--- /dev/null
+++ b/tests/functional/test_microblaze_replay.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+#
+# Replay test that boots a Linux kernel on an microblaze machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from replay_kernel import ReplayKernelBase
+
+
+class MicroblazeReplay(ReplayKernelBase):
+
+ ASSET_DAY17 = Asset(
+ ('https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/'
+ 'day17.tar.xz'),
+ '3ba7439dfbea7af4876662c97f8e1f0cdad9231fc166e4861d17042489270057')
+
+ def test_microblaze_s3adsp1800(self):
+ self.set_machine('petalogix-s3adsp1800')
+ kernel_path = self.archive_extract(self.ASSET_DAY17,
+ member='day17/ballerina.bin')
+ self.run_rr(kernel_path, self.REPLAY_KERNEL_COMMAND_LINE,
+ 'QEMU advent calendar')
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_microblaze_s3adsp1800.py b/tests/functional/test_microblaze_s3adsp1800.py
index 4f692ff..f093b16 100755
--- a/tests/functional/test_microblaze_s3adsp1800.py
+++ b/tests/functional/test_microblaze_s3adsp1800.py
@@ -7,27 +7,32 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-import time
-from qemu_test import exec_command, exec_command_and_wait_for_pattern
+from qemu_test import exec_command_and_wait_for_pattern
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
-from qemu_test.utils import archive_extract
+
class MicroblazeMachine(QemuSystemTest):
timeout = 90
- ASSET_IMAGE = Asset(
+ ASSET_IMAGE_BE = Asset(
('https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/'
'day17.tar.xz'),
'3ba7439dfbea7af4876662c97f8e1f0cdad9231fc166e4861d17042489270057')
- def test_microblaze_s3adsp1800(self):
+ ASSET_IMAGE_LE = Asset(
+ ('http://www.qemu-advent-calendar.org/2023/download/day13.tar.gz'),
+ 'b9b3d43c5dd79db88ada495cc6e0d1f591153fe41355e925d791fbf44de50c22')
+
+ def do_ballerina_be_test(self, force_endianness=False):
self.set_machine('petalogix-s3adsp1800')
- file_path = self.ASSET_IMAGE.fetch()
- archive_extract(file_path, self.workdir)
+ self.archive_extract(self.ASSET_IMAGE_BE)
self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir + '/day17/ballerina.bin')
+ self.vm.add_args('-kernel',
+ self.scratch_file('day17', 'ballerina.bin'))
+ if force_endianness:
+ self.vm.add_args('-M', 'endianness=big')
self.vm.launch()
wait_for_console_pattern(self, 'This architecture does not have '
'kernel memory protection')
@@ -36,5 +41,36 @@ class MicroblazeMachine(QemuSystemTest):
# message, that's why we don't test for a later string here. This
# needs some investigation by a microblaze wizard one day...
+ def do_xmaton_le_test(self, force_endianness=False):
+ self.require_netdev('user')
+ self.set_machine('petalogix-s3adsp1800')
+ self.archive_extract(self.ASSET_IMAGE_LE)
+ self.vm.set_console()
+ self.vm.add_args('-kernel', self.scratch_file('day13', 'xmaton.bin'))
+ if force_endianness:
+ self.vm.add_args('-M', 'endianness=little')
+ tftproot = self.scratch_file('day13')
+ self.vm.add_args('-nic', f'user,tftp={tftproot}')
+ self.vm.launch()
+ wait_for_console_pattern(self, 'QEMU Advent Calendar 2023')
+ wait_for_console_pattern(self, 'buildroot login:')
+ exec_command_and_wait_for_pattern(self, 'root', '#')
+ exec_command_and_wait_for_pattern(self,
+ 'tftp -g -r xmaton.png 10.0.2.2 ; md5sum xmaton.png',
+ '821cd3cab8efd16ad6ee5acc3642a8ea')
+
+
+class MicroblazeBigEndianMachine(MicroblazeMachine):
+
+ ASSET_IMAGE_BE = MicroblazeMachine.ASSET_IMAGE_BE
+ ASSET_IMAGE_LE = MicroblazeMachine.ASSET_IMAGE_LE
+
+ def test_microblaze_s3adsp1800_legacy_be(self):
+ self.do_ballerina_be_test()
+
+ def test_microblaze_s3adsp1800_legacy_le(self):
+ self.do_xmaton_le_test(force_endianness=True)
+
+
if __name__ == '__main__':
QemuSystemTest.main()
diff --git a/tests/functional/test_microblazeel_s3adsp1800.py b/tests/functional/test_microblazeel_s3adsp1800.py
index faa3927..915902d 100755
--- a/tests/functional/test_microblazeel_s3adsp1800.py
+++ b/tests/functional/test_microblazeel_s3adsp1800.py
@@ -7,36 +7,20 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-import time
-from qemu_test import exec_command, exec_command_and_wait_for_pattern
-from qemu_test import QemuSystemTest, Asset
-from qemu_test import wait_for_console_pattern
-from qemu_test.utils import archive_extract
-
-class MicroblazeelMachine(QemuSystemTest):
-
- timeout = 90
-
- ASSET_IMAGE = Asset(
- ('http://www.qemu-advent-calendar.org/2023/download/day13.tar.gz'),
- 'b9b3d43c5dd79db88ada495cc6e0d1f591153fe41355e925d791fbf44de50c22')
-
- def test_microblazeel_s3adsp1800(self):
- self.require_netdev('user')
- self.set_machine('petalogix-s3adsp1800')
- file_path = self.ASSET_IMAGE.fetch()
- archive_extract(file_path, self.workdir)
- self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir + '/day13/xmaton.bin')
- self.vm.add_args('-nic', 'user,tftp=' + self.workdir + '/day13/')
- self.vm.launch()
- wait_for_console_pattern(self, 'QEMU Advent Calendar 2023')
- time.sleep(0.1)
- exec_command(self, 'root')
- time.sleep(0.1)
- exec_command_and_wait_for_pattern(self,
- 'tftp -g -r xmaton.png 10.0.2.2 ; md5sum xmaton.png',
- '821cd3cab8efd16ad6ee5acc3642a8ea')
+from test_microblaze_s3adsp1800 import MicroblazeMachine
+
+
+class MicroblazeLittleEndianMachine(MicroblazeMachine):
+
+ ASSET_IMAGE_LE = MicroblazeMachine.ASSET_IMAGE_LE
+ ASSET_IMAGE_BE = MicroblazeMachine.ASSET_IMAGE_BE
+
+ def test_microblaze_s3adsp1800_legacy_le(self):
+ self.do_xmaton_le_test()
+
+ def test_microblaze_s3adsp1800_legacy_be(self):
+ self.do_ballerina_be_test(force_endianness=True)
+
if __name__ == '__main__':
- QemuSystemTest.main()
+ MicroblazeMachine.main()
diff --git a/tests/functional/test_migration.py b/tests/functional/test_migration.py
new file mode 100755
index 0000000..c4393c3
--- /dev/null
+++ b/tests/functional/test_migration.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3
+#
+# Migration test
+#
+# Copyright (c) 2019 Red Hat, Inc.
+#
+# Authors:
+# Cleber Rosa <crosa@redhat.com>
+# Caio Carrara <ccarrara@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import tempfile
+import time
+
+from qemu_test import QemuSystemTest, skipIfMissingCommands
+from qemu_test.ports import Ports
+
+
+class MigrationTest(QemuSystemTest):
+
+ timeout = 10
+
+ @staticmethod
+ def migration_finished(vm):
+ return vm.cmd('query-migrate')['status'] in ('completed', 'failed')
+
+ def assert_migration(self, src_vm, dst_vm):
+
+ end = time.monotonic() + self.timeout
+ while time.monotonic() < end and not self.migration_finished(src_vm):
+ time.sleep(0.1)
+
+ end = time.monotonic() + self.timeout
+ while time.monotonic() < end and not self.migration_finished(dst_vm):
+ time.sleep(0.1)
+
+ self.assertEqual(src_vm.cmd('query-migrate')['status'], 'completed')
+ self.assertEqual(dst_vm.cmd('query-migrate')['status'], 'completed')
+ self.assertEqual(dst_vm.cmd('query-status')['status'], 'running')
+ self.assertEqual(src_vm.cmd('query-status')['status'],'postmigrate')
+
+ def select_machine(self):
+ target_machine = {
+ 'aarch64': 'quanta-gsj',
+ 'alpha': 'clipper',
+ 'arm': 'npcm750-evb',
+ 'i386': 'isapc',
+ 'ppc': 'sam460ex',
+ 'ppc64': 'mac99',
+ 'riscv32': 'spike',
+ 'riscv64': 'virt',
+ 'sparc': 'SS-4',
+ 'sparc64': 'sun4u',
+ 'x86_64': 'microvm',
+ }
+ self.set_machine(target_machine[self.arch])
+
+ def do_migrate(self, dest_uri, src_uri=None):
+ self.select_machine()
+ dest_vm = self.get_vm('-incoming', dest_uri, name="dest-qemu")
+ dest_vm.add_args('-nodefaults')
+ dest_vm.launch()
+ if src_uri is None:
+ src_uri = dest_uri
+ source_vm = self.get_vm(name="source-qemu")
+ source_vm.add_args('-nodefaults')
+ source_vm.launch()
+ source_vm.qmp('migrate', uri=src_uri)
+ self.assert_migration(source_vm, dest_vm)
+
+ def _get_free_port(self, ports):
+ port = ports.find_free_port()
+ if port is None:
+ self.skipTest('Failed to find a free port')
+ return port
+
+ def test_migration_with_tcp_localhost(self):
+ with Ports() as ports:
+ dest_uri = 'tcp:localhost:%u' % self._get_free_port(ports)
+ self.do_migrate(dest_uri)
+
+ def test_migration_with_unix(self):
+ with tempfile.TemporaryDirectory(prefix='socket_') as socket_path:
+ dest_uri = 'unix:%s/qemu-test.sock' % socket_path
+ self.do_migrate(dest_uri)
+
+ @skipIfMissingCommands('ncat')
+ def test_migration_with_exec(self):
+ with Ports() as ports:
+ free_port = self._get_free_port(ports)
+ dest_uri = 'exec:ncat -l localhost %u' % free_port
+ src_uri = 'exec:ncat localhost %u' % free_port
+ self.do_migrate(dest_uri, src_uri)
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_mips64_malta.py b/tests/functional/test_mips64_malta.py
new file mode 100755
index 0000000..53c3e0c
--- /dev/null
+++ b/tests/functional/test_mips64_malta.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+#
+# Functional tests for the big-endian 64-bit MIPS Malta board
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+from test_mips_malta import mips_check_wheezy
+
+
+class MaltaMachineConsole(LinuxKernelTest):
+
+ ASSET_WHEEZY_KERNEL = Asset(
+ ('https://people.debian.org/~aurel32/qemu/mips/'
+ 'vmlinux-3.2.0-4-5kc-malta'),
+ '3e4ec154db080b3f1839f04dde83120654a33e5e1716863de576c47cb94f68f6')
+
+ ASSET_WHEEZY_DISK = Asset(
+ ('https://people.debian.org/~aurel32/qemu/mips/'
+ 'debian_wheezy_mips_standard.qcow2'),
+ 'de03599285b8382ad309309a6c4869f6c6c42a5cfc983342bab9ec0dfa7849a2')
+
+ def test_wheezy(self):
+ kernel_path = self.ASSET_WHEEZY_KERNEL.fetch()
+ image_path = self.ASSET_WHEEZY_DISK.fetch()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
+ + 'console=ttyS0 root=/dev/sda1')
+ mips_check_wheezy(self,
+ kernel_path, image_path, kernel_command_line, cpuinfo='MIPS 20Kc',
+ dl_file='/boot/initrd.img-3.2.0-4-5kc-malta',
+ hsum='d98b953bb4a41c0fc0fd8d19bbc691c08989ac52568c1d3054d92dfd890d3f06')
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_mips64_tuxrun.py b/tests/functional/test_mips64_tuxrun.py
new file mode 100755
index 0000000..0e4c659
--- /dev/null
+++ b/tests/functional/test_mips64_tuxrun.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunMips64Test(TuxRunBaselineTest):
+
+ ASSET_MIPS64_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/mips64/vmlinux',
+ 'fe2882d216898ba2c56b49ba59f46ad392f36871f7fe325373cd926848b9dbdc')
+ ASSET_MIPS64_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/mips64/rootfs.ext4.zst',
+ 'b8c98400216b6d4fb3b3ff05e9929aa015948b596cf0b82234813c84a4f7f4d5')
+
+ def test_mips64(self):
+ self.set_machine('malta')
+ self.root="sda"
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_MIPS64_KERNEL,
+ rootfs_asset=self.ASSET_MIPS64_ROOTFS,
+ drive="driver=ide-hd,bus=ide.0,unit=0")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_mips64el_fuloong2e.py b/tests/functional/test_mips64el_fuloong2e.py
index 7688a32..35e500b 100755
--- a/tests/functional/test_mips64el_fuloong2e.py
+++ b/tests/functional/test_mips64el_fuloong2e.py
@@ -12,15 +12,34 @@
import os
import subprocess
-from qemu_test import QemuSystemTest
-from qemu_test import wait_for_console_pattern
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import wait_for_console_pattern, skipUntrustedTest
from unittest import skipUnless
-class MipsFuloong2e(QemuSystemTest):
+class MipsFuloong2e(LinuxKernelTest):
timeout = 60
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ ASSET_KERNEL = Asset(
+ ('http://archive.debian.org/debian/pool/main/l/linux/'
+ 'linux-image-3.16.0-6-loongson-2e_3.16.56-1+deb8u1_mipsel.deb'),
+ '2a70f15b397f4ced632b0c15cb22660394190644146d804d60a4796eefbe1f50')
+
+ def test_linux_kernel_3_16(self):
+ kernel_path = self.archive_extract(
+ self.ASSET_KERNEL,
+ member='boot/vmlinux-3.16.0-6-loongson-2e')
+
+ self.set_machine('fuloong2e')
+ self.vm.set_console()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+
+ @skipUntrustedTest()
@skipUnless(os.getenv('RESCUE_YL_PATH'), 'RESCUE_YL_PATH not available')
def test_linux_kernel_2_6_27_isa_serial(self):
# Recovery system for the Yeeloong laptop
@@ -42,4 +61,4 @@ class MipsFuloong2e(QemuSystemTest):
if __name__ == '__main__':
- QemuSystemTest.main()
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_mips64el_loongson3v.py b/tests/functional/test_mips64el_loongson3v.py
index 55d6292..f85371e 100755
--- a/tests/functional/test_mips64el_loongson3v.py
+++ b/tests/functional/test_mips64el_loongson3v.py
@@ -9,12 +9,9 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
-import time
-
-from unittest import skipUnless
from qemu_test import QemuSystemTest, Asset
-from qemu_test import wait_for_console_pattern
+from qemu_test import wait_for_console_pattern, skipUntrustedTest
+
class MipsLoongson3v(QemuSystemTest):
timeout = 60
@@ -24,7 +21,7 @@ class MipsLoongson3v(QemuSystemTest):
'releases/download/20210112/pmon-3avirt.bin'),
'fcdf6bb2cb7885a4a62f31fcb0d5e368bac7b6cea28f40c6dfa678af22fea20a')
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipUntrustedTest()
def test_pmon_serial_console(self):
self.set_machine('loongson3-virt')
diff --git a/tests/functional/test_mips64el_malta.py b/tests/functional/test_mips64el_malta.py
new file mode 100755
index 0000000..3cc79b7
--- /dev/null
+++ b/tests/functional/test_mips64el_malta.py
@@ -0,0 +1,197 @@
+#!/usr/bin/env python3
+#
+# Functional tests for the little-endian 64-bit MIPS Malta board
+#
+# Copyright (c) Philippe Mathieu-Daudé <f4bug@amsat.org>
+#
+# 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
+
+import os
+import logging
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test import skipIfMissingImports, skipFlakyTest, skipUntrustedTest
+
+from test_mips_malta import mips_check_wheezy
+
+
+class MaltaMachineConsole(LinuxKernelTest):
+
+ ASSET_KERNEL_2_63_2 = Asset(
+ ('http://snapshot.debian.org/archive/debian/'
+ '20130217T032700Z/pool/main/l/linux-2.6/'
+ 'linux-image-2.6.32-5-5kc-malta_2.6.32-48_mipsel.deb'),
+ '35eb476f03be589824b0310358f1c447d85e645b88cbcd2ac02b97ef560f9f8d')
+
+ def test_mips64el_malta(self):
+ """
+ This test requires the ar tool to extract "data.tar.gz" from
+ the Debian package.
+
+ The kernel can be rebuilt using this Debian kernel source [1] and
+ following the instructions on [2].
+
+ [1] http://snapshot.debian.org/package/linux-2.6/2.6.32-48/
+ #linux-source-2.6.32_2.6.32-48
+ [2] https://kernel-team.pages.debian.net/kernel-handbook/
+ ch-common-tasks.html#s-common-official
+ """
+ kernel_path = self.archive_extract(
+ self.ASSET_KERNEL_2_63_2,
+ member='boot/vmlinux-2.6.32-5-5kc-malta')
+
+ self.set_machine('malta')
+ self.vm.set_console()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+
+ ASSET_KERNEL_3_19_3 = Asset(
+ ('https://github.com/philmd/qemu-testing-blob/'
+ 'raw/9ad2df38/mips/malta/mips64el/'
+ 'vmlinux-3.19.3.mtoman.20150408'),
+ '8d3beb003bc66051ead98e7172139017fcf9ce2172576541c57e86418dfa5ab8')
+
+ ASSET_CPIO_R1 = Asset(
+ ('https://github.com/groeck/linux-build-test/'
+ 'raw/8584a59e/rootfs/mipsel64/'
+ 'rootfs.mipsel64r1.cpio.gz'),
+ '75ba10cd35fb44e32948eeb26974f061b703c81c4ba2fab1ebcacf1d1bec3b61')
+
+ @skipUntrustedTest()
+ def test_mips64el_malta_5KEc_cpio(self):
+ kernel_path = self.ASSET_KERNEL_3_19_3.fetch()
+ initrd_path = self.uncompress(self.ASSET_CPIO_R1)
+
+ self.set_machine('malta')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
+ + 'console=ttyS0 console=tty '
+ + 'rdinit=/sbin/init noreboot')
+ self.vm.add_args('-cpu', '5KEc',
+ '-kernel', kernel_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line,
+ '-no-reboot')
+ self.vm.launch()
+ self.wait_for_console_pattern('Boot successful.')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'MIPS 5KE')
+ exec_command_and_wait_for_pattern(self, 'uname -a',
+ '3.19.3.mtoman.20150408')
+ exec_command_and_wait_for_pattern(self, 'reboot',
+ 'reboot: Restarting system')
+ # Wait for VM to shut down gracefully
+ self.vm.wait()
+
+ ASSET_WHEEZY_KERNEL = Asset(
+ ('https://people.debian.org/~aurel32/qemu/mipsel/'
+ 'vmlinux-3.2.0-4-5kc-malta'),
+ '5e8b725244c59745bb8b64f5d8f49f25fecfa549f3395fb6d19a3b9e5065b85b')
+
+ ASSET_WHEEZY_DISK = Asset(
+ ('https://people.debian.org/~aurel32/qemu/mipsel/'
+ 'debian_wheezy_mipsel_standard.qcow2'),
+ '454f09ae39f7e6461c84727b927100d2c7813841f2a0a5dce328114887ecf914')
+
+ def test_wheezy(self):
+ kernel_path = self.ASSET_WHEEZY_KERNEL.fetch()
+ image_path = self.ASSET_WHEEZY_DISK.fetch()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
+ + 'console=ttyS0 root=/dev/sda1')
+ mips_check_wheezy(self,
+ kernel_path, image_path, kernel_command_line, cpuinfo='MIPS 20Kc',
+ dl_file='/boot/initrd.img-3.2.0-4-5kc-malta',
+ hsum='7579f8b56c1187c7c04d0dc3c0c56c7a6314c5ddd3a9bf8803ecc7cf8a3be9f8')
+
+
+@skipIfMissingImports('numpy', 'cv2')
+class MaltaMachineFramebuffer(LinuxKernelTest):
+
+ timeout = 30
+
+ ASSET_KERNEL_4_7_0 = Asset(
+ ('https://github.com/philmd/qemu-testing-blob/raw/a5966ca4b5/'
+ 'mips/malta/mips64el/vmlinux-4.7.0-rc1.I6400.gz'),
+ '1f64efc59968a3c328672e6b10213fe574bb2308d9d2ed44e75e40be59e9fbc2')
+
+ ASSET_TUXLOGO = Asset(
+ ('https://github.com/torvalds/linux/raw/v2.6.12/'
+ 'drivers/video/logo/logo_linux_vga16.ppm'),
+ 'b762f0d91ec018887ad1b334543c2fdf9be9fdfc87672b409211efaa3ea0ef79')
+
+ def do_test_i6400_framebuffer_logo(self, cpu_cores_count):
+ """
+ Boot Linux kernel and check Tux logo is displayed on the framebuffer.
+ """
+
+ import numpy as np
+ import cv2
+
+ screendump_path = self.scratch_file('screendump.pbm')
+
+ kernel_path = self.uncompress(self.ASSET_KERNEL_4_7_0)
+
+ tuxlogo_path = self.ASSET_TUXLOGO.fetch()
+
+ self.set_machine('malta')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'clocksource=GIC console=tty0 console=ttyS0')
+ self.vm.add_args('-kernel', kernel_path,
+ '-cpu', 'I6400',
+ '-smp', '%u' % cpu_cores_count,
+ '-vga', 'std',
+ '-append', kernel_command_line)
+ self.vm.launch()
+ framebuffer_ready = 'Console: switching to colour frame buffer device'
+ self.wait_for_console_pattern(framebuffer_ready)
+ self.vm.cmd('human-monitor-command', command_line='stop')
+ res = self.vm.cmd('human-monitor-command',
+ command_line='screendump %s' % screendump_path)
+ if 'unknown command' in res:
+ self.skipTest('screendump not available')
+ logger = logging.getLogger('framebuffer')
+
+ match_threshold = 0.95
+ screendump_bgr = cv2.imread(screendump_path, cv2.IMREAD_COLOR)
+ tuxlogo_bgr = cv2.imread(tuxlogo_path, cv2.IMREAD_COLOR)
+ result = cv2.matchTemplate(screendump_bgr, tuxlogo_bgr,
+ cv2.TM_CCOEFF_NORMED)
+ loc = np.where(result >= match_threshold)
+ tuxlogo_count = 0
+ h, w = tuxlogo_bgr.shape[:2]
+ debug_png = os.getenv('QEMU_TEST_CV2_SCREENDUMP_PNG_PATH')
+ for tuxlogo_count, pt in enumerate(zip(*loc[::-1]), start=1):
+ logger.debug('found Tux at position (x, y) = %s', pt)
+ cv2.rectangle(screendump_bgr, pt,
+ (pt[0] + w, pt[1] + h), (0, 0, 255), 2)
+ if debug_png:
+ cv2.imwrite(debug_png, screendump_bgr)
+ self.assertGreaterEqual(tuxlogo_count, cpu_cores_count)
+
+ def test_mips_malta_i6400_framebuffer_logo_1core(self):
+ self.do_test_i6400_framebuffer_logo(1)
+
+ # XXX file tracking bug
+ @skipFlakyTest(bug_url=None)
+ def test_mips_malta_i6400_framebuffer_logo_7cores(self):
+ self.do_test_i6400_framebuffer_logo(7)
+
+ @skipFlakyTest(bug_url=None)
+ def test_mips_malta_i6400_framebuffer_logo_8cores(self):
+ self.do_test_i6400_framebuffer_logo(8)
+
+
+from test_mipsel_malta import MaltaMachineYAMON
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_mips64el_replay.py b/tests/functional/test_mips64el_replay.py
new file mode 100755
index 0000000..26a6ccf
--- /dev/null
+++ b/tests/functional/test_mips64el_replay.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+#
+# Replay tests for the little-endian 64-bit MIPS Malta board
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset, skipUntrustedTest
+from replay_kernel import ReplayKernelBase
+
+
+class Mips64elReplay(ReplayKernelBase):
+
+ ASSET_KERNEL_2_63_2 = Asset(
+ ('http://snapshot.debian.org/archive/debian/'
+ '20130217T032700Z/pool/main/l/linux-2.6/'
+ 'linux-image-2.6.32-5-5kc-malta_2.6.32-48_mipsel.deb'),
+ '35eb476f03be589824b0310358f1c447d85e645b88cbcd2ac02b97ef560f9f8d')
+
+ def test_replay_mips64el_malta(self):
+ self.set_machine('malta')
+ kernel_path = self.archive_extract(self.ASSET_KERNEL_2_63_2,
+ member='boot/vmlinux-2.6.32-5-5kc-malta')
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
+
+
+ ASSET_KERNEL_3_19_3 = Asset(
+ ('https://github.com/philmd/qemu-testing-blob/'
+ 'raw/9ad2df38/mips/malta/mips64el/'
+ 'vmlinux-3.19.3.mtoman.20150408'),
+ '8d3beb003bc66051ead98e7172139017fcf9ce2172576541c57e86418dfa5ab8')
+
+ ASSET_CPIO_R1 = Asset(
+ ('https://github.com/groeck/linux-build-test/'
+ 'raw/8584a59e/rootfs/mipsel64/'
+ 'rootfs.mipsel64r1.cpio.gz'),
+ '75ba10cd35fb44e32948eeb26974f061b703c81c4ba2fab1ebcacf1d1bec3b61')
+
+ @skipUntrustedTest()
+ def test_replay_mips64el_malta_5KEc_cpio(self):
+ self.set_machine('malta')
+ self.cpu = '5KEc'
+ kernel_path = self.ASSET_KERNEL_3_19_3.fetch()
+ initrd_path = self.uncompress(self.ASSET_CPIO_R1)
+
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0 console=tty '
+ 'rdinit=/sbin/init noreboot')
+ console_pattern = 'Boot successful.'
+ self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5,
+ args=('-initrd', initrd_path))
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_mips64el_tuxrun.py b/tests/functional/test_mips64el_tuxrun.py
new file mode 100755
index 0000000..0a24757
--- /dev/null
+++ b/tests/functional/test_mips64el_tuxrun.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunMips64ELTest(TuxRunBaselineTest):
+
+ ASSET_MIPS64EL_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/mips64el/vmlinux',
+ '0d2829a96f005229839c4cd586d4d8a136ea4b488d29821611c8e97f2266bfa9')
+ ASSET_MIPS64EL_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/mips64el/rootfs.ext4.zst',
+ '69c8b69a4f1582ce4c6f01a994968f5d73bffb2fc99cbeeeb26c8b5a28eaeb84')
+
+ def test_mips64el(self):
+ self.set_machine('malta')
+ self.root="sda"
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_MIPS64EL_KERNEL,
+ rootfs_asset=self.ASSET_MIPS64EL_ROOTFS,
+ drive="driver=ide-hd,bus=ide.0,unit=0")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_mips_malta.py b/tests/functional/test_mips_malta.py
new file mode 100755
index 0000000..30279f0
--- /dev/null
+++ b/tests/functional/test_mips_malta.py
@@ -0,0 +1,196 @@
+#!/usr/bin/env python3
+#
+# Functional tests for the big-endian 32-bit MIPS Malta board
+#
+# Copyright (c) Philippe Mathieu-Daudé <f4bug@amsat.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import LinuxKernelTest, Asset, wait_for_console_pattern
+from qemu_test import exec_command_and_wait_for_pattern
+
+
+def mips_run_common_commands(test, prompt='#'):
+ exec_command_and_wait_for_pattern(test,
+ 'uname -m',
+ 'mips')
+ exec_command_and_wait_for_pattern(test,
+ 'grep XT-PIC /proc/interrupts',
+ 'timer')
+ wait_for_console_pattern(test, prompt)
+ exec_command_and_wait_for_pattern(test,
+ 'grep XT-PIC /proc/interrupts',
+ 'serial')
+ wait_for_console_pattern(test, prompt)
+ exec_command_and_wait_for_pattern(test,
+ 'grep XT-PIC /proc/interrupts',
+ 'ata_piix')
+ wait_for_console_pattern(test, prompt)
+ exec_command_and_wait_for_pattern(test,
+ 'grep XT-PIC /proc/interrupts',
+ 'rtc')
+ wait_for_console_pattern(test, prompt)
+ exec_command_and_wait_for_pattern(test,
+ 'cat /proc/devices',
+ 'input')
+ wait_for_console_pattern(test, prompt)
+ exec_command_and_wait_for_pattern(test,
+ 'cat /proc/devices',
+ 'fb')
+ wait_for_console_pattern(test, prompt)
+ exec_command_and_wait_for_pattern(test,
+ 'cat /proc/ioports',
+ ' : serial')
+ wait_for_console_pattern(test, prompt)
+ exec_command_and_wait_for_pattern(test,
+ 'cat /proc/ioports',
+ ' : ata_piix')
+ wait_for_console_pattern(test, prompt)
+
+def mips_check_wheezy(test, kernel_path, image_path, kernel_command_line,
+ dl_file, hsum, nic='pcnet', cpuinfo='MIPS 24Kc'):
+ test.require_netdev('user')
+ test.require_device(nic)
+ test.set_machine('malta')
+
+ port=8080
+ test.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line,
+ '-drive', 'file=%s,snapshot=on' % image_path,
+ '-netdev', 'user,id=n1' +
+ ',tftp=' + os.path.basename(kernel_path) +
+ ',hostfwd=tcp:127.0.0.1:0-:%d' % port,
+ '-device', f'{nic},netdev=n1',
+ '-no-reboot')
+ test.vm.set_console()
+ test.vm.launch()
+
+ wait_for_console_pattern(test, 'login: ', 'Oops')
+ exec_command_and_wait_for_pattern(test, 'root', 'Password:')
+ exec_command_and_wait_for_pattern(test, 'root', ':~# ')
+ mips_run_common_commands(test)
+
+ exec_command_and_wait_for_pattern(test, 'cd /', '# ')
+ test.check_http_download(dl_file, hsum, port,
+ pythoncmd='python -m SimpleHTTPServer')
+
+ exec_command_and_wait_for_pattern(test, 'cat /proc/cpuinfo', cpuinfo)
+ exec_command_and_wait_for_pattern(test, 'cat /proc/devices', 'usb')
+ exec_command_and_wait_for_pattern(test, 'cat /proc/ioports',
+ ' : piix4_smbus')
+ exec_command_and_wait_for_pattern(test, 'lspci -d 11ab:4620',
+ 'GT-64120')
+ exec_command_and_wait_for_pattern(test,
+ 'cat /sys/bus/i2c/devices/i2c-0/name',
+ 'SMBus PIIX4 adapter')
+ exec_command_and_wait_for_pattern(test, 'cat /proc/mtd', 'YAMON')
+ # Empty 'Board Config' (64KB)
+ exec_command_and_wait_for_pattern(test, 'md5sum /dev/mtd2ro',
+ '0dfbe8aa4c20b52e1b8bf3cb6cbdf193')
+
+
+class MaltaMachineConsole(LinuxKernelTest):
+
+ ASSET_KERNEL_2_63_2 = Asset(
+ ('http://snapshot.debian.org/archive/debian/'
+ '20130217T032700Z/pool/main/l/linux-2.6/'
+ 'linux-image-2.6.32-5-4kc-malta_2.6.32-48_mips.deb'),
+ '16ca524148afb0626f483163e5edf352bc1ab0e4fc7b9f9d473252762f2c7a43')
+
+ def test_mips_malta(self):
+ kernel_path = self.archive_extract(
+ self.ASSET_KERNEL_2_63_2,
+ member='boot/vmlinux-2.6.32-5-4kc-malta')
+
+ self.set_machine('malta')
+ self.vm.set_console()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+
+ ASSET_KERNEL_4_5_0 = Asset(
+ ('http://snapshot.debian.org/archive/debian/'
+ '20160601T041800Z/pool/main/l/linux/'
+ 'linux-image-4.5.0-2-4kc-malta_4.5.5-1_mips.deb'),
+ '526b17d5889840888b76fc2c36a0ebde182c9b1410a3a1e68203c3b160eb2027')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/groeck/linux-build-test/raw/'
+ '8584a59ed9e5eb5ee7ca91f6d74bbb06619205b8/rootfs/'
+ 'mips/rootfs.cpio.gz'),
+ 'dcfe3a7fe3200da3a00d176b95caaa086495eb158f2bff64afc67d7e1eb2cddc')
+
+ def test_mips_malta_cpio(self):
+ self.require_netdev('user')
+ self.set_machine('malta')
+ self.require_device('pcnet')
+
+ kernel_path = self.archive_extract(
+ self.ASSET_KERNEL_4_5_0,
+ member='boot/vmlinux-4.5.0-2-4kc-malta')
+ initrd_path = self.uncompress(self.ASSET_INITRD)
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
+ + 'console=ttyS0 console=tty '
+ + 'rdinit=/sbin/init noreboot')
+ self.vm.add_args('-kernel', kernel_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line,
+ '-netdev', 'user,id=n1,tftp=' + self.scratch_file('boot'),
+ '-device', 'pcnet,netdev=n1',
+ '-no-reboot')
+ self.vm.launch()
+ self.wait_for_console_pattern('Boot successful.')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'BogoMIPS')
+ exec_command_and_wait_for_pattern(self, 'uname -a',
+ '4.5.0-2-4kc-malta #1 Debian')
+ mips_run_common_commands(self)
+
+ exec_command_and_wait_for_pattern(self, 'ip link set eth0 up',
+ 'eth0: link up')
+ exec_command_and_wait_for_pattern(self,
+ 'ip addr add 10.0.2.15 dev eth0',
+ '#')
+ exec_command_and_wait_for_pattern(self, 'route add default eth0', '#')
+ exec_command_and_wait_for_pattern(self,
+ 'tftp -g -r vmlinux-4.5.0-2-4kc-malta 10.0.2.2', '#')
+ exec_command_and_wait_for_pattern(self,
+ 'md5sum vmlinux-4.5.0-2-4kc-malta',
+ 'a98218a7efbdefb2dfdf9ecd08c98318')
+
+ exec_command_and_wait_for_pattern(self, 'reboot',
+ 'reboot: Restarting system')
+ # Wait for VM to shut down gracefully
+ self.vm.wait()
+
+ ASSET_WHEEZY_KERNEL = Asset(
+ ('https://people.debian.org/~aurel32/qemu/mips/'
+ 'vmlinux-3.2.0-4-4kc-malta'),
+ '0377fcda31299213c10b8e5babe7260ef99188b3ae1aca6f56594abb71e7f67e')
+
+ ASSET_WHEEZY_DISK = Asset(
+ ('https://people.debian.org/~aurel32/qemu/mips/'
+ 'debian_wheezy_mips_standard.qcow2'),
+ 'de03599285b8382ad309309a6c4869f6c6c42a5cfc983342bab9ec0dfa7849a2')
+
+ def test_wheezy(self):
+ kernel_path = self.ASSET_WHEEZY_KERNEL.fetch()
+ image_path = self.ASSET_WHEEZY_DISK.fetch()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
+ + 'console=ttyS0 root=/dev/sda1')
+ mips_check_wheezy(self,
+ kernel_path, image_path, kernel_command_line, nic='e1000',
+ dl_file='/boot/initrd.img-3.2.0-4-4kc-malta',
+ hsum='ff0c0369143d9bbb9a6e6bc79322a2be535619df639e84103237f406e87493dc')
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_mips_replay.py b/tests/functional/test_mips_replay.py
new file mode 100755
index 0000000..4327481
--- /dev/null
+++ b/tests/functional/test_mips_replay.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+#
+# Replay tests for the big-endian 32-bit MIPS Malta board
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset, skipSlowTest
+from replay_kernel import ReplayKernelBase
+
+
+class MipsReplay(ReplayKernelBase):
+
+ ASSET_KERNEL_2_63_2 = Asset(
+ ('http://snapshot.debian.org/archive/debian/'
+ '20130217T032700Z/pool/main/l/linux-2.6/'
+ 'linux-image-2.6.32-5-4kc-malta_2.6.32-48_mips.deb'),
+ '16ca524148afb0626f483163e5edf352bc1ab0e4fc7b9f9d473252762f2c7a43')
+
+ def test_replay_mips_malta(self):
+ self.set_machine('malta')
+ kernel_path = self.archive_extract(self.ASSET_KERNEL_2_63_2,
+ member='boot/vmlinux-2.6.32-5-4kc-malta')
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
+
+ ASSET_KERNEL_4_5_0 = Asset(
+ ('http://snapshot.debian.org/archive/debian/'
+ '20160601T041800Z/pool/main/l/linux/'
+ 'linux-image-4.5.0-2-4kc-malta_4.5.5-1_mips.deb'),
+ '526b17d5889840888b76fc2c36a0ebde182c9b1410a3a1e68203c3b160eb2027')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/groeck/linux-build-test/raw/'
+ '8584a59ed9e5eb5ee7ca91f6d74bbb06619205b8/rootfs/'
+ 'mips/rootfs.cpio.gz'),
+ 'dcfe3a7fe3200da3a00d176b95caaa086495eb158f2bff64afc67d7e1eb2cddc')
+
+ @skipSlowTest()
+ def test_replay_mips_malta_cpio(self):
+ self.set_machine('malta')
+ kernel_path = self.archive_extract(self.ASSET_KERNEL_4_5_0,
+ member='boot/vmlinux-4.5.0-2-4kc-malta')
+ initrd_path = self.uncompress(self.ASSET_INITRD)
+
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0 console=tty '
+ 'rdinit=/sbin/init noreboot')
+ console_pattern = 'Boot successful.'
+ self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5,
+ args=('-initrd', initrd_path))
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_mips_tuxrun.py b/tests/functional/test_mips_tuxrun.py
new file mode 100755
index 0000000..6771dbd
--- /dev/null
+++ b/tests/functional/test_mips_tuxrun.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunMipsTest(TuxRunBaselineTest):
+
+ ASSET_MIPS_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/mips32/vmlinux',
+ 'b6f97fc698ae8c96456ad8c996c7454228074df0d7520dedd0a15e2913700a19')
+ ASSET_MIPS_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/mips32/rootfs.ext4.zst',
+ '87055cf3cbde3fd134e5039e7b87feb03231d8c4b21ee712b8ba3308dfa72f50')
+
+ def test_mips32(self):
+ self.set_machine('malta')
+ self.cpu="mips32r6-generic"
+ self.root="sda"
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_MIPS_KERNEL,
+ rootfs_asset=self.ASSET_MIPS_ROOTFS,
+ drive="driver=ide-hd,bus=ide.0,unit=0")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_mipsel_malta.py b/tests/functional/test_mipsel_malta.py
new file mode 100755
index 0000000..9ee2884
--- /dev/null
+++ b/tests/functional/test_mipsel_malta.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python3
+#
+# Functional tests for the little-endian 32-bit MIPS Malta board
+#
+# Copyright (c) Philippe Mathieu-Daudé <f4bug@amsat.org>
+#
+# 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
+
+from qemu_test import QemuSystemTest, LinuxKernelTest, Asset
+from qemu_test import interrupt_interactive_console_until_pattern
+from qemu_test import wait_for_console_pattern
+
+from test_mips_malta import mips_check_wheezy
+
+
+class MaltaMachineConsole(LinuxKernelTest):
+
+ ASSET_KERNEL_4K = Asset(
+ ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
+ 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
+ 'generic_nano32r6el_page4k.xz'),
+ '019e034094ac6cf3aa77df5e130fb023ce4dbc804b04bfcc560c6403e1ae6bdb')
+ ASSET_KERNEL_16K = Asset(
+ ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
+ 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
+ 'generic_nano32r6el_page16k_up.xz'),
+ '3a54a10b3108c16a448dca9ea3db378733a27423befc2a45a5bdf990bd85e12c')
+ ASSET_KERNEL_64K = Asset(
+ ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
+ 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
+ 'generic_nano32r6el_page64k_dbg.xz'),
+ 'ce21ff4b07a981ecb8a39db2876616f5a2473eb2ab459c6f67465b9914b0c6b6')
+
+ def do_test_mips_malta32el_nanomips(self, kernel):
+ kernel_path = self.uncompress(kernel)
+
+ self.set_machine('malta')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
+ + 'mem=256m@@0x0 '
+ + 'console=ttyS0')
+ self.vm.add_args('-cpu', 'I7200',
+ '-no-reboot',
+ '-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+
+ def test_mips_malta32el_nanomips_4k(self):
+ self.do_test_mips_malta32el_nanomips(self.ASSET_KERNEL_4K)
+
+ def test_mips_malta32el_nanomips_16k_up(self):
+ self.do_test_mips_malta32el_nanomips(self.ASSET_KERNEL_16K)
+
+ def test_mips_malta32el_nanomips_64k_dbg(self):
+ self.do_test_mips_malta32el_nanomips(self.ASSET_KERNEL_64K)
+
+ ASSET_WHEEZY_KERNEL = Asset(
+ ('https://people.debian.org/~aurel32/qemu/mipsel/'
+ 'vmlinux-3.2.0-4-4kc-malta'),
+ 'dc8a3648305b0201ca7a5cd135fe2890067a65d93c38728022bb0e656ad2bf9a')
+
+ ASSET_WHEEZY_DISK = Asset(
+ ('https://people.debian.org/~aurel32/qemu/mipsel/'
+ 'debian_wheezy_mipsel_standard.qcow2'),
+ '454f09ae39f7e6461c84727b927100d2c7813841f2a0a5dce328114887ecf914')
+
+ def test_wheezy(self):
+ kernel_path = self.ASSET_WHEEZY_KERNEL.fetch()
+ image_path = self.ASSET_WHEEZY_DISK.fetch()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
+ + 'console=ttyS0 root=/dev/sda1')
+ mips_check_wheezy(self,
+ kernel_path, image_path, kernel_command_line,
+ dl_file='/boot/initrd.img-3.2.0-4-4kc-malta',
+ hsum='9fc9f250ed56a74e35e704ddfd5a1c5a5625adefc5c9da91f649288d3ca000f0')
+
+
+class MaltaMachineYAMON(QemuSystemTest):
+
+ ASSET_YAMON_ROM = Asset(
+ ('https://s3-eu-west-1.amazonaws.com/downloads-mips/mips-downloads/'
+ 'YAMON/yamon-bin-02.22.zip'),
+ 'eef86f0eed0ef554f041dcd47b87eebea0e6f9f1184ed31f7e9e8b4a803860ab')
+
+ def test_mipsel_malta_yamon(self):
+ yamon_bin = 'yamon-02.22.bin'
+ self.archive_extract(self.ASSET_YAMON_ROM)
+ yamon_path = self.scratch_file(yamon_bin)
+
+ self.set_machine('malta')
+ self.vm.set_console()
+ self.vm.add_args('-bios', yamon_path)
+ self.vm.launch()
+
+ prompt = 'YAMON>'
+ pattern = 'YAMON ROM Monitor'
+ interrupt_interactive_console_until_pattern(self, pattern, prompt)
+ wait_for_console_pattern(self, prompt)
+ self.vm.shutdown()
+
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_mipsel_replay.py b/tests/functional/test_mipsel_replay.py
new file mode 100644
index 0000000..5f4796c
--- /dev/null
+++ b/tests/functional/test_mipsel_replay.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+#
+# Replay tests for the little-endian 32-bit MIPS Malta board
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset, skipSlowTest
+from replay_kernel import ReplayKernelBase
+
+
+class MipselReplay(ReplayKernelBase):
+
+ ASSET_KERNEL_4K = Asset(
+ ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
+ 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
+ 'generic_nano32r6el_page4k.xz'),
+ '019e034094ac6cf3aa77df5e130fb023ce4dbc804b04bfcc560c6403e1ae6bdb')
+ ASSET_KERNEL_16K = Asset(
+ ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
+ 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
+ 'generic_nano32r6el_page16k_up.xz'),
+ '3a54a10b3108c16a448dca9ea3db378733a27423befc2a45a5bdf990bd85e12c')
+ ASSET_KERNEL_64K = Asset(
+ ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
+ 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
+ 'generic_nano32r6el_page64k_dbg.xz'),
+ 'ce21ff4b07a981ecb8a39db2876616f5a2473eb2ab459c6f67465b9914b0c6b6')
+
+ def do_test_replay_mips_malta32el_nanomips(self, kernel_asset):
+ self.set_machine('malta')
+ self.cpu = 'I7200'
+ kernel_path = self.uncompress(kernel_asset)
+
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'mem=256m@@0x0 '
+ 'console=ttyS0')
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
+
+ @skipSlowTest()
+ def test_replay_mips_malta32el_nanomips_4k(self):
+ self.do_test_replay_mips_malta32el_nanomips(self.ASSET_KERNEL_4K)
+
+ @skipSlowTest()
+ def test_replay_mips_malta32el_nanomips_16k_up(self):
+ self.do_test_replay_mips_malta32el_nanomips(self.ASSET_KERNEL_16K)
+
+ @skipSlowTest()
+ def test_replay_mips_malta32el_nanomips_64k_dbg(self):
+ self.do_test_replay_mips_malta32el_nanomips(self.ASSET_KERNEL_64K)
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_mipsel_tuxrun.py b/tests/functional/test_mipsel_tuxrun.py
new file mode 100755
index 0000000..d4b39ba
--- /dev/null
+++ b/tests/functional/test_mipsel_tuxrun.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunMipsELTest(TuxRunBaselineTest):
+
+ ASSET_MIPSEL_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/mips32el/vmlinux',
+ '660dd8c7a6ca7a32d37b4e6348865532ab0edb66802e8cc07869338444cf4929')
+ ASSET_MIPSEL_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/mips32el/rootfs.ext4.zst',
+ 'c5d69542bcaed54a4f34671671eb4be5c608ee02671d4d0436544367816a73b1')
+
+ def test_mips32el(self):
+ self.set_machine('malta')
+ self.cpu="mips32r6-generic"
+ self.root="sda"
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_MIPSEL_KERNEL,
+ rootfs_asset=self.ASSET_MIPSEL_ROOTFS,
+ drive="driver=ide-hd,bus=ide.0,unit=0")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_multiprocess.py b/tests/functional/test_multiprocess.py
new file mode 100755
index 0000000..751cf10
--- /dev/null
+++ b/tests/functional/test_multiprocess.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+#
+# Test for multiprocess qemu
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+
+import os
+import socket
+
+from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern
+from qemu_test import exec_command, exec_command_and_wait_for_pattern
+
+class Multiprocess(QemuSystemTest):
+
+ KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
+
+ ASSET_KERNEL_X86 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux'
+ '/releases/31/Everything/x86_64/os/images/pxeboot/vmlinuz'),
+ 'd4738d03dbbe083ca610d0821d0a8f1488bebbdccef54ce33e3adb35fda00129')
+
+ ASSET_INITRD_X86 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux'
+ '/releases/31/Everything/x86_64/os/images/pxeboot/initrd.img'),
+ '3b6cb5c91a14c42e2f61520f1689264d865e772a1f0069e660a800d31dd61fb9')
+
+ ASSET_KERNEL_AARCH64 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux'
+ '/releases/31/Everything/aarch64/os/images/pxeboot/vmlinuz'),
+ '3ae07fcafbfc8e4abeb693035a74fe10698faae15e9ccd48882a9167800c1527')
+
+ ASSET_INITRD_AARCH64 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux'
+ '/releases/31/Everything/aarch64/os/images/pxeboot/initrd.img'),
+ '9fd230cab10b1dafea41cf00150e6669d37051fad133bd618d2130284e16d526')
+
+ def do_test(self, kernel_asset, initrd_asset,
+ kernel_command_line, machine_type):
+ """Main test method"""
+ self.require_accelerator('kvm')
+ self.require_device('x-pci-proxy-dev')
+
+ # Create socketpair to connect proxy and remote processes
+ proxy_sock, remote_sock = socket.socketpair(socket.AF_UNIX,
+ socket.SOCK_STREAM)
+ os.set_inheritable(proxy_sock.fileno(), True)
+ os.set_inheritable(remote_sock.fileno(), True)
+
+ kernel_path = kernel_asset.fetch()
+ initrd_path = initrd_asset.fetch()
+
+ # Create remote process
+ remote_vm = self.get_vm()
+ remote_vm.add_args('-machine', 'x-remote')
+ remote_vm.add_args('-nodefaults')
+ remote_vm.add_args('-device', 'lsi53c895a,id=lsi1')
+ remote_vm.add_args('-object', 'x-remote-object,id=robj1,'
+ 'devid=lsi1,fd='+str(remote_sock.fileno()))
+ remote_vm.launch()
+
+ # Create proxy process
+ self.vm.set_console()
+ self.vm.add_args('-machine', machine_type)
+ self.vm.add_args('-accel', 'kvm')
+ self.vm.add_args('-cpu', 'host')
+ self.vm.add_args('-object',
+ 'memory-backend-memfd,id=sysmem-file,size=2G')
+ self.vm.add_args('--numa', 'node,memdev=sysmem-file')
+ self.vm.add_args('-m', '2048')
+ self.vm.add_args('-kernel', kernel_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line)
+ self.vm.add_args('-device',
+ 'x-pci-proxy-dev,'
+ 'id=lsi1,fd='+str(proxy_sock.fileno()))
+ self.vm.launch()
+ wait_for_console_pattern(self, 'as init process',
+ 'Kernel panic - not syncing')
+ exec_command(self, 'mount -t sysfs sysfs /sys')
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/bus/pci/devices/*/uevent',
+ 'PCI_ID=1000:0012')
+
+ def test_multiprocess(self):
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE
+ if self.arch == 'x86_64':
+ kernel_command_line += 'console=ttyS0 rdinit=/bin/bash'
+ self.do_test(self.ASSET_KERNEL_X86, self.ASSET_INITRD_X86,
+ kernel_command_line, 'pc')
+ elif self.arch == 'aarch64':
+ kernel_command_line += 'rdinit=/bin/bash console=ttyAMA0'
+ self.do_test(self.ASSET_KERNEL_AARCH64, self.ASSET_INITRD_AARCH64,
+ kernel_command_line, 'virt,gic-version=3')
+ else:
+ assert False
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_netdev_ethtool.py b/tests/functional/test_netdev_ethtool.py
index d5b911c..ee1a397 100755
--- a/tests/functional/test_netdev_ethtool.py
+++ b/tests/functional/test_netdev_ethtool.py
@@ -5,7 +5,7 @@
# This test leverages ethtool's --test sequence to validate network
# device behaviour.
#
-# SPDX-License-Identifier: GPL-2.0-or-late
+# SPDX-License-Identifier: GPL-2.0-or-later
from unittest import skip
from qemu_test import QemuSystemTest, Asset
diff --git a/tests/functional/test_or1k_replay.py b/tests/functional/test_or1k_replay.py
new file mode 100755
index 0000000..2b60a93
--- /dev/null
+++ b/tests/functional/test_or1k_replay.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+#
+# Replay test that boots a Linux kernel on an OpenRISC-1000 SIM machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from replay_kernel import ReplayKernelBase
+
+
+class Or1kReplay(ReplayKernelBase):
+
+ ASSET_DAY20 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day20.tar.xz',
+ 'ff9d7dd7c6bdba325bd85ee85c02db61ff653e129558aeffe6aff55bffb6763a')
+
+ def test_sim(self):
+ self.set_machine('or1k-sim')
+ kernel_path = self.archive_extract(self.ASSET_DAY20,
+ member='day20/vmlinux')
+ self.run_rr(kernel_path, self.REPLAY_KERNEL_COMMAND_LINE,
+ 'QEMU advent calendar')
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_or1k_sim.py b/tests/functional/test_or1k_sim.py
new file mode 100755
index 0000000..f9f0b69
--- /dev/null
+++ b/tests/functional/test_or1k_sim.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on an OpenRISC-1000 SIM machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class OpenRISC1kSimTest(LinuxKernelTest):
+
+ ASSET_DAY20 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day20.tar.xz',
+ 'ff9d7dd7c6bdba325bd85ee85c02db61ff653e129558aeffe6aff55bffb6763a')
+
+ def test_or1k_sim(self):
+ self.set_machine('or1k-sim')
+ self.archive_extract(self.ASSET_DAY20)
+ self.vm.set_console()
+ self.vm.add_args('-kernel', self.scratch_file('day20', 'vmlinux'))
+ self.vm.launch()
+ self.wait_for_console_pattern('QEMU advent calendar')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_pc_cpu_hotplug_props.py b/tests/functional/test_pc_cpu_hotplug_props.py
index 9d5a37c..2bed8ad 100755
--- a/tests/functional/test_pc_cpu_hotplug_props.py
+++ b/tests/functional/test_pc_cpu_hotplug_props.py
@@ -26,6 +26,7 @@ from qemu_test import QemuSystemTest
class OmittedCPUProps(QemuSystemTest):
def test_no_die_id(self):
+ self.set_machine('pc')
self.vm.add_args('-nodefaults', '-S')
self.vm.add_args('-smp', '1,sockets=2,cores=2,threads=2,maxcpus=8')
self.vm.add_args('-device', 'qemu64-x86_64-cpu,socket-id=1,core-id=0,thread-id=0')
diff --git a/tests/functional/test_ppc64_e500.py b/tests/functional/test_ppc64_e500.py
new file mode 100755
index 0000000..f5fcad9
--- /dev/null
+++ b/tests/functional/test_ppc64_e500.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+#
+# Boot a Linux kernel on a e500 ppc64 machine and check the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+
+
+class E500Test(LinuxKernelTest):
+
+ ASSET_BR2_E5500_UIMAGE = Asset(
+ 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/buildroot/qemu_ppc64_e5500-2023.11-8-gdcd9f0f6eb-20240104/uImage',
+ '2478187c455d6cca3984e9dfde9c635d824ea16236b85fd6b4809f744706deda')
+
+ ASSET_BR2_E5500_ROOTFS = Asset(
+ 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main//buildroot/qemu_ppc64_e5500-2023.11-8-gdcd9f0f6eb-20240104/rootfs.ext2',
+ '9035ef97237c84c7522baaff17d25cdfca4bb7a053d5e296e902919473423d76')
+
+ def test_ppc64_e500_buildroot(self):
+ self.set_machine('ppce500')
+ self.require_netdev('user')
+ self.cpu = 'e5500'
+
+ uimage_path = self.ASSET_BR2_E5500_UIMAGE.fetch()
+ rootfs_path = self.ASSET_BR2_E5500_ROOTFS.fetch()
+
+ self.vm.set_console()
+ self.vm.add_args('-kernel', uimage_path,
+ '-append', 'root=/dev/vda',
+ '-drive', f'file={rootfs_path},if=virtio,format=raw',
+ '-snapshot', '-no-shutdown')
+ self.vm.launch()
+
+ self.wait_for_console_pattern('Linux version')
+ self.wait_for_console_pattern('/init as init process')
+ self.wait_for_console_pattern('lease of 10.0.2.15')
+ self.wait_for_console_pattern('buildroot login:')
+ exec_command_and_wait_for_pattern(self, 'root', '#')
+ exec_command_and_wait_for_pattern(self, 'poweroff', 'Power down')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_ppc64_hv.py b/tests/functional/test_ppc64_hv.py
index 1a6e4b6..d87f440 100755
--- a/tests/functional/test_ppc64_hv.py
+++ b/tests/functional/test_ppc64_hv.py
@@ -9,34 +9,14 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from unittest import skipIf, skipUnless
-from qemu_test import QemuSystemTest, Asset
-from qemu_test import wait_for_console_pattern, exec_command
import os
-import time
import subprocess
-from datetime import datetime
-deps = ["xorriso"] # dependent tools needed in the test setup/box.
-
-def which(tool):
- """ looks up the full path for @tool, returns None if not found
- or if @tool does not have executable permissions.
- """
- paths=os.getenv('PATH')
- for p in paths.split(os.path.pathsep):
- p = os.path.join(p, tool)
- if os.path.exists(p) and os.access(p, os.X_OK):
- return p
- return None
-
-def missing_deps():
- """ returns True if any of the test dependent tools are absent.
- """
- for dep in deps:
- if which(dep) is None:
- return True
- return False
+from datetime import datetime
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern, exec_command
+from qemu_test import skipIfMissingCommands, skipBigDataTest
+from qemu_test import exec_command_and_wait_for_pattern
# Alpine is a light weight distro that supports QEMU. These tests boot
# that on the machine then run a QEMU guest inside it in KVM mode,
@@ -45,8 +25,8 @@ def missing_deps():
# large download, but it may be more polite to create qcow2 image with
# QEMU already installed and use that.
# XXX: The order of these tests seems to matter, see git blame.
-@skipIf(missing_deps(), 'dependencies (%s) not installed' % ','.join(deps))
-@skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), 'storage limited')
+@skipIfMissingCommands("xorriso")
+@skipBigDataTest()
class HypervisorTest(QemuSystemTest):
timeout = 1000
@@ -55,9 +35,9 @@ class HypervisorTest(QemuSystemTest):
good_message = 'VFS: Cannot open root device'
ASSET_ISO = Asset(
- ('https://dl-cdn.alpinelinux.org/alpine/v3.18/'
- 'releases/ppc64le/alpine-standard-3.18.4-ppc64le.iso'),
- 'c26b8d3e17c2f3f0fed02b4b1296589c2390e6d5548610099af75300edd7b3ff')
+ ('https://dl-cdn.alpinelinux.org/alpine/v3.21/'
+ 'releases/ppc64le/alpine-standard-3.21.0-ppc64le.iso'),
+ '7651ab4e3027604535c0b36e86c901b4695bf8fe97b908f5b48590f6baae8f30')
def extract_from_iso(self, iso, path):
"""
@@ -67,24 +47,15 @@ class HypervisorTest(QemuSystemTest):
:param path: path within the iso file of the file to be extracted
:returns: path of the extracted file
"""
- filename = os.path.basename(path)
+ filename = self.scratch_file(os.path.basename(path))
- cwd = os.getcwd()
- os.chdir(self.workdir)
-
- with open(filename, "w") as outfile:
- cmd = "xorriso -osirrox on -indev %s -cpx %s %s" % (iso, path, filename)
- subprocess.run(cmd.split(),
- stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+ cmd = "xorriso -osirrox on -indev %s -cpx %s %s" % (iso, path, filename)
+ subprocess.run(cmd.split(),
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
os.chmod(filename, 0o600)
- os.chdir(cwd)
- # Return complete path to extracted file. Because callers to
- # extract_from_iso() specify 'path' with a leading slash, it is
- # necessary to use os.path.relpath() as otherwise os.path.join()
- # interprets it as an absolute path and drops the self.workdir part.
- return os.path.normpath(os.path.join(self.workdir, filename))
+ return filename
def setUp(self):
super().setUp()
@@ -99,34 +70,33 @@ class HypervisorTest(QemuSystemTest):
self.vm.add_args("-kernel", self.vmlinuz)
self.vm.add_args("-initrd", self.initramfs)
self.vm.add_args("-smp", "4", "-m", "2g")
- self.vm.add_args("-drive", f"file={self.iso_path},format=raw,if=none,id=drive0")
+ self.vm.add_args("-drive", f"file={self.iso_path},format=raw,if=none,"
+ "id=drive0,read-only=true")
self.vm.launch()
- wait_for_console_pattern(self, 'Welcome to Alpine Linux 3.18')
- exec_command(self, 'root')
+ ps1='localhost:~#'
wait_for_console_pattern(self, 'localhost login:')
- wait_for_console_pattern(self, 'You may change this message by editing /etc/motd.')
+ exec_command_and_wait_for_pattern(self, 'root', ps1)
# If the time is wrong, SSL certificates can fail.
- exec_command(self, 'date -s "' + datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S' + '"'))
- exec_command(self, 'setup-alpine -qe')
- wait_for_console_pattern(self, 'Updating repository indexes... done.')
+ exec_command_and_wait_for_pattern(self, 'date -s "' + datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S' + '"'), ps1)
+ ps1='alpine:~#'
+ exec_command_and_wait_for_pattern(self, 'setup-alpine -qe', ps1)
+ exec_command_and_wait_for_pattern(self, 'setup-apkrepos -c1', ps1)
+ exec_command_and_wait_for_pattern(self, 'apk update', ps1)
+ # Could upgrade here but it usually should not be necessary
+ # exec_command_and_wait_for_pattern(self, 'apk upgrade --available', ps1)
def do_stop_alpine(self):
- exec_command(self, 'poweroff')
+ exec_command(self, 'echo "TEST ME"')
wait_for_console_pattern(self, 'alpine:~#')
+ exec_command(self, 'poweroff')
+ wait_for_console_pattern(self, 'reboot: Power down')
self.vm.wait()
def do_setup_kvm(self):
- exec_command(self, 'echo http://dl-cdn.alpinelinux.org/alpine/v3.18/main > /etc/apk/repositories')
- wait_for_console_pattern(self, 'alpine:~#')
- exec_command(self, 'echo http://dl-cdn.alpinelinux.org/alpine/v3.18/community >> /etc/apk/repositories')
- wait_for_console_pattern(self, 'alpine:~#')
- exec_command(self, 'apk update')
- wait_for_console_pattern(self, 'alpine:~#')
- exec_command(self, 'apk add qemu-system-ppc64')
- wait_for_console_pattern(self, 'alpine:~#')
- exec_command(self, 'modprobe kvm-hv')
- wait_for_console_pattern(self, 'alpine:~#')
+ ps1='alpine:~#'
+ exec_command_and_wait_for_pattern(self, 'apk add qemu-system-ppc64', ps1)
+ exec_command_and_wait_for_pattern(self, 'modprobe kvm-hv', ps1)
# This uses the host's block device as the source file for guest block
# device for install media. This is a bit hacky but allows reuse of the
@@ -144,20 +114,18 @@ class HypervisorTest(QemuSystemTest):
'-initrd /media/nvme0n1/boot/initramfs-lts '
'-kernel /media/nvme0n1/boot/vmlinuz-lts '
'-append \'usbcore.nousb ' + append + '\'')
- # Alpine 3.18 kernel seems to crash in XHCI USB driver.
- wait_for_console_pattern(self, 'Welcome to Alpine Linux 3.18')
- exec_command(self, 'root')
+ # Alpine 3.21 kernel seems to crash in XHCI USB driver.
+ ps1='localhost:~#'
wait_for_console_pattern(self, 'localhost login:')
- wait_for_console_pattern(self, 'You may change this message by editing /etc/motd.')
- exec_command(self, 'poweroff >& /dev/null')
- wait_for_console_pattern(self, 'localhost:~#')
+ exec_command_and_wait_for_pattern(self, 'root', ps1)
+ exec_command(self, 'poweroff')
wait_for_console_pattern(self, 'reboot: Power down')
- time.sleep(1)
- exec_command(self, '')
+ # Now wait for the host's prompt to come back
wait_for_console_pattern(self, 'alpine:~#')
def test_hv_pseries(self):
self.require_accelerator("tcg")
+ self.require_netdev('user')
self.set_machine('pseries')
self.vm.add_args("-accel", "tcg,thread=multi")
self.vm.add_args('-device', 'nvme,serial=1234,drive=drive0')
@@ -169,6 +137,7 @@ class HypervisorTest(QemuSystemTest):
def test_hv_pseries_kvm(self):
self.require_accelerator("kvm")
+ self.require_netdev('user')
self.set_machine('pseries')
self.vm.add_args("-accel", "kvm")
self.vm.add_args('-device', 'nvme,serial=1234,drive=drive0')
@@ -180,6 +149,7 @@ class HypervisorTest(QemuSystemTest):
def test_hv_powernv(self):
self.require_accelerator("tcg")
+ self.require_netdev('user')
self.set_machine('powernv')
self.vm.add_args("-accel", "tcg,thread=multi")
self.vm.add_args('-device', 'nvme,bus=pcie.2,addr=0x0,serial=1234,drive=drive0',
diff --git a/tests/functional/test_ppc64_mac99.py b/tests/functional/test_ppc64_mac99.py
new file mode 100755
index 0000000..dfd9c01
--- /dev/null
+++ b/tests/functional/test_ppc64_mac99.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a mac99 machine with a PPC970 CPU
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+
+class mac99Test(LinuxKernelTest):
+
+ ASSET_BR2_MAC99_LINUX = Asset(
+ 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/vmlinux',
+ 'd59307437e4365f2cced0bbd1b04949f7397b282ef349b7cafd894d74aadfbff')
+
+ ASSET_BR2_MAC99_ROOTFS = Asset(
+ 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main//buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/rootfs.ext2',
+ 'bbd5fd8af62f580bc4e585f326fe584e22856572633a8333178ea6d4ed4955a4')
+
+ def test_ppc64_mac99_buildroot(self):
+ self.set_machine('mac99')
+
+ linux_path = self.ASSET_BR2_MAC99_LINUX.fetch()
+ rootfs_path = self.ASSET_BR2_MAC99_ROOTFS.fetch()
+
+ self.vm.set_console()
+
+ # Note: We need '-nographic' to get a serial console
+ self.vm.add_args('-kernel', linux_path,
+ '-append', 'root=/dev/sda',
+ '-drive', f'file={rootfs_path},format=raw',
+ '-snapshot', '-nographic')
+ self.vm.launch()
+
+ self.wait_for_console_pattern('>> OpenBIOS')
+ self.wait_for_console_pattern('Linux version')
+ self.wait_for_console_pattern('/init as init process')
+ self.wait_for_console_pattern('gem 0000:f0:0e.0 eth0: Link is up at 100 Mbps')
+ self.wait_for_console_pattern('buildroot login:')
+ exec_command_and_wait_for_pattern(self, 'root', '#')
+ exec_command_and_wait_for_pattern(self, 'poweroff', 'Power down')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_ppc64_powernv.py b/tests/functional/test_ppc64_powernv.py
index 67497d6..685e217 100755
--- a/tests/functional/test_ppc64_powernv.py
+++ b/tests/functional/test_ppc64_powernv.py
@@ -7,10 +7,10 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from qemu_test import QemuSystemTest, Asset
+from qemu_test import LinuxKernelTest, Asset
from qemu_test import wait_for_console_pattern
-class powernvMachine(QemuSystemTest):
+class powernvMachine(LinuxKernelTest):
timeout = 90
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 console=hvc0 '
@@ -78,5 +78,41 @@ class powernvMachine(QemuSystemTest):
wait_for_console_pattern(self, console_pattern, self.panic_message)
wait_for_console_pattern(self, self.good_message, self.panic_message)
+
+ ASSET_EPAPR_KERNEL = Asset(
+ ('https://github.com/open-power/op-build/releases/download/v2.7/'
+ 'zImage.epapr'),
+ '0ab237df661727e5392cee97460e8674057a883c5f74381a128fa772588d45cd')
+
+ def do_test_ppc64_powernv(self, proc):
+ self.require_accelerator("tcg")
+ kernel_path = self.ASSET_EPAPR_KERNEL.fetch()
+ self.vm.set_console()
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', 'console=tty0 console=hvc0',
+ '-device', 'pcie-pci-bridge,id=bridge1,bus=pcie.1,addr=0x0',
+ '-device', 'nvme,bus=pcie.2,addr=0x0,serial=1234',
+ '-device', 'e1000e,bus=bridge1,addr=0x3',
+ '-device', 'nec-usb-xhci,bus=bridge1,addr=0x2')
+ self.vm.launch()
+
+ self.wait_for_console_pattern("CPU: " + proc + " generation processor")
+ self.wait_for_console_pattern("zImage starting: loaded")
+ self.wait_for_console_pattern("Run /init as init process")
+ # Device detection output driven by udev probing is sometimes cut off
+ # from console output, suspect S14silence-console init script.
+
+ def test_powernv8(self):
+ self.set_machine('powernv8')
+ self.do_test_ppc64_powernv('P8')
+
+ def test_powernv9(self):
+ self.set_machine('powernv9')
+ self.do_test_ppc64_powernv('P9')
+
+ def test_powernv10(self):
+ self.set_machine('powernv10')
+ self.do_test_ppc64_powernv('P10')
+
if __name__ == '__main__':
- QemuSystemTest.main()
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_ppc64_pseries.py b/tests/functional/test_ppc64_pseries.py
index fdc404e..6705793 100755
--- a/tests/functional/test_ppc64_pseries.py
+++ b/tests/functional/test_ppc64_pseries.py
@@ -63,6 +63,7 @@ class pseriesMachine(QemuSystemTest):
wait_for_console_pattern(self, self.good_message, self.panic_message)
def test_ppc64_linux_smt_boot(self):
+ self.set_machine('pseries')
self.vm.add_args('-smp', '4,threads=4')
self.do_test_ppc64_linux_boot()
console_pattern = 'CPU maps initialized for 4 threads per core'
diff --git a/tests/functional/test_ppc64_replay.py b/tests/functional/test_ppc64_replay.py
new file mode 100755
index 0000000..e8c9c4b
--- /dev/null
+++ b/tests/functional/test_ppc64_replay.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+#
+# Replay test that boots a Linux kernel on ppc64 machines
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset, skipFlakyTest
+from replay_kernel import ReplayKernelBase
+
+
+class Ppc64Replay(ReplayKernelBase):
+
+ ASSET_DAY19 = Asset(
+ ('https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/'
+ 'day19.tar.xz'),
+ '20b1bb5a8488c664defbb5d283addc91a05335a936c63b3f5ff7eee74b725755')
+
+ @skipFlakyTest('https://gitlab.com/qemu-project/qemu/-/issues/2523')
+ def test_ppc64_e500(self):
+ self.set_machine('ppce500')
+ self.cpu = 'e5500'
+ kernel_path = self.archive_extract(self.ASSET_DAY19,
+ member='day19/uImage')
+ self.run_rr(kernel_path, self.REPLAY_KERNEL_COMMAND_LINE,
+ 'QEMU advent calendar')
+
+ ASSET_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora-secondary/'
+ 'releases/29/Everything/ppc64le/os/ppc/ppc64/vmlinuz'),
+ '383c2f5c23bc0d9d32680c3924d3fd7ee25cc5ef97091ac1aa5e1d853422fc5f')
+
+ def test_ppc64_pseries(self):
+ self.set_machine('pseries')
+ kernel_path = self.ASSET_KERNEL.fetch()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=hvc0'
+ console_pattern = 'VFS: Cannot open root device'
+ self.run_rr(kernel_path, kernel_command_line, console_pattern)
+
+ def test_ppc64_powernv(self):
+ self.set_machine('powernv')
+ kernel_path = self.ASSET_KERNEL.fetch()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + \
+ 'console=tty0 console=hvc0'
+ console_pattern = 'VFS: Cannot open root device'
+ self.run_rr(kernel_path, kernel_command_line, console_pattern)
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_ppc64_reverse_debug.py b/tests/functional/test_ppc64_reverse_debug.py
new file mode 100755
index 0000000..5931ade
--- /dev/null
+++ b/tests/functional/test_ppc64_reverse_debug.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Reverse debugging test
+#
+# Copyright (c) 2020 ISP RAS
+#
+# Author:
+# Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from qemu_test import skipIfMissingImports, skipFlakyTest
+from reverse_debugging import ReverseDebugging
+
+
+@skipIfMissingImports('avocado.utils')
+class ReverseDebugging_ppc64(ReverseDebugging):
+
+ REG_PC = 0x40
+
+ @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/1992")
+ def test_ppc64_pseries(self):
+ self.set_machine('pseries')
+ # SLOF branches back to its entry point, which causes this test
+ # to take the 'hit a breakpoint again' path. That's not a problem,
+ # just slightly different than the other machines.
+ self.endian_is_le = False
+ self.reverse_debugging()
+
+ @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/1992")
+ def test_ppc64_powernv(self):
+ self.set_machine('powernv')
+ self.endian_is_le = False
+ self.reverse_debugging()
+
+
+if __name__ == '__main__':
+ ReverseDebugging.main()
diff --git a/tests/functional/test_ppc64_tuxrun.py b/tests/functional/test_ppc64_tuxrun.py
new file mode 100755
index 0000000..e8f79c6
--- /dev/null
+++ b/tests/functional/test_ppc64_tuxrun.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from subprocess import check_call, DEVNULL
+import tempfile
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunPPC64Test(TuxRunBaselineTest):
+
+ def ppc64_common_tuxrun(self, kernel_asset, rootfs_asset, prefix):
+ self.set_machine('pseries')
+ self.cpu='POWER10'
+ self.console='hvc0'
+ self.root='sda'
+ self.extradev='spapr-vscsi'
+ # add device args to command line.
+ self.require_netdev('user')
+ self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
+ '-device', 'virtio-net,netdev=vnet')
+ self.vm.add_args('-netdev', '{"type":"user","id":"hostnet0"}',
+ '-device', '{"driver":"virtio-net-pci","netdev":'
+ '"hostnet0","id":"net0","mac":"52:54:00:4c:e3:86",'
+ '"bus":"pci.0","addr":"0x9"}')
+ self.vm.add_args('-device', '{"driver":"qemu-xhci","p2":15,"p3":15,'
+ '"id":"usb","bus":"pci.0","addr":"0x2"}')
+ self.vm.add_args('-device', '{"driver":"virtio-scsi-pci","id":"scsi0"'
+ ',"bus":"pci.0","addr":"0x3"}')
+ self.vm.add_args('-device', '{"driver":"virtio-serial-pci","id":'
+ '"virtio-serial0","bus":"pci.0","addr":"0x4"}')
+ self.vm.add_args('-device', '{"driver":"scsi-cd","bus":"scsi0.0"'
+ ',"channel":0,"scsi-id":0,"lun":0,"device_id":'
+ '"drive-scsi0-0-0-0","id":"scsi0-0-0-0"}')
+ self.vm.add_args('-device', '{"driver":"virtio-balloon-pci",'
+ '"id":"balloon0","bus":"pci.0","addr":"0x6"}')
+ self.vm.add_args('-audiodev', '{"id":"audio1","driver":"none"}')
+ self.vm.add_args('-device', '{"driver":"usb-tablet","id":"input0"'
+ ',"bus":"usb.0","port":"1"}')
+ self.vm.add_args('-device', '{"driver":"usb-kbd","id":"input1"'
+ ',"bus":"usb.0","port":"2"}')
+ self.vm.add_args('-device', '{"driver":"VGA","id":"video0",'
+ '"vgamem_mb":16,"bus":"pci.0","addr":"0x7"}')
+ self.vm.add_args('-object', '{"qom-type":"rng-random","id":"objrng0"'
+ ',"filename":"/dev/urandom"}',
+ '-device', '{"driver":"virtio-rng-pci","rng":"objrng0"'
+ ',"id":"rng0","bus":"pci.0","addr":"0x8"}')
+ self.vm.add_args('-object', '{"qom-type":"cryptodev-backend-builtin",'
+ '"id":"objcrypto0","queues":1}',
+ '-device', '{"driver":"virtio-crypto-pci",'
+ '"cryptodev":"objcrypto0","id":"crypto0","bus"'
+ ':"pci.0","addr":"0xa"}')
+ self.vm.add_args('-device', '{"driver":"spapr-pci-host-bridge"'
+ ',"index":1,"id":"pci.1"}')
+ self.vm.add_args('-device', '{"driver":"spapr-vscsi","id":"scsi1"'
+ ',"reg":12288}')
+ self.vm.add_args('-m', '1G,slots=32,maxmem=2G',
+ '-object', 'memory-backend-ram,id=ram1,size=1G',
+ '-device', 'pc-dimm,id=dimm1,memdev=ram1')
+
+ # Create a temporary qcow2 and launch the test-case
+ with tempfile.NamedTemporaryFile(prefix=prefix,
+ suffix='.qcow2') as qcow2:
+ check_call([self.qemu_img, 'create', '-f', 'qcow2',
+ qcow2.name, ' 1G'],
+ stdout=DEVNULL, stderr=DEVNULL)
+
+ self.vm.add_args('-drive', 'file=' + qcow2.name +
+ ',format=qcow2,if=none,id='
+ 'drive-virtio-disk1',
+ '-device', 'virtio-blk-pci,bus=pci.0,'
+ 'addr=0xb,drive=drive-virtio-disk1,id=virtio-disk1'
+ ',bootindex=2')
+ self.common_tuxrun(kernel_asset, rootfs_asset=rootfs_asset,
+ drive="scsi-hd")
+
+ ASSET_PPC64_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/ppc64/vmlinux',
+ '8219d5cb26e7654ad7826fe8aee6290f7c01eef44f2cd6d26c15fe8f99e1c17c')
+ ASSET_PPC64_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/ppc64/rootfs.ext4.zst',
+ 'b68e12314303c5dd0fef37ae98021299a206085ae591893e73557af99a02d373')
+
+ def test_ppc64(self):
+ self.ppc64_common_tuxrun(kernel_asset=self.ASSET_PPC64_KERNEL,
+ rootfs_asset=self.ASSET_PPC64_ROOTFS,
+ prefix='tuxrun_ppc64_')
+
+ ASSET_PPC64LE_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/ppc64le/vmlinux',
+ '21aea1fbc18bf6fa7d8ca4ea48d4940b2c8363c077acd564eb47d769b7495279')
+ ASSET_PPC64LE_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/ppc64le/rootfs.ext4.zst',
+ '67d36a3f9597b738e8b7359bdf04500f4d9bb82fc35eaa65aa439d888b2392f4')
+
+ def test_ppc64le(self):
+ self.ppc64_common_tuxrun(kernel_asset=self.ASSET_PPC64LE_KERNEL,
+ rootfs_asset=self.ASSET_PPC64LE_ROOTFS,
+ prefix='tuxrun_ppc64le_')
+
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_ppc_405.py b/tests/functional/test_ppc_405.py
deleted file mode 100755
index 9851c03..0000000
--- a/tests/functional/test_ppc_405.py
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env python3
-#
-# Test that the U-Boot firmware boots on ppc 405 machines and check the console
-#
-# Copyright (c) 2021 Red Hat, Inc.
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-from qemu_test import QemuSystemTest, Asset
-from qemu_test import wait_for_console_pattern
-from qemu_test import exec_command_and_wait_for_pattern
-
-class Ppc405Machine(QemuSystemTest):
-
- timeout = 90
-
- ASSET_UBOOT = Asset(
- ('https://gitlab.com/huth/u-boot/-/raw/taihu-2021-10-09/'
- 'u-boot-taihu.bin'),
- 'a076bb6cdeaafa406330e51e074b66d8878d9036d67d4caa0137be03ee4c112c')
-
- def do_test_ppc405(self):
- file_path = self.ASSET_UBOOT.fetch()
- self.vm.set_console(console_index=1)
- self.vm.add_args('-bios', file_path)
- self.vm.launch()
- wait_for_console_pattern(self, 'AMCC PPC405EP Evaluation Board')
- exec_command_and_wait_for_pattern(self, 'reset', 'AMCC PowerPC 405EP')
-
- def test_ppc_ref405ep(self):
- self.require_accelerator("tcg")
- self.set_machine('ref405ep')
- self.do_test_ppc405()
-
-if __name__ == '__main__':
- QemuSystemTest.main()
diff --git a/tests/functional/test_ppc_40p.py b/tests/functional/test_ppc_40p.py
index c64e876..614972a 100755
--- a/tests/functional/test_ppc_40p.py
+++ b/tests/functional/test_ppc_40p.py
@@ -7,11 +7,9 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-import os
-
-from unittest import skipUnless
from qemu_test import QemuSystemTest, Asset
-from qemu_test import wait_for_console_pattern
+from qemu_test import wait_for_console_pattern, skipUntrustedTest
+from qemu_test import exec_command_and_wait_for_pattern
class IbmPrep40pMachine(QemuSystemTest):
@@ -37,7 +35,7 @@ class IbmPrep40pMachine(QemuSystemTest):
# All rights reserved.
# U.S. Government Users Restricted Rights - Use, duplication or disclosure
# restricted by GSA ADP Schedule Contract with IBM Corp.
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipUntrustedTest()
def test_factory_firmware_and_netbsd(self):
self.set_machine('40p')
self.require_accelerator("tcg")
@@ -46,7 +44,8 @@ class IbmPrep40pMachine(QemuSystemTest):
self.vm.set_console()
self.vm.add_args('-bios', bios_path,
- '-fda', drive_path)
+ '-drive',
+ f"file={drive_path},format=raw,if=floppy,read-only=true")
self.vm.launch()
os_banner = 'NetBSD 4.0 (GENERIC) #0: Sun Dec 16 00:49:40 PST 2007'
wait_for_console_pattern(self, os_banner)
@@ -74,5 +73,22 @@ class IbmPrep40pMachine(QemuSystemTest):
self.vm.launch()
wait_for_console_pattern(self, 'NetBSD/prep BOOT, Revision 1.9')
+ ASSET_40P_SANDALFOOT = Asset(
+ 'http://www.juneau-lug.org/zImage.initrd.sandalfoot',
+ '749ab02f576c6dc8f33b9fb022ecb44bf6a35a0472f2ea6a5e9956bc15933901')
+
+ def test_openbios_and_linux(self):
+ self.set_machine('40p')
+ self.require_accelerator("tcg")
+ drive_path = self.ASSET_40P_SANDALFOOT.fetch()
+ self.vm.set_console()
+ self.vm.add_args('-cdrom', drive_path,
+ '-boot', 'd')
+
+ self.vm.launch()
+ wait_for_console_pattern(self, 'Please press Enter to activate this console.')
+ exec_command_and_wait_for_pattern(self, '\012', '#')
+ exec_command_and_wait_for_pattern(self, 'uname -a', 'Linux ppc 2.4.18')
+
if __name__ == '__main__':
QemuSystemTest.main()
diff --git a/tests/functional/test_ppc_amiga.py b/tests/functional/test_ppc_amiga.py
index b793b5c..8600e2e 100755
--- a/tests/functional/test_ppc_amiga.py
+++ b/tests/functional/test_ppc_amiga.py
@@ -10,8 +10,8 @@
import subprocess
from qemu_test import QemuSystemTest, Asset
-from qemu_test import wait_for_console_pattern, run_cmd
-from zipfile import ZipFile
+from qemu_test import wait_for_console_pattern
+
class AmigaOneMachine(QemuSystemTest):
@@ -26,16 +26,16 @@ class AmigaOneMachine(QemuSystemTest):
self.require_accelerator("tcg")
self.set_machine('amigaone')
tar_name = 'A1Firmware_Floppy_05-Mar-2005.zip'
- zip_file = self.ASSET_IMAGE.fetch()
- with ZipFile(zip_file, 'r') as zf:
- zf.extractall(path=self.workdir)
- bios_fh = open(self.workdir + "/u-boot-amigaone.bin", "wb")
- subprocess.run(['tail', '-c', '524288',
- self.workdir + "/floppy_edition/updater.image"],
- stdout=bios_fh)
+ self.archive_extract(self.ASSET_IMAGE, format="zip")
+ bios = self.scratch_file("u-boot-amigaone.bin")
+ with open(bios, "wb") as bios_fh:
+ subprocess.run(['tail', '-c', '524288',
+ self.scratch_file("floppy_edition",
+ "updater.image")],
+ stdout=bios_fh)
self.vm.set_console()
- self.vm.add_args('-bios', self.workdir + '/u-boot-amigaone.bin')
+ self.vm.add_args('-bios', bios)
self.vm.launch()
wait_for_console_pattern(self, 'FLASH:')
diff --git a/tests/functional/test_ppc_bamboo.py b/tests/functional/test_ppc_bamboo.py
index e72cbde..fddcc24 100755
--- a/tests/functional/test_ppc_bamboo.py
+++ b/tests/functional/test_ppc_bamboo.py
@@ -7,11 +7,11 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from qemu_test.utils import archive_extract
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
from qemu_test import exec_command_and_wait_for_pattern
+
class BambooMachine(QemuSystemTest):
timeout = 90
@@ -25,13 +25,14 @@ class BambooMachine(QemuSystemTest):
self.set_machine('bamboo')
self.require_accelerator("tcg")
self.require_netdev('user')
- file_path = self.ASSET_IMAGE.fetch()
- archive_extract(file_path, self.workdir)
+ self.archive_extract(self.ASSET_IMAGE)
self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir +
- '/system-image-powerpc-440fp/linux',
- '-initrd', self.workdir +
- '/system-image-powerpc-440fp/rootfs.cpio.gz',
+ self.vm.add_args('-kernel',
+ self.scratch_file('system-image-powerpc-440fp',
+ 'linux'),
+ '-initrd',
+ self.scratch_file('system-image-powerpc-440fp',
+ 'rootfs.cpio.gz'),
'-nic', 'user,model=rtl8139,restrict=on')
self.vm.launch()
wait_for_console_pattern(self, 'Type exit when done')
diff --git a/tests/functional/test_ppc_mac.py b/tests/functional/test_ppc_mac.py
new file mode 100755
index 0000000..9e4bc1a
--- /dev/null
+++ b/tests/functional/test_ppc_mac.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+#
+# Boot Linux kernel on a mac99 and g3beige ppc machine and check the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class MacTest(LinuxKernelTest):
+
+ ASSET_DAY15 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day15.tar.xz',
+ '03e0757c131d2959decf293a3572d3b96c5a53587165bf05ce41b2818a2bccd5')
+
+ def do_day15_test(self):
+ # mac99 also works with kvm_pr but we don't have a reliable way at
+ # the moment (e.g. by looking at /proc/modules) to detect whether
+ # we're running kvm_hv or kvm_pr. For now let's disable this test
+ # if we don't have TCG support.
+ self.require_accelerator("tcg")
+ self.archive_extract(self.ASSET_DAY15)
+ self.vm.add_args('-M', 'graphics=off')
+ self.launch_kernel(self.scratch_file('day15', 'invaders.elf'),
+ wait_for='QEMU advent calendar')
+
+ def test_ppc_g3beige(self):
+ self.set_machine('g3beige')
+ self.do_day15_test()
+
+ def test_ppc_mac99(self):
+ self.set_machine('mac99')
+ self.do_day15_test()
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_ppc_mpc8544ds.py b/tests/functional/test_ppc_mpc8544ds.py
index 2b3f089..0715410 100755
--- a/tests/functional/test_ppc_mpc8544ds.py
+++ b/tests/functional/test_ppc_mpc8544ds.py
@@ -7,10 +7,10 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from qemu_test.utils import archive_extract
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
+
class Mpc8544dsMachine(QemuSystemTest):
timeout = 90
@@ -25,10 +25,10 @@ class Mpc8544dsMachine(QemuSystemTest):
def test_ppc_mpc8544ds(self):
self.require_accelerator("tcg")
self.set_machine('mpc8544ds')
- file_path = self.ASSET_IMAGE.fetch()
- archive_extract(file_path, self.workdir, member='creek/creek.bin')
+ kernel_file = self.archive_extract(self.ASSET_IMAGE,
+ member='creek/creek.bin')
self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir + '/creek/creek.bin')
+ self.vm.add_args('-kernel', kernel_file)
self.vm.launch()
wait_for_console_pattern(self, 'QEMU advent calendar 2020',
self.panic_message)
diff --git a/tests/functional/test_ppc_replay.py b/tests/functional/test_ppc_replay.py
new file mode 100755
index 0000000..8382070
--- /dev/null
+++ b/tests/functional/test_ppc_replay.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+#
+# Replay tests for ppc machines
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from replay_kernel import ReplayKernelBase
+
+
+class PpcReplay(ReplayKernelBase):
+
+ ASSET_DAY15 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day15.tar.xz',
+ '03e0757c131d2959decf293a3572d3b96c5a53587165bf05ce41b2818a2bccd5')
+
+ def do_day15_test(self):
+ self.require_accelerator("tcg")
+ kernel_path = self.archive_extract(self.ASSET_DAY15,
+ member='day15/invaders.elf')
+ self.run_rr(kernel_path, self.REPLAY_KERNEL_COMMAND_LINE,
+ 'QEMU advent calendar', args=('-M', 'graphics=off'))
+
+ def test_g3beige(self):
+ self.set_machine('g3beige')
+ self.do_day15_test()
+
+ def test_mac99(self):
+ self.set_machine('mac99')
+ self.do_day15_test()
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_ppc_sam460ex.py b/tests/functional/test_ppc_sam460ex.py
new file mode 100644
index 0000000..31cf9dd
--- /dev/null
+++ b/tests/functional/test_ppc_sam460ex.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a sam460ex machine with a PPC 460EX CPU
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+
+
+class sam460exTest(LinuxKernelTest):
+
+ ASSET_BR2_SAM460EX_LINUX = Asset(
+ 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/buildroot/qemu_ppc_sam460ex-2023.11-8-gdcd9f0f6eb-20240105/vmlinux',
+ '6f46346f3e20e8b5fc050ff363f350f8b9d76a051b9e0bd7ea470cc680c14df2')
+
+ def test_ppc_sam460ex_buildroot(self):
+ self.set_machine('sam460ex')
+ self.require_netdev('user')
+
+ linux_path = self.ASSET_BR2_SAM460EX_LINUX.fetch()
+
+ self.vm.set_console()
+ self.vm.add_args('-kernel', linux_path,
+ '-device', 'virtio-net-pci,netdev=net0',
+ '-netdev', 'user,id=net0')
+ self.vm.launch()
+
+ self.wait_for_console_pattern('Linux version')
+ self.wait_for_console_pattern('Hardware name: amcc,canyonlands 460EX')
+ self.wait_for_console_pattern('/init as init process')
+ self.wait_for_console_pattern('lease of 10.0.2.15 obtained')
+ self.wait_for_console_pattern('buildroot login:')
+ exec_command_and_wait_for_pattern(self, 'root', '#')
+ exec_command_and_wait_for_pattern(self, 'poweroff', 'System Halted')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_ppc_tuxrun.py b/tests/functional/test_ppc_tuxrun.py
new file mode 100755
index 0000000..5458a7f
--- /dev/null
+++ b/tests/functional/test_ppc_tuxrun.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunPPC32Test(TuxRunBaselineTest):
+
+ ASSET_PPC32_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/ppc32/uImage',
+ 'aa5d81deabdb255a318c4bc5ffd6fdd2b5da1ef39f1955dcc35b671d258b68e9')
+ ASSET_PPC32_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/ppc32/rootfs.ext4.zst',
+ '67554f830269d6bf53b67c7dd206bcc821e463993d526b1644066fea8117019b')
+
+ def test_ppc32(self):
+ self.set_machine('ppce500')
+ self.cpu='e500mc'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_PPC32_KERNEL,
+ rootfs_asset=self.ASSET_PPC32_ROOTFS,
+ drive="virtio-blk-pci")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_ppc_virtex_ml507.py b/tests/functional/test_ppc_virtex_ml507.py
index ffa9a06..8fe4354 100755
--- a/tests/functional/test_ppc_virtex_ml507.py
+++ b/tests/functional/test_ppc_virtex_ml507.py
@@ -7,10 +7,10 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from qemu_test.utils import archive_extract
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
+
class VirtexMl507Machine(QemuSystemTest):
timeout = 90
@@ -25,11 +25,11 @@ class VirtexMl507Machine(QemuSystemTest):
def test_ppc_virtex_ml507(self):
self.require_accelerator("tcg")
self.set_machine('virtex-ml507')
- file_path = self.ASSET_IMAGE.fetch()
- archive_extract(file_path, self.workdir)
+ self.archive_extract(self.ASSET_IMAGE)
self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir + '/hippo/hippo.linux',
- '-dtb', self.workdir + '/hippo/virtex440-ml507.dtb',
+ self.vm.add_args('-kernel', self.scratch_file('hippo', 'hippo.linux'),
+ '-dtb', self.scratch_file('hippo',
+ 'virtex440-ml507.dtb'),
'-m', '512')
self.vm.launch()
wait_for_console_pattern(self, 'QEMU advent calendar 2020',
diff --git a/tests/functional/test_riscv32_tuxrun.py b/tests/functional/test_riscv32_tuxrun.py
new file mode 100755
index 0000000..3c57020
--- /dev/null
+++ b/tests/functional/test_riscv32_tuxrun.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunRiscV32Test(TuxRunBaselineTest):
+
+ ASSET_RISCV32_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/riscv32/Image',
+ '872bc8f8e0d4661825d5f47f7bec64988e9d0a8bd5db8917d57e16f66d83b329')
+ ASSET_RISCV32_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/riscv32/rootfs.ext4.zst',
+ '511ad34e63222db08d6c1da16fad224970de36517a784110956ba6a24a0ee5f6')
+
+ def test_riscv32(self):
+ self.set_machine('virt')
+ self.common_tuxrun(kernel_asset=self.ASSET_RISCV32_KERNEL,
+ rootfs_asset=self.ASSET_RISCV32_ROOTFS)
+
+ def test_riscv32_maxcpu(self):
+ self.set_machine('virt')
+ self.cpu='max'
+ self.common_tuxrun(kernel_asset=self.ASSET_RISCV32_KERNEL,
+ rootfs_asset=self.ASSET_RISCV32_ROOTFS)
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_riscv64_tuxrun.py b/tests/functional/test_riscv64_tuxrun.py
new file mode 100755
index 0000000..0d8de36
--- /dev/null
+++ b/tests/functional/test_riscv64_tuxrun.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunRiscV64Test(TuxRunBaselineTest):
+
+ ASSET_RISCV64_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/riscv64/Image',
+ '2bd8132a3bf21570290042324fff48c987f42f2a00c08de979f43f0662ebadba')
+ ASSET_RISCV64_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/riscv64/rootfs.ext4.zst',
+ 'aa4736a9872651dfc0d95e709465eedf1134fd19d42b8cb305bfd776f9801004')
+
+ ASSET_RISCV32_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/riscv32/Image',
+ '872bc8f8e0d4661825d5f47f7bec64988e9d0a8bd5db8917d57e16f66d83b329')
+ ASSET_RISCV32_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/riscv32/rootfs.ext4.zst',
+ '511ad34e63222db08d6c1da16fad224970de36517a784110956ba6a24a0ee5f6')
+
+ def test_riscv64(self):
+ self.set_machine('virt')
+ self.common_tuxrun(kernel_asset=self.ASSET_RISCV64_KERNEL,
+ rootfs_asset=self.ASSET_RISCV64_ROOTFS)
+
+ def test_riscv64_maxcpu(self):
+ self.set_machine('virt')
+ self.cpu='max'
+ self.common_tuxrun(kernel_asset=self.ASSET_RISCV64_KERNEL,
+ rootfs_asset=self.ASSET_RISCV64_ROOTFS)
+
+ def test_riscv64_rv32(self):
+ self.set_machine('virt')
+ self.cpu='rv32'
+ self.common_tuxrun(kernel_asset=self.ASSET_RISCV32_KERNEL,
+ rootfs_asset=self.ASSET_RISCV32_ROOTFS)
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_riscv_opensbi.py b/tests/functional/test_riscv_opensbi.py
new file mode 100755
index 0000000..d077e40
--- /dev/null
+++ b/tests/functional/test_riscv_opensbi.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+#
+# OpenSBI boot test for RISC-V machines
+#
+# Copyright (c) 2022, Ventana Micro
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from qemu_test import QemuSystemTest
+from qemu_test import wait_for_console_pattern
+
+class RiscvOpenSBI(QemuSystemTest):
+
+ timeout = 5
+
+ def boot_opensbi(self):
+ self.vm.set_console()
+ self.vm.launch()
+ wait_for_console_pattern(self, 'Platform Name')
+ wait_for_console_pattern(self, 'Boot HART MEDELEG')
+
+ def test_riscv_spike(self):
+ self.set_machine('spike')
+ self.boot_opensbi()
+
+ def test_riscv_sifive_u(self):
+ self.set_machine('sifive_u')
+ self.boot_opensbi()
+
+ def test_riscv_virt(self):
+ self.set_machine('virt')
+ self.boot_opensbi()
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_rx_gdbsim.py b/tests/functional/test_rx_gdbsim.py
index 5687f75..4924579 100755
--- a/tests/functional/test_rx_gdbsim.py
+++ b/tests/functional/test_rx_gdbsim.py
@@ -10,13 +10,9 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-import os
-
-from unittest import skipUnless
from qemu_test import QemuSystemTest, Asset
from qemu_test import exec_command_and_wait_for_pattern
-from qemu_test import wait_for_console_pattern
-from qemu_test.utils import gzip_uncompress
+from qemu_test import wait_for_console_pattern, skipFlakyTest
class RxGdbSimMachine(QemuSystemTest):
@@ -25,13 +21,16 @@ class RxGdbSimMachine(QemuSystemTest):
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
ASSET_UBOOT = Asset(
- 'https://acc.dl.osdn.jp/users/23/23888/u-boot.bin.gz',
- '7146567d669e91dbac166384b29aeba1715beb844c8551e904b86831bfd9d046')
+ ('https://github.com/philmd/qemu-testing-blob/raw/rx-gdbsim/rx/gdbsim/'
+ 'u-boot.bin'),
+ 'dd7dd4220cccf7aeb32227b26233bf39600db05c3f8e26005bcc2bf6c927207d')
ASSET_DTB = Asset(
- 'https://acc.dl.osdn.jp/users/23/23887/rx-virt.dtb',
+ ('https://github.com/philmd/qemu-testing-blob/raw/rx-gdbsim/rx/gdbsim/'
+ 'rx-gdbsim.dtb'),
'aa278d9c1907a4501741d7ee57e7f65c02dd1b3e0323b33c6d4247f1b32cf29a')
ASSET_KERNEL = Asset(
- 'http://acc.dl.osdn.jp/users/23/23845/zImage',
+ ('https://github.com/philmd/qemu-testing-blob/raw/rx-gdbsim/rx/gdbsim/'
+ 'zImage'),
'baa43205e74a7220ed8482188c5e9ce497226712abb7f4e7e4f825ce19ff9656')
def test_uboot(self):
@@ -40,9 +39,7 @@ class RxGdbSimMachine(QemuSystemTest):
"""
self.set_machine('gdbsim-r5f562n8')
- uboot_path_gz = self.ASSET_UBOOT.fetch()
- uboot_path = os.path.join(self.workdir, 'u-boot.bin')
- gzip_uncompress(uboot_path_gz, uboot_path)
+ uboot_path = self.ASSET_UBOOT.fetch()
self.vm.set_console()
self.vm.add_args('-bios', uboot_path,
@@ -52,9 +49,10 @@ class RxGdbSimMachine(QemuSystemTest):
wait_for_console_pattern(self, uboot_version)
gcc_version = 'rx-unknown-linux-gcc (GCC) 9.0.0 20181105 (experimental)'
# FIXME limit baudrate on chardev, else we type too fast
+ # https://gitlab.com/qemu-project/qemu/-/issues/2691
#exec_command_and_wait_for_pattern(self, 'version', gcc_version)
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
+ @skipFlakyTest(bug_url="https://gitlab.com/qemu-project/qemu/-/issues/2691")
def test_linux_sash(self):
"""
Boots a Linux kernel and checks that the console is operational.
diff --git a/tests/functional/test_s390x_ccw_virtio.py b/tests/functional/test_s390x_ccw_virtio.py
index f7acd90..453711a 100755
--- a/tests/functional/test_s390x_ccw_virtio.py
+++ b/tests/functional/test_s390x_ccw_virtio.py
@@ -17,7 +17,7 @@ import tempfile
from qemu_test import QemuSystemTest, Asset
from qemu_test import exec_command_and_wait_for_pattern
from qemu_test import wait_for_console_pattern
-from qemu_test.utils import lzma_uncompress
+
class S390CCWVirtioMachine(QemuSystemTest):
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
@@ -174,9 +174,7 @@ class S390CCWVirtioMachine(QemuSystemTest):
kernel_path = self.ASSET_F31_KERNEL.fetch()
- initrd_path_xz = self.ASSET_F31_INITRD.fetch()
- initrd_path = os.path.join(self.workdir, 'initrd-raw.img')
- lzma_uncompress(initrd_path_xz, initrd_path)
+ initrd_path = self.uncompress(self.ASSET_F31_INITRD, format="xz")
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + ' audit=0 '
diff --git a/tests/functional/test_s390x_replay.py b/tests/functional/test_s390x_replay.py
new file mode 100755
index 0000000..33b5843
--- /dev/null
+++ b/tests/functional/test_s390x_replay.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+#
+# Replay test that boots a Linux kernel on an s390x machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from replay_kernel import ReplayKernelBase
+
+
+class S390xReplay(ReplayKernelBase):
+
+ ASSET_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora-secondary/'
+ 'releases/29/Everything/s390x/os/images/kernel.img'),
+ 'dace03b8ae0c9f670ebb9b8d6ce5eb24b62987f346de8f1300a439bb00bb99e7')
+
+ def test_s390_ccw_virtio(self):
+ self.set_machine('s390-ccw-virtio')
+ kernel_path = self.ASSET_KERNEL.fetch()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=sclp0'
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=9)
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_s390x_topology.py b/tests/functional/test_s390x_topology.py
index 20727f6..1b5dc65 100755
--- a/tests/functional/test_s390x_topology.py
+++ b/tests/functional/test_s390x_topology.py
@@ -10,14 +10,10 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-import os
-import time
-
from qemu_test import QemuSystemTest, Asset
from qemu_test import exec_command
from qemu_test import exec_command_and_wait_for_pattern
from qemu_test import wait_for_console_pattern
-from qemu_test.utils import lzma_uncompress
class S390CPUTopology(QemuSystemTest):
@@ -89,9 +85,7 @@ class S390CPUTopology(QemuSystemTest):
"""
self.require_accelerator("kvm")
kernel_path = self.ASSET_F35_KERNEL.fetch()
- initrd_path_xz = self.ASSET_F35_INITRD.fetch()
- initrd_path = os.path.join(self.workdir, 'initrd-raw.img')
- lzma_uncompress(initrd_path_xz, initrd_path)
+ initrd_path = self.uncompress(self.ASSET_F35_INITRD, format="xz")
self.vm.set_console()
kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE
@@ -223,12 +217,12 @@ class S390CPUTopology(QemuSystemTest):
self.assertEqual(res['return']['polarization'], 'horizontal')
self.check_topology(0, 0, 0, 0, 'medium', False)
- self.guest_set_dispatching('1');
+ self.guest_set_dispatching('1')
res = self.vm.qmp('query-s390x-cpu-polarization')
self.assertEqual(res['return']['polarization'], 'vertical')
self.check_topology(0, 0, 0, 0, 'medium', False)
- self.guest_set_dispatching('0');
+ self.guest_set_dispatching('0')
res = self.vm.qmp('query-s390x-cpu-polarization')
self.assertEqual(res['return']['polarization'], 'horizontal')
self.check_topology(0, 0, 0, 0, 'medium', False)
@@ -289,7 +283,7 @@ class S390CPUTopology(QemuSystemTest):
self.check_polarization('vertical:high')
self.check_topology(0, 0, 0, 0, 'high', False)
- self.guest_set_dispatching('0');
+ self.guest_set_dispatching('0')
self.check_polarization("horizontal")
self.check_topology(0, 0, 0, 0, 'high', False)
@@ -316,11 +310,11 @@ class S390CPUTopology(QemuSystemTest):
self.check_topology(0, 0, 0, 0, 'high', True)
self.check_polarization("horizontal")
- self.guest_set_dispatching('1');
+ self.guest_set_dispatching('1')
self.check_topology(0, 0, 0, 0, 'high', True)
self.check_polarization("vertical:high")
- self.guest_set_dispatching('0');
+ self.guest_set_dispatching('0')
self.check_topology(0, 0, 0, 0, 'high', True)
self.check_polarization("horizontal")
@@ -366,7 +360,7 @@ class S390CPUTopology(QemuSystemTest):
self.check_topology(0, 0, 0, 0, 'high', True)
- self.guest_set_dispatching('1');
+ self.guest_set_dispatching('1')
self.check_topology(0, 0, 0, 0, 'high', True)
diff --git a/tests/functional/test_s390x_tuxrun.py b/tests/functional/test_s390x_tuxrun.py
new file mode 100755
index 0000000..8df3c68
--- /dev/null
+++ b/tests/functional/test_s390x_tuxrun.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunS390xTest(TuxRunBaselineTest):
+
+ ASSET_S390X_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/s390/bzImage',
+ 'ee67e91db52a2aed104a7c72b2a08987c678f8179c029626789c35d6dd0fedf1')
+ ASSET_S390X_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/s390/rootfs.ext4.zst',
+ 'bff7971fc2fef56372d98afe4557b82fd0a785a241e44c29b058e577ad1bbb44')
+
+ def test_s390(self):
+ self.set_machine('s390-ccw-virtio')
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_S390X_KERNEL,
+ rootfs_asset=self.ASSET_S390X_ROOTFS,
+ drive="virtio-blk-ccw",
+ haltmsg="Requesting system halt")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_sh4_r2d.py b/tests/functional/test_sh4_r2d.py
new file mode 100755
index 0000000..03a64837
--- /dev/null
+++ b/tests/functional/test_sh4_r2d.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+#
+# Boot a Linux kernel on a r2d sh4 machine and check the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset, skipFlakyTest
+
+
+class R2dTest(LinuxKernelTest):
+
+ ASSET_DAY09 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day09.tar.xz',
+ 'a61b44d2630a739d1380cc4ff4b80981d47ccfd5992f1484ccf48322c35f09ac')
+
+ # This test has a 6-10% failure rate on various hosts that look
+ # like issues with a buggy kernel.
+ # XXX file tracking bug
+ @skipFlakyTest(bug_url=None)
+ def test_r2d(self):
+ self.set_machine('r2d')
+ self.archive_extract(self.ASSET_DAY09)
+ self.vm.add_args('-append', 'console=ttySC1')
+ self.launch_kernel(self.scratch_file('day09', 'zImage'),
+ console_index=1,
+ wait_for='QEMU advent calendar')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_sh4_tuxrun.py b/tests/functional/test_sh4_tuxrun.py
new file mode 100755
index 0000000..1748f8c
--- /dev/null
+++ b/tests/functional/test_sh4_tuxrun.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset, exec_command_and_wait_for_pattern
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunSh4Test(TuxRunBaselineTest):
+
+ ASSET_SH4_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/sh4/zImage',
+ '29d9b2aba604a0f53a5dc3b5d0f2b8e35d497de1129f8ee5139eb6fdf0db692f')
+ ASSET_SH4_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/sh4/rootfs.ext4.zst',
+ '3592a7a3d5a641e8b9821449e77bc43c9904a56c30d45da0694349cfd86743fd')
+
+ def test_sh4(self):
+ self.set_machine('r2d')
+ self.cpu='sh7785'
+ self.root='sda'
+ self.console='ttySC1'
+
+ # The test is currently too unstable to do much in userspace
+ # so we skip common_tuxrun and do a minimal boot and shutdown.
+ (kernel, disk, dtb) = self.fetch_tuxrun_assets(self.ASSET_SH4_KERNEL,
+ self.ASSET_SH4_ROOTFS)
+
+ # the console comes on the second serial port
+ self.prepare_run(kernel, disk,
+ "driver=ide-hd,bus=ide.0,unit=0",
+ console_index=1)
+ self.vm.launch()
+
+ self.wait_for_console_pattern("tuxtest login:")
+ exec_command_and_wait_for_pattern(self, 'root', 'root@tuxtest:~#')
+ exec_command_and_wait_for_pattern(self, 'halt',
+ "reboot: System halted")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_sh4eb_r2d.py b/tests/functional/test_sh4eb_r2d.py
new file mode 100755
index 0000000..473093b
--- /dev/null
+++ b/tests/functional/test_sh4eb_r2d.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+#
+# Boot a Linux kernel on a r2d sh4eb machine and check the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+
+
+class R2dEBTest(LinuxKernelTest):
+
+ ASSET_TGZ = Asset(
+ 'https://landley.net/bin/mkroot/0.8.11/sh4eb.tgz',
+ 'be8c6cb5aef8406899dc5aa5e22b6aa45840eb886cdd3ced51555c10577ada2c')
+
+ def test_sh4eb_r2d(self):
+ self.set_machine('r2d')
+ self.archive_extract(self.ASSET_TGZ)
+ self.vm.add_args('-append', 'console=ttySC1 noiotrap')
+ self.launch_kernel(self.scratch_file('sh4eb', 'linux-kernel'),
+ initrd=self.scratch_file('sh4eb',
+ 'initramfs.cpio.gz'),
+ console_index=1, wait_for='Type exit when done')
+ exec_command_and_wait_for_pattern(self, 'exit', 'Restarting system')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_sparc64_sun4u.py b/tests/functional/test_sparc64_sun4u.py
index 32e245f..27ac289 100755
--- a/tests/functional/test_sparc64_sun4u.py
+++ b/tests/functional/test_sparc64_sun4u.py
@@ -10,11 +10,9 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-import os
-
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
-from qemu_test.utils import archive_extract
+
class Sun4uMachine(QemuSystemTest):
"""Boots the Linux kernel and checks that the console is operational"""
@@ -28,11 +26,10 @@ class Sun4uMachine(QemuSystemTest):
def test_sparc64_sun4u(self):
self.set_machine('sun4u')
- file_path = self.ASSET_IMAGE.fetch()
- kernel_name = 'day23/vmlinux'
- archive_extract(file_path, self.workdir, kernel_name)
+ kernel_file = self.archive_extract(self.ASSET_IMAGE,
+ member='day23/vmlinux')
self.vm.set_console()
- self.vm.add_args('-kernel', os.path.join(self.workdir, kernel_name),
+ self.vm.add_args('-kernel', kernel_file,
'-append', 'printk.time=0')
self.vm.launch()
wait_for_console_pattern(self, 'Starting logging: OK')
diff --git a/tests/functional/test_sparc64_tuxrun.py b/tests/functional/test_sparc64_tuxrun.py
new file mode 100755
index 0000000..0d7b43d
--- /dev/null
+++ b/tests/functional/test_sparc64_tuxrun.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunSparc64Test(TuxRunBaselineTest):
+
+ ASSET_SPARC64_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/sparc64/vmlinux',
+ 'a04cfb2e70a264051d161fdd93aabf4b2a9472f2e435c14ed18c5848c5fed261')
+ ASSET_SPARC64_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/sparc64/rootfs.ext4.zst',
+ '479c3dc104c82b68be55e2c0c5c38cd473d0b37ad4badccde4775bb88ce34611')
+
+ def test_sparc64(self):
+ self.set_machine('sun4u')
+ self.root='sda'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_SPARC64_KERNEL,
+ rootfs_asset=self.ASSET_SPARC64_ROOTFS,
+ drive="driver=ide-hd,bus=ide.0,unit=0")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_sparc_replay.py b/tests/functional/test_sparc_replay.py
new file mode 100755
index 0000000..865d648
--- /dev/null
+++ b/tests/functional/test_sparc_replay.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+#
+# Replay test that boots a Linux kernel on a sparc sun4m machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from replay_kernel import ReplayKernelBase
+
+
+class SparcReplay(ReplayKernelBase):
+
+ ASSET_DAY11 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day11.tar.xz',
+ 'c776533ba756bf4dd3f1fc4c024fb50ef0d853e05c5f5ddf0900a32d1eaa49e0')
+
+ def test_replay(self):
+ self.set_machine('SS-10')
+ kernel_path = self.archive_extract(self.ASSET_DAY11,
+ member="day11/zImage.elf")
+ self.run_rr(kernel_path, self.REPLAY_KERNEL_COMMAND_LINE,
+ 'QEMU advent calendar')
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_sparc_sun4m.py b/tests/functional/test_sparc_sun4m.py
new file mode 100755
index 0000000..7cd28eb
--- /dev/null
+++ b/tests/functional/test_sparc_sun4m.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on a sparc sun4m machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class Sun4mTest(LinuxKernelTest):
+
+ ASSET_DAY11 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day11.tar.xz',
+ 'c776533ba756bf4dd3f1fc4c024fb50ef0d853e05c5f5ddf0900a32d1eaa49e0')
+
+ def test_sparc_ss20(self):
+ self.set_machine('SS-20')
+ self.archive_extract(self.ASSET_DAY11)
+ self.launch_kernel(self.scratch_file('day11', 'zImage.elf'),
+ wait_for='QEMU advent calendar')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_virtio_balloon.py b/tests/functional/test_virtio_balloon.py
new file mode 100755
index 0000000..5877b6c
--- /dev/null
+++ b/tests/functional/test_virtio_balloon.py
@@ -0,0 +1,178 @@
+#!/usr/bin/env python3
+#
+# virtio-balloon tests
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import time
+
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+from qemu_test import exec_command_and_wait_for_pattern
+
+UNSET_STATS_VALUE = 18446744073709551615
+
+
+class VirtioBalloonx86(QemuSystemTest):
+
+ ASSET_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Server/x86_64/os/images/pxeboot/vmlinuz'),
+ 'd4738d03dbbe083ca610d0821d0a8f1488bebbdccef54ce33e3adb35fda00129')
+
+ ASSET_INITRD = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Server/x86_64/os/images/pxeboot/initrd.img'),
+ '277cd6c7adf77c7e63d73bbb2cded8ef9e2d3a2f100000e92ff1f8396513cd8b')
+
+ ASSET_DISKIMAGE = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Cloud/x86_64/images/Fedora-Cloud-Base-31-1.9.x86_64.qcow2'),
+ 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0')
+
+ DEFAULT_KERNEL_PARAMS = ('root=/dev/vda1 console=ttyS0 net.ifnames=0 '
+ 'rd.rescue quiet')
+
+ def wait_for_console_pattern(self, success_message, vm=None):
+ wait_for_console_pattern(
+ self,
+ success_message,
+ failure_message="Kernel panic - not syncing",
+ vm=vm,
+ )
+
+ def mount_root(self):
+ self.wait_for_console_pattern('Entering emergency mode.')
+ prompt = '# '
+ self.wait_for_console_pattern(prompt)
+
+ # Synchronize on virtio-block driver creating the root device
+ exec_command_and_wait_for_pattern(self,
+ "while ! (dmesg -c | grep vda:) ; do sleep 1 ; done",
+ "vda1")
+
+ exec_command_and_wait_for_pattern(self, 'mount /dev/vda1 /sysroot',
+ prompt)
+ exec_command_and_wait_for_pattern(self, 'chroot /sysroot',
+ prompt)
+ exec_command_and_wait_for_pattern(self, "modprobe virtio-balloon",
+ prompt)
+
+ def assert_initial_stats(self):
+ ret = self.vm.qmp('qom-get',
+ {'path': '/machine/peripheral/balloon',
+ 'property': 'guest-stats'})['return']
+ when = ret.get('last-update')
+ assert when == 0
+ stats = ret.get('stats')
+ for name, val in stats.items():
+ assert val == UNSET_STATS_VALUE
+
+ def assert_running_stats(self, then):
+ # We told the QEMU to refresh stats every 100ms, but
+ # there can be a delay between virtio-ballon driver
+ # being modprobed and seeing the first stats refresh
+ # Retry a few times for robustness under heavy load
+ retries = 10
+ when = 0
+ while when == 0 and retries:
+ ret = self.vm.qmp('qom-get',
+ {'path': '/machine/peripheral/balloon',
+ 'property': 'guest-stats'})['return']
+ when = ret.get('last-update')
+ if when == 0:
+ retries = retries - 1
+ time.sleep(0.5)
+
+ now = time.time()
+
+ assert when > then and when < now
+ stats = ret.get('stats')
+ # Stat we expect this particular Kernel to have set
+ expectData = [
+ "stat-available-memory",
+ "stat-disk-caches",
+ "stat-free-memory",
+ "stat-htlb-pgalloc",
+ "stat-htlb-pgfail",
+ "stat-major-faults",
+ "stat-minor-faults",
+ "stat-swap-in",
+ "stat-swap-out",
+ "stat-total-memory",
+ ]
+ for name, val in stats.items():
+ if name in expectData:
+ assert val != UNSET_STATS_VALUE
+ else:
+ assert val == UNSET_STATS_VALUE
+
+ def test_virtio_balloon_stats(self):
+ self.set_machine('q35')
+ self.require_accelerator("kvm")
+ kernel_path = self.ASSET_KERNEL.fetch()
+ initrd_path = self.ASSET_INITRD.fetch()
+ diskimage_path = self.ASSET_DISKIMAGE.fetch()
+
+ self.vm.set_console()
+ self.vm.add_args("-S")
+ self.vm.add_args("-cpu", "max")
+ self.vm.add_args("-m", "2G")
+ # Slow down BIOS phase with boot menu, so that after a system
+ # reset, we can reliably catch the clean stats again in BIOS
+ # phase before the guest OS launches
+ self.vm.add_args("-boot", "menu=on")
+ self.vm.add_args("-accel", "kvm")
+ self.vm.add_args("-device", "virtio-balloon,id=balloon")
+ self.vm.add_args('-drive',
+ f'file={diskimage_path},if=none,id=drv0,snapshot=on')
+ self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,' +
+ 'drive=drv0,id=virtio-disk0,bootindex=1')
+
+ self.vm.add_args(
+ "-kernel",
+ kernel_path,
+ "-initrd",
+ initrd_path,
+ "-append",
+ self.DEFAULT_KERNEL_PARAMS
+ )
+ self.vm.launch()
+
+ # Poll stats at 100ms
+ self.vm.qmp('qom-set',
+ {'path': '/machine/peripheral/balloon',
+ 'property': 'guest-stats-polling-interval',
+ 'value': 100 })
+
+ # We've not run any guest code yet, neither BIOS or guest,
+ # so stats should be all default values
+ self.assert_initial_stats()
+
+ self.vm.qmp('cont')
+
+ then = time.time()
+ self.mount_root()
+ self.assert_running_stats(then)
+
+ # Race window between these two commands, where we
+ # rely on '-boot menu=on' to (hopefully) ensure we're
+ # still executing the BIOS when QEMU processes the
+ # 'stop', and thus have not loaded the virtio-balloon
+ # driver in the guest
+ self.vm.qmp('system_reset')
+ self.vm.qmp('stop')
+
+ # If the above assumption held, we're in BIOS now and
+ # stats should be all back at their default values
+ self.assert_initial_stats()
+ self.vm.qmp('cont')
+
+ then = time.time()
+ self.mount_root()
+ self.assert_running_stats(then)
+
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_virtio_gpu.py b/tests/functional/test_virtio_gpu.py
index 441cbdc..81c9156 100755
--- a/tests/functional/test_virtio_gpu.py
+++ b/tests/functional/test_virtio_gpu.py
@@ -6,25 +6,19 @@
# later. See the COPYING file in the top-level directory.
-from qemu_test import BUILD_DIR
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
from qemu_test import exec_command_and_wait_for_pattern
from qemu_test import is_readable_executable_file
-from qemu.utils import kvm_available
import os
import socket
import subprocess
-def pick_default_vug_bin():
- relative_path = "./contrib/vhost-user-gpu/vhost-user-gpu"
- if is_readable_executable_file(relative_path):
- return relative_path
-
- bld_dir_path = os.path.join(BUILD_DIR, relative_path)
+def pick_default_vug_bin(test):
+ bld_dir_path = test.build_file("contrib", "vhost-user-gpu", "vhost-user-gpu")
if is_readable_executable_file(bld_dir_path):
return bld_dir_path
@@ -80,15 +74,14 @@ class VirtioGPUx86(QemuSystemTest):
self.wait_for_console_pattern("as init process")
exec_command_and_wait_for_pattern(
- self, "/usr/sbin/modprobe virtio_gpu", ""
+ self, "/usr/sbin/modprobe virtio_gpu", "features: +virgl +edid"
)
- self.wait_for_console_pattern("features: +virgl +edid")
def test_vhost_user_vga_virgl(self):
# FIXME: should check presence of vhost-user-gpu, virgl, memfd etc
self.require_accelerator('kvm')
- vug = pick_default_vug_bin()
+ vug = pick_default_vug_bin(self)
if not vug:
self.skipTest("Could not find vhost-user-gpu")
@@ -102,9 +95,7 @@ class VirtioGPUx86(QemuSystemTest):
os.set_inheritable(qemu_sock.fileno(), True)
os.set_inheritable(vug_sock.fileno(), True)
- self._vug_log_path = os.path.join(
- self.logdir, "vhost-user-gpu.log"
- )
+ self._vug_log_path = self.log_file("vhost-user-gpu.log")
self._vug_log_file = open(self._vug_log_path, "wb")
self.log.info('Complete vhost-user-gpu.log file can be '
'found at %s', self._vug_log_path)
diff --git a/tests/functional/test_virtio_version.py b/tests/functional/test_virtio_version.py
index eb23060..a5ea732 100755
--- a/tests/functional/test_virtio_version.py
+++ b/tests/functional/test_virtio_version.py
@@ -9,8 +9,6 @@ Check compatibility of virtio device types
#
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-import sys
-import os
from qemu.machine import QEMUMachine
from qemu_test import QemuSystemTest
@@ -141,6 +139,7 @@ class VirtioVersionCheck(QemuSystemTest):
def test_conventional_devs(self):
+ self.set_machine('pc')
self.check_all_variants('virtio-net-pci', VIRTIO_NET)
# virtio-blk requires 'driver' parameter
#self.check_all_variants('virtio-blk-pci', VIRTIO_BLOCK)
@@ -167,6 +166,7 @@ class VirtioVersionCheck(QemuSystemTest):
self.assertIn('pci-express-device', ifaces)
def test_modern_only_devs(self):
+ self.set_machine('pc')
self.check_modern_only('virtio-vga', VIRTIO_GPU)
self.check_modern_only('virtio-gpu-pci', VIRTIO_GPU)
self.check_modern_only('virtio-mouse-pci', VIRTIO_INPUT)
diff --git a/tests/avocado/vnc.py b/tests/functional/test_vnc.py
index 862c899..f1dd159 100644..100755
--- a/tests/avocado/vnc.py
+++ b/tests/functional/test_vnc.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Simple functional tests for VNC functionality
#
# Copyright (c) 2018 Red Hat, Inc.
@@ -9,25 +11,13 @@
# later. See the COPYING file in the top-level directory.
import socket
-from typing import List
-from avocado_qemu import QemuSystemTest
+from qemu.machine.machine import VMLaunchFailure
+from qemu_test import QemuSystemTest
+from qemu_test.ports import Ports
VNC_ADDR = '127.0.0.1'
-VNC_PORT_START = 32768
-VNC_PORT_END = VNC_PORT_START + 1024
-
-
-def check_bind(port: int) -> bool:
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
- try:
- sock.bind((VNC_ADDR, port))
- except OSError:
- return False
-
- return True
-
def check_connect(port: int) -> bool:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
@@ -38,32 +28,20 @@ def check_connect(port: int) -> bool:
return True
-
-def find_free_ports(count: int) -> List[int]:
- result = []
- for port in range(VNC_PORT_START, VNC_PORT_END):
- if check_bind(port):
- result.append(port)
- if len(result) >= count:
- break
- assert len(result) == count
- return result
-
-
class Vnc(QemuSystemTest):
- """
- :avocado: tags=vnc,quick
- :avocado: tags=machine:none
- """
- def test_no_vnc(self):
- self.vm.add_args('-nodefaults', '-S')
- self.vm.launch()
- self.assertFalse(self.vm.qmp('query-vnc')['return']['enabled'])
def test_no_vnc_change_password(self):
+ self.set_machine('none')
self.vm.add_args('-nodefaults', '-S')
self.vm.launch()
- self.assertFalse(self.vm.qmp('query-vnc')['return']['enabled'])
+
+ query_vnc_response = self.vm.qmp('query-vnc')
+ if 'error' in query_vnc_response:
+ self.assertEqual(query_vnc_response['error']['class'],
+ 'CommandNotFound')
+ self.skipTest('VNC support not available')
+ self.assertFalse(query_vnc_response['return']['enabled'])
+
set_password_response = self.vm.qmp('change-vnc-password',
password='new_password')
self.assertIn('error', set_password_response)
@@ -72,9 +50,22 @@ class Vnc(QemuSystemTest):
self.assertEqual(set_password_response['error']['desc'],
'Could not set password')
+ def launch_guarded(self):
+ try:
+ self.vm.launch()
+ except VMLaunchFailure as excp:
+ if "-vnc: invalid option" in excp.output:
+ self.skipTest("VNC support not available")
+ elif "Cipher backend does not support DES algorithm" in excp.output:
+ self.skipTest("No cryptographic backend available")
+ else:
+ self.log.info("unhandled launch failure: %s", excp.output)
+ raise excp
+
def test_change_password_requires_a_password(self):
- self.vm.add_args('-nodefaults', '-S', '-vnc', ':0')
- self.vm.launch()
+ self.set_machine('none')
+ self.vm.add_args('-nodefaults', '-S', '-vnc', ':1,to=999')
+ self.launch_guarded()
self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled'])
set_password_response = self.vm.qmp('change-vnc-password',
password='new_password')
@@ -85,20 +76,20 @@ class Vnc(QemuSystemTest):
'Could not set password')
def test_change_password(self):
- self.vm.add_args('-nodefaults', '-S', '-vnc', ':0,password=on')
- self.vm.launch()
+ self.set_machine('none')
+ self.vm.add_args('-nodefaults', '-S', '-vnc', ':1,to=999,password=on')
+ self.launch_guarded()
self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled'])
self.vm.cmd('change-vnc-password',
password='new_password')
- def test_change_listen(self):
- a, b, c = find_free_ports(3)
+ def do_test_change_listen(self, a, b, c):
self.assertFalse(check_connect(a))
self.assertFalse(check_connect(b))
self.assertFalse(check_connect(c))
self.vm.add_args('-nodefaults', '-S', '-vnc', f'{VNC_ADDR}:{a - 5900}')
- self.vm.launch()
+ self.launch_guarded()
self.assertEqual(self.vm.qmp('query-vnc')['return']['service'], str(a))
self.assertTrue(check_connect(a))
self.assertFalse(check_connect(b))
@@ -113,3 +104,13 @@ class Vnc(QemuSystemTest):
self.assertFalse(check_connect(a))
self.assertTrue(check_connect(b))
self.assertTrue(check_connect(c))
+
+ def test_change_listen(self):
+ self.set_machine('none')
+ with Ports() as ports:
+ a, b, c = ports.find_free_ports(3)
+ self.do_test_change_listen(a, b, c)
+
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_x86_64_hotplug_blk.py b/tests/functional/test_x86_64_hotplug_blk.py
new file mode 100755
index 0000000..7ddbfef
--- /dev/null
+++ b/tests/functional/test_x86_64_hotplug_blk.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+#
+# Functional test that hotplugs a virtio blk disk and checks it on a Linux
+# guest
+#
+# Copyright (c) 2021 Red Hat, Inc.
+# Copyright (c) Yandex
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern
+
+
+class HotPlugBlk(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Server/x86_64/os/images/pxeboot/vmlinuz'),
+ 'd4738d03dbbe083ca610d0821d0a8f1488bebbdccef54ce33e3adb35fda00129')
+
+ ASSET_INITRD = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Server/x86_64/os/images/pxeboot/initrd.img'),
+ '277cd6c7adf77c7e63d73bbb2cded8ef9e2d3a2f100000e92ff1f8396513cd8b')
+
+ def blockdev_add(self) -> None:
+ self.vm.cmd('blockdev-add', **{
+ 'driver': 'null-co',
+ 'size': 1073741824,
+ 'node-name': 'disk'
+ })
+
+ def assert_vda(self) -> None:
+ exec_command_and_wait_for_pattern(self, 'while ! test -e /sys/block/vda ;'
+ ' do sleep 0.2 ; done', '# ')
+
+ def assert_no_vda(self) -> None:
+ exec_command_and_wait_for_pattern(self, 'while test -e /sys/block/vda ;'
+ ' do sleep 0.2 ; done', '# ')
+
+ def plug(self) -> None:
+ args = {
+ 'driver': 'virtio-blk-pci',
+ 'drive': 'disk',
+ 'id': 'virtio-disk0',
+ 'bus': 'pci.1',
+ 'addr': '1',
+ }
+
+ self.assert_no_vda()
+ self.vm.cmd('device_add', args)
+ self.wait_for_console_pattern('virtio_blk virtio0: [vda]')
+ self.assert_vda()
+
+ def unplug(self) -> None:
+ self.vm.cmd('device_del', id='virtio-disk0')
+
+ self.vm.event_wait('DEVICE_DELETED', 1.0,
+ match={'data': {'device': 'virtio-disk0'}})
+
+ self.assert_no_vda()
+
+ def test(self) -> None:
+ self.require_accelerator('kvm')
+ self.set_machine('q35')
+
+ self.vm.add_args('-accel', 'kvm')
+ self.vm.add_args('-device', 'pcie-pci-bridge,id=pci.1,bus=pcie.0')
+ self.vm.add_args('-m', '1G')
+ self.vm.add_args('-append', 'console=ttyS0 rd.rescue')
+
+ self.launch_kernel(self.ASSET_KERNEL.fetch(),
+ self.ASSET_INITRD.fetch(),
+ wait_for='Entering emergency mode.')
+ self.wait_for_console_pattern('# ')
+
+ self.blockdev_add()
+
+ self.plug()
+ self.unplug()
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_x86_64_hotplug_cpu.py b/tests/functional/test_x86_64_hotplug_cpu.py
new file mode 100755
index 0000000..7b9200a
--- /dev/null
+++ b/tests/functional/test_x86_64_hotplug_cpu.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python3
+#
+# Functional test that hotplugs a CPU and checks it on a Linux guest
+#
+# Copyright (c) 2021 Red Hat, Inc.
+#
+# Author:
+# Cleber Rosa <crosa@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern
+
+
+class HotPlugCPU(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Server/x86_64/os/images/pxeboot/vmlinuz'),
+ 'd4738d03dbbe083ca610d0821d0a8f1488bebbdccef54ce33e3adb35fda00129')
+
+ ASSET_INITRD = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Server/x86_64/os/images/pxeboot/initrd.img'),
+ '277cd6c7adf77c7e63d73bbb2cded8ef9e2d3a2f100000e92ff1f8396513cd8b')
+
+ def test_hotplug(self):
+
+ self.require_accelerator('kvm')
+ self.vm.add_args('-accel', 'kvm')
+ self.vm.add_args('-cpu', 'Haswell')
+ self.vm.add_args('-smp', '1,sockets=1,cores=2,threads=1,maxcpus=2')
+ self.vm.add_args('-m', '1G')
+ self.vm.add_args('-append', 'console=ttyS0 rd.rescue')
+
+ self.launch_kernel(self.ASSET_KERNEL.fetch(),
+ self.ASSET_INITRD.fetch(),
+ wait_for='Entering emergency mode.')
+ prompt = '# '
+ self.wait_for_console_pattern(prompt)
+
+ exec_command_and_wait_for_pattern(self,
+ 'cd /sys/devices/system/cpu/cpu0',
+ 'cpu0#')
+ exec_command_and_wait_for_pattern(self,
+ 'cd /sys/devices/system/cpu/cpu1',
+ 'No such file or directory')
+
+ self.vm.cmd('device_add',
+ driver='Haswell-x86_64-cpu',
+ id='c1',
+ socket_id=0,
+ core_id=1,
+ thread_id=0)
+ self.wait_for_console_pattern('CPU1 has been hot-added')
+
+ exec_command_and_wait_for_pattern(self,
+ 'cd /sys/devices/system/cpu/cpu1',
+ 'cpu1#')
+
+ exec_command_and_wait_for_pattern(self, 'cd ..', prompt)
+ self.vm.cmd('device_del', id='c1')
+
+ exec_command_and_wait_for_pattern(self,
+ 'while cd /sys/devices/system/cpu/cpu1 ;'
+ ' do sleep 0.2 ; done',
+ 'No such file or directory')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/avocado/kvm_xen_guest.py b/tests/functional/test_x86_64_kvm_xen.py
index f8cb458..a5d4450 100644..100755
--- a/tests/avocado/kvm_xen_guest.py
+++ b/tests/functional/test_x86_64_kvm_xen.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# KVM Xen guest functional tests
#
# Copyright © 2021 Red Hat, Inc.
@@ -9,23 +11,14 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
-
from qemu.machine import machine
-from avocado_qemu import LinuxSSHMixIn
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
+from qemu_test import QemuSystemTest, Asset, exec_command_and_wait_for_pattern
+from qemu_test import wait_for_console_pattern
-class KVMXenGuest(QemuSystemTest, LinuxSSHMixIn):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:q35
- :avocado: tags=accel:kvm
- :avocado: tags=kvm_xen_guest
- """
+class KVMXenGuest(QemuSystemTest):
- KERNEL_DEFAULT = 'printk.time=0 root=/dev/xvda console=ttyS0'
+ KERNEL_DEFAULT = 'printk.time=0 root=/dev/xvda console=ttyS0 quiet'
kernel_path = None
kernel_params = None
@@ -33,28 +26,28 @@ class KVMXenGuest(QemuSystemTest, LinuxSSHMixIn):
# Fetch assets from the kvm-xen-guest subdir of my shared test
# images directory on fileserver.linaro.org where you can find
# build instructions for how they where assembled.
- def get_asset(self, name, sha1):
- base_url = ('https://fileserver.linaro.org/s/'
- 'kE4nCFLdQcoBF9t/download?'
- 'path=%2Fkvm-xen-guest&files=' )
- url = base_url + name
- # use explicit name rather than failing to neatly parse the
- # URL into a unique one
- return self.fetch_asset(name=name, locations=(url), asset_hash=sha1)
+ ASSET_KERNEL = Asset(
+ ('https://fileserver.linaro.org/s/kE4nCFLdQcoBF9t/download?'
+ 'path=%2Fkvm-xen-guest&files=bzImage'),
+ 'ec0ad7bb8c33c5982baee0a75505fe7dbf29d3ff5d44258204d6307c6fe0132a')
+
+ ASSET_ROOTFS = Asset(
+ ('https://fileserver.linaro.org/s/kE4nCFLdQcoBF9t/download?'
+ 'path=%2Fkvm-xen-guest&files=rootfs.ext4'),
+ 'b11045d649006c649c184e93339aaa41a8fe20a1a86620af70323252eb29e40b')
def common_vm_setup(self):
# We also catch lack of KVM_XEN support if we fail to launch
self.require_accelerator("kvm")
+ self.require_netdev('user')
self.vm.set_console()
self.vm.add_args("-accel", "kvm,xen-version=0x4000a,kernel-irqchip=split")
self.vm.add_args("-smp", "2")
- self.kernel_path = self.get_asset("bzImage",
- "367962983d0d32109998a70b45dcee4672d0b045")
- self.rootfs = self.get_asset("rootfs.ext4",
- "f1478401ea4b3fa2ea196396be44315bab2bb5e4")
+ self.kernel_path = self.ASSET_KERNEL.fetch()
+ self.rootfs = self.ASSET_ROOTFS.fetch()
def run_and_check(self):
self.vm.add_args('-kernel', self.kernel_path,
@@ -68,10 +61,10 @@ class KVMXenGuest(QemuSystemTest, LinuxSSHMixIn):
self.vm.launch()
except machine.VMLaunchFailure as e:
if "Xen HVM guest support not present" in e.output:
- self.cancel("KVM Xen support is not present "
- "(need v5.12+ kernel with CONFIG_KVM_XEN)")
+ self.skipTest("KVM Xen support is not present "
+ "(need v5.12+ kernel with CONFIG_KVM_XEN)")
elif "Property 'kvm-accel.xen-version' not found" in e.output:
- self.cancel("QEMU not built with CONFIG_XEN_EMU support")
+ self.skipTest("QEMU not built with CONFIG_XEN_EMU support")
else:
raise e
@@ -79,93 +72,86 @@ class KVMXenGuest(QemuSystemTest, LinuxSSHMixIn):
console_pattern = 'Starting dropbear sshd: OK'
wait_for_console_pattern(self, console_pattern, 'Oops')
self.log.info('sshd ready')
- self.ssh_connect('root', '', False)
- self.ssh_command('cat /proc/cmdline')
- self.ssh_command('dmesg | grep -e "Grant table initialized"')
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cmdline', 'xen')
+ exec_command_and_wait_for_pattern(self, 'dmesg | grep "Grant table"',
+ 'Grant table initialized')
+ wait_for_console_pattern(self, '#', 'Oops')
def test_kvm_xen_guest(self):
- """
- :avocado: tags=kvm_xen_guest
- """
-
self.common_vm_setup()
self.kernel_params = (self.KERNEL_DEFAULT +
' xen_emul_unplug=ide-disks')
self.run_and_check()
- self.ssh_command('grep xen-pirq.*msi /proc/interrupts')
+ exec_command_and_wait_for_pattern(self,
+ 'grep xen-pirq.*msi /proc/interrupts',
+ 'virtio0-output')
def test_kvm_xen_guest_nomsi(self):
- """
- :avocado: tags=kvm_xen_guest_nomsi
- """
-
self.common_vm_setup()
self.kernel_params = (self.KERNEL_DEFAULT +
' xen_emul_unplug=ide-disks pci=nomsi')
self.run_and_check()
- self.ssh_command('grep xen-pirq.* /proc/interrupts')
+ exec_command_and_wait_for_pattern(self,
+ 'grep xen-pirq.* /proc/interrupts',
+ 'virtio0')
def test_kvm_xen_guest_noapic_nomsi(self):
- """
- :avocado: tags=kvm_xen_guest_noapic_nomsi
- """
-
self.common_vm_setup()
self.kernel_params = (self.KERNEL_DEFAULT +
' xen_emul_unplug=ide-disks noapic pci=nomsi')
self.run_and_check()
- self.ssh_command('grep xen-pirq /proc/interrupts')
+ exec_command_and_wait_for_pattern(self,
+ 'grep xen-pirq /proc/interrupts',
+ 'virtio0')
def test_kvm_xen_guest_vapic(self):
- """
- :avocado: tags=kvm_xen_guest_vapic
- """
-
self.common_vm_setup()
self.vm.add_args('-cpu', 'host,+xen-vapic')
self.kernel_params = (self.KERNEL_DEFAULT +
' xen_emul_unplug=ide-disks')
self.run_and_check()
- self.ssh_command('grep xen-pirq /proc/interrupts')
- self.ssh_command('grep PCI-MSI /proc/interrupts')
+ exec_command_and_wait_for_pattern(self,
+ 'grep xen-pirq /proc/interrupts',
+ 'acpi')
+ wait_for_console_pattern(self, '#')
+ exec_command_and_wait_for_pattern(self,
+ 'grep PCI-MSI /proc/interrupts',
+ 'virtio0-output')
def test_kvm_xen_guest_novector(self):
- """
- :avocado: tags=kvm_xen_guest_novector
- """
-
self.common_vm_setup()
self.kernel_params = (self.KERNEL_DEFAULT +
' xen_emul_unplug=ide-disks' +
' xen_no_vector_callback')
self.run_and_check()
- self.ssh_command('grep xen-platform-pci /proc/interrupts')
+ exec_command_and_wait_for_pattern(self,
+ 'grep xen-platform-pci /proc/interrupts',
+ 'fasteoi')
def test_kvm_xen_guest_novector_nomsi(self):
- """
- :avocado: tags=kvm_xen_guest_novector_nomsi
- """
-
self.common_vm_setup()
self.kernel_params = (self.KERNEL_DEFAULT +
' xen_emul_unplug=ide-disks pci=nomsi' +
' xen_no_vector_callback')
self.run_and_check()
- self.ssh_command('grep xen-platform-pci /proc/interrupts')
+ exec_command_and_wait_for_pattern(self,
+ 'grep xen-platform-pci /proc/interrupts',
+ 'IO-APIC')
def test_kvm_xen_guest_novector_noapic(self):
- """
- :avocado: tags=kvm_xen_guest_novector_noapic
- """
-
self.common_vm_setup()
self.kernel_params = (self.KERNEL_DEFAULT +
' xen_emul_unplug=ide-disks' +
' xen_no_vector_callback noapic')
self.run_and_check()
- self.ssh_command('grep xen-platform-pci /proc/interrupts')
+ exec_command_and_wait_for_pattern(self,
+ 'grep xen-platform-pci /proc/interrupts',
+ 'XT-PIC')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_x86_64_replay.py b/tests/functional/test_x86_64_replay.py
new file mode 100755
index 0000000..27287d4
--- /dev/null
+++ b/tests/functional/test_x86_64_replay.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+#
+# Replay test that boots a Linux kernel on x86_64 machines
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from subprocess import check_call, DEVNULL
+
+from qemu_test import Asset, skipFlakyTest, get_qemu_img
+from replay_kernel import ReplayKernelBase
+
+
+class X86Replay(ReplayKernelBase):
+
+ ASSET_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/x86_64/bzImage',
+ 'f57bfc6553bcd6e0a54aab86095bf642b33b5571d14e3af1731b18c87ed5aef8')
+
+ ASSET_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/x86_64/rootfs.ext4.zst',
+ '4b8b2a99117519c5290e1202cb36eb6c7aaba92b357b5160f5970cf5fb78a751')
+
+ def do_test_x86(self, machine, blkdevice, devroot):
+ self.require_netdev('user')
+ self.set_machine(machine)
+ self.cpu="Nehalem"
+ kernel_path = self.ASSET_KERNEL.fetch()
+
+ raw_disk = self.uncompress(self.ASSET_ROOTFS)
+ disk = self.scratch_file('scratch.qcow2')
+ qemu_img = get_qemu_img(self)
+ check_call([qemu_img, 'create', '-f', 'qcow2', '-b', raw_disk,
+ '-F', 'raw', disk], stdout=DEVNULL, stderr=DEVNULL)
+
+ args = ('-drive', 'file=%s,snapshot=on,id=hd0,if=none' % disk,
+ '-drive', 'driver=blkreplay,id=hd0-rr,if=none,image=hd0',
+ '-device', '%s,drive=hd0-rr' % blkdevice,
+ '-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
+ '-device', 'virtio-net,netdev=vnet',
+ '-object', 'filter-replay,id=replay,netdev=vnet')
+
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ f"console=ttyS0 root=/dev/{devroot}")
+ console_pattern = 'Welcome to TuxTest'
+ self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5,
+ args=args)
+
+ @skipFlakyTest('https://gitlab.com/qemu-project/qemu/-/issues/2094')
+ def test_pc(self):
+ self.do_test_x86('pc', 'virtio-blk', 'vda')
+
+ def test_q35(self):
+ self.do_test_x86('q35', 'ide-hd', 'sda')
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/functional/test_x86_64_reverse_debug.py b/tests/functional/test_x86_64_reverse_debug.py
new file mode 100755
index 0000000..d713e91
--- /dev/null
+++ b/tests/functional/test_x86_64_reverse_debug.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Reverse debugging test
+#
+# Copyright (c) 2020 ISP RAS
+#
+# Author:
+# Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from qemu_test import skipIfMissingImports, skipFlakyTest
+from reverse_debugging import ReverseDebugging
+
+
+@skipIfMissingImports('avocado.utils')
+class ReverseDebugging_X86_64(ReverseDebugging):
+
+ REG_PC = 0x10
+ REG_CS = 0x12
+ def get_pc(self, g):
+ return self.get_reg_le(g, self.REG_PC) \
+ + self.get_reg_le(g, self.REG_CS) * 0x10
+
+ @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/2922")
+ def test_x86_64_pc(self):
+ self.set_machine('pc')
+ # start with BIOS only
+ self.reverse_debugging()
+
+
+if __name__ == '__main__':
+ ReverseDebugging.main()
diff --git a/tests/functional/test_x86_64_tuxrun.py b/tests/functional/test_x86_64_tuxrun.py
new file mode 100755
index 0000000..fcbc62b
--- /dev/null
+++ b/tests/functional/test_x86_64_tuxrun.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunX86Test(TuxRunBaselineTest):
+
+ ASSET_X86_64_KERNEL = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/x86_64/bzImage',
+ 'f57bfc6553bcd6e0a54aab86095bf642b33b5571d14e3af1731b18c87ed5aef8')
+ ASSET_X86_64_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/buildroot/20241119/x86_64/rootfs.ext4.zst',
+ '4b8b2a99117519c5290e1202cb36eb6c7aaba92b357b5160f5970cf5fb78a751')
+
+ def test_x86_64(self):
+ self.set_machine('q35')
+ self.cpu="Nehalem"
+ self.root='sda'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_X86_64_KERNEL,
+ rootfs_asset=self.ASSET_X86_64_ROOTFS,
+ drive="driver=ide-hd,bus=ide.0,unit=0")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_xtensa_lx60.py b/tests/functional/test_xtensa_lx60.py
new file mode 100755
index 0000000..147c920
--- /dev/null
+++ b/tests/functional/test_xtensa_lx60.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on an xtensa lx650 machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class XTensaLX60Test(LinuxKernelTest):
+
+ ASSET_DAY02 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day02.tar.xz',
+ '68ff07f9b3fd3df36d015eb46299ba44748e94bfbb2d5295fddc1a8d4a9fd324')
+
+ def test_xtensa_lx60(self):
+ self.set_machine('lx60')
+ self.cpu = 'dc233c'
+ self.archive_extract(self.ASSET_DAY02)
+ self.launch_kernel(self.scratch_file('day02',
+ 'santas-sleigh-ride.elf'),
+ wait_for='QEMU advent calendar')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_xtensa_replay.py b/tests/functional/test_xtensa_replay.py
new file mode 100755
index 0000000..eb00a3b
--- /dev/null
+++ b/tests/functional/test_xtensa_replay.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+#
+# Replay test that boots a Linux kernel on an xtensa lx650 machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from replay_kernel import ReplayKernelBase
+
+
+class XTensaReplay(ReplayKernelBase):
+
+ ASSET_DAY02 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day02.tar.xz',
+ '68ff07f9b3fd3df36d015eb46299ba44748e94bfbb2d5295fddc1a8d4a9fd324')
+
+ def test_replay(self):
+ self.set_machine('lx60')
+ self.cpu = 'dc233c'
+ kernel_path = self.archive_extract(self.ASSET_DAY02,
+ member='day02/santas-sleigh-ride.elf')
+ self.run_rr(kernel_path, self.REPLAY_KERNEL_COMMAND_LINE,
+ 'QEMU advent calendar')
+
+
+if __name__ == '__main__':
+ ReplayKernelBase.main()
diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py
index 368ff8a..75e9c92 100755
--- a/tests/guest-debug/run-test.py
+++ b/tests/guest-debug/run-test.py
@@ -27,11 +27,17 @@ def get_args():
parser.add_argument("--binary", help="Binary to debug",
required=True)
parser.add_argument("--test", help="GDB test script")
+ parser.add_argument('test_args', nargs='*',
+ help="Additional args for GDB test script. "
+ "The args should be preceded by -- to avoid confusion "
+ "with flags for runner script")
parser.add_argument("--gdb", help="The gdb binary to use",
default=None)
parser.add_argument("--gdb-args", help="Additional gdb arguments")
parser.add_argument("--output", help="A file to redirect output to")
parser.add_argument("--stderr", help="A file to redirect stderr to")
+ parser.add_argument("--no-suspend", action="store_true",
+ help="Ask the binary to not wait for GDB connection")
return parser.parse_args()
@@ -69,10 +75,19 @@ if __name__ == '__main__':
# Launch QEMU with binary
if "system" in args.qemu:
+ if args.no_suspend:
+ suspend = ''
+ else:
+ suspend = ' -S'
cmd = f'{args.qemu} {args.qargs} {args.binary}' \
- f' -S -gdb unix:path={socket_name},server=on'
+ f'{suspend} -gdb unix:path={socket_name},server=on'
else:
- cmd = f'{args.qemu} {args.qargs} -g {socket_name} {args.binary}'
+ if args.no_suspend:
+ suspend = ',suspend=n'
+ else:
+ suspend = ''
+ cmd = f'{args.qemu} {args.qargs} -g {socket_name}{suspend}' \
+ f' {args.binary}'
log(output, "QEMU CMD: %s" % (cmd))
inferior = subprocess.Popen(shlex.split(cmd))
@@ -91,6 +106,8 @@ if __name__ == '__main__':
gdb_cmd += " -ex 'target remote %s'" % (socket_name)
# finally the test script itself
if args.test:
+ if args.test_args:
+ gdb_cmd += f" -ex \"py sys.argv={args.test_args}\""
gdb_cmd += " -x %s" % (args.test)
diff --git a/tests/guest-debug/test_gdbstub.py b/tests/guest-debug/test_gdbstub.py
index 46fbf98..4f08089 100644
--- a/tests/guest-debug/test_gdbstub.py
+++ b/tests/guest-debug/test_gdbstub.py
@@ -2,6 +2,7 @@
"""
from __future__ import print_function
+import argparse
import gdb
import os
import sys
@@ -10,6 +11,16 @@ import traceback
fail_count = 0
+def gdb_exit(status):
+ gdb.execute(f"exit {status}")
+
+
+class arg_parser(argparse.ArgumentParser):
+ def exit(self, status=None, message=""):
+ print("Wrong GDB script test argument! " + message)
+ gdb_exit(1)
+
+
def report(cond, msg):
"""Report success/fail of a test"""
if cond:
@@ -33,11 +44,11 @@ def main(test, expected_arch=None):
"connected to {}".format(expected_arch))
except (gdb.error, AttributeError):
print("SKIP: not connected")
- exit(0)
+ gdb_exit(0)
if gdb.parse_and_eval("$pc") == 0:
print("SKIP: PC not set")
- exit(0)
+ gdb_exit(0)
try:
test()
@@ -57,4 +68,4 @@ def main(test, expected_arch=None):
pass
print("All tests complete: {} failures".format(fail_count))
- gdb.execute(f"exit {fail_count}")
+ gdb_exit(fail_count)
diff --git a/tests/include/meson.build b/tests/include/meson.build
index 9abba30..8e8d1ec 100644
--- a/tests/include/meson.build
+++ b/tests/include/meson.build
@@ -13,4 +13,4 @@ test_qapi_outputs_extra = [
test_qapi_files_extra = custom_target('QAPI test (include)',
output: test_qapi_outputs_extra,
input: test_qapi_files,
- command: 'true')
+ command: [python, '-c', ''])
diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci
-Subproject 789b4601bce4e01f43fdb6ad4ce5ab4e4667444
+Subproject 18c4bfe02c467e5639bf9a687139735ccd7a3ff
diff --git a/tests/lcitool/mappings.yml b/tests/lcitool/mappings.yml
index 03b974a..8f0e95e 100644
--- a/tests/lcitool/mappings.yml
+++ b/tests/lcitool/mappings.yml
@@ -1,9 +1,17 @@
mappings:
+ # Too old on Ubuntu 22.04; we install it from cargo instead
+ bindgen:
+ Ubuntu2204:
+
flake8:
OpenSUSELeap15:
meson:
OpenSUSELeap15:
+ # Use Meson from PyPI wherever Rust is enabled
+ Debian:
+ Fedora:
+ Ubuntu:
python3:
OpenSUSELeap15: python311-base
@@ -60,10 +68,15 @@ mappings:
python3-wheel:
OpenSUSELeap15: python311-pip
+ rust:
+ Debian12: rustc-web
+ Ubuntu2204: rustc-1.77
+ Ubuntu2404: rustc-1.77
+
pypi_mappings:
# Request more recent version
meson:
- default: meson==0.63.2
+ default: meson==1.8.1
# Drop packages that need devel headers
python3-numpy:
diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml
index 252e871..c07242f 100644
--- a/tests/lcitool/projects/qemu.yml
+++ b/tests/lcitool/projects/qemu.yml
@@ -3,6 +3,7 @@ packages:
- alsa
- bash
- bc
+ - bindgen
- bison
- brlapi
- bzip2
@@ -42,6 +43,7 @@ packages:
- libc-static
- libcacard
- libcap-ng
+ - libcbor
- libcurl
- libdrm
- libepoxy
@@ -101,6 +103,7 @@ packages:
- python3-tomli
- python3-venv
- rpm2cpio
+ - rust
- sdl2
- sdl2-image
- sed
@@ -119,6 +122,7 @@ packages:
- usbredir
- virglrenderer
- vte
+ - vulkan-tools
- which
- xen
- xorriso
diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh
index ac803e3..d3488b2 100755
--- a/tests/lcitool/refresh
+++ b/tests/lcitool/refresh
@@ -116,6 +116,42 @@ debian12_extras = [
"ENV QEMU_CONFIGURE_OPTS --enable-netmap\n"
]
+# Based on the hub.docker.com/library/rust Dockerfiles
+fedora_rustup_nightly_extras = [
+ "RUN dnf install -y wget\n",
+ "ENV RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo\n",
+ "ENV RUSTC=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc\n",
+ "ENV RUSTDOC=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustdoc\n",
+ "ENV CARGO=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo\n",
+ "RUN set -eux && \\\n",
+ " rustArch='x86_64-unknown-linux-gnu' && \\\n",
+ " rustupSha256='6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d' && \\\n",
+ ' url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" && \\\n',
+ ' wget "$url" && \\\n',
+ ' echo "${rustupSha256} *rustup-init" | sha256sum -c - && \\\n',
+ " chmod +x rustup-init && \\\n",
+ " ./rustup-init -y --no-modify-path --profile default --default-toolchain nightly --default-host ${rustArch} && \\\n",
+ " chmod -R a+w $RUSTUP_HOME $CARGO_HOME && \\\n",
+ " /usr/local/cargo/bin/rustup --version && \\\n",
+ " /usr/local/cargo/bin/rustup run nightly cargo --version && \\\n",
+ " /usr/local/cargo/bin/rustup run nightly rustc --version && \\\n",
+ ' test "$CARGO" = "$(/usr/local/cargo/bin/rustup +nightly which cargo)" && \\\n',
+ ' test "$RUSTDOC" = "$(/usr/local/cargo/bin/rustup +nightly which rustdoc)" && \\\n',
+ ' test "$RUSTC" = "$(/usr/local/cargo/bin/rustup +nightly which rustc)"\n',
+ 'ENV PATH=$CARGO_HOME/bin:$PATH\n',
+ 'RUN /usr/local/cargo/bin/rustup run nightly cargo install bindgen-cli\n',
+ 'RUN $CARGO --list\n',
+]
+
+ubuntu2204_rust_extras = [
+ "ENV RUSTC=/usr/bin/rustc-1.77\n",
+ "ENV RUSTDOC=/usr/bin/rustdoc-1.77\n",
+ "ENV CARGO_HOME=/usr/local/cargo\n",
+ 'ENV PATH=$CARGO_HOME/bin:$PATH\n',
+ "RUN DEBIAN_FRONTEND=noninteractive eatmydata \\\n",
+ " apt install -y --no-install-recommends cargo\n",
+ 'RUN cargo install bindgen-cli\n',
+]
def cross_build(prefix, targets):
conf = "ENV QEMU_CONFIGURE_OPTS --cross-prefix=%s\n" % (prefix)
@@ -131,13 +167,20 @@ try:
#
# Standard native builds
#
- generate_dockerfile("alpine", "alpine-319")
+ generate_dockerfile("alpine", "alpine-321")
generate_dockerfile("centos9", "centos-stream-9")
generate_dockerfile("debian", "debian-12",
trailer="".join(debian12_extras))
generate_dockerfile("fedora", "fedora-40")
generate_dockerfile("opensuse-leap", "opensuse-leap-15")
- generate_dockerfile("ubuntu2204", "ubuntu-2204")
+ generate_dockerfile("ubuntu2204", "ubuntu-2204",
+ trailer="".join(ubuntu2204_rust_extras))
+
+ #
+ # Non-fatal Rust-enabled build
+ #
+ generate_dockerfile("fedora-rust-nightly", "fedora-40",
+ trailer="".join(fedora_rustup_nightly_extras))
#
# Cross compiling builds
@@ -154,30 +197,24 @@ try:
trailer=cross_build("aarch64-linux-gnu-",
"aarch64-softmmu,aarch64-linux-user"))
- # migration to bookworm stalled: https://lists.debian.org/debian-arm/2023/09/msg00006.html
- generate_dockerfile("debian-armel-cross", "debian-11",
- cross="armv6l",
- trailer=cross_build("arm-linux-gnueabi-",
- "arm-softmmu,arm-linux-user,armeb-linux-user"))
-
generate_dockerfile("debian-armhf-cross", "debian-12",
cross="armv7l",
trailer=cross_build("arm-linux-gnueabihf-",
"arm-softmmu,arm-linux-user"))
- generate_dockerfile("debian-i686-cross", "debian-11",
+ generate_dockerfile("debian-i686-cross", "debian-12",
cross="i686",
trailer=cross_build("i686-linux-gnu-",
"x86_64-softmmu,"
"x86_64-linux-user,"
"i386-softmmu,i386-linux-user"))
- generate_dockerfile("debian-mips64el-cross", "debian-11",
+ generate_dockerfile("debian-mips64el-cross", "debian-12",
cross="mips64el",
trailer=cross_build("mips64el-linux-gnuabi64-",
"mips64el-softmmu,mips64el-linux-user"))
- generate_dockerfile("debian-mipsel-cross", "debian-11",
+ generate_dockerfile("debian-mipsel-cross", "debian-12",
cross="mipsel",
trailer=cross_build("mipsel-linux-gnu-",
"mipsel-softmmu,mipsel-linux-user"))
@@ -187,7 +224,9 @@ try:
trailer=cross_build("powerpc64le-linux-gnu-",
"ppc64-softmmu,ppc64-linux-user"))
- generate_dockerfile("debian-riscv64-cross", "debian-sid",
+ # while not yet a release architecture the packages are still
+ # build while part of testing
+ generate_dockerfile("debian-riscv64-cross", "debian-13",
project="qemu-minimal",
cross="riscv64",
trailer=cross_build("riscv64-linux-gnu-",
@@ -207,14 +246,13 @@ try:
#
# Cirrus packages lists for GitLab
#
- generate_cirrus("freebsd-13")
- generate_cirrus("macos-13")
+ generate_cirrus("freebsd-14")
generate_cirrus("macos-14")
#
# VM packages lists
#
- generate_pkglist("freebsd", "freebsd-13")
+ generate_pkglist("freebsd", "freebsd-14")
#
# Ansible package lists
diff --git a/tests/meson.build b/tests/meson.build
index 907a4c1..c596192 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -16,6 +16,8 @@ test_qapi_outputs = [
'test-qapi-events-sub-sub-module.h',
'test-qapi-events.c',
'test-qapi-events.h',
+ 'test-qapi-features.c',
+ 'test-qapi-features.h',
'test-qapi-init-commands.c',
'test-qapi-init-commands.h',
'test-qapi-introspect.c',
@@ -84,5 +86,5 @@ endif
subdir('unit')
subdir('qapi-schema')
subdir('qtest')
-subdir('migration')
+subdir('migration-stress')
subdir('functional')
diff --git a/tests/migration/guestperf-batch.py b/tests/migration-stress/guestperf-batch.py
index 9485eef..9485eef 100755
--- a/tests/migration/guestperf-batch.py
+++ b/tests/migration-stress/guestperf-batch.py
diff --git a/tests/migration/guestperf-plot.py b/tests/migration-stress/guestperf-plot.py
index 32977b4..32977b4 100755
--- a/tests/migration/guestperf-plot.py
+++ b/tests/migration-stress/guestperf-plot.py
diff --git a/tests/migration/guestperf.py b/tests/migration-stress/guestperf.py
index 07182f2..07182f2 100755
--- a/tests/migration/guestperf.py
+++ b/tests/migration-stress/guestperf.py
diff --git a/tests/migration/guestperf/__init__.py b/tests/migration-stress/guestperf/__init__.py
index e69de29..e69de29 100644
--- a/tests/migration/guestperf/__init__.py
+++ b/tests/migration-stress/guestperf/__init__.py
diff --git a/tests/migration/guestperf/comparison.py b/tests/migration-stress/guestperf/comparison.py
index 42cc037..dee3ac2 100644
--- a/tests/migration/guestperf/comparison.py
+++ b/tests/migration-stress/guestperf/comparison.py
@@ -127,7 +127,7 @@ COMPARISONS = [
# varying numbers of channels
Comparison("compr-multifd", scenarios = [
Scenario("compr-multifd-channels-4",
- multifd=True, multifd_channels=2),
+ multifd=True, multifd_channels=4),
Scenario("compr-multifd-channels-8",
multifd=True, multifd_channels=8),
Scenario("compr-multifd-channels-32",
@@ -158,4 +158,17 @@ COMPARISONS = [
Scenario("compr-dirty-limit-50MB",
dirty_limit=True, vcpu_dirty_limit=50),
]),
+
+ # Looking at effect of multifd with
+ # different compression algorithms
+ Comparison("compr-multifd-compression", scenarios = [
+ Scenario("compr-multifd-compression-zlib",
+ multifd=True, multifd_channels=2, multifd_compression="zlib"),
+ Scenario("compr-multifd-compression-zstd",
+ multifd=True, multifd_channels=2, multifd_compression="zstd"),
+ Scenario("compr-multifd-compression-qpl",
+ multifd=True, multifd_channels=2, multifd_compression="qpl"),
+ Scenario("compr-multifd-compression-uadk",
+ multifd=True, multifd_channels=2, multifd_compression="uadk"),
+ ]),
]
diff --git a/tests/migration/guestperf/engine.py b/tests/migration-stress/guestperf/engine.py
index 608d727..d8462db 100644
--- a/tests/migration/guestperf/engine.py
+++ b/tests/migration-stress/guestperf/engine.py
@@ -24,13 +24,15 @@ import sys
import time
from guestperf.progress import Progress, ProgressStats
-from guestperf.report import Report
+from guestperf.report import Report, ReportResult
from guestperf.timings import TimingRecord, Timings
sys.path.append(os.path.join(os.path.dirname(__file__),
'..', '..', '..', 'python'))
from qemu.machine import QEMUMachine
+# multifd supported compression algorithms
+MULTIFD_CMP_ALGS = ("zlib", "zstd", "qpl", "uadk")
class Engine(object):
@@ -106,7 +108,8 @@ class Engine(object):
info.get("dirty-limit-ring-full-time", 0),
)
- def _migrate(self, hardware, scenario, src, dst, connect_uri):
+ def _migrate(self, hardware, scenario, src,
+ dst, connect_uri, defer_migrate):
src_qemu_time = []
src_vcpu_time = []
src_pid = src.get_pid()
@@ -190,6 +193,12 @@ class Engine(object):
scenario._compression_xbzrle_cache))
if scenario._multifd:
+ if (scenario._multifd_compression and
+ (scenario._multifd_compression not in MULTIFD_CMP_ALGS)):
+ raise Exception("unsupported multifd compression "
+ "algorithm: %s" %
+ scenario._multifd_compression)
+
resp = src.cmd("migrate-set-capabilities",
capabilities = [
{ "capability": "multifd",
@@ -205,6 +214,12 @@ class Engine(object):
resp = dst.cmd("migrate-set-parameters",
multifd_channels=scenario._multifd_channels)
+ if scenario._multifd_compression:
+ resp = src.cmd("migrate-set-parameters",
+ multifd_compression=scenario._multifd_compression)
+ resp = dst.cmd("migrate-set-parameters",
+ multifd_compression=scenario._multifd_compression)
+
if scenario._dirty_limit:
if not hardware._dirty_ring_size:
raise Exception("dirty ring size must be configured when "
@@ -220,6 +235,8 @@ class Engine(object):
resp = src.cmd("migrate-set-parameters",
vcpu_dirty_limit=scenario._vcpu_dirty_limit)
+ if defer_migrate:
+ resp = dst.cmd("migrate-incoming", uri=connect_uri)
resp = src.cmd("migrate", uri=connect_uri)
post_copy = False
@@ -259,7 +276,11 @@ class Engine(object):
src_vcpu_time.extend(self._vcpu_timing(src_pid, src_threads))
sleep_secs -= 1
- return [progress_history, src_qemu_time, src_vcpu_time]
+ result = ReportResult()
+ if progress._status == "completed" and not paused:
+ result = ReportResult(True)
+
+ return [progress_history, src_qemu_time, src_vcpu_time, result]
if self._verbose and (loop % 20) == 0:
print("Iter %d: remain %5dMB of %5dMB (total %5dMB @ %5dMb/sec)" % (
@@ -373,11 +394,14 @@ class Engine(object):
def _get_src_args(self, hardware):
return self._get_common_args(hardware)
- def _get_dst_args(self, hardware, uri):
+ def _get_dst_args(self, hardware, uri, defer_migrate):
tunnelled = False
if self._dst_host != "localhost":
tunnelled = True
argv = self._get_common_args(hardware, tunnelled)
+
+ if defer_migrate:
+ return argv + ["-incoming", "defer"]
return argv + ["-incoming", uri]
@staticmethod
@@ -424,6 +448,7 @@ class Engine(object):
def run(self, hardware, scenario, result_dir=os.getcwd()):
abs_result_dir = os.path.join(result_dir, scenario._name)
+ defer_migrate = False
if self._transport == "tcp":
uri = "tcp:%s:9000" % self._dst_host
@@ -439,6 +464,9 @@ class Engine(object):
except:
pass
+ if scenario._multifd:
+ defer_migrate = True
+
if self._dst_host != "localhost":
dstmonaddr = ("localhost", 9001)
else:
@@ -452,7 +480,7 @@ class Engine(object):
monitor_address=srcmonaddr)
dst = QEMUMachine(self._binary,
- args=self._get_dst_args(hardware, uri),
+ args=self._get_dst_args(hardware, uri, defer_migrate),
wrapper=self._get_dst_wrapper(hardware),
name="qemu-dst-%d" % os.getpid(),
monitor_address=dstmonaddr)
@@ -461,10 +489,12 @@ class Engine(object):
src.launch()
dst.launch()
- ret = self._migrate(hardware, scenario, src, dst, uri)
+ ret = self._migrate(hardware, scenario, src,
+ dst, uri, defer_migrate)
progress_history = ret[0]
qemu_timings = ret[1]
vcpu_timings = ret[2]
+ result = ret[3]
if uri[0:5] == "unix:" and os.path.exists(uri[5:]):
os.remove(uri[5:])
@@ -484,6 +514,7 @@ class Engine(object):
Timings(self._get_timings(src) + self._get_timings(dst)),
Timings(qemu_timings),
Timings(vcpu_timings),
+ result,
self._binary, self._dst_host, self._kernel,
self._initrd, self._transport, self._sleep)
except Exception as e:
diff --git a/tests/migration/guestperf/hardware.py b/tests/migration-stress/guestperf/hardware.py
index f779cc0..f779cc0 100644
--- a/tests/migration/guestperf/hardware.py
+++ b/tests/migration-stress/guestperf/hardware.py
diff --git a/tests/migration/guestperf/plot.py b/tests/migration-stress/guestperf/plot.py
index 30b3f66..30b3f66 100644
--- a/tests/migration/guestperf/plot.py
+++ b/tests/migration-stress/guestperf/plot.py
diff --git a/tests/migration/guestperf/progress.py b/tests/migration-stress/guestperf/progress.py
index d490584..d490584 100644
--- a/tests/migration/guestperf/progress.py
+++ b/tests/migration-stress/guestperf/progress.py
diff --git a/tests/migration/guestperf/report.py b/tests/migration-stress/guestperf/report.py
index 1efd40c..e135e01 100644
--- a/tests/migration/guestperf/report.py
+++ b/tests/migration-stress/guestperf/report.py
@@ -24,6 +24,22 @@ from guestperf.scenario import Scenario
from guestperf.progress import Progress
from guestperf.timings import Timings
+class ReportResult(object):
+
+ def __init__(self, success=False):
+ self._success = success
+
+ def serialize(self):
+ return {
+ "success": self._success,
+ }
+
+ @classmethod
+ def deserialize(cls, data):
+ return cls(
+ data["success"])
+
+
class Report(object):
def __init__(self,
@@ -33,6 +49,7 @@ class Report(object):
guest_timings,
qemu_timings,
vcpu_timings,
+ result,
binary,
dst_host,
kernel,
@@ -46,6 +63,7 @@ class Report(object):
self._guest_timings = guest_timings
self._qemu_timings = qemu_timings
self._vcpu_timings = vcpu_timings
+ self._result = result
self._binary = binary
self._dst_host = dst_host
self._kernel = kernel
@@ -61,6 +79,7 @@ class Report(object):
"guest_timings": self._guest_timings.serialize(),
"qemu_timings": self._qemu_timings.serialize(),
"vcpu_timings": self._vcpu_timings.serialize(),
+ "result": self._result.serialize(),
"binary": self._binary,
"dst_host": self._dst_host,
"kernel": self._kernel,
@@ -78,6 +97,7 @@ class Report(object):
Timings.deserialize(data["guest_timings"]),
Timings.deserialize(data["qemu_timings"]),
Timings.deserialize(data["vcpu_timings"]),
+ ReportResult.deserialize(data["result"]),
data["binary"],
data["dst_host"],
data["kernel"],
diff --git a/tests/migration/guestperf/scenario.py b/tests/migration-stress/guestperf/scenario.py
index 154c4f5..4be7faf 100644
--- a/tests/migration/guestperf/scenario.py
+++ b/tests/migration-stress/guestperf/scenario.py
@@ -30,7 +30,7 @@ class Scenario(object):
auto_converge=False, auto_converge_step=10,
compression_mt=False, compression_mt_threads=1,
compression_xbzrle=False, compression_xbzrle_cache=10,
- multifd=False, multifd_channels=2,
+ multifd=False, multifd_channels=2, multifd_compression="",
dirty_limit=False, x_vcpu_dirty_limit_period=500,
vcpu_dirty_limit=1):
@@ -61,6 +61,7 @@ class Scenario(object):
self._multifd = multifd
self._multifd_channels = multifd_channels
+ self._multifd_compression = multifd_compression
self._dirty_limit = dirty_limit
self._x_vcpu_dirty_limit_period = x_vcpu_dirty_limit_period
@@ -85,6 +86,7 @@ class Scenario(object):
"compression_xbzrle_cache": self._compression_xbzrle_cache,
"multifd": self._multifd,
"multifd_channels": self._multifd_channels,
+ "multifd_compression": self._multifd_compression,
"dirty_limit": self._dirty_limit,
"x_vcpu_dirty_limit_period": self._x_vcpu_dirty_limit_period,
"vcpu_dirty_limit": self._vcpu_dirty_limit,
@@ -109,4 +111,5 @@ class Scenario(object):
data["compression_xbzrle"],
data["compression_xbzrle_cache"],
data["multifd"],
- data["multifd_channels"])
+ data["multifd_channels"],
+ data["multifd_compression"])
diff --git a/tests/migration/guestperf/shell.py b/tests/migration-stress/guestperf/shell.py
index c85d89e..63bbe32 100644
--- a/tests/migration/guestperf/shell.py
+++ b/tests/migration-stress/guestperf/shell.py
@@ -46,7 +46,8 @@ class BaseShell(object):
parser.add_argument("--binary", dest="binary", default="/usr/bin/qemu-system-x86_64")
parser.add_argument("--dst-host", dest="dst_host", default="localhost")
parser.add_argument("--kernel", dest="kernel", default="/boot/vmlinuz-%s" % platform.release())
- parser.add_argument("--initrd", dest="initrd", default="tests/migration/initrd-stress.img")
+ parser.add_argument("--initrd", dest="initrd",
+ default="tests/migration-stress/initrd-stress.img")
parser.add_argument("--transport", dest="transport", default="unix")
@@ -130,6 +131,8 @@ class Shell(BaseShell):
action="store_true")
parser.add_argument("--multifd-channels", dest="multifd_channels",
default=2, type=int)
+ parser.add_argument("--multifd-compression", dest="multifd_compression",
+ default="")
parser.add_argument("--dirty-limit", dest="dirty_limit", default=False,
action="store_true")
@@ -166,6 +169,7 @@ class Shell(BaseShell):
multifd=args.multifd,
multifd_channels=args.multifd_channels,
+ multifd_compression=args.multifd_compression,
dirty_limit=args.dirty_limit,
x_vcpu_dirty_limit_period=\
diff --git a/tests/migration/guestperf/timings.py b/tests/migration-stress/guestperf/timings.py
index 2374010..2374010 100644
--- a/tests/migration/guestperf/timings.py
+++ b/tests/migration-stress/guestperf/timings.py
diff --git a/tests/migration/initrd-stress.sh b/tests/migration-stress/initrd-stress.sh
index 0f20ac2..0f20ac2 100755
--- a/tests/migration/initrd-stress.sh
+++ b/tests/migration-stress/initrd-stress.sh
diff --git a/tests/migration/meson.build b/tests/migration-stress/meson.build
index a91aa61..a91aa61 100644
--- a/tests/migration/meson.build
+++ b/tests/migration-stress/meson.build
diff --git a/tests/migration/stress.c b/tests/migration-stress/stress.c
index 88acf8d..88acf8d 100644
--- a/tests/migration/stress.c
+++ b/tests/migration-stress/stress.c
diff --git a/tests/qapi-schema/alternate-array.out b/tests/qapi-schema/alternate-array.out
index a657d85..2f30973 100644
--- a/tests/qapi-schema/alternate-array.out
+++ b/tests/qapi-schema/alternate-array.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
index ce4f6a4..937070c 100644
--- a/tests/qapi-schema/comments.out
+++ b/tests/qapi-schema/comments.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index f64bf38..14b808f 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -12,6 +12,10 @@
##
##
+# Just text, no heading.
+##
+
+##
# == Subsection
#
# *with emphasis*
@@ -208,7 +212,7 @@
#
# -> "this example"
#
-# <- "has no title"
+# <- ... has no title ...
##
{ 'command': 'cmd-boxed', 'boxed': true,
'data': 'Object',
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 6d24f11..dc8352e 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
@@ -59,6 +58,9 @@ doc freeform
= Section
doc freeform
body=
+Just text, no heading.
+doc freeform
+ body=
== Subsection
*with emphasis*
@@ -111,7 +113,7 @@ The _one_ {and only}, description on the same line
Also _one_ {and only}
feature=enum-member-feat
a member feature
- section=None
+ section=Plain
@two is undocumented
doc symbol=Base
body=
@@ -169,15 +171,15 @@ description starts on the same line
a feature
feature=cmd-feat2
another feature
- section=None
+ section=Plain
.. note:: @arg3 is undocumented
section=Returns
@Object
section=Errors
some
- section=TODO
+ section=Todo
frobnicate
- section=None
+ section=Plain
.. admonition:: Notes
- Lorem ipsum dolor sit amet
@@ -210,12 +212,12 @@ If you're bored enough to read this, go see a video of boxed cats
a feature
feature=cmd-feat2
another feature
- section=None
+ section=Plain
.. qmp-example::
-> "this example"
- <- "has no title"
+ <- ... has no title ...
doc symbol=EVT_BOXED
body=
diff --git a/tests/qapi-schema/doc-good.txt b/tests/qapi-schema/doc-good.txt
index cb37db6..17a1d56 100644
--- a/tests/qapi-schema/doc-good.txt
+++ b/tests/qapi-schema/doc-good.txt
@@ -264,7 +264,7 @@ Example::
-> "this example"
- <- "has no title"
+ <- ... has no title ...
"EVT_BOXED" (Event)
diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out
index 3feb3f6..d1981f8 100644
--- a/tests/qapi-schema/empty.out
+++ b/tests/qapi-schema/empty.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/features-too-many.err b/tests/qapi-schema/features-too-many.err
new file mode 100644
index 0000000..bbbd6e5
--- /dev/null
+++ b/tests/qapi-schema/features-too-many.err
@@ -0,0 +1,2 @@
+features-too-many.json: In command 'go-fish':
+features-too-many.json:2: Maximum of 64 schema features is permitted
diff --git a/tests/qapi-schema/features-too-many.json b/tests/qapi-schema/features-too-many.json
new file mode 100644
index 0000000..aab0a0b
--- /dev/null
+++ b/tests/qapi-schema/features-too-many.json
@@ -0,0 +1,13 @@
+# Max 64 features, with 2 specials, so 63rd custom is invalid
+{ 'command': 'go-fish',
+ 'features': [
+ 'f00', 'f01', 'f02', 'f03', 'f04', 'f05', 'f06', 'f07',
+ 'f08', 'f09', 'f0a', 'f0b', 'f0c', 'f0d', 'f0e', 'f0f',
+ 'f10', 'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17',
+ 'f18', 'f19', 'f1a', 'f1b', 'f1c', 'f1d', 'f1e', 'f1f',
+ 'f20', 'f21', 'f22', 'f23', 'f24', 'f25', 'f26', 'f27',
+ 'f28', 'f29', 'f2a', 'f2b', 'f2c', 'f2d', 'f2e', 'f2f',
+ 'f30', 'f31', 'f32', 'f33', 'f34', 'f35', 'f36', 'f37',
+ 'f38', 'f39', 'f3a', 'f3b', 'f3c', 'f3d', 'f3e'
+ ]
+}
diff --git a/tests/qapi-schema/features-too-many.out b/tests/qapi-schema/features-too-many.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/qapi-schema/features-too-many.out
diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out
index 16dbd9b..c564d27 100644
--- a/tests/qapi-schema/include-repetition.out
+++ b/tests/qapi-schema/include-repetition.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out
index 48e923b..ec8200a 100644
--- a/tests/qapi-schema/include-simple.out
+++ b/tests/qapi-schema/include-simple.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index 6a30ded..a7c22c3 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build
index 0f479d9..9577178 100644
--- a/tests/qapi-schema/meson.build
+++ b/tests/qapi-schema/meson.build
@@ -105,6 +105,7 @@ schemas = [
'event-case.json',
'event-member-invalid-dict.json',
'event-nest-struct.json',
+ 'features-too-many.json',
'features-bad-type.json',
'features-deprecated-type.json',
'features-duplicate-name.json',
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index e2f0981..4617eb4 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 7e3f9f4..4be9302 100755
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -96,17 +96,8 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
@staticmethod
def _print_if(ifcond, indent=4):
- # TODO Drop this hack after replacing OrderedDict by plain
- # dict (requires Python 3.7)
- def _massage(subcond):
- if isinstance(subcond, str):
- return subcond
- if isinstance(subcond, list):
- return [_massage(val) for val in subcond]
- return {key: _massage(val) for key, val in subcond.items()}
-
if ifcond.is_present():
- print('%sif %s' % (' ' * indent, _massage(ifcond.ifcond)))
+ print('%sif %s' % (' ' * indent, ifcond.ifcond))
@classmethod
def _print_features(cls, features, indent=4):
@@ -131,7 +122,7 @@ def test_frontend(fname):
for feat, section in doc.features.items():
print(' feature=%s\n%s' % (feat, section.text))
for section in doc.sections:
- print(' section=%s\n%s' % (section.tag, section.text))
+ print(' section=%s\n%s' % (section.kind, section.text))
def open_test_result(dir_name, file_name, update):
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
index 98d17b1..8452845 100755
--- a/tests/qemu-iotests/041
+++ b/tests/qemu-iotests/041
@@ -1100,10 +1100,8 @@ class TestRepairQuorum(iotests.QMPTestCase):
# Check the full error message now
self.vm.shutdown()
- log = self.vm.get_log()
- log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log)
+ log = iotests.filter_qtest(self.vm.get_log())
log = re.sub(r'^Formatting.*\n', '', log)
- log = re.sub(r'\n\[I \+\d+\.\d+\] CLOSED\n?$', '', log)
log = re.sub(r'^%s: ' % os.path.basename(iotests.qemu_prog), '', log)
self.assertEqual(log,
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
index 7e10c5f..f19b532 100644
--- a/tests/qemu-iotests/051.pc.out
+++ b/tests/qemu-iotests/051.pc.out
@@ -181,7 +181,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-scsi,id=virtio-scsi1 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) QEMU_PROG: -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on: Cannot change iothread of active block backend
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-blk-pci,drive=disk,iothread=thread0,share-rw=on
QEMU X.Y.Z monitor - type 'help' for more information
diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106
index ae0fc46..5554843 100755
--- a/tests/qemu-iotests/106
+++ b/tests/qemu-iotests/106
@@ -40,6 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt raw
_supported_proto file fuse
_supported_os Linux
+_require_disk_usage
# in kB
CREATION_SIZE=128
diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125
index 46279d6..708e7c5 100755
--- a/tests/qemu-iotests/125
+++ b/tests/qemu-iotests/125
@@ -35,7 +35,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
get_image_size_on_host()
{
- echo $(($(stat -c '%b * %B' "$TEST_IMG_FILE")))
+ disk_usage "$TEST_IMG_FILE"
}
# get standard environment and filters
diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165
index b24907a..b3b1709 100755
--- a/tests/qemu-iotests/165
+++ b/tests/qemu-iotests/165
@@ -82,9 +82,7 @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase):
self.vm.shutdown()
#catch 'Persistent bitmaps are lost' possible error
- log = self.vm.get_log()
- log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log)
- log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log)
+ log = iotests.filter_qtest(self.vm.get_log())
if log:
print(log)
diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out
index 07eebf3..146fc72 100644
--- a/tests/qemu-iotests/172.out
+++ b/tests/qemu-iotests/172.out
@@ -68,9 +68,6 @@ floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -125,9 +122,6 @@ ide1-cd0: [not inserted]
floppy0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -183,9 +177,6 @@ floppy1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -265,9 +256,6 @@ floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -322,9 +310,6 @@ ide1-cd0: [not inserted]
floppy0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -380,9 +365,6 @@ floppy1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -422,9 +404,6 @@ none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -461,9 +440,6 @@ none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -519,9 +495,6 @@ none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -586,9 +559,6 @@ none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -644,9 +614,6 @@ none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -702,9 +669,6 @@ none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -760,9 +724,6 @@ none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -827,9 +788,6 @@ none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -885,9 +843,6 @@ none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -930,9 +885,6 @@ none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -1106,9 +1058,6 @@ none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -1145,9 +1094,6 @@ none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -1187,9 +1133,6 @@ none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
@@ -1226,9 +1169,6 @@ none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[N]
Removable device: not locked, tray closed
-
-sd0: [not inserted]
- Removable device: not locked, tray closed
(qemu) quit
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
index f74f053..bbbf550 100755
--- a/tests/qemu-iotests/175
+++ b/tests/qemu-iotests/175
@@ -77,6 +77,7 @@ _supported_os Linux
_default_cache_mode none
_supported_cache_modes none directsync
+_require_disk_usage
size=$((1 * 1024 * 1024))
diff --git a/tests/qemu-iotests/184.out b/tests/qemu-iotests/184.out
index e8f631f..52692b6 100644
--- a/tests/qemu-iotests/184.out
+++ b/tests/qemu-iotests/184.out
@@ -26,6 +26,7 @@ Testing:
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"backing-image": {
"virtual-size": 1073741824,
@@ -59,6 +60,7 @@ Testing:
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 1073741824,
"filename": "null-co://",
diff --git a/tests/qemu-iotests/191.out b/tests/qemu-iotests/191.out
index c3309e4..2a72ca7 100644
--- a/tests/qemu-iotests/191.out
+++ b/tests/qemu-iotests/191.out
@@ -114,6 +114,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"backing-image": {
"virtual-size": 67108864,
@@ -155,6 +156,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 197120,
"filename": "TEST_DIR/t.IMGFMT.ovl2",
@@ -183,6 +185,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"backing-image": {
"virtual-size": 67108864,
@@ -224,6 +227,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 197120,
"filename": "TEST_DIR/t.IMGFMT",
@@ -252,6 +256,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"backing-image": {
"virtual-size": 67108864,
@@ -293,6 +298,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 393216,
"filename": "TEST_DIR/t.IMGFMT.mid",
@@ -321,6 +327,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 67108864,
"filename": "TEST_DIR/t.IMGFMT.base",
@@ -350,6 +357,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 393216,
"filename": "TEST_DIR/t.IMGFMT.base",
@@ -521,6 +529,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"backing-image": {
"virtual-size": 67108864,
@@ -562,6 +571,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 197120,
"filename": "TEST_DIR/t.IMGFMT.ovl2",
@@ -590,6 +600,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"backing-image": {
"backing-image": {
@@ -642,6 +653,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 197120,
"filename": "TEST_DIR/t.IMGFMT.ovl3",
@@ -670,6 +682,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 67108864,
"filename": "TEST_DIR/t.IMGFMT.base",
@@ -699,6 +712,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 393216,
"filename": "TEST_DIR/t.IMGFMT.base",
@@ -727,6 +741,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"backing-image": {
"virtual-size": 67108864,
@@ -768,6 +783,7 @@ wrote 65536/65536 bytes at offset 1048576
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 197120,
"filename": "TEST_DIR/t.IMGFMT",
diff --git a/tests/qemu-iotests/194 b/tests/qemu-iotests/194
index c0ce82d..e114c0b 100755
--- a/tests/qemu-iotests/194
+++ b/tests/qemu-iotests/194
@@ -34,6 +34,7 @@ with iotests.FilePath('source.img') as source_img_path, \
img_size = '1G'
iotests.qemu_img_create('-f', iotests.imgfmt, source_img_path, img_size)
+ iotests.qemu_io('-f', iotests.imgfmt, '-c', 'write 512M 1M', source_img_path)
iotests.qemu_img_create('-f', iotests.imgfmt, dest_img_path, img_size)
iotests.log('Launching VMs...')
@@ -61,7 +62,8 @@ with iotests.FilePath('source.img') as source_img_path, \
iotests.log('Waiting for `drive-mirror` to complete...')
iotests.log(source_vm.event_wait('BLOCK_JOB_READY'),
- filters=[iotests.filter_qmp_event])
+ filters=[iotests.filter_qmp_event,
+ iotests.filter_block_job])
iotests.log('Starting migration...')
capabilities = [{'capability': 'events', 'state': True},
@@ -87,7 +89,8 @@ with iotests.FilePath('source.img') as source_img_path, \
while True:
event2 = source_vm.event_wait('BLOCK_JOB_COMPLETED')
- iotests.log(event2, filters=[iotests.filter_qmp_event])
+ iotests.log(event2, filters=[iotests.filter_qmp_event,
+ iotests.filter_block_job])
if event2['event'] == 'BLOCK_JOB_COMPLETED':
iotests.log('Stopping the NBD server on destination...')
iotests.log(dest_vm.qmp('nbd-server-stop'))
diff --git a/tests/qemu-iotests/194.out b/tests/qemu-iotests/194.out
index 376ed1d..d02655a 100644
--- a/tests/qemu-iotests/194.out
+++ b/tests/qemu-iotests/194.out
@@ -7,17 +7,18 @@ Launching NBD server on destination...
Starting `drive-mirror` on source...
{"return": {}}
Waiting for `drive-mirror` to complete...
-{"data": {"device": "mirror-job0", "len": 1073741824, "offset": 1073741824, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"device": "mirror-job0", "len": "LEN", "offset": "OFFSET", "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
Starting migration...
{"return": {}}
{"execute": "migrate-start-postcopy", "arguments": {}}
{"return": {}}
{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"status": "device"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
Gracefully ending the `drive-mirror` job on source...
{"return": {}}
-{"data": {"device": "mirror-job0", "len": 1073741824, "offset": 1073741824, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"device": "mirror-job0", "len": "LEN", "offset": "OFFSET", "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
Stopping the NBD server on destination...
{"return": {}}
Wait for migration completion on target...
diff --git a/tests/qemu-iotests/203.out b/tests/qemu-iotests/203.out
index 9d4abba..8e58705 100644
--- a/tests/qemu-iotests/203.out
+++ b/tests/qemu-iotests/203.out
@@ -8,4 +8,5 @@ Starting migration...
{"return": {}}
{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"status": "device"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out
index f02c754..ff9f9a6 100644
--- a/tests/qemu-iotests/211.out
+++ b/tests/qemu-iotests/211.out
@@ -17,7 +17,7 @@ file format: IMGFMT
virtual size: 128 MiB (134217728 bytes)
cluster_size: 1048576
-[{"data": false, "depth": 0, "length": 134217728, "present": true, "start": 0, "zero": true}]
+[{"compressed": false, "data": false, "depth": 0, "length": 134217728, "present": true, "start": 0, "zero": true}]
=== Successful image creation (explicit defaults) ===
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
@@ -35,7 +35,7 @@ file format: IMGFMT
virtual size: 64 MiB (67108864 bytes)
cluster_size: 1048576
-[{"data": false, "depth": 0, "length": 67108864, "present": true, "start": 0, "zero": true}]
+[{"compressed": false, "data": false, "depth": 0, "length": 67108864, "present": true, "start": 0, "zero": true}]
=== Successful image creation (with non-default options) ===
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
@@ -53,7 +53,7 @@ file format: IMGFMT
virtual size: 32 MiB (33554432 bytes)
cluster_size: 1048576
-[{"data": true, "depth": 0, "length": 3072, "offset": 1024, "present": true, "start": 0, "zero": false}, {"data": true, "depth": 0, "length": 33551360, "offset": 4096, "present": true, "start": 3072, "zero": true}]
+[{"compressed": false, "data": true, "depth": 0, "length": 3072, "offset": 1024, "present": true, "start": 0, "zero": false}, {"compressed": false, "data": true, "depth": 0, "length": 33551360, "offset": 4096, "present": true, "start": 3072, "zero": true}]
=== Invalid BlockdevRef ===
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "this doesn't exist", "size": 33554432}}}
diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221
index c463fd4..eba00b8 100755
--- a/tests/qemu-iotests/221
+++ b/tests/qemu-iotests/221
@@ -41,6 +41,7 @@ _supported_os Linux
_default_cache_mode writeback
_supported_cache_modes writeback writethrough unsafe
+_require_disk_usage
echo
echo "=== Check mapping of unaligned raw image ==="
diff --git a/tests/qemu-iotests/234.out b/tests/qemu-iotests/234.out
index ac8b643..be3e138 100644
--- a/tests/qemu-iotests/234.out
+++ b/tests/qemu-iotests/234.out
@@ -10,6 +10,7 @@ Starting migration to B...
{"return": {}}
{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"status": "device"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
@@ -27,6 +28,7 @@ Starting migration back to A...
{"return": {}}
{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"status": "device"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240
index 9b281e1..f8af9ff 100755
--- a/tests/qemu-iotests/240
+++ b/tests/qemu-iotests/240
@@ -81,8 +81,6 @@ class TestCase(iotests.QMPTestCase):
self.vm.qmp_log('device_del', id='scsi-hd0')
self.vm.event_wait('DEVICE_DELETED')
- self.vm.qmp_log('device_add', id='scsi-hd1', driver='scsi-hd', drive='hd0', bus="scsi1.0")
-
self.vm.qmp_log('device_del', id='scsi-hd1')
self.vm.event_wait('DEVICE_DELETED')
self.vm.qmp_log('blockdev-del', node_name='hd0')
diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out
index 89ed25e..10dcc42 100644
--- a/tests/qemu-iotests/240.out
+++ b/tests/qemu-iotests/240.out
@@ -46,10 +46,8 @@
{"execute": "device_add", "arguments": {"bus": "scsi0.0", "drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}}
{"return": {}}
{"execute": "device_add", "arguments": {"bus": "scsi1.0", "drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd1"}}
-{"error": {"class": "GenericError", "desc": "Cannot change iothread of active block backend"}}
-{"execute": "device_del", "arguments": {"id": "scsi-hd0"}}
{"return": {}}
-{"execute": "device_add", "arguments": {"bus": "scsi1.0", "drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd1"}}
+{"execute": "device_del", "arguments": {"id": "scsi-hd0"}}
{"return": {}}
{"execute": "device_del", "arguments": {"id": "scsi-hd1"}}
{"return": {}}
diff --git a/tests/qemu-iotests/250 b/tests/qemu-iotests/250
index af48f83..c0a0dbc 100755
--- a/tests/qemu-iotests/250
+++ b/tests/qemu-iotests/250
@@ -52,11 +52,6 @@ _unsupported_imgopts data_file
# bdrv_co_truncate(bs->file) call in qcow2_co_truncate(), which might succeed
# anyway.
-disk_usage()
-{
- du --block-size=1 $1 | awk '{print $1}'
-}
-
size=2100M
_make_test_img -o "cluster_size=1M,preallocation=metadata" $size
diff --git a/tests/qemu-iotests/253 b/tests/qemu-iotests/253
index 35039d2..6da85e6 100755
--- a/tests/qemu-iotests/253
+++ b/tests/qemu-iotests/253
@@ -41,6 +41,7 @@ _supported_os Linux
_default_cache_mode none
_supported_cache_modes none directsync
+_require_disk_usage
echo
echo "=== Check mapping of unaligned raw image ==="
diff --git a/tests/qemu-iotests/262.out b/tests/qemu-iotests/262.out
index b8a2d35..bd7706b 100644
--- a/tests/qemu-iotests/262.out
+++ b/tests/qemu-iotests/262.out
@@ -8,6 +8,7 @@ Starting migration to B...
{"return": {}}
{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"status": "device"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
diff --git a/tests/qemu-iotests/273.out b/tests/qemu-iotests/273.out
index 71843f0..c19753c 100644
--- a/tests/qemu-iotests/273.out
+++ b/tests/qemu-iotests/273.out
@@ -23,6 +23,7 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"backing-image": {
"backing-image": {
@@ -74,6 +75,7 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 197120,
"filename": "TEST_DIR/t.IMGFMT",
@@ -102,6 +104,7 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"backing-image": {
"virtual-size": 197120,
@@ -142,6 +145,7 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 197120,
"filename": "TEST_DIR/t.IMGFMT.mid",
@@ -170,6 +174,7 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
{
"iops_rd": 0,
"detect_zeroes": "off",
+ "active": true,
"image": {
"virtual-size": 197120,
"filename": "TEST_DIR/t.IMGFMT.base",
diff --git a/tests/qemu-iotests/280.out b/tests/qemu-iotests/280.out
index 546dbb4..3741114 100644
--- a/tests/qemu-iotests/280.out
+++ b/tests/qemu-iotests/280.out
@@ -7,6 +7,7 @@ Enabling migration QMP events on VM...
{"return": {}}
{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"status": "device"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
VM is now stopped:
diff --git a/tests/qemu-iotests/302 b/tests/qemu-iotests/302
index a6d79e7..e980ec5 100755
--- a/tests/qemu-iotests/302
+++ b/tests/qemu-iotests/302
@@ -115,13 +115,22 @@ with tarfile.open(tar_file, "w") as tar:
disk = tarfile.TarInfo("disk")
disk.size = actual_size
- tar.addfile(disk)
- # 6. Shrink the tar to the actual size, aligned to 512 bytes.
+ # Since python 3.13 we cannot use addfile() to create the member header.
+ # Add the tarinfo directly using public but undocumented attributes.
- tar_size = offset + (disk.size + 511) & ~511
- tar.fileobj.seek(tar_size)
- tar.fileobj.truncate(tar_size)
+ buf = disk.tobuf(tar.format, tar.encoding, tar.errors)
+ tar.fileobj.write(buf)
+ tar.members.append(disk)
+
+ # Update the offset and position to the location of the next member.
+
+ tar.offset = offset + (disk.size + 511) & ~511
+ tar.fileobj.seek(tar.offset)
+
+ # 6. Shrink the tar to the actual size.
+
+ tar.fileobj.truncate(tar.offset)
with tarfile.open(tar_file) as tar:
members = [{"name": m.name, "size": m.size, "offset": m.offset_data}
diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308
index ea81dc4..6eced3a 100755
--- a/tests/qemu-iotests/308
+++ b/tests/qemu-iotests/308
@@ -51,6 +51,7 @@ _unsupported_fmt vpc
_supported_proto file # We create the FUSE export manually
_supported_os Linux # We need /dev/urandom
+_require_disk_usage
# $1: Export ID
# $2: Options (beyond the node-name and ID)
@@ -290,7 +291,7 @@ echo '--- Try growing non-growable export ---'
# Get the current size so we can write beyond the EOF
orig_len=$(get_proto_len "$EXT_MP" "$TEST_IMG")
-orig_disk_usage=$(stat -c '%b' "$TEST_IMG")
+orig_disk_usage=$(disk_usage "$TEST_IMG")
# Should fail (exports are non-growable by default)
# (Note that qemu-io can never write beyond the EOF, so we have to use
@@ -312,7 +313,7 @@ else
echo 'OK: Post-truncate image size is as expected'
fi
-new_disk_usage=$(stat -c '%b' "$TEST_IMG")
+new_disk_usage=$(disk_usage "$TEST_IMG")
if [ "$new_disk_usage" -gt "$orig_disk_usage" ]; then
echo 'OK: Disk usage grew with fallocate'
else
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 95c1257..e977cb4 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -140,6 +140,12 @@ _optstr_add()
fi
}
+# report real disk usage for sparse files
+disk_usage()
+{
+ du --block-size=1 "$1" | awk '{print $1}'
+}
+
# Set the variables to the empty string to turn Valgrind off
# for specific processes, e.g.
# $ VALGRIND_QEMU_IO= ./check -qcow2 -valgrind 015
@@ -990,6 +996,36 @@ _require_large_file()
rm "$FILENAME"
}
+# Check whether disk_usage can be reliably used.
+_require_disk_usage()
+{
+ local unusable=false
+ # ZFS triggers known failures on this front; it does not immediately
+ # allocate files, and then aggressively compresses writes even when full
+ # allocation was requested.
+ if [ -z "$TEST_IMG_FILE" ]; then
+ FILENAME="$TEST_IMG"
+ else
+ FILENAME="$TEST_IMG_FILE"
+ fi
+ if [ -e "FILENAME" ]; then
+ echo "unwilling to overwrite existing file"
+ exit 1
+ fi
+ $QEMU_IMG create -f raw "$FILENAME" 5M > /dev/null
+ if [ $(disk_usage "$FILENAME") -gt $((1024*1024)) ]; then
+ unusable=true
+ fi
+ $QEMU_IMG create -f raw -o preallocation=full "$FILENAME" 5M > /dev/null
+ if [ $(disk_usage "$FILENAME") -lt $((4*1024*1024)) ]; then
+ unusable=true
+ fi
+ rm -f "$FILENAME"
+ if $unusable; then
+ _notrun "file system on $TEST_DIR does not handle sparse files nicely"
+ fi
+}
+
# Check that a set of devices is available in the QEMU binary
#
_require_devices()
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index ea48af4..0527477 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -601,13 +601,23 @@ def filter_chown(msg):
return chown_re.sub("chown UID:GID", msg)
def filter_qmp_event(event):
- '''Filter a QMP event dict'''
+ '''Filter the timestamp of a QMP event dict'''
event = dict(event)
if 'timestamp' in event:
event['timestamp']['seconds'] = 'SECS'
event['timestamp']['microseconds'] = 'USECS'
return event
+def filter_block_job(event):
+ '''Filter the offset and length of a QMP block job event dict'''
+ event = dict(event)
+ if 'data' in event:
+ if 'offset' in event['data']:
+ event['data']['offset'] = 'OFFSET'
+ if 'len' in event['data']:
+ event['data']['len'] = 'LEN'
+ return event
+
def filter_qmp(qmsg, filter_fn):
'''Given a string filter, filter a QMP object's values.
filter_fn takes a (key, value) pair.'''
@@ -701,6 +711,10 @@ def filter_qmp_imgfmt(qmsg):
def filter_nbd_exports(output: str) -> str:
return re.sub(r'((min|opt|max) block): [0-9]+', r'\1: XXX', output)
+def filter_qtest(output: str) -> str:
+ output = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', output)
+ output = re.sub(r'\n?\[I \+\d+\.\d+\] CLOSED\n?$', '', output)
+ return output
Msg = TypeVar('Msg', Dict[str, Any], List[Any], str)
@@ -909,6 +923,10 @@ class VM(qtest.QEMUQtestMachine):
self._args.append(addr)
return self
+ def add_paused(self):
+ self._args.append('-S')
+ return self
+
def hmp(self, command_line: str, use_log: bool = False) -> QMPMessage:
cmd = 'human-monitor-command'
kwargs: Dict[str, Any] = {'command-line': command_line}
@@ -1614,10 +1632,13 @@ class ReproducibleStreamWrapper:
self.stream.write(arg)
class ReproducibleTestRunner(unittest.TextTestRunner):
- def __init__(self, stream: Optional[TextIO] = None,
- resultclass: Type[unittest.TestResult] =
- ReproducibleTestResult,
- **kwargs: Any) -> None:
+ def __init__(
+ self,
+ stream: Optional[TextIO] = None,
+ resultclass: Type[unittest.TextTestResult] =
+ ReproducibleTestResult,
+ **kwargs: Any
+ ) -> None:
rstream = ReproducibleStreamWrapper(stream or sys.stdout)
super().__init__(stream=rstream, # type: ignore
descriptions=True,
diff --git a/tests/qemu-iotests/pylintrc b/tests/qemu-iotests/pylintrc
index 05b75ee..c5f4833 100644
--- a/tests/qemu-iotests/pylintrc
+++ b/tests/qemu-iotests/pylintrc
@@ -13,6 +13,7 @@ disable=invalid-name,
no-else-return,
too-few-public-methods,
too-many-arguments,
+ too-many-positional-arguments,
too-many-branches,
too-many-lines,
too-many-locals,
diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py
index c8848f2..6326e46 100644
--- a/tests/qemu-iotests/testenv.py
+++ b/tests/qemu-iotests/testenv.py
@@ -240,9 +240,12 @@ class TestEnv(ContextManager['TestEnv']):
('aarch64', 'virt'),
('avr', 'mega2560'),
('m68k', 'virt'),
+ ('or1k', 'virt'),
('riscv32', 'virt'),
('riscv64', 'virt'),
('rx', 'gdbsim-r5f562n8'),
+ ('sh4', 'r2d'),
+ ('sh4eb', 'r2d'),
('tricore', 'tricore_testboard')
)
for suffix, machine in machine_map:
diff --git a/tests/qemu-iotests/tests/backup-discard-source b/tests/qemu-iotests/tests/backup-discard-source
index 2391b12..17fef9c 100755
--- a/tests/qemu-iotests/tests/backup-discard-source
+++ b/tests/qemu-iotests/tests/backup-discard-source
@@ -28,20 +28,14 @@ from iotests import qemu_img_create, qemu_img_map, qemu_io
temp_img = os.path.join(iotests.test_dir, 'temp')
source_img = os.path.join(iotests.test_dir, 'source')
target_img = os.path.join(iotests.test_dir, 'target')
-size = '1M'
-
-
-def get_actual_size(vm, node_name):
- nodes = vm.cmd('query-named-block-nodes', flat=True)
- node = next(n for n in nodes if n['node-name'] == node_name)
- return node['image']['actual-size']
+size = 1024 * 1024
class TestBackup(iotests.QMPTestCase):
def setUp(self):
- qemu_img_create('-f', iotests.imgfmt, source_img, size)
- qemu_img_create('-f', iotests.imgfmt, temp_img, size)
- qemu_img_create('-f', iotests.imgfmt, target_img, size)
+ qemu_img_create('-f', iotests.imgfmt, source_img, str(size))
+ qemu_img_create('-f', iotests.imgfmt, temp_img, str(size))
+ qemu_img_create('-f', iotests.imgfmt, target_img, str(size))
qemu_io('-c', 'write 0 1M', source_img)
self.vm = iotests.VM()
@@ -84,7 +78,12 @@ class TestBackup(iotests.QMPTestCase):
}
})
- self.assertLess(get_actual_size(self.vm, 'temp'), 512 * 1024)
+ self.bitmap = {
+ 'node': 'temp',
+ 'name': 'bitmap0'
+ }
+
+ self.vm.cmd('block-dirty-bitmap-add', self.bitmap)
def tearDown(self):
# That should fail, because region is discarded
@@ -98,7 +97,7 @@ class TestBackup(iotests.QMPTestCase):
mapping = qemu_img_map(temp_img)
self.assertEqual(len(mapping), 1)
self.assertEqual(mapping[0]['start'], 0)
- self.assertEqual(mapping[0]['length'], 1024 * 1024)
+ self.assertEqual(mapping[0]['length'], size)
self.assertEqual(mapping[0]['data'], False)
os.remove(temp_img)
@@ -113,6 +112,13 @@ class TestBackup(iotests.QMPTestCase):
self.vm.event_wait(name='BLOCK_JOB_COMPLETED')
+ def get_bitmap_count(self):
+ nodes = self.vm.cmd('query-named-block-nodes', flat=True)
+ temp = next(n for n in nodes if n['node-name'] == 'temp')
+ bitmap = temp['dirty-bitmaps'][0]
+ assert bitmap['name'] == self.bitmap['name']
+ return bitmap['count']
+
def test_discard_written(self):
"""
1. Guest writes
@@ -125,7 +131,7 @@ class TestBackup(iotests.QMPTestCase):
self.assert_qmp(result, 'return', '')
# Check that data is written to temporary image
- self.assertGreater(get_actual_size(self.vm, 'temp'), 1024 * 1024)
+ self.assertEqual(self.get_bitmap_count(), size)
self.do_backup()
@@ -138,13 +144,18 @@ class TestBackup(iotests.QMPTestCase):
"""
self.do_backup()
+ # backup job did discard operation and pollute the bitmap,
+ # we have to clean the bitmap, to check next write
+ self.assertEqual(self.get_bitmap_count(), size)
+ self.vm.cmd('block-dirty-bitmap-clear', self.bitmap)
+
# Try trigger copy-before-write operation
result = self.vm.hmp_qemu_io('cbw', 'write 0 1M')
self.assert_qmp(result, 'return', '')
# Check that data is not written to temporary image, as region
# is discarded from copy-before-write process
- self.assertLess(get_actual_size(self.vm, 'temp'), 512 * 1024)
+ self.assertEqual(self.get_bitmap_count(), 0)
if __name__ == '__main__':
diff --git a/tests/qemu-iotests/tests/commit-zero-blocks b/tests/qemu-iotests/tests/commit-zero-blocks
new file mode 100755
index 0000000..de00273
--- /dev/null
+++ b/tests/qemu-iotests/tests/commit-zero-blocks
@@ -0,0 +1,96 @@
+#!/usr/bin/env bash
+# group: rw quick
+#
+# Test for commit of discarded blocks
+#
+# This tests committing a live snapshot where some of the blocks that
+# are present in the base image are discarded in the intermediate image.
+# This intends to check that these blocks are also discarded in the base
+# image after the commit.
+#
+# Copyright (C) 2024 Vincent Vanlaer.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# creator
+owner=libvirt-e6954efa@volkihar.be
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_qemu
+ _rm_test_img "${TEST_IMG}.base"
+ _rm_test_img "${TEST_IMG}.mid"
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+cd ..
+. ./common.rc
+. ./common.filter
+. ./common.qemu
+
+_supported_fmt qcow2
+_supported_proto file
+
+size="1M"
+
+TEST_IMG="$TEST_IMG.base" _make_test_img $size
+TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base" -F $IMGFMT $size
+_make_test_img -b "${TEST_IMG}.mid" -F $IMGFMT $size
+
+$QEMU_IO -c "write -P 0x01 64k 128k" "$TEST_IMG.base" | _filter_qemu_io
+$QEMU_IO -c "discard 64k 64k" "$TEST_IMG.mid" | _filter_qemu_io
+
+echo
+echo "=== Base image info before commit ==="
+TEST_IMG="${TEST_IMG}.base" _img_info | _filter_img_info
+$QEMU_IMG map --output=json "$TEST_IMG.base" | _filter_qemu_img_map
+
+echo
+echo "=== Middle image info before commit ==="
+TEST_IMG="${TEST_IMG}.mid" _img_info | _filter_img_info
+$QEMU_IMG map --output=json "$TEST_IMG.mid" | _filter_qemu_img_map
+
+echo
+echo === Running QEMU Live Commit Test ===
+echo
+
+qemu_comm_method="qmp"
+_launch_qemu -drive file="${TEST_IMG}",if=virtio,id=test
+h=$QEMU_HANDLE
+
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" "return"
+
+_send_qemu_cmd $h "{ 'execute': 'block-commit',
+ 'arguments': { 'device': 'test',
+ 'top': '"${TEST_IMG}.mid"',
+ 'base': '"${TEST_IMG}.base"'} }" '"status": "null"'
+
+_cleanup_qemu
+
+echo
+echo "=== Base image info after commit ==="
+TEST_IMG="${TEST_IMG}.base" _img_info | _filter_img_info
+$QEMU_IMG map --output=json "$TEST_IMG.base" | _filter_qemu_img_map
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/tests/commit-zero-blocks.out b/tests/qemu-iotests/tests/commit-zero-blocks.out
new file mode 100644
index 0000000..85bdc46
--- /dev/null
+++ b/tests/qemu-iotests/tests/commit-zero-blocks.out
@@ -0,0 +1,54 @@
+QA output created by commit-zero-blocks
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576
+Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.mid backing_fmt=IMGFMT
+wrote 131072/131072 bytes at offset 65536
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+discard 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Base image info before commit ===
+image: TEST_DIR/t.IMGFMT.base
+file format: IMGFMT
+virtual size: 1 MiB (1048576 bytes)
+[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
+{ "start": 65536, "length": 131072, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
+{ "start": 196608, "length": 851968, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
+
+=== Middle image info before commit ===
+image: TEST_DIR/t.IMGFMT.mid
+file format: IMGFMT
+virtual size: 1 MiB (1048576 bytes)
+backing file: TEST_DIR/t.IMGFMT.base
+backing file format: IMGFMT
+[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
+{ "start": 65536, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
+{ "start": 131072, "length": 65536, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
+{ "start": 196608, "length": 851968, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
+
+=== Running QEMU Live Commit Test ===
+
+{ 'execute': 'qmp_capabilities' }
+{"return": {}}
+{ 'execute': 'block-commit',
+ 'arguments': { 'device': 'test',
+ 'top': 'TEST_DIR/t.IMGFMT.mid',
+ 'base': 'TEST_DIR/t.IMGFMT.base'} }
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "test"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "test"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "test"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "test"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "test", "len": 1048576, "offset": 1048576, "speed": 0, "type": "commit"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "test"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "test"}}
+
+=== Base image info after commit ===
+image: TEST_DIR/t.IMGFMT.base
+file format: IMGFMT
+virtual size: 1 MiB (1048576 bytes)
+[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
+{ "start": 65536, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
+{ "start": 131072, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
+{ "start": 196608, "length": 851968, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
+*** done
diff --git a/tests/qemu-iotests/tests/copy-before-write b/tests/qemu-iotests/tests/copy-before-write
index d33bea5..236cb8a 100755
--- a/tests/qemu-iotests/tests/copy-before-write
+++ b/tests/qemu-iotests/tests/copy-before-write
@@ -95,8 +95,69 @@ class TestCbwError(iotests.QMPTestCase):
self.vm.shutdown()
log = self.vm.get_log()
- log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log)
- log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log)
+ log = iotests.filter_qtest(log)
+ log = iotests.filter_qemu_io(log)
+ return log
+
+ def do_cbw_error_via_blockdev_backup(self, on_cbw_error=None):
+ self.vm.cmd('blockdev-add', {
+ 'node-name': 'source',
+ 'driver': iotests.imgfmt,
+ 'file': {
+ 'driver': 'file',
+ 'filename': source_img
+ }
+ })
+
+ self.vm.cmd('blockdev-add', {
+ 'node-name': 'target',
+ 'driver': iotests.imgfmt,
+ 'file': {
+ 'driver': 'blkdebug',
+ 'image': {
+ 'driver': 'file',
+ 'filename': temp_img
+ },
+ 'inject-error': [
+ {
+ 'event': 'write_aio',
+ 'errno': 5,
+ 'immediately': False,
+ 'once': True
+ }
+ ]
+ }
+ })
+
+ blockdev_backup_options = {
+ 'device': 'source',
+ 'target': 'target',
+ 'sync': 'none',
+ 'job-id': 'job-id',
+ 'filter-node-name': 'cbw'
+ }
+
+ if on_cbw_error:
+ blockdev_backup_options['on-cbw-error'] = on_cbw_error
+
+ self.vm.cmd('blockdev-backup', blockdev_backup_options)
+
+ self.vm.cmd('blockdev-add', {
+ 'node-name': 'access',
+ 'driver': 'snapshot-access',
+ 'file': 'cbw'
+ })
+
+ result = self.vm.qmp('human-monitor-command',
+ command_line='qemu-io cbw "write 0 1M"')
+ self.assert_qmp(result, 'return', '')
+
+ result = self.vm.qmp('human-monitor-command',
+ command_line='qemu-io access "read 0 1M"')
+ self.assert_qmp(result, 'return', '')
+
+ self.vm.shutdown()
+ log = self.vm.get_log()
log = iotests.filter_qemu_io(log)
return log
@@ -126,6 +187,39 @@ read 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
""")
+ def test_break_snapshot_policy_forwarding(self):
+ """Ensure CBW filter accepts break-snapshot policy
+ specified in blockdev-backup QMP command.
+ """
+ log = self.do_cbw_error_via_blockdev_backup('break-snapshot')
+ self.assertEqual(log, """\
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read failed: Permission denied
+""")
+
+ def test_break_guest_write_policy_forwarding(self):
+ """Ensure CBW filter accepts break-guest-write policy
+ specified in blockdev-backup QMP command.
+ """
+ log = self.do_cbw_error_via_blockdev_backup('break-guest-write')
+ self.assertEqual(log, """\
+write failed: Input/output error
+read 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+""")
+
+ def test_default_on_cbw_error_policy_forwarding(self):
+ """Ensure break-guest-write policy is used by default when
+ on-cbw-error is not explicitly specified.
+ """
+ log = self.do_cbw_error_via_blockdev_backup()
+ self.assertEqual(log, """\
+write failed: Input/output error
+read 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+""")
+
def do_cbw_timeout(self, on_cbw_error):
self.vm.cmd('object-add', {
'qom-type': 'throttle-group',
diff --git a/tests/qemu-iotests/tests/copy-before-write.out b/tests/qemu-iotests/tests/copy-before-write.out
index 89968f3..2f7d390 100644
--- a/tests/qemu-iotests/tests/copy-before-write.out
+++ b/tests/qemu-iotests/tests/copy-before-write.out
@@ -1,5 +1,5 @@
-....
+.......
----------------------------------------------------------------------
-Ran 4 tests
+Ran 7 tests
OK
diff --git a/tests/qemu-iotests/tests/graph-changes-while-io b/tests/qemu-iotests/tests/graph-changes-while-io
index 194fda5..dca1167 100755
--- a/tests/qemu-iotests/tests/graph-changes-while-io
+++ b/tests/qemu-iotests/tests/graph-changes-while-io
@@ -27,6 +27,7 @@ from iotests import imgfmt, qemu_img, qemu_img_create, qemu_io, \
top = os.path.join(iotests.test_dir, 'top.img')
+mid = os.path.join(iotests.test_dir, 'mid.img')
nbd_sock = os.path.join(iotests.sock_dir, 'nbd.sock')
@@ -57,6 +58,16 @@ class TestGraphChangesWhileIO(QMPTestCase):
def tearDown(self) -> None:
self.qsd.stop()
+ os.remove(top)
+
+ def _wait_for_blockjob(self, status: str) -> None:
+ done = False
+ while not done:
+ for event in self.qsd.get_qmp().get_events(wait=10.0):
+ if event['event'] != 'JOB_STATUS_CHANGE':
+ continue
+ if event['data']['status'] == status:
+ done = True
def test_blockdev_add_while_io(self) -> None:
# Run qemu-img bench in the background
@@ -116,15 +127,92 @@ class TestGraphChangesWhileIO(QMPTestCase):
'device': 'job0',
})
- cancelled = False
- while not cancelled:
- for event in self.qsd.get_qmp().get_events(wait=10.0):
- if event['event'] != 'JOB_STATUS_CHANGE':
- continue
- if event['data']['status'] == 'null':
- cancelled = True
+ self._wait_for_blockjob('null')
+
+ bench_thr.join()
+
+ def test_remove_lower_snapshot_while_io(self) -> None:
+ # Run qemu-img bench in the background
+ bench_thr = Thread(target=do_qemu_img_bench, args=(100000, ))
+ bench_thr.start()
+
+ # While I/O is performed on 'node0' node, consequently add 2 snapshots
+ # on top of it, then remove (commit) them starting from lower one.
+ while bench_thr.is_alive():
+ # Recreate snapshot images on every iteration
+ qemu_img_create('-f', imgfmt, mid, '1G')
+ qemu_img_create('-f', imgfmt, top, '1G')
+
+ self.qsd.cmd('blockdev-add', {
+ 'driver': imgfmt,
+ 'node-name': 'mid',
+ 'file': {
+ 'driver': 'file',
+ 'filename': mid
+ }
+ })
+
+ self.qsd.cmd('blockdev-snapshot', {
+ 'node': 'node0',
+ 'overlay': 'mid',
+ })
+
+ self.qsd.cmd('blockdev-add', {
+ 'driver': imgfmt,
+ 'node-name': 'top',
+ 'file': {
+ 'driver': 'file',
+ 'filename': top
+ }
+ })
+
+ self.qsd.cmd('blockdev-snapshot', {
+ 'node': 'mid',
+ 'overlay': 'top',
+ })
+
+ self.qsd.cmd('block-commit', {
+ 'job-id': 'commit-mid',
+ 'device': 'top',
+ 'top-node': 'mid',
+ 'base-node': 'node0',
+ 'auto-finalize': True,
+ 'auto-dismiss': False,
+ })
+
+ self._wait_for_blockjob('concluded')
+ self.qsd.cmd('job-dismiss', {
+ 'id': 'commit-mid',
+ })
+
+ self.qsd.cmd('block-commit', {
+ 'job-id': 'commit-top',
+ 'device': 'top',
+ 'top-node': 'top',
+ 'base-node': 'node0',
+ 'auto-finalize': True,
+ 'auto-dismiss': False,
+ })
+
+ self._wait_for_blockjob('ready')
+ self.qsd.cmd('job-complete', {
+ 'id': 'commit-top',
+ })
+
+ self._wait_for_blockjob('concluded')
+ self.qsd.cmd('job-dismiss', {
+ 'id': 'commit-top',
+ })
+
+ self.qsd.cmd('blockdev-del', {
+ 'node-name': 'mid'
+ })
+ self.qsd.cmd('blockdev-del', {
+ 'node-name': 'top'
+ })
bench_thr.join()
+ os.remove(mid)
if __name__ == '__main__':
# Format must support raw backing files
diff --git a/tests/qemu-iotests/tests/graph-changes-while-io.out b/tests/qemu-iotests/tests/graph-changes-while-io.out
index fbc63e6..8d7e9967 100644
--- a/tests/qemu-iotests/tests/graph-changes-while-io.out
+++ b/tests/qemu-iotests/tests/graph-changes-while-io.out
@@ -1,5 +1,5 @@
-..
+...
----------------------------------------------------------------------
-Ran 2 tests
+Ran 3 tests
OK
diff --git a/tests/qemu-iotests/tests/inactive-node-nbd b/tests/qemu-iotests/tests/inactive-node-nbd
new file mode 100755
index 0000000..a95b37e
--- /dev/null
+++ b/tests/qemu-iotests/tests/inactive-node-nbd
@@ -0,0 +1,303 @@
+#!/usr/bin/env python3
+# group: rw quick
+#
+# Copyright (C) Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
+
+import iotests
+
+from iotests import QemuIoInteractive
+from iotests import filter_qemu_io, filter_qtest, filter_qmp_testfiles
+
+iotests.script_initialize(supported_fmts=['generic'],
+ supported_protocols=['file'],
+ supported_platforms=['linux'])
+
+def get_export(node_name='disk-fmt', allow_inactive=None):
+ exp = {
+ 'id': 'exp0',
+ 'type': 'nbd',
+ 'node-name': node_name,
+ 'writable': True,
+ }
+
+ if allow_inactive is not None:
+ exp['allow-inactive'] = allow_inactive
+
+ return exp
+
+def node_is_active(_vm, node_name):
+ nodes = _vm.cmd('query-named-block-nodes', flat=True)
+ node = next(n for n in nodes if n['node-name'] == node_name)
+ return node['active']
+
+with iotests.FilePath('disk.img') as path, \
+ iotests.FilePath('snap.qcow2') as snap_path, \
+ iotests.FilePath('snap2.qcow2') as snap2_path, \
+ iotests.FilePath('target.img') as target_path, \
+ iotests.FilePath('nbd.sock', base_dir=iotests.sock_dir) as nbd_sock, \
+ iotests.VM() as vm:
+
+ img_size = '10M'
+
+ iotests.log('Preparing disk...')
+ iotests.qemu_img_create('-f', iotests.imgfmt, path, img_size)
+ iotests.qemu_img_create('-f', iotests.imgfmt, target_path, img_size)
+
+ iotests.qemu_img_create('-f', 'qcow2', '-b', path, '-F', iotests.imgfmt,
+ snap_path)
+ iotests.qemu_img_create('-f', 'qcow2', '-b', snap_path, '-F', 'qcow2',
+ snap2_path)
+
+ iotests.log('Launching VM...')
+ vm.add_blockdev(f'file,node-name=disk-file,filename={path}')
+ vm.add_blockdev(f'{iotests.imgfmt},file=disk-file,node-name=disk-fmt,'
+ 'active=off')
+ vm.add_blockdev(f'file,node-name=target-file,filename={target_path}')
+ vm.add_blockdev(f'{iotests.imgfmt},file=target-file,node-name=target-fmt')
+ vm.add_blockdev(f'file,node-name=snap-file,filename={snap_path}')
+ vm.add_blockdev(f'file,node-name=snap2-file,filename={snap2_path}')
+
+ # Actually running the VM activates all images
+ vm.add_paused()
+
+ vm.launch()
+ vm.qmp_log('nbd-server-start',
+ addr={'type': 'unix', 'data':{'path': nbd_sock}},
+ filters=[filter_qmp_testfiles])
+
+ iotests.log('\n=== Creating export of inactive node ===')
+
+ iotests.log('\nExports activate nodes without allow-inactive')
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ vm.qmp_log('block-export-add', **get_export())
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ vm.qmp_log('query-block-exports')
+ vm.qmp_log('block-export-del', id='exp0')
+ vm.event_wait('BLOCK_EXPORT_DELETED')
+ vm.qmp_log('query-block-exports')
+
+ iotests.log('\nExports activate nodes with allow-inactive=false')
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=False)
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ vm.qmp_log('block-export-add', **get_export(allow_inactive=False))
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ vm.qmp_log('query-block-exports')
+ vm.qmp_log('block-export-del', id='exp0')
+ vm.event_wait('BLOCK_EXPORT_DELETED')
+ vm.qmp_log('query-block-exports')
+
+ iotests.log('\nExport leaves nodes inactive with allow-inactive=true')
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=False)
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ vm.qmp_log('block-export-add', **get_export(allow_inactive=True))
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ vm.qmp_log('query-block-exports')
+ vm.qmp_log('block-export-del', id='exp0')
+ vm.event_wait('BLOCK_EXPORT_DELETED')
+ vm.qmp_log('query-block-exports')
+
+ iotests.log('\n=== Inactivating node with existing export ===')
+
+ iotests.log('\nInactivating nodes with an export fails without '
+ 'allow-inactive')
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=True)
+ vm.qmp_log('block-export-add', **get_export(node_name='disk-fmt'))
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=False)
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ vm.qmp_log('query-block-exports')
+ vm.qmp_log('block-export-del', id='exp0')
+ vm.event_wait('BLOCK_EXPORT_DELETED')
+ vm.qmp_log('query-block-exports')
+
+ iotests.log('\nInactivating nodes with an export fails with '
+ 'allow-inactive=false')
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=True)
+ vm.qmp_log('block-export-add',
+ **get_export(node_name='disk-fmt', allow_inactive=False))
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=False)
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ vm.qmp_log('query-block-exports')
+ vm.qmp_log('block-export-del', id='exp0')
+ vm.event_wait('BLOCK_EXPORT_DELETED')
+ vm.qmp_log('query-block-exports')
+
+ iotests.log('\nInactivating nodes with an export works with '
+ 'allow-inactive=true')
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=True)
+ vm.qmp_log('block-export-add',
+ **get_export(node_name='disk-fmt', allow_inactive=True))
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=False)
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ vm.qmp_log('query-block-exports')
+ vm.qmp_log('block-export-del', id='exp0')
+ vm.event_wait('BLOCK_EXPORT_DELETED')
+ vm.qmp_log('query-block-exports')
+
+ iotests.log('\n=== Inactive nodes with parent ===')
+
+ iotests.log('\nInactivating nodes with an active parent fails')
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=True)
+ vm.qmp_log('blockdev-set-active', node_name='disk-file', active=False)
+ iotests.log('disk-file active: %s' % node_is_active(vm, 'disk-file'))
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+
+ iotests.log('\nInactivating nodes with an inactive parent works')
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=False)
+ vm.qmp_log('blockdev-set-active', node_name='disk-file', active=False)
+ iotests.log('disk-file active: %s' % node_is_active(vm, 'disk-file'))
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+
+ iotests.log('\nCreating active parent node with an inactive child fails')
+ vm.qmp_log('blockdev-add', driver='raw', file='disk-fmt',
+ node_name='disk-filter')
+ vm.qmp_log('blockdev-add', driver='raw', file='disk-fmt',
+ node_name='disk-filter', active=True)
+
+ iotests.log('\nCreating inactive parent node with an inactive child works')
+ vm.qmp_log('blockdev-add', driver='raw', file='disk-fmt',
+ node_name='disk-filter', active=False)
+ vm.qmp_log('blockdev-del', node_name='disk-filter')
+
+ iotests.log('\n=== Resizing an inactive node ===')
+ vm.qmp_log('block_resize', node_name='disk-fmt', size=16*1024*1024)
+
+ iotests.log('\n=== Taking a snapshot of an inactive node ===')
+
+ iotests.log('\nActive overlay over inactive backing file automatically '
+ 'makes both inactive for compatibility')
+ vm.qmp_log('blockdev-add', driver='qcow2', node_name='snap-fmt',
+ file='snap-file', backing=None)
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
+ vm.qmp_log('blockdev-snapshot', node='disk-fmt', overlay='snap-fmt')
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
+ vm.qmp_log('blockdev-del', node_name='snap-fmt')
+
+ iotests.log('\nInactive overlay over inactive backing file just works')
+ vm.qmp_log('blockdev-add', driver='qcow2', node_name='snap-fmt',
+ file='snap-file', backing=None, active=False)
+ vm.qmp_log('blockdev-snapshot', node='disk-fmt', overlay='snap-fmt')
+
+ iotests.log('\n=== Block jobs with inactive nodes ===')
+
+ iotests.log('\nStreaming into an inactive node')
+ vm.qmp_log('block-stream', device='snap-fmt',
+ filters=[iotests.filter_qmp_generated_node_ids])
+
+ iotests.log('\nCommitting an inactive root node (active commit)')
+ vm.qmp_log('block-commit', job_id='job0', device='snap-fmt',
+ filters=[iotests.filter_qmp_generated_node_ids])
+
+ iotests.log('\nCommitting an inactive intermediate node to inactive base')
+ vm.qmp_log('blockdev-add', driver='qcow2', node_name='snap2-fmt',
+ file='snap2-file', backing='snap-fmt', active=False)
+
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
+ iotests.log('snap2-fmt active: %s' % node_is_active(vm, 'snap2-fmt'))
+
+ vm.qmp_log('block-commit', job_id='job0', device='snap2-fmt',
+ top_node='snap-fmt',
+ filters=[iotests.filter_qmp_generated_node_ids])
+
+ iotests.log('\nCommitting an inactive intermediate node to active base')
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=True)
+ vm.qmp_log('block-commit', job_id='job0', device='snap2-fmt',
+ top_node='snap-fmt',
+ filters=[iotests.filter_qmp_generated_node_ids])
+
+ iotests.log('\nMirror from inactive source to active target')
+ vm.qmp_log('blockdev-mirror', job_id='job0', device='snap2-fmt',
+ target='target-fmt', sync='full',
+ filters=[iotests.filter_qmp_generated_node_ids])
+
+ iotests.log('\nMirror from active source to inactive target')
+
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
+ iotests.log('snap2-fmt active: %s' % node_is_active(vm, 'snap2-fmt'))
+ iotests.log('target-fmt active: %s' % node_is_active(vm, 'target-fmt'))
+
+ # Activating snap2-fmt recursively activates the whole backing chain
+ vm.qmp_log('blockdev-set-active', node_name='snap2-fmt', active=True)
+ vm.qmp_log('blockdev-set-active', node_name='target-fmt', active=False)
+
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
+ iotests.log('snap2-fmt active: %s' % node_is_active(vm, 'snap2-fmt'))
+ iotests.log('target-fmt active: %s' % node_is_active(vm, 'target-fmt'))
+
+ vm.qmp_log('blockdev-mirror', job_id='job0', device='snap2-fmt',
+ target='target-fmt', sync='full',
+ filters=[iotests.filter_qmp_generated_node_ids])
+
+ iotests.log('\nBackup from active source to inactive target')
+
+ vm.qmp_log('blockdev-backup', job_id='job0', device='snap2-fmt',
+ target='target-fmt', sync='full',
+ filters=[iotests.filter_qmp_generated_node_ids])
+
+ iotests.log('\nBackup from inactive source to active target')
+
+ # Inactivating snap2-fmt recursively inactivates the whole backing chain
+ vm.qmp_log('blockdev-set-active', node_name='snap2-fmt', active=False)
+ vm.qmp_log('blockdev-set-active', node_name='target-fmt', active=True)
+
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
+ iotests.log('snap2-fmt active: %s' % node_is_active(vm, 'snap2-fmt'))
+ iotests.log('target-fmt active: %s' % node_is_active(vm, 'target-fmt'))
+
+ vm.qmp_log('blockdev-backup', job_id='job0', device='snap2-fmt',
+ target='target-fmt', sync='full',
+ filters=[iotests.filter_qmp_generated_node_ids])
+
+ iotests.log('\n=== Accessing export on inactive node ===')
+
+ # Use the target node because it has the right image format and isn't the
+ # (read-only) backing file of a qcow2 node
+ vm.qmp_log('blockdev-set-active', node_name='target-fmt', active=False)
+ vm.qmp_log('block-export-add',
+ **get_export(node_name='target-fmt', allow_inactive=True))
+
+ # The read should succeed, everything else should fail gracefully
+ qemu_io = QemuIoInteractive('-f', 'raw',
+ f'nbd+unix:///target-fmt?socket={nbd_sock}')
+ iotests.log(qemu_io.cmd('read 0 64k'), filters=[filter_qemu_io])
+ iotests.log(qemu_io.cmd('write 0 64k'), filters=[filter_qemu_io])
+ iotests.log(qemu_io.cmd('write -z 0 64k'), filters=[filter_qemu_io])
+ iotests.log(qemu_io.cmd('write -zu 0 64k'), filters=[filter_qemu_io])
+ iotests.log(qemu_io.cmd('discard 0 64k'), filters=[filter_qemu_io])
+ iotests.log(qemu_io.cmd('flush'), filters=[filter_qemu_io])
+ iotests.log(qemu_io.cmd('map'), filters=[filter_qemu_io])
+ qemu_io.close()
+
+ iotests.log('\n=== Resuming VM activates all images ===')
+ vm.qmp_log('cont')
+
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
+ iotests.log('snap2-fmt active: %s' % node_is_active(vm, 'snap2-fmt'))
+ iotests.log('target-fmt active: %s' % node_is_active(vm, 'target-fmt'))
+
+ iotests.log('\nShutting down...')
+ vm.shutdown()
+ log = vm.get_log()
+ if log:
+ iotests.log(log, [filter_qtest, filter_qemu_io])
diff --git a/tests/qemu-iotests/tests/inactive-node-nbd.out b/tests/qemu-iotests/tests/inactive-node-nbd.out
new file mode 100644
index 0000000..a458b4f
--- /dev/null
+++ b/tests/qemu-iotests/tests/inactive-node-nbd.out
@@ -0,0 +1,239 @@
+Preparing disk...
+Launching VM...
+{"execute": "nbd-server-start", "arguments": {"addr": {"data": {"path": "SOCK_DIR/PID-nbd.sock"}, "type": "unix"}}}
+{"return": {}}
+
+=== Creating export of inactive node ===
+
+Exports activate nodes without allow-inactive
+disk-fmt active: False
+{"execute": "block-export-add", "arguments": {"id": "exp0", "node-name": "disk-fmt", "type": "nbd", "writable": true}}
+{"return": {}}
+disk-fmt active: True
+{"execute": "query-block-exports", "arguments": {}}
+{"return": [{"id": "exp0", "node-name": "disk-fmt", "shutting-down": false, "type": "nbd"}]}
+{"execute": "block-export-del", "arguments": {"id": "exp0"}}
+{"return": {}}
+{"execute": "query-block-exports", "arguments": {}}
+{"return": []}
+
+Exports activate nodes with allow-inactive=false
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-fmt"}}
+{"return": {}}
+disk-fmt active: False
+{"execute": "block-export-add", "arguments": {"allow-inactive": false, "id": "exp0", "node-name": "disk-fmt", "type": "nbd", "writable": true}}
+{"return": {}}
+disk-fmt active: True
+{"execute": "query-block-exports", "arguments": {}}
+{"return": [{"id": "exp0", "node-name": "disk-fmt", "shutting-down": false, "type": "nbd"}]}
+{"execute": "block-export-del", "arguments": {"id": "exp0"}}
+{"return": {}}
+{"execute": "query-block-exports", "arguments": {}}
+{"return": []}
+
+Export leaves nodes inactive with allow-inactive=true
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-fmt"}}
+{"return": {}}
+disk-fmt active: False
+{"execute": "block-export-add", "arguments": {"allow-inactive": true, "id": "exp0", "node-name": "disk-fmt", "type": "nbd", "writable": true}}
+{"return": {}}
+disk-fmt active: False
+{"execute": "query-block-exports", "arguments": {}}
+{"return": [{"id": "exp0", "node-name": "disk-fmt", "shutting-down": false, "type": "nbd"}]}
+{"execute": "block-export-del", "arguments": {"id": "exp0"}}
+{"return": {}}
+{"execute": "query-block-exports", "arguments": {}}
+{"return": []}
+
+=== Inactivating node with existing export ===
+
+Inactivating nodes with an export fails without allow-inactive
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "disk-fmt"}}
+{"return": {}}
+{"execute": "block-export-add", "arguments": {"id": "exp0", "node-name": "disk-fmt", "type": "nbd", "writable": true}}
+{"return": {}}
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-fmt"}}
+{"error": {"class": "GenericError", "desc": "Failed to inactivate node: Operation not permitted"}}
+disk-fmt active: True
+{"execute": "query-block-exports", "arguments": {}}
+{"return": [{"id": "exp0", "node-name": "disk-fmt", "shutting-down": false, "type": "nbd"}]}
+{"execute": "block-export-del", "arguments": {"id": "exp0"}}
+{"return": {}}
+{"execute": "query-block-exports", "arguments": {}}
+{"return": []}
+
+Inactivating nodes with an export fails with allow-inactive=false
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "disk-fmt"}}
+{"return": {}}
+{"execute": "block-export-add", "arguments": {"allow-inactive": false, "id": "exp0", "node-name": "disk-fmt", "type": "nbd", "writable": true}}
+{"return": {}}
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-fmt"}}
+{"error": {"class": "GenericError", "desc": "Failed to inactivate node: Operation not permitted"}}
+disk-fmt active: True
+{"execute": "query-block-exports", "arguments": {}}
+{"return": [{"id": "exp0", "node-name": "disk-fmt", "shutting-down": false, "type": "nbd"}]}
+{"execute": "block-export-del", "arguments": {"id": "exp0"}}
+{"return": {}}
+{"execute": "query-block-exports", "arguments": {}}
+{"return": []}
+
+Inactivating nodes with an export works with allow-inactive=true
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "disk-fmt"}}
+{"return": {}}
+{"execute": "block-export-add", "arguments": {"allow-inactive": true, "id": "exp0", "node-name": "disk-fmt", "type": "nbd", "writable": true}}
+{"return": {}}
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-fmt"}}
+{"return": {}}
+disk-fmt active: False
+{"execute": "query-block-exports", "arguments": {}}
+{"return": [{"id": "exp0", "node-name": "disk-fmt", "shutting-down": false, "type": "nbd"}]}
+{"execute": "block-export-del", "arguments": {"id": "exp0"}}
+{"return": {}}
+{"execute": "query-block-exports", "arguments": {}}
+{"return": []}
+
+=== Inactive nodes with parent ===
+
+Inactivating nodes with an active parent fails
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "disk-fmt"}}
+{"return": {}}
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-file"}}
+{"error": {"class": "GenericError", "desc": "Node has active parent node"}}
+disk-file active: True
+disk-fmt active: True
+
+Inactivating nodes with an inactive parent works
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-fmt"}}
+{"return": {}}
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-file"}}
+{"return": {}}
+disk-file active: False
+disk-fmt active: False
+
+Creating active parent node with an inactive child fails
+{"execute": "blockdev-add", "arguments": {"driver": "raw", "file": "disk-fmt", "node-name": "disk-filter"}}
+{"error": {"class": "GenericError", "desc": "Inactive 'disk-fmt' can't be a file child of active 'disk-filter'"}}
+{"execute": "blockdev-add", "arguments": {"active": true, "driver": "raw", "file": "disk-fmt", "node-name": "disk-filter"}}
+{"error": {"class": "GenericError", "desc": "Inactive 'disk-fmt' can't be a file child of active 'disk-filter'"}}
+
+Creating inactive parent node with an inactive child works
+{"execute": "blockdev-add", "arguments": {"active": false, "driver": "raw", "file": "disk-fmt", "node-name": "disk-filter"}}
+{"return": {}}
+{"execute": "blockdev-del", "arguments": {"node-name": "disk-filter"}}
+{"return": {}}
+
+=== Resizing an inactive node ===
+{"execute": "block_resize", "arguments": {"node-name": "disk-fmt", "size": 16777216}}
+{"error": {"class": "GenericError", "desc": "Permission 'resize' unavailable on inactive node"}}
+
+=== Taking a snapshot of an inactive node ===
+
+Active overlay over inactive backing file automatically makes both inactive for compatibility
+{"execute": "blockdev-add", "arguments": {"backing": null, "driver": "qcow2", "file": "snap-file", "node-name": "snap-fmt"}}
+{"return": {}}
+disk-fmt active: False
+snap-fmt active: True
+{"execute": "blockdev-snapshot", "arguments": {"node": "disk-fmt", "overlay": "snap-fmt"}}
+{"return": {}}
+disk-fmt active: False
+snap-fmt active: False
+{"execute": "blockdev-del", "arguments": {"node-name": "snap-fmt"}}
+{"return": {}}
+
+Inactive overlay over inactive backing file just works
+{"execute": "blockdev-add", "arguments": {"active": false, "backing": null, "driver": "qcow2", "file": "snap-file", "node-name": "snap-fmt"}}
+{"return": {}}
+{"execute": "blockdev-snapshot", "arguments": {"node": "disk-fmt", "overlay": "snap-fmt"}}
+{"return": {}}
+
+=== Block jobs with inactive nodes ===
+
+Streaming into an inactive node
+{"execute": "block-stream", "arguments": {"device": "snap-fmt"}}
+{"error": {"class": "GenericError", "desc": "Could not create node: Inactive 'snap-fmt' can't be a file child of active 'NODE_NAME'"}}
+
+Committing an inactive root node (active commit)
+{"execute": "block-commit", "arguments": {"device": "snap-fmt", "job-id": "job0"}}
+{"error": {"class": "GenericError", "desc": "Inactive 'snap-fmt' can't be a backing child of active 'NODE_NAME'"}}
+
+Committing an inactive intermediate node to inactive base
+{"execute": "blockdev-add", "arguments": {"active": false, "backing": "snap-fmt", "driver": "qcow2", "file": "snap2-file", "node-name": "snap2-fmt"}}
+{"return": {}}
+disk-fmt active: False
+snap-fmt active: False
+snap2-fmt active: False
+{"execute": "block-commit", "arguments": {"device": "snap2-fmt", "job-id": "job0", "top-node": "snap-fmt"}}
+{"error": {"class": "GenericError", "desc": "Inactive 'snap-fmt' can't be a backing child of active 'NODE_NAME'"}}
+
+Committing an inactive intermediate node to active base
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "disk-fmt"}}
+{"return": {}}
+{"execute": "block-commit", "arguments": {"device": "snap2-fmt", "job-id": "job0", "top-node": "snap-fmt"}}
+{"error": {"class": "GenericError", "desc": "Inactive 'snap-fmt' can't be a backing child of active 'NODE_NAME'"}}
+
+Mirror from inactive source to active target
+{"execute": "blockdev-mirror", "arguments": {"device": "snap2-fmt", "job-id": "job0", "sync": "full", "target": "target-fmt"}}
+{"error": {"class": "GenericError", "desc": "Inactive 'snap2-fmt' can't be a backing child of active 'NODE_NAME'"}}
+
+Mirror from active source to inactive target
+disk-fmt active: True
+snap-fmt active: False
+snap2-fmt active: False
+target-fmt active: True
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "snap2-fmt"}}
+{"return": {}}
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "target-fmt"}}
+{"return": {}}
+disk-fmt active: True
+snap-fmt active: True
+snap2-fmt active: True
+target-fmt active: False
+{"execute": "blockdev-mirror", "arguments": {"device": "snap2-fmt", "job-id": "job0", "sync": "full", "target": "target-fmt"}}
+{"error": {"class": "GenericError", "desc": "Permission 'write' unavailable on inactive node"}}
+
+Backup from active source to inactive target
+{"execute": "blockdev-backup", "arguments": {"device": "snap2-fmt", "job-id": "job0", "sync": "full", "target": "target-fmt"}}
+{"error": {"class": "GenericError", "desc": "Could not create node: Inactive 'target-fmt' can't be a target child of active 'NODE_NAME'"}}
+
+Backup from inactive source to active target
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "snap2-fmt"}}
+{"return": {}}
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "target-fmt"}}
+{"return": {}}
+disk-fmt active: False
+snap-fmt active: False
+snap2-fmt active: False
+target-fmt active: True
+{"execute": "blockdev-backup", "arguments": {"device": "snap2-fmt", "job-id": "job0", "sync": "full", "target": "target-fmt"}}
+{"error": {"class": "GenericError", "desc": "Could not create node: Inactive 'snap2-fmt' can't be a file child of active 'NODE_NAME'"}}
+
+=== Accessing export on inactive node ===
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "target-fmt"}}
+{"return": {}}
+{"execute": "block-export-add", "arguments": {"allow-inactive": true, "id": "exp0", "node-name": "target-fmt", "type": "nbd", "writable": true}}
+{"return": {}}
+read 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+write failed: Operation not permitted
+
+write failed: Operation not permitted
+
+write failed: Operation not permitted
+
+discard failed: Operation not permitted
+
+
+qemu-io: Failed to get allocation status: Operation not permitted
+
+
+=== Resuming VM activates all images ===
+{"execute": "cont", "arguments": {}}
+{"return": {}}
+disk-fmt active: True
+snap-fmt active: True
+snap2-fmt active: True
+target-fmt active: True
+
+Shutting down...
+
diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-test b/tests/qemu-iotests/tests/migrate-bitmaps-test
index f98e721..8fb4099 100755
--- a/tests/qemu-iotests/tests/migrate-bitmaps-test
+++ b/tests/qemu-iotests/tests/migrate-bitmaps-test
@@ -122,11 +122,10 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase):
# catch 'Could not reopen qcow2 layer: Bitmap already exists'
# possible error
- log = self.vm_a.get_log()
- log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log)
- log = re.sub(r'^(wrote .* bytes at offset .*\n.*KiB.*ops.*sec.*\n){3}',
+ log = iotests.filter_qtest(self.vm_a.get_log())
+ log = re.sub(r'^(wrote .* bytes at offset .*\n'
+ r'.*KiB.*ops.*sec.*\n?){3}',
'', log)
- log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log)
self.assertEqual(log, '')
# test that bitmap is still persistent
diff --git a/tests/qemu-iotests/tests/mirror-sparse b/tests/qemu-iotests/tests/mirror-sparse
new file mode 100755
index 0000000..cfcaa60
--- /dev/null
+++ b/tests/qemu-iotests/tests/mirror-sparse
@@ -0,0 +1,128 @@
+#!/usr/bin/env bash
+# group: rw auto quick
+#
+# Test blockdev-mirror with raw sparse destination
+#
+# Copyright (C) 2025 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+ _cleanup_qemu
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+cd ..
+. ./common.rc
+. ./common.filter
+. ./common.qemu
+
+_supported_fmt qcow2 raw # Format of the source. dst is always raw file
+_supported_proto file
+_supported_os Linux
+_require_disk_usage
+
+echo
+echo "=== Initial image setup ==="
+echo
+
+TEST_IMG="$TEST_IMG.base" _make_test_img 20M
+$QEMU_IO -c 'w 8M 2M' -f $IMGFMT "$TEST_IMG.base" | _filter_qemu_io
+
+_launch_qemu \
+ -blockdev '{"driver":"file", "cache":{"direct":true, "no-flush":false},
+ "filename":"'"$TEST_IMG.base"'", "node-name":"src-file"}' \
+ -blockdev '{"driver":"'$IMGFMT'", "node-name":"src", "file":"src-file"}'
+h1=$QEMU_HANDLE
+_send_qemu_cmd $h1 '{"execute": "qmp_capabilities"}' 'return'
+
+# Check several combinations; most should result in a sparse destination;
+# the destination should only be fully allocated if pre-allocated
+# and not punching holes due to detect-zeroes
+# do_test creation discard zeroes result
+do_test() {
+ creation=$1
+ discard=$2
+ zeroes=$3
+ expected=$4
+
+echo
+echo "=== Testing creation=$creation discard=$discard zeroes=$zeroes ==="
+echo
+
+rm -f $TEST_IMG
+if test $creation = external; then
+ truncate --size=20M $TEST_IMG
+else
+ _send_qemu_cmd $h1 '{"execute": "blockdev-create", "arguments":
+ {"options": {"driver":"file", "filename":"'$TEST_IMG'",
+ "size":'$((20*1024*1024))', "preallocation":"'$creation'"},
+ "job-id":"job1"}}' 'concluded'
+ _send_qemu_cmd $h1 '{"execute": "job-dismiss", "arguments":
+ {"id": "job1"}}' 'return'
+fi
+_send_qemu_cmd $h1 '{"execute": "blockdev-add", "arguments":
+ {"node-name": "dst", "driver":"file",
+ "filename":"'$TEST_IMG'", "aio":"threads",
+ "auto-read-only":true, "discard":"'$discard'",
+ "detect-zeroes":"'$zeroes'"}}' 'return'
+_send_qemu_cmd $h1 '{"execute":"blockdev-mirror", "arguments":
+ {"sync":"full", "device":"src", "target":"dst",
+ "job-id":"job2"}}' 'return'
+_timed_wait_for $h1 '"ready"'
+_send_qemu_cmd $h1 '{"execute": "job-complete", "arguments":
+ {"id":"job2"}}' 'return' \
+ | _filter_block_job_offset | _filter_block_job_len
+_send_qemu_cmd $h1 '{"execute": "blockdev-del", "arguments":
+ {"node-name": "dst"}}' 'return' \
+ | _filter_block_job_offset | _filter_block_job_len
+$QEMU_IMG compare -U -f $IMGFMT -F raw $TEST_IMG.base $TEST_IMG
+# Some filesystems can fudge allocations for various reasons; rather
+# than expecting precise 2M and 20M images, it is better to allow for slop.
+result=$(disk_usage $TEST_IMG)
+if test $result -lt $((4*1024*1024)); then
+ actual=sparse
+elif test $result -gt $((19*1024*1024)); then
+ actual=full
+else
+ actual="unexpected size ($result)"
+fi
+echo "Destination is $actual; expected $expected"
+}
+
+do_test external ignore off sparse
+do_test external unmap off sparse
+do_test external unmap unmap sparse
+do_test off ignore off sparse
+do_test off unmap off sparse
+do_test off unmap unmap sparse
+do_test full ignore off full
+do_test full unmap off sparse
+do_test full unmap unmap sparse
+
+_send_qemu_cmd $h1 '{"execute":"quit"}' ''
+
+# success, all done
+echo '*** done'
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/tests/mirror-sparse.out b/tests/qemu-iotests/tests/mirror-sparse.out
new file mode 100644
index 0000000..2103b89
--- /dev/null
+++ b/tests/qemu-iotests/tests/mirror-sparse.out
@@ -0,0 +1,365 @@
+QA output created by mirror-sparse
+
+=== Initial image setup ===
+
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=20971520
+wrote 2097152/2097152 bytes at offset 8388608
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+{"execute": "qmp_capabilities"}
+{"return": {}}
+
+=== Testing creation=external discard=ignore zeroes=off ===
+
+{"execute": "blockdev-add", "arguments":
+ {"node-name": "dst", "driver":"file",
+ "filename":"TEST_DIR/t.IMGFMT", "aio":"threads",
+ "auto-read-only":true, "discard":"ignore",
+ "detect-zeroes":"off"}}
+{"return": {}}
+{"execute":"blockdev-mirror", "arguments":
+ {"sync":"full", "device":"src", "target":"dst",
+ "job-id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}}
+{"execute": "job-complete", "arguments":
+ {"id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"return": {}}
+{"execute": "blockdev-del", "arguments":
+ {"node-name": "dst"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}}
+{"return": {}}
+Images are identical.
+Destination is sparse; expected sparse
+
+=== Testing creation=external discard=unmap zeroes=off ===
+
+{"execute": "blockdev-add", "arguments":
+ {"node-name": "dst", "driver":"file",
+ "filename":"TEST_DIR/t.IMGFMT", "aio":"threads",
+ "auto-read-only":true, "discard":"unmap",
+ "detect-zeroes":"off"}}
+{"return": {}}
+{"execute":"blockdev-mirror", "arguments":
+ {"sync":"full", "device":"src", "target":"dst",
+ "job-id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}}
+{"execute": "job-complete", "arguments":
+ {"id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"return": {}}
+{"execute": "blockdev-del", "arguments":
+ {"node-name": "dst"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}}
+{"return": {}}
+Images are identical.
+Destination is sparse; expected sparse
+
+=== Testing creation=external discard=unmap zeroes=unmap ===
+
+{"execute": "blockdev-add", "arguments":
+ {"node-name": "dst", "driver":"file",
+ "filename":"TEST_DIR/t.IMGFMT", "aio":"threads",
+ "auto-read-only":true, "discard":"unmap",
+ "detect-zeroes":"unmap"}}
+{"return": {}}
+{"execute":"blockdev-mirror", "arguments":
+ {"sync":"full", "device":"src", "target":"dst",
+ "job-id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}}
+{"execute": "job-complete", "arguments":
+ {"id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"return": {}}
+{"execute": "blockdev-del", "arguments":
+ {"node-name": "dst"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}}
+{"return": {}}
+Images are identical.
+Destination is sparse; expected sparse
+
+=== Testing creation=off discard=ignore zeroes=off ===
+
+{"execute": "blockdev-create", "arguments":
+ {"options": {"driver":"file", "filename":"TEST_DIR/t.IMGFMT",
+ "size":20971520, "preallocation":"off"},
+ "job-id":"job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job1"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job1"}}
+{"execute": "job-dismiss", "arguments":
+ {"id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job1"}}
+{"return": {}}
+{"execute": "blockdev-add", "arguments":
+ {"node-name": "dst", "driver":"file",
+ "filename":"TEST_DIR/t.IMGFMT", "aio":"threads",
+ "auto-read-only":true, "discard":"ignore",
+ "detect-zeroes":"off"}}
+{"return": {}}
+{"execute":"blockdev-mirror", "arguments":
+ {"sync":"full", "device":"src", "target":"dst",
+ "job-id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}}
+{"execute": "job-complete", "arguments":
+ {"id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"return": {}}
+{"execute": "blockdev-del", "arguments":
+ {"node-name": "dst"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}}
+{"return": {}}
+Images are identical.
+Destination is sparse; expected sparse
+
+=== Testing creation=off discard=unmap zeroes=off ===
+
+{"execute": "blockdev-create", "arguments":
+ {"options": {"driver":"file", "filename":"TEST_DIR/t.IMGFMT",
+ "size":20971520, "preallocation":"off"},
+ "job-id":"job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job1"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job1"}}
+{"execute": "job-dismiss", "arguments":
+ {"id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job1"}}
+{"return": {}}
+{"execute": "blockdev-add", "arguments":
+ {"node-name": "dst", "driver":"file",
+ "filename":"TEST_DIR/t.IMGFMT", "aio":"threads",
+ "auto-read-only":true, "discard":"unmap",
+ "detect-zeroes":"off"}}
+{"return": {}}
+{"execute":"blockdev-mirror", "arguments":
+ {"sync":"full", "device":"src", "target":"dst",
+ "job-id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}}
+{"execute": "job-complete", "arguments":
+ {"id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"return": {}}
+{"execute": "blockdev-del", "arguments":
+ {"node-name": "dst"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}}
+{"return": {}}
+Images are identical.
+Destination is sparse; expected sparse
+
+=== Testing creation=off discard=unmap zeroes=unmap ===
+
+{"execute": "blockdev-create", "arguments":
+ {"options": {"driver":"file", "filename":"TEST_DIR/t.IMGFMT",
+ "size":20971520, "preallocation":"off"},
+ "job-id":"job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job1"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job1"}}
+{"execute": "job-dismiss", "arguments":
+ {"id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job1"}}
+{"return": {}}
+{"execute": "blockdev-add", "arguments":
+ {"node-name": "dst", "driver":"file",
+ "filename":"TEST_DIR/t.IMGFMT", "aio":"threads",
+ "auto-read-only":true, "discard":"unmap",
+ "detect-zeroes":"unmap"}}
+{"return": {}}
+{"execute":"blockdev-mirror", "arguments":
+ {"sync":"full", "device":"src", "target":"dst",
+ "job-id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}}
+{"execute": "job-complete", "arguments":
+ {"id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"return": {}}
+{"execute": "blockdev-del", "arguments":
+ {"node-name": "dst"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}}
+{"return": {}}
+Images are identical.
+Destination is sparse; expected sparse
+
+=== Testing creation=full discard=ignore zeroes=off ===
+
+{"execute": "blockdev-create", "arguments":
+ {"options": {"driver":"file", "filename":"TEST_DIR/t.IMGFMT",
+ "size":20971520, "preallocation":"full"},
+ "job-id":"job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job1"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job1"}}
+{"execute": "job-dismiss", "arguments":
+ {"id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job1"}}
+{"return": {}}
+{"execute": "blockdev-add", "arguments":
+ {"node-name": "dst", "driver":"file",
+ "filename":"TEST_DIR/t.IMGFMT", "aio":"threads",
+ "auto-read-only":true, "discard":"ignore",
+ "detect-zeroes":"off"}}
+{"return": {}}
+{"execute":"blockdev-mirror", "arguments":
+ {"sync":"full", "device":"src", "target":"dst",
+ "job-id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}}
+{"execute": "job-complete", "arguments":
+ {"id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"return": {}}
+{"execute": "blockdev-del", "arguments":
+ {"node-name": "dst"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}}
+{"return": {}}
+Images are identical.
+Destination is full; expected full
+
+=== Testing creation=full discard=unmap zeroes=off ===
+
+{"execute": "blockdev-create", "arguments":
+ {"options": {"driver":"file", "filename":"TEST_DIR/t.IMGFMT",
+ "size":20971520, "preallocation":"full"},
+ "job-id":"job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job1"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job1"}}
+{"execute": "job-dismiss", "arguments":
+ {"id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job1"}}
+{"return": {}}
+{"execute": "blockdev-add", "arguments":
+ {"node-name": "dst", "driver":"file",
+ "filename":"TEST_DIR/t.IMGFMT", "aio":"threads",
+ "auto-read-only":true, "discard":"unmap",
+ "detect-zeroes":"off"}}
+{"return": {}}
+{"execute":"blockdev-mirror", "arguments":
+ {"sync":"full", "device":"src", "target":"dst",
+ "job-id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}}
+{"execute": "job-complete", "arguments":
+ {"id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"return": {}}
+{"execute": "blockdev-del", "arguments":
+ {"node-name": "dst"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}}
+{"return": {}}
+Images are identical.
+Destination is sparse; expected sparse
+
+=== Testing creation=full discard=unmap zeroes=unmap ===
+
+{"execute": "blockdev-create", "arguments":
+ {"options": {"driver":"file", "filename":"TEST_DIR/t.IMGFMT",
+ "size":20971520, "preallocation":"full"},
+ "job-id":"job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job1"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job1"}}
+{"execute": "job-dismiss", "arguments":
+ {"id": "job1"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job1"}}
+{"return": {}}
+{"execute": "blockdev-add", "arguments":
+ {"node-name": "dst", "driver":"file",
+ "filename":"TEST_DIR/t.IMGFMT", "aio":"threads",
+ "auto-read-only":true, "discard":"unmap",
+ "detect-zeroes":"unmap"}}
+{"return": {}}
+{"execute":"blockdev-mirror", "arguments":
+ {"sync":"full", "device":"src", "target":"dst",
+ "job-id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}}
+{"execute": "job-complete", "arguments":
+ {"id":"job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"return": {}}
+{"execute": "blockdev-del", "arguments":
+ {"node-name": "dst"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}}
+{"return": {}}
+Images are identical.
+Destination is sparse; expected sparse
+{"execute":"quit"}
+*** done
diff --git a/tests/qemu-iotests/tests/qcow2-encryption b/tests/qemu-iotests/tests/qcow2-encryption
new file mode 100755
index 0000000..95f6195
--- /dev/null
+++ b/tests/qemu-iotests/tests/qcow2-encryption
@@ -0,0 +1,75 @@
+#!/usr/bin/env bash
+# group: rw quick
+#
+# Test case for encryption support in qcow2
+#
+# Copyright (C) 2025 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf@redhat.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ../common.rc
+. ../common.filter
+
+# This tests qcow2-specific low-level functionality
+_supported_fmt qcow2
+_supported_proto file
+_require_working_luks
+
+IMG_SIZE=64M
+
+echo
+echo "=== Create an encrypted image ==="
+echo
+
+_make_test_img --object secret,id=sec0,data=123456 -o encrypt.format=luks,encrypt.key-secret=sec0 $IMG_SIZE
+$PYTHON ../qcow2.py "$TEST_IMG" dump-header-exts
+_img_info
+$QEMU_IMG check \
+ --object secret,id=sec0,data=123456 \
+ --image-opts file.filename="$TEST_IMG",encrypt.key-secret=sec0 \
+ | _filter_qemu_img_check
+
+echo
+echo "=== Remove the header extension ==="
+echo
+
+$PYTHON ../qcow2.py "$TEST_IMG" del-header-ext 0x0537be77
+$PYTHON ../qcow2.py "$TEST_IMG" dump-header-exts
+_img_info
+$QEMU_IMG check \
+ --object secret,id=sec0,data=123456 \
+ --image-opts file.filename="$TEST_IMG",encrypt.key-secret=sec0 2>&1 \
+ | _filter_qemu_img_check \
+ | _filter_testdir
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/tests/qcow2-encryption.out b/tests/qemu-iotests/tests/qcow2-encryption.out
new file mode 100644
index 0000000..9b549dc2
--- /dev/null
+++ b/tests/qemu-iotests/tests/qcow2-encryption.out
@@ -0,0 +1,32 @@
+QA output created by qcow2-encryption
+
+=== Create an encrypted image ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+Header extension:
+magic 0x537be77 (Crypto header)
+length 16
+data <binary>
+
+Header extension:
+magic 0x6803f857 (Feature table)
+length 384
+data <binary>
+
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 64 MiB (67108864 bytes)
+encrypted: yes
+cluster_size: 65536
+No errors were found on the image.
+
+=== Remove the header extension ===
+
+Header extension:
+magic 0x6803f857 (Feature table)
+length 384
+data <binary>
+
+qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Missing CRYPTO header for crypt method 2
+qemu-img: Could not open 'file.filename=TEST_DIR/t.qcow2,encrypt.key-secret=sec0': Missing CRYPTO header for crypt method 2
+*** done
diff --git a/tests/qemu-iotests/tests/qsd-migrate b/tests/qemu-iotests/tests/qsd-migrate
new file mode 100755
index 0000000..a4c6592
--- /dev/null
+++ b/tests/qemu-iotests/tests/qsd-migrate
@@ -0,0 +1,140 @@
+#!/usr/bin/env python3
+# group: rw quick
+#
+# Copyright (C) Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
+
+import iotests
+
+from iotests import filter_qemu_io, filter_qtest
+
+iotests.script_initialize(supported_fmts=['qcow2', 'qed', 'raw'],
+ supported_protocols=['file'],
+ supported_platforms=['linux'])
+
+with iotests.FilePath('disk.img') as path, \
+ iotests.FilePath('nbd-src.sock', base_dir=iotests.sock_dir) as nbd_src, \
+ iotests.FilePath('nbd-dst.sock', base_dir=iotests.sock_dir) as nbd_dst, \
+ iotests.FilePath('migrate.sock', base_dir=iotests.sock_dir) as mig_sock, \
+ iotests.VM(path_suffix="-src") as vm_src, \
+ iotests.VM(path_suffix="-dst") as vm_dst:
+
+ img_size = '10M'
+
+ iotests.log('Preparing disk...')
+ iotests.qemu_img_create('-f', iotests.imgfmt, path, img_size)
+
+ iotests.log('Launching source QSD...')
+ qsd_src = iotests.QemuStorageDaemon(
+ '--blockdev', f'file,node-name=disk-file,filename={path}',
+ '--blockdev', f'{iotests.imgfmt},file=disk-file,node-name=disk-fmt',
+ '--nbd-server', f'addr.type=unix,addr.path={nbd_src}',
+ '--export', 'nbd,id=exp0,node-name=disk-fmt,writable=true,'
+ 'allow-inactive=true',
+ qmp=True,
+ )
+
+ iotests.log('Launching source VM...')
+ vm_src.add_args('-blockdev', f'nbd,node-name=disk,server.type=unix,'
+ f'server.path={nbd_src},export=disk-fmt')
+ vm_src.add_args('-device', 'virtio-blk,drive=disk,id=virtio0')
+ vm_src.launch()
+
+ iotests.log('Launching destination QSD...')
+ qsd_dst = iotests.QemuStorageDaemon(
+ '--blockdev', f'file,node-name=disk-file,filename={path},active=off',
+ '--blockdev', f'{iotests.imgfmt},file=disk-file,node-name=disk-fmt,'
+ f'active=off',
+ '--nbd-server', f'addr.type=unix,addr.path={nbd_dst}',
+ '--export', 'nbd,id=exp0,node-name=disk-fmt,writable=true,'
+ 'allow-inactive=true',
+ qmp=True,
+ instance_id='b',
+ )
+
+ iotests.log('Launching destination VM...')
+ vm_dst.add_args('-blockdev', f'nbd,node-name=disk,server.type=unix,'
+ f'server.path={nbd_dst},export=disk-fmt')
+ vm_dst.add_args('-device', 'virtio-blk,drive=disk,id=virtio0')
+ vm_dst.add_args('-incoming', f'unix:{mig_sock}')
+ vm_dst.launch()
+
+ iotests.log('\nTest I/O on the source')
+ vm_src.hmp_qemu_io('virtio0/virtio-backend', 'write -P 0x11 0 4k',
+ use_log=True, qdev=True)
+ vm_src.hmp_qemu_io('virtio0/virtio-backend', 'read -P 0x11 0 4k',
+ use_log=True, qdev=True)
+
+ iotests.log('\nStarting migration...')
+
+ mig_caps = [
+ {'capability': 'events', 'state': True},
+ {'capability': 'pause-before-switchover', 'state': True},
+ ]
+ vm_src.qmp_log('migrate-set-capabilities', capabilities=mig_caps)
+ vm_dst.qmp_log('migrate-set-capabilities', capabilities=mig_caps)
+ vm_src.qmp_log('migrate', uri=f'unix:{mig_sock}',
+ filters=[iotests.filter_qmp_testfiles])
+
+ vm_src.event_wait('MIGRATION',
+ match={'data': {'status': 'pre-switchover'}})
+
+ iotests.log('\nPre-switchover: Reconfigure QSD instances')
+
+ iotests.log(qsd_src.qmp('blockdev-set-active', {'active': False}))
+
+ # Reading is okay from both sides while the image is inactive. Note that
+ # the destination may have stale data until it activates the image, though.
+ vm_src.hmp_qemu_io('virtio0/virtio-backend', 'read -P 0x11 0 4k',
+ use_log=True, qdev=True)
+ vm_dst.hmp_qemu_io('virtio0/virtio-backend', 'read 0 4k',
+ use_log=True, qdev=True)
+
+ iotests.log(qsd_dst.qmp('blockdev-set-active', {'active': True}))
+
+ iotests.log('\nCompleting migration...')
+
+ vm_src.qmp_log('migrate-continue', state='pre-switchover')
+ vm_dst.event_wait('MIGRATION', match={'data': {'status': 'completed'}})
+
+ iotests.log('\nTest I/O on the destination')
+
+ # Now the destination must see what the source wrote
+ vm_dst.hmp_qemu_io('virtio0/virtio-backend', 'read -P 0x11 0 4k',
+ use_log=True, qdev=True)
+
+ # And be able to overwrite it
+ vm_dst.hmp_qemu_io('virtio0/virtio-backend', 'write -P 0x22 0 4k',
+ use_log=True, qdev=True)
+ vm_dst.hmp_qemu_io('virtio0/virtio-backend', 'read -P 0x22 0 4k',
+ use_log=True, qdev=True)
+
+ iotests.log('\nDone')
+
+ vm_src.shutdown()
+ iotests.log('\n--- vm_src log ---')
+ log = vm_src.get_log()
+ if log:
+ iotests.log(log, [filter_qtest, filter_qemu_io])
+ qsd_src.stop()
+
+ vm_dst.shutdown()
+ iotests.log('\n--- vm_dst log ---')
+ log = vm_dst.get_log()
+ if log:
+ iotests.log(log, [filter_qtest, filter_qemu_io])
+ qsd_dst.stop()
diff --git a/tests/qemu-iotests/tests/qsd-migrate.out b/tests/qemu-iotests/tests/qsd-migrate.out
new file mode 100644
index 0000000..4a5241e
--- /dev/null
+++ b/tests/qemu-iotests/tests/qsd-migrate.out
@@ -0,0 +1,59 @@
+Preparing disk...
+Launching source QSD...
+Launching source VM...
+Launching destination QSD...
+Launching destination VM...
+
+Test I/O on the source
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"write -P 0x11 0 4k\""}}
+{"return": ""}
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"read -P 0x11 0 4k\""}}
+{"return": ""}
+
+Starting migration...
+{"execute": "migrate-set-capabilities", "arguments": {"capabilities": [{"capability": "events", "state": true}, {"capability": "pause-before-switchover", "state": true}]}}
+{"return": {}}
+{"execute": "migrate-set-capabilities", "arguments": {"capabilities": [{"capability": "events", "state": true}, {"capability": "pause-before-switchover", "state": true}]}}
+{"return": {}}
+{"execute": "migrate", "arguments": {"uri": "unix:SOCK_DIR/PID-migrate.sock"}}
+{"return": {}}
+
+Pre-switchover: Reconfigure QSD instances
+{"return": {}}
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"read -P 0x11 0 4k\""}}
+{"return": ""}
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"read 0 4k\""}}
+{"return": ""}
+{"return": {}}
+
+Completing migration...
+{"execute": "migrate-continue", "arguments": {"state": "pre-switchover"}}
+{"return": {}}
+
+Test I/O on the destination
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"read -P 0x11 0 4k\""}}
+{"return": ""}
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"write -P 0x22 0 4k\""}}
+{"return": ""}
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"read -P 0x22 0 4k\""}}
+{"return": ""}
+
+Done
+
+--- vm_src log ---
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- vm_dst log ---
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/tests/write-zeroes-unmap b/tests/qemu-iotests/tests/write-zeroes-unmap
index 7cfeeaf..f90fb8e 100755
--- a/tests/qemu-iotests/tests/write-zeroes-unmap
+++ b/tests/qemu-iotests/tests/write-zeroes-unmap
@@ -32,6 +32,7 @@ cd ..
_supported_fmt raw
_supported_proto file
_supported_os Linux
+_require_disk_usage
create_test_image() {
_make_test_img -f $IMGFMT 1m
diff --git a/tests/qtest/acpi-utils.c b/tests/qtest/acpi-utils.c
index 673fc97..9dc24fb 100644
--- a/tests/qtest/acpi-utils.c
+++ b/tests/qtest/acpi-utils.c
@@ -156,5 +156,4 @@ uint64_t acpi_find_rsdp_address_uefi(QTestState *qts, uint64_t start,
g_usleep(TEST_DELAY);
}
g_assert_not_reached();
- return 0;
}
diff --git a/tests/qtest/adm1266-test.c b/tests/qtest/adm1266-test.c
index 6c312c4..5ae8206 100644
--- a/tests/qtest/adm1266-test.c
+++ b/tests/qtest/adm1266-test.c
@@ -13,8 +13,8 @@
#include "libqtest-single.h"
#include "libqos/qgraph.h"
#include "libqos/i2c.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qnum.h"
+#include "qobject/qdict.h"
+#include "qobject/qnum.h"
#include "qemu/bitops.h"
#define TEST_ID "adm1266-test"
diff --git a/tests/qtest/adm1272-test.c b/tests/qtest/adm1272-test.c
index 63f8514..2abda8d 100644
--- a/tests/qtest/adm1272-test.c
+++ b/tests/qtest/adm1272-test.c
@@ -12,8 +12,8 @@
#include "libqtest-single.h"
#include "libqos/qgraph.h"
#include "libqos/i2c.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qnum.h"
+#include "qobject/qdict.h"
+#include "qobject/qnum.h"
#include "qemu/bitops.h"
#define TEST_ID "adm1272-test"
diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c
index 5a1923f..e8aabfc 100644
--- a/tests/qtest/ahci-test.c
+++ b/tests/qtest/ahci-test.c
@@ -30,7 +30,7 @@
#include "libqos/ahci.h"
#include "libqos/pci-pc.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qemu/host-utils.h"
#include "hw/pci/pci_ids.h"
@@ -1881,7 +1881,6 @@ static void test_io_interface(gconstpointer opaque)
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,
diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c
index cfd6f77..eb8ddeb 100644
--- a/tests/qtest/arm-cpu-features.c
+++ b/tests/qtest/arm-cpu-features.c
@@ -11,8 +11,8 @@
#include "qemu/osdep.h"
#include "qemu/bitops.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qjson.h"
+#include "qobject/qdict.h"
+#include "qobject/qjson.h"
/*
* We expect the SVE max-vq to be 16. Also it must be <= 64
@@ -419,21 +419,28 @@ static void pauth_tests_default(QTestState *qts, const char *cpu_type)
assert_has_feature_enabled(qts, cpu_type, "pauth");
assert_has_feature_disabled(qts, cpu_type, "pauth-impdef");
assert_has_feature_disabled(qts, cpu_type, "pauth-qarma3");
+ assert_has_feature_disabled(qts, cpu_type, "pauth-qarma5");
assert_set_feature(qts, cpu_type, "pauth", false);
assert_set_feature(qts, cpu_type, "pauth", true);
assert_set_feature(qts, cpu_type, "pauth-impdef", true);
assert_set_feature(qts, cpu_type, "pauth-impdef", false);
assert_set_feature(qts, cpu_type, "pauth-qarma3", true);
assert_set_feature(qts, cpu_type, "pauth-qarma3", false);
+ assert_set_feature(qts, cpu_type, "pauth-qarma5", true);
+ assert_set_feature(qts, cpu_type, "pauth-qarma5", false);
assert_error(qts, cpu_type,
- "cannot enable pauth-impdef or pauth-qarma3 without pauth",
+ "cannot enable pauth-impdef, pauth-qarma3 or pauth-qarma5 without pauth",
"{ 'pauth': false, 'pauth-impdef': true }");
assert_error(qts, cpu_type,
- "cannot enable pauth-impdef or pauth-qarma3 without pauth",
+ "cannot enable pauth-impdef, pauth-qarma3 or pauth-qarma5 without pauth",
"{ 'pauth': false, 'pauth-qarma3': true }");
assert_error(qts, cpu_type,
- "cannot enable both pauth-impdef and pauth-qarma3",
- "{ 'pauth': true, 'pauth-impdef': true, 'pauth-qarma3': true }");
+ "cannot enable pauth-impdef, pauth-qarma3 or pauth-qarma5 without pauth",
+ "{ 'pauth': false, 'pauth-qarma5': true }");
+ assert_error(qts, cpu_type,
+ "cannot enable pauth-impdef, pauth-qarma3 and pauth-qarma5 at the same time",
+ "{ 'pauth': true, 'pauth-impdef': true, 'pauth-qarma3': true,"
+ " 'pauth-qarma5': true }");
}
static void test_query_cpu_model_expansion(const void *data)
diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c
new file mode 100644
index 0000000..0f7f911
--- /dev/null
+++ b/tests/qtest/aspeed-hace-utils.c
@@ -0,0 +1,646 @@
+/*
+ * QTest testcase for the ASPEED Hash and Crypto Engine
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 IBM Corp.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/bitops.h"
+#include "aspeed-hace-utils.h"
+
+/*
+ * Test vector is the ascii "abc"
+ *
+ * Expected results were generated using command line utitiles:
+ *
+ * echo -n -e 'abc' | dd of=/tmp/test
+ * for hash in sha512sum sha384sum sha256sum md5sum; do $hash /tmp/test; done
+ *
+ */
+static const uint8_t test_vector[3] = {0x61, 0x62, 0x63};
+
+static const uint8_t test_result_sha512[64] = {
+ 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49,
+ 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
+ 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a,
+ 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
+ 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f,
+ 0xa5, 0x4c, 0xa4, 0x9f};
+
+static const uint8_t test_result_sha384[48] = {
+ 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b, 0xb5, 0xa0, 0x3d, 0x69,
+ 0x9a, 0xc6, 0x50, 0x07, 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63,
+ 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed, 0x80, 0x86, 0x07, 0x2b,
+ 0xa1, 0xe7, 0xcc, 0x23, 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7};
+
+static const uint8_t test_result_sha256[32] = {
+ 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
+ 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad};
+
+static const uint8_t test_result_md5[16] = {
+ 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d,
+ 0x28, 0xe1, 0x7f, 0x72};
+
+/*
+ * The Scatter-Gather Test vector is the ascii "abc" "def" "ghi", broken
+ * into blocks of 3 characters as shown
+ *
+ * Expected results were generated using command line utitiles:
+ *
+ * echo -n -e 'abcdefghijkl' | dd of=/tmp/test
+ * for hash in sha512sum sha384sum sha256sum; do $hash /tmp/test; done
+ *
+ */
+static const uint8_t test_vector_sg1[6] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
+static const uint8_t test_vector_sg2[3] = {0x67, 0x68, 0x69};
+static const uint8_t test_vector_sg3[3] = {0x6a, 0x6b, 0x6c};
+
+static const uint8_t test_result_sg_sha512[64] = {
+ 0x17, 0x80, 0x7c, 0x72, 0x8e, 0xe3, 0xba, 0x35, 0xe7, 0xcf, 0x7a, 0xf8,
+ 0x23, 0x11, 0x6d, 0x26, 0xe4, 0x1e, 0x5d, 0x4d, 0x6c, 0x2f, 0xf1, 0xf3,
+ 0x72, 0x0d, 0x3d, 0x96, 0xaa, 0xcb, 0x6f, 0x69, 0xde, 0x64, 0x2e, 0x63,
+ 0xd5, 0xb7, 0x3f, 0xc3, 0x96, 0xc1, 0x2b, 0xe3, 0x8b, 0x2b, 0xd5, 0xd8,
+ 0x84, 0x25, 0x7c, 0x32, 0xc8, 0xf6, 0xd0, 0x85, 0x4a, 0xe6, 0xb5, 0x40,
+ 0xf8, 0x6d, 0xda, 0x2e};
+
+static const uint8_t test_result_sg_sha384[48] = {
+ 0x10, 0x3c, 0xa9, 0x6c, 0x06, 0xa1, 0xce, 0x79, 0x8f, 0x08, 0xf8, 0xef,
+ 0xf0, 0xdf, 0xb0, 0xcc, 0xdb, 0x56, 0x7d, 0x48, 0xb2, 0x85, 0xb2, 0x3d,
+ 0x0c, 0xd7, 0x73, 0x45, 0x46, 0x67, 0xa3, 0xc2, 0xfa, 0x5f, 0x1b, 0x58,
+ 0xd9, 0xcd, 0xf2, 0x32, 0x9b, 0xd9, 0x97, 0x97, 0x30, 0xbf, 0xaa, 0xff};
+
+static const uint8_t test_result_sg_sha256[32] = {
+ 0xd6, 0x82, 0xed, 0x4c, 0xa4, 0xd9, 0x89, 0xc1, 0x34, 0xec, 0x94, 0xf1,
+ 0x55, 0x1e, 0x1e, 0xc5, 0x80, 0xdd, 0x6d, 0x5a, 0x6e, 0xcd, 0xe9, 0xf3,
+ 0xd3, 0x5e, 0x6e, 0x4a, 0x71, 0x7f, 0xbd, 0xe4};
+
+/*
+ * The accumulative mode requires firmware to provide internal initial state
+ * and message padding (including length L at the end of padding).
+ *
+ * This test vector is a ascii text "abc" with padding message.
+ *
+ * Expected results were generated using command line utitiles:
+ *
+ * echo -n -e 'abc' | dd of=/tmp/test
+ * for hash in sha512sum sha384sum sha256sum; do $hash /tmp/test; done
+ */
+static const uint8_t test_vector_accum_512[128] = {
+ 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18};
+
+static const uint8_t test_vector_accum_384[128] = {
+ 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18};
+
+static const uint8_t test_vector_accum_256[64] = {
+ 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18};
+
+static const uint8_t test_result_accum_sha512[64] = {
+ 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49,
+ 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
+ 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a,
+ 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
+ 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f,
+ 0xa5, 0x4c, 0xa4, 0x9f};
+
+static const uint8_t test_result_accum_sha384[48] = {
+ 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b, 0xb5, 0xa0, 0x3d, 0x69,
+ 0x9a, 0xc6, 0x50, 0x07, 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63,
+ 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed, 0x80, 0x86, 0x07, 0x2b,
+ 0xa1, 0xe7, 0xcc, 0x23, 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7};
+
+static const uint8_t test_result_accum_sha256[32] = {
+ 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
+ 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad};
+
+static void write_regs(QTestState *s, uint32_t base, uint64_t src,
+ uint32_t length, uint64_t out, uint32_t method)
+{
+ qtest_writel(s, base + HACE_HASH_SRC, extract64(src, 0, 32));
+ qtest_writel(s, base + HACE_HASH_SRC_HI, extract64(src, 32, 32));
+ qtest_writel(s, base + HACE_HASH_DIGEST, extract64(out, 0, 32));
+ qtest_writel(s, base + HACE_HASH_DIGEST_HI, extract64(out, 32, 32));
+ qtest_writel(s, base + HACE_HASH_DATA_LEN, length);
+ qtest_writel(s, base + HACE_HASH_CMD, HACE_SHA_BE_EN | method);
+}
+
+void aspeed_test_md5(const char *machine, const uint32_t base,
+ const uint64_t src_addr)
+
+{
+ QTestState *s = qtest_init(machine);
+
+ uint64_t digest_addr = src_addr + 0x010000;
+ uint8_t digest[16] = {0};
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector));
+
+ write_regs(s, base, src_addr, sizeof(test_vector),
+ digest_addr, HACE_ALGO_MD5);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_md5, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+void aspeed_test_sha256(const char *machine, const uint32_t base,
+ const uint64_t src_addr)
+{
+ QTestState *s = qtest_init(machine);
+
+ const uint64_t digest_addr = src_addr + 0x10000;
+ uint8_t digest[32] = {0};
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector));
+
+ write_regs(s, base, src_addr, sizeof(test_vector), digest_addr,
+ HACE_ALGO_SHA256);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_sha256, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+void aspeed_test_sha384(const char *machine, const uint32_t base,
+ const uint64_t src_addr)
+{
+ QTestState *s = qtest_init(machine);
+
+ const uint64_t digest_addr = src_addr + 0x10000;
+ uint8_t digest[48] = {0};
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector));
+
+ write_regs(s, base, src_addr, sizeof(test_vector), digest_addr,
+ HACE_ALGO_SHA384);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_sha384, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+void aspeed_test_sha512(const char *machine, const uint32_t base,
+ const uint64_t src_addr)
+{
+ QTestState *s = qtest_init(machine);
+
+ const uint64_t digest_addr = src_addr + 0x10000;
+ uint8_t digest[64] = {0};
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector));
+
+ write_regs(s, base, src_addr, sizeof(test_vector), digest_addr,
+ HACE_ALGO_SHA512);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_sha512, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+void aspeed_test_sha256_sg(const char *machine, const uint32_t base,
+ const uint64_t src_addr)
+{
+ QTestState *s = qtest_init(machine);
+
+ const uint64_t src_addr_1 = src_addr + 0x10000;
+ const uint64_t src_addr_2 = src_addr + 0x20000;
+ const uint64_t src_addr_3 = src_addr + 0x30000;
+ const uint64_t digest_addr = src_addr + 0x40000;
+ uint8_t digest[32] = {0};
+ struct AspeedSgList array[] = {
+ { cpu_to_le32(sizeof(test_vector_sg1)),
+ cpu_to_le32(src_addr_1) },
+ { cpu_to_le32(sizeof(test_vector_sg2)),
+ cpu_to_le32(src_addr_2) },
+ { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST),
+ cpu_to_le32(src_addr_3) },
+ };
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1));
+ qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2));
+ qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3));
+ qtest_memwrite(s, src_addr, array, sizeof(array));
+
+ write_regs(s, base, src_addr,
+ (sizeof(test_vector_sg1)
+ + sizeof(test_vector_sg2)
+ + sizeof(test_vector_sg3)),
+ digest_addr, HACE_ALGO_SHA256 | HACE_SG_EN);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_sg_sha256, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+void aspeed_test_sha384_sg(const char *machine, const uint32_t base,
+ const uint64_t src_addr)
+{
+ QTestState *s = qtest_init(machine);
+
+ const uint64_t src_addr_1 = src_addr + 0x10000;
+ const uint64_t src_addr_2 = src_addr + 0x20000;
+ const uint64_t src_addr_3 = src_addr + 0x30000;
+ const uint64_t digest_addr = src_addr + 0x40000;
+ uint8_t digest[48] = {0};
+ struct AspeedSgList array[] = {
+ { cpu_to_le32(sizeof(test_vector_sg1)),
+ cpu_to_le32(src_addr_1) },
+ { cpu_to_le32(sizeof(test_vector_sg2)),
+ cpu_to_le32(src_addr_2) },
+ { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST),
+ cpu_to_le32(src_addr_3) },
+ };
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1));
+ qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2));
+ qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3));
+ qtest_memwrite(s, src_addr, array, sizeof(array));
+
+ write_regs(s, base, src_addr,
+ (sizeof(test_vector_sg1)
+ + sizeof(test_vector_sg2)
+ + sizeof(test_vector_sg3)),
+ digest_addr, HACE_ALGO_SHA384 | HACE_SG_EN);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_sg_sha384, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+void aspeed_test_sha512_sg(const char *machine, const uint32_t base,
+ const uint64_t src_addr)
+{
+ QTestState *s = qtest_init(machine);
+
+ const uint64_t src_addr_1 = src_addr + 0x10000;
+ const uint64_t src_addr_2 = src_addr + 0x20000;
+ const uint64_t src_addr_3 = src_addr + 0x30000;
+ const uint64_t digest_addr = src_addr + 0x40000;
+ uint8_t digest[64] = {0};
+ struct AspeedSgList array[] = {
+ { cpu_to_le32(sizeof(test_vector_sg1)),
+ cpu_to_le32(src_addr_1) },
+ { cpu_to_le32(sizeof(test_vector_sg2)),
+ cpu_to_le32(src_addr_2) },
+ { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST),
+ cpu_to_le32(src_addr_3) },
+ };
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1));
+ qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2));
+ qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3));
+ qtest_memwrite(s, src_addr, array, sizeof(array));
+
+ write_regs(s, base, src_addr,
+ (sizeof(test_vector_sg1)
+ + sizeof(test_vector_sg2)
+ + sizeof(test_vector_sg3)),
+ digest_addr, HACE_ALGO_SHA512 | HACE_SG_EN);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_sg_sha512, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+void aspeed_test_sha256_accum(const char *machine, const uint32_t base,
+ const uint64_t src_addr)
+{
+ QTestState *s = qtest_init(machine);
+
+ const uint64_t buffer_addr = src_addr + 0x10000;
+ const uint64_t digest_addr = src_addr + 0x40000;
+ uint8_t digest[32] = {0};
+ struct AspeedSgList array[] = {
+ { cpu_to_le32(sizeof(test_vector_accum_256) | SG_LIST_LEN_LAST),
+ cpu_to_le32(buffer_addr) },
+ };
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, buffer_addr, test_vector_accum_256,
+ sizeof(test_vector_accum_256));
+ qtest_memwrite(s, src_addr, array, sizeof(array));
+
+ write_regs(s, base, src_addr, sizeof(test_vector_accum_256),
+ digest_addr, HACE_ALGO_SHA256 | HACE_SG_EN | HACE_ACCUM_EN);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_accum_sha256, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+void aspeed_test_sha384_accum(const char *machine, const uint32_t base,
+ const uint64_t src_addr)
+{
+ QTestState *s = qtest_init(machine);
+
+ const uint64_t buffer_addr = src_addr + 0x10000;
+ const uint64_t digest_addr = src_addr + 0x40000;
+ uint8_t digest[48] = {0};
+ struct AspeedSgList array[] = {
+ { cpu_to_le32(sizeof(test_vector_accum_384) | SG_LIST_LEN_LAST),
+ cpu_to_le32(buffer_addr) },
+ };
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, buffer_addr, test_vector_accum_384,
+ sizeof(test_vector_accum_384));
+ qtest_memwrite(s, src_addr, array, sizeof(array));
+
+ write_regs(s, base, src_addr, sizeof(test_vector_accum_384),
+ digest_addr, HACE_ALGO_SHA384 | HACE_SG_EN | HACE_ACCUM_EN);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_accum_sha384, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+void aspeed_test_sha512_accum(const char *machine, const uint32_t base,
+ const uint64_t src_addr)
+{
+ QTestState *s = qtest_init(machine);
+
+ const uint64_t buffer_addr = src_addr + 0x10000;
+ const uint64_t digest_addr = src_addr + 0x40000;
+ uint8_t digest[64] = {0};
+ struct AspeedSgList array[] = {
+ { cpu_to_le32(sizeof(test_vector_accum_512) | SG_LIST_LEN_LAST),
+ cpu_to_le32(buffer_addr) },
+ };
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, buffer_addr, test_vector_accum_512,
+ sizeof(test_vector_accum_512));
+ qtest_memwrite(s, src_addr, array, sizeof(array));
+
+ write_regs(s, base, src_addr, sizeof(test_vector_accum_512),
+ digest_addr, HACE_ALGO_SHA512 | HACE_SG_EN | HACE_ACCUM_EN);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_accum_sha512, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+void aspeed_test_addresses(const char *machine, const uint32_t base,
+ const struct AspeedMasks *expected)
+{
+ QTestState *s = qtest_init(machine);
+
+ /*
+ * Check command mode is zero, meaning engine is in direct access mode,
+ * as this affects the masking behavior of the HASH_SRC register.
+ */
+ g_assert_cmphex(qtest_readl(s, base + HACE_CMD), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC_HI), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST_HI), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_KEY_BUFF), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_KEY_BUFF_HI), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0);
+
+ /* Check that the address masking is correct */
+ qtest_writel(s, base + HACE_HASH_SRC, 0xffffffff);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, expected->src);
+
+ qtest_writel(s, base + HACE_HASH_SRC_HI, 0xffffffff);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC_HI),
+ ==, expected->src_hi);
+
+ qtest_writel(s, base + HACE_HASH_DIGEST, 0xffffffff);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==,
+ expected->dest);
+
+ qtest_writel(s, base + HACE_HASH_DIGEST_HI, 0xffffffff);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST_HI), ==,
+ expected->dest_hi);
+
+ qtest_writel(s, base + HACE_HASH_KEY_BUFF, 0xffffffff);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_KEY_BUFF), ==,
+ expected->key);
+
+ qtest_writel(s, base + HACE_HASH_KEY_BUFF_HI, 0xffffffff);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_KEY_BUFF_HI), ==,
+ expected->key_hi);
+
+ qtest_writel(s, base + HACE_HASH_DATA_LEN, 0xffffffff);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==,
+ expected->len);
+
+ /* Reset to zero */
+ qtest_writel(s, base + HACE_HASH_SRC, 0);
+ qtest_writel(s, base + HACE_HASH_SRC_HI, 0);
+ qtest_writel(s, base + HACE_HASH_DIGEST, 0);
+ qtest_writel(s, base + HACE_HASH_DIGEST_HI, 0);
+ qtest_writel(s, base + HACE_HASH_KEY_BUFF, 0);
+ qtest_writel(s, base + HACE_HASH_KEY_BUFF_HI, 0);
+ qtest_writel(s, base + HACE_HASH_DATA_LEN, 0);
+
+ /* Check that all bits are now zero */
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC_HI), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST_HI), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_KEY_BUFF), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_KEY_BUFF_HI), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0);
+
+ qtest_quit(s);
+}
+
diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h
new file mode 100644
index 0000000..c8b2ec4
--- /dev/null
+++ b/tests/qtest/aspeed-hace-utils.h
@@ -0,0 +1,84 @@
+/*
+ * QTest testcase for the ASPEED Hash and Crypto Engine
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 IBM Corp.
+ */
+
+#ifndef TESTS_ASPEED_HACE_UTILS_H
+#define TESTS_ASPEED_HACE_UTILS_H
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/bitops.h"
+
+#define HACE_CMD 0x10
+#define HACE_SHA_BE_EN BIT(3)
+#define HACE_MD5_LE_EN BIT(2)
+#define HACE_ALGO_MD5 0
+#define HACE_ALGO_SHA1 BIT(5)
+#define HACE_ALGO_SHA224 BIT(6)
+#define HACE_ALGO_SHA256 (BIT(4) | BIT(6))
+#define HACE_ALGO_SHA512 (BIT(5) | BIT(6))
+#define HACE_ALGO_SHA384 (BIT(5) | BIT(6) | BIT(10))
+#define HACE_SG_EN BIT(18)
+#define HACE_ACCUM_EN BIT(8)
+
+#define HACE_STS 0x1c
+#define HACE_RSA_ISR BIT(13)
+#define HACE_CRYPTO_ISR BIT(12)
+#define HACE_HASH_ISR BIT(9)
+#define HACE_RSA_BUSY BIT(2)
+#define HACE_CRYPTO_BUSY BIT(1)
+#define HACE_HASH_BUSY BIT(0)
+#define HACE_HASH_SRC 0x20
+#define HACE_HASH_DIGEST 0x24
+#define HACE_HASH_KEY_BUFF 0x28
+#define HACE_HASH_DATA_LEN 0x2c
+#define HACE_HASH_CMD 0x30
+#define HACE_HASH_SRC_HI 0x90
+#define HACE_HASH_DIGEST_HI 0x94
+#define HACE_HASH_KEY_BUFF_HI 0x98
+
+/* Scatter-Gather Hash */
+#define SG_LIST_LEN_LAST BIT(31)
+struct AspeedSgList {
+ uint32_t len;
+ uint32_t addr;
+} __attribute__ ((__packed__));
+
+struct AspeedMasks {
+ uint32_t src;
+ uint32_t dest;
+ uint32_t key;
+ uint32_t len;
+ uint32_t src_hi;
+ uint32_t dest_hi;
+ uint32_t key_hi;
+};
+
+void aspeed_test_md5(const char *machine, const uint32_t base,
+ const uint64_t src_addr);
+void aspeed_test_sha256(const char *machine, const uint32_t base,
+ const uint64_t src_addr);
+void aspeed_test_sha384(const char *machine, const uint32_t base,
+ const uint64_t src_addr);
+void aspeed_test_sha512(const char *machine, const uint32_t base,
+ const uint64_t src_addr);
+void aspeed_test_sha256_sg(const char *machine, const uint32_t base,
+ const uint64_t src_addr);
+void aspeed_test_sha384_sg(const char *machine, const uint32_t base,
+ const uint64_t src_addr);
+void aspeed_test_sha512_sg(const char *machine, const uint32_t base,
+ const uint64_t src_addr);
+void aspeed_test_sha256_accum(const char *machine, const uint32_t base,
+ const uint64_t src_addr);
+void aspeed_test_sha384_accum(const char *machine, const uint32_t base,
+ const uint64_t src_addr);
+void aspeed_test_sha512_accum(const char *machine, const uint32_t base,
+ const uint64_t src_addr);
+void aspeed_test_addresses(const char *machine, const uint32_t base,
+ const struct AspeedMasks *expected);
+
+#endif /* TESTS_ASPEED_HACE_UTILS_H */
+
diff --git a/tests/qtest/aspeed-smc-utils.c b/tests/qtest/aspeed-smc-utils.c
new file mode 100644
index 0000000..c27d09e
--- /dev/null
+++ b/tests/qtest/aspeed-smc-utils.c
@@ -0,0 +1,686 @@
+/*
+ * 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"
+#include "qemu/bitops.h"
+#include "aspeed-smc-utils.h"
+
+/*
+ * 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 inline void spi_writel(const AspeedSMCTestData *data, uint64_t offset,
+ uint32_t value)
+{
+ qtest_writel(data->s, data->spi_base + offset, value);
+}
+
+static inline uint32_t spi_readl(const AspeedSMCTestData *data, uint64_t offset)
+{
+ return qtest_readl(data->s, data->spi_base + offset);
+}
+
+static inline void flash_writeb(const AspeedSMCTestData *data, uint64_t offset,
+ uint8_t value)
+{
+ qtest_writeb(data->s, data->flash_base + offset, value);
+}
+
+static inline void flash_writel(const AspeedSMCTestData *data, uint64_t offset,
+ uint32_t value)
+{
+ qtest_writel(data->s, data->flash_base + offset, value);
+}
+
+static inline uint8_t flash_readb(const AspeedSMCTestData *data,
+ uint64_t offset)
+{
+ return qtest_readb(data->s, data->flash_base + offset);
+}
+
+static inline uint32_t flash_readl(const AspeedSMCTestData *data,
+ uint64_t offset)
+{
+ return qtest_readl(data->s, data->flash_base + offset);
+}
+
+static void spi_conf(const AspeedSMCTestData *data, uint32_t value)
+{
+ uint32_t conf = spi_readl(data, R_CONF);
+
+ conf |= value;
+ spi_writel(data, R_CONF, conf);
+}
+
+static void spi_conf_remove(const AspeedSMCTestData *data, uint32_t value)
+{
+ uint32_t conf = spi_readl(data, R_CONF);
+
+ conf &= ~value;
+ spi_writel(data, R_CONF, conf);
+}
+
+static void spi_ce_ctrl(const AspeedSMCTestData *data, uint32_t value)
+{
+ uint32_t conf = spi_readl(data, R_CE_CTRL);
+
+ conf |= value;
+ spi_writel(data, R_CE_CTRL, conf);
+}
+
+static void spi_ctrl_setmode(const AspeedSMCTestData *data, uint8_t mode,
+ uint8_t cmd)
+{
+ uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
+ uint32_t ctrl = spi_readl(data, ctrl_reg);
+ ctrl &= ~(CTRL_USERMODE | 0xff << 16);
+ ctrl |= mode | (cmd << 16);
+ spi_writel(data, ctrl_reg, ctrl);
+}
+
+static void spi_ctrl_start_user(const AspeedSMCTestData *data)
+{
+ uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
+ uint32_t ctrl = spi_readl(data, ctrl_reg);
+
+ ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
+ spi_writel(data, ctrl_reg, ctrl);
+
+ ctrl &= ~CTRL_CE_STOP_ACTIVE;
+ spi_writel(data, ctrl_reg, ctrl);
+}
+
+static void spi_ctrl_stop_user(const AspeedSMCTestData *data)
+{
+ uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
+ uint32_t ctrl = spi_readl(data, ctrl_reg);
+
+ ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
+ spi_writel(data, ctrl_reg, ctrl);
+}
+
+static void spi_ctrl_set_io_mode(const AspeedSMCTestData *data, uint32_t value)
+{
+ uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
+ uint32_t ctrl = spi_readl(data, ctrl_reg);
+ uint32_t mode;
+
+ mode = value & CTRL_IO_MODE_MASK;
+ ctrl &= ~CTRL_IO_MODE_MASK;
+ ctrl |= mode;
+ spi_writel(data, ctrl_reg, ctrl);
+}
+
+static void flash_reset(const AspeedSMCTestData *data)
+{
+ spi_conf(data, 1 << (CONF_ENABLE_W0 + data->cs));
+
+ spi_ctrl_start_user(data);
+ flash_writeb(data, 0, RESET_ENABLE);
+ flash_writeb(data, 0, RESET_MEMORY);
+ flash_writeb(data, 0, WREN);
+ flash_writeb(data, 0, BULK_ERASE);
+ flash_writeb(data, 0, WRDI);
+ spi_ctrl_stop_user(data);
+
+ spi_conf_remove(data, 1 << (CONF_ENABLE_W0 + data->cs));
+}
+
+static void read_page(const AspeedSMCTestData *data, uint32_t addr,
+ uint32_t *page)
+{
+ int i;
+
+ spi_ctrl_start_user(data);
+
+ flash_writeb(data, 0, EN_4BYTE_ADDR);
+ flash_writeb(data, 0, READ);
+ flash_writel(data, 0, make_be32(addr));
+
+ /* Continuous read are supported */
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ page[i] = make_be32(flash_readl(data, 0));
+ }
+ spi_ctrl_stop_user(data);
+}
+
+static void read_page_mem(const AspeedSMCTestData *data, uint32_t addr,
+ uint32_t *page)
+{
+ int i;
+
+ /* move out USER mode to use direct reads from the AHB bus */
+ spi_ctrl_setmode(data, CTRL_READMODE, READ);
+
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ page[i] = make_be32(flash_readl(data, addr + i * 4));
+ }
+}
+
+static void write_page_mem(const AspeedSMCTestData *data, uint32_t addr,
+ uint32_t write_value)
+{
+ spi_ctrl_setmode(data, CTRL_WRITEMODE, PP);
+
+ for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(data, addr + i * 4, write_value);
+ }
+}
+
+static void assert_page_mem(const AspeedSMCTestData *data, uint32_t addr,
+ uint32_t expected_value)
+{
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ read_page_mem(data, addr, page);
+ for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, expected_value);
+ }
+}
+
+void aspeed_smc_test_read_jedec(const void *data)
+{
+ const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
+ uint32_t jedec = 0x0;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, JEDEC_READ);
+ jedec |= flash_readb(test_data, 0) << 16;
+ jedec |= flash_readb(test_data, 0) << 8;
+ jedec |= flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+
+ flash_reset(test_data);
+
+ g_assert_cmphex(jedec, ==, test_data->jedec_id);
+}
+
+void aspeed_smc_test_erase_sector(const void *data)
+{
+ const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
+ uint32_t some_page_addr = test_data->page_addr;
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ int i;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ /*
+ * Previous page should be full of 0xffs after backend is
+ * initialized
+ */
+ read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(some_page_addr));
+
+ /* Fill the page with its own addresses */
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
+ }
+ spi_ctrl_stop_user(test_data);
+
+ /* Check the page is correctly written */
+ read_page(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
+ }
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, ERASE_SECTOR);
+ flash_writel(test_data, 0, make_be32(some_page_addr));
+ spi_ctrl_stop_user(test_data);
+
+ /* Check the page is erased */
+ read_page(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ flash_reset(test_data);
+}
+
+void aspeed_smc_test_erase_all(const void *data)
+{
+ const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
+ uint32_t some_page_addr = test_data->page_addr;
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ int i;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ /*
+ * Previous page should be full of 0xffs after backend is
+ * initialized
+ */
+ read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(some_page_addr));
+
+ /* Fill the page with its own addresses */
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
+ }
+ spi_ctrl_stop_user(test_data);
+
+ /* Check the page is correctly written */
+ read_page(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
+ }
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, BULK_ERASE);
+ spi_ctrl_stop_user(test_data);
+
+ /* Check the page is erased */
+ read_page(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ flash_reset(test_data);
+}
+
+void aspeed_smc_test_write_page(const void *data)
+{
+ const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
+ uint32_t my_page_addr = test_data->page_addr;
+ uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ int i;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(my_page_addr));
+
+ /* Fill the page with its own addresses */
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
+ }
+ spi_ctrl_stop_user(test_data);
+
+ /* Check what was written */
+ read_page(test_data, my_page_addr, page);
+ for (i = 0; i < FLASH_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(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ flash_reset(test_data);
+}
+
+void aspeed_smc_test_read_page_mem(const void *data)
+{
+ const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
+ uint32_t my_page_addr = test_data->page_addr;
+ uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ int i;
+
+ /*
+ * Enable 4BYTE mode for controller.
+ */
+ spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
+
+ /* Enable 4BYTE mode for flash. */
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(my_page_addr));
+
+ /* Fill the page with its own addresses */
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
+ }
+ spi_ctrl_stop_user(test_data);
+ spi_conf_remove(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ /* Check what was written */
+ read_page_mem(test_data, my_page_addr, page);
+ for (i = 0; i < FLASH_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(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ flash_reset(test_data);
+}
+
+void aspeed_smc_test_write_page_mem(const void *data)
+{
+ const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
+ uint32_t my_page_addr = test_data->page_addr;
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ int i;
+
+ /*
+ * Enable 4BYTE mode for controller.
+ */
+ spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
+
+ /* Enable 4BYTE mode for flash. */
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ spi_ctrl_stop_user(test_data);
+
+ /* move out USER mode to use direct writes to the AHB bus */
+ spi_ctrl_setmode(test_data, CTRL_WRITEMODE, PP);
+
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(test_data, my_page_addr + i * 4,
+ make_be32(my_page_addr + i * 4));
+ }
+
+ /* Check what was written */
+ read_page_mem(test_data, my_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
+ }
+
+ flash_reset(test_data);
+}
+
+void aspeed_smc_test_read_status_reg(const void *data)
+{
+ const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
+ uint8_t r;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+
+ g_assert_cmphex(r & SR_WEL, ==, 0);
+ g_assert(!qtest_qom_get_bool
+ (test_data->s, test_data->node, "write-enable"));
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+
+ g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
+ g_assert(qtest_qom_get_bool
+ (test_data->s, test_data->node, "write-enable"));
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WRDI);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+
+ g_assert_cmphex(r & SR_WEL, ==, 0);
+ g_assert(!qtest_qom_get_bool
+ (test_data->s, test_data->node, "write-enable"));
+
+ flash_reset(test_data);
+}
+
+void aspeed_smc_test_status_reg_write_protection(const void *data)
+{
+ const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
+ uint8_t r;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ /* default case: WP# is high and SRWD is low -> status register writable */
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ /* test ability to write SRWD */
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, SRWD);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+ g_assert_cmphex(r & SRWD, ==, SRWD);
+
+ /* WP# high and SRWD high -> status register writable */
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ /* test ability to write SRWD */
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, 0);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+ g_assert_cmphex(r & SRWD, ==, 0);
+
+ /* WP# low and SRWD low -> status register writable */
+ qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 0);
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ /* test ability to write SRWD */
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, SRWD);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+ g_assert_cmphex(r & SRWD, ==, SRWD);
+
+ /* WP# low and SRWD high -> status register NOT writable */
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0 , WREN);
+ /* test ability to write SRWD */
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, 0);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+ /* write is not successful */
+ g_assert_cmphex(r & SRWD, ==, SRWD);
+
+ qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 1);
+ flash_reset(test_data);
+}
+
+void aspeed_smc_test_write_block_protect(const void *data)
+{
+ const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
+ uint32_t sector_size = 65536;
+ uint32_t n_sectors = 512;
+
+ spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ uint32_t bp_bits = 0b0;
+
+ for (int i = 0; i < 16; i++) {
+ bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2);
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, BULK_ERASE);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, bp_bits);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ spi_ctrl_stop_user(test_data);
+
+ uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
+ uint32_t protection_start = n_sectors - num_protected_sectors;
+ uint32_t protection_end = n_sectors;
+
+ for (int sector = 0; sector < n_sectors; sector++) {
+ uint32_t addr = sector * sector_size;
+
+ assert_page_mem(test_data, addr, 0xffffffff);
+ write_page_mem(test_data, addr, make_be32(0xabcdef12));
+
+ uint32_t expected_value = protection_start <= sector
+ && sector < protection_end
+ ? 0xffffffff : 0xabcdef12;
+
+ assert_page_mem(test_data, addr, expected_value);
+ }
+ }
+
+ flash_reset(test_data);
+}
+
+void aspeed_smc_test_write_block_protect_bottom_bit(const void *data)
+{
+ const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
+ uint32_t sector_size = 65536;
+ uint32_t n_sectors = 512;
+
+ spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ /* top bottom bit is enabled */
+ uint32_t bp_bits = 0b00100 << 3;
+
+ for (int i = 0; i < 16; i++) {
+ bp_bits = (((i & 0b1000) | 0b0100) << 3) | ((i & 0b0111) << 2);
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, BULK_ERASE);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, bp_bits);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ spi_ctrl_stop_user(test_data);
+
+ uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
+ uint32_t protection_start = 0;
+ uint32_t protection_end = num_protected_sectors;
+
+ for (int sector = 0; sector < n_sectors; sector++) {
+ uint32_t addr = sector * sector_size;
+
+ assert_page_mem(test_data, addr, 0xffffffff);
+ write_page_mem(test_data, addr, make_be32(0xabcdef12));
+
+ uint32_t expected_value = protection_start <= sector
+ && sector < protection_end
+ ? 0xffffffff : 0xabcdef12;
+
+ assert_page_mem(test_data, addr, expected_value);
+ }
+ }
+
+ flash_reset(test_data);
+}
+
+void aspeed_smc_test_write_page_qpi(const void *data)
+{
+ const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
+ uint32_t my_page_addr = test_data->page_addr;
+ uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ uint32_t page_pattern[] = {
+ 0xebd8c134, 0x5da196bc, 0xae15e729, 0x5085ccdf
+ };
+ int i;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(my_page_addr));
+
+ /* Set QPI mode */
+ spi_ctrl_set_io_mode(test_data, CTRL_IO_QUAD_IO);
+
+ /* Fill the page pattern */
+ for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
+ flash_writel(test_data, 0, make_be32(page_pattern[i]));
+ }
+
+ /* Fill the page with its own addresses */
+ for (; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
+ }
+
+ /* Restore io mode */
+ spi_ctrl_set_io_mode(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+
+ /* Check what was written */
+ read_page(test_data, my_page_addr, page);
+ for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
+ g_assert_cmphex(page[i], ==, page_pattern[i]);
+ }
+ for (; i < FLASH_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(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ flash_reset(test_data);
+}
+
diff --git a/tests/qtest/aspeed-smc-utils.h b/tests/qtest/aspeed-smc-utils.h
new file mode 100644
index 0000000..b07870f
--- /dev/null
+++ b/tests/qtest/aspeed-smc-utils.h
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#ifndef TESTS_ASPEED_SMC_UTILS_H
+#define TESTS_ASPEED_SMC_UTILS_H
+
+#include "qemu/osdep.h"
+#include "qemu/bswap.h"
+#include "libqtest-single.h"
+#include "qemu/bitops.h"
+
+/*
+ * ASPEED SPI Controller registers
+ */
+#define R_CONF 0x00
+#define CONF_ENABLE_W0 16
+#define R_CE_CTRL 0x04
+#define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */
+#define R_CTRL0 0x10
+#define CTRL_IO_QUAD_IO BIT(31)
+#define CTRL_CE_STOP_ACTIVE BIT(2)
+#define CTRL_READMODE 0x0
+#define CTRL_FREADMODE 0x1
+#define CTRL_WRITEMODE 0x2
+#define CTRL_USERMODE 0x3
+#define SR_WEL BIT(1)
+
+/*
+ * Flash commands
+ */
+enum {
+ JEDEC_READ = 0x9f,
+ RDSR = 0x5,
+ WRDI = 0x4,
+ BULK_ERASE = 0xc7,
+ READ = 0x03,
+ PP = 0x02,
+ WRSR = 0x1,
+ WREN = 0x6,
+ SRWD = 0x80,
+ RESET_ENABLE = 0x66,
+ RESET_MEMORY = 0x99,
+ EN_4BYTE_ADDR = 0xB7,
+ ERASE_SECTOR = 0xd8,
+};
+
+#define CTRL_IO_MODE_MASK (BIT(31) | BIT(30) | BIT(29) | BIT(28))
+#define FLASH_PAGE_SIZE 256
+
+typedef struct AspeedSMCTestData {
+ QTestState *s;
+ uint64_t spi_base;
+ uint64_t flash_base;
+ uint32_t jedec_id;
+ char *tmp_path;
+ uint8_t cs;
+ const char *node;
+ uint32_t page_addr;
+} AspeedSMCTestData;
+
+void aspeed_smc_test_read_jedec(const void *data);
+void aspeed_smc_test_erase_sector(const void *data);
+void aspeed_smc_test_erase_all(const void *data);
+void aspeed_smc_test_write_page(const void *data);
+void aspeed_smc_test_read_page_mem(const void *data);
+void aspeed_smc_test_write_page_mem(const void *data);
+void aspeed_smc_test_read_status_reg(const void *data);
+void aspeed_smc_test_status_reg_write_protection(const void *data);
+void aspeed_smc_test_write_block_protect(const void *data);
+void aspeed_smc_test_write_block_protect_bottom_bit(const void *data);
+void aspeed_smc_test_write_page_qpi(const void *data);
+
+#endif /* TESTS_ASPEED_SMC_UTILS_H */
diff --git a/tests/qtest/aspeed_gpio-test.c b/tests/qtest/aspeed_gpio-test.c
index d38f51d..12675d4 100644
--- a/tests/qtest/aspeed_gpio-test.c
+++ b/tests/qtest/aspeed_gpio-test.c
@@ -25,7 +25,7 @@
#include "qemu/osdep.h"
#include "qemu/bitops.h"
#include "qemu/timer.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "libqtest-single.h"
#define AST2600_GPIO_BASE 0x1E780000
diff --git a/tests/qtest/aspeed_hace-test.c b/tests/qtest/aspeed_hace-test.c
index ce86a44..3877702 100644
--- a/tests/qtest/aspeed_hace-test.c
+++ b/tests/qtest/aspeed_hace-test.c
@@ -6,599 +6,222 @@
*/
#include "qemu/osdep.h"
-
#include "libqtest.h"
#include "qemu/bitops.h"
+#include "aspeed-hace-utils.h"
-#define HACE_CMD 0x10
-#define HACE_SHA_BE_EN BIT(3)
-#define HACE_MD5_LE_EN BIT(2)
-#define HACE_ALGO_MD5 0
-#define HACE_ALGO_SHA1 BIT(5)
-#define HACE_ALGO_SHA224 BIT(6)
-#define HACE_ALGO_SHA256 (BIT(4) | BIT(6))
-#define HACE_ALGO_SHA512 (BIT(5) | BIT(6))
-#define HACE_ALGO_SHA384 (BIT(5) | BIT(6) | BIT(10))
-#define HACE_SG_EN BIT(18)
-#define HACE_ACCUM_EN BIT(8)
-
-#define HACE_STS 0x1c
-#define HACE_RSA_ISR BIT(13)
-#define HACE_CRYPTO_ISR BIT(12)
-#define HACE_HASH_ISR BIT(9)
-#define HACE_RSA_BUSY BIT(2)
-#define HACE_CRYPTO_BUSY BIT(1)
-#define HACE_HASH_BUSY BIT(0)
-#define HACE_HASH_SRC 0x20
-#define HACE_HASH_DIGEST 0x24
-#define HACE_HASH_KEY_BUFF 0x28
-#define HACE_HASH_DATA_LEN 0x2c
-#define HACE_HASH_CMD 0x30
-/* Scatter-Gather Hash */
-#define SG_LIST_LEN_LAST BIT(31)
-struct AspeedSgList {
- uint32_t len;
- uint32_t addr;
-} __attribute__ ((__packed__));
-
-/*
- * Test vector is the ascii "abc"
- *
- * Expected results were generated using command line utitiles:
- *
- * echo -n -e 'abc' | dd of=/tmp/test
- * for hash in sha512sum sha256sum md5sum; do $hash /tmp/test; done
- *
- */
-static const uint8_t test_vector[] = {0x61, 0x62, 0x63};
-
-static const uint8_t test_result_sha512[] = {
- 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49,
- 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
- 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a,
- 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
- 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f,
- 0xa5, 0x4c, 0xa4, 0x9f};
+static const struct AspeedMasks ast1030_masks = {
+ .src = 0x7fffffff,
+ .dest = 0x7ffffff8,
+ .key = 0x7ffffff8,
+ .len = 0x0fffffff,
+};
-static const uint8_t test_result_sha256[] = {
- 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
- 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
- 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad};
+static const struct AspeedMasks ast2600_masks = {
+ .src = 0x7fffffff,
+ .dest = 0x7ffffff8,
+ .key = 0x7ffffff8,
+ .len = 0x0fffffff,
+};
-static const uint8_t test_result_md5[] = {
- 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d,
- 0x28, 0xe1, 0x7f, 0x72};
+static const struct AspeedMasks ast2500_masks = {
+ .src = 0x3fffffff,
+ .dest = 0x3ffffff8,
+ .key = 0x3fffffc0,
+ .len = 0x0fffffff,
+};
-/*
- * The Scatter-Gather Test vector is the ascii "abc" "def" "ghi", broken
- * into blocks of 3 characters as shown
- *
- * Expected results were generated using command line utitiles:
- *
- * echo -n -e 'abcdefghijkl' | dd of=/tmp/test
- * for hash in sha512sum sha256sum; do $hash /tmp/test; done
- *
- */
-static const uint8_t test_vector_sg1[] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
-static const uint8_t test_vector_sg2[] = {0x67, 0x68, 0x69};
-static const uint8_t test_vector_sg3[] = {0x6a, 0x6b, 0x6c};
-
-static const uint8_t test_result_sg_sha512[] = {
- 0x17, 0x80, 0x7c, 0x72, 0x8e, 0xe3, 0xba, 0x35, 0xe7, 0xcf, 0x7a, 0xf8,
- 0x23, 0x11, 0x6d, 0x26, 0xe4, 0x1e, 0x5d, 0x4d, 0x6c, 0x2f, 0xf1, 0xf3,
- 0x72, 0x0d, 0x3d, 0x96, 0xaa, 0xcb, 0x6f, 0x69, 0xde, 0x64, 0x2e, 0x63,
- 0xd5, 0xb7, 0x3f, 0xc3, 0x96, 0xc1, 0x2b, 0xe3, 0x8b, 0x2b, 0xd5, 0xd8,
- 0x84, 0x25, 0x7c, 0x32, 0xc8, 0xf6, 0xd0, 0x85, 0x4a, 0xe6, 0xb5, 0x40,
- 0xf8, 0x6d, 0xda, 0x2e};
-
-static const uint8_t test_result_sg_sha256[] = {
- 0xd6, 0x82, 0xed, 0x4c, 0xa4, 0xd9, 0x89, 0xc1, 0x34, 0xec, 0x94, 0xf1,
- 0x55, 0x1e, 0x1e, 0xc5, 0x80, 0xdd, 0x6d, 0x5a, 0x6e, 0xcd, 0xe9, 0xf3,
- 0xd3, 0x5e, 0x6e, 0x4a, 0x71, 0x7f, 0xbd, 0xe4};
+static const struct AspeedMasks ast2400_masks = {
+ .src = 0x0fffffff,
+ .dest = 0x0ffffff8,
+ .key = 0x0fffffc0,
+ .len = 0x0fffffff,
+};
-/*
- * The accumulative mode requires firmware to provide internal initial state
- * and message padding (including length L at the end of padding).
- *
- * This test vector is a ascii text "abc" with padding message.
- *
- * Expected results were generated using command line utitiles:
- *
- * echo -n -e 'abc' | dd of=/tmp/test
- * for hash in sha512sum sha256sum; do $hash /tmp/test; done
- */
-static const uint8_t test_vector_accum_512[] = {
- 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18};
-
-static const uint8_t test_vector_accum_256[] = {
- 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18};
-
-static const uint8_t test_result_accum_sha512[] = {
- 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49,
- 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
- 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a,
- 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
- 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f,
- 0xa5, 0x4c, 0xa4, 0x9f};
-
-static const uint8_t test_result_accum_sha256[] = {
- 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
- 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
- 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad};
-
-static void write_regs(QTestState *s, uint32_t base, uint32_t src,
- uint32_t length, uint32_t out, uint32_t method)
+/* ast1030 */
+static void test_md5_ast1030(void)
{
- qtest_writel(s, base + HACE_HASH_SRC, src);
- qtest_writel(s, base + HACE_HASH_DIGEST, out);
- qtest_writel(s, base + HACE_HASH_DATA_LEN, length);
- qtest_writel(s, base + HACE_HASH_CMD, HACE_SHA_BE_EN | method);
+ aspeed_test_md5("-machine ast1030-evb", 0x7e6d0000, 0x00000000);
}
-static void test_md5(const char *machine, const uint32_t base,
- const uint32_t src_addr)
-
+static void test_sha256_ast1030(void)
{
- QTestState *s = qtest_init(machine);
-
- uint32_t digest_addr = src_addr + 0x01000000;
- uint8_t digest[16] = {0};
-
- /* Check engine is idle, no busy or irq bits set */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Write test vector into memory */
- qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector));
-
- write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, HACE_ALGO_MD5);
-
- /* Check hash IRQ status is asserted */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
-
- /* Clear IRQ status and check status is deasserted */
- qtest_writel(s, base + HACE_STS, 0x00000200);
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Read computed digest from memory */
- qtest_memread(s, digest_addr, digest, sizeof(digest));
-
- /* Check result of computation */
- g_assert_cmpmem(digest, sizeof(digest),
- test_result_md5, sizeof(digest));
-
- qtest_quit(s);
+ aspeed_test_sha256("-machine ast1030-evb", 0x7e6d0000, 0x00000000);
}
-static void test_sha256(const char *machine, const uint32_t base,
- const uint32_t src_addr)
+static void test_sha256_sg_ast1030(void)
{
- QTestState *s = qtest_init(machine);
-
- const uint32_t digest_addr = src_addr + 0x1000000;
- uint8_t digest[32] = {0};
-
- /* Check engine is idle, no busy or irq bits set */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Write test vector into memory */
- qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector));
-
- write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, HACE_ALGO_SHA256);
-
- /* Check hash IRQ status is asserted */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
-
- /* Clear IRQ status and check status is deasserted */
- qtest_writel(s, base + HACE_STS, 0x00000200);
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Read computed digest from memory */
- qtest_memread(s, digest_addr, digest, sizeof(digest));
-
- /* Check result of computation */
- g_assert_cmpmem(digest, sizeof(digest),
- test_result_sha256, sizeof(digest));
-
- qtest_quit(s);
+ aspeed_test_sha256_sg("-machine ast1030-evb", 0x7e6d0000, 0x00000000);
}
-static void test_sha512(const char *machine, const uint32_t base,
- const uint32_t src_addr)
+static void test_sha384_ast1030(void)
{
- QTestState *s = qtest_init(machine);
-
- const uint32_t digest_addr = src_addr + 0x1000000;
- uint8_t digest[64] = {0};
-
- /* Check engine is idle, no busy or irq bits set */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Write test vector into memory */
- qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector));
-
- write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, HACE_ALGO_SHA512);
-
- /* Check hash IRQ status is asserted */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
-
- /* Clear IRQ status and check status is deasserted */
- qtest_writel(s, base + HACE_STS, 0x00000200);
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Read computed digest from memory */
- qtest_memread(s, digest_addr, digest, sizeof(digest));
-
- /* Check result of computation */
- g_assert_cmpmem(digest, sizeof(digest),
- test_result_sha512, sizeof(digest));
-
- qtest_quit(s);
+ aspeed_test_sha384("-machine ast1030-evb", 0x7e6d0000, 0x00000000);
}
-static void test_sha256_sg(const char *machine, const uint32_t base,
- const uint32_t src_addr)
+static void test_sha384_sg_ast1030(void)
{
- QTestState *s = qtest_init(machine);
-
- const uint32_t src_addr_1 = src_addr + 0x1000000;
- const uint32_t src_addr_2 = src_addr + 0x2000000;
- const uint32_t src_addr_3 = src_addr + 0x3000000;
- const uint32_t digest_addr = src_addr + 0x4000000;
- uint8_t digest[32] = {0};
- struct AspeedSgList array[] = {
- { cpu_to_le32(sizeof(test_vector_sg1)),
- cpu_to_le32(src_addr_1) },
- { cpu_to_le32(sizeof(test_vector_sg2)),
- cpu_to_le32(src_addr_2) },
- { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST),
- cpu_to_le32(src_addr_3) },
- };
-
- /* Check engine is idle, no busy or irq bits set */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Write test vector into memory */
- qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1));
- qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2));
- qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3));
- qtest_memwrite(s, src_addr, array, sizeof(array));
-
- write_regs(s, base, src_addr,
- (sizeof(test_vector_sg1)
- + sizeof(test_vector_sg2)
- + sizeof(test_vector_sg3)),
- digest_addr, HACE_ALGO_SHA256 | HACE_SG_EN);
-
- /* Check hash IRQ status is asserted */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
-
- /* Clear IRQ status and check status is deasserted */
- qtest_writel(s, base + HACE_STS, 0x00000200);
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Read computed digest from memory */
- qtest_memread(s, digest_addr, digest, sizeof(digest));
-
- /* Check result of computation */
- g_assert_cmpmem(digest, sizeof(digest),
- test_result_sg_sha256, sizeof(digest));
-
- qtest_quit(s);
+ aspeed_test_sha384_sg("-machine ast1030-evb", 0x7e6d0000, 0x00000000);
}
-static void test_sha512_sg(const char *machine, const uint32_t base,
- const uint32_t src_addr)
+static void test_sha512_ast1030(void)
{
- QTestState *s = qtest_init(machine);
-
- const uint32_t src_addr_1 = src_addr + 0x1000000;
- const uint32_t src_addr_2 = src_addr + 0x2000000;
- const uint32_t src_addr_3 = src_addr + 0x3000000;
- const uint32_t digest_addr = src_addr + 0x4000000;
- uint8_t digest[64] = {0};
- struct AspeedSgList array[] = {
- { cpu_to_le32(sizeof(test_vector_sg1)),
- cpu_to_le32(src_addr_1) },
- { cpu_to_le32(sizeof(test_vector_sg2)),
- cpu_to_le32(src_addr_2) },
- { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST),
- cpu_to_le32(src_addr_3) },
- };
-
- /* Check engine is idle, no busy or irq bits set */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Write test vector into memory */
- qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1));
- qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2));
- qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3));
- qtest_memwrite(s, src_addr, array, sizeof(array));
-
- write_regs(s, base, src_addr,
- (sizeof(test_vector_sg1)
- + sizeof(test_vector_sg2)
- + sizeof(test_vector_sg3)),
- digest_addr, HACE_ALGO_SHA512 | HACE_SG_EN);
-
- /* Check hash IRQ status is asserted */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
-
- /* Clear IRQ status and check status is deasserted */
- qtest_writel(s, base + HACE_STS, 0x00000200);
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Read computed digest from memory */
- qtest_memread(s, digest_addr, digest, sizeof(digest));
-
- /* Check result of computation */
- g_assert_cmpmem(digest, sizeof(digest),
- test_result_sg_sha512, sizeof(digest));
-
- qtest_quit(s);
+ aspeed_test_sha512("-machine ast1030-evb", 0x7e6d0000, 0x00000000);
}
-static void test_sha256_accum(const char *machine, const uint32_t base,
- const uint32_t src_addr)
+static void test_sha512_sg_ast1030(void)
{
- QTestState *s = qtest_init(machine);
-
- const uint32_t buffer_addr = src_addr + 0x1000000;
- const uint32_t digest_addr = src_addr + 0x4000000;
- uint8_t digest[32] = {0};
- struct AspeedSgList array[] = {
- { cpu_to_le32(sizeof(test_vector_accum_256) | SG_LIST_LEN_LAST),
- cpu_to_le32(buffer_addr) },
- };
-
- /* Check engine is idle, no busy or irq bits set */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Write test vector into memory */
- qtest_memwrite(s, buffer_addr, test_vector_accum_256,
- sizeof(test_vector_accum_256));
- qtest_memwrite(s, src_addr, array, sizeof(array));
-
- write_regs(s, base, src_addr, sizeof(test_vector_accum_256),
- digest_addr, HACE_ALGO_SHA256 | HACE_SG_EN | HACE_ACCUM_EN);
-
- /* Check hash IRQ status is asserted */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
-
- /* Clear IRQ status and check status is deasserted */
- qtest_writel(s, base + HACE_STS, 0x00000200);
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Read computed digest from memory */
- qtest_memread(s, digest_addr, digest, sizeof(digest));
-
- /* Check result of computation */
- g_assert_cmpmem(digest, sizeof(digest),
- test_result_accum_sha256, sizeof(digest));
-
- qtest_quit(s);
+ aspeed_test_sha512_sg("-machine ast1030-evb", 0x7e6d0000, 0x00000000);
}
-static void test_sha512_accum(const char *machine, const uint32_t base,
- const uint32_t src_addr)
+static void test_sha256_accum_ast1030(void)
{
- QTestState *s = qtest_init(machine);
-
- const uint32_t buffer_addr = src_addr + 0x1000000;
- const uint32_t digest_addr = src_addr + 0x4000000;
- uint8_t digest[64] = {0};
- struct AspeedSgList array[] = {
- { cpu_to_le32(sizeof(test_vector_accum_512) | SG_LIST_LEN_LAST),
- cpu_to_le32(buffer_addr) },
- };
-
- /* Check engine is idle, no busy or irq bits set */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Write test vector into memory */
- qtest_memwrite(s, buffer_addr, test_vector_accum_512,
- sizeof(test_vector_accum_512));
- qtest_memwrite(s, src_addr, array, sizeof(array));
-
- write_regs(s, base, src_addr, sizeof(test_vector_accum_512),
- digest_addr, HACE_ALGO_SHA512 | HACE_SG_EN | HACE_ACCUM_EN);
-
- /* Check hash IRQ status is asserted */
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
-
- /* Clear IRQ status and check status is deasserted */
- qtest_writel(s, base + HACE_STS, 0x00000200);
- g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
-
- /* Read computed digest from memory */
- qtest_memread(s, digest_addr, digest, sizeof(digest));
-
- /* Check result of computation */
- g_assert_cmpmem(digest, sizeof(digest),
- test_result_accum_sha512, sizeof(digest));
-
- qtest_quit(s);
+ aspeed_test_sha256_accum("-machine ast1030-evb", 0x7e6d0000, 0x00000000);
}
-struct masks {
- uint32_t src;
- uint32_t dest;
- uint32_t len;
-};
-
-static const struct masks ast2600_masks = {
- .src = 0x7fffffff,
- .dest = 0x7ffffff8,
- .len = 0x0fffffff,
-};
-
-static const struct masks ast2500_masks = {
- .src = 0x3fffffff,
- .dest = 0x3ffffff8,
- .len = 0x0fffffff,
-};
-
-static const struct masks ast2400_masks = {
- .src = 0x0fffffff,
- .dest = 0x0ffffff8,
- .len = 0x0fffffff,
-};
-
-static void test_addresses(const char *machine, const uint32_t base,
- const struct masks *expected)
+static void test_sha384_accum_ast1030(void)
{
- QTestState *s = qtest_init(machine);
-
- /*
- * Check command mode is zero, meaning engine is in direct access mode,
- * as this affects the masking behavior of the HASH_SRC register.
- */
- g_assert_cmphex(qtest_readl(s, base + HACE_CMD), ==, 0);
- g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0);
- g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0);
- g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0);
-
-
- /* Check that the address masking is correct */
- qtest_writel(s, base + HACE_HASH_SRC, 0xffffffff);
- g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, expected->src);
-
- qtest_writel(s, base + HACE_HASH_DIGEST, 0xffffffff);
- g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, expected->dest);
-
- qtest_writel(s, base + HACE_HASH_DATA_LEN, 0xffffffff);
- g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, expected->len);
-
- /* Reset to zero */
- qtest_writel(s, base + HACE_HASH_SRC, 0);
- qtest_writel(s, base + HACE_HASH_DIGEST, 0);
- qtest_writel(s, base + HACE_HASH_DATA_LEN, 0);
+ aspeed_test_sha384_accum("-machine ast1030-evb", 0x7e6d0000, 0x00000000);
+}
- /* Check that all bits are now zero */
- g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0);
- g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0);
- g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0);
+static void test_sha512_accum_ast1030(void)
+{
+ aspeed_test_sha512_accum("-machine ast1030-evb", 0x7e6d0000, 0x00000000);
+}
- qtest_quit(s);
+static void test_addresses_ast1030(void)
+{
+ aspeed_test_addresses("-machine ast1030-evb", 0x7e6d0000, &ast1030_masks);
}
/* ast2600 */
static void test_md5_ast2600(void)
{
- test_md5("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+ aspeed_test_md5("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
}
static void test_sha256_ast2600(void)
{
- test_sha256("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+ aspeed_test_sha256("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
}
static void test_sha256_sg_ast2600(void)
{
- test_sha256_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+ aspeed_test_sha256_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+}
+
+static void test_sha384_ast2600(void)
+{
+ aspeed_test_sha384("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+}
+
+static void test_sha384_sg_ast2600(void)
+{
+ aspeed_test_sha384_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
}
static void test_sha512_ast2600(void)
{
- test_sha512("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+ aspeed_test_sha512("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
}
static void test_sha512_sg_ast2600(void)
{
- test_sha512_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+ aspeed_test_sha512_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
}
static void test_sha256_accum_ast2600(void)
{
- test_sha256_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+ aspeed_test_sha256_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+}
+
+static void test_sha384_accum_ast2600(void)
+{
+ aspeed_test_sha384_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
}
static void test_sha512_accum_ast2600(void)
{
- test_sha512_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+ aspeed_test_sha512_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
}
static void test_addresses_ast2600(void)
{
- test_addresses("-machine ast2600-evb", 0x1e6d0000, &ast2600_masks);
+ aspeed_test_addresses("-machine ast2600-evb", 0x1e6d0000, &ast2600_masks);
}
/* ast2500 */
static void test_md5_ast2500(void)
{
- test_md5("-machine ast2500-evb", 0x1e6e3000, 0x80000000);
+ aspeed_test_md5("-machine ast2500-evb", 0x1e6e3000, 0x80000000);
}
static void test_sha256_ast2500(void)
{
- test_sha256("-machine ast2500-evb", 0x1e6e3000, 0x80000000);
+ aspeed_test_sha256("-machine ast2500-evb", 0x1e6e3000, 0x80000000);
}
static void test_sha512_ast2500(void)
{
- test_sha512("-machine ast2500-evb", 0x1e6e3000, 0x80000000);
+ aspeed_test_sha512("-machine ast2500-evb", 0x1e6e3000, 0x80000000);
}
static void test_addresses_ast2500(void)
{
- test_addresses("-machine ast2500-evb", 0x1e6e3000, &ast2500_masks);
+ aspeed_test_addresses("-machine ast2500-evb", 0x1e6e3000, &ast2500_masks);
}
/* ast2400 */
static void test_md5_ast2400(void)
{
- test_md5("-machine palmetto-bmc", 0x1e6e3000, 0x40000000);
+ aspeed_test_md5("-machine palmetto-bmc", 0x1e6e3000, 0x40000000);
}
static void test_sha256_ast2400(void)
{
- test_sha256("-machine palmetto-bmc", 0x1e6e3000, 0x40000000);
+ aspeed_test_sha256("-machine palmetto-bmc", 0x1e6e3000, 0x40000000);
}
static void test_sha512_ast2400(void)
{
- test_sha512("-machine palmetto-bmc", 0x1e6e3000, 0x40000000);
+ aspeed_test_sha512("-machine palmetto-bmc", 0x1e6e3000, 0x40000000);
}
static void test_addresses_ast2400(void)
{
- test_addresses("-machine palmetto-bmc", 0x1e6e3000, &ast2400_masks);
+ aspeed_test_addresses("-machine palmetto-bmc", 0x1e6e3000, &ast2400_masks);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
+ qtest_add_func("ast1030/hace/addresses", test_addresses_ast1030);
+ qtest_add_func("ast1030/hace/sha512", test_sha512_ast1030);
+ qtest_add_func("ast1030/hace/sha384", test_sha384_ast1030);
+ qtest_add_func("ast1030/hace/sha256", test_sha256_ast1030);
+ qtest_add_func("ast1030/hace/md5", test_md5_ast1030);
+
+ qtest_add_func("ast1030/hace/sha512_sg", test_sha512_sg_ast1030);
+ qtest_add_func("ast1030/hace/sha384_sg", test_sha384_sg_ast1030);
+ qtest_add_func("ast1030/hace/sha256_sg", test_sha256_sg_ast1030);
+
+ qtest_add_func("ast1030/hace/sha512_accum", test_sha512_accum_ast1030);
+ qtest_add_func("ast1030/hace/sha384_accum", test_sha384_accum_ast1030);
+ qtest_add_func("ast1030/hace/sha256_accum", test_sha256_accum_ast1030);
+
qtest_add_func("ast2600/hace/addresses", test_addresses_ast2600);
qtest_add_func("ast2600/hace/sha512", test_sha512_ast2600);
+ qtest_add_func("ast2600/hace/sha384", test_sha384_ast2600);
qtest_add_func("ast2600/hace/sha256", test_sha256_ast2600);
qtest_add_func("ast2600/hace/md5", test_md5_ast2600);
qtest_add_func("ast2600/hace/sha512_sg", test_sha512_sg_ast2600);
+ qtest_add_func("ast2600/hace/sha384_sg", test_sha384_sg_ast2600);
qtest_add_func("ast2600/hace/sha256_sg", test_sha256_sg_ast2600);
qtest_add_func("ast2600/hace/sha512_accum", test_sha512_accum_ast2600);
+ qtest_add_func("ast2600/hace/sha384_accum", test_sha384_accum_ast2600);
qtest_add_func("ast2600/hace/sha256_accum", test_sha256_accum_ast2600);
qtest_add_func("ast2500/hace/addresses", test_addresses_ast2500);
diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
index c713a37..52a00e6 100644
--- a/tests/qtest/aspeed_smc-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -27,623 +27,211 @@
#include "qemu/bswap.h"
#include "libqtest-single.h"
#include "qemu/bitops.h"
+#include "aspeed-smc-utils.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 SR_WEL BIT(1)
-
-#define ASPEED_FMC_BASE 0x1E620000
-#define ASPEED_FLASH_BASE 0x20000000
-
-/*
- * Flash commands
- */
-enum {
- JEDEC_READ = 0x9f,
- RDSR = 0x5,
- WRDI = 0x4,
- BULK_ERASE = 0xc7,
- READ = 0x03,
- PP = 0x02,
- WRSR = 0x1,
- WREN = 0x6,
- SRWD = 0x80,
- 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 FLASH_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)
+static void test_palmetto_bmc(AspeedSMCTestData *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);
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, BULK_ERASE);
- writeb(ASPEED_FLASH_BASE, WRDI);
- 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 < FLASH_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 < FLASH_PAGE_SIZE / 4; i++) {
- page[i] = make_be32(readl(ASPEED_FLASH_BASE + addr + i * 4));
- }
-}
-
-static void write_page_mem(uint32_t addr, uint32_t write_value)
-{
- spi_ctrl_setmode(CTRL_WRITEMODE, PP);
-
- for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- writel(ASPEED_FLASH_BASE + addr + i * 4, write_value);
- }
-}
-
-static void assert_page_mem(uint32_t addr, uint32_t expected_value)
-{
- uint32_t page[FLASH_PAGE_SIZE / 4];
- read_page_mem(addr, page);
- for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, expected_value);
- }
-}
-
-static void test_erase_sector(void)
-{
- uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE;
- uint32_t page[FLASH_PAGE_SIZE / 4];
- int i;
-
- spi_conf(CONF_ENABLE_W0);
-
- /*
- * Previous page should be full of 0xffs after backend is
- * initialized
- */
- read_page(some_page_addr - FLASH_PAGE_SIZE, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, 0xffffffff);
- }
-
- 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(some_page_addr));
-
- /* Fill the page with its own addresses */
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
- }
- spi_ctrl_stop_user();
-
- /* Check the page is correctly written */
- read_page(some_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
- }
-
- 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();
-
- /* Check the page is erased */
- read_page(some_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, 0xffffffff);
- }
-
- flash_reset();
-}
-
-static void test_erase_all(void)
-{
- uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
- uint32_t page[FLASH_PAGE_SIZE / 4];
- int i;
-
- spi_conf(CONF_ENABLE_W0);
-
- /*
- * Previous page should be full of 0xffs after backend is
- * initialized
- */
- read_page(some_page_addr - FLASH_PAGE_SIZE, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, 0xffffffff);
- }
-
- 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(some_page_addr));
-
- /* Fill the page with its own addresses */
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
- }
- spi_ctrl_stop_user();
-
- /* Check the page is correctly written */
- read_page(some_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
- }
-
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, BULK_ERASE);
- spi_ctrl_stop_user();
-
- /* Check the page is erased */
- read_page(some_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, 0xffffffff);
- }
-
- flash_reset();
-}
-
-static void test_write_page(void)
-{
- uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
- uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
- uint32_t page[FLASH_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 < FLASH_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 < FLASH_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 < FLASH_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 * FLASH_PAGE_SIZE; /* beyond 16MB */
- uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
- uint32_t page[FLASH_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);
- 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 < FLASH_PAGE_SIZE / 4; i++) {
- writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
- }
- 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 < FLASH_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 < FLASH_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 * FLASH_PAGE_SIZE;
- uint32_t page[FLASH_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 < FLASH_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 < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
- }
-
- flash_reset();
-}
-
-static void test_read_status_reg(void)
-{
- uint8_t r;
-
- spi_conf(CONF_ENABLE_W0);
-
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
-
- g_assert_cmphex(r & SR_WEL, ==, 0);
- g_assert(!qtest_qom_get_bool
- (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
-
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
-
- g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
- g_assert(qtest_qom_get_bool
- (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
-
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WRDI);
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
-
- g_assert_cmphex(r & SR_WEL, ==, 0);
- g_assert(!qtest_qom_get_bool
- (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
+ int ret;
+ int fd;
- flash_reset();
-}
+ fd = g_file_open_tmp("qtest.m25p80.n25q256a.XXXXXX", &data->tmp_path, NULL);
+ g_assert(fd >= 0);
+ ret = ftruncate(fd, 32 * 1024 * 1024);
+ g_assert(ret == 0);
+ close(fd);
-static void test_status_reg_write_protection(void)
+ data->s = qtest_initf("-m 256 -machine palmetto-bmc "
+ "-drive file=%s,format=raw,if=mtd",
+ data->tmp_path);
+
+ /* fmc cs0 with n25q256a flash */
+ data->flash_base = 0x20000000;
+ data->spi_base = 0x1E620000;
+ data->jedec_id = 0x20ba19;
+ data->cs = 0;
+ data->node = "/machine/soc/fmc/ssi.0/child[0]";
+ /* beyond 16MB */
+ data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
+
+ qtest_add_data_func("/ast2400/smc/read_jedec",
+ data, aspeed_smc_test_read_jedec);
+ qtest_add_data_func("/ast2400/smc/erase_sector",
+ data, aspeed_smc_test_erase_sector);
+ qtest_add_data_func("/ast2400/smc/erase_all",
+ data, aspeed_smc_test_erase_all);
+ qtest_add_data_func("/ast2400/smc/write_page",
+ data, aspeed_smc_test_write_page);
+ qtest_add_data_func("/ast2400/smc/read_page_mem",
+ data, aspeed_smc_test_read_page_mem);
+ qtest_add_data_func("/ast2400/smc/write_page_mem",
+ data, aspeed_smc_test_write_page_mem);
+ qtest_add_data_func("/ast2400/smc/read_status_reg",
+ data, aspeed_smc_test_read_status_reg);
+ qtest_add_data_func("/ast2400/smc/status_reg_write_protection",
+ data, aspeed_smc_test_status_reg_write_protection);
+ qtest_add_data_func("/ast2400/smc/write_block_protect",
+ data, aspeed_smc_test_write_block_protect);
+ qtest_add_data_func("/ast2400/smc/write_block_protect_bottom_bit",
+ data, aspeed_smc_test_write_block_protect_bottom_bit);
+}
+
+static void test_ast2500_evb(AspeedSMCTestData *data)
{
- uint8_t r;
-
- spi_conf(CONF_ENABLE_W0);
-
- /* default case: WP# is high and SRWD is low -> status register writable */
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
- /* test ability to write SRWD */
- writeb(ASPEED_FLASH_BASE, WRSR);
- writeb(ASPEED_FLASH_BASE, SRWD);
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
- g_assert_cmphex(r & SRWD, ==, SRWD);
-
- /* WP# high and SRWD high -> status register writable */
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
- /* test ability to write SRWD */
- writeb(ASPEED_FLASH_BASE, WRSR);
- writeb(ASPEED_FLASH_BASE, 0);
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
- g_assert_cmphex(r & SRWD, ==, 0);
-
- /* WP# low and SRWD low -> status register writable */
- qtest_set_irq_in(global_qtest,
- "/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 0);
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
- /* test ability to write SRWD */
- writeb(ASPEED_FLASH_BASE, WRSR);
- writeb(ASPEED_FLASH_BASE, SRWD);
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
- g_assert_cmphex(r & SRWD, ==, SRWD);
-
- /* WP# low and SRWD high -> status register NOT writable */
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
- /* test ability to write SRWD */
- writeb(ASPEED_FLASH_BASE, WRSR);
- writeb(ASPEED_FLASH_BASE, 0);
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
- /* write is not successful */
- g_assert_cmphex(r & SRWD, ==, SRWD);
+ int ret;
+ int fd;
- qtest_set_irq_in(global_qtest,
- "/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 1);
- flash_reset();
-}
+ fd = g_file_open_tmp("qtest.m25p80.mx25l25635e.XXXXXX",
+ &data->tmp_path, NULL);
+ g_assert(fd >= 0);
+ ret = ftruncate(fd, 32 * 1024 * 1024);
+ g_assert(ret == 0);
+ close(fd);
-static void test_write_block_protect(void)
+ data->s = qtest_initf("-machine ast2500-evb "
+ "-drive file=%s,format=raw,if=mtd",
+ data->tmp_path);
+
+ /* fmc cs0 with mx25l25635e flash */
+ data->flash_base = 0x20000000;
+ data->spi_base = 0x1E620000;
+ data->jedec_id = 0xc22019;
+ data->cs = 0;
+ data->node = "/machine/soc/fmc/ssi.0/child[0]";
+ /* beyond 16MB */
+ data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
+
+ qtest_add_data_func("/ast2500/smc/read_jedec",
+ data, aspeed_smc_test_read_jedec);
+ qtest_add_data_func("/ast2500/smc/erase_sector",
+ data, aspeed_smc_test_erase_sector);
+ qtest_add_data_func("/ast2500/smc/erase_all",
+ data, aspeed_smc_test_erase_all);
+ qtest_add_data_func("/ast2500/smc/write_page",
+ data, aspeed_smc_test_write_page);
+ qtest_add_data_func("/ast2500/smc/read_page_mem",
+ data, aspeed_smc_test_read_page_mem);
+ qtest_add_data_func("/ast2500/smc/write_page_mem",
+ data, aspeed_smc_test_write_page_mem);
+ qtest_add_data_func("/ast2500/smc/read_status_reg",
+ data, aspeed_smc_test_read_status_reg);
+ qtest_add_data_func("/ast2500/smc/write_page_qpi",
+ data, aspeed_smc_test_write_page_qpi);
+}
+
+static void test_ast2600_evb(AspeedSMCTestData *data)
{
- uint32_t sector_size = 65536;
- uint32_t n_sectors = 512;
-
- spi_ce_ctrl(1 << CRTL_EXTENDED0);
- spi_conf(CONF_ENABLE_W0);
-
- uint32_t bp_bits = 0b0;
-
- for (int i = 0; i < 16; i++) {
- bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2);
-
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, BULK_ERASE);
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, WRSR);
- writeb(ASPEED_FLASH_BASE, bp_bits);
- writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
- writeb(ASPEED_FLASH_BASE, WREN);
- spi_ctrl_stop_user();
-
- uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
- uint32_t protection_start = n_sectors - num_protected_sectors;
- uint32_t protection_end = n_sectors;
-
- for (int sector = 0; sector < n_sectors; sector++) {
- uint32_t addr = sector * sector_size;
-
- assert_page_mem(addr, 0xffffffff);
- write_page_mem(addr, make_be32(0xabcdef12));
-
- uint32_t expected_value = protection_start <= sector
- && sector < protection_end
- ? 0xffffffff : 0xabcdef12;
-
- assert_page_mem(addr, expected_value);
- }
- }
+ int ret;
+ int fd;
- flash_reset();
-}
+ fd = g_file_open_tmp("qtest.m25p80.mx66u51235f.XXXXXX",
+ &data->tmp_path, NULL);
+ g_assert(fd >= 0);
+ ret = ftruncate(fd, 64 * 1024 * 1024);
+ g_assert(ret == 0);
+ close(fd);
-static void test_write_block_protect_bottom_bit(void)
+ data->s = qtest_initf("-machine ast2600-evb "
+ "-drive file=%s,format=raw,if=mtd",
+ data->tmp_path);
+
+ /* fmc cs0 with mx66u51235f flash */
+ data->flash_base = 0x20000000;
+ data->spi_base = 0x1E620000;
+ data->jedec_id = 0xc2253a;
+ data->cs = 0;
+ data->node = "/machine/soc/fmc/ssi.0/child[0]";
+ /* beyond 16MB */
+ data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
+
+ qtest_add_data_func("/ast2600/smc/read_jedec",
+ data, aspeed_smc_test_read_jedec);
+ qtest_add_data_func("/ast2600/smc/erase_sector",
+ data, aspeed_smc_test_erase_sector);
+ qtest_add_data_func("/ast2600/smc/erase_all",
+ data, aspeed_smc_test_erase_all);
+ qtest_add_data_func("/ast2600/smc/write_page",
+ data, aspeed_smc_test_write_page);
+ qtest_add_data_func("/ast2600/smc/read_page_mem",
+ data, aspeed_smc_test_read_page_mem);
+ qtest_add_data_func("/ast2600/smc/write_page_mem",
+ data, aspeed_smc_test_write_page_mem);
+ qtest_add_data_func("/ast2600/smc/read_status_reg",
+ data, aspeed_smc_test_read_status_reg);
+ qtest_add_data_func("/ast2600/smc/write_page_qpi",
+ data, aspeed_smc_test_write_page_qpi);
+}
+
+static void test_ast1030_evb(AspeedSMCTestData *data)
{
- uint32_t sector_size = 65536;
- uint32_t n_sectors = 512;
-
- spi_ce_ctrl(1 << CRTL_EXTENDED0);
- spi_conf(CONF_ENABLE_W0);
-
- /* top bottom bit is enabled */
- uint32_t bp_bits = 0b00100 << 3;
-
- for (int i = 0; i < 16; i++) {
- bp_bits = (((i & 0b1000) | 0b0100) << 3) | ((i & 0b0111) << 2);
-
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, BULK_ERASE);
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, WRSR);
- writeb(ASPEED_FLASH_BASE, bp_bits);
- writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
- writeb(ASPEED_FLASH_BASE, WREN);
- spi_ctrl_stop_user();
-
- uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
- uint32_t protection_start = 0;
- uint32_t protection_end = num_protected_sectors;
-
- for (int sector = 0; sector < n_sectors; sector++) {
- uint32_t addr = sector * sector_size;
-
- assert_page_mem(addr, 0xffffffff);
- write_page_mem(addr, make_be32(0xabcdef12));
-
- uint32_t expected_value = protection_start <= sector
- && sector < protection_end
- ? 0xffffffff : 0xabcdef12;
+ int ret;
+ int fd;
- assert_page_mem(addr, expected_value);
- }
- }
+ fd = g_file_open_tmp("qtest.m25p80.w25q80bl.XXXXXX",
+ &data->tmp_path, NULL);
+ g_assert(fd >= 0);
+ ret = ftruncate(fd, 1 * 1024 * 1024);
+ g_assert(ret == 0);
+ close(fd);
- flash_reset();
+ data->s = qtest_initf("-machine ast1030-evb "
+ "-drive file=%s,format=raw,if=mtd",
+ data->tmp_path);
+
+ /* fmc cs0 with w25q80bl flash */
+ data->flash_base = 0x80000000;
+ data->spi_base = 0x7E620000;
+ data->jedec_id = 0xef4014;
+ data->cs = 0;
+ data->node = "/machine/soc/fmc/ssi.0/child[0]";
+ /* beyond 512KB */
+ data->page_addr = 0x800 * FLASH_PAGE_SIZE;
+
+ qtest_add_data_func("/ast1030/smc/read_jedec",
+ data, aspeed_smc_test_read_jedec);
+ qtest_add_data_func("/ast1030/smc/erase_sector",
+ data, aspeed_smc_test_erase_sector);
+ qtest_add_data_func("/ast1030/smc/erase_all",
+ data, aspeed_smc_test_erase_all);
+ qtest_add_data_func("/ast1030/smc/write_page",
+ data, aspeed_smc_test_write_page);
+ qtest_add_data_func("/ast1030/smc/read_page_mem",
+ data, aspeed_smc_test_read_page_mem);
+ qtest_add_data_func("/ast1030/smc/write_page_mem",
+ data, aspeed_smc_test_write_page_mem);
+ qtest_add_data_func("/ast1030/smc/read_status_reg",
+ data, aspeed_smc_test_read_status_reg);
+ qtest_add_data_func("/ast1030/smc/write_page_qpi",
+ data, aspeed_smc_test_write_page_qpi);
}
int main(int argc, char **argv)
{
- g_autofree char *tmp_path = NULL;
+ AspeedSMCTestData palmetto_data;
+ AspeedSMCTestData ast2500_evb_data;
+ AspeedSMCTestData ast2600_evb_data;
+ AspeedSMCTestData ast1030_evb_data;
int ret;
- int fd;
g_test_init(&argc, &argv, NULL);
- fd = g_file_open_tmp("qtest.m25p80.XXXXXX", &tmp_path, NULL);
- 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("/ast2400/smc/read_jedec", test_read_jedec);
- qtest_add_func("/ast2400/smc/erase_sector", test_erase_sector);
- qtest_add_func("/ast2400/smc/erase_all", test_erase_all);
- qtest_add_func("/ast2400/smc/write_page", test_write_page);
- qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem);
- qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem);
- qtest_add_func("/ast2400/smc/read_status_reg", test_read_status_reg);
- qtest_add_func("/ast2400/smc/status_reg_write_protection",
- test_status_reg_write_protection);
- qtest_add_func("/ast2400/smc/write_block_protect",
- test_write_block_protect);
- qtest_add_func("/ast2400/smc/write_block_protect_bottom_bit",
- test_write_block_protect_bottom_bit);
-
- flash_reset();
+ test_palmetto_bmc(&palmetto_data);
+ test_ast2500_evb(&ast2500_evb_data);
+ test_ast2600_evb(&ast2600_evb_data);
+ test_ast1030_evb(&ast1030_evb_data);
ret = g_test_run();
- qtest_quit(global_qtest);
- unlink(tmp_path);
+ qtest_quit(palmetto_data.s);
+ qtest_quit(ast2500_evb_data.s);
+ qtest_quit(ast2600_evb_data.s);
+ qtest_quit(ast1030_evb_data.s);
+ unlink(palmetto_data.tmp_path);
+ unlink(ast2500_evb_data.tmp_path);
+ unlink(ast2600_evb_data.tmp_path);
+ unlink(ast1030_evb_data.tmp_path);
+ g_free(palmetto_data.tmp_path);
+ g_free(ast2500_evb_data.tmp_path);
+ g_free(ast2600_evb_data.tmp_path);
+ g_free(ast1030_evb_data.tmp_path);
+
return ret;
}
diff --git a/tests/qtest/ast2700-gpio-test.c b/tests/qtest/ast2700-gpio-test.c
new file mode 100644
index 0000000..eeae9bf
--- /dev/null
+++ b/tests/qtest/ast2700-gpio-test.c
@@ -0,0 +1,95 @@
+/*
+ * QTest testcase for the ASPEED AST2700 GPIO Controller.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "qemu/timer.h"
+#include "qobject/qdict.h"
+#include "libqtest-single.h"
+
+#define AST2700_GPIO_BASE 0x14C0B000
+#define GPIOA0_CONTROL 0x180
+
+static void test_output_pins(const char *machine, const uint32_t base)
+{
+ QTestState *s = qtest_init(machine);
+ uint32_t offset = 0;
+ uint32_t value = 0;
+ uint32_t pin = 0;
+
+ for (char c = 'A'; c <= 'D'; c++) {
+ for (int i = 0; i < 8; i++) {
+ offset = base + (pin * 4);
+
+ /* output direction and output hi */
+ qtest_writel(s, offset, 0x00000003);
+ value = qtest_readl(s, offset);
+ g_assert_cmphex(value, ==, 0x00000003);
+
+ /* output direction and output low */
+ qtest_writel(s, offset, 0x00000002);
+ value = qtest_readl(s, offset);
+ g_assert_cmphex(value, ==, 0x00000002);
+ pin++;
+ }
+ }
+
+ qtest_quit(s);
+}
+
+static void test_input_pins(const char *machine, const uint32_t base)
+{
+ QTestState *s = qtest_init(machine);
+ char name[16];
+ uint32_t offset = 0;
+ uint32_t value = 0;
+ uint32_t pin = 0;
+
+ for (char c = 'A'; c <= 'D'; c++) {
+ for (int i = 0; i < 8; i++) {
+ sprintf(name, "gpio%c%d", c, i);
+ offset = base + (pin * 4);
+ /* input direction */
+ qtest_writel(s, offset, 0);
+
+ /* set input */
+ qtest_qom_set_bool(s, "/machine/soc/gpio", name, true);
+ value = qtest_readl(s, offset);
+ g_assert_cmphex(value, ==, 0x00002000);
+
+ /* clear input */
+ qtest_qom_set_bool(s, "/machine/soc/gpio", name, false);
+ value = qtest_readl(s, offset);
+ g_assert_cmphex(value, ==, 0);
+ pin++;
+ }
+ }
+
+ qtest_quit(s);
+}
+
+static void test_2700_input_pins(void)
+{
+ test_input_pins("-machine ast2700-evb",
+ AST2700_GPIO_BASE + GPIOA0_CONTROL);
+}
+
+static void test_2700_output_pins(void)
+{
+ test_output_pins("-machine ast2700-evb",
+ AST2700_GPIO_BASE + GPIOA0_CONTROL);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/ast2700/gpio/input_pins", test_2700_input_pins);
+ qtest_add_func("/ast2700/gpio/output_pins", test_2700_output_pins);
+
+ return g_test_run();
+}
diff --git a/tests/qtest/ast2700-hace-test.c b/tests/qtest/ast2700-hace-test.c
new file mode 100644
index 0000000..a400e29
--- /dev/null
+++ b/tests/qtest/ast2700-hace-test.c
@@ -0,0 +1,98 @@
+/*
+ * QTest testcase for the ASPEED Hash and Crypto Engine
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (C) 2025 ASPEED Technology Inc.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/bitops.h"
+#include "aspeed-hace-utils.h"
+
+static const struct AspeedMasks as2700_masks = {
+ .src = 0x7fffffff,
+ .dest = 0x7ffffff8,
+ .key = 0x7ffffff8,
+ .len = 0x0fffffff,
+ .src_hi = 0x00000003,
+ .dest_hi = 0x00000003,
+ .key_hi = 0x00000003,
+};
+
+/* ast2700 */
+static void test_md5_ast2700(void)
+{
+ aspeed_test_md5("-machine ast2700a1-evb", 0x12070000, 0x400000000);
+}
+
+static void test_sha256_ast2700(void)
+{
+ aspeed_test_sha256("-machine ast2700a1-evb", 0x12070000, 0x400000000);
+}
+
+static void test_sha256_sg_ast2700(void)
+{
+ aspeed_test_sha256_sg("-machine ast2700a1-evb", 0x12070000, 0x400000000);
+}
+
+static void test_sha384_ast2700(void)
+{
+ aspeed_test_sha384("-machine ast2700a1-evb", 0x12070000, 0x400000000);
+}
+
+static void test_sha384_sg_ast2700(void)
+{
+ aspeed_test_sha384_sg("-machine ast2700a1-evb", 0x12070000, 0x400000000);
+}
+
+static void test_sha512_ast2700(void)
+{
+ aspeed_test_sha512("-machine ast2700a1-evb", 0x12070000, 0x400000000);
+}
+
+static void test_sha512_sg_ast2700(void)
+{
+ aspeed_test_sha512_sg("-machine ast2700a1-evb", 0x12070000, 0x400000000);
+}
+
+static void test_sha256_accum_ast2700(void)
+{
+ aspeed_test_sha256_accum("-machine ast2700a1-evb", 0x12070000, 0x400000000);
+}
+
+static void test_sha384_accum_ast2700(void)
+{
+ aspeed_test_sha384_accum("-machine ast2700a1-evb", 0x12070000, 0x400000000);
+}
+
+static void test_sha512_accum_ast2700(void)
+{
+ aspeed_test_sha512_accum("-machine ast2700a1-evb", 0x12070000, 0x400000000);
+}
+
+static void test_addresses_ast2700(void)
+{
+ aspeed_test_addresses("-machine ast2700a1-evb", 0x12070000, &as2700_masks);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("ast2700/hace/addresses", test_addresses_ast2700);
+ qtest_add_func("ast2700/hace/sha512", test_sha512_ast2700);
+ qtest_add_func("ast2700/hace/sha384", test_sha384_ast2700);
+ qtest_add_func("ast2700/hace/sha256", test_sha256_ast2700);
+ qtest_add_func("ast2700/hace/md5", test_md5_ast2700);
+
+ qtest_add_func("ast2700/hace/sha512_sg", test_sha512_sg_ast2700);
+ qtest_add_func("ast2700/hace/sha384_sg", test_sha384_sg_ast2700);
+ qtest_add_func("ast2700/hace/sha256_sg", test_sha256_sg_ast2700);
+
+ qtest_add_func("ast2700/hace/sha512_accum", test_sha512_accum_ast2700);
+ qtest_add_func("ast2700/hace/sha384_accum", test_sha384_accum_ast2700);
+ qtest_add_func("ast2700/hace/sha256_accum", test_sha256_accum_ast2700);
+
+ return g_test_run();
+}
diff --git a/tests/qtest/ast2700-smc-test.c b/tests/qtest/ast2700-smc-test.c
new file mode 100644
index 0000000..62d538d
--- /dev/null
+++ b/tests/qtest/ast2700-smc-test.c
@@ -0,0 +1,72 @@
+/*
+ * QTest testcase for the M25P80 Flash using the ASPEED SPI Controller since
+ * AST2700.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bswap.h"
+#include "libqtest-single.h"
+#include "qemu/bitops.h"
+#include "aspeed-smc-utils.h"
+
+static void test_ast2700_evb(AspeedSMCTestData *data)
+{
+ int ret;
+ int fd;
+
+ fd = g_file_open_tmp("qtest.m25p80.w25q01jvq.XXXXXX",
+ &data->tmp_path, NULL);
+ g_assert(fd >= 0);
+ ret = ftruncate(fd, 128 * 1024 * 1024);
+ g_assert(ret == 0);
+ close(fd);
+
+ data->s = qtest_initf("-machine ast2700-evb "
+ "-drive file=%s,format=raw,if=mtd",
+ data->tmp_path);
+
+ /* fmc cs0 with w25q01jvq flash */
+ data->flash_base = 0x100000000;
+ data->spi_base = 0x14000000;
+ data->jedec_id = 0xef4021;
+ data->cs = 0;
+ data->node = "/machine/soc/fmc/ssi.0/child[0]";
+ /* beyond 64MB */
+ data->page_addr = 0x40000 * FLASH_PAGE_SIZE;
+
+ qtest_add_data_func("/ast2700/smc/read_jedec",
+ data, aspeed_smc_test_read_jedec);
+ qtest_add_data_func("/ast2700/smc/erase_sector",
+ data, aspeed_smc_test_erase_sector);
+ qtest_add_data_func("/ast2700/smc/erase_all",
+ data, aspeed_smc_test_erase_all);
+ qtest_add_data_func("/ast2700/smc/write_page",
+ data, aspeed_smc_test_write_page);
+ qtest_add_data_func("/ast2700/smc/read_page_mem",
+ data, aspeed_smc_test_read_page_mem);
+ qtest_add_data_func("/ast2700/smc/write_page_mem",
+ data, aspeed_smc_test_write_page_mem);
+ qtest_add_data_func("/ast2700/smc/read_status_reg",
+ data, aspeed_smc_test_read_status_reg);
+ qtest_add_data_func("/ast2700/smc/write_page_qpi",
+ data, aspeed_smc_test_write_page_qpi);
+}
+
+int main(int argc, char **argv)
+{
+ AspeedSMCTestData ast2700_evb_data;
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ test_ast2700_evb(&ast2700_evb_data);
+ ret = g_test_run();
+
+ qtest_quit(ast2700_evb_data.s);
+ unlink(ast2700_evb_data.tmp_path);
+ g_free(ast2700_evb_data.tmp_path);
+ return ret;
+}
diff --git a/tests/qtest/bcm2835-i2c-test.c b/tests/qtest/bcm2835-i2c-test.c
index 513ecce..1599194 100644
--- a/tests/qtest/bcm2835-i2c-test.c
+++ b/tests/qtest/bcm2835-i2c-test.c
@@ -81,7 +81,7 @@ static void test_i2c_read_write(gconstpointer data)
g_assert_cmpint(i2cdata, ==, 0xde);
i2cdata = readl(base_addr + BCM2835_I2C_FIFO);
- g_assert_cmpint(i2cdata, ==, 0xad);
+ g_assert_cmpint(i2cdata, ==, 0xa0);
/* Clear flags */
writel(base_addr + BCM2835_I2C_S, BCM2835_I2C_S_DONE | BCM2835_I2C_S_ERR |
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index 36e5c0a..4dbc07e 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -292,6 +292,7 @@ static void dump_aml_files(test_data *data, bool rebuild)
g_free(aml_file);
}
+ free_test_data(&exp_data);
}
static bool create_tmp_asl(AcpiSdtTable *sdt)
@@ -959,7 +960,7 @@ static void test_acpi_piix4_tcg_bridge(void)
free_test_data(&data);
/* check that reboot/reset doesn't change any ACPI tables */
- qtest_qmp_send(data.qts, "{'execute':'system_reset' }");
+ qtest_system_reset(data.qts);
process_acpi_tables(&data);
free_test_data(&data);
}
@@ -1216,7 +1217,7 @@ static void test_acpi_q35_multif_bridge(void)
free_test_data(&data);
/* check that reboot/reset doesn't change any ACPI tables */
- qtest_qmp_send(data.qts, "{'execute':'system_reset' }");
+ qtest_system_reset(data.qts);
process_acpi_tables(&data);
free_test_data(&data);
}
@@ -1621,7 +1622,7 @@ static void test_acpi_aarch64_virt_tcg_memhp(void)
.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,
+ .scan_len = 256ULL * MiB,
};
data.variant = ".memhp";
@@ -1706,6 +1707,32 @@ static void test_acpi_microvm_ioapic2_tcg(void)
free_test_data(&data);
}
+static void test_acpi_riscv64_virt_tcg_numamem(void)
+{
+ test_data data = {
+ .machine = "virt",
+ .arch = "riscv64",
+ .tcg_only = true,
+ .uefi_fl1 = "pc-bios/edk2-riscv-code.fd",
+ .uefi_fl2 = "pc-bios/edk2-riscv-vars.fd",
+ .cd = "tests/data/uefi-boot-images/bios-tables-test.riscv64.iso.qcow2",
+ .ram_start = 0x80000000ULL,
+ .scan_len = 128ULL * MiB,
+ };
+
+ data.variant = ".numamem";
+ /*
+ * RHCT will have ISA string encoded. To reduce the effort
+ * of updating expected AML file for any new default ISA extension,
+ * use the profile rva22s64.
+ */
+ test_acpi_one(" -cpu rva22s64"
+ " -object memory-backend-ram,id=ram0,size=128M"
+ " -numa node,memdev=ram0",
+ &data);
+ free_test_data(&data);
+}
+
static void test_acpi_aarch64_virt_tcg_numamem(void)
{
test_data data = {
@@ -1716,7 +1743,7 @@ static void test_acpi_aarch64_virt_tcg_numamem(void)
.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,
+ .scan_len = 128ULL * MiB,
};
data.variant = ".numamem";
@@ -1738,7 +1765,7 @@ static void test_acpi_aarch64_virt_tcg_pxb(void)
.uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
.uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
.ram_start = 0x40000000ULL,
- .scan_len = 128ULL * 1024 * 1024,
+ .scan_len = 128ULL * MiB,
};
/*
* While using -cdrom, the cdrom would auto plugged into pxb-pcie,
@@ -1814,7 +1841,7 @@ static void test_acpi_aarch64_virt_tcg_acpi_hmat(void)
.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,
+ .scan_len = 128ULL * MiB,
};
data.variant = ".acpihmatvirt";
@@ -1910,6 +1937,101 @@ static void test_acpi_q35_tcg_acpi_hmat_noinitiator(void)
free_test_data(&data);
}
+/* Test intended to hit corner cases of SRAT and HMAT */
+static void test_acpi_q35_tcg_acpi_hmat_generic_x(void)
+{
+ test_data data = {};
+
+ data.machine = MACHINE_Q35;
+ data.arch = "x86";
+ data.variant = ".acpihmat-generic-x";
+ test_acpi_one(" -machine hmat=on,cxl=on"
+ " -smp 3,sockets=3"
+ " -m 128M,maxmem=384M,slots=2"
+ " -device pcie-root-port,chassis=1,id=pci.1"
+ " -device pci-testdev,bus=pci.1,"
+ "multifunction=on,addr=00.0"
+ " -device pci-testdev,bus=pci.1,addr=00.1"
+ " -device pci-testdev,bus=pci.1,id=gidev,addr=00.2"
+ " -device pxb-cxl,bus_nr=64,bus=pcie.0,id=cxl.1"
+ " -object memory-backend-ram,size=64M,id=ram0"
+ " -object memory-backend-ram,size=64M,id=ram1"
+ " -numa node,nodeid=0,cpus=0,memdev=ram0"
+ " -numa node,nodeid=1"
+ " -object acpi-generic-initiator,id=gi0,pci-dev=gidev,node=1"
+ " -numa node,nodeid=2"
+ " -object acpi-generic-port,id=gp0,pci-bus=cxl.1,node=2"
+ " -numa node,nodeid=3,cpus=1"
+ " -numa node,nodeid=4,memdev=ram1"
+ " -numa node,nodeid=5,cpus=2"
+ " -numa hmat-lb,initiator=0,target=0,hierarchy=memory,"
+ "data-type=access-latency,latency=10"
+ " -numa hmat-lb,initiator=0,target=0,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=800M"
+ " -numa hmat-lb,initiator=0,target=2,hierarchy=memory,"
+ "data-type=access-latency,latency=100"
+ " -numa hmat-lb,initiator=0,target=2,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=200M"
+ " -numa hmat-lb,initiator=0,target=4,hierarchy=memory,"
+ "data-type=access-latency,latency=100"
+ " -numa hmat-lb,initiator=0,target=4,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=200M"
+ " -numa hmat-lb,initiator=0,target=5,hierarchy=memory,"
+ "data-type=access-latency,latency=200"
+ " -numa hmat-lb,initiator=0,target=5,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=400M"
+ " -numa hmat-lb,initiator=1,target=0,hierarchy=memory,"
+ "data-type=access-latency,latency=500"
+ " -numa hmat-lb,initiator=1,target=0,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=100M"
+ " -numa hmat-lb,initiator=1,target=2,hierarchy=memory,"
+ "data-type=access-latency,latency=50"
+ " -numa hmat-lb,initiator=1,target=2,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=400M"
+ " -numa hmat-lb,initiator=1,target=4,hierarchy=memory,"
+ "data-type=access-latency,latency=50"
+ " -numa hmat-lb,initiator=1,target=4,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=800M"
+ " -numa hmat-lb,initiator=1,target=5,hierarchy=memory,"
+ "data-type=access-latency,latency=500"
+ " -numa hmat-lb,initiator=1,target=5,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=100M"
+ " -numa hmat-lb,initiator=3,target=0,hierarchy=memory,"
+ "data-type=access-latency,latency=20"
+ " -numa hmat-lb,initiator=3,target=0,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=400M"
+ " -numa hmat-lb,initiator=3,target=2,hierarchy=memory,"
+ "data-type=access-latency,latency=80"
+ " -numa hmat-lb,initiator=3,target=2,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=200M"
+ " -numa hmat-lb,initiator=3,target=4,hierarchy=memory,"
+ "data-type=access-latency,latency=80"
+ " -numa hmat-lb,initiator=3,target=4,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=200M"
+ " -numa hmat-lb,initiator=3,target=5,hierarchy=memory,"
+ "data-type=access-latency,latency=20"
+ " -numa hmat-lb,initiator=3,target=5,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=400M"
+ " -numa hmat-lb,initiator=5,target=0,hierarchy=memory,"
+ "data-type=access-latency,latency=20"
+ " -numa hmat-lb,initiator=5,target=0,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=400M"
+ " -numa hmat-lb,initiator=5,target=2,hierarchy=memory,"
+ "data-type=access-latency,latency=80"
+ " -numa hmat-lb,initiator=5,target=4,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=200M"
+ " -numa hmat-lb,initiator=5,target=4,hierarchy=memory,"
+ "data-type=access-latency,latency=80"
+ " -numa hmat-lb,initiator=5,target=2,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=200M"
+ " -numa hmat-lb,initiator=5,target=5,hierarchy=memory,"
+ "data-type=access-latency,latency=10"
+ " -numa hmat-lb,initiator=5,target=5,hierarchy=memory,"
+ "data-type=access-bandwidth,bandwidth=800M",
+ &data);
+ free_test_data(&data);
+}
+
#ifdef CONFIG_POSIX
static void test_acpi_erst(const char *machine, const char *arch)
{
@@ -1973,7 +2095,7 @@ static void test_acpi_riscv64_virt_tcg(void)
.uefi_fl2 = "pc-bios/edk2-riscv-vars.fd",
.cd = "tests/data/uefi-boot-images/bios-tables-test.riscv64.iso.qcow2",
.ram_start = 0x80000000ULL,
- .scan_len = 128ULL * 1024 * 1024,
+ .scan_len = 128ULL * MiB,
};
/*
@@ -1995,7 +2117,7 @@ static void test_acpi_aarch64_virt_tcg(void)
.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,
+ .scan_len = 128ULL * MiB,
};
data.smbios_cpu_max_speed = 2900;
@@ -2016,7 +2138,7 @@ static void test_acpi_aarch64_virt_tcg_topology(void)
.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,
+ .scan_len = 128ULL * MiB,
};
test_acpi_one("-cpu cortex-a57 "
@@ -2024,6 +2146,25 @@ static void test_acpi_aarch64_virt_tcg_topology(void)
free_test_data(&data);
}
+static void test_acpi_aarch64_virt_tcg_its_off(void)
+{
+ test_data data = {
+ .machine = "virt",
+ .arch = "aarch64",
+ .variant = ".its_off",
+ .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 "
+ "-M gic-version=3,iommu=smmuv3,its=off", &data);
+ free_test_data(&data);
+}
+
static void test_acpi_q35_viot(void)
{
test_data data = {
@@ -2101,7 +2242,7 @@ static void test_acpi_aarch64_virt_viot(void)
.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,
+ .scan_len = 128ULL * MiB,
};
test_acpi_one("-cpu cortex-a57 "
@@ -2285,7 +2426,7 @@ static void test_acpi_aarch64_virt_oem_fields(void)
.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,
+ .scan_len = 128ULL * MiB,
};
char *args;
@@ -2388,6 +2529,8 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/q35/nohpet", test_acpi_q35_tcg_nohpet);
qtest_add_func("acpi/q35/acpihmat-noinitiator",
test_acpi_q35_tcg_acpi_hmat_noinitiator);
+ qtest_add_func("acpi/q35/acpihmat-genericx",
+ test_acpi_q35_tcg_acpi_hmat_generic_x);
/* i386 does not support memory hotplug */
if (strcmp(arch, "i386")) {
@@ -2453,6 +2596,8 @@ int main(int argc, char *argv[])
test_acpi_aarch64_virt_tcg_acpi_hmat);
qtest_add_func("acpi/virt/topology",
test_acpi_aarch64_virt_tcg_topology);
+ qtest_add_func("acpi/virt/its_off",
+ test_acpi_aarch64_virt_tcg_its_off);
qtest_add_func("acpi/virt/numamem",
test_acpi_aarch64_virt_tcg_numamem);
qtest_add_func("acpi/virt/memhp", test_acpi_aarch64_virt_tcg_memhp);
@@ -2466,6 +2611,8 @@ int main(int argc, char *argv[])
} else if (strcmp(arch, "riscv64") == 0) {
if (has_tcg && qtest_has_device("virtio-blk-pci")) {
qtest_add_func("acpi/virt", test_acpi_riscv64_virt_tcg);
+ qtest_add_func("acpi/virt/numamem",
+ test_acpi_riscv64_virt_tcg_numamem);
}
}
ret = g_test_run();
diff --git a/tests/qtest/boot-order-test.c b/tests/qtest/boot-order-test.c
index 8f2b6ef..74d6b82 100644
--- a/tests/qtest/boot-order-test.c
+++ b/tests/qtest/boot-order-test.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include "libqos/fw_cfg.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "standard-headers/linux/qemu_fw_cfg.h"
typedef struct {
@@ -31,7 +31,7 @@ static void test_a_boot_order(const char *machine,
uint64_t actual;
QTestState *qts;
- if (machine && !qtest_has_machine(machine)) {
+ if (!qtest_has_machine(machine)) {
g_test_skip("Machine is not available");
return;
}
@@ -40,12 +40,7 @@ static void test_a_boot_order(const char *machine,
machine ?: "", test_args);
actual = read_boot_order(qts);
g_assert_cmphex(actual, ==, expected_boot);
- qtest_qmp_assert_success(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");
+ qtest_system_reset(qts);
actual = read_boot_order(qts);
g_assert_cmphex(actual, ==, expected_reboot);
qtest_quit(qts);
@@ -107,7 +102,7 @@ static const boot_order_test test_cases_pc[] = {
static void test_pc_boot_order(void)
{
- test_boot_orders(NULL, read_boot_order_pc, test_cases_pc);
+ test_boot_orders("pc", read_boot_order_pc, test_cases_pc);
}
static uint64_t read_boot_order_pmac(QTestState *qts)
diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c
index 3b92fa5..a05d26e 100644
--- a/tests/qtest/boot-serial-test.c
+++ b/tests/qtest/boot-serial-test.c
@@ -70,18 +70,23 @@ static const uint8_t kernel_plml605[] = {
};
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 */
+ 0x10, 0x30, 0x9f, 0xe5, /* ldr r3, [pc, #16] Get &UART0 */
+ 0x10, 0x20, 0x9f, 0xe5, /* ldr r2, [pc, #16] Get &CR */
+ 0xb0, 0x23, 0xc3, 0xe1, /* strh r2, [r3, #48] Set CR */
+ 0x54, 0x20, 0xa0, 0xe3, /* mov r2, #'T' */
+ 0x00, 0x20, 0xc3, 0xe5, /* loop: strb r2, [r3] *TXDAT = 'T' */
+ 0xff, 0xff, 0xff, 0xea, /* b -4 (loop) */
+ 0x00, 0x10, 0x20, 0x3f, /* UART0: 0x3f201000 */
+ 0x01, 0x01, 0x00, 0x00, /* CR: 0x101 = UARTEN|TXE */
};
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) */
+ 0x02, 0x20, 0xa1, 0xd2, /* mov x2, #0x9000000 Load UART0 */
+ 0x21, 0x20, 0x80, 0x52, /* mov w1, 0x101 CR = UARTEN|TXE */
+ 0x41, 0x60, 0x00, 0x79, /* strh w1, [x2, #48] Set CR */
+ 0x81, 0x0a, 0x80, 0x52, /* mov w1, #'T' */
+ 0x41, 0x00, 0x00, 0x39, /* loop: strb w1, [x2] *TXDAT = 'T' */
+ 0xff, 0xff, 0xff, 0x17, /* b -4 (loop) */
};
static const uint8_t kernel_nrf51[] = {
@@ -184,8 +189,6 @@ static const testdef_t tests[] = {
{ "microblazeel", "petalogix-ml605", "", "TT",
sizeof(kernel_plml605), kernel_plml605 },
{ "arm", "raspi2b", "", "TT", sizeof(bios_raspi2), 0, bios_raspi2 },
- /* For hppa, force bios to output to serial by disabling graphics. */
- { "hppa", "hppa", "-vga none", "SeaBIOS wants SYSTEM HALT" },
{ "aarch64", "virt", "-cpu max", "TT", sizeof(kernel_aarch64),
kernel_aarch64 },
{ "arm", "microbit", "", "T", sizeof(kernel_nrf51), kernel_nrf51 },
diff --git a/tests/qtest/cdrom-test.c b/tests/qtest/cdrom-test.c
index 5d89e62..56e2d28 100644
--- a/tests/qtest/cdrom-test.c
+++ b/tests/qtest/cdrom-test.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include "libqtest.h"
#include "boot-sector.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
static char isoimage[] = "cdrom-boot-iso-XXXXXX";
@@ -135,13 +135,35 @@ static void add_x86_tests(void)
return;
}
- qtest_add_data_func("cdrom/boot/default", "-cdrom ", test_cdboot);
- if (qtest_has_device("virtio-scsi-ccw")) {
- qtest_add_data_func("cdrom/boot/virtio-scsi",
- "-device virtio-scsi -device scsi-cd,drive=cdr "
- "-blockdev file,node-name=cdr,filename=",
- test_cdboot);
+ if (qtest_has_machine("pc")) {
+ qtest_add_data_func("cdrom/boot/default", "-cdrom ", test_cdboot);
+ if (qtest_has_device("virtio-scsi-ccw")) {
+ qtest_add_data_func("cdrom/boot/virtio-scsi",
+ "-device virtio-scsi -device scsi-cd,drive=cdr "
+ "-blockdev file,node-name=cdr,filename=",
+ test_cdboot);
+ }
+
+ if (qtest_has_device("am53c974")) {
+ qtest_add_data_func("cdrom/boot/am53c974",
+ "-device am53c974 -device scsi-cd,drive=cd1 "
+ "-drive if=none,id=cd1,format=raw,file=",
+ test_cdboot);
+ }
+ if (qtest_has_device("dc390")) {
+ qtest_add_data_func("cdrom/boot/dc390",
+ "-device dc390 -device scsi-cd,drive=cd1 "
+ "-blockdev file,node-name=cd1,filename=",
+ test_cdboot);
+ }
+ if (qtest_has_device("lsi53c895a")) {
+ qtest_add_data_func("cdrom/boot/lsi53c895a",
+ "-device lsi53c895a -device scsi-cd,drive=cd1 "
+ "-blockdev file,node-name=cd1,filename=",
+ test_cdboot);
+ }
}
+
/*
* Unstable CI test under load
* See https://lists.gnu.org/archive/html/qemu-devel/2019-02/msg05509.html
@@ -150,35 +172,20 @@ static void add_x86_tests(void)
qtest_add_data_func("cdrom/boot/isapc", "-M isapc "
"-drive if=ide,media=cdrom,file=", test_cdboot);
}
- if (qtest_has_device("am53c974")) {
- qtest_add_data_func("cdrom/boot/am53c974",
- "-device am53c974 -device scsi-cd,drive=cd1 "
- "-drive if=none,id=cd1,format=raw,file=",
- test_cdboot);
- }
- if (qtest_has_device("dc390")) {
- qtest_add_data_func("cdrom/boot/dc390",
- "-device dc390 -device scsi-cd,drive=cd1 "
- "-blockdev file,node-name=cd1,filename=",
- test_cdboot);
- }
- if (qtest_has_device("lsi53c895a")) {
- qtest_add_data_func("cdrom/boot/lsi53c895a",
- "-device lsi53c895a -device scsi-cd,drive=cd1 "
- "-blockdev file,node-name=cd1,filename=",
- test_cdboot);
- }
- if (qtest_has_device("megasas")) {
- qtest_add_data_func("cdrom/boot/megasas", "-M q35 "
- "-device megasas -device scsi-cd,drive=cd1 "
- "-blockdev file,node-name=cd1,filename=",
- test_cdboot);
- }
- if (qtest_has_device("megasas-gen2")) {
- 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);
+
+ if (qtest_has_machine("q35")) {
+ if (qtest_has_device("megasas")) {
+ qtest_add_data_func("cdrom/boot/megasas", "-M q35 "
+ "-device megasas -device scsi-cd,drive=cd1 "
+ "-blockdev file,node-name=cd1,filename=",
+ test_cdboot);
+ }
+ if (qtest_has_device("megasas-gen2")) {
+ 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);
+ }
}
}
@@ -206,6 +213,30 @@ static void add_s390x_tests(void)
"-drive driver=null-co,read-zeroes=on,if=none,id=d1 "
"-device virtio-blk,drive=d2,bootindex=1 "
"-drive if=none,id=d2,media=cdrom,file=", test_cdboot);
+ qtest_add_data_func("cdrom/boot/as-fallback-device",
+ "-device virtio-serial -device virtio-scsi "
+ "-device virtio-blk,drive=d1,bootindex=1 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d1 "
+ "-device virtio-blk,drive=d2,bootindex=2 "
+ "-drive if=none,id=d2,media=cdrom,file=", test_cdboot);
+ qtest_add_data_func("cdrom/boot/as-last-option",
+ "-device virtio-serial -device virtio-scsi "
+ "-device virtio-blk,drive=d1,bootindex=1 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d1 "
+ "-device virtio-blk,drive=d2,bootindex=2 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d2 "
+ "-device virtio-blk,drive=d3,bootindex=3 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d3 "
+ "-device scsi-hd,drive=d4,bootindex=4 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d4 "
+ "-device scsi-hd,drive=d5,bootindex=5 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d5 "
+ "-device virtio-blk,drive=d6,bootindex=6 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d6 "
+ "-device scsi-hd,drive=d7,bootindex=7 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d7 "
+ "-device scsi-cd,drive=d8,bootindex=8 "
+ "-drive if=none,id=d8,media=cdrom,file=", test_cdboot);
if (qtest_has_device("x-terminal3270")) {
qtest_add_data_func("cdrom/boot/without-bootindex",
"-device virtio-scsi -device virtio-serial "
diff --git a/tests/qtest/cmsdk-apb-watchdog-test.c b/tests/qtest/cmsdk-apb-watchdog-test.c
index 00b5dbb..cd0c602 100644
--- a/tests/qtest/cmsdk-apb-watchdog-test.c
+++ b/tests/qtest/cmsdk-apb-watchdog-test.c
@@ -15,14 +15,12 @@
*/
#include "qemu/osdep.h"
+#include "exec/hwaddr.h"
#include "qemu/bitops.h"
#include "libqtest-single.h"
-/*
- * lm3s811evb watchdog; at board startup this runs at 200MHz / 16 == 12.5MHz,
- * which is 80ns per tick.
- */
#define WDOG_BASE 0x40000000
+#define WDOG_BASE_MPS2 0x40008000
#define WDOGLOAD 0
#define WDOGVALUE 4
@@ -37,39 +35,97 @@
#define SYSDIV_SHIFT 23
#define SYSDIV_LENGTH 4
-static void test_watchdog(void)
+#define WDOGLOAD_DEFAULT 0xFFFFFFFF
+#define WDOGVALUE_DEFAULT 0xFFFFFFFF
+
+typedef struct CMSDKAPBWatchdogTestArgs {
+ int64_t tick;
+ hwaddr wdog_base;
+ const char *machine;
+} CMSDKAPBWatchdogTestArgs;
+
+enum {
+ MACHINE_LM3S811EVB,
+ MACHINE_MPS2_AN385,
+};
+
+/*
+ * lm3s811evb watchdog; at board startup this runs at 200MHz / 16 == 12.5MHz,
+ * which is 80ns per tick.
+ *
+ * IoTKit/ARMSSE dualtimer; driven at 25MHz in mps2-an385, so 40ns per tick
+ */
+static const CMSDKAPBWatchdogTestArgs machine_info[] = {
+ [MACHINE_LM3S811EVB] = {
+ .tick = 80,
+ .wdog_base = WDOG_BASE,
+ .machine = "lm3s811evb",
+ },
+ [MACHINE_MPS2_AN385] = {
+ .tick = 40,
+ .wdog_base = WDOG_BASE_MPS2,
+ .machine = "mps2-an385",
+ },
+};
+
+static void system_reset(QTestState *qtest)
{
- g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
+ QDict *resp;
- writel(WDOG_BASE + WDOGCONTROL, 1);
- writel(WDOG_BASE + WDOGLOAD, 1000);
+ resp = qtest_qmp(qtest, "{'execute': 'system_reset'}");
+ g_assert(qdict_haskey(resp, "return"));
+ qobject_unref(resp);
+ qtest_qmp_eventwait(qtest, "RESET");
+}
+
+static void test_watchdog(const void *ptr)
+{
+ const CMSDKAPBWatchdogTestArgs *args = ptr;
+ hwaddr wdog_base = args->wdog_base;
+ int64_t tick = args->tick;
+ g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
+ qtest_start(cmdline);
+
+ g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
+
+ writel(wdog_base + WDOGCONTROL, 1);
+ writel(wdog_base + WDOGLOAD, 1000);
/* Step to just past the 500th tick */
- clock_step(500 * 80 + 1);
- g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
- g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
+ clock_step(500 * tick + 1);
+ g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 500);
/* Just past the 1000th tick: timer should have fired */
- clock_step(500 * 80);
- g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
- g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 0);
+ clock_step(500 * tick);
+ g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 1);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 0);
/* VALUE reloads at following tick */
- clock_step(80);
- g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
+ clock_step(tick);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1000);
/* Writing any value to WDOGINTCLR clears the interrupt and reloads */
- clock_step(500 * 80);
- g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
- g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
- writel(WDOG_BASE + WDOGINTCLR, 0);
- g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
- g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
+ clock_step(500 * tick);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 500);
+ g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 1);
+ writel(wdog_base + WDOGINTCLR, 0);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1000);
+ g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
+
+ qtest_end();
}
-static void test_clock_change(void)
+/*
+ * This test can only be executed in the stellaris board since it relies on a
+ * component of the board to change the clocking parameters of the watchdog.
+ */
+static void test_clock_change(const void *ptr)
{
uint32_t rcc;
+ const CMSDKAPBWatchdogTestArgs *args = ptr;
+ g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
+ qtest_start(cmdline);
/*
* Test that writing to the stellaris board's RCC register to
@@ -109,23 +165,231 @@ static void test_clock_change(void)
writel(WDOG_BASE + WDOGINTCLR, 0);
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
+
+ qtest_end();
}
-int main(int argc, char **argv)
+/* Tests the counter is not running after reset. */
+static void test_watchdog_reset(const void *ptr)
{
- int r;
+ const CMSDKAPBWatchdogTestArgs *args = ptr;
+ hwaddr wdog_base = args->wdog_base;
+ int64_t tick = args->tick;
+ g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
+ qtest_start(cmdline);
+ g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
- g_test_init(&argc, &argv, NULL);
+ g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
+ g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
+
+ g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0);
+
+ /*
+ * The counter should not be running if WDOGCONTROL.INTEN has not been set,
+ * as it is the case after a cold reset.
+ */
+ clock_step(15 * tick + 1);
+ g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
+ g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
+
+ /* Let the counter run before reset */
+ writel(wdog_base + WDOGLOAD, 3000);
+ writel(wdog_base + WDOGCONTROL, 1);
+
+ /* Verify it is running */
+ clock_step(1000 * tick + 1);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 3000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 2000);
+
+ system_reset(global_qtest);
- qtest_start("-machine lm3s811evb");
+ /* Check defaults after reset */
+ g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
+ g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
- qtest_add_func("/cmsdk-apb-watchdog/watchdog", test_watchdog);
- qtest_add_func("/cmsdk-apb-watchdog/watchdog_clock_change",
- test_clock_change);
+ /* The counter should not be running after reset. */
+ clock_step(1000 * tick + 1);
+ g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
+ g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
- r = g_test_run();
+ qtest_end();
+}
+
+/*
+ * Tests inten works as the counter enable based on this description:
+ *
+ * Enable the interrupt event, WDOGINT. Set HIGH to enable the counter and the
+ * interrupt, or LOW to disable the counter and interrupt. Reloads the counter
+ * from the value in WDOGLOAD when the interrupt is enabled, after previously
+ * being disabled.
+ */
+static void test_watchdog_inten(const void *ptr)
+{
+ const CMSDKAPBWatchdogTestArgs *args = ptr;
+ hwaddr wdog_base = args->wdog_base;
+ int64_t tick = args->tick;
+ g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
+ qtest_start(cmdline);
+ g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
+
+ g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
+ g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
+
+ /*
+ * When WDOGLOAD is written to, the count is immediately restarted from the
+ * new value.
+ *
+ * Note: the counter should not be running as long as WDOGCONTROL.INTEN is
+ * not set
+ */
+ writel(wdog_base + WDOGLOAD, 4000);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
+ clock_step(500 * tick + 1);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
+
+ /* Set HIGH WDOGCONTROL.INTEN to enable the counter and the interrupt */
+ writel(wdog_base + WDOGCONTROL, 1);
+ clock_step(500 * tick + 1);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500);
+
+ /* or LOW to disable the counter and interrupt. */
+ writel(wdog_base + WDOGCONTROL, 0);
+ clock_step(100 * tick);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500);
+
+ /*
+ * Reloads the counter from the value in WDOGLOAD when the interrupt is
+ * enabled, after previously being disabled.
+ */
+ writel(wdog_base + WDOGCONTROL, 1);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
+
+ /* Test counter is still on */
+ clock_step(50 * tick + 1);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3950);
+
+ /*
+ * When WDOGLOAD is written to, the count is immediately restarted from the
+ * new value.
+ *
+ * Note: the counter should be running since WDOGCONTROL.INTEN is set
+ */
+ writel(wdog_base + WDOGLOAD, 5000);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 5000);
+ clock_step(4999 * tick + 1);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1);
+ g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
+
+ /* Finally disable and check the conditions don't change */
+ writel(wdog_base + WDOGCONTROL, 0);
+ clock_step(10 * tick);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1);
+ g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
+
+ qtest_end();
+}
+
+/*
+ * Tests the following custom behavior:
+ *
+ * The Luminary version of this device ignores writes to this register after the
+ * guest has enabled interrupts (so they can only be disabled again via reset).
+ */
+static void test_watchdog_inten_luminary(const void *ptr)
+{
+ const CMSDKAPBWatchdogTestArgs *args = ptr;
+ hwaddr wdog_base = args->wdog_base;
+ int64_t tick = args->tick;
+ g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
+ qtest_start(cmdline);
+ g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
+
+ g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
+ g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
+
+ /*
+ * When WDOGLOAD is written to, the count is immediately restarted from the
+ * new value.
+ *
+ * Note: the counter should not be running as long as WDOGCONTROL.INTEN is
+ * not set
+ */
+ writel(wdog_base + WDOGLOAD, 4000);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
+ clock_step(500 * tick + 1);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
+
+ /* Set HIGH WDOGCONTROL.INTEN to enable the counter and the interrupt */
+ writel(wdog_base + WDOGCONTROL, 1);
+ clock_step(500 * tick + 1);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500);
+
+ /*
+ * The Luminary version of this device ignores writes to this register after
+ * the guest has enabled interrupts
+ */
+ writel(wdog_base + WDOGCONTROL, 0);
+ clock_step(100 * tick);
+ g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
+ g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3400);
+ g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0x1);
+
+ /* They can only be disabled again via reset */
+ system_reset(global_qtest);
+
+ /* Check defaults after reset */
+ g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
+ g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
+ g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0);
+
+ /* The counter should not be running after reset. */
+ clock_step(1000 * tick + 1);
+ g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
+ g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
qtest_end();
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_set_nonfatal_assertions();
+
+ if (qtest_has_machine(machine_info[MACHINE_LM3S811EVB].machine)) {
+ qtest_add_data_func("/cmsdk-apb-watchdog/watchdog",
+ &machine_info[MACHINE_LM3S811EVB], test_watchdog);
+ qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_clock_change",
+ &machine_info[MACHINE_LM3S811EVB],
+ test_clock_change);
+ qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_reset",
+ &machine_info[MACHINE_LM3S811EVB],
+ test_watchdog_reset);
+ qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_inten_luminary",
+ &machine_info[MACHINE_LM3S811EVB],
+ test_watchdog_inten_luminary);
+ }
+ if (qtest_has_machine(machine_info[MACHINE_MPS2_AN385].machine)) {
+ qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_mps2",
+ &machine_info[MACHINE_MPS2_AN385], test_watchdog);
+ qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_reset_mps2",
+ &machine_info[MACHINE_MPS2_AN385],
+ test_watchdog_reset);
+ qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_inten",
+ &machine_info[MACHINE_MPS2_AN385],
+ test_watchdog_inten);
+ }
- return r;
+ return g_test_run();
}
diff --git a/tests/qtest/cpu-plug-test.c b/tests/qtest/cpu-plug-test.c
index 7f5dd5f..44d7046 100644
--- a/tests/qtest/cpu-plug-test.c
+++ b/tests/qtest/cpu-plug-test.c
@@ -10,8 +10,8 @@
#include "qemu/osdep.h"
#include "libqtest-single.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
struct PlugTestData {
char *machine;
@@ -156,6 +156,28 @@ static void add_s390x_test_case(const char *mname)
g_free(path);
}
+static void add_loongarch_test_case(const char *mname)
+{
+ char *path;
+ PlugTestData *data;
+
+ data = g_new(PlugTestData, 1);
+ data->machine = g_strdup(mname);
+ data->cpu_model = "la464";
+ data->device_model = g_strdup("la464-loongarch-cpu");
+ data->sockets = 1;
+ 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);
+}
+
int main(int argc, char **argv)
{
const char *arch = qtest_get_arch();
@@ -168,6 +190,8 @@ int main(int argc, char **argv)
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());
+ } else if (g_str_equal(arch, "loongarch64")) {
+ add_loongarch_test_case("virt");
}
return g_test_run();
diff --git a/tests/qtest/dbus-display-test.c b/tests/qtest/dbus-display-test.c
index 0390bdc..f7fc873 100644
--- a/tests/qtest/dbus-display-test.c
+++ b/tests/qtest/dbus-display-test.c
@@ -2,9 +2,14 @@
#include "qemu/sockets.h"
#include "qemu/dbus.h"
#include "qemu/sockets.h"
+#include "glib.h"
+#include "glibconfig.h"
#include <gio/gio.h>
#include <gio/gunixfdlist.h>
#include "libqtest.h"
+#ifndef WIN32
+#include <sys/mman.h>
+#endif
#include "ui/dbus-display1.h"
static GDBusConnection*
@@ -82,6 +87,7 @@ typedef struct TestDBusConsoleRegister {
GThread *thread;
GDBusConnection *listener_conn;
GDBusObjectManagerServer *server;
+ bool with_map;
} TestDBusConsoleRegister;
static gboolean listener_handle_scanout(
@@ -94,13 +100,49 @@ static gboolean listener_handle_scanout(
GVariant *arg_data,
TestDBusConsoleRegister *test)
{
+ if (!test->with_map) {
+ g_main_loop_quit(test->loop);
+ }
+
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+#ifndef WIN32
+static gboolean listener_handle_scanout_map(
+ QemuDBusDisplay1ListenerUnixMap *object,
+ GDBusMethodInvocation *invocation,
+ GUnixFDList *fd_list,
+ GVariant *arg_handle,
+ guint arg_offset,
+ guint arg_width,
+ guint arg_height,
+ guint arg_stride,
+ guint arg_pixman_format,
+ TestDBusConsoleRegister *test)
+{
+ int fd = -1;
+ gint32 handle = g_variant_get_handle(arg_handle);
+ g_autoptr(GError) error = NULL;
+ void *addr = NULL;
+ size_t len = arg_height * arg_stride;
+
+ g_assert_cmpuint(g_unix_fd_list_get_length(fd_list), ==, 1);
+ fd = g_unix_fd_list_get(fd_list, handle, &error);
+ g_assert_no_error(error);
+
+ addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, arg_offset);
+ g_assert_no_errno(addr == MAP_FAILED ? -1 : 0);
+ g_assert_no_errno(munmap(addr, len));
+
g_main_loop_quit(test->loop);
+ close(fd);
return DBUS_METHOD_INVOCATION_HANDLED;
}
+#endif
static void
-test_dbus_console_setup_listener(TestDBusConsoleRegister *test)
+test_dbus_console_setup_listener(TestDBusConsoleRegister *test, bool with_map)
{
g_autoptr(GDBusObjectSkeleton) listener = NULL;
g_autoptr(QemuDBusDisplay1ListenerSkeleton) iface = NULL;
@@ -114,6 +156,25 @@ test_dbus_console_setup_listener(TestDBusConsoleRegister *test)
NULL);
g_dbus_object_skeleton_add_interface(listener,
G_DBUS_INTERFACE_SKELETON(iface));
+ if (with_map) {
+#ifdef WIN32
+ g_test_skip("map test lacking on win32");
+ return;
+#else
+ g_autoptr(QemuDBusDisplay1ListenerUnixMapSkeleton) iface_map =
+ QEMU_DBUS_DISPLAY1_LISTENER_UNIX_MAP_SKELETON(
+ qemu_dbus_display1_listener_unix_map_skeleton_new());
+
+ g_object_connect(iface_map,
+ "signal::handle-scanout-map", listener_handle_scanout_map, test,
+ NULL);
+ g_dbus_object_skeleton_add_interface(listener,
+ G_DBUS_INTERFACE_SKELETON(iface_map));
+ g_object_set(iface, "interfaces",
+ (const gchar *[]) { "org.qemu.Display1.Listener.Unix.Map", NULL },
+ NULL);
+#endif
+ }
g_dbus_object_manager_server_export(test->server, listener);
g_dbus_object_manager_server_set_connection(test->server,
test->listener_conn);
@@ -145,7 +206,7 @@ test_dbus_console_registered(GObject *source_object,
g_assert_no_error(err);
test->listener_conn = g_thread_join(test->thread);
- test_dbus_console_setup_listener(test);
+ test_dbus_console_setup_listener(test, test->with_map);
}
static gpointer
@@ -155,7 +216,7 @@ test_dbus_p2p_server_setup_thread(gpointer data)
}
static void
-test_dbus_display_console(void)
+test_dbus_display_console(const void* data)
{
g_autoptr(GError) err = NULL;
g_autoptr(GDBusConnection) conn = NULL;
@@ -163,7 +224,7 @@ test_dbus_display_console(void)
g_autoptr(GMainLoop) loop = NULL;
QTestState *qts = NULL;
int pair[2];
- TestDBusConsoleRegister test = { 0, };
+ TestDBusConsoleRegister test = { 0, .with_map = GPOINTER_TO_INT(data) };
#ifdef WIN32
WSAPROTOCOL_INFOW info;
g_autoptr(GVariant) listener = NULL;
@@ -299,7 +360,8 @@ main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
qtest_add_func("/dbus-display/vm", test_dbus_display_vm);
- qtest_add_func("/dbus-display/console", test_dbus_display_console);
+ qtest_add_data_func("/dbus-display/console", GINT_TO_POINTER(false), test_dbus_display_console);
+ qtest_add_data_func("/dbus-display/console/map", GINT_TO_POINTER(true), test_dbus_display_console);
qtest_add_func("/dbus-display/keyboard", test_dbus_display_keyboard);
return g_test_run();
diff --git a/tests/qtest/device-introspect-test.c b/tests/qtest/device-introspect-test.c
index 587da59..f84cec5 100644
--- a/tests/qtest/device-introspect-test.c
+++ b/tests/qtest/device-introspect-test.c
@@ -18,9 +18,9 @@
*/
#include "qemu/osdep.h"
-#include "qapi/qmp/qstring.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qstring.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
#include "libqtest.h"
const char common_args[] = "-nodefaults -machine none";
diff --git a/tests/qtest/device-plug-test.c b/tests/qtest/device-plug-test.c
index c6f3315..2707ee5 100644
--- a/tests/qtest/device-plug-test.c
+++ b/tests/qtest/device-plug-test.c
@@ -12,17 +12,8 @@
#include "qemu/osdep.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qstring.h"
-
-static void system_reset(QTestState *qtest)
-{
- QDict *resp;
-
- resp = qtest_qmp(qtest, "{'execute': 'system_reset'}");
- g_assert(qdict_haskey(resp, "return"));
- qobject_unref(resp);
-}
+#include "qobject/qdict.h"
+#include "qobject/qstring.h"
static void wait_device_deleted_event(QTestState *qtest, const char *id)
{
@@ -58,7 +49,7 @@ static void process_device_remove(QTestState *qtest, const char *id)
* handled, removing the device.
*/
qtest_qmp_device_del_send(qtest, id);
- system_reset(qtest);
+ qtest_system_reset_nowait(qtest);
wait_device_deleted_event(qtest, id);
}
diff --git a/tests/qtest/drive_del-test.c b/tests/qtest/drive_del-test.c
index 7b67a4b..30d9451 100644
--- a/tests/qtest/drive_del-test.c
+++ b/tests/qtest/drive_del-test.c
@@ -13,8 +13,8 @@
#include "qemu/osdep.h"
#include "libqtest.h"
#include "libqos/virtio.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
static const char *qvirtio_get_dev_type(void);
@@ -154,15 +154,10 @@ static void device_add(QTestState *qts)
static void device_del(QTestState *qts, bool and_reset)
{
- QDict *response;
-
qtest_qmp_device_del_send(qts, "dev0");
if (and_reset) {
- response = qtest_qmp(qts, "{'execute': 'system_reset' }");
- g_assert(response);
- g_assert(qdict_haskey(response, "return"));
- qobject_unref(response);
+ qtest_system_reset_nowait(qts);
}
qtest_qmp_eventwait(qts, "DEVICE_DELETED");
diff --git a/tests/qtest/emc141x-test.c b/tests/qtest/emc141x-test.c
index 8c86694..a24103e 100644
--- a/tests/qtest/emc141x-test.c
+++ b/tests/qtest/emc141x-test.c
@@ -10,7 +10,7 @@
#include "libqtest-single.h"
#include "libqos/qgraph.h"
#include "libqos/i2c.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "hw/sensor/emc141x_regs.h"
#define EMC1414_TEST_ID "emc1414-test"
diff --git a/tests/qtest/fdc-test.c b/tests/qtest/fdc-test.c
index 5e8fbda..1b37a8a 100644
--- a/tests/qtest/fdc-test.c
+++ b/tests/qtest/fdc-test.c
@@ -26,7 +26,7 @@
#include "libqtest-single.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#define DRIVE_FLOPPY_BLANK \
"-drive if=floppy,file=null-co://,file.read-zeroes=on,format=raw,size=1440k"
@@ -552,7 +552,7 @@ static bool qtest_check_clang_sanitizer(void)
#ifdef QEMU_SANITIZE_ADDRESS
return true;
#else
- g_test_skip("QEMU not configured using --enable-sanitizers");
+ g_test_skip("QEMU not configured using --enable-asan");
return false;
#endif
}
diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c
index 9b9c9f9..ca248a5 100644
--- a/tests/qtest/fuzz/fuzz.c
+++ b/tests/qtest/fuzz/fuzz.c
@@ -17,9 +17,9 @@
#include "qemu/cutils.h"
#include "qemu/datadir.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "sysemu/runstate.h"
+#include "system/system.h"
+#include "system/qtest.h"
+#include "system/runstate.h"
#include "qemu/main-loop.h"
#include "qemu/rcu.h"
#include "tests/qtest/libqtest.h"
@@ -41,6 +41,7 @@ static FuzzTargetList *fuzz_target_list;
static FuzzTarget *fuzz_target;
static QTestState *fuzz_qts;
+int (*qemu_main)(void);
void flush_events(QTestState *s)
diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c
index d107a49..f12080e 100644
--- a/tests/qtest/fuzz/generic_fuzz.c
+++ b/tests/qtest/fuzz/generic_fuzz.c
@@ -20,8 +20,8 @@
#include "tests/qtest/libqos/pci-pc.h"
#include "fuzz.h"
#include "string.h"
-#include "exec/memory.h"
-#include "exec/ramblock.h"
+#include "system/memory.h"
+#include "system/ramblock.h"
#include "hw/qdev-core.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_device.h"
@@ -572,7 +572,6 @@ static void op_add_dma_pattern(QTestState *s,
pattern p = {a.index, a.stride, len - sizeof(a), data + sizeof(a)};
p.index = a.index % p.len;
g_array_append_val(dma_patterns, p);
- return;
}
static void op_clear_dma_patterns(QTestState *s,
diff --git a/tests/qtest/fuzz/qos_fuzz.c b/tests/qtest/fuzz/qos_fuzz.c
index d3839bf..9afe8bf 100644
--- a/tests/qtest/fuzz/qos_fuzz.c
+++ b/tests/qtest/fuzz/qos_fuzz.c
@@ -19,7 +19,7 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qapi/error.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "qemu/main-loop.h"
#include "tests/qtest/libqtest.h"
diff --git a/tests/qtest/fuzz/qtest_wrappers.c b/tests/qtest/fuzz/qtest_wrappers.c
index 0580f8d..d7adcbe 100644
--- a/tests/qtest/fuzz/qtest_wrappers.c
+++ b/tests/qtest/fuzz/qtest_wrappers.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include "hw/core/cpu.h"
-#include "exec/ioport.h"
+#include "system/ioport.h"
#include "fuzz.h"
diff --git a/tests/qtest/fw_cfg-test.c b/tests/qtest/fw_cfg-test.c
index 5dc807b..e48b34a 100644
--- a/tests/qtest/fw_cfg-test.c
+++ b/tests/qtest/fw_cfg-test.c
@@ -243,12 +243,6 @@ int main(int argc, char **argv)
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);
diff --git a/tests/qtest/hd-geo-test.c b/tests/qtest/hd-geo-test.c
index d08bffa..41481a5 100644
--- a/tests/qtest/hd-geo-test.c
+++ b/tests/qtest/hd-geo-test.c
@@ -17,7 +17,7 @@
#include "qemu/osdep.h"
#include "qemu/bswap.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qlist.h"
#include "libqtest.h"
#include "libqos/fw_cfg.h"
#include "libqos/libqos.h"
@@ -900,7 +900,6 @@ static void test_override_hot_unplug(TestArgs *args, const char *devid,
QTestState *qts;
char *joined_args;
QFWCFG *fw_cfg;
- QDict *response;
int i;
joined_args = g_strjoinv(" ", args->argv);
@@ -913,13 +912,7 @@ static void test_override_hot_unplug(TestArgs *args, const char *devid,
/* unplug device an restart */
qtest_qmp_device_del_send(qts, devid);
- 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");
+ qtest_system_reset(qts);
read_bootdevices(fw_cfg, expected2);
@@ -1074,17 +1067,26 @@ int main(int argc, char **argv)
}
}
- 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()) {
+ if (qtest_has_machine("pc")) {
+ 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()) {
+ g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
+ "skipping hd-geo/override/* tests");
+ goto test_add_done;
+ }
+
+ if (qtest_has_machine("pc")) {
qtest_add_func("hd-geo/override/ide", test_override_ide);
if (qtest_has_device("lsi53c895a")) {
qtest_add_func("hd-geo/override/scsi", test_override_scsi);
@@ -1104,30 +1106,26 @@ int main(int argc, char **argv)
qtest_add_func("hd-geo/override/virtio_blk",
test_override_virtio_blk);
}
+ }
- if (qtest_has_machine("q35")) {
- qtest_add_func("hd-geo/override/sata", test_override_sata);
- qtest_add_func("hd-geo/override/zero_chs_q35",
- test_override_zero_chs_q35);
- if (qtest_has_device("lsi53c895a")) {
- qtest_add_func("hd-geo/override/scsi_q35",
- test_override_scsi_q35);
- }
- if (qtest_has_device("virtio-scsi-pci")) {
- qtest_add_func("hd-geo/override/scsi_hot_unplug_q35",
- test_override_scsi_hot_unplug_q35);
- }
- if (qtest_has_device("virtio-blk-pci")) {
- qtest_add_func("hd-geo/override/virtio_hot_unplug_q35",
- test_override_virtio_hot_unplug_q35);
- qtest_add_func("hd-geo/override/virtio_blk_q35",
- test_override_virtio_blk_q35);
- }
-
+ if (qtest_has_machine("q35")) {
+ qtest_add_func("hd-geo/override/sata", test_override_sata);
+ qtest_add_func("hd-geo/override/zero_chs_q35",
+ test_override_zero_chs_q35);
+ if (qtest_has_device("lsi53c895a")) {
+ qtest_add_func("hd-geo/override/scsi_q35",
+ test_override_scsi_q35);
+ }
+ if (qtest_has_device("virtio-scsi-pci")) {
+ qtest_add_func("hd-geo/override/scsi_hot_unplug_q35",
+ test_override_scsi_hot_unplug_q35);
+ }
+ if (qtest_has_device("virtio-blk-pci")) {
+ qtest_add_func("hd-geo/override/virtio_hot_unplug_q35",
+ test_override_virtio_hot_unplug_q35);
+ qtest_add_func("hd-geo/override/virtio_blk_q35",
+ test_override_virtio_blk_q35);
}
- } else {
- g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
- "skipping hd-geo/override/* tests");
}
test_add_done:
diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c
index 90ba6b2..ceee444 100644
--- a/tests/qtest/ide-test.c
+++ b/tests/qtest/ide-test.c
@@ -29,7 +29,7 @@
#include "libqos/libqos.h"
#include "libqos/pci-pc.h"
#include "libqos/malloc-pc.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qemu/bswap.h"
#include "hw/pci/pci_ids.h"
#include "hw/pci/pci_regs.h"
diff --git a/tests/qtest/intel-iommu-test.c b/tests/qtest/intel-iommu-test.c
new file mode 100644
index 0000000..c521b37
--- /dev/null
+++ b/tests/qtest/intel-iommu-test.c
@@ -0,0 +1,64 @@
+/*
+ * QTest testcase for intel-iommu
+ *
+ * Copyright (c) 2024 Intel, Inc.
+ *
+ * Author: Zhenzhong Duan <zhenzhong.duan@intel.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "hw/i386/intel_iommu_internal.h"
+
+#define CAP_STAGE_1_FIXED1 (VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND | \
+ VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS)
+#define ECAP_STAGE_1_FIXED1 (VTD_ECAP_QI | VTD_ECAP_IR | VTD_ECAP_IRO | \
+ VTD_ECAP_MHMV | VTD_ECAP_SMTS | VTD_ECAP_FLTS)
+
+static inline uint64_t vtd_reg_readq(QTestState *s, uint64_t offset)
+{
+ return qtest_readq(s, Q35_HOST_BRIDGE_IOMMU_ADDR + offset);
+}
+
+static void test_intel_iommu_stage_1(void)
+{
+ uint8_t init_csr[DMAR_REG_SIZE]; /* register values */
+ uint8_t post_reset_csr[DMAR_REG_SIZE]; /* register values */
+ uint64_t cap, ecap, tmp;
+ QTestState *s;
+
+ s = qtest_init("-M q35 -device intel-iommu,x-scalable-mode=on,x-flts=on");
+
+ cap = vtd_reg_readq(s, DMAR_CAP_REG);
+ g_assert((cap & CAP_STAGE_1_FIXED1) == CAP_STAGE_1_FIXED1);
+
+ tmp = cap & VTD_CAP_SAGAW_MASK;
+ g_assert(tmp == (VTD_CAP_SAGAW_39bit | VTD_CAP_SAGAW_48bit));
+
+ tmp = VTD_MGAW_FROM_CAP(cap);
+ g_assert(tmp == VTD_HOST_AW_48BIT - 1);
+
+ ecap = vtd_reg_readq(s, DMAR_ECAP_REG);
+ g_assert((ecap & ECAP_STAGE_1_FIXED1) == ECAP_STAGE_1_FIXED1);
+
+ qtest_memread(s, Q35_HOST_BRIDGE_IOMMU_ADDR, init_csr, DMAR_REG_SIZE);
+
+ qobject_unref(qtest_qmp(s, "{ 'execute': 'system_reset' }"));
+ qtest_qmp_eventwait(s, "RESET");
+
+ qtest_memread(s, Q35_HOST_BRIDGE_IOMMU_ADDR, post_reset_csr, DMAR_REG_SIZE);
+ /* Ensure registers are consistent after hard reset */
+ g_assert(!memcmp(init_csr, post_reset_csr, DMAR_REG_SIZE));
+
+ qtest_quit(s);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ qtest_add_func("/q35/intel-iommu/stage-1", test_intel_iommu_stage_1);
+
+ return g_test_run();
+}
diff --git a/tests/qtest/ipmi-bt-test.c b/tests/qtest/ipmi-bt-test.c
index 383239b..637732f 100644
--- a/tests/qtest/ipmi-bt-test.c
+++ b/tests/qtest/ipmi-bt-test.c
@@ -251,7 +251,7 @@ static void emu_msg_handler(void)
msg[msg_len++] = 0xa0;
write_emu_msg(msg, msg_len);
} else {
- g_assert(0);
+ g_assert_not_reached();
}
}
@@ -411,7 +411,7 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
global_qtest = qtest_initf(
- " -chardev socket,id=ipmi0,host=127.0.0.1,port=%d,reconnect=10"
+ " -chardev socket,id=ipmi0,host=127.0.0.1,port=%d,reconnect-ms=10000"
" -device ipmi-bmc-extern,chardev=ipmi0,id=bmc0"
" -device isa-ipmi-bt,bmc=bmc0", emu_port);
qtest_irq_intercept_in(global_qtest, "ioapic");
diff --git a/tests/qtest/ipmi-kcs-test.c b/tests/qtest/ipmi-kcs-test.c
index afc24dd..3186c6a 100644
--- a/tests/qtest/ipmi-kcs-test.c
+++ b/tests/qtest/ipmi-kcs-test.c
@@ -145,7 +145,7 @@ static void kcs_cmd(uint8_t *cmd, unsigned int cmd_len,
break;
default:
- g_assert(0);
+ g_assert_not_reached();
}
*rsp_len = j;
}
@@ -184,7 +184,7 @@ static void kcs_abort(uint8_t *cmd, unsigned int cmd_len,
break;
default:
- g_assert(0);
+ g_assert_not_reached();
}
/* Start the abort here */
diff --git a/tests/qtest/isl_pmbus_vr-test.c b/tests/qtest/isl_pmbus_vr-test.c
index 5553ea4..1ff840c 100644
--- a/tests/qtest/isl_pmbus_vr-test.c
+++ b/tests/qtest/isl_pmbus_vr-test.c
@@ -21,8 +21,8 @@
#include "libqtest-single.h"
#include "libqos/qgraph.h"
#include "libqos/i2c.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qnum.h"
+#include "qobject/qdict.h"
+#include "qobject/qnum.h"
#include "qemu/bitops.h"
#define TEST_ID "isl_pmbus_vr-test"
diff --git a/tests/qtest/libqmp.c b/tests/qtest/libqmp.c
index a89cab0..16fe546 100644
--- a/tests/qtest/libqmp.c
+++ b/tests/qtest/libqmp.c
@@ -25,8 +25,8 @@
#include "qemu/cutils.h"
#include "qemu/sockets.h"
#include "qapi/error.h"
-#include "qapi/qmp/json-parser.h"
-#include "qapi/qmp/qjson.h"
+#include "qobject/json-parser.h"
+#include "qobject/qjson.h"
#define SOCKET_MAX_FDS 16
diff --git a/tests/qtest/libqmp.h b/tests/qtest/libqmp.h
index 3445b75..4a931c9 100644
--- a/tests/qtest/libqmp.h
+++ b/tests/qtest/libqmp.h
@@ -18,7 +18,7 @@
#ifndef LIBQMP_H
#define LIBQMP_H
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
QDict *qmp_fd_receive(int fd);
#ifndef _WIN32
diff --git a/tests/qtest/libqos/arm-imx25-pdk-machine.c b/tests/qtest/libqos/arm-imx25-pdk-machine.c
index 8fe128f..2d8b754 100644
--- a/tests/qtest/libqos/arm-imx25-pdk-machine.c
+++ b/tests/qtest/libqos/arm-imx25-pdk-machine.c
@@ -23,6 +23,7 @@
#include "libqos-malloc.h"
#include "qgraph.h"
#include "i2c.h"
+#include "hw/i2c/imx_i2c.h"
#define ARM_PAGE_SIZE 4096
#define IMX25_PDK_RAM_START 0x80000000
@@ -50,7 +51,7 @@ static void *imx25_pdk_get_driver(void *object, const char *interface)
static QOSGraphObject *imx25_pdk_get_device(void *obj, const char *device)
{
QIMX25PDKMachine *machine = obj;
- if (!g_strcmp0(device, "imx.i2c")) {
+ if (!g_strcmp0(device, TYPE_IMX_I2C)) {
return &machine->i2c_1.obj;
}
@@ -86,7 +87,7 @@ static void imx25_pdk_register_nodes(void)
.extra_device_opts = "bus=i2c-bus.0"
};
qos_node_create_machine("arm/imx25-pdk", qos_create_machine_arm_imx25_pdk);
- qos_node_contains("arm/imx25-pdk", "imx.i2c", &edge, NULL);
+ qos_node_contains("arm/imx25-pdk", TYPE_IMX_I2C, &edge, NULL);
}
libqos_init(imx25_pdk_register_nodes);
diff --git a/tests/qtest/libqos/arm-n800-machine.c b/tests/qtest/libqos/arm-n800-machine.c
deleted file mode 100644
index 4e5afe0..0000000
--- a/tests/qtest/libqos/arm-n800-machine.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * libqos driver framework
- *
- * Copyright (c) 2019 Red Hat, Inc.
- *
- * Author: Paolo Bonzini <pbonzini@redhat.com>
- *
- * 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.1 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 "../libqtest.h"
-#include "libqos-malloc.h"
-#include "qgraph.h"
-#include "i2c.h"
-
-#define ARM_PAGE_SIZE 4096
-#define N800_RAM_START 0x80000000
-#define N800_RAM_END 0x88000000
-
-typedef struct QN800Machine QN800Machine;
-
-struct QN800Machine {
- QOSGraphObject obj;
- QGuestAllocator alloc;
- OMAPI2C i2c_1;
-};
-
-static void *n800_get_driver(void *object, const char *interface)
-{
- QN800Machine *machine = object;
- if (!g_strcmp0(interface, "memory")) {
- return &machine->alloc;
- }
-
- fprintf(stderr, "%s not present in arm/n800\n", interface);
- g_assert_not_reached();
-}
-
-static QOSGraphObject *n800_get_device(void *obj, const char *device)
-{
- QN800Machine *machine = obj;
- if (!g_strcmp0(device, "omap_i2c")) {
- return &machine->i2c_1.obj;
- }
-
- fprintf(stderr, "%s not present in arm/n800\n", device);
- g_assert_not_reached();
-}
-
-static void n800_destructor(QOSGraphObject *obj)
-{
- QN800Machine *machine = (QN800Machine *) obj;
- alloc_destroy(&machine->alloc);
-}
-
-static void *qos_create_machine_arm_n800(QTestState *qts)
-{
- QN800Machine *machine = g_new0(QN800Machine, 1);
-
- alloc_init(&machine->alloc, 0,
- N800_RAM_START,
- N800_RAM_END,
- ARM_PAGE_SIZE);
- machine->obj.get_device = n800_get_device;
- machine->obj.get_driver = n800_get_driver;
- machine->obj.destructor = n800_destructor;
-
- omap_i2c_init(&machine->i2c_1, qts, 0x48070000);
- return &machine->obj;
-}
-
-static void n800_register_nodes(void)
-{
- QOSGraphEdgeOptions edge = {
- .extra_device_opts = "bus=i2c-bus.0"
- };
- qos_node_create_machine("arm/n800", qos_create_machine_arm_n800);
- qos_node_contains("arm/n800", "omap_i2c", &edge, NULL);
-}
-
-libqos_init(n800_register_nodes);
diff --git a/tests/qtest/libqos/fw_cfg.c b/tests/qtest/libqos/fw_cfg.c
index 89f053c..0ab3959 100644
--- a/tests/qtest/libqos/fw_cfg.c
+++ b/tests/qtest/libqos/fw_cfg.c
@@ -14,6 +14,8 @@
#include "qemu/osdep.h"
#include "fw_cfg.h"
+#include "malloc-pc.h"
+#include "libqos-malloc.h"
#include "../libqtest.h"
#include "qemu/bswap.h"
#include "hw/nvram/fw_cfg.h"
@@ -60,6 +62,91 @@ static void mm_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
qtest_writew(fw_cfg->qts, fw_cfg->base, key);
}
+static void qfw_cfg_dma_transfer(QFWCFG *fw_cfg, QOSState *qs, void *address,
+ uint32_t length, uint32_t control)
+{
+ FWCfgDmaAccess access;
+ uint32_t addr;
+ uint64_t guest_access_addr;
+ uint64_t gaddr;
+
+ /* create a data buffer in guest memory */
+ gaddr = guest_alloc(&qs->alloc, length);
+
+ if (control & FW_CFG_DMA_CTL_WRITE) {
+ qtest_bufwrite(fw_cfg->qts, gaddr, address, length);
+ }
+ access.address = cpu_to_be64(gaddr);
+ access.length = cpu_to_be32(length);
+ access.control = cpu_to_be32(control);
+
+ /* now create a separate buffer in guest memory for 'access' */
+ guest_access_addr = guest_alloc(&qs->alloc, sizeof(access));
+ qtest_bufwrite(fw_cfg->qts, guest_access_addr, &access, sizeof(access));
+
+ /* write lower 32 bits of address */
+ addr = cpu_to_be32((uint32_t)(uintptr_t)guest_access_addr);
+ qtest_outl(fw_cfg->qts, fw_cfg->base + 8, addr);
+
+ /* write upper 32 bits of address */
+ addr = cpu_to_be32((uint32_t)(uintptr_t)(guest_access_addr >> 32));
+ qtest_outl(fw_cfg->qts, fw_cfg->base + 4, addr);
+
+ g_assert(!(be32_to_cpu(access.control) & FW_CFG_DMA_CTL_ERROR));
+
+ if (control & FW_CFG_DMA_CTL_READ) {
+ qtest_bufread(fw_cfg->qts, gaddr, address, length);
+ }
+
+ guest_free(&qs->alloc, guest_access_addr);
+ guest_free(&qs->alloc, gaddr);
+}
+
+static void qfw_cfg_write_entry(QFWCFG *fw_cfg, QOSState *qs, uint16_t key,
+ void *buf, uint32_t len)
+{
+ qfw_cfg_select(fw_cfg, key);
+ qfw_cfg_dma_transfer(fw_cfg, qs, buf, len, FW_CFG_DMA_CTL_WRITE);
+}
+
+static void qfw_cfg_read_entry(QFWCFG *fw_cfg, QOSState *qs, uint16_t key,
+ void *buf, uint32_t len)
+{
+ qfw_cfg_select(fw_cfg, key);
+ qfw_cfg_dma_transfer(fw_cfg, qs, buf, len, FW_CFG_DMA_CTL_READ);
+}
+
+static bool find_pdir_entry(QFWCFG *fw_cfg, const char *filename,
+ uint16_t *sel, uint32_t *size)
+{
+ g_autofree unsigned char *filesbuf = NULL;
+ uint32_t count;
+ size_t dsize;
+ FWCfgFile *pdir_entry;
+ uint32_t i;
+ bool found = false;
+
+ *size = 0;
+ *sel = 0;
+
+ qfw_cfg_get(fw_cfg, FW_CFG_FILE_DIR, &count, sizeof(count));
+ count = be32_to_cpu(count);
+ dsize = sizeof(uint32_t) + count * sizeof(struct fw_cfg_file);
+ filesbuf = g_malloc(dsize);
+ qfw_cfg_get(fw_cfg, FW_CFG_FILE_DIR, filesbuf, dsize);
+ pdir_entry = (FWCfgFile *)(filesbuf + sizeof(uint32_t));
+ for (i = 0; i < count; ++i, ++pdir_entry) {
+ if (!strcmp(pdir_entry->name, filename)) {
+ *size = be32_to_cpu(pdir_entry->size);
+ *sel = be16_to_cpu(pdir_entry->select);
+ found = true;
+ break;
+ }
+ }
+
+ return found;
+}
+
/*
* The caller need check the return value. When the return value is
* nonzero, it means that some bytes have been transferred.
@@ -73,37 +160,106 @@ static void mm_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
* populated, it has received only a starting slice of the fw_cfg file.
*/
size_t qfw_cfg_get_file(QFWCFG *fw_cfg, const char *filename,
- void *data, size_t buflen)
+ void *data, size_t buflen)
{
- uint32_t count;
- uint32_t i;
- unsigned char *filesbuf = NULL;
- size_t dsize;
- FWCfgFile *pdir_entry;
size_t filesize = 0;
+ uint32_t len;
+ uint16_t sel;
- qfw_cfg_get(fw_cfg, FW_CFG_FILE_DIR, &count, sizeof(count));
- count = be32_to_cpu(count);
- dsize = sizeof(uint32_t) + count * sizeof(struct fw_cfg_file);
- filesbuf = g_malloc(dsize);
- qfw_cfg_get(fw_cfg, FW_CFG_FILE_DIR, filesbuf, dsize);
- pdir_entry = (FWCfgFile *)(filesbuf + sizeof(uint32_t));
- for (i = 0; i < count; ++i, ++pdir_entry) {
- if (!strcmp(pdir_entry->name, filename)) {
- uint32_t len = be32_to_cpu(pdir_entry->size);
- uint16_t sel = be16_to_cpu(pdir_entry->select);
- filesize = len;
- if (len > buflen) {
- len = buflen;
- }
- qfw_cfg_get(fw_cfg, sel, data, len);
- break;
+ if (find_pdir_entry(fw_cfg, filename, &sel, &len)) {
+ filesize = len;
+ if (len > buflen) {
+ len = buflen;
}
+ qfw_cfg_get(fw_cfg, sel, data, len);
}
- g_free(filesbuf);
+
return filesize;
}
+/*
+ * The caller need check the return value. When the return value is
+ * nonzero, it means that some bytes have been transferred.
+ *
+ * If the fw_cfg file in question is smaller than the allocated & passed-in
+ * buffer, then the first len bytes were read.
+ *
+ * If the fw_cfg file in question is larger than the passed-in
+ * buffer, then the return value explains how much was actually read.
+ *
+ * It is illegal to call this function if fw_cfg does not support DMA
+ * interface. The caller should ensure that DMA is supported before
+ * calling this function.
+ *
+ * Passed QOSState pointer qs must be initialized. qs->alloc must also be
+ * properly initialized.
+ */
+size_t qfw_cfg_read_file(QFWCFG *fw_cfg, QOSState *qs, const char *filename,
+ void *data, size_t buflen)
+{
+ uint32_t len = 0;
+ uint16_t sel;
+ uint32_t id;
+
+ g_assert(qs);
+ g_assert(filename);
+ g_assert(data);
+ g_assert(buflen);
+ /* check if DMA is supported since we use DMA for read */
+ id = qfw_cfg_get_u32(fw_cfg, FW_CFG_ID);
+ g_assert(id & FW_CFG_VERSION_DMA);
+
+ if (find_pdir_entry(fw_cfg, filename, &sel, &len)) {
+ if (len > buflen) {
+ len = buflen;
+ }
+ qfw_cfg_read_entry(fw_cfg, qs, sel, data, len);
+ }
+
+ return len;
+}
+
+/*
+ * The caller need check the return value. When the return value is
+ * nonzero, it means that some bytes have been transferred.
+ *
+ * If the fw_cfg file in question is smaller than the allocated & passed-in
+ * buffer, then the buffer has been partially written.
+ *
+ * If the fw_cfg file in question is larger than the passed-in
+ * buffer, then the return value explains how much was actually written.
+ *
+ * It is illegal to call this function if fw_cfg does not support DMA
+ * interface. The caller should ensure that DMA is supported before
+ * calling this function.
+ *
+ * Passed QOSState pointer qs must be initialized. qs->alloc must also be
+ * properly initialized.
+ */
+size_t qfw_cfg_write_file(QFWCFG *fw_cfg, QOSState *qs, const char *filename,
+ void *data, size_t buflen)
+{
+ uint32_t len = 0;
+ uint16_t sel;
+ uint32_t id;
+
+ g_assert(qs);
+ g_assert(filename);
+ g_assert(data);
+ g_assert(buflen);
+ /* write operation is only valid if DMA is supported */
+ id = qfw_cfg_get_u32(fw_cfg, FW_CFG_ID);
+ g_assert(id & FW_CFG_VERSION_DMA);
+
+ if (find_pdir_entry(fw_cfg, filename, &sel, &len)) {
+ if (len > buflen) {
+ len = buflen;
+ }
+ qfw_cfg_write_entry(fw_cfg, qs, sel, data, len);
+ }
+ return len;
+}
+
static void mm_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len)
{
uint8_t *ptr = data;
diff --git a/tests/qtest/libqos/fw_cfg.h b/tests/qtest/libqos/fw_cfg.h
index b0456a1..6d6ff09 100644
--- a/tests/qtest/libqos/fw_cfg.h
+++ b/tests/qtest/libqos/fw_cfg.h
@@ -14,6 +14,7 @@
#define LIBQOS_FW_CFG_H
#include "../libqtest.h"
+#include "libqos.h"
typedef struct QFWCFG QFWCFG;
@@ -33,7 +34,10 @@ uint32_t qfw_cfg_get_u32(QFWCFG *fw_cfg, uint16_t key);
uint64_t qfw_cfg_get_u64(QFWCFG *fw_cfg, uint16_t key);
size_t qfw_cfg_get_file(QFWCFG *fw_cfg, const char *filename,
void *data, size_t buflen);
-
+size_t qfw_cfg_write_file(QFWCFG *fw_cfg, QOSState *qs, const char *filename,
+ void *data, size_t buflen);
+size_t qfw_cfg_read_file(QFWCFG *fw_cfg, QOSState *qs, const char *filename,
+ void *data, size_t buflen);
QFWCFG *mm_fw_cfg_init(QTestState *qts, uint64_t base);
void mm_fw_cfg_uninit(QFWCFG *fw_cfg);
QFWCFG *io_fw_cfg_init(QTestState *qts, uint16_t base);
diff --git a/tests/qtest/libqos/generic-pcihost.c b/tests/qtest/libqos/generic-pcihost.c
index 3124b0e..4bbeb5f 100644
--- a/tests/qtest/libqos/generic-pcihost.c
+++ b/tests/qtest/libqos/generic-pcihost.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include "../libqtest.h"
#include "generic-pcihost.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "hw/pci/pci_regs.h"
#include "qemu/host-utils.h"
diff --git a/tests/qtest/libqos/i2c-imx.c b/tests/qtest/libqos/i2c-imx.c
index 710cb92..6d868e4 100644
--- a/tests/qtest/libqos/i2c-imx.c
+++ b/tests/qtest/libqos/i2c-imx.c
@@ -209,8 +209,8 @@ void imx_i2c_init(IMXI2C *s, QTestState *qts, uint64_t addr)
static void imx_i2c_register_nodes(void)
{
- qos_node_create_driver("imx.i2c", NULL);
- qos_node_produces("imx.i2c", "i2c-bus");
+ qos_node_create_driver(TYPE_IMX_I2C, NULL);
+ qos_node_produces(TYPE_IMX_I2C, "i2c-bus");
}
libqos_init(imx_i2c_register_nodes);
diff --git a/tests/qtest/libqos/igb.c b/tests/qtest/libqos/igb.c
index f40c4ec..ab3ef6f 100644
--- a/tests/qtest/libqos/igb.c
+++ b/tests/qtest/libqos/igb.c
@@ -104,10 +104,10 @@ static void igb_pci_start_hw(QOSGraphObject *obj)
e1000e_macreg_write(&d->e1000e, E1000_RDT(0), 0);
e1000e_macreg_write(&d->e1000e, E1000_RDH(0), 0);
e1000e_macreg_write(&d->e1000e, E1000_RA,
- le32_to_cpu(*(uint32_t *)address));
+ ldl_le_p(address));
e1000e_macreg_write(&d->e1000e, E1000_RA + 4,
E1000_RAH_AV | E1000_RAH_POOL_1 |
- le16_to_cpu(*(uint16_t *)(address + 4)));
+ lduw_le_p(address + 4));
/* Set supported receive descriptor mode */
e1000e_macreg_write(&d->e1000e,
diff --git a/tests/qtest/libqos/libqos-malloc.c b/tests/qtest/libqos/libqos-malloc.c
index d756697..c90f8f0 100644
--- a/tests/qtest/libqos/libqos-malloc.c
+++ b/tests/qtest/libqos/libqos-malloc.c
@@ -342,5 +342,4 @@ void migrate_allocator(QGuestAllocator *src,
QTAILQ_INIT(src->free);
node = mlist_new(src->start, src->end - src->start);
QTAILQ_INSERT_HEAD(src->free, node, MLIST_ENTNAME);
- return;
}
diff --git a/tests/qtest/libqos/libqos.c b/tests/qtest/libqos/libqos.c
index 5c0fa1f..9b49d0d 100644
--- a/tests/qtest/libqos/libqos.c
+++ b/tests/qtest/libqos/libqos.c
@@ -2,7 +2,7 @@
#include "../libqtest.h"
#include "libqos.h"
#include "pci.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
/*** Test Setup & Teardown ***/
@@ -117,13 +117,14 @@ void migrate(QOSState *from, QOSState *to, const char *uri)
g_assert(qdict_haskey(sub, "status"));
st = qdict_get_str(sub, "status");
- /* "setup", "active", "completed", "failed", "cancelled" */
+ /* "setup", "active", "device", "completed", "failed", "cancelled" */
if (strcmp(st, "completed") == 0) {
qobject_unref(rsp);
break;
}
if ((strcmp(st, "setup") == 0) || (strcmp(st, "active") == 0)
+ || (strcmp(st, "device") == 0)
|| (strcmp(st, "wait-unplug") == 0)) {
qobject_unref(rsp);
g_usleep(5000);
diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build
index 1b2b2db..1ddaf7b 100644
--- a/tests/qtest/libqos/meson.build
+++ b/tests/qtest/libqos/meson.build
@@ -32,7 +32,6 @@ libqos_srcs = files(
'i2c-omap.c',
'igb.c',
'sdhci.c',
- 'tpci200.c',
'virtio.c',
'virtio-balloon.c',
'virtio-blk.c',
@@ -52,7 +51,6 @@ libqos_srcs = files(
# qgraph machines:
'aarch64-xlnx-zcu102-machine.c',
'arm-imx25-pdk-machine.c',
- 'arm-n800-machine.c',
'arm-raspi2-machine.c',
'arm-sabrelite-machine.c',
'arm-smdkc210-machine.c',
@@ -68,6 +66,13 @@ if have_virtfs
libqos_srcs += files('virtio-9p.c', 'virtio-9p-client.c')
endif
+if config_all_devices.has_key('CONFIG_RISCV_IOMMU')
+ libqos_srcs += files('riscv-iommu.c')
+endif
+if config_all_devices.has_key('CONFIG_TPCI200')
+ libqos_srcs += files('tpci200.c')
+endif
+
libqos = static_library('qos', libqos_srcs + genh,
build_by_default: false)
diff --git a/tests/qtest/libqos/pci-pc.c b/tests/qtest/libqos/pci-pc.c
index 9604628..147009f 100644
--- a/tests/qtest/libqos/pci-pc.c
+++ b/tests/qtest/libqos/pci-pc.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include "../libqtest.h"
#include "pci-pc.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "hw/pci/pci_regs.h"
#include "qemu/module.h"
diff --git a/tests/qtest/libqos/pci.c b/tests/qtest/libqos/pci.c
index b23d723..a59197b 100644
--- a/tests/qtest/libqos/pci.c
+++ b/tests/qtest/libqos/pci.c
@@ -328,8 +328,6 @@ bool qpci_msix_pending(QPCIDevice *dev, uint16_t entry)
g_assert(dev->msix_enabled);
pba_entry = qpci_io_readl(dev, dev->msix_pba_bar, dev->msix_pba_off + off);
- qpci_io_writel(dev, dev->msix_pba_bar, dev->msix_pba_off + off,
- pba_entry & ~(1 << bit_n));
return (pba_entry & (1 << bit_n)) != 0;
}
diff --git a/tests/qtest/libqos/qgraph.h b/tests/qtest/libqos/qgraph.h
index 1b5de02..81fbfdd 100644
--- a/tests/qtest/libqos/qgraph.h
+++ b/tests/qtest/libqos/qgraph.h
@@ -355,7 +355,7 @@ void qos_object_start_hw(QOSGraphObject *obj);
QOSGraphObject *qos_machine_new(QOSGraphNode *node, QTestState *qts);
/**
- * qos_machine_new(): instantiate a new driver node
+ * qos_driver_new(): instantiate a new driver node
* @node: A driver node to be instantiated
* @parent: A #QOSGraphObject to be consumed by the new driver node
* @alloc: An allocator to be used by the new driver node.
diff --git a/tests/qtest/libqos/qos_external.c b/tests/qtest/libqos/qos_external.c
index c6bb8bf..493ab74 100644
--- a/tests/qtest/libqos/qos_external.c
+++ b/tests/qtest/libqos/qos_external.c
@@ -19,11 +19,11 @@
#include "qemu/osdep.h"
#include <getopt.h>
#include "../libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qbool.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qdict.h"
+#include "qobject/qbool.h"
+#include "qobject/qstring.h"
#include "qemu/module.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qlist.h"
#include "libqos-malloc.h"
#include "qgraph.h"
#include "qgraph_internal.h"
diff --git a/tests/qtest/libqos/riscv-iommu.c b/tests/qtest/libqos/riscv-iommu.c
new file mode 100644
index 0000000..01e3b31
--- /dev/null
+++ b/tests/qtest/libqos/riscv-iommu.c
@@ -0,0 +1,76 @@
+/*
+ * libqos driver riscv-iommu-pci framework
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "../libqtest.h"
+#include "qemu/module.h"
+#include "qgraph.h"
+#include "pci.h"
+#include "riscv-iommu.h"
+
+static void *riscv_iommu_pci_get_driver(void *obj, const char *interface)
+{
+ QRISCVIOMMU *r_iommu_pci = obj;
+
+ if (!g_strcmp0(interface, "pci-device")) {
+ return &r_iommu_pci->dev;
+ }
+
+ fprintf(stderr, "%s not present in riscv_iommu_pci\n", interface);
+ g_assert_not_reached();
+}
+
+static void riscv_iommu_pci_start_hw(QOSGraphObject *obj)
+{
+ QRISCVIOMMU *pci = (QRISCVIOMMU *)obj;
+ qpci_device_enable(&pci->dev);
+}
+
+static void riscv_iommu_pci_destructor(QOSGraphObject *obj)
+{
+ QRISCVIOMMU *pci = (QRISCVIOMMU *)obj;
+ qpci_iounmap(&pci->dev, pci->reg_bar);
+}
+
+static void *riscv_iommu_pci_create(void *pci_bus, QGuestAllocator *alloc,
+ void *addr)
+{
+ QRISCVIOMMU *r_iommu_pci = g_new0(QRISCVIOMMU, 1);
+ QPCIBus *bus = pci_bus;
+
+ qpci_device_init(&r_iommu_pci->dev, bus, addr);
+ r_iommu_pci->reg_bar = qpci_iomap(&r_iommu_pci->dev, 0, NULL);
+
+ r_iommu_pci->obj.get_driver = riscv_iommu_pci_get_driver;
+ r_iommu_pci->obj.start_hw = riscv_iommu_pci_start_hw;
+ r_iommu_pci->obj.destructor = riscv_iommu_pci_destructor;
+ return &r_iommu_pci->obj;
+}
+
+static void riscv_iommu_pci_register_nodes(void)
+{
+ QPCIAddress addr = {
+ .vendor_id = RISCV_IOMMU_PCI_VENDOR_ID,
+ .device_id = RISCV_IOMMU_PCI_DEVICE_ID,
+ .devfn = QPCI_DEVFN(1, 0),
+ };
+
+ QOSGraphEdgeOptions opts = {
+ .extra_device_opts = "addr=01.0",
+ };
+
+ add_qpci_address(&opts, &addr);
+
+ qos_node_create_driver("riscv-iommu-pci", riscv_iommu_pci_create);
+ qos_node_produces("riscv-iommu-pci", "pci-device");
+ qos_node_consumes("riscv-iommu-pci", "pci-bus", &opts);
+}
+
+libqos_init(riscv_iommu_pci_register_nodes);
diff --git a/tests/qtest/libqos/riscv-iommu.h b/tests/qtest/libqos/riscv-iommu.h
new file mode 100644
index 0000000..318db13
--- /dev/null
+++ b/tests/qtest/libqos/riscv-iommu.h
@@ -0,0 +1,101 @@
+/*
+ * libqos driver riscv-iommu-pci framework
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef TESTS_LIBQOS_RISCV_IOMMU_H
+#define TESTS_LIBQOS_RISCV_IOMMU_H
+
+#include "qgraph.h"
+#include "pci.h"
+#include "qemu/bitops.h"
+
+#ifndef GENMASK_ULL
+#define GENMASK_ULL(h, l) (((~0ULL) >> (63 - (h) + (l))) << (l))
+#endif
+
+/*
+ * RISC-V IOMMU uses PCI_VENDOR_ID_REDHAT 0x1b36 and
+ * PCI_DEVICE_ID_REDHAT_RISCV_IOMMU 0x0014.
+ */
+#define RISCV_IOMMU_PCI_VENDOR_ID 0x1b36
+#define RISCV_IOMMU_PCI_DEVICE_ID 0x0014
+#define RISCV_IOMMU_PCI_DEVICE_CLASS 0x0806
+
+/* Common field positions */
+#define RISCV_IOMMU_QUEUE_ENABLE BIT(0)
+#define RISCV_IOMMU_QUEUE_INTR_ENABLE BIT(1)
+#define RISCV_IOMMU_QUEUE_MEM_FAULT BIT(8)
+#define RISCV_IOMMU_QUEUE_ACTIVE BIT(16)
+#define RISCV_IOMMU_QUEUE_BUSY BIT(17)
+
+#define RISCV_IOMMU_REG_CAP 0x0000
+#define RISCV_IOMMU_CAP_VERSION GENMASK_ULL(7, 0)
+
+#define RISCV_IOMMU_REG_DDTP 0x0010
+#define RISCV_IOMMU_DDTP_BUSY BIT_ULL(4)
+#define RISCV_IOMMU_DDTP_MODE GENMASK_ULL(3, 0)
+#define RISCV_IOMMU_DDTP_MODE_OFF 0
+
+#define RISCV_IOMMU_REG_CQCSR 0x0048
+#define RISCV_IOMMU_CQCSR_CQEN RISCV_IOMMU_QUEUE_ENABLE
+#define RISCV_IOMMU_CQCSR_CIE RISCV_IOMMU_QUEUE_INTR_ENABLE
+#define RISCV_IOMMU_CQCSR_CQON RISCV_IOMMU_QUEUE_ACTIVE
+#define RISCV_IOMMU_CQCSR_BUSY RISCV_IOMMU_QUEUE_BUSY
+
+#define RISCV_IOMMU_REG_FQCSR 0x004C
+#define RISCV_IOMMU_FQCSR_FQEN RISCV_IOMMU_QUEUE_ENABLE
+#define RISCV_IOMMU_FQCSR_FIE RISCV_IOMMU_QUEUE_INTR_ENABLE
+#define RISCV_IOMMU_FQCSR_FQON RISCV_IOMMU_QUEUE_ACTIVE
+#define RISCV_IOMMU_FQCSR_BUSY RISCV_IOMMU_QUEUE_BUSY
+
+#define RISCV_IOMMU_REG_PQCSR 0x0050
+#define RISCV_IOMMU_PQCSR_PQEN RISCV_IOMMU_QUEUE_ENABLE
+#define RISCV_IOMMU_PQCSR_PIE RISCV_IOMMU_QUEUE_INTR_ENABLE
+#define RISCV_IOMMU_PQCSR_PQON RISCV_IOMMU_QUEUE_ACTIVE
+#define RISCV_IOMMU_PQCSR_BUSY RISCV_IOMMU_QUEUE_BUSY
+
+#define RISCV_IOMMU_REG_IPSR 0x0054
+
+#define RISCV_IOMMU_REG_IVEC 0x02F8
+#define RISCV_IOMMU_REG_IVEC_CIV GENMASK_ULL(3, 0)
+#define RISCV_IOMMU_REG_IVEC_FIV GENMASK_ULL(7, 4)
+#define RISCV_IOMMU_REG_IVEC_PMIV GENMASK_ULL(11, 8)
+#define RISCV_IOMMU_REG_IVEC_PIV GENMASK_ULL(15, 12)
+
+#define RISCV_IOMMU_REG_CQB 0x0018
+#define RISCV_IOMMU_CQB_PPN_START 10
+#define RISCV_IOMMU_CQB_PPN_LEN 44
+#define RISCV_IOMMU_CQB_LOG2SZ_START 0
+#define RISCV_IOMMU_CQB_LOG2SZ_LEN 5
+
+#define RISCV_IOMMU_REG_CQT 0x0024
+
+#define RISCV_IOMMU_REG_FQB 0x0028
+#define RISCV_IOMMU_FQB_PPN_START 10
+#define RISCV_IOMMU_FQB_PPN_LEN 44
+#define RISCV_IOMMU_FQB_LOG2SZ_START 0
+#define RISCV_IOMMU_FQB_LOG2SZ_LEN 5
+
+#define RISCV_IOMMU_REG_FQT 0x0034
+
+#define RISCV_IOMMU_REG_PQB 0x0038
+#define RISCV_IOMMU_PQB_PPN_START 10
+#define RISCV_IOMMU_PQB_PPN_LEN 44
+#define RISCV_IOMMU_PQB_LOG2SZ_START 0
+#define RISCV_IOMMU_PQB_LOG2SZ_LEN 5
+
+#define RISCV_IOMMU_REG_PQT 0x0044
+
+typedef struct QRISCVIOMMU {
+ QOSGraphObject obj;
+ QPCIDevice dev;
+ QPCIBar reg_bar;
+} QRISCVIOMMU;
+
+#endif
diff --git a/tests/qtest/libqos/virtio-9p-client.c b/tests/qtest/libqos/virtio-9p-client.c
index b8adc8d..6ab4501 100644
--- a/tests/qtest/libqos/virtio-9p-client.c
+++ b/tests/qtest/libqos/virtio-9p-client.c
@@ -235,10 +235,11 @@ static const char *rmessage_name(uint8_t id)
id == P9_RMKDIR ? "RMKDIR" :
id == P9_RLCREATE ? "RLCREATE" :
id == P9_RSYMLINK ? "RSYMLINK" :
+ id == P9_RGETATTR ? "RGETATTR" :
id == P9_RLINK ? "RLINK" :
id == P9_RUNLINKAT ? "RUNLINKAT" :
id == P9_RFLUSH ? "RFLUSH" :
- id == P9_RREADDIR ? "READDIR" :
+ id == P9_RREADDIR ? "RREADDIR" :
"<unknown>";
}
@@ -556,6 +557,55 @@ void v9fs_rgetattr(P9Req *req, v9fs_attr *attr)
v9fs_req_free(req);
}
+/*
+ * size[4] Tsetattr tag[2] fid[4] valid[4] mode[4] uid[4] gid[4] size[8]
+ * atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]
+ */
+TSetAttrRes v9fs_tsetattr(TSetAttrOpt opt)
+{
+ P9Req *req;
+ uint32_t err;
+
+ g_assert(opt.client);
+
+ req = v9fs_req_init(
+ opt.client, 4/*fid*/ + 4/*valid*/ + 4/*mode*/ + 4/*uid*/ + 4/*gid*/ +
+ 8/*size*/ + 8/*atime_sec*/ + 8/*atime_nsec*/ + 8/*mtime_sec*/ +
+ 8/*mtime_nsec*/, P9_TSETATTR, opt.tag
+ );
+ v9fs_uint32_write(req, opt.fid);
+ v9fs_uint32_write(req, (uint32_t) opt.attr.valid);
+ v9fs_uint32_write(req, opt.attr.mode);
+ v9fs_uint32_write(req, opt.attr.uid);
+ v9fs_uint32_write(req, opt.attr.gid);
+ v9fs_uint64_write(req, opt.attr.size);
+ v9fs_uint64_write(req, opt.attr.atime_sec);
+ v9fs_uint64_write(req, opt.attr.atime_nsec);
+ v9fs_uint64_write(req, opt.attr.mtime_sec);
+ v9fs_uint64_write(req, opt.attr.mtime_nsec);
+ v9fs_req_send(req);
+
+ if (!opt.requestOnly) {
+ v9fs_req_wait_for_reply(req, NULL);
+ if (opt.expectErr) {
+ v9fs_rlerror(req, &err);
+ g_assert_cmpint(err, ==, opt.expectErr);
+ } else {
+ v9fs_rsetattr(req);
+ }
+ req = NULL; /* request was freed */
+ }
+
+ return (TSetAttrRes) { .req = req };
+}
+
+/* size[4] Rsetattr tag[2] */
+void v9fs_rsetattr(P9Req *req)
+{
+ v9fs_req_recv(req, P9_RSETATTR);
+ v9fs_req_free(req);
+}
+
/* size[4] Treaddir tag[2] fid[4] offset[8] count[4] */
TReadDirRes v9fs_treaddir(TReadDirOpt opt)
{
diff --git a/tests/qtest/libqos/virtio-9p-client.h b/tests/qtest/libqos/virtio-9p-client.h
index 78228eb..e3221a3 100644
--- a/tests/qtest/libqos/virtio-9p-client.h
+++ b/tests/qtest/libqos/virtio-9p-client.h
@@ -65,6 +65,16 @@ typedef struct v9fs_attr {
#define P9_GETATTR_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
#define P9_GETATTR_ALL 0x00003fffULL /* Mask for ALL fields */
+#define P9_SETATTR_MODE 0x00000001UL
+#define P9_SETATTR_UID 0x00000002UL
+#define P9_SETATTR_GID 0x00000004UL
+#define P9_SETATTR_SIZE 0x00000008UL
+#define P9_SETATTR_ATIME 0x00000010UL
+#define P9_SETATTR_MTIME 0x00000020UL
+#define P9_SETATTR_CTIME 0x00000040UL
+#define P9_SETATTR_ATIME_SET 0x00000080UL
+#define P9_SETATTR_MTIME_SET 0x00000100UL
+
struct V9fsDirent {
v9fs_qid qid;
uint64_t offset;
@@ -182,6 +192,28 @@ typedef struct TGetAttrRes {
P9Req *req;
} TGetAttrRes;
+/* options for 'Tsetattr' 9p request */
+typedef struct TSetAttrOpt {
+ /* 9P client being used (mandatory) */
+ QVirtio9P *client;
+ /* user supplied tag number being returned with response (optional) */
+ uint16_t tag;
+ /* file ID of file/dir whose attributes shall be modified (required) */
+ uint32_t fid;
+ /* new attribute values to be set by 9p server */
+ v9fs_attr attr;
+ /* only send Tsetattr request but not wait for a reply? (optional) */
+ bool requestOnly;
+ /* do we expect an Rlerror response, if yes which error code? (optional) */
+ uint32_t expectErr;
+} TSetAttrOpt;
+
+/* result of 'Tsetattr' 9p request */
+typedef struct TSetAttrRes {
+ /* if requestOnly was set: request object for further processing */
+ P9Req *req;
+} TSetAttrRes;
+
/* options for 'Treaddir' 9p request */
typedef struct TReadDirOpt {
/* 9P client being used (mandatory) */
@@ -470,6 +502,8 @@ TWalkRes v9fs_twalk(TWalkOpt opt);
void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid);
TGetAttrRes v9fs_tgetattr(TGetAttrOpt);
void v9fs_rgetattr(P9Req *req, v9fs_attr *attr);
+TSetAttrRes v9fs_tsetattr(TSetAttrOpt opt);
+void v9fs_rsetattr(P9Req *req);
TReadDirRes v9fs_treaddir(TReadDirOpt);
void v9fs_rreaddir(P9Req *req, uint32_t *count, uint32_t *nentries,
struct V9fsDirent **entries);
diff --git a/tests/qtest/libqos/virtio-pci-modern.c b/tests/qtest/libqos/virtio-pci-modern.c
index 18d1188..4e67fcb 100644
--- a/tests/qtest/libqos/virtio-pci-modern.c
+++ b/tests/qtest/libqos/virtio-pci-modern.c
@@ -173,13 +173,11 @@ static bool get_config_isr_status(QVirtioDevice *d)
static void wait_config_isr_status(QVirtioDevice *d, gint64 timeout_us)
{
- QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
gint64 start_time = g_get_monotonic_time();
- do {
+ while (!get_config_isr_status(d)) {
g_assert(g_get_monotonic_time() - start_time <= timeout_us);
- qtest_clock_step(dev->pdev->bus->qts, 100);
- } while (!get_config_isr_status(d));
+ }
}
static void queue_select(QVirtioDevice *d, uint16_t index)
diff --git a/tests/qtest/libqos/virtio-pci.c b/tests/qtest/libqos/virtio-pci.c
index 485b8f6..002bf8b 100644
--- a/tests/qtest/libqos/virtio-pci.c
+++ b/tests/qtest/libqos/virtio-pci.c
@@ -171,13 +171,11 @@ static bool qvirtio_pci_get_config_isr_status(QVirtioDevice *d)
static void qvirtio_pci_wait_config_isr_status(QVirtioDevice *d,
gint64 timeout_us)
{
- QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
gint64 start_time = g_get_monotonic_time();
- do {
+ while (!qvirtio_pci_get_config_isr_status(d)) {
g_assert(g_get_monotonic_time() - start_time <= timeout_us);
- qtest_clock_step(dev->pdev->bus->qts, 100);
- } while (!qvirtio_pci_get_config_isr_status(d));
+ }
}
static void qvirtio_pci_queue_select(QVirtioDevice *d, uint16_t index)
diff --git a/tests/qtest/libqos/virtio-scmi.c b/tests/qtest/libqos/virtio-scmi.c
index ce8f4d5..6b5bd4d 100644
--- a/tests/qtest/libqos/virtio-scmi.c
+++ b/tests/qtest/libqos/virtio-scmi.c
@@ -1,7 +1,7 @@
/*
* virtio-scmi nodes for testing
*
- * SPDX-FileCopyrightText: Linaro Ltd
+ * Copyright (c) Linaro Ltd.
* SPDX-FileCopyrightText: Red Hat, Inc.
* SPDX-License-Identifier: GPL-2.0-or-later
*
diff --git a/tests/qtest/libqos/virtio.c b/tests/qtest/libqos/virtio.c
index a21b6ee..5a709d0 100644
--- a/tests/qtest/libqos/virtio.c
+++ b/tests/qtest/libqos/virtio.c
@@ -25,49 +25,63 @@
*/
static uint16_t qvirtio_readw(QVirtioDevice *d, QTestState *qts, uint64_t addr)
{
- uint16_t val = qtest_readw(qts, addr);
+ uint16_t val;
- if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
- val = bswap16(val);
+ if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
+ qtest_memread(qts, addr, &val, sizeof(val));
+ val = le16_to_cpu(val);
+ } else {
+ val = qtest_readw(qts, addr);
}
+
return val;
}
static uint32_t qvirtio_readl(QVirtioDevice *d, QTestState *qts, uint64_t addr)
{
- uint32_t val = qtest_readl(qts, addr);
+ uint32_t val;
- if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
- val = bswap32(val);
+ if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
+ qtest_memread(qts, addr, &val, sizeof(val));
+ val = le32_to_cpu(val);
+ } else {
+ val = qtest_readl(qts, addr);
}
+
return val;
}
static void qvirtio_writew(QVirtioDevice *d, QTestState *qts,
uint64_t addr, uint16_t val)
{
- if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
- val = bswap16(val);
+ if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
+ val = cpu_to_le16(val);
+ qtest_memwrite(qts, addr, &val, sizeof(val));
+ } else {
+ qtest_writew(qts, addr, val);
}
- qtest_writew(qts, addr, val);
}
static void qvirtio_writel(QVirtioDevice *d, QTestState *qts,
uint64_t addr, uint32_t val)
{
- if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
- val = bswap32(val);
+ if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
+ val = cpu_to_le32(val);
+ qtest_memwrite(qts, addr, &val, sizeof(val));
+ } else {
+ qtest_writel(qts, addr, val);
}
- qtest_writel(qts, addr, val);
}
static void qvirtio_writeq(QVirtioDevice *d, QTestState *qts,
uint64_t addr, uint64_t val)
{
- if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
- val = bswap64(val);
+ if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
+ val = cpu_to_le64(val);
+ qtest_memwrite(qts, addr, &val, sizeof(val));
+ } else {
+ qtest_writeq(qts, addr, val);
}
- qtest_writeq(qts, addr, val);
}
uint8_t qvirtio_config_readb(QVirtioDevice *d, uint64_t addr)
@@ -170,7 +184,6 @@ void qvirtio_wait_queue_isr(QTestState *qts, QVirtioDevice *d,
gint64 start_time = g_get_monotonic_time();
for (;;) {
- qtest_clock_step(qts, 100);
if (d->bus->get_queue_isr_status(d, vq)) {
return;
}
@@ -192,7 +205,6 @@ uint8_t qvirtio_wait_status_byte_no_isr(QTestState *qts, QVirtioDevice *d,
uint8_t val;
while ((val = qtest_readb(qts, addr)) == 0xff) {
- qtest_clock_step(qts, 100);
g_assert(!d->bus->get_queue_isr_status(d, vq));
g_assert(g_get_monotonic_time() - start_time <= timeout_us);
}
@@ -219,14 +231,12 @@ void qvirtio_wait_used_elem(QTestState *qts, QVirtioDevice *d,
for (;;) {
uint32_t got_desc_idx;
- qtest_clock_step(qts, 100);
if (d->bus->get_queue_isr_status(d, vq) &&
qvirtqueue_get_buf(qts, vq, &got_desc_idx, len)) {
g_assert_cmpint(got_desc_idx, ==, desc_idx);
return;
}
-
g_assert(g_get_monotonic_time() - start_time <= timeout_us);
}
}
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index 9d07de1..94526b7 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -30,14 +30,15 @@
#include "libqtest.h"
#include "libqmp.h"
+#include "qemu/accel.h"
#include "qemu/ctype.h"
#include "qemu/cutils.h"
#include "qemu/sockets.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qjson.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qstring.h"
-#include "qapi/qmp/qbool.h"
+#include "qobject/qdict.h"
+#include "qobject/qjson.h"
+#include "qobject/qlist.h"
+#include "qobject/qstring.h"
+#include "qobject/qbool.h"
#define MAX_IRQ 256
@@ -75,6 +76,8 @@ struct QTestState
{
int fd;
int qmp_fd;
+ int sock;
+ int qmpsock;
pid_t qemu_pid; /* our child QEMU process */
int wstatus;
#ifdef _WIN32
@@ -215,6 +218,22 @@ static void qtest_check_status(QTestState *s)
#endif
}
+void qtest_system_reset_nowait(QTestState *s)
+{
+ /* Request the system reset, but do not wait for it to complete */
+ qtest_qmp_assert_success(s, "{'execute': 'system_reset' }");
+}
+
+void qtest_system_reset(QTestState *s)
+{
+ qtest_system_reset_nowait(s);
+ /*
+ * Wait for the RESET event, which is sent once the system reset
+ * has actually completed.
+ */
+ qtest_qmp_eventwait(s, "RESET");
+}
+
void qtest_wait_qemu(QTestState *s)
{
if (s->qemu_pid != -1) {
@@ -442,18 +461,19 @@ static QTestState *G_GNUC_PRINTF(2, 3) qtest_spawn_qemu(const char *qemu_bin,
return s;
}
+static char *qtest_socket_path(const char *suffix)
+{
+ return g_strdup_printf("%s/qtest-%d.%s", g_get_tmp_dir(), getpid(), suffix);
+}
+
static QTestState *qtest_init_internal(const char *qemu_bin,
- const char *extra_args)
+ const char *extra_args,
+ bool do_connect)
{
QTestState *s;
int sock, qmpsock, i;
- gchar *socket_path;
- gchar *qmp_socket_path;
-
- socket_path = g_strdup_printf("%s/qtest-%d.sock",
- g_get_tmp_dir(), getpid());
- qmp_socket_path = g_strdup_printf("%s/qtest-%d.qmp",
- g_get_tmp_dir(), getpid());
+ g_autofree gchar *socket_path = qtest_socket_path("sock");
+ g_autofree gchar *qmp_socket_path = qtest_socket_path("qmp");
/*
* It's possible that if an earlier test run crashed it might
@@ -485,22 +505,19 @@ static QTestState *qtest_init_internal(const char *qemu_bin,
qtest_client_set_rx_handler(s, qtest_client_socket_recv_line);
qtest_client_set_tx_handler(s, qtest_client_socket_send);
- 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;
}
+ s->fd = -1;
+ s->qmp_fd = -1;
+ s->sock = sock;
+ s->qmpsock = qmpsock;
+ if (do_connect) {
+ qtest_connect(s);
+ }
+
/*
* Stopping QEMU for debugging is not supported on Windows.
*
@@ -515,34 +532,69 @@ static QTestState *qtest_init_internal(const char *qemu_bin,
}
#endif
- /* ask endianness of the target */
+ return s;
+}
- s->big_endian = qtest_query_target_endianness(s);
+void qtest_connect(QTestState *s)
+{
+ g_autofree gchar *socket_path = qtest_socket_path("sock");
+ g_autofree gchar *qmp_socket_path = qtest_socket_path("qmp");
- return s;
+ g_assert(s->sock >= 0 && s->qmpsock >= 0);
+ s->fd = socket_accept(s->sock);
+ if (s->fd >= 0) {
+ s->qmp_fd = socket_accept(s->qmpsock);
+ }
+ unlink(socket_path);
+ unlink(qmp_socket_path);
+ g_assert(s->fd >= 0 && s->qmp_fd >= 0);
+ s->sock = s->qmpsock = -1;
+ /* ask endianness of the target */
+ s->big_endian = qtest_query_target_endianness(s);
}
QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
{
- return qtest_init_internal(qtest_qemu_binary(NULL), extra_args);
+ return qtest_init_internal(qtest_qemu_binary(NULL), extra_args, true);
}
-QTestState *qtest_init_with_env(const char *var, const char *extra_args)
+void qtest_qmp_handshake(QTestState *s, QList *capabilities)
{
- QTestState *s = qtest_init_internal(qtest_qemu_binary(var), extra_args);
- QDict *greeting;
-
/* Read the QMP greeting and then do the handshake */
- greeting = qtest_qmp_receive(s);
+ QDict *greeting = qtest_qmp_receive(s);
qobject_unref(greeting);
- qobject_unref(qtest_qmp(s, "{ 'execute': 'qmp_capabilities' }"));
+ if (capabilities) {
+ qtest_qmp_assert_success(s,
+ "{ 'execute': 'qmp_capabilities', "
+ "'arguments': { 'enable': %p } }",
+ qobject_ref(capabilities));
+ } else {
+ qtest_qmp_assert_success(s, "{ 'execute': 'qmp_capabilities' }");
+ }
+}
+
+QTestState *qtest_init_ext(const char *var, const char *extra_args,
+ QList *capabilities, bool do_connect)
+{
+ QTestState *s = qtest_init_internal(qtest_qemu_binary(var), extra_args,
+ do_connect);
+
+ if (do_connect) {
+ qtest_qmp_handshake(s, capabilities);
+ } else {
+ /*
+ * If the connection is delayed, the capabilities must be set
+ * at that moment.
+ */
+ assert(!capabilities);
+ }
return s;
}
QTestState *qtest_init(const char *extra_args)
{
- return qtest_init_with_env(NULL, extra_args);
+ return qtest_init_ext(NULL, extra_args, NULL, true);
}
QTestState *qtest_vinitf(const char *fmt, va_list ap)
@@ -752,6 +804,7 @@ QDict *qtest_qmp_receive(QTestState *s)
QDict *qtest_qmp_receive_dict(QTestState *s)
{
+ g_assert(s->qmp_fd >= 0);
return qmp_fd_receive(s->qmp_fd);
}
@@ -779,12 +832,14 @@ int qtest_socket_server(const char *socket_path)
void qtest_qmp_vsend_fds(QTestState *s, int *fds, size_t fds_num,
const char *fmt, va_list ap)
{
+ g_assert(s->qmp_fd >= 0);
qmp_fd_vsend_fds(s->qmp_fd, fds, fds_num, fmt, ap);
}
#endif
void qtest_qmp_vsend(QTestState *s, const char *fmt, va_list ap)
{
+ g_assert(s->qmp_fd >= 0);
qmp_fd_vsend(s->qmp_fd, fmt, ap);
}
@@ -845,6 +900,7 @@ void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...)
{
va_list ap;
+ g_assert(s->qmp_fd >= 0);
va_start(ap, fmt);
qmp_fd_vsend_raw(s->qmp_fd, fmt, ap);
va_end(ap);
@@ -948,15 +1004,62 @@ const char *qtest_get_arch(void)
return end + 1;
}
+static bool qtest_qom_has_concrete_type(const char *parent_typename,
+ const char *child_typename,
+ QList **cached_list)
+{
+ QList *list = cached_list ? *cached_list : NULL;
+ const QListEntry *p;
+ QObject *qobj;
+ QString *qstr;
+ QDict *devinfo;
+ int idx;
+
+ if (!list) {
+ QDict *resp;
+ QDict *args;
+ QTestState *qts = qtest_init("-machine none");
+
+ args = qdict_new();
+ qdict_put_bool(args, "abstract", false);
+ qdict_put_str(args, "implements", parent_typename);
+
+ resp = qtest_qmp(qts, "{'execute': 'qom-list-types', 'arguments': %p }",
+ args);
+ g_assert(qdict_haskey(resp, "return"));
+ list = qdict_get_qlist(resp, "return");
+ qobject_ref(list);
+ qobject_unref(resp);
+
+ qtest_quit(qts);
+
+ if (cached_list) {
+ *cached_list = list;
+ }
+ }
+
+ for (p = qlist_first(list), idx = 0; p; p = qlist_next(p), idx++) {
+ devinfo = qobject_to(QDict, qlist_entry_obj(p));
+ g_assert(devinfo);
+
+ qobj = qdict_get(devinfo, "name");
+ g_assert(qobj);
+ qstr = qobject_to(QString, qobj);
+ g_assert(qstr);
+ if (g_str_equal(qstring_get_str(qstr), child_typename)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool qtest_has_accel(const char *accel_name)
{
- if (g_str_equal(accel_name, "tcg")) {
-#if defined(CONFIG_TCG)
- return true;
-#else
- return false;
-#endif
- } else if (g_str_equal(accel_name, "kvm")) {
+ static QList *list;
+ g_autofree char *accel_type = NULL;
+
+ if (g_str_equal(accel_name, "kvm")) {
int i;
const char *arch = qtest_get_arch();
const char *targets[] = { CONFIG_KVM_TARGETS };
@@ -968,11 +1071,12 @@ bool qtest_has_accel(const char *accel_name)
}
}
}
- } else {
- /* not implemented */
- g_assert_not_reached();
+ return false;
}
- return false;
+
+ accel_type = g_strconcat(accel_name, ACCEL_CLASS_SUFFIX, NULL);
+
+ return qtest_qom_has_concrete_type("accel", accel_type, &list);
}
bool qtest_get_irq(QTestState *s, int num)
@@ -1202,6 +1306,33 @@ uint64_t qtest_rtas_call(QTestState *s, const char *name,
return 0;
}
+static void qtest_rsp_csr(QTestState *s, uint64_t *val)
+{
+ gchar **args;
+ uint64_t ret;
+ int rc;
+
+ args = qtest_rsp_args(s, 3);
+
+ rc = qemu_strtou64(args[1], NULL, 16, &ret);
+ g_assert(rc == 0);
+ rc = qemu_strtou64(args[2], NULL, 16, val);
+ g_assert(rc == 0);
+
+ g_strfreev(args);
+}
+
+uint64_t qtest_csr_call(QTestState *s, const char *name,
+ uint64_t cpu, int csr,
+ uint64_t *val)
+{
+ qtest_sendf(s, "csr %s 0x%"PRIx64" %d 0x%"PRIx64"\n",
+ name, cpu, csr, *val);
+
+ qtest_rsp_csr(s, val);
+ return 0;
+}
+
void qtest_add_func(const char *str, void (*fn)(void))
{
gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
@@ -1523,7 +1654,7 @@ static struct MachInfo *qtest_get_machines(const char *var)
silence_spawn_log = !g_test_verbose();
- qts = qtest_init_with_env(qemu_var, "-machine none");
+ qts = qtest_init_ext(qemu_var, "-machine none", NULL, true);
response = qtest_qmp(qts, "{ 'execute': 'query-machines' }");
g_assert(response);
list = qdict_get_qlist(response, "return");
@@ -1578,7 +1709,7 @@ static struct CpuModel *qtest_get_cpu_models(void)
silence_spawn_log = !g_test_verbose();
- qts = qtest_init_with_env(NULL, "-machine none");
+ qts = qtest_init_ext(NULL, "-machine none", NULL, true);
response = qtest_qmp(qts, "{ 'execute': 'query-cpu-definitions' }");
g_assert(response);
list = qdict_get_qlist(response, "return");
@@ -1648,7 +1779,9 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine),
/* Ignore machines that cannot be used for qtests */
if (!strncmp("xenfv", machines[i].name, 5) ||
g_str_equal("xenpv", machines[i].name) ||
- g_str_equal("xenpvh", machines[i].name)) {
+ g_str_equal("xenpvh", machines[i].name) ||
+ g_str_equal("vmapple", machines[i].name) ||
+ g_str_equal("nitro-enclave", machines[i].name)) {
continue;
}
if (!skip_old_versioned ||
@@ -1699,45 +1832,8 @@ bool qtest_has_machine(const char *machine)
bool qtest_has_device(const char *device)
{
static QList *list;
- const QListEntry *p;
- QObject *qobj;
- QString *qstr;
- QDict *devinfo;
- int idx;
- if (!list) {
- QDict *resp;
- QDict *args;
- QTestState *qts = qtest_init("-machine none");
-
- args = qdict_new();
- qdict_put_bool(args, "abstract", false);
- qdict_put_str(args, "implements", "device");
-
- resp = qtest_qmp(qts, "{'execute': 'qom-list-types', 'arguments': %p }",
- args);
- g_assert(qdict_haskey(resp, "return"));
- list = qdict_get_qlist(resp, "return");
- qobject_ref(list);
- qobject_unref(resp);
-
- qtest_quit(qts);
- }
-
- for (p = qlist_first(list), idx = 0; p; p = qlist_next(p), idx++) {
- devinfo = qobject_to(QDict, qlist_entry_obj(p));
- g_assert(devinfo);
-
- qobj = qdict_get(devinfo, "name");
- g_assert(qobj);
- qstr = qobject_to(QString, qobj);
- g_assert(qstr);
- if (g_str_equal(qstring_get_str(qstr), device)) {
- return true;
- }
- }
-
- return false;
+ return qtest_qom_has_concrete_type("device", device, &list);
}
/*
@@ -1918,7 +2014,6 @@ void qtest_client_inproc_recv(void *opaque, const char *str)
qts->rx = g_string_new(NULL);
}
g_string_append(qts->rx, str);
- return;
}
void qtest_qom_set_bool(QTestState *s, const char *path, const char *property,
diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
index beb96b1..b3f2e7f 100644
--- a/tests/qtest/libqtest.h
+++ b/tests/qtest/libqtest.h
@@ -17,8 +17,9 @@
#ifndef LIBQTEST_H
#define LIBQTEST_H
-#include "qapi/qmp/qobject.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qobject.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
#include "libqmp.h"
typedef struct QTestState QTestState;
@@ -56,17 +57,21 @@ QTestState *qtest_vinitf(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0);
QTestState *qtest_init(const char *extra_args);
/**
- * qtest_init_with_env:
+ * qtest_init_ext:
* @var: Environment variable from where to take the QEMU binary
* @extra_args: Other arguments to pass to QEMU. CAUTION: these
* arguments are subject to word splitting and shell evaluation.
+ * @capabilities: list of QMP capabilities (strings) to enable
+ * @do_connect: connect to qemu monitor and qtest socket.
*
* Like qtest_init(), but use a different environment variable for the
- * QEMU binary.
+ * QEMU binary, allow specify capabilities and skip connecting
+ * to QEMU monitor.
*
* Returns: #QTestState instance.
*/
-QTestState *qtest_init_with_env(const char *var, const char *extra_args);
+QTestState *qtest_init_ext(const char *var, const char *extra_args,
+ QList *capabilities, bool do_connect);
/**
* qtest_init_without_qmp_handshake:
@@ -78,6 +83,22 @@ QTestState *qtest_init_with_env(const char *var, const char *extra_args);
QTestState *qtest_init_without_qmp_handshake(const char *extra_args);
/**
+ * qtest_connect
+ * @s: #QTestState instance to connect
+ * Connect to qemu monitor and qtest socket, after skipping them in
+ * qtest_init_ext. Does not handshake with the monitor.
+ */
+void qtest_connect(QTestState *s);
+
+/**
+ * qtest_qmp_handshake:
+ * @s: #QTestState instance to operate on.
+ * @capabilities: list of QMP capabilities (strings) to enable
+ * Perform handshake after connecting to qemu monitor.
+ */
+void qtest_qmp_handshake(QTestState *s, QList *capabilities);
+
+/**
* qtest_init_with_serial:
* @extra_args: other arguments to pass to QEMU. CAUTION: these
* arguments are subject to word splitting and shell evaluation.
@@ -89,6 +110,31 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args);
QTestState *qtest_init_with_serial(const char *extra_args, int *sock_fd);
/**
+ * qtest_system_reset:
+ * @s: #QTestState instance to operate on.
+ *
+ * Send a "system_reset" command to the QEMU under test, and wait for
+ * the reset to complete before returning.
+ */
+void qtest_system_reset(QTestState *s);
+
+/**
+ * qtest_system_reset_nowait:
+ * @s: #QTestState instance to operate on.
+ *
+ * Send a "system_reset" command to the QEMU under test, but do not
+ * wait for the reset to complete before returning. The caller is
+ * responsible for waiting for either the RESET event or some other
+ * event of interest to them before proceeding.
+ *
+ * This function should only be used if you're specifically testing
+ * for some other event; in that case you can't use qtest_system_reset()
+ * because it will read and discard any other QMP events that arrive
+ * before the RESET event.
+ */
+void qtest_system_reset_nowait(QTestState *s);
+
+/**
* qtest_wait_qemu:
* @s: #QTestState instance to operate on.
*
@@ -340,7 +386,7 @@ QDict *qtest_qmp_event_ref(QTestState *s, const char *event);
char *qtest_hmp(QTestState *s, const char *fmt, ...) G_GNUC_PRINTF(2, 3);
/**
- * qtest_hmpv:
+ * qtest_vhmp:
* @s: #QTestState instance to operate on.
* @fmt: HMP command to send to QEMU, formats arguments like vsprintf().
* @ap: HMP command arguments
@@ -576,6 +622,20 @@ uint64_t qtest_rtas_call(QTestState *s, const char *name,
uint32_t nret, uint64_t ret);
/**
+ * qtest_csr_call:
+ * @s: #QTestState instance to operate on.
+ * @name: name of the command to call.
+ * @cpu: hart number.
+ * @csr: CSR number.
+ * @val: Value for reading/writing.
+ *
+ * Call an RISC-V CSR read/write function
+ */
+uint64_t qtest_csr_call(QTestState *s, const char *name,
+ uint64_t cpu, int csr,
+ uint64_t *val);
+
+/**
* qtest_bufread:
* @s: #QTestState instance to operate on.
* @addr: Guest address to read from.
@@ -879,7 +939,7 @@ void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
#ifndef _WIN32
/**
- * qtest_qmp_fd_assert_success_ref:
+ * qtest_qmp_fds_assert_success_ref:
* @qts: QTestState instance to operate on
* @fds: the file descriptors to send
* @nfds: number of @fds to send
@@ -896,7 +956,7 @@ QDict *qtest_qmp_fds_assert_success_ref(QTestState *qts, int *fds, size_t nfds,
G_GNUC_PRINTF(4, 5);
/**
- * qtest_qmp_fd_assert_success:
+ * qtest_qmp_fds_assert_success:
* @qts: QTestState instance to operate on
* @fds: the file descriptors to send
* @nfds: number of @fds to send
diff --git a/tests/qtest/lsm303dlhc-mag-test.c b/tests/qtest/lsm303dlhc-mag-test.c
index 0f64e7f..55ef459 100644
--- a/tests/qtest/lsm303dlhc-mag-test.c
+++ b/tests/qtest/lsm303dlhc-mag-test.c
@@ -13,7 +13,7 @@
#include "libqtest-single.h"
#include "libqos/qgraph.h"
#include "libqos/i2c.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#define LSM303DLHC_MAG_TEST_ID "lsm303dlhc_mag-test"
#define LSM303DLHC_MAG_REG_CRA 0x00
diff --git a/tests/qtest/m48t59-test.c b/tests/qtest/m48t59-test.c
index 605797a..1e39a0e 100644
--- a/tests/qtest/m48t59-test.c
+++ b/tests/qtest/m48t59-test.c
@@ -247,11 +247,6 @@ static void base_setup(void)
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();
}
diff --git a/tests/qtest/machine-none-test.c b/tests/qtest/machine-none-test.c
index 05da7bc..b6a87d2 100644
--- a/tests/qtest/machine-none-test.c
+++ b/tests/qtest/machine-none-test.c
@@ -14,7 +14,7 @@
#include "qemu/cutils.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
struct arch2cpu {
@@ -30,7 +30,6 @@ static struct arch2cpu cpus_map[] = {
{ "x86_64", "qemu64,apic-id=0" },
{ "i386", "qemu32,apic-id=0" },
{ "alpha", "ev67" },
- { "cris", "crisv32" },
{ "m68k", "m5206" },
{ "microblaze", "any" },
{ "microblazeel", "any" },
diff --git a/tests/qtest/max34451-test.c b/tests/qtest/max34451-test.c
index dbf6ddc..5e0878c 100644
--- a/tests/qtest/max34451-test.c
+++ b/tests/qtest/max34451-test.c
@@ -11,8 +11,8 @@
#include "libqtest-single.h"
#include "libqos/qgraph.h"
#include "libqos/i2c.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qnum.h"
+#include "qobject/qdict.h"
+#include "qobject/qnum.h"
#include "qemu/bitops.h"
#define TEST_ID "max34451-test"
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index fc852f3..8ad8490 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -4,9 +4,11 @@ slow_qtests = {
'bios-tables-test' : 910,
'cdrom-test' : 610,
'device-introspect-test' : 720,
+ 'ide-test' : 120,
'migration-test' : 480,
'npcm7xx_pwm-test': 300,
'npcm7xx_watchdog_timer-test': 120,
+ 'qmp-cmd-test' : 120,
'qom-test' : 900,
'stm32l4x5_usart-test' : 600,
'test-hmp' : 240,
@@ -50,7 +52,16 @@ qtests_filter = \
qtests_i386 = \
(slirp.found() ? ['pxe-test'] : []) + \
qtests_filter + \
- (have_tools ? ['ahci-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_ACPI_VMGENID') ? ['vmgenid-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_AHCI_ICH9') and have_tools ? ['ahci-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_AHCI_ICH9') ? ['tco-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_FDC_ISA') ? ['fdc-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_I440FX') ? ['fw_cfg-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_FW_CFG_DMA') ? ['vmcoreinfo-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_I440FX') ? ['i440fx-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_I440FX') ? ['ide-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_I440FX') ? ['numa-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_I440FX') ? ['test-x86-cpuid-compat'] : []) + \
(config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \
(config_all_devices.has_key('CONFIG_SGA') ? ['boot-serial-test'] : []) + \
(config_all_devices.has_key('CONFIG_ISA_IPMI_KCS') ? ['ipmi-kcs-test'] : []) + \
@@ -64,6 +75,7 @@ qtests_i386 = \
(config_all_devices.has_key('CONFIG_I82801B11') ? ['i82801b11-test'] : []) + \
(config_all_devices.has_key('CONFIG_IOH3420') ? ['ioh3420-test'] : []) + \
(config_all_devices.has_key('CONFIG_LPC_ICH9') ? ['lpc-ich9-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_MC146818RTC') ? ['rtc-test'] : []) + \
(config_all_devices.has_key('CONFIG_USB_UHCI') ? ['usb-hcd-uhci-test'] : []) + \
(config_all_devices.has_key('CONFIG_USB_UHCI') and \
config_all_devices.has_key('CONFIG_USB_EHCI') ? ['usb-hcd-ehci-test'] : []) + \
@@ -77,9 +89,12 @@ qtests_i386 = \
(config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \
(config_all_devices.has_key('CONFIG_LSI_SCSI_PCI') ? ['fuzz-lsi53c895a-test'] : []) + \
(config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_VIRTIO_BALLOON') ? ['virtio-balloon-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_Q35') ? ['q35-test'] : []) + \
(config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \
(config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \
(config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_VTD') ? ['intel-iommu-test'] : []) + \
(host_os != 'windows' and \
config_all_devices.has_key('CONFIG_ACPI_ERST') ? ['erst-test'] : []) + \
(config_all_devices.has_key('CONFIG_PCIE_PORT') and \
@@ -92,25 +107,16 @@ qtests_i386 = \
config_all_devices.has_key('CONFIG_PARALLEL') ? ['bios-tables-test'] : []) + \
qtests_pci + \
qtests_cxl + \
- ['fdc-test',
- 'ide-test',
+ [
'hd-geo-test',
'boot-order-test',
- 'rtc-test',
- 'i440fx-test',
- 'fw_cfg-test',
'device-plug-test',
'drive_del-test',
- 'tco-test',
'cpu-plug-test',
- 'q35-test',
- 'vmgenid-test',
'migration-test',
- 'test-x86-cpuid-compat',
- 'numa-test'
]
-if dbus_display
+if dbus_display and config_all_devices.has_key('CONFIG_VGA')
qtests_i386 += ['dbus-display-test']
endif
@@ -136,12 +142,14 @@ qtests_alpha = ['boot-serial-test'] + \
qtests_avr = [ 'boot-serial-test' ]
-qtests_hppa = ['boot-serial-test'] + \
+qtests_hppa = \
qtests_filter + \
(config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : [])
qtests_loongarch64 = qtests_filter + \
- ['boot-serial-test', 'numa-test']
+ (config_all_devices.has_key('CONFIG_LOONGARCH_VIRT') ? ['numa-test'] : []) + \
+ ['boot-serial-test',
+ 'cpu-plug-test']
qtests_m68k = ['boot-serial-test'] + \
qtests_filter
@@ -163,7 +171,6 @@ qtests_mips64el = qtests_mips
qtests_ppc = \
qtests_filter + \
(config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \
- (config_all_devices.has_key('CONFIG_M48T59') ? ['m48t59-test'] : []) + \
(config_all_accel.has_key('CONFIG_TCG') ? ['prom-env-test'] : []) + \
(config_all_accel.has_key('CONFIG_TCG') ? ['boot-serial-test'] : []) + \
['boot-order-test']
@@ -172,13 +179,15 @@ qtests_ppc64 = \
qtests_ppc + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['device-plug-test'] : []) + \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-xscom-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-xive2-test'] : []) + \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-spi-seeprom-test'] : []) + \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-host-i2c-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_PSERIES') ? ['numa-test'] : []) + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['rtas-test'] : []) + \
(slirp.found() ? ['pxe-test'] : []) + \
(config_all_devices.has_key('CONFIG_USB_UHCI') ? ['usb-hcd-uhci-test'] : []) + \
(config_all_devices.has_key('CONFIG_USB_XHCI_NEC') ? ['usb-hcd-xhci-test'] : []) + \
- qtests_pci + ['migration-test', 'numa-test', 'cpu-plug-test', 'drive_del-test']
+ qtests_pci + ['migration-test', 'cpu-plug-test', 'drive_del-test']
qtests_sh4 = (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : [])
qtests_sh4eb = (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : [])
@@ -199,13 +208,18 @@ qtests_npcm7xx = \
'npcm7xx_sdhci-test',
'npcm7xx_smbus-test',
'npcm7xx_timer-test',
- 'npcm7xx_watchdog_timer-test',
- 'npcm_gmac-test'] + \
+ 'npcm7xx_watchdog_timer-test'] + \
(slirp.found() ? ['npcm7xx_emc-test'] : [])
+qtests_npcm8xx = \
+ ['npcm_gmac-test']
qtests_aspeed = \
- ['aspeed_hace-test',
- 'aspeed_smc-test',
- 'aspeed_gpio-test']
+ ['aspeed_gpio-test',
+ 'aspeed_hace-test',
+ 'aspeed_smc-test']
+qtests_aspeed64 = \
+ ['ast2700-gpio-test',
+ 'ast2700-hace-test',
+ 'ast2700-smc-test']
qtests_stm32l4x5 = \
['stm32l4x5_exti-test',
@@ -218,7 +232,8 @@ qtests_arm = \
(config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \
(config_all_devices.has_key('CONFIG_CMSDK_APB_DUALTIMER') ? ['cmsdk-apb-dualtimer-test'] : []) + \
(config_all_devices.has_key('CONFIG_CMSDK_APB_TIMER') ? ['cmsdk-apb-timer-test'] : []) + \
- (config_all_devices.has_key('CONFIG_CMSDK_APB_WATCHDOG') ? ['cmsdk-apb-watchdog-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_STELLARIS') or
+ config_all_devices.has_key('CONFIG_MPS2') ? ['cmsdk-apb-watchdog-test'] : []) + \
(config_all_devices.has_key('CONFIG_PFLASH_CFI02') and
config_all_devices.has_key('CONFIG_MUSICPAL') ? ['pflash-cfi02-test'] : []) + \
(config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed : []) + \
@@ -244,6 +259,8 @@ qtests_aarch64 = \
(config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test', 'bcm2835-i2c-test'] : []) + \
(config_all_accel.has_key('CONFIG_TCG') and \
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed64 : []) + \
+ (config_all_devices.has_key('CONFIG_NPCM8XX') ? qtests_npcm8xx : []) + \
['arm-cpu-features',
'numa-test',
'boot-serial-test',
@@ -261,7 +278,7 @@ qtests_s390x = \
qtests_riscv32 = \
(config_all_devices.has_key('CONFIG_SIFIVE_E_AON') ? ['sifive-e-aon-watchdog-test'] : [])
-qtests_riscv64 = \
+qtests_riscv64 = ['riscv-csr-test'] + \
(unpack_edk2_blobs ? ['bios-tables-test'] : [])
qos_test_ss = ss.source_set()
@@ -273,7 +290,6 @@ qos_test_ss.add(
'e1000-test.c',
'eepro100-test.c',
'es1370-test.c',
- 'ipoctal232-test.c',
'lsm303dlhc-mag-test.c',
'isl_pmbus_vr-test.c',
'max34451-test.c',
@@ -284,6 +300,7 @@ qos_test_ss.add(
'pca9552-test.c',
'pci-test.c',
'pcnet-test.c',
+ 'rs5c372-test.c',
'sdhci-test.c',
'spapr-phb-test.c',
'tmp105-test.c',
@@ -298,11 +315,15 @@ qos_test_ss.add(
'vmxnet3-test.c',
'igb-test.c',
'ufs-test.c',
+ 'riscv-iommu-test.c',
)
if config_all_devices.has_key('CONFIG_VIRTIO_SERIAL')
qos_test_ss.add(files('virtio-serial-test.c'))
endif
+if config_all_devices.has_key('CONFIG_IP_OCTAL_232')
+ qos_test_ss.add(files('ipoctal232-test.c'))
+endif
if host_os != 'windows'
qos_test_ss.add(files('e1000e-test.c'))
@@ -319,23 +340,44 @@ endif
tpmemu_files = ['tpm-emu.c', 'tpm-util.c', 'tpm-tests.c']
-migration_files = [files('migration-helpers.c')]
+migration_files = [files(
+ 'migration/bootfile.c',
+ 'migration/framework.c',
+ 'migration/migration-qmp.c',
+ 'migration/migration-util.c',
+ 'migration/compression-tests.c',
+ 'migration/cpr-tests.c',
+ 'migration/file-tests.c',
+ 'migration/misc-tests.c',
+ 'migration/precopy-tests.c',
+ 'migration/postcopy-tests.c',
+)]
+
+migration_tls_files = []
if gnutls.found()
- migration_files += [files('../unit/crypto-tls-psk-helpers.c'), gnutls]
+ migration_tls_files = [files('migration/tls-tests.c',
+ '../unit/crypto-tls-psk-helpers.c'), gnutls]
if tasn1.found()
- migration_files += [files('../unit/crypto-tls-x509-helpers.c'), tasn1]
+ migration_tls_files += [files('../unit/crypto-tls-x509-helpers.c'), tasn1]
endif
endif
qtests = {
+ 'aspeed_hace-test': files('aspeed-hace-utils.c', 'aspeed_hace-test.c'),
+ 'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'),
+ 'ast2700-hace-test': files('aspeed-hace-utils.c', 'ast2700-hace-test.c'),
+ 'ast2700-smc-test': files('aspeed-smc-utils.c', 'ast2700-smc-test.c'),
'bios-tables-test': [io, 'boot-sector.c', 'acpi-utils.c', 'tpm-emu.c'],
'cdrom-test': files('boot-sector.c'),
- 'dbus-vmstate-test': files('migration-helpers.c') + dbus_vmstate1,
+ 'dbus-vmstate-test': files('migration/migration-qmp.c',
+ 'migration/migration-util.c') + dbus_vmstate1,
'erst-test': files('erst-test.c'),
'ivshmem-test': [rt, '../../contrib/ivshmem-server/ivshmem-server.c'],
- 'migration-test': migration_files,
+ 'migration-test': migration_files + migration_tls_files,
'pxe-test': files('boot-sector.c'),
+ 'pnv-xive2-test': files('pnv-xive2-common.c', 'pnv-xive2-flush-sync.c',
+ 'pnv-xive2-nvpg_bar.c'),
'qos-test': [chardev, io, qos_test_ss.apply({}).sources()],
'tpm-crb-swtpm-test': [io, tpmemu_files],
'tpm-crb-test': [io, tpmemu_files],
@@ -344,7 +386,7 @@ qtests = {
'tpm-tis-i2c-test': [io, tpmemu_files, 'qtest_aspeed.c'],
'tpm-tis-device-swtpm-test': [io, tpmemu_files, 'tpm-tis-util.c'],
'tpm-tis-device-test': [io, tpmemu_files, 'tpm-tis-util.c'],
- 'virtio-net-failover': files('migration-helpers.c'),
+ 'virtio-net-failover': migration_files,
'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'),
'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'),
}
@@ -352,7 +394,7 @@ qtests = {
if vnc.found()
gvnc = dependency('gvnc-1.0', method: 'pkg-config', required: false)
if gvnc.found()
- qtests += {'vnc-display-test': [gvnc]}
+ qtests += {'vnc-display-test': [gvnc, keymap_targets]}
qtests_generic += [ 'vnc-display-test' ]
endif
endif
@@ -370,6 +412,8 @@ foreach dir : target_dirs
target_base = dir.split('-')[0]
qtest_emulator = emulators['qemu-system-' + target_base]
target_qtests = get_variable('qtests_' + target_base, []) + qtests_generic
+ has_kvm = ('CONFIG_KVM' in config_all_accel and host_os == 'linux'
+ and cpu == target_base and fs.exists('/dev/kvm'))
test_deps = roms
qtest_env = environment()
@@ -403,11 +447,18 @@ foreach dir : target_dirs
test: executable(test, src, dependencies: deps)
}
endif
+
+ test_args = ['--tap', '-k']
+
+ if test == 'migration-test' and has_kvm
+ test_args += ['--full']
+ endif
+
test('qtest-@0@/@1@'.format(target_base, test),
qtest_executables[test],
depends: [test_deps, qtest_emulator, emulator_modules],
env: qtest_env,
- args: ['--tap', '-k'],
+ args: test_args,
protocol: 'tap',
timeout: slow_qtests.get(test, 60),
priority: slow_qtests.get(test, 60),
diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c
deleted file mode 100644
index a43d180..0000000
--- a/tests/qtest/migration-helpers.c
+++ /dev/null
@@ -1,531 +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 "qemu/ctype.h"
-#include "qapi/qmp/qjson.h"
-#include "qapi/qapi-visit-sockets.h"
-#include "qapi/qobject-input-visitor.h"
-#include "qapi/error.h"
-#include "qapi/qmp/qlist.h"
-#include "qemu/cutils.h"
-#include "qemu/memalign.h"
-
-#include "migration-helpers.h"
-
-/*
- * Number of seconds we wait when looking for migration
- * status changes, to avoid test suite hanging forever
- * when things go wrong. Needs to be higher enough to
- * avoid false positives on loaded hosts.
- */
-#define MIGRATION_STATUS_WAIT_TIMEOUT 120
-
-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("vsock:%s:%s",
- addr->u.vsock.cid,
- addr->u.vsock.port);
- default:
- return g_strdup("unknown address type");
- }
-}
-
-static QDict *SocketAddress_to_qdict(SocketAddress *addr)
-{
- QDict *dict = qdict_new();
-
- switch (addr->type) {
- case SOCKET_ADDRESS_TYPE_INET:
- qdict_put_str(dict, "type", "inet");
- qdict_put_str(dict, "host", addr->u.inet.host);
- qdict_put_str(dict, "port", addr->u.inet.port);
- break;
- case SOCKET_ADDRESS_TYPE_UNIX:
- qdict_put_str(dict, "type", "unix");
- qdict_put_str(dict, "path", addr->u.q_unix.path);
- break;
- case SOCKET_ADDRESS_TYPE_FD:
- qdict_put_str(dict, "type", "fd");
- qdict_put_str(dict, "str", addr->u.fd.str);
- break;
- case SOCKET_ADDRESS_TYPE_VSOCK:
- qdict_put_str(dict, "type", "vsock");
- qdict_put_str(dict, "cid", addr->u.vsock.cid);
- qdict_put_str(dict, "port", addr->u.vsock.port);
- break;
- default:
- g_assert_not_reached();
- break;
- }
-
- return dict;
-}
-
-static SocketAddressList *migrate_get_socket_address(QTestState *who)
-{
- QDict *rsp;
- SocketAddressList *addrs;
- Visitor *iv = NULL;
- QObject *object;
-
- rsp = migrate_query(who);
- object = qdict_get(rsp, "socket-address");
-
- iv = qobject_input_visitor_new(object);
- visit_type_SocketAddressList(iv, NULL, &addrs, &error_abort);
- visit_free(iv);
-
- qobject_unref(rsp);
- return addrs;
-}
-
-static char *
-migrate_get_connect_uri(QTestState *who)
-{
- SocketAddressList *addrs;
- char *connect_uri;
-
- addrs = migrate_get_socket_address(who);
- connect_uri = SocketAddress_to_str(addrs->value);
-
- qapi_free_SocketAddressList(addrs);
- return connect_uri;
-}
-
-static QDict *
-migrate_get_connect_qdict(QTestState *who)
-{
- SocketAddressList *addrs;
- QDict *connect_qdict;
-
- addrs = migrate_get_socket_address(who);
- connect_qdict = SocketAddress_to_qdict(addrs->value);
-
- qapi_free_SocketAddressList(addrs);
- return connect_qdict;
-}
-
-static void migrate_set_ports(QTestState *to, QList *channel_list)
-{
- QDict *addr;
- QListEntry *entry;
- const char *addr_port = NULL;
-
- addr = migrate_get_connect_qdict(to);
-
- QLIST_FOREACH_ENTRY(channel_list, entry) {
- QDict *channel = qobject_to(QDict, qlist_entry_obj(entry));
- QDict *addrdict = qdict_get_qdict(channel, "addr");
-
- if (qdict_haskey(addrdict, "port") &&
- qdict_haskey(addr, "port") &&
- (strcmp(qdict_get_str(addrdict, "port"), "0") == 0)) {
- addr_port = qdict_get_str(addr, "port");
- qdict_put_str(addrdict, "port", addr_port);
- }
- }
-
- qobject_unref(addr);
-}
-
-bool migrate_watch_for_events(QTestState *who, const char *name,
- QDict *event, void *opaque)
-{
- QTestMigrationState *state = opaque;
-
- if (g_str_equal(name, "STOP")) {
- state->stop_seen = true;
- return true;
- } else if (g_str_equal(name, "SUSPEND")) {
- state->suspend_seen = true;
- return true;
- } else if (g_str_equal(name, "RESUME")) {
- state->resume_seen = true;
- return true;
- }
-
- return false;
-}
-
-void migrate_qmp_fail(QTestState *who, const char *uri,
- const char *channels, const char *fmt, ...)
-{
- va_list ap;
- QDict *args, *err;
-
- va_start(ap, fmt);
- args = qdict_from_vjsonf_nofail(fmt, ap);
- va_end(ap);
-
- g_assert(!qdict_haskey(args, "uri"));
- if (uri) {
- qdict_put_str(args, "uri", uri);
- }
-
- g_assert(!qdict_haskey(args, "channels"));
- if (channels) {
- QObject *channels_obj = qobject_from_json(channels, &error_abort);
- qdict_put_obj(args, "channels", channels_obj);
- }
-
- err = qtest_qmp_assert_failure_ref(
- who, "{ 'execute': 'migrate', 'arguments': %p}", args);
-
- g_assert(qdict_haskey(err, "desc"));
-
- qobject_unref(err);
-}
-
-/*
- * 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, QTestState *to, const char *uri,
- const char *channels, const char *fmt, ...)
-{
- va_list ap;
- QDict *args;
- g_autofree char *connect_uri = NULL;
-
- va_start(ap, fmt);
- args = qdict_from_vjsonf_nofail(fmt, ap);
- va_end(ap);
-
- g_assert(!qdict_haskey(args, "uri"));
- if (uri) {
- qdict_put_str(args, "uri", uri);
- } else if (!channels) {
- connect_uri = migrate_get_connect_uri(to);
- qdict_put_str(args, "uri", connect_uri);
- }
-
- g_assert(!qdict_haskey(args, "channels"));
- if (channels) {
- QObject *channels_obj = qobject_from_json(channels, &error_abort);
- QList *channel_list = qobject_to(QList, channels_obj);
- migrate_set_ports(to, channel_list);
- qdict_put_obj(args, "channels", channels_obj);
- }
-
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate', 'arguments': %p}", args);
-}
-
-void migrate_set_capability(QTestState *who, const char *capability,
- bool value)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate-set-capabilities',"
- "'arguments': { "
- "'capabilities': [ { "
- "'capability': %s, 'state': %i } ] } }",
- capability, value);
-}
-
-void migrate_incoming_qmp(QTestState *to, 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);
-
- /* This function relies on the event to work, make sure it's enabled */
- migrate_set_capability(to, "events", true);
-
- rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
- args);
-
- if (!qdict_haskey(rsp, "return")) {
- g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(rsp), true);
- g_test_message("%s", s->str);
- }
-
- g_assert(qdict_haskey(rsp, "return"));
- qobject_unref(rsp);
-
- migration_event_wait(to, "setup");
-}
-
-/*
- * Note: caller is responsible to free the returned object via
- * qobject_unref() after use
- */
-QDict *migrate_query(QTestState *who)
-{
- return qtest_qmp_assert_success_ref(who, "{ 'execute': 'query-migrate' }");
-}
-
-QDict *migrate_query_not_failed(QTestState *who)
-{
- const char *status;
- QDict *rsp = migrate_query(who);
- status = qdict_get_str(rsp, "status");
- if (g_str_equal(status, "failed")) {
- g_printerr("query-migrate shows failed migration: %s\n",
- qdict_get_str(rsp, "error-desc"));
- }
- g_assert(!g_str_equal(status, "failed"));
- return rsp;
-}
-
-/*
- * 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)
-{
- g_test_timer_start();
- while (!check_migration_status(who, goal, ungoals)) {
- usleep(1000);
-
- g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT);
- }
-}
-
-void wait_for_migration_complete(QTestState *who)
-{
- wait_for_migration_status(who, "completed", NULL);
-}
-
-void wait_for_migration_fail(QTestState *from, bool allow_active)
-{
- g_test_timer_start();
- 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);
-
- g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT);
- } while (!failed);
-
- /* Is the machine currently running? */
- rsp_return = qtest_qmp_assert_success_ref(from,
- "{ 'execute': 'query-status' }");
- g_assert(qdict_haskey(rsp_return, "running"));
- g_assert(qdict_get_bool(rsp_return, "running"));
- qobject_unref(rsp_return);
-}
-
-char *find_common_machine_version(const char *mtype, const char *var1,
- const char *var2)
-{
- g_autofree char *type1 = qtest_resolve_machine_alias(var1, mtype);
- g_autofree char *type2 = qtest_resolve_machine_alias(var2, mtype);
-
- g_assert(type1 && type2);
-
- if (g_str_equal(type1, type2)) {
- /* either can be used */
- return g_strdup(type1);
- }
-
- if (qtest_has_machine_with_env(var2, type1)) {
- return g_strdup(type1);
- }
-
- if (qtest_has_machine_with_env(var1, type2)) {
- return g_strdup(type2);
- }
-
- g_test_message("No common machine version for machine type '%s' between "
- "binaries %s and %s", mtype, getenv(var1), getenv(var2));
- g_assert_not_reached();
-}
-
-char *resolve_machine_version(const char *alias, const char *var1,
- const char *var2)
-{
- const char *mname = g_getenv("QTEST_QEMU_MACHINE_TYPE");
- g_autofree char *machine_name = NULL;
-
- if (mname) {
- const char *dash = strrchr(mname, '-');
- const char *dot = strrchr(mname, '.');
-
- machine_name = g_strdup(mname);
-
- if (dash && dot) {
- assert(qtest_has_machine(machine_name));
- return g_steal_pointer(&machine_name);
- }
- /* else: probably an alias, let it be resolved below */
- } else {
- /* use the hardcoded alias */
- machine_name = g_strdup(alias);
- }
-
- return find_common_machine_version(machine_name, var1, var2);
-}
-
-typedef struct {
- char *name;
- void (*func)(void);
-} MigrationTest;
-
-static void migration_test_destroy(gpointer data)
-{
- MigrationTest *test = (MigrationTest *)data;
-
- g_free(test->name);
- g_free(test);
-}
-
-static void migration_test_wrapper(const void *data)
-{
- MigrationTest *test = (MigrationTest *)data;
-
- g_test_message("Running /%s%s", qtest_get_arch(), test->name);
- test->func();
-}
-
-void migration_test_add(const char *path, void (*fn)(void))
-{
- MigrationTest *test = g_new0(MigrationTest, 1);
-
- test->func = fn;
- test->name = g_strdup(path);
-
- qtest_add_data_func_full(path, test, migration_test_wrapper,
- migration_test_destroy);
-}
-
-#ifdef O_DIRECT
-/*
- * Probe for O_DIRECT support on the filesystem. Since this is used
- * for tests, be conservative, if anything fails, assume it's
- * unsupported.
- */
-bool probe_o_direct_support(const char *tmpfs)
-{
- g_autofree char *filename = g_strdup_printf("%s/probe-o-direct", tmpfs);
- int fd, flags = O_CREAT | O_RDWR | O_TRUNC | O_DIRECT;
- void *buf;
- ssize_t ret, len;
- uint64_t offset;
-
- fd = open(filename, flags, 0660);
- if (fd < 0) {
- unlink(filename);
- return false;
- }
-
- /*
- * Using 1MB alignment as conservative choice to satisfy any
- * plausible architecture default page size, and/or filesystem
- * alignment restrictions.
- */
- len = 0x100000;
- offset = 0x100000;
-
- buf = qemu_try_memalign(len, len);
- g_assert(buf);
-
- ret = pwrite(fd, buf, len, offset);
- unlink(filename);
- g_free(buf);
-
- if (ret < 0) {
- return false;
- }
-
- return true;
-}
-#endif
-
-/*
- * Wait for a "MIGRATION" event. This is what Libvirt uses to track
- * migration status changes.
- */
-void migration_event_wait(QTestState *s, const char *target)
-{
- QDict *response, *data;
- const char *status;
- bool found;
-
- do {
- response = qtest_qmp_eventwait_ref(s, "MIGRATION");
- data = qdict_get_qdict(response, "data");
- g_assert(data);
- status = qdict_get_str(data, "status");
- found = (strcmp(status, target) == 0);
- qobject_unref(response);
- } while (!found);
-}
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 9d08101..0893687 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -11,3964 +11,56 @@
*/
#include "qemu/osdep.h"
-
-#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
+#include "migration/framework.h"
#include "qemu/module.h"
-#include "qemu/option.h"
-#include "qemu/range.h"
-#include "qemu/sockets.h"
-#include "chardev/char.h"
-#include "crypto/tlscredspsk.h"
-#include "qapi/qmp/qlist.h"
-#include "ppc-util.h"
-
-#include "migration-helpers.h"
-#include "tests/migration/migration-test.h"
-#ifdef CONFIG_GNUTLS
-# include "tests/unit/crypto-tls-psk-helpers.h"
-# ifdef CONFIG_TASN1
-# include "tests/unit/crypto-tls-x509-helpers.h"
-# endif /* CONFIG_TASN1 */
-#endif /* CONFIG_GNUTLS */
-
-/* For dirty ring test; so far only x86_64 is supported */
-#if defined(__linux__) && defined(HOST_X86_64)
-#include "linux/kvm.h"
-#endif
-
-unsigned start_address;
-unsigned end_address;
-static bool uffd_feature_thread_id;
-static QTestMigrationState src_state;
-static QTestMigrationState dst_state;
-
-/*
- * An initial 3 MB offset is used as that corresponds
- * to ~1 sec of data transfer with our bandwidth setting.
- */
-#define MAGIC_OFFSET_BASE (3 * 1024 * 1024)
-/*
- * A further 1k is added to ensure we're not a multiple
- * of TEST_MEM_PAGE_SIZE, thus avoid clash with writes
- * from the migration guest workload.
- */
-#define MAGIC_OFFSET_SHUFFLE 1024
-#define MAGIC_OFFSET (MAGIC_OFFSET_BASE + MAGIC_OFFSET_SHUFFLE)
-#define MAGIC_MARKER 0xFEED12345678CAFEULL
-
-/*
- * Dirtylimit stop working if dirty page rate error
- * value less than DIRTYLIMIT_TOLERANCE_RANGE
- */
-#define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */
-
-#define ANALYZE_SCRIPT "scripts/analyze-migration.py"
-
-#define QEMU_VM_FILE_MAGIC 0x5145564d
-#define FILE_TEST_FILENAME "migfile"
-#define FILE_TEST_OFFSET 0x1000
-#define FILE_TEST_MARKER 'X'
-#define QEMU_ENV_SRC "QTEST_QEMU_BINARY_SRC"
-#define QEMU_ENV_DST "QTEST_QEMU_BINARY_DST"
-
-typedef enum PostcopyRecoveryFailStage {
- /*
- * "no failure" must be 0 as it's the default. OTOH, real failure
- * cases must be >0 to make sure they trigger by a "if" test.
- */
- POSTCOPY_FAIL_NONE = 0,
- POSTCOPY_FAIL_CHANNEL_ESTABLISH,
- POSTCOPY_FAIL_RECOVERY,
- POSTCOPY_FAIL_MAX
-} PostcopyRecoveryFailStage;
-
-#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 "qemu/userfaultfd.h"
-
-static bool ufd_version_check(void)
-{
- struct uffdio_api api_struct;
- uint64_t ioctl_mask;
-
- int ufd = uffd_open(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 = 1ULL << _UFFDIO_REGISTER |
- 1ULL << _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 char *tmpfs;
-static char *bootpath;
-
-/* 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/ppc64/a-b-kernel.h"
-#include "tests/migration/s390x/a-b-bios.h"
-
-static void bootfile_delete(void)
-{
- if (!bootpath) {
- return;
- }
- unlink(bootpath);
- g_free(bootpath);
- bootpath = NULL;
-}
-
-static void bootfile_create(char *dir, bool suspend_me)
-{
- const char *arch = qtest_get_arch();
- unsigned char *content;
- size_t len;
-
- bootfile_delete();
- bootpath = g_strdup_printf("%s/bootsect", dir);
- if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
- /* the assembled x86 boot sector should be exactly one sector large */
- g_assert(sizeof(x86_bootsect) == 512);
- x86_bootsect[SYM_suspend_me - SYM_start] = suspend_me;
- content = x86_bootsect;
- len = sizeof(x86_bootsect);
- } else if (g_str_equal(arch, "s390x")) {
- content = s390x_elf;
- len = sizeof(s390x_elf);
- } else if (strcmp(arch, "ppc64") == 0) {
- content = ppc64_kernel;
- len = sizeof(ppc64_kernel);
- } else if (strcmp(arch, "aarch64") == 0) {
- content = aarch64_kernel;
- len = sizeof(aarch64_kernel);
- g_assert(sizeof(aarch64_kernel) <= ARM_TEST_MAX_KERNEL_SIZE);
- } else {
- g_assert_not_reached();
- }
-
- 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 (unless we enabled suspend/resume)
- */
-static void wait_for_serial(const char *side)
-{
- g_autofree char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
- FILE *serialfile = fopen(serialpath, "r");
-
- do {
- int readvalue = fgetc(serialfile);
-
- switch (readvalue) {
- case 'A':
- /* Fine */
- break;
-
- case 'B':
- /* It's alive! */
- fclose(serialfile);
- return;
-
- case EOF:
- 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);
-}
-
-static void wait_for_stop(QTestState *who, QTestMigrationState *state)
-{
- if (!state->stop_seen) {
- qtest_qmp_eventwait(who, "STOP");
- }
-}
-
-static void wait_for_resume(QTestState *who, QTestMigrationState *state)
-{
- if (!state->resume_seen) {
- qtest_qmp_eventwait(who, "RESUME");
- }
-}
-
-static void wait_for_suspend(QTestState *who, QTestMigrationState *state)
-{
- if (state->suspend_me && !state->suspend_seen) {
- qtest_qmp_eventwait(who, "SUSPEND");
- }
-}
-
-/*
- * 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_not_failed(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_not_failed(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_not_failed(who);
- g_assert(qdict_haskey(rsp_return, "postcopy-blocktime"));
- qobject_unref(rsp_return);
-}
-
-/*
- * Wait for two changes in the migration pass count, but bail if we stop.
- */
-static void wait_for_migration_pass(QTestState *who)
-{
- uint64_t pass, prev_pass = 0, changes = 0;
-
- while (changes < 2 && !src_state.stop_seen && !src_state.suspend_seen) {
- usleep(1000);
- pass = get_migration_pass(who);
- changes += (pass != prev_pass);
- prev_pass = pass;
- }
-}
-
-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)
-{
- g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, filename);
-
- unlink(path);
-}
-
-static long long migrate_get_parameter_int(QTestState *who,
- const char *parameter)
-{
- QDict *rsp;
- long long result;
-
- rsp = qtest_qmp_assert_success_ref(
- 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)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate-set-parameters',"
- "'arguments': { %s: %lld } }",
- parameter, value);
- migrate_check_parameter_int(who, parameter, value);
-}
-
-static char *migrate_get_parameter_str(QTestState *who,
- const char *parameter)
-{
- QDict *rsp;
- char *result;
-
- rsp = qtest_qmp_assert_success_ref(
- who, "{ 'execute': 'query-migrate-parameters' }");
- result = g_strdup(qdict_get_str(rsp, parameter));
- qobject_unref(rsp);
- return result;
-}
-
-static void migrate_check_parameter_str(QTestState *who, const char *parameter,
- const char *value)
-{
- g_autofree char *result = migrate_get_parameter_str(who, parameter);
- g_assert_cmpstr(result, ==, value);
-}
-
-static void migrate_set_parameter_str(QTestState *who, const char *parameter,
- const char *value)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate-set-parameters',"
- "'arguments': { %s: %s } }",
- parameter, value);
- migrate_check_parameter_str(who, parameter, value);
-}
-
-static long long migrate_get_parameter_bool(QTestState *who,
- const char *parameter)
-{
- QDict *rsp;
- int result;
-
- rsp = qtest_qmp_assert_success_ref(
- who, "{ 'execute': 'query-migrate-parameters' }");
- result = qdict_get_bool(rsp, parameter);
- qobject_unref(rsp);
- return !!result;
-}
-
-static void migrate_check_parameter_bool(QTestState *who, const char *parameter,
- int value)
-{
- int result;
-
- result = migrate_get_parameter_bool(who, parameter);
- g_assert_cmpint(result, ==, value);
-}
-
-static void migrate_set_parameter_bool(QTestState *who, const char *parameter,
- int value)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate-set-parameters',"
- "'arguments': { %s: %i } }",
- parameter, value);
- migrate_check_parameter_bool(who, parameter, value);
-}
-
-static void migrate_ensure_non_converge(QTestState *who)
-{
- /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
- migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
- migrate_set_parameter_int(who, "downtime-limit", 1);
-}
-
-static void migrate_ensure_converge(QTestState *who)
-{
- /* Should converge with 30s downtime + 1 gbs bandwidth limit */
- migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
- migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
-}
-
-/*
- * Our goal is to ensure that we run a single full migration
- * iteration, and also dirty memory, ensuring that at least
- * one further iteration is required.
- *
- * We can't directly synchronize with the start of a migration
- * so we have to apply some tricks monitoring memory that is
- * transferred.
- *
- * Initially we set the migration bandwidth to an insanely
- * low value, with tiny max downtime too. This basically
- * guarantees migration will never complete.
- *
- * This will result in a test that is unacceptably slow though,
- * so we can't let the entire migration pass run at this speed.
- * Our intent is to let it run just long enough that we can
- * prove data prior to the marker has been transferred *AND*
- * also prove this transferred data is dirty again.
- *
- * Before migration starts, we write a 64-bit magic marker
- * into a fixed location in the src VM RAM.
- *
- * Then watch dst memory until the marker appears. This is
- * proof that start_address -> MAGIC_OFFSET_BASE has been
- * transferred.
- *
- * Finally we go back to the source and read a byte just
- * before the marker until we see it flip in value. This
- * is proof that start_address -> MAGIC_OFFSET_BASE
- * is now dirty again.
- *
- * IOW, we're guaranteed at least a 2nd migration pass
- * at this point.
- *
- * We can now let migration run at full speed to finish
- * the test
- */
-static void migrate_prepare_for_dirty_mem(QTestState *from)
-{
- /*
- * The guest workflow iterates from start_address to
- * end_address, writing 1 byte every TEST_MEM_PAGE_SIZE
- * bytes.
- *
- * IOW, if we write to mem at a point which is NOT
- * a multiple of TEST_MEM_PAGE_SIZE, our write won't
- * conflict with the migration workflow.
- *
- * We put in a marker here, that we'll use to determine
- * when the data has been transferred to the dst.
- */
- qtest_writeq(from, start_address + MAGIC_OFFSET, MAGIC_MARKER);
-}
-
-static void migrate_wait_for_dirty_mem(QTestState *from,
- QTestState *to)
-{
- uint64_t watch_address = start_address + MAGIC_OFFSET_BASE;
- uint64_t marker_address = start_address + MAGIC_OFFSET;
- uint8_t watch_byte;
-
- /*
- * Wait for the MAGIC_MARKER to get transferred, as an
- * indicator that a migration pass has made some known
- * amount of progress.
- */
- do {
- usleep(1000 * 10);
- } while (qtest_readq(to, marker_address) != MAGIC_MARKER);
-
-
- /* If suspended, src only iterates once, and watch_byte may never change */
- if (src_state.suspend_me) {
- return;
- }
-
- /*
- * Now ensure that already transferred bytes are
- * dirty again from the guest workload. Note the
- * guest byte value will wrap around and by chance
- * match the original watch_byte. This is harmless
- * as we'll eventually see a different value if we
- * keep watching
- */
- watch_byte = qtest_readb(from, watch_address);
- do {
- usleep(1000 * 10);
- } while (qtest_readb(from, watch_address) == watch_byte);
-}
-
-
-static void migrate_pause(QTestState *who)
-{
- qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }");
-}
-
-static void migrate_continue(QTestState *who, const char *state)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate-continue',"
- " 'arguments': { 'state': %s } }",
- state);
-}
-
-static void migrate_recover(QTestState *who, const char *uri)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate-recover', "
- " 'id': 'recover-cmd', "
- " 'arguments': { 'uri': %s } }",
- uri);
-}
-
-static void migrate_cancel(QTestState *who)
-{
- qtest_qmp_assert_success(who, "{ 'execute': 'migrate_cancel' }");
-}
-
-static void migrate_postcopy_start(QTestState *from, QTestState *to)
-{
- qtest_qmp_assert_success(from, "{ 'execute': 'migrate-start-postcopy' }");
-
- wait_for_stop(from, &src_state);
- qtest_qmp_eventwait(to, "RESUME");
-}
-
-typedef struct {
- /*
- * QTEST_LOG=1 may override this. When QTEST_LOG=1, we always dump errors
- * unconditionally, because it means the user would like to be verbose.
- */
- bool hide_stderr;
- bool use_shmem;
- /* only launch the target process */
- bool only_target;
- /* Use dirty ring if true; dirty logging otherwise */
- bool use_dirty_ring;
- const char *opts_source;
- const char *opts_target;
- /* suspend the src before migrating to dest. */
- bool suspend_me;
-} MigrateStart;
-
-/*
- * A hook that runs after the src and dst QEMUs have been
- * created, but before the migration is started. This can
- * be used to set migration parameters and capabilities.
- *
- * Returns: NULL, or a pointer to opaque state to be
- * later passed to the TestMigrateFinishHook
- */
-typedef void * (*TestMigrateStartHook)(QTestState *from,
- QTestState *to);
-
-/*
- * A hook that runs after the migration has finished,
- * regardless of whether it succeeded or failed, but
- * before QEMU has terminated (unless it self-terminated
- * due to migration error)
- *
- * @opaque is a pointer to state previously returned
- * by the TestMigrateStartHook if any, or NULL.
- */
-typedef void (*TestMigrateFinishHook)(QTestState *from,
- QTestState *to,
- void *opaque);
-
-typedef struct {
- /* Optional: fine tune start parameters */
- MigrateStart start;
-
- /* Required: the URI for the dst QEMU to listen on */
- const char *listen_uri;
-
- /*
- * Optional: the URI for the src QEMU to connect to
- * If NULL, then it will query the dst QEMU for its actual
- * listening address and use that as the connect address.
- * This allows for dynamically picking a free TCP port.
- */
- const char *connect_uri;
-
- /*
- * Optional: JSON-formatted list of src QEMU URIs. If a port is
- * defined as '0' in any QDict key a value of '0' will be
- * automatically converted to the correct destination port.
- */
- const char *connect_channels;
-
- /* Optional: callback to run at start to set migration parameters */
- TestMigrateStartHook start_hook;
- /* Optional: callback to run at finish to cleanup */
- TestMigrateFinishHook finish_hook;
-
- /*
- * Optional: normally we expect the migration process to complete.
- *
- * There can be a variety of reasons and stages in which failure
- * can happen during tests.
- *
- * If a failure is expected to happen at time of establishing
- * the connection, then MIG_TEST_FAIL will indicate that the dst
- * QEMU is expected to stay running and accept future migration
- * connections.
- *
- * If a failure is expected to happen while processing the
- * migration stream, then MIG_TEST_FAIL_DEST_QUIT_ERR will indicate
- * that the dst QEMU is expected to quit with non-zero exit status
- */
- enum {
- /* This test should succeed, the default */
- MIG_TEST_SUCCEED = 0,
- /* This test should fail, dest qemu should keep alive */
- MIG_TEST_FAIL,
- /* This test should fail, dest qemu should fail with abnormal status */
- MIG_TEST_FAIL_DEST_QUIT_ERR,
- /* The QMP command for this migration should fail with an error */
- MIG_TEST_QMP_ERROR,
- } result;
-
- /*
- * Optional: set number of migration passes to wait for, if live==true.
- * If zero, then merely wait for a few MB of dirty data
- */
- unsigned int iterations;
-
- /*
- * Optional: whether the guest CPUs should be running during a precopy
- * migration test. We used to always run with live but it took much
- * longer so we reduced live tests to only the ones that have solid
- * reason to be tested live-only. For each of the new test cases for
- * precopy please provide justifications to use live explicitly (please
- * refer to existing ones with live=true), or use live=off by default.
- */
- bool live;
-
- /* Postcopy specific fields */
- void *postcopy_data;
- bool postcopy_preempt;
- PostcopyRecoveryFailStage postcopy_recovery_fail_stage;
-} MigrateCommon;
-
-static int test_migrate_start(QTestState **from, QTestState **to,
- const char *uri, MigrateStart *args)
-{
- g_autofree gchar *arch_source = NULL;
- g_autofree gchar *arch_target = NULL;
- /* options for source and target */
- g_autofree gchar *arch_opts = NULL;
- g_autofree gchar *cmd_source = NULL;
- g_autofree gchar *cmd_target = NULL;
- const gchar *ignore_stderr;
- g_autofree char *shmem_opts = NULL;
- g_autofree char *shmem_path = NULL;
- const char *kvm_opts = NULL;
- const char *arch = qtest_get_arch();
- const char *memory_size;
- const char *machine_alias, *machine_opts = "";
- g_autofree char *machine = NULL;
-
- 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;
- }
- }
-
- dst_state = (QTestMigrationState) { };
- src_state = (QTestMigrationState) { };
- bootfile_create(tmpfs, args->suspend_me);
- src_state.suspend_me = args->suspend_me;
-
- if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
- memory_size = "150M";
-
- if (g_str_equal(arch, "i386")) {
- machine_alias = "pc";
- } else {
- machine_alias = "q35";
- }
- arch_opts = g_strdup_printf(
- "-drive if=none,id=d0,file=%s,format=raw "
- "-device ide-hd,drive=d0,secs=1,cyls=1,heads=1", bootpath);
- start_address = X86_TEST_MEM_START;
- end_address = X86_TEST_MEM_END;
- } else if (g_str_equal(arch, "s390x")) {
- memory_size = "128M";
- machine_alias = "s390-ccw-virtio";
- arch_opts = g_strdup_printf("-bios %s", bootpath);
- start_address = S390_TEST_MEM_START;
- end_address = S390_TEST_MEM_END;
- } else if (strcmp(arch, "ppc64") == 0) {
- memory_size = "256M";
- start_address = PPC_TEST_MEM_START;
- end_address = PPC_TEST_MEM_END;
- machine_alias = "pseries";
- machine_opts = "vsmt=8";
- arch_opts = g_strdup_printf(
- "-nodefaults -machine " PSERIES_DEFAULT_CAPABILITIES " "
- "-bios %s", bootpath);
- } else if (strcmp(arch, "aarch64") == 0) {
- memory_size = "150M";
- machine_alias = "virt";
- machine_opts = "gic-version=3";
- arch_opts = g_strdup_printf("-cpu max -kernel %s", bootpath);
- start_address = ARM_TEST_MEM_START;
- end_address = ARM_TEST_MEM_END;
- } else {
- g_assert_not_reached();
- }
-
- if (!getenv("QTEST_LOG") && args->hide_stderr) {
-#ifndef _WIN32
- ignore_stderr = "2>/dev/null";
-#else
- /*
- * On Windows the QEMU executable is created via CreateProcess() and
- * IO redirection does not work, so don't bother adding IO redirection
- * to the command line.
- */
- ignore_stderr = "";
-#endif
- } 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);
- }
-
- if (args->use_dirty_ring) {
- kvm_opts = ",dirty-ring-size=4096";
- }
-
- if (!qtest_has_machine(machine_alias)) {
- g_autofree char *msg = g_strdup_printf("machine %s not supported", machine_alias);
- g_test_skip(msg);
- return -1;
- }
-
- machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC,
- QEMU_ENV_DST);
-
- g_test_message("Using machine type: %s", machine);
-
- cmd_source = g_strdup_printf("-accel kvm%s -accel tcg "
- "-machine %s,%s "
- "-name source,debug-threads=on "
- "-m %s "
- "-serial file:%s/src_serial "
- "%s %s %s %s %s",
- kvm_opts ? kvm_opts : "",
- machine, machine_opts,
- memory_size, tmpfs,
- arch_opts ? arch_opts : "",
- arch_source ? arch_source : "",
- shmem_opts ? shmem_opts : "",
- args->opts_source ? args->opts_source : "",
- ignore_stderr);
- if (!args->only_target) {
- *from = qtest_init_with_env(QEMU_ENV_SRC, cmd_source);
- qtest_qmp_set_event_callback(*from,
- migrate_watch_for_events,
- &src_state);
- }
-
- cmd_target = g_strdup_printf("-accel kvm%s -accel tcg "
- "-machine %s,%s "
- "-name target,debug-threads=on "
- "-m %s "
- "-serial file:%s/dest_serial "
- "-incoming %s "
- "%s %s %s %s %s",
- kvm_opts ? kvm_opts : "",
- machine, machine_opts,
- memory_size, tmpfs, uri,
- arch_opts ? arch_opts : "",
- arch_target ? arch_target : "",
- shmem_opts ? shmem_opts : "",
- args->opts_target ? args->opts_target : "",
- ignore_stderr);
- *to = qtest_init_with_env(QEMU_ENV_DST, cmd_target);
- qtest_qmp_set_event_callback(*to,
- migrate_watch_for_events,
- &dst_state);
-
- /*
- * Remove shmem file immediately to avoid memory leak in test failed case.
- * It's valid because QEMU has already opened this file
- */
- if (args->use_shmem) {
- unlink(shmem_path);
- }
-
- /*
- * Always enable migration events. Libvirt always uses it, let's try
- * to mimic as closer as that.
- */
- migrate_set_capability(*from, "events", true);
- migrate_set_capability(*to, "events", true);
-
- 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_assert_success(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("migsocket");
- cleanup("src_serial");
- cleanup("dest_serial");
- cleanup(FILE_TEST_FILENAME);
-}
-
-#ifdef CONFIG_GNUTLS
-struct TestMigrateTLSPSKData {
- char *workdir;
- char *workdiralt;
- char *pskfile;
- char *pskfilealt;
-};
-
-static void *
-test_migrate_tls_psk_start_common(QTestState *from,
- QTestState *to,
- bool mismatch)
-{
- struct TestMigrateTLSPSKData *data =
- g_new0(struct TestMigrateTLSPSKData, 1);
-
- data->workdir = g_strdup_printf("%s/tlscredspsk0", tmpfs);
- data->pskfile = g_strdup_printf("%s/%s", data->workdir,
- QCRYPTO_TLS_CREDS_PSKFILE);
- g_mkdir_with_parents(data->workdir, 0700);
- test_tls_psk_init(data->pskfile);
-
- if (mismatch) {
- data->workdiralt = g_strdup_printf("%s/tlscredspskalt0", tmpfs);
- data->pskfilealt = g_strdup_printf("%s/%s", data->workdiralt,
- QCRYPTO_TLS_CREDS_PSKFILE);
- g_mkdir_with_parents(data->workdiralt, 0700);
- test_tls_psk_init_alt(data->pskfilealt);
- }
-
- qtest_qmp_assert_success(from,
- "{ 'execute': 'object-add',"
- " 'arguments': { 'qom-type': 'tls-creds-psk',"
- " 'id': 'tlscredspsk0',"
- " 'endpoint': 'client',"
- " 'dir': %s,"
- " 'username': 'qemu'} }",
- data->workdir);
-
- qtest_qmp_assert_success(to,
- "{ 'execute': 'object-add',"
- " 'arguments': { 'qom-type': 'tls-creds-psk',"
- " 'id': 'tlscredspsk0',"
- " 'endpoint': 'server',"
- " 'dir': %s } }",
- mismatch ? data->workdiralt : data->workdir);
-
- migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0");
- migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0");
-
- return data;
-}
-
-static void *
-test_migrate_tls_psk_start_match(QTestState *from,
- QTestState *to)
-{
- return test_migrate_tls_psk_start_common(from, to, false);
-}
-
-static void *
-test_migrate_tls_psk_start_mismatch(QTestState *from,
- QTestState *to)
-{
- return test_migrate_tls_psk_start_common(from, to, true);
-}
-
-static void
-test_migrate_tls_psk_finish(QTestState *from,
- QTestState *to,
- void *opaque)
-{
- struct TestMigrateTLSPSKData *data = opaque;
-
- test_tls_psk_cleanup(data->pskfile);
- if (data->pskfilealt) {
- test_tls_psk_cleanup(data->pskfilealt);
- }
- rmdir(data->workdir);
- if (data->workdiralt) {
- rmdir(data->workdiralt);
- }
-
- g_free(data->workdiralt);
- g_free(data->pskfilealt);
- g_free(data->workdir);
- g_free(data->pskfile);
- g_free(data);
-}
-
-#ifdef CONFIG_TASN1
-typedef struct {
- char *workdir;
- char *keyfile;
- char *cacert;
- char *servercert;
- char *serverkey;
- char *clientcert;
- char *clientkey;
-} TestMigrateTLSX509Data;
-
-typedef struct {
- bool verifyclient;
- bool clientcert;
- bool hostileclient;
- bool authzclient;
- const char *certhostname;
- const char *certipaddr;
-} TestMigrateTLSX509;
-
-static void *
-test_migrate_tls_x509_start_common(QTestState *from,
- QTestState *to,
- TestMigrateTLSX509 *args)
-{
- TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1);
-
- data->workdir = g_strdup_printf("%s/tlscredsx5090", tmpfs);
- data->keyfile = g_strdup_printf("%s/key.pem", data->workdir);
-
- data->cacert = g_strdup_printf("%s/ca-cert.pem", data->workdir);
- data->serverkey = g_strdup_printf("%s/server-key.pem", data->workdir);
- data->servercert = g_strdup_printf("%s/server-cert.pem", data->workdir);
- if (args->clientcert) {
- data->clientkey = g_strdup_printf("%s/client-key.pem", data->workdir);
- data->clientcert = g_strdup_printf("%s/client-cert.pem", data->workdir);
- }
-
- g_mkdir_with_parents(data->workdir, 0700);
-
- test_tls_init(data->keyfile);
-#ifndef _WIN32
- g_assert(link(data->keyfile, data->serverkey) == 0);
-#else
- g_assert(CreateHardLink(data->serverkey, data->keyfile, NULL) != 0);
-#endif
- if (args->clientcert) {
-#ifndef _WIN32
- g_assert(link(data->keyfile, data->clientkey) == 0);
-#else
- g_assert(CreateHardLink(data->clientkey, data->keyfile, NULL) != 0);
-#endif
- }
-
- TLS_ROOT_REQ_SIMPLE(cacertreq, data->cacert);
- if (args->clientcert) {
- TLS_CERT_REQ_SIMPLE_CLIENT(servercertreq, cacertreq,
- args->hostileclient ?
- QCRYPTO_TLS_TEST_CLIENT_HOSTILE_NAME :
- QCRYPTO_TLS_TEST_CLIENT_NAME,
- data->clientcert);
- test_tls_deinit_cert(&servercertreq);
- }
-
- TLS_CERT_REQ_SIMPLE_SERVER(clientcertreq, cacertreq,
- data->servercert,
- args->certhostname,
- args->certipaddr);
- test_tls_deinit_cert(&clientcertreq);
- test_tls_deinit_cert(&cacertreq);
-
- qtest_qmp_assert_success(from,
- "{ 'execute': 'object-add',"
- " 'arguments': { 'qom-type': 'tls-creds-x509',"
- " 'id': 'tlscredsx509client0',"
- " 'endpoint': 'client',"
- " 'dir': %s,"
- " 'sanity-check': true,"
- " 'verify-peer': true} }",
- data->workdir);
- migrate_set_parameter_str(from, "tls-creds", "tlscredsx509client0");
- if (args->certhostname) {
- migrate_set_parameter_str(from, "tls-hostname", args->certhostname);
- }
-
- qtest_qmp_assert_success(to,
- "{ 'execute': 'object-add',"
- " 'arguments': { 'qom-type': 'tls-creds-x509',"
- " 'id': 'tlscredsx509server0',"
- " 'endpoint': 'server',"
- " 'dir': %s,"
- " 'sanity-check': true,"
- " 'verify-peer': %i} }",
- data->workdir, args->verifyclient);
- migrate_set_parameter_str(to, "tls-creds", "tlscredsx509server0");
-
- if (args->authzclient) {
- qtest_qmp_assert_success(to,
- "{ 'execute': 'object-add',"
- " 'arguments': { 'qom-type': 'authz-simple',"
- " 'id': 'tlsauthz0',"
- " 'identity': %s} }",
- "CN=" QCRYPTO_TLS_TEST_CLIENT_NAME);
- migrate_set_parameter_str(to, "tls-authz", "tlsauthz0");
- }
-
- return data;
-}
-
-/*
- * The normal case: match server's cert hostname against
- * whatever host we were telling QEMU to connect to (if any)
- */
-static void *
-test_migrate_tls_x509_start_default_host(QTestState *from,
- QTestState *to)
-{
- TestMigrateTLSX509 args = {
- .verifyclient = true,
- .clientcert = true,
- .certipaddr = "127.0.0.1"
- };
- return test_migrate_tls_x509_start_common(from, to, &args);
-}
-
-/*
- * The unusual case: the server's cert is different from
- * the address we're telling QEMU to connect to (if any),
- * so we must give QEMU an explicit hostname to validate
- */
-static void *
-test_migrate_tls_x509_start_override_host(QTestState *from,
- QTestState *to)
-{
- TestMigrateTLSX509 args = {
- .verifyclient = true,
- .clientcert = true,
- .certhostname = "qemu.org",
- };
- return test_migrate_tls_x509_start_common(from, to, &args);
-}
-
-/*
- * The unusual case: the server's cert is different from
- * the address we're telling QEMU to connect to, and so we
- * expect the client to reject the server
- */
-static void *
-test_migrate_tls_x509_start_mismatch_host(QTestState *from,
- QTestState *to)
-{
- TestMigrateTLSX509 args = {
- .verifyclient = true,
- .clientcert = true,
- .certipaddr = "10.0.0.1",
- };
- return test_migrate_tls_x509_start_common(from, to, &args);
-}
-
-static void *
-test_migrate_tls_x509_start_friendly_client(QTestState *from,
- QTestState *to)
-{
- TestMigrateTLSX509 args = {
- .verifyclient = true,
- .clientcert = true,
- .authzclient = true,
- .certipaddr = "127.0.0.1",
- };
- return test_migrate_tls_x509_start_common(from, to, &args);
-}
-
-static void *
-test_migrate_tls_x509_start_hostile_client(QTestState *from,
- QTestState *to)
-{
- TestMigrateTLSX509 args = {
- .verifyclient = true,
- .clientcert = true,
- .hostileclient = true,
- .authzclient = true,
- .certipaddr = "127.0.0.1",
- };
- return test_migrate_tls_x509_start_common(from, to, &args);
-}
-
-/*
- * The case with no client certificate presented,
- * and no server verification
- */
-static void *
-test_migrate_tls_x509_start_allow_anon_client(QTestState *from,
- QTestState *to)
-{
- TestMigrateTLSX509 args = {
- .certipaddr = "127.0.0.1",
- };
- return test_migrate_tls_x509_start_common(from, to, &args);
-}
-
-/*
- * The case with no client certificate presented,
- * and server verification rejecting
- */
-static void *
-test_migrate_tls_x509_start_reject_anon_client(QTestState *from,
- QTestState *to)
-{
- TestMigrateTLSX509 args = {
- .verifyclient = true,
- .certipaddr = "127.0.0.1",
- };
- return test_migrate_tls_x509_start_common(from, to, &args);
-}
-
-static void
-test_migrate_tls_x509_finish(QTestState *from,
- QTestState *to,
- void *opaque)
-{
- TestMigrateTLSX509Data *data = opaque;
-
- test_tls_cleanup(data->keyfile);
- g_free(data->keyfile);
-
- unlink(data->cacert);
- g_free(data->cacert);
- unlink(data->servercert);
- g_free(data->servercert);
- unlink(data->serverkey);
- g_free(data->serverkey);
-
- if (data->clientcert) {
- unlink(data->clientcert);
- g_free(data->clientcert);
- }
- if (data->clientkey) {
- unlink(data->clientkey);
- g_free(data->clientkey);
- }
-
- rmdir(data->workdir);
- g_free(data->workdir);
-
- g_free(data);
-}
-#endif /* CONFIG_TASN1 */
-#endif /* CONFIG_GNUTLS */
-
-static int migrate_postcopy_prepare(QTestState **from_ptr,
- QTestState **to_ptr,
- MigrateCommon *args)
-{
- QTestState *from, *to;
-
- if (test_migrate_start(&from, &to, "defer", &args->start)) {
- return -1;
- }
-
- if (args->start_hook) {
- args->postcopy_data = args->start_hook(from, to);
- }
-
- migrate_set_capability(from, "postcopy-ram", true);
- migrate_set_capability(to, "postcopy-ram", true);
- migrate_set_capability(to, "postcopy-blocktime", true);
-
- if (args->postcopy_preempt) {
- migrate_set_capability(from, "postcopy-preempt", true);
- migrate_set_capability(to, "postcopy-preempt", true);
- }
-
- migrate_ensure_non_converge(from);
-
- migrate_prepare_for_dirty_mem(from);
- qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
- " 'arguments': { "
- " 'channels': [ { 'channel-type': 'main',"
- " 'addr': { 'transport': 'socket',"
- " 'type': 'inet',"
- " 'host': '127.0.0.1',"
- " 'port': '0' } } ] } }");
-
- /* Wait for the first serial output from the source */
- wait_for_serial("src_serial");
- wait_for_suspend(from, &src_state);
-
- migrate_qmp(from, to, NULL, NULL, "{}");
-
- migrate_wait_for_dirty_mem(from, to);
-
- *from_ptr = from;
- *to_ptr = to;
-
- return 0;
-}
-
-static void migrate_postcopy_complete(QTestState *from, QTestState *to,
- MigrateCommon *args)
-{
- wait_for_migration_complete(from);
-
- if (args->start.suspend_me) {
- /* wakeup succeeds only if guest is suspended */
- qtest_qmp_assert_success(to, "{'execute': 'system_wakeup'}");
- }
-
- /* Make sure we get at least one "B" on destination */
- wait_for_serial("dest_serial");
-
- if (uffd_feature_thread_id) {
- read_blocktime(to);
- }
-
- if (args->finish_hook) {
- args->finish_hook(from, to, args->postcopy_data);
- args->postcopy_data = NULL;
- }
-
- test_migrate_end(from, to, true);
-}
-
-static void test_postcopy_common(MigrateCommon *args)
-{
- QTestState *from, *to;
-
- if (migrate_postcopy_prepare(&from, &to, args)) {
- return;
- }
- migrate_postcopy_start(from, to);
- migrate_postcopy_complete(from, to, args);
-}
-
-static void test_postcopy(void)
-{
- MigrateCommon args = { };
-
- test_postcopy_common(&args);
-}
-
-static void test_postcopy_suspend(void)
-{
- MigrateCommon args = {
- .start.suspend_me = true,
- };
-
- test_postcopy_common(&args);
-}
-
-static void test_postcopy_preempt(void)
-{
- MigrateCommon args = {
- .postcopy_preempt = true,
- };
-
- test_postcopy_common(&args);
-}
-
-#ifdef CONFIG_GNUTLS
-static void test_postcopy_tls_psk(void)
-{
- MigrateCommon args = {
- .start_hook = test_migrate_tls_psk_start_match,
- .finish_hook = test_migrate_tls_psk_finish,
- };
-
- test_postcopy_common(&args);
-}
-
-static void test_postcopy_preempt_tls_psk(void)
-{
- MigrateCommon args = {
- .postcopy_preempt = true,
- .start_hook = test_migrate_tls_psk_start_match,
- .finish_hook = test_migrate_tls_psk_finish,
- };
-
- test_postcopy_common(&args);
-}
-#endif
-
-static void wait_for_postcopy_status(QTestState *one, const char *status)
-{
- wait_for_migration_status(one, status,
- (const char * []) { "failed", "active",
- "completed", NULL });
-}
-
-static void postcopy_recover_fail(QTestState *from, QTestState *to,
- PostcopyRecoveryFailStage stage)
-{
-#ifndef _WIN32
- bool fail_early = (stage == POSTCOPY_FAIL_CHANNEL_ESTABLISH);
- int ret, pair1[2], pair2[2];
- char c;
-
- g_assert(stage > POSTCOPY_FAIL_NONE && stage < POSTCOPY_FAIL_MAX);
-
- /* Create two unrelated socketpairs */
- ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair1);
- g_assert_cmpint(ret, ==, 0);
-
- ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair2);
- g_assert_cmpint(ret, ==, 0);
-
- /*
- * Give the guests unpaired ends of the sockets, so they'll all blocked
- * at reading. This mimics a wrong channel established.
- */
- qtest_qmp_fds_assert_success(from, &pair1[0], 1,
- "{ 'execute': 'getfd',"
- " 'arguments': { 'fdname': 'fd-mig' }}");
- qtest_qmp_fds_assert_success(to, &pair2[0], 1,
- "{ 'execute': 'getfd',"
- " 'arguments': { 'fdname': 'fd-mig' }}");
-
- /*
- * Write the 1st byte as QEMU_VM_COMMAND (0x8) for the dest socket, to
- * emulate the 1st byte of a real recovery, but stops from there to
- * keep dest QEMU in RECOVER. This is needed so that we can kick off
- * the recover process on dest QEMU (by triggering the G_IO_IN event).
- *
- * NOTE: this trick is not needed on src QEMUs, because src doesn't
- * rely on an pre-existing G_IO_IN event, so it will always trigger the
- * upcoming recovery anyway even if it can read nothing.
- */
-#define QEMU_VM_COMMAND 0x08
- c = QEMU_VM_COMMAND;
- ret = send(pair2[1], &c, 1, 0);
- g_assert_cmpint(ret, ==, 1);
-
- if (stage == POSTCOPY_FAIL_CHANNEL_ESTABLISH) {
- /*
- * This will make src QEMU to fail at an early stage when trying to
- * resume later, where it shouldn't reach RECOVER stage at all.
- */
- close(pair1[1]);
- }
-
- migrate_recover(to, "fd:fd-mig");
- migrate_qmp(from, to, "fd:fd-mig", NULL, "{'resume': true}");
-
- /*
- * Source QEMU has an extra RECOVER_SETUP phase, dest doesn't have it.
- * Make sure it appears along the way.
- */
- migration_event_wait(from, "postcopy-recover-setup");
-
- if (fail_early) {
- /*
- * When fails at reconnection, src QEMU will automatically goes
- * back to PAUSED state. Making sure there is an event in this
- * case: Libvirt relies on this to detect early reconnection
- * errors.
- */
- migration_event_wait(from, "postcopy-paused");
- } else {
- /*
- * We want to test "fail later" at RECOVER stage here. Make sure
- * both QEMU instances will go into RECOVER stage first, then test
- * kicking them out using migrate-pause.
- *
- * Explicitly check the RECOVER event on src, that's what Libvirt
- * relies on, rather than polling.
- */
- migration_event_wait(from, "postcopy-recover");
- wait_for_postcopy_status(from, "postcopy-recover");
-
- /* Need an explicit kick on src QEMU in this case */
- migrate_pause(from);
- }
-
- /*
- * For all failure cases, we'll reach such states on both sides now.
- * Check them.
- */
- wait_for_postcopy_status(from, "postcopy-paused");
- wait_for_postcopy_status(to, "postcopy-recover");
-
- /*
- * Kick dest QEMU out too. This is normally not needed in reality
- * because when the channel is shutdown it should also happen on src.
- * However here we used separate socket pairs so we need to do that
- * explicitly.
- */
- migrate_pause(to);
- wait_for_postcopy_status(to, "postcopy-paused");
-
- close(pair1[0]);
- close(pair2[0]);
- close(pair2[1]);
-
- if (stage != POSTCOPY_FAIL_CHANNEL_ESTABLISH) {
- close(pair1[1]);
- }
-#endif
-}
-
-static void test_postcopy_recovery_common(MigrateCommon *args)
-{
- QTestState *from, *to;
- g_autofree char *uri = NULL;
-
- /* Always hide errors for postcopy recover tests since they're expected */
- args->start.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_postcopy_status(to, "postcopy-paused");
- wait_for_postcopy_status(from, "postcopy-paused");
-
- if (args->postcopy_recovery_fail_stage) {
- /*
- * Test when a wrong socket specified for recover, and then the
- * ability to kick it out, and continue with a correct socket.
- */
- postcopy_recover_fail(from, to, args->postcopy_recovery_fail_stage);
- /* continue with a good recovery */
- }
-
- /*
- * 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
- */
- migrate_qmp(from, to, uri, NULL, "{'resume': true}");
-
- /* Restore the postcopy bandwidth to unlimited */
- migrate_set_parameter_int(from, "max-postcopy-bandwidth", 0);
-
- migrate_postcopy_complete(from, to, args);
-}
-
-static void test_postcopy_recovery(void)
-{
- MigrateCommon args = { };
-
- test_postcopy_recovery_common(&args);
-}
-
-static void test_postcopy_recovery_fail_handshake(void)
-{
- MigrateCommon args = {
- .postcopy_recovery_fail_stage = POSTCOPY_FAIL_RECOVERY,
- };
-
- test_postcopy_recovery_common(&args);
-}
-
-static void test_postcopy_recovery_fail_reconnect(void)
-{
- MigrateCommon args = {
- .postcopy_recovery_fail_stage = POSTCOPY_FAIL_CHANNEL_ESTABLISH,
- };
-
- test_postcopy_recovery_common(&args);
-}
-
-#ifdef CONFIG_GNUTLS
-static void test_postcopy_recovery_tls_psk(void)
-{
- MigrateCommon args = {
- .start_hook = test_migrate_tls_psk_start_match,
- .finish_hook = test_migrate_tls_psk_finish,
- };
-
- test_postcopy_recovery_common(&args);
-}
-#endif
-
-static void test_postcopy_preempt_recovery(void)
-{
- MigrateCommon args = {
- .postcopy_preempt = true,
- };
-
- test_postcopy_recovery_common(&args);
-}
-
-#ifdef CONFIG_GNUTLS
-/* This contains preempt+recovery+tls test altogether */
-static void test_postcopy_preempt_all(void)
-{
- MigrateCommon args = {
- .postcopy_preempt = true,
- .start_hook = test_migrate_tls_psk_start_match,
- .finish_hook = test_migrate_tls_psk_finish,
- };
-
- test_postcopy_recovery_common(&args);
-}
-
-#endif
-
-static void test_baddest(void)
-{
- MigrateStart args = {
- .hide_stderr = true
- };
- QTestState *from, *to;
-
- if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) {
- return;
- }
- migrate_qmp(from, to, "tcp:127.0.0.1:0", NULL, "{}");
- wait_for_migration_fail(from, false);
- test_migrate_end(from, to, false);
-}
-
-#ifndef _WIN32
-static void test_analyze_script(void)
-{
- MigrateStart args = {
- .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
- };
- QTestState *from, *to;
- g_autofree char *uri = NULL;
- g_autofree char *file = NULL;
- int pid, wstatus;
- const char *python = g_getenv("PYTHON");
-
- if (!python) {
- g_test_skip("PYTHON variable not set");
- return;
- }
-
- /* dummy url */
- if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) {
- return;
- }
-
- /*
- * Setting these two capabilities causes the "configuration"
- * vmstate to include subsections for them. The script needs to
- * parse those subsections properly.
- */
- migrate_set_capability(from, "validate-uuid", true);
- migrate_set_capability(from, "x-ignore-shared", true);
-
- file = g_strdup_printf("%s/migfile", tmpfs);
- uri = g_strdup_printf("exec:cat > %s", file);
-
- migrate_ensure_converge(from);
- migrate_qmp(from, to, uri, NULL, "{}");
- wait_for_migration_complete(from);
-
- pid = fork();
- if (!pid) {
- close(1);
- open("/dev/null", O_WRONLY);
- execl(python, python, ANALYZE_SCRIPT, "-f", file, NULL);
- g_assert_not_reached();
- }
-
- g_assert(waitpid(pid, &wstatus, 0) == pid);
- if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) {
- g_test_message("Failed to analyze the migration stream");
- g_test_fail();
- }
- test_migrate_end(from, to, false);
- cleanup("migfile");
-}
-#endif
-
-static void test_precopy_common(MigrateCommon *args)
-{
- QTestState *from, *to;
- void *data_hook = NULL;
-
- if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) {
- return;
- }
-
- if (args->start_hook) {
- data_hook = args->start_hook(from, to);
- }
-
- /* Wait for the first serial output from the source */
- if (args->result == MIG_TEST_SUCCEED) {
- wait_for_serial("src_serial");
- wait_for_suspend(from, &src_state);
- }
-
- if (args->live) {
- migrate_ensure_non_converge(from);
- migrate_prepare_for_dirty_mem(from);
- } else {
- /*
- * Testing non-live migration, we allow it to run at
- * full speed to ensure short test case duration.
- * For tests expected to fail, we don't need to
- * change anything.
- */
- if (args->result == MIG_TEST_SUCCEED) {
- qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
- wait_for_stop(from, &src_state);
- migrate_ensure_converge(from);
- }
- }
-
- if (args->result == MIG_TEST_QMP_ERROR) {
- migrate_qmp_fail(from, args->connect_uri, args->connect_channels, "{}");
- goto finish;
- }
-
- migrate_qmp(from, to, args->connect_uri, args->connect_channels, "{}");
-
- if (args->result != MIG_TEST_SUCCEED) {
- bool allow_active = args->result == MIG_TEST_FAIL;
- wait_for_migration_fail(from, allow_active);
-
- if (args->result == MIG_TEST_FAIL_DEST_QUIT_ERR) {
- qtest_set_expected_status(to, EXIT_FAILURE);
- }
- } else {
- if (args->live) {
- /*
- * For initial iteration(s) we must do a full pass,
- * but for the final iteration, we need only wait
- * for some dirty mem before switching to converge
- */
- while (args->iterations > 1) {
- wait_for_migration_pass(from);
- args->iterations--;
- }
- migrate_wait_for_dirty_mem(from, to);
-
- migrate_ensure_converge(from);
-
- /*
- * We do this first, as it has a timeout to stop us
- * hanging forever if migration didn't converge
- */
- wait_for_migration_complete(from);
-
- wait_for_stop(from, &src_state);
-
- } else {
- wait_for_migration_complete(from);
- /*
- * Must wait for dst to finish reading all incoming
- * data on the socket before issuing 'cont' otherwise
- * it'll be ignored
- */
- wait_for_migration_complete(to);
-
- qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}");
- }
-
- wait_for_resume(to, &dst_state);
-
- if (args->start.suspend_me) {
- /* wakeup succeeds only if guest is suspended */
- qtest_qmp_assert_success(to, "{'execute': 'system_wakeup'}");
- }
-
- wait_for_serial("dest_serial");
- }
-
-finish:
- if (args->finish_hook) {
- args->finish_hook(from, to, data_hook);
- }
-
- test_migrate_end(from, to, args->result == MIG_TEST_SUCCEED);
-}
-
-static void file_dirty_offset_region(void)
-{
- g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
- size_t size = FILE_TEST_OFFSET;
- g_autofree char *data = g_new0(char, size);
-
- memset(data, FILE_TEST_MARKER, size);
- g_assert(g_file_set_contents(path, data, size, NULL));
-}
-
-static void file_check_offset_region(void)
-{
- g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
- size_t size = FILE_TEST_OFFSET;
- g_autofree char *expected = g_new0(char, size);
- g_autofree char *actual = NULL;
- uint64_t *stream_start;
-
- /*
- * Ensure the skipped offset region's data has not been touched
- * and the migration stream starts at the right place.
- */
-
- memset(expected, FILE_TEST_MARKER, size);
-
- g_assert(g_file_get_contents(path, &actual, NULL, NULL));
- g_assert(!memcmp(actual, expected, size));
-
- stream_start = (uint64_t *)(actual + size);
- g_assert_cmpint(cpu_to_be64(*stream_start) >> 32, ==, QEMU_VM_FILE_MAGIC);
-}
-
-static void test_file_common(MigrateCommon *args, bool stop_src)
-{
- QTestState *from, *to;
- void *data_hook = NULL;
- bool check_offset = false;
-
- if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) {
- return;
- }
-
- /*
- * File migration is never live. We can keep the source VM running
- * during migration, but the destination will not be running
- * concurrently.
- */
- g_assert_false(args->live);
-
- if (g_strrstr(args->connect_uri, "offset=")) {
- check_offset = true;
- /*
- * This comes before the start_hook because it's equivalent to
- * a management application creating the file and writing to
- * it so hooks should expect the file to be already present.
- */
- file_dirty_offset_region();
- }
-
- if (args->start_hook) {
- data_hook = args->start_hook(from, to);
- }
-
- migrate_ensure_converge(from);
- wait_for_serial("src_serial");
-
- if (stop_src) {
- qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
- wait_for_stop(from, &src_state);
- }
-
- if (args->result == MIG_TEST_QMP_ERROR) {
- migrate_qmp_fail(from, args->connect_uri, NULL, "{}");
- goto finish;
- }
-
- migrate_qmp(from, to, args->connect_uri, NULL, "{}");
- wait_for_migration_complete(from);
-
- /*
- * We need to wait for the source to finish before starting the
- * destination.
- */
- migrate_incoming_qmp(to, args->connect_uri, "{}");
- wait_for_migration_complete(to);
-
- if (stop_src) {
- qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}");
- }
- wait_for_resume(to, &dst_state);
-
- wait_for_serial("dest_serial");
-
- if (check_offset) {
- file_check_offset_region();
- }
-
-finish:
- if (args->finish_hook) {
- args->finish_hook(from, to, data_hook);
- }
-
- test_migrate_end(from, to, args->result == MIG_TEST_SUCCEED);
-}
-
-static void test_precopy_unix_plain(void)
-{
- g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
- MigrateCommon args = {
- .listen_uri = uri,
- .connect_uri = uri,
- /*
- * The simplest use case of precopy, covering smoke tests of
- * get-dirty-log dirty tracking.
- */
- .live = true,
- };
-
- test_precopy_common(&args);
-}
-
-static void test_precopy_unix_suspend_live(void)
-{
- g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
- MigrateCommon args = {
- .listen_uri = uri,
- .connect_uri = uri,
- /*
- * despite being live, the test is fast because the src
- * suspends immediately.
- */
- .live = true,
- .start.suspend_me = true,
- };
-
- test_precopy_common(&args);
-}
-
-static void test_precopy_unix_suspend_notlive(void)
-{
- g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
- MigrateCommon args = {
- .listen_uri = uri,
- .connect_uri = uri,
- .start.suspend_me = true,
- };
-
- test_precopy_common(&args);
-}
-
-static void test_precopy_unix_dirty_ring(void)
-{
- g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
- MigrateCommon args = {
- .start = {
- .use_dirty_ring = true,
- },
- .listen_uri = uri,
- .connect_uri = uri,
- /*
- * Besides the precopy/unix basic test, cover dirty ring interface
- * rather than get-dirty-log.
- */
- .live = true,
- };
-
- test_precopy_common(&args);
-}
-
-#ifdef CONFIG_GNUTLS
-static void test_precopy_unix_tls_psk(void)
-{
- g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = uri,
- .start_hook = test_migrate_tls_psk_start_match,
- .finish_hook = test_migrate_tls_psk_finish,
- };
-
- test_precopy_common(&args);
-}
-
-#ifdef CONFIG_TASN1
-static void test_precopy_unix_tls_x509_default_host(void)
-{
- g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
- MigrateCommon args = {
- .start = {
- .hide_stderr = true,
- },
- .connect_uri = uri,
- .listen_uri = uri,
- .start_hook = test_migrate_tls_x509_start_default_host,
- .finish_hook = test_migrate_tls_x509_finish,
- .result = MIG_TEST_FAIL_DEST_QUIT_ERR,
- };
- test_precopy_common(&args);
-}
-
-static void test_precopy_unix_tls_x509_override_host(void)
+static void parse_args(int *argc_p, char ***argv_p, bool *full_set)
{
- g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = uri,
- .start_hook = test_migrate_tls_x509_start_override_host,
- .finish_hook = test_migrate_tls_x509_finish,
- };
-
- test_precopy_common(&args);
-}
-#endif /* CONFIG_TASN1 */
-#endif /* CONFIG_GNUTLS */
-
-#if 0
-/* Currently upset on aarch64 TCG */
-static void test_ignore_shared(void)
-{
- g_autofree 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_ensure_non_converge(from);
- migrate_prepare_for_dirty_mem(from);
+ int argc = *argc_p;
+ char **argv = *argv_p;
+ int i, j;
- 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, to, uri, NULL, "{}");
-
- migrate_wait_for_dirty_mem(from, to);
-
- wait_for_stop(from, &src_state);
-
- 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);
-}
-#endif
-
-static void *
-test_migrate_xbzrle_start(QTestState *from,
- QTestState *to)
-{
- migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432);
-
- migrate_set_capability(from, "xbzrle", true);
- migrate_set_capability(to, "xbzrle", true);
-
- return NULL;
-}
-
-static void test_precopy_unix_xbzrle(void)
-{
- g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = uri,
- .start_hook = test_migrate_xbzrle_start,
- .iterations = 2,
- /*
- * XBZRLE needs pages to be modified when doing the 2nd+ round
- * iteration to have real data pushed to the stream.
- */
- .live = true,
- };
-
- test_precopy_common(&args);
-}
-
-static void test_precopy_file(void)
-{
- g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
- FILE_TEST_FILENAME);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = "defer",
- };
-
- test_file_common(&args, true);
-}
-
-#ifndef _WIN32
-static void fdset_add_fds(QTestState *qts, const char *file, int flags,
- int num_fds, bool direct_io)
-{
- for (int i = 0; i < num_fds; i++) {
- int fd;
-
-#ifdef O_DIRECT
- /* only secondary channels can use direct-io */
- if (direct_io && i != 0) {
- flags |= O_DIRECT;
+ j = 1;
+ for (i = 1; i < argc; i++) {
+ if (g_str_equal(argv[i], "--full")) {
+ *full_set = true;
+ continue;
}
-#endif
-
- fd = open(file, flags, 0660);
- assert(fd != -1);
-
- qtest_qmp_fds_assert_success(qts, &fd, 1, "{'execute': 'add-fd', "
- "'arguments': {'fdset-id': 1}}");
- close(fd);
- }
-}
-
-static void *file_offset_fdset_start_hook(QTestState *from, QTestState *to)
-{
- g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
-
- fdset_add_fds(from, file, O_WRONLY, 1, false);
- fdset_add_fds(to, file, O_RDONLY, 1, false);
-
- return NULL;
-}
-
-static void test_precopy_file_offset_fdset(void)
-{
- g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
- FILE_TEST_OFFSET);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = "defer",
- .start_hook = file_offset_fdset_start_hook,
- };
-
- test_file_common(&args, false);
-}
-#endif
-
-static void test_precopy_file_offset(void)
-{
- g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=%d", tmpfs,
- FILE_TEST_FILENAME,
- FILE_TEST_OFFSET);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = "defer",
- };
-
- test_file_common(&args, false);
-}
-
-static void test_precopy_file_offset_bad(void)
-{
- /* using a value not supported by qemu_strtosz() */
- g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=0x20M",
- tmpfs, FILE_TEST_FILENAME);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = "defer",
- .result = MIG_TEST_QMP_ERROR,
- };
-
- test_file_common(&args, false);
-}
-
-static void *test_mode_reboot_start(QTestState *from, QTestState *to)
-{
- migrate_set_parameter_str(from, "mode", "cpr-reboot");
- migrate_set_parameter_str(to, "mode", "cpr-reboot");
-
- migrate_set_capability(from, "x-ignore-shared", true);
- migrate_set_capability(to, "x-ignore-shared", true);
-
- return NULL;
-}
-
-static void *migrate_mapped_ram_start(QTestState *from, QTestState *to)
-{
- migrate_set_capability(from, "mapped-ram", true);
- migrate_set_capability(to, "mapped-ram", true);
-
- return NULL;
-}
-
-static void test_mode_reboot(void)
-{
- g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
- FILE_TEST_FILENAME);
- MigrateCommon args = {
- .start.use_shmem = true,
- .connect_uri = uri,
- .listen_uri = "defer",
- .start_hook = test_mode_reboot_start
- };
-
- test_file_common(&args, true);
-}
-
-static void test_precopy_file_mapped_ram_live(void)
-{
- g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
- FILE_TEST_FILENAME);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = "defer",
- .start_hook = migrate_mapped_ram_start,
- };
-
- test_file_common(&args, false);
-}
-
-static void test_precopy_file_mapped_ram(void)
-{
- g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
- FILE_TEST_FILENAME);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = "defer",
- .start_hook = migrate_mapped_ram_start,
- };
-
- test_file_common(&args, true);
-}
-
-static void *migrate_multifd_mapped_ram_start(QTestState *from, QTestState *to)
-{
- migrate_mapped_ram_start(from, to);
-
- migrate_set_parameter_int(from, "multifd-channels", 4);
- migrate_set_parameter_int(to, "multifd-channels", 4);
-
- migrate_set_capability(from, "multifd", true);
- migrate_set_capability(to, "multifd", true);
-
- return NULL;
-}
-
-static void test_multifd_file_mapped_ram_live(void)
-{
- g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
- FILE_TEST_FILENAME);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = "defer",
- .start_hook = migrate_multifd_mapped_ram_start,
- };
-
- test_file_common(&args, false);
-}
-
-static void test_multifd_file_mapped_ram(void)
-{
- g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
- FILE_TEST_FILENAME);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = "defer",
- .start_hook = migrate_multifd_mapped_ram_start,
- };
-
- test_file_common(&args, true);
-}
-
-static void *multifd_mapped_ram_dio_start(QTestState *from, QTestState *to)
-{
- migrate_multifd_mapped_ram_start(from, to);
-
- migrate_set_parameter_bool(from, "direct-io", true);
- migrate_set_parameter_bool(to, "direct-io", true);
-
- return NULL;
-}
-
-static void test_multifd_file_mapped_ram_dio(void)
-{
- g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
- FILE_TEST_FILENAME);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = "defer",
- .start_hook = multifd_mapped_ram_dio_start,
- };
-
- if (!probe_o_direct_support(tmpfs)) {
- g_test_skip("Filesystem does not support O_DIRECT");
- return;
- }
-
- test_file_common(&args, true);
-}
-
-#ifndef _WIN32
-static void multifd_mapped_ram_fdset_end(QTestState *from, QTestState *to,
- void *opaque)
-{
- QDict *resp;
- QList *fdsets;
-
- /*
- * Remove the fdsets after migration, otherwise a second migration
- * would fail due fdset reuse.
- */
- qtest_qmp_assert_success(from, "{'execute': 'remove-fd', "
- "'arguments': { 'fdset-id': 1}}");
-
- /*
- * Make sure no fdsets are left after migration, otherwise a
- * second migration would fail due fdset reuse.
- */
- resp = qtest_qmp(from, "{'execute': 'query-fdsets', "
- "'arguments': {}}");
- g_assert(qdict_haskey(resp, "return"));
- fdsets = qdict_get_qlist(resp, "return");
- g_assert(fdsets && qlist_empty(fdsets));
- qobject_unref(resp);
-}
-
-static void *multifd_mapped_ram_fdset_dio(QTestState *from, QTestState *to)
-{
- g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
-
- fdset_add_fds(from, file, O_WRONLY, 2, true);
- fdset_add_fds(to, file, O_RDONLY, 2, true);
-
- migrate_multifd_mapped_ram_start(from, to);
- migrate_set_parameter_bool(from, "direct-io", true);
- migrate_set_parameter_bool(to, "direct-io", true);
-
- return NULL;
-}
-
-static void *multifd_mapped_ram_fdset(QTestState *from, QTestState *to)
-{
- g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
-
- fdset_add_fds(from, file, O_WRONLY, 2, false);
- fdset_add_fds(to, file, O_RDONLY, 2, false);
-
- migrate_multifd_mapped_ram_start(from, to);
-
- return NULL;
-}
-
-static void test_multifd_file_mapped_ram_fdset(void)
-{
- g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
- FILE_TEST_OFFSET);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = "defer",
- .start_hook = multifd_mapped_ram_fdset,
- .finish_hook = multifd_mapped_ram_fdset_end,
- };
-
- test_file_common(&args, true);
-}
-
-static void test_multifd_file_mapped_ram_fdset_dio(void)
-{
- g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
- FILE_TEST_OFFSET);
- MigrateCommon args = {
- .connect_uri = uri,
- .listen_uri = "defer",
- .start_hook = multifd_mapped_ram_fdset_dio,
- .finish_hook = multifd_mapped_ram_fdset_end,
- };
-
- if (!probe_o_direct_support(tmpfs)) {
- g_test_skip("Filesystem does not support O_DIRECT");
- return;
- }
-
- test_file_common(&args, true);
-}
-#endif /* !_WIN32 */
-
-static void test_precopy_tcp_plain(void)
-{
- MigrateCommon args = {
- .listen_uri = "tcp:127.0.0.1:0",
- };
-
- test_precopy_common(&args);
-}
-
-static void *test_migrate_switchover_ack_start(QTestState *from, QTestState *to)
-{
-
- migrate_set_capability(from, "return-path", true);
- migrate_set_capability(to, "return-path", true);
-
- migrate_set_capability(from, "switchover-ack", true);
- migrate_set_capability(to, "switchover-ack", true);
-
- return NULL;
-}
-
-static void test_precopy_tcp_switchover_ack(void)
-{
- MigrateCommon args = {
- .listen_uri = "tcp:127.0.0.1:0",
- .start_hook = test_migrate_switchover_ack_start,
- /*
- * Source VM must be running in order to consider the switchover ACK
- * when deciding to do switchover or not.
- */
- .live = true,
- };
-
- test_precopy_common(&args);
-}
-
-#ifdef CONFIG_GNUTLS
-static void test_precopy_tcp_tls_psk_match(void)
-{
- MigrateCommon args = {
- .listen_uri = "tcp:127.0.0.1:0",
- .start_hook = test_migrate_tls_psk_start_match,
- .finish_hook = test_migrate_tls_psk_finish,
- };
-
- test_precopy_common(&args);
-}
-
-static void test_precopy_tcp_tls_psk_mismatch(void)
-{
- MigrateCommon args = {
- .start = {
- .hide_stderr = true,
- },
- .listen_uri = "tcp:127.0.0.1:0",
- .start_hook = test_migrate_tls_psk_start_mismatch,
- .finish_hook = test_migrate_tls_psk_finish,
- .result = MIG_TEST_FAIL,
- };
-
- test_precopy_common(&args);
-}
-
-#ifdef CONFIG_TASN1
-static void test_precopy_tcp_tls_x509_default_host(void)
-{
- MigrateCommon args = {
- .listen_uri = "tcp:127.0.0.1:0",
- .start_hook = test_migrate_tls_x509_start_default_host,
- .finish_hook = test_migrate_tls_x509_finish,
- };
-
- test_precopy_common(&args);
-}
-
-static void test_precopy_tcp_tls_x509_override_host(void)
-{
- MigrateCommon args = {
- .listen_uri = "tcp:127.0.0.1:0",
- .start_hook = test_migrate_tls_x509_start_override_host,
- .finish_hook = test_migrate_tls_x509_finish,
- };
-
- test_precopy_common(&args);
-}
-
-static void test_precopy_tcp_tls_x509_mismatch_host(void)
-{
- MigrateCommon args = {
- .start = {
- .hide_stderr = true,
- },
- .listen_uri = "tcp:127.0.0.1:0",
- .start_hook = test_migrate_tls_x509_start_mismatch_host,
- .finish_hook = test_migrate_tls_x509_finish,
- .result = MIG_TEST_FAIL_DEST_QUIT_ERR,
- };
-
- test_precopy_common(&args);
-}
-
-static void test_precopy_tcp_tls_x509_friendly_client(void)
-{
- MigrateCommon args = {
- .listen_uri = "tcp:127.0.0.1:0",
- .start_hook = test_migrate_tls_x509_start_friendly_client,
- .finish_hook = test_migrate_tls_x509_finish,
- };
-
- test_precopy_common(&args);
-}
-
-static void test_precopy_tcp_tls_x509_hostile_client(void)
-{
- MigrateCommon args = {
- .start = {
- .hide_stderr = true,
- },
- .listen_uri = "tcp:127.0.0.1:0",
- .start_hook = test_migrate_tls_x509_start_hostile_client,
- .finish_hook = test_migrate_tls_x509_finish,
- .result = MIG_TEST_FAIL,
- };
-
- test_precopy_common(&args);
-}
-
-static void test_precopy_tcp_tls_x509_allow_anon_client(void)
-{
- MigrateCommon args = {
- .listen_uri = "tcp:127.0.0.1:0",
- .start_hook = test_migrate_tls_x509_start_allow_anon_client,
- .finish_hook = test_migrate_tls_x509_finish,
- };
-
- test_precopy_common(&args);
-}
-
-static void test_precopy_tcp_tls_x509_reject_anon_client(void)
-{
- MigrateCommon args = {
- .start = {
- .hide_stderr = true,
- },
- .listen_uri = "tcp:127.0.0.1:0",
- .start_hook = test_migrate_tls_x509_start_reject_anon_client,
- .finish_hook = test_migrate_tls_x509_finish,
- .result = MIG_TEST_FAIL,
- };
-
- test_precopy_common(&args);
-}
-#endif /* CONFIG_TASN1 */
-#endif /* CONFIG_GNUTLS */
-
-#ifndef _WIN32
-static void *test_migrate_fd_start_hook(QTestState *from,
- QTestState *to)
-{
- int ret;
- int pair[2];
-
- /* Create two connected sockets for migration */
- ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair);
- g_assert_cmpint(ret, ==, 0);
-
- /* Send the 1st socket to the target */
- qtest_qmp_fds_assert_success(to, &pair[0], 1,
- "{ 'execute': 'getfd',"
- " 'arguments': { 'fdname': 'fd-mig' }}");
- close(pair[0]);
-
- /* Start incoming migration from the 1st socket */
- migrate_incoming_qmp(to, "fd:fd-mig", "{}");
-
- /* Send the 2nd socket to the target */
- qtest_qmp_fds_assert_success(from, &pair[1], 1,
- "{ 'execute': 'getfd',"
- " 'arguments': { 'fdname': 'fd-mig' }}");
- close(pair[1]);
-
- return NULL;
-}
-
-static void test_migrate_fd_finish_hook(QTestState *from,
- QTestState *to,
- void *opaque)
-{
- QDict *rsp;
- const char *error_desc;
-
- /* 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);
-}
-
-static void test_migrate_precopy_fd_socket(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .connect_uri = "fd:fd-mig",
- .start_hook = test_migrate_fd_start_hook,
- .finish_hook = test_migrate_fd_finish_hook
- };
- test_precopy_common(&args);
-}
-
-static void *migrate_precopy_fd_file_start(QTestState *from, QTestState *to)
-{
- g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
- int src_flags = O_CREAT | O_RDWR;
- int dst_flags = O_CREAT | O_RDWR;
- int fds[2];
-
- fds[0] = open(file, src_flags, 0660);
- assert(fds[0] != -1);
-
- fds[1] = open(file, dst_flags, 0660);
- assert(fds[1] != -1);
-
-
- qtest_qmp_fds_assert_success(to, &fds[0], 1,
- "{ 'execute': 'getfd',"
- " 'arguments': { 'fdname': 'fd-mig' }}");
-
- qtest_qmp_fds_assert_success(from, &fds[1], 1,
- "{ 'execute': 'getfd',"
- " 'arguments': { 'fdname': 'fd-mig' }}");
-
- close(fds[0]);
- close(fds[1]);
-
- return NULL;
-}
-
-static void test_migrate_precopy_fd_file(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .connect_uri = "fd:fd-mig",
- .start_hook = migrate_precopy_fd_file_start,
- .finish_hook = test_migrate_fd_finish_hook
- };
- test_file_common(&args, true);
-}
-#endif /* _WIN32 */
-
-static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
-{
- g_autofree 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, to, uri, NULL, "{}");
-
- if (should_fail) {
- qtest_set_expected_status(to, EXIT_FAILURE);
- wait_for_migration_fail(from, true);
- } else {
- wait_for_migration_complete(from);
- }
-
- test_migrate_end(from, to, false);
-}
-
-static void test_validate_uuid(void)
-{
- MigrateStart args = {
- .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
- .opts_target = "-uuid 11111111-1111-1111-1111-111111111111",
- };
-
- do_test_validate_uuid(&args, false);
-}
-
-static void test_validate_uuid_error(void)
-{
- MigrateStart args = {
- .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
- .opts_target = "-uuid 22222222-2222-2222-2222-222222222222",
- .hide_stderr = true,
- };
-
- do_test_validate_uuid(&args, true);
-}
-
-static void test_validate_uuid_src_not_set(void)
-{
- MigrateStart args = {
- .opts_target = "-uuid 22222222-2222-2222-2222-222222222222",
- .hide_stderr = true,
- };
-
- do_test_validate_uuid(&args, false);
-}
-
-static void test_validate_uuid_dst_not_set(void)
-{
- MigrateStart args = {
- .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
- .hide_stderr = true,
- };
-
- do_test_validate_uuid(&args, false);
-}
-
-static void do_test_validate_uri_channel(MigrateCommon *args)
-{
- QTestState *from, *to;
-
- if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) {
- return;
- }
-
- /* Wait for the first serial output from the source */
- wait_for_serial("src_serial");
-
- /*
- * 'uri' and 'channels' validation is checked even before the migration
- * starts.
- */
- migrate_qmp_fail(from, args->connect_uri, args->connect_channels, "{}");
- test_migrate_end(from, to, false);
-}
-
-static void test_validate_uri_channels_both_set(void)
-{
- MigrateCommon args = {
- .start = {
- .hide_stderr = true,
- },
- .listen_uri = "defer",
- .connect_uri = "tcp:127.0.0.1:0",
- .connect_channels = "[ { 'channel-type': 'main',"
- " 'addr': { 'transport': 'socket',"
- " 'type': 'inet',"
- " 'host': '127.0.0.1',"
- " 'port': '0' } } ]",
- };
-
- do_test_validate_uri_channel(&args);
-}
-
-static void test_validate_uri_channels_none_set(void)
-{
- MigrateCommon args = {
- .start = {
- .hide_stderr = true,
- },
- .listen_uri = "defer",
- };
-
- do_test_validate_uri_channel(&args);
-}
-
-/*
- * The way auto_converge works, we need to do too many passes to
- * run this test. Auto_converge logic is only run once every
- * three iterations, so:
- *
- * - 3 iterations without auto_converge enabled
- * - 3 iterations with pct = 5
- * - 3 iterations with pct = 30
- * - 3 iterations with pct = 55
- * - 3 iterations with pct = 80
- * - 3 iterations with pct = 95 (max(95, 80 + 25))
- *
- * To make things even worse, we need to run the initial stage at
- * 3MB/s so we enter autoconverge even when host is (over)loaded.
- */
-static void test_migrate_auto_converge(void)
-{
- g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
- MigrateStart args = {};
- QTestState *from, *to;
- int64_t percentage;
-
- /*
- * We want the test to be stable and as fast as possible.
- * E.g., with 1Gb/s bandwidth migration may pass without throttling,
- * so we need to decrease a bandwidth.
- */
- const int64_t init_pct = 5, inc_pct = 25, max_pct = 95;
-
- 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_ensure_non_converge(from);
-
- /* 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, to, uri, NULL, "{}");
-
- /* Wait for throttling begins */
- percentage = 0;
- do {
- percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
- if (percentage != 0) {
- break;
+ argv[j++] = argv[i];
+ if (i >= j) {
+ argv[i] = NULL;
}
- usleep(20);
- g_assert_false(src_state.stop_seen);
- } while (true);
- /* The first percentage of throttling should be at least init_pct */
- g_assert_cmpint(percentage, >=, init_pct);
- /* Now, when we tested that throttling works, let it converge */
- migrate_ensure_converge(from);
-
- /*
- * 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);
- migrate_continue(from, "pre-switchover");
-
- qtest_qmp_eventwait(to, "RESUME");
-
- wait_for_serial("dest_serial");
- wait_for_migration_complete(from);
-
- test_migrate_end(from, to, true);
-}
-
-static void *
-test_migrate_precopy_tcp_multifd_start_common(QTestState *from,
- QTestState *to,
- const char *method)
-{
- migrate_set_parameter_int(from, "multifd-channels", 16);
- migrate_set_parameter_int(to, "multifd-channels", 16);
-
- migrate_set_parameter_str(from, "multifd-compression", method);
- migrate_set_parameter_str(to, "multifd-compression", method);
-
- migrate_set_capability(from, "multifd", true);
- migrate_set_capability(to, "multifd", true);
-
- /* Start incoming migration from the 1st socket */
- migrate_incoming_qmp(to, "tcp:127.0.0.1:0", "{}");
-
- return NULL;
-}
-
-static void *
-test_migrate_precopy_tcp_multifd_start(QTestState *from,
- QTestState *to)
-{
- return test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
-}
-
-static void *
-test_migrate_precopy_tcp_multifd_start_zero_page_legacy(QTestState *from,
- QTestState *to)
-{
- test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
- migrate_set_parameter_str(from, "zero-page-detection", "legacy");
- return NULL;
-}
-
-static void *
-test_migration_precopy_tcp_multifd_start_no_zero_page(QTestState *from,
- QTestState *to)
-{
- test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
- migrate_set_parameter_str(from, "zero-page-detection", "none");
- return NULL;
-}
-
-static void *
-test_migrate_precopy_tcp_multifd_zlib_start(QTestState *from,
- QTestState *to)
-{
- /*
- * Overloading this test to also check that set_parameter does not error.
- * This is also done in the tests for the other compression methods.
- */
- migrate_set_parameter_int(from, "multifd-zlib-level", 2);
- migrate_set_parameter_int(to, "multifd-zlib-level", 2);
-
- return test_migrate_precopy_tcp_multifd_start_common(from, to, "zlib");
-}
-
-#ifdef CONFIG_ZSTD
-static void *
-test_migrate_precopy_tcp_multifd_zstd_start(QTestState *from,
- QTestState *to)
-{
- migrate_set_parameter_int(from, "multifd-zstd-level", 2);
- migrate_set_parameter_int(to, "multifd-zstd-level", 2);
-
- return test_migrate_precopy_tcp_multifd_start_common(from, to, "zstd");
-}
-#endif /* CONFIG_ZSTD */
-
-#ifdef CONFIG_QPL
-static void *
-test_migrate_precopy_tcp_multifd_qpl_start(QTestState *from,
- QTestState *to)
-{
- return test_migrate_precopy_tcp_multifd_start_common(from, to, "qpl");
-}
-#endif /* CONFIG_QPL */
-#ifdef CONFIG_UADK
-static void *
-test_migrate_precopy_tcp_multifd_uadk_start(QTestState *from,
- QTestState *to)
-{
- return test_migrate_precopy_tcp_multifd_start_common(from, to, "uadk");
-}
-#endif /* CONFIG_UADK */
-
-static void test_multifd_tcp_uri_none(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .start_hook = test_migrate_precopy_tcp_multifd_start,
- /*
- * Multifd is more complicated than most of the features, it
- * directly takes guest page buffers when sending, make sure
- * everything will work alright even if guest page is changing.
- */
- .live = true,
- };
- test_precopy_common(&args);
-}
-
-static void test_multifd_tcp_zero_page_legacy(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .start_hook = test_migrate_precopy_tcp_multifd_start_zero_page_legacy,
- /*
- * Multifd is more complicated than most of the features, it
- * directly takes guest page buffers when sending, make sure
- * everything will work alright even if guest page is changing.
- */
- .live = true,
- };
- test_precopy_common(&args);
-}
-
-static void test_multifd_tcp_no_zero_page(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .start_hook = test_migration_precopy_tcp_multifd_start_no_zero_page,
- /*
- * Multifd is more complicated than most of the features, it
- * directly takes guest page buffers when sending, make sure
- * everything will work alright even if guest page is changing.
- */
- .live = true,
- };
- test_precopy_common(&args);
-}
-
-static void test_multifd_tcp_channels_none(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .start_hook = test_migrate_precopy_tcp_multifd_start,
- .live = true,
- .connect_channels = "[ { 'channel-type': 'main',"
- " 'addr': { 'transport': 'socket',"
- " 'type': 'inet',"
- " 'host': '127.0.0.1',"
- " 'port': '0' } } ]",
- };
- test_precopy_common(&args);
-}
-
-static void test_multifd_tcp_zlib(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .start_hook = test_migrate_precopy_tcp_multifd_zlib_start,
- };
- test_precopy_common(&args);
-}
-
-#ifdef CONFIG_ZSTD
-static void test_multifd_tcp_zstd(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .start_hook = test_migrate_precopy_tcp_multifd_zstd_start,
- };
- test_precopy_common(&args);
-}
-#endif
-
-#ifdef CONFIG_QPL
-static void test_multifd_tcp_qpl(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .start_hook = test_migrate_precopy_tcp_multifd_qpl_start,
- };
- test_precopy_common(&args);
-}
-#endif
-
-#ifdef CONFIG_UADK
-static void test_multifd_tcp_uadk(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .start_hook = test_migrate_precopy_tcp_multifd_uadk_start,
- };
- test_precopy_common(&args);
-}
-#endif
-
-#ifdef CONFIG_GNUTLS
-static void *
-test_migrate_multifd_tcp_tls_psk_start_match(QTestState *from,
- QTestState *to)
-{
- test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
- return test_migrate_tls_psk_start_match(from, to);
-}
-
-static void *
-test_migrate_multifd_tcp_tls_psk_start_mismatch(QTestState *from,
- QTestState *to)
-{
- test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
- return test_migrate_tls_psk_start_mismatch(from, to);
-}
-
-#ifdef CONFIG_TASN1
-static void *
-test_migrate_multifd_tls_x509_start_default_host(QTestState *from,
- QTestState *to)
-{
- test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
- return test_migrate_tls_x509_start_default_host(from, to);
-}
-
-static void *
-test_migrate_multifd_tls_x509_start_override_host(QTestState *from,
- QTestState *to)
-{
- test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
- return test_migrate_tls_x509_start_override_host(from, to);
-}
-
-static void *
-test_migrate_multifd_tls_x509_start_mismatch_host(QTestState *from,
- QTestState *to)
-{
- test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
- return test_migrate_tls_x509_start_mismatch_host(from, to);
-}
-
-static void *
-test_migrate_multifd_tls_x509_start_allow_anon_client(QTestState *from,
- QTestState *to)
-{
- test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
- return test_migrate_tls_x509_start_allow_anon_client(from, to);
-}
-
-static void *
-test_migrate_multifd_tls_x509_start_reject_anon_client(QTestState *from,
- QTestState *to)
-{
- test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
- return test_migrate_tls_x509_start_reject_anon_client(from, to);
-}
-#endif /* CONFIG_TASN1 */
-
-static void test_multifd_tcp_tls_psk_match(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .start_hook = test_migrate_multifd_tcp_tls_psk_start_match,
- .finish_hook = test_migrate_tls_psk_finish,
- };
- test_precopy_common(&args);
-}
-
-static void test_multifd_tcp_tls_psk_mismatch(void)
-{
- MigrateCommon args = {
- .start = {
- .hide_stderr = true,
- },
- .listen_uri = "defer",
- .start_hook = test_migrate_multifd_tcp_tls_psk_start_mismatch,
- .finish_hook = test_migrate_tls_psk_finish,
- .result = MIG_TEST_FAIL,
- };
- test_precopy_common(&args);
-}
-
-#ifdef CONFIG_TASN1
-static void test_multifd_tcp_tls_x509_default_host(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .start_hook = test_migrate_multifd_tls_x509_start_default_host,
- .finish_hook = test_migrate_tls_x509_finish,
- };
- test_precopy_common(&args);
-}
-
-static void test_multifd_tcp_tls_x509_override_host(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .start_hook = test_migrate_multifd_tls_x509_start_override_host,
- .finish_hook = test_migrate_tls_x509_finish,
- };
- test_precopy_common(&args);
-}
-
-static void test_multifd_tcp_tls_x509_mismatch_host(void)
-{
- /*
- * This has different behaviour to the non-multifd case.
- *
- * In non-multifd case when client aborts due to mismatched
- * cert host, the server has already started trying to load
- * migration state, and so it exits with I/O failure.
- *
- * In multifd case when client aborts due to mismatched
- * cert host, the server is still waiting for the other
- * multifd connections to arrive so hasn't started trying
- * to load migration state, and thus just aborts the migration
- * without exiting.
- */
- MigrateCommon args = {
- .start = {
- .hide_stderr = true,
- },
- .listen_uri = "defer",
- .start_hook = test_migrate_multifd_tls_x509_start_mismatch_host,
- .finish_hook = test_migrate_tls_x509_finish,
- .result = MIG_TEST_FAIL,
- };
- test_precopy_common(&args);
-}
-
-static void test_multifd_tcp_tls_x509_allow_anon_client(void)
-{
- MigrateCommon args = {
- .listen_uri = "defer",
- .start_hook = test_migrate_multifd_tls_x509_start_allow_anon_client,
- .finish_hook = test_migrate_tls_x509_finish,
- };
- test_precopy_common(&args);
-}
-
-static void test_multifd_tcp_tls_x509_reject_anon_client(void)
-{
- MigrateCommon args = {
- .start = {
- .hide_stderr = true,
- },
- .listen_uri = "defer",
- .start_hook = test_migrate_multifd_tls_x509_start_reject_anon_client,
- .finish_hook = test_migrate_tls_x509_finish,
- .result = MIG_TEST_FAIL,
- };
- test_precopy_common(&args);
-}
-#endif /* CONFIG_TASN1 */
-#endif /* CONFIG_GNUTLS */
-
-/*
- * This test does:
- * source target
- * migrate_incoming
- * migrate
- * migrate_cancel
- * launch another target
- * migrate
- *
- * And see that it works
- */
-static void test_multifd_tcp_cancel(void)
-{
- MigrateStart args = {
- .hide_stderr = true,
- };
- QTestState *from, *to, *to2;
-
- if (test_migrate_start(&from, &to, "defer", &args)) {
- return;
}
-
- migrate_ensure_non_converge(from);
- migrate_prepare_for_dirty_mem(from);
-
- migrate_set_parameter_int(from, "multifd-channels", 16);
- migrate_set_parameter_int(to, "multifd-channels", 16);
-
- migrate_set_capability(from, "multifd", true);
- migrate_set_capability(to, "multifd", true);
-
- /* Start incoming migration from the 1st socket */
- migrate_incoming_qmp(to, "tcp:127.0.0.1:0", "{}");
-
- /* Wait for the first serial output from the source */
- wait_for_serial("src_serial");
-
- migrate_qmp(from, to, NULL, NULL, "{}");
-
- migrate_wait_for_dirty_mem(from, to);
-
- migrate_cancel(from);
-
- /* Make sure QEMU process "to" exited */
- qtest_set_expected_status(to, EXIT_FAILURE);
- qtest_wait_qemu(to);
- qtest_quit(to);
-
- args = (MigrateStart){
- .only_target = true,
- };
-
- if (test_migrate_start(&from, &to2, "defer", &args)) {
- return;
- }
-
- migrate_set_parameter_int(to2, "multifd-channels", 16);
-
- migrate_set_capability(to2, "multifd", true);
-
- /* Start incoming migration from the 1st socket */
- migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", "{}");
-
- wait_for_migration_status(from, "cancelled", NULL);
-
- migrate_ensure_non_converge(from);
-
- migrate_qmp(from, to2, NULL, NULL, "{}");
-
- migrate_wait_for_dirty_mem(from, to2);
-
- migrate_ensure_converge(from);
-
- wait_for_stop(from, &src_state);
- qtest_qmp_eventwait(to2, "RESUME");
-
- wait_for_serial("dest_serial");
- wait_for_migration_complete(from);
- test_migrate_end(from, to2, true);
-}
-
-static void calc_dirty_rate(QTestState *who, uint64_t calc_time)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'calc-dirty-rate',"
- "'arguments': { "
- "'calc-time': %" PRIu64 ","
- "'mode': 'dirty-ring' }}",
- calc_time);
-}
-
-static QDict *query_dirty_rate(QTestState *who)
-{
- return qtest_qmp_assert_success_ref(who,
- "{ 'execute': 'query-dirty-rate' }");
-}
-
-static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'set-vcpu-dirty-limit',"
- "'arguments': { "
- "'dirty-rate': %" PRIu64 " } }",
- dirtyrate);
-}
-
-static void cancel_vcpu_dirty_limit(QTestState *who)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'cancel-vcpu-dirty-limit' }");
-}
-
-static QDict *query_vcpu_dirty_limit(QTestState *who)
-{
- QDict *rsp;
-
- rsp = qtest_qmp(who, "{ 'execute': 'query-vcpu-dirty-limit' }");
- g_assert(!qdict_haskey(rsp, "error"));
- g_assert(qdict_haskey(rsp, "return"));
-
- return rsp;
-}
-
-static bool calc_dirtyrate_ready(QTestState *who)
-{
- QDict *rsp_return;
- const char *status;
- bool ready;
-
- rsp_return = query_dirty_rate(who);
- g_assert(rsp_return);
-
- status = qdict_get_str(rsp_return, "status");
- g_assert(status);
- ready = g_strcmp0(status, "measuring");
- qobject_unref(rsp_return);
-
- return ready;
-}
-
-static void wait_for_calc_dirtyrate_complete(QTestState *who,
- int64_t time_s)
-{
- int max_try_count = 10000;
- usleep(time_s * 1000000);
-
- while (!calc_dirtyrate_ready(who) && max_try_count--) {
- usleep(1000);
- }
-
- /*
- * Set the timeout with 10 s(max_try_count * 1000us),
- * if dirtyrate measurement not complete, fail test.
- */
- g_assert_cmpint(max_try_count, !=, 0);
-}
-
-static int64_t get_dirty_rate(QTestState *who)
-{
- QDict *rsp_return;
- const char *status;
- QList *rates;
- const QListEntry *entry;
- QDict *rate;
- int64_t dirtyrate;
-
- rsp_return = query_dirty_rate(who);
- g_assert(rsp_return);
-
- status = qdict_get_str(rsp_return, "status");
- g_assert(status);
- g_assert_cmpstr(status, ==, "measured");
-
- rates = qdict_get_qlist(rsp_return, "vcpu-dirty-rate");
- g_assert(rates && !qlist_empty(rates));
-
- entry = qlist_first(rates);
- g_assert(entry);
-
- rate = qobject_to(QDict, qlist_entry_obj(entry));
- g_assert(rate);
-
- dirtyrate = qdict_get_try_int(rate, "dirty-rate", -1);
-
- qobject_unref(rsp_return);
- return dirtyrate;
-}
-
-static int64_t get_limit_rate(QTestState *who)
-{
- QDict *rsp_return;
- QList *rates;
- const QListEntry *entry;
- QDict *rate;
- int64_t dirtyrate;
-
- rsp_return = query_vcpu_dirty_limit(who);
- g_assert(rsp_return);
-
- rates = qdict_get_qlist(rsp_return, "return");
- g_assert(rates && !qlist_empty(rates));
-
- entry = qlist_first(rates);
- g_assert(entry);
-
- rate = qobject_to(QDict, qlist_entry_obj(entry));
- g_assert(rate);
-
- dirtyrate = qdict_get_try_int(rate, "limit-rate", -1);
-
- qobject_unref(rsp_return);
- return dirtyrate;
-}
-
-static QTestState *dirtylimit_start_vm(void)
-{
- QTestState *vm = NULL;
- g_autofree gchar *cmd = NULL;
-
- bootfile_create(tmpfs, false);
- cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 "
- "-name dirtylimit-test,debug-threads=on "
- "-m 150M -smp 1 "
- "-serial file:%s/vm_serial "
- "-drive file=%s,format=raw ",
- tmpfs, bootpath);
-
- vm = qtest_init(cmd);
- return vm;
-}
-
-static void dirtylimit_stop_vm(QTestState *vm)
-{
- qtest_quit(vm);
- cleanup("vm_serial");
-}
-
-static void test_vcpu_dirty_limit(void)
-{
- QTestState *vm;
- int64_t origin_rate;
- int64_t quota_rate;
- int64_t rate ;
- int max_try_count = 20;
- int hit = 0;
-
- /* Start vm for vcpu dirtylimit test */
- vm = dirtylimit_start_vm();
-
- /* Wait for the first serial output from the vm*/
- wait_for_serial("vm_serial");
-
- /* Do dirtyrate measurement with calc time equals 1s */
- calc_dirty_rate(vm, 1);
-
- /* Sleep calc time and wait for calc dirtyrate complete */
- wait_for_calc_dirtyrate_complete(vm, 1);
-
- /* Query original dirty page rate */
- origin_rate = get_dirty_rate(vm);
-
- /* VM booted from bootsect should dirty memory steadily */
- assert(origin_rate != 0);
-
- /* Setup quota dirty page rate at half of origin */
- quota_rate = origin_rate / 2;
-
- /* Set dirtylimit */
- dirtylimit_set_all(vm, quota_rate);
-
- /*
- * Check if set-vcpu-dirty-limit and query-vcpu-dirty-limit
- * works literally
- */
- g_assert_cmpint(quota_rate, ==, get_limit_rate(vm));
-
- /* Sleep a bit to check if it take effect */
- usleep(2000000);
-
- /*
- * Check if dirtylimit take effect realistically, set the
- * timeout with 20 s(max_try_count * 1s), if dirtylimit
- * doesn't take effect, fail test.
- */
- while (--max_try_count) {
- calc_dirty_rate(vm, 1);
- wait_for_calc_dirtyrate_complete(vm, 1);
- rate = get_dirty_rate(vm);
-
- /*
- * Assume hitting if current rate is less
- * than quota rate (within accepting error)
- */
- if (rate < (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
- hit = 1;
- break;
- }
- }
-
- g_assert_cmpint(hit, ==, 1);
-
- hit = 0;
- max_try_count = 20;
-
- /* Check if dirtylimit cancellation take effect */
- cancel_vcpu_dirty_limit(vm);
- while (--max_try_count) {
- calc_dirty_rate(vm, 1);
- wait_for_calc_dirtyrate_complete(vm, 1);
- rate = get_dirty_rate(vm);
-
- /*
- * Assume dirtylimit be canceled if current rate is
- * greater than quota rate (within accepting error)
- */
- if (rate > (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
- hit = 1;
- break;
- }
- }
-
- g_assert_cmpint(hit, ==, 1);
- dirtylimit_stop_vm(vm);
-}
-
-static void migrate_dirty_limit_wait_showup(QTestState *from,
- const int64_t period,
- const int64_t value)
-{
- /* Enable dirty limit capability */
- migrate_set_capability(from, "dirty-limit", true);
-
- /* Set dirty limit parameters */
- migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period);
- migrate_set_parameter_int(from, "vcpu-dirty-limit", value);
-
- /* Make sure migrate can't converge */
- migrate_ensure_non_converge(from);
-
- /* To check limit rate after precopy */
- migrate_set_capability(from, "pause-before-switchover", true);
-
- /* Wait for the serial output from the source */
- wait_for_serial("src_serial");
-}
-
-/*
- * This test does:
- * source destination
- * start vm
- * start incoming vm
- * migrate
- * wait dirty limit to begin
- * cancel migrate
- * cancellation check
- * restart incoming vm
- * migrate
- * wait dirty limit to begin
- * wait pre-switchover event
- * convergence condition check
- *
- * And see if dirty limit migration works correctly.
- * This test case involves many passes, so it runs in slow mode only.
- */
-static void test_migrate_dirty_limit(void)
-{
- g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
- QTestState *from, *to;
- int64_t remaining;
- uint64_t throttle_us_per_full;
- /*
- * We want the test to be stable and as fast as possible.
- * E.g., with 1Gb/s bandwidth migration may pass without dirty limit,
- * so we need to decrease a bandwidth.
- */
- const int64_t dirtylimit_period = 1000, dirtylimit_value = 50;
- 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;
- int max_try_count = 10;
- MigrateCommon args = {
- .start = {
- .hide_stderr = true,
- .use_dirty_ring = true,
- },
- .listen_uri = uri,
- .connect_uri = uri,
- };
-
- /* Start src, dst vm */
- if (test_migrate_start(&from, &to, args.listen_uri, &args.start)) {
- return;
- }
-
- /* Prepare for dirty limit migration and wait src vm show up */
- migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
-
- /* Start migrate */
- migrate_qmp(from, to, args.connect_uri, NULL, "{}");
-
- /* Wait for dirty limit throttle begin */
- throttle_us_per_full = 0;
- while (throttle_us_per_full == 0) {
- throttle_us_per_full =
- read_migrate_property_int(from, "dirty-limit-throttle-time-per-round");
- usleep(100);
- g_assert_false(src_state.stop_seen);
- }
-
- /* Now cancel migrate and wait for dirty limit throttle switch off */
- migrate_cancel(from);
- wait_for_migration_status(from, "cancelled", NULL);
-
- /* Check if dirty limit throttle switched off, set timeout 1ms */
- do {
- throttle_us_per_full =
- read_migrate_property_int(from, "dirty-limit-throttle-time-per-round");
- usleep(100);
- g_assert_false(src_state.stop_seen);
- } while (throttle_us_per_full != 0 && --max_try_count);
-
- /* Assert dirty limit is not in service */
- g_assert_cmpint(throttle_us_per_full, ==, 0);
-
- args = (MigrateCommon) {
- .start = {
- .only_target = true,
- .use_dirty_ring = true,
- },
- .listen_uri = uri,
- .connect_uri = uri,
- };
-
- /* Restart dst vm, src vm already show up so we needn't wait anymore */
- if (test_migrate_start(&from, &to, args.listen_uri, &args.start)) {
- return;
- }
-
- /* Start migrate */
- migrate_qmp(from, to, args.connect_uri, NULL, "{}");
-
- /* Wait for dirty limit throttle begin */
- throttle_us_per_full = 0;
- while (throttle_us_per_full == 0) {
- throttle_us_per_full =
- read_migrate_property_int(from, "dirty-limit-throttle-time-per-round");
- usleep(100);
- g_assert_false(src_state.stop_seen);
- }
-
- /*
- * The dirty limit rate should equals the return value of
- * query-vcpu-dirty-limit if dirty limit cap set
- */
- g_assert_cmpint(dirtylimit_value, ==, get_limit_rate(from));
-
- /* Now, we have tested if dirty limit 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 if migration
- * satisfy the convergence condition
- */
- wait_for_migration_status(from, "pre-switchover", NULL);
-
- remaining = read_ram_property_int(from, "remaining");
- g_assert_cmpint(remaining, <,
- (expected_threshold + expected_threshold / 100));
-
- migrate_continue(from, "pre-switchover");
-
- qtest_qmp_eventwait(to, "RESUME");
-
- wait_for_serial("dest_serial");
- wait_for_migration_complete(from);
-
- test_migrate_end(from, to, true);
-}
-
-static bool kvm_dirty_ring_supported(void)
-{
-#if defined(__linux__) && defined(HOST_X86_64)
- int ret, kvm_fd = open("/dev/kvm", O_RDONLY);
-
- if (kvm_fd < 0) {
- return false;
- }
-
- ret = ioctl(kvm_fd, KVM_CHECK_EXTENSION, KVM_CAP_DIRTY_LOG_RING);
- close(kvm_fd);
-
- /* We test with 4096 slots */
- if (ret < 4096) {
- return false;
- }
-
- return true;
-#else
- return false;
-#endif
+ *argc_p = j;
}
int main(int argc, char **argv)
{
- bool has_kvm, has_tcg;
- bool has_uffd, is_x86;
- const char *arch;
- g_autoptr(GError) err = NULL;
- const char *qemu_src = getenv(QEMU_ENV_SRC);
- const char *qemu_dst = getenv(QEMU_ENV_DST);
+ MigrationTestEnv *env;
int ret;
+ bool full_set = false;
- g_test_init(&argc, &argv, NULL);
-
- /*
- * The default QTEST_QEMU_BINARY must always be provided because
- * that is what helpers use to query the accel type and
- * architecture.
- */
- if (qemu_src && qemu_dst) {
- g_test_message("Only one of %s, %s is allowed",
- QEMU_ENV_SRC, QEMU_ENV_DST);
- exit(1);
- }
-
- has_kvm = qtest_has_accel("kvm");
- has_tcg = qtest_has_accel("tcg");
-
- if (!has_tcg && !has_kvm) {
- g_test_skip("No KVM or TCG accelerator available");
- return 0;
- }
-
- has_uffd = ufd_version_check();
- arch = qtest_get_arch();
- is_x86 = !strcmp(arch, "i386") || !strcmp(arch, "x86_64");
-
- tmpfs = g_dir_make_tmp("migration-test-XXXXXX", &err);
- if (!tmpfs) {
- g_test_message("Can't create temporary directory in %s: %s",
- g_get_tmp_dir(), err->message);
- }
- g_assert(tmpfs);
+ /* strip the --full option if it's present */
+ parse_args(&argc, &argv, &full_set);
+ g_test_init(&argc, &argv, NULL);
+ env = migration_get_env();
+ env->full_set = full_set;
module_call_init(MODULE_INIT_QOM);
- migration_test_add("/migration/bad_dest", test_baddest);
-#ifndef _WIN32
- migration_test_add("/migration/analyze-script", test_analyze_script);
-#endif
-
- if (is_x86) {
- migration_test_add("/migration/precopy/unix/suspend/live",
- test_precopy_unix_suspend_live);
- migration_test_add("/migration/precopy/unix/suspend/notlive",
- test_precopy_unix_suspend_notlive);
- }
-
- if (has_uffd) {
- migration_test_add("/migration/postcopy/plain", test_postcopy);
- migration_test_add("/migration/postcopy/recovery/plain",
- test_postcopy_recovery);
- migration_test_add("/migration/postcopy/preempt/plain",
- test_postcopy_preempt);
- migration_test_add("/migration/postcopy/preempt/recovery/plain",
- test_postcopy_preempt_recovery);
- migration_test_add("/migration/postcopy/recovery/double-failures/handshake",
- test_postcopy_recovery_fail_handshake);
- migration_test_add("/migration/postcopy/recovery/double-failures/reconnect",
- test_postcopy_recovery_fail_reconnect);
- if (is_x86) {
- migration_test_add("/migration/postcopy/suspend",
- test_postcopy_suspend);
- }
- }
-
- migration_test_add("/migration/precopy/unix/plain",
- test_precopy_unix_plain);
- migration_test_add("/migration/precopy/unix/xbzrle",
- test_precopy_unix_xbzrle);
- migration_test_add("/migration/precopy/file",
- test_precopy_file);
- migration_test_add("/migration/precopy/file/offset",
- test_precopy_file_offset);
-#ifndef _WIN32
- migration_test_add("/migration/precopy/file/offset/fdset",
- test_precopy_file_offset_fdset);
-#endif
- migration_test_add("/migration/precopy/file/offset/bad",
- test_precopy_file_offset_bad);
-
- /*
- * Our CI system has problems with shared memory.
- * Don't run this test until we find a workaround.
- */
- if (getenv("QEMU_TEST_FLAKY_TESTS")) {
- migration_test_add("/migration/mode/reboot", test_mode_reboot);
- }
-
- migration_test_add("/migration/precopy/file/mapped-ram",
- test_precopy_file_mapped_ram);
- migration_test_add("/migration/precopy/file/mapped-ram/live",
- test_precopy_file_mapped_ram_live);
-
- migration_test_add("/migration/multifd/file/mapped-ram",
- test_multifd_file_mapped_ram);
- migration_test_add("/migration/multifd/file/mapped-ram/live",
- test_multifd_file_mapped_ram_live);
-
- migration_test_add("/migration/multifd/file/mapped-ram/dio",
- test_multifd_file_mapped_ram_dio);
-
-#ifndef _WIN32
- migration_test_add("/migration/multifd/file/mapped-ram/fdset",
- test_multifd_file_mapped_ram_fdset);
- migration_test_add("/migration/multifd/file/mapped-ram/fdset/dio",
- test_multifd_file_mapped_ram_fdset_dio);
-#endif
-
-#ifdef CONFIG_GNUTLS
- migration_test_add("/migration/precopy/unix/tls/psk",
- test_precopy_unix_tls_psk);
-
- if (has_uffd) {
- /*
- * NOTE: psk test is enough for postcopy, as other types of TLS
- * channels are tested under precopy. Here what we want to test is the
- * general postcopy path that has TLS channel enabled.
- */
- migration_test_add("/migration/postcopy/tls/psk",
- test_postcopy_tls_psk);
- migration_test_add("/migration/postcopy/recovery/tls/psk",
- test_postcopy_recovery_tls_psk);
- migration_test_add("/migration/postcopy/preempt/tls/psk",
- test_postcopy_preempt_tls_psk);
- migration_test_add("/migration/postcopy/preempt/recovery/tls/psk",
- test_postcopy_preempt_all);
- }
-#ifdef CONFIG_TASN1
- migration_test_add("/migration/precopy/unix/tls/x509/default-host",
- test_precopy_unix_tls_x509_default_host);
- migration_test_add("/migration/precopy/unix/tls/x509/override-host",
- test_precopy_unix_tls_x509_override_host);
-#endif /* CONFIG_TASN1 */
-#endif /* CONFIG_GNUTLS */
-
- migration_test_add("/migration/precopy/tcp/plain", test_precopy_tcp_plain);
-
- migration_test_add("/migration/precopy/tcp/plain/switchover-ack",
- test_precopy_tcp_switchover_ack);
-
-#ifdef CONFIG_GNUTLS
- migration_test_add("/migration/precopy/tcp/tls/psk/match",
- test_precopy_tcp_tls_psk_match);
- migration_test_add("/migration/precopy/tcp/tls/psk/mismatch",
- test_precopy_tcp_tls_psk_mismatch);
-#ifdef CONFIG_TASN1
- migration_test_add("/migration/precopy/tcp/tls/x509/default-host",
- test_precopy_tcp_tls_x509_default_host);
- migration_test_add("/migration/precopy/tcp/tls/x509/override-host",
- test_precopy_tcp_tls_x509_override_host);
- migration_test_add("/migration/precopy/tcp/tls/x509/mismatch-host",
- test_precopy_tcp_tls_x509_mismatch_host);
- migration_test_add("/migration/precopy/tcp/tls/x509/friendly-client",
- test_precopy_tcp_tls_x509_friendly_client);
- migration_test_add("/migration/precopy/tcp/tls/x509/hostile-client",
- test_precopy_tcp_tls_x509_hostile_client);
- migration_test_add("/migration/precopy/tcp/tls/x509/allow-anon-client",
- test_precopy_tcp_tls_x509_allow_anon_client);
- migration_test_add("/migration/precopy/tcp/tls/x509/reject-anon-client",
- test_precopy_tcp_tls_x509_reject_anon_client);
-#endif /* CONFIG_TASN1 */
-#endif /* CONFIG_GNUTLS */
-
- /* migration_test_add("/migration/ignore_shared", test_ignore_shared); */
-#ifndef _WIN32
- migration_test_add("/migration/precopy/fd/tcp",
- test_migrate_precopy_fd_socket);
- migration_test_add("/migration/precopy/fd/file",
- test_migrate_precopy_fd_file);
-#endif
- migration_test_add("/migration/validate_uuid", test_validate_uuid);
- migration_test_add("/migration/validate_uuid_error",
- test_validate_uuid_error);
- migration_test_add("/migration/validate_uuid_src_not_set",
- test_validate_uuid_src_not_set);
- migration_test_add("/migration/validate_uuid_dst_not_set",
- test_validate_uuid_dst_not_set);
- migration_test_add("/migration/validate_uri/channels/both_set",
- test_validate_uri_channels_both_set);
- migration_test_add("/migration/validate_uri/channels/none_set",
- test_validate_uri_channels_none_set);
- /*
- * See explanation why this test is slow on function definition
- */
- if (g_test_slow()) {
- migration_test_add("/migration/auto_converge",
- test_migrate_auto_converge);
- if (g_str_equal(arch, "x86_64") &&
- has_kvm && kvm_dirty_ring_supported()) {
- migration_test_add("/migration/dirty_limit",
- test_migrate_dirty_limit);
- }
- }
- migration_test_add("/migration/multifd/tcp/uri/plain/none",
- test_multifd_tcp_uri_none);
- migration_test_add("/migration/multifd/tcp/channels/plain/none",
- test_multifd_tcp_channels_none);
- migration_test_add("/migration/multifd/tcp/plain/zero-page/legacy",
- test_multifd_tcp_zero_page_legacy);
- migration_test_add("/migration/multifd/tcp/plain/zero-page/none",
- test_multifd_tcp_no_zero_page);
- migration_test_add("/migration/multifd/tcp/plain/cancel",
- test_multifd_tcp_cancel);
- migration_test_add("/migration/multifd/tcp/plain/zlib",
- test_multifd_tcp_zlib);
-#ifdef CONFIG_ZSTD
- migration_test_add("/migration/multifd/tcp/plain/zstd",
- test_multifd_tcp_zstd);
-#endif
-#ifdef CONFIG_QPL
- migration_test_add("/migration/multifd/tcp/plain/qpl",
- test_multifd_tcp_qpl);
-#endif
-#ifdef CONFIG_UADK
- migration_test_add("/migration/multifd/tcp/plain/uadk",
- test_multifd_tcp_uadk);
-#endif
-#ifdef CONFIG_GNUTLS
- migration_test_add("/migration/multifd/tcp/tls/psk/match",
- test_multifd_tcp_tls_psk_match);
- migration_test_add("/migration/multifd/tcp/tls/psk/mismatch",
- test_multifd_tcp_tls_psk_mismatch);
-#ifdef CONFIG_TASN1
- migration_test_add("/migration/multifd/tcp/tls/x509/default-host",
- test_multifd_tcp_tls_x509_default_host);
- migration_test_add("/migration/multifd/tcp/tls/x509/override-host",
- test_multifd_tcp_tls_x509_override_host);
- migration_test_add("/migration/multifd/tcp/tls/x509/mismatch-host",
- test_multifd_tcp_tls_x509_mismatch_host);
- migration_test_add("/migration/multifd/tcp/tls/x509/allow-anon-client",
- test_multifd_tcp_tls_x509_allow_anon_client);
- migration_test_add("/migration/multifd/tcp/tls/x509/reject-anon-client",
- test_multifd_tcp_tls_x509_reject_anon_client);
-#endif /* CONFIG_TASN1 */
-#endif /* CONFIG_GNUTLS */
-
- if (g_str_equal(arch, "x86_64") && has_kvm && kvm_dirty_ring_supported()) {
- migration_test_add("/migration/dirty_ring",
- test_precopy_unix_dirty_ring);
- if (qtest_has_machine("pc")) {
- migration_test_add("/migration/vcpu_dirty_limit",
- test_vcpu_dirty_limit);
- }
- }
+ migration_test_add_tls(env);
+ migration_test_add_compression(env);
+ migration_test_add_postcopy(env);
+ migration_test_add_file(env);
+ migration_test_add_precopy(env);
+ migration_test_add_cpr(env);
+ migration_test_add_misc(env);
ret = g_test_run();
g_assert_cmpint(ret, ==, 0);
- bootfile_delete();
- ret = rmdir(tmpfs);
- if (ret != 0) {
- g_test_message("unable to rmdir: path (%s): %s",
- tmpfs, strerror(errno));
- }
- g_free(tmpfs);
+ ret = migration_env_clean(env);
return ret;
}
diff --git a/tests/migration/Makefile b/tests/qtest/migration/Makefile
index 2c5ee28..2c5ee28 100644
--- a/tests/migration/Makefile
+++ b/tests/qtest/migration/Makefile
diff --git a/tests/migration/aarch64/Makefile b/tests/qtest/migration/aarch64/Makefile
index 9c4fa18..9c4fa18 100644
--- a/tests/migration/aarch64/Makefile
+++ b/tests/qtest/migration/aarch64/Makefile
diff --git a/tests/migration/aarch64/a-b-kernel.S b/tests/qtest/migration/aarch64/a-b-kernel.S
index a4103ec..a4103ec 100644
--- a/tests/migration/aarch64/a-b-kernel.S
+++ b/tests/qtest/migration/aarch64/a-b-kernel.S
diff --git a/tests/migration/aarch64/a-b-kernel.h b/tests/qtest/migration/aarch64/a-b-kernel.h
index 34e518d..34e518d 100644
--- a/tests/migration/aarch64/a-b-kernel.h
+++ b/tests/qtest/migration/aarch64/a-b-kernel.h
diff --git a/tests/qtest/migration/bootfile.c b/tests/qtest/migration/bootfile.c
new file mode 100644
index 0000000..fac059d
--- /dev/null
+++ b/tests/qtest/migration/bootfile.c
@@ -0,0 +1,70 @@
+/*
+ * Guest code setup for migration tests
+ *
+ * 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"
+
+/*
+ * 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 "bootfile.h"
+#include "i386/a-b-bootblock.h"
+#include "aarch64/a-b-kernel.h"
+#include "ppc64/a-b-kernel.h"
+#include "s390x/a-b-bios.h"
+
+static char *bootpath;
+
+void bootfile_delete(void)
+{
+ if (!bootpath) {
+ return;
+ }
+ unlink(bootpath);
+ g_free(bootpath);
+ bootpath = NULL;
+}
+
+char *bootfile_create(const char *arch, const char *dir, bool suspend_me)
+{
+ unsigned char *content;
+ size_t len;
+
+ bootfile_delete();
+ bootpath = g_strdup_printf("%s/bootsect", dir);
+ if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+ /* the assembled x86 boot sector should be exactly one sector large */
+ g_assert(sizeof(x86_bootsect) == 512);
+ x86_bootsect[SYM_suspend_me - SYM_start] = suspend_me;
+ content = x86_bootsect;
+ len = sizeof(x86_bootsect);
+ } else if (g_str_equal(arch, "s390x")) {
+ content = s390x_elf;
+ len = sizeof(s390x_elf);
+ } else if (strcmp(arch, "ppc64") == 0) {
+ content = ppc64_kernel;
+ len = sizeof(ppc64_kernel);
+ } else if (strcmp(arch, "aarch64") == 0) {
+ content = aarch64_kernel;
+ len = sizeof(aarch64_kernel);
+ g_assert(sizeof(aarch64_kernel) <= ARM_TEST_MAX_KERNEL_SIZE);
+ } else {
+ g_assert_not_reached();
+ }
+
+ FILE *bootfile = fopen(bootpath, "wb");
+
+ g_assert_cmpint(fwrite(content, len, 1, bootfile), ==, 1);
+ fclose(bootfile);
+
+ return bootpath;
+}
diff --git a/tests/migration/migration-test.h b/tests/qtest/migration/bootfile.h
index 194df7d..6d6a673 100644
--- a/tests/migration/migration-test.h
+++ b/tests/qtest/migration/bootfile.h
@@ -5,8 +5,8 @@
* See the COPYING file in the top-level directory.
*/
-#ifndef MIGRATION_TEST_H
-#define MIGRATION_TEST_H
+#ifndef BOOTFILE_H
+#define BOOTFILE_H
/* Common */
#define TEST_MEM_PAGE_SIZE 4096
@@ -33,4 +33,7 @@
*/
#define ARM_TEST_MAX_KERNEL_SIZE (512 * 1024)
-#endif /* MIGRATION_TEST_H */
+void bootfile_delete(void);
+char *bootfile_create(const char *arch, const char *dir, bool suspend_me);
+
+#endif /* BOOTFILE_H */
diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
new file mode 100644
index 0000000..b827665
--- /dev/null
+++ b/tests/qtest/migration/compression-tests.c
@@ -0,0 +1,226 @@
+/*
+ * QTest testcases for migration compression
+ *
+ * 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 "migration/framework.h"
+#include "migration/migration-qmp.h"
+#include "migration/migration-util.h"
+#include "qemu/module.h"
+
+
+static char *tmpfs;
+
+#ifdef CONFIG_ZSTD
+static void *
+migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from,
+ QTestState *to)
+{
+ migrate_set_parameter_int(from, "multifd-zstd-level", 2);
+ migrate_set_parameter_int(to, "multifd-zstd-level", 2);
+
+ return migrate_hook_start_precopy_tcp_multifd_common(from, to, "zstd");
+}
+
+static void test_multifd_tcp_zstd(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ .start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
+ };
+ test_precopy_common(&args);
+}
+
+static void test_multifd_postcopy_tcp_zstd(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ .caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true,
+ },
+ .start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
+ };
+
+ test_precopy_common(&args);
+}
+#endif /* CONFIG_ZSTD */
+
+#ifdef CONFIG_QATZIP
+static void *
+migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from,
+ QTestState *to)
+{
+ migrate_set_parameter_int(from, "multifd-qatzip-level", 2);
+ migrate_set_parameter_int(to, "multifd-qatzip-level", 2);
+
+ return migrate_hook_start_precopy_tcp_multifd_common(from, to, "qatzip");
+}
+
+static void test_multifd_tcp_qatzip(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ .start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip,
+ };
+ test_precopy_common(&args);
+}
+#endif
+
+#ifdef CONFIG_QPL
+static void *
+migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from,
+ QTestState *to)
+{
+ return migrate_hook_start_precopy_tcp_multifd_common(from, to, "qpl");
+}
+
+static void test_multifd_tcp_qpl(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ .start_hook = migrate_hook_start_precopy_tcp_multifd_qpl,
+ };
+ test_precopy_common(&args);
+}
+#endif /* CONFIG_QPL */
+
+#ifdef CONFIG_UADK
+static void *
+migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from,
+ QTestState *to)
+{
+ return migrate_hook_start_precopy_tcp_multifd_common(from, to, "uadk");
+}
+
+static void test_multifd_tcp_uadk(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ .start_hook = migrate_hook_start_precopy_tcp_multifd_uadk,
+ };
+ test_precopy_common(&args);
+}
+#endif /* CONFIG_UADK */
+
+static void *
+migrate_hook_start_xbzrle(QTestState *from,
+ QTestState *to)
+{
+ migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432);
+ return NULL;
+}
+
+static void test_precopy_unix_xbzrle(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = uri,
+ .start_hook = migrate_hook_start_xbzrle,
+ .iterations = 2,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_XBZRLE] = true,
+ },
+ /*
+ * XBZRLE needs pages to be modified when doing the 2nd+ round
+ * iteration to have real data pushed to the stream.
+ */
+ .live = true,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void *
+migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from,
+ QTestState *to)
+{
+ /*
+ * Overloading this test to also check that set_parameter does not error.
+ * This is also done in the tests for the other compression methods.
+ */
+ migrate_set_parameter_int(from, "multifd-zlib-level", 2);
+ migrate_set_parameter_int(to, "multifd-zlib-level", 2);
+
+ return migrate_hook_start_precopy_tcp_multifd_common(from, to, "zlib");
+}
+
+static void test_multifd_tcp_zlib(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ .start_hook = migrate_hook_start_precopy_tcp_multifd_zlib,
+ };
+ test_precopy_common(&args);
+}
+
+static void migration_test_add_compression_smoke(MigrationTestEnv *env)
+{
+ migration_test_add("/migration/multifd/tcp/plain/zlib",
+ test_multifd_tcp_zlib);
+}
+
+void migration_test_add_compression(MigrationTestEnv *env)
+{
+ tmpfs = env->tmpfs;
+
+ migration_test_add_compression_smoke(env);
+
+ if (!env->full_set) {
+ return;
+ }
+
+#ifdef CONFIG_ZSTD
+ migration_test_add("/migration/multifd/tcp/plain/zstd",
+ test_multifd_tcp_zstd);
+ if (env->has_uffd) {
+ migration_test_add("/migration/multifd+postcopy/tcp/plain/zstd",
+ test_multifd_postcopy_tcp_zstd);
+ }
+#endif
+
+#ifdef CONFIG_QATZIP
+ migration_test_add("/migration/multifd/tcp/plain/qatzip",
+ test_multifd_tcp_qatzip);
+#endif
+
+#ifdef CONFIG_QPL
+ migration_test_add("/migration/multifd/tcp/plain/qpl",
+ test_multifd_tcp_qpl);
+#endif
+
+#ifdef CONFIG_UADK
+ migration_test_add("/migration/multifd/tcp/plain/uadk",
+ test_multifd_tcp_uadk);
+#endif
+
+ if (g_test_slow()) {
+ migration_test_add("/migration/precopy/unix/xbzrle",
+ test_precopy_unix_xbzrle);
+ }
+}
diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
new file mode 100644
index 0000000..5e764a6
--- /dev/null
+++ b/tests/qtest/migration/cpr-tests.c
@@ -0,0 +1,136 @@
+/*
+ * QTest testcases for CPR
+ *
+ * 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 "migration/framework.h"
+#include "migration/migration-qmp.h"
+#include "migration/migration-util.h"
+
+
+static char *tmpfs;
+
+static void *migrate_hook_start_mode_reboot(QTestState *from, QTestState *to)
+{
+ migrate_set_parameter_str(from, "mode", "cpr-reboot");
+ migrate_set_parameter_str(to, "mode", "cpr-reboot");
+
+ return NULL;
+}
+
+static void test_mode_reboot(void)
+{
+ g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
+ FILE_TEST_FILENAME);
+ MigrateCommon args = {
+ .start.use_shmem = true,
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_mode_reboot,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true,
+ },
+ };
+
+ test_file_common(&args, true);
+}
+
+static void *test_mode_transfer_start(QTestState *from, QTestState *to)
+{
+ migrate_set_parameter_str(from, "mode", "cpr-transfer");
+ return NULL;
+}
+
+/*
+ * cpr-transfer mode cannot use the target monitor prior to starting the
+ * migration, and cannot connect synchronously to the monitor, so defer
+ * the target connection.
+ */
+static void test_mode_transfer_common(bool incoming_defer)
+{
+ g_autofree char *cpr_path = g_strdup_printf("%s/cpr.sock", tmpfs);
+ g_autofree char *mig_path = g_strdup_printf("%s/migsocket", tmpfs);
+ g_autofree char *uri = g_strdup_printf("unix:%s", mig_path);
+ g_autofree char *opts_target = NULL;
+
+ const char *opts = "-machine aux-ram-share=on -nodefaults";
+ g_autofree const char *cpr_channel = g_strdup_printf(
+ "cpr,addr.transport=socket,addr.type=unix,addr.path=%s",
+ cpr_path);
+
+ g_autofree char *connect_channels = g_strdup_printf(
+ "[ { 'channel-type': 'main',"
+ " 'addr': { 'transport': 'socket',"
+ " 'type': 'unix',"
+ " 'path': '%s' } } ]",
+ mig_path);
+
+ /*
+ * Set up a UNIX domain socket for the CPR channel before
+ * launching the destination VM, to avoid timing issues
+ * during connection setup.
+ */
+ int cpr_sockfd = qtest_socket_server(cpr_path);
+ g_assert(cpr_sockfd >= 0);
+
+ opts_target = g_strdup_printf("-incoming cpr,addr.transport=socket,"
+ "addr.type=fd,addr.str=%d %s",
+ cpr_sockfd, opts);
+ MigrateCommon args = {
+ .start.opts_source = opts,
+ .start.opts_target = opts_target,
+ .start.defer_target_connect = true,
+ .start.memory_backend = "-object memory-backend-memfd,id=pc.ram,size=%s"
+ " -machine memory-backend=pc.ram",
+ .listen_uri = incoming_defer ? "defer" : uri,
+ .connect_channels = connect_channels,
+ .cpr_channel = cpr_channel,
+ .start_hook = test_mode_transfer_start,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_mode_transfer(void)
+{
+ test_mode_transfer_common(NULL);
+}
+
+static void test_mode_transfer_defer(void)
+{
+ test_mode_transfer_common(true);
+}
+
+void migration_test_add_cpr(MigrationTestEnv *env)
+{
+ tmpfs = env->tmpfs;
+
+ /* no tests in the smoke set for now */
+
+ if (!env->full_set) {
+ return;
+ }
+
+ /*
+ * Our CI system has problems with shared memory.
+ * Don't run this test until we find a workaround.
+ */
+ if (getenv("QEMU_TEST_FLAKY_TESTS")) {
+ migration_test_add("/migration/mode/reboot", test_mode_reboot);
+ }
+
+ if (env->has_kvm) {
+ migration_test_add("/migration/mode/transfer", test_mode_transfer);
+ migration_test_add("/migration/mode/transfer/defer",
+ test_mode_transfer_defer);
+ }
+}
diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c
new file mode 100644
index 0000000..4d78ce0
--- /dev/null
+++ b/tests/qtest/migration/file-tests.c
@@ -0,0 +1,341 @@
+/*
+ * QTest testcases for migration to file
+ *
+ * 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 "migration/framework.h"
+#include "migration/migration-qmp.h"
+#include "migration/migration-util.h"
+#include "qobject/qlist.h"
+
+
+static char *tmpfs;
+
+static void test_precopy_file(void)
+{
+ g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
+ FILE_TEST_FILENAME);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ };
+
+ test_file_common(&args, true);
+}
+
+#ifndef _WIN32
+static void fdset_add_fds(QTestState *qts, const char *file, int flags,
+ int num_fds, bool direct_io)
+{
+ for (int i = 0; i < num_fds; i++) {
+ int fd;
+
+#ifdef O_DIRECT
+ /* only secondary channels can use direct-io */
+ if (direct_io && i != 0) {
+ flags |= O_DIRECT;
+ }
+#endif
+
+ fd = open(file, flags, 0660);
+ assert(fd != -1);
+
+ qtest_qmp_fds_assert_success(qts, &fd, 1, "{'execute': 'add-fd', "
+ "'arguments': {'fdset-id': 1}}");
+ close(fd);
+ }
+}
+
+static void *migrate_hook_start_file_offset_fdset(QTestState *from,
+ QTestState *to)
+{
+ g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
+
+ fdset_add_fds(from, file, O_WRONLY, 1, false);
+ fdset_add_fds(to, file, O_RDONLY, 1, false);
+
+ return NULL;
+}
+
+static void test_precopy_file_offset_fdset(void)
+{
+ g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
+ FILE_TEST_OFFSET);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_file_offset_fdset,
+ };
+
+ test_file_common(&args, false);
+}
+#endif
+
+static void test_precopy_file_offset(void)
+{
+ g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=%d", tmpfs,
+ FILE_TEST_FILENAME,
+ FILE_TEST_OFFSET);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ };
+
+ test_file_common(&args, false);
+}
+
+static void test_precopy_file_offset_bad(void)
+{
+ /* using a value not supported by qemu_strtosz() */
+ g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=0x20M",
+ tmpfs, FILE_TEST_FILENAME);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ .result = MIG_TEST_QMP_ERROR,
+ };
+
+ test_file_common(&args, false);
+}
+
+static void test_precopy_file_mapped_ram_live(void)
+{
+ g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
+ FILE_TEST_FILENAME);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
+ },
+ };
+
+ test_file_common(&args, false);
+}
+
+static void test_precopy_file_mapped_ram(void)
+{
+ g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
+ FILE_TEST_FILENAME);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
+ },
+ };
+
+ test_file_common(&args, true);
+}
+
+static void test_multifd_file_mapped_ram_live(void)
+{
+ g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
+ FILE_TEST_FILENAME);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
+ },
+ };
+
+ test_file_common(&args, false);
+}
+
+static void test_multifd_file_mapped_ram(void)
+{
+ g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
+ FILE_TEST_FILENAME);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
+ },
+ };
+
+ test_file_common(&args, true);
+}
+
+static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from,
+ QTestState *to)
+{
+ migrate_set_parameter_bool(from, "direct-io", true);
+ migrate_set_parameter_bool(to, "direct-io", true);
+
+ return NULL;
+}
+
+static void test_multifd_file_mapped_ram_dio(void)
+{
+ g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
+ FILE_TEST_FILENAME);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_multifd_mapped_ram_dio,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ };
+
+ if (!probe_o_direct_support(tmpfs)) {
+ g_test_skip("Filesystem does not support O_DIRECT");
+ return;
+ }
+
+ test_file_common(&args, true);
+}
+
+#ifndef _WIN32
+static void migrate_hook_end_multifd_mapped_ram_fdset(QTestState *from,
+ QTestState *to,
+ void *opaque)
+{
+ QDict *resp;
+ QList *fdsets;
+
+ /*
+ * Remove the fdsets after migration, otherwise a second migration
+ * would fail due fdset reuse.
+ */
+ qtest_qmp_assert_success(from, "{'execute': 'remove-fd', "
+ "'arguments': { 'fdset-id': 1}}");
+
+ /*
+ * Make sure no fdsets are left after migration, otherwise a
+ * second migration would fail due fdset reuse.
+ */
+ resp = qtest_qmp(from, "{'execute': 'query-fdsets', "
+ "'arguments': {}}");
+ g_assert(qdict_haskey(resp, "return"));
+ fdsets = qdict_get_qlist(resp, "return");
+ g_assert(fdsets && qlist_empty(fdsets));
+ qobject_unref(resp);
+}
+
+static void *migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState *from,
+ QTestState *to)
+{
+ g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
+
+ fdset_add_fds(from, file, O_WRONLY, 2, true);
+ fdset_add_fds(to, file, O_RDONLY, 2, true);
+
+ migrate_set_parameter_bool(from, "direct-io", true);
+ migrate_set_parameter_bool(to, "direct-io", true);
+
+ return NULL;
+}
+
+static void *migrate_hook_start_multifd_mapped_ram_fdset(QTestState *from,
+ QTestState *to)
+{
+ g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
+
+ fdset_add_fds(from, file, O_WRONLY, 2, false);
+ fdset_add_fds(to, file, O_RDONLY, 2, false);
+
+ return NULL;
+}
+
+static void test_multifd_file_mapped_ram_fdset(void)
+{
+ g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
+ FILE_TEST_OFFSET);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_multifd_mapped_ram_fdset,
+ .end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ };
+
+ test_file_common(&args, true);
+}
+
+static void test_multifd_file_mapped_ram_fdset_dio(void)
+{
+ g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
+ FILE_TEST_OFFSET);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio,
+ .end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ };
+
+ if (!probe_o_direct_support(tmpfs)) {
+ g_test_skip("Filesystem does not support O_DIRECT");
+ return;
+ }
+
+ test_file_common(&args, true);
+}
+#endif /* !_WIN32 */
+
+static void migration_test_add_file_smoke(MigrationTestEnv *env)
+{
+ migration_test_add("/migration/precopy/file",
+ test_precopy_file);
+
+ migration_test_add("/migration/multifd/file/mapped-ram/dio",
+ test_multifd_file_mapped_ram_dio);
+}
+
+void migration_test_add_file(MigrationTestEnv *env)
+{
+ tmpfs = env->tmpfs;
+
+ migration_test_add_file_smoke(env);
+
+ if (!env->full_set) {
+ return;
+ }
+
+ migration_test_add("/migration/precopy/file/offset",
+ test_precopy_file_offset);
+#ifndef _WIN32
+ migration_test_add("/migration/precopy/file/offset/fdset",
+ test_precopy_file_offset_fdset);
+#endif
+ migration_test_add("/migration/precopy/file/offset/bad",
+ test_precopy_file_offset_bad);
+
+ migration_test_add("/migration/precopy/file/mapped-ram",
+ test_precopy_file_mapped_ram);
+ migration_test_add("/migration/precopy/file/mapped-ram/live",
+ test_precopy_file_mapped_ram_live);
+
+ migration_test_add("/migration/multifd/file/mapped-ram",
+ test_multifd_file_mapped_ram);
+ migration_test_add("/migration/multifd/file/mapped-ram/live",
+ test_multifd_file_mapped_ram_live);
+
+#ifndef _WIN32
+ migration_test_add("/migration/multifd/file/mapped-ram/fdset",
+ test_multifd_file_mapped_ram_fdset);
+ migration_test_add("/migration/multifd/file/mapped-ram/fdset/dio",
+ test_multifd_file_mapped_ram_fdset_dio);
+#endif
+}
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
new file mode 100644
index 0000000..407c902
--- /dev/null
+++ b/tests/qtest/migration/framework.c
@@ -0,0 +1,1066 @@
+/*
+ * 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 "chardev/char.h"
+#include "crypto/tlscredspsk.h"
+#include "libqtest.h"
+#include "migration/bootfile.h"
+#include "migration/framework.h"
+#include "migration/migration-qmp.h"
+#include "migration/migration-util.h"
+#include "ppc-util.h"
+#include "qapi/error.h"
+#include "qobject/qjson.h"
+#include "qobject/qlist.h"
+#include "qemu/module.h"
+#include "qemu/option.h"
+#include "qemu/range.h"
+#include "qemu/sockets.h"
+
+
+#define QEMU_VM_FILE_MAGIC 0x5145564d
+#define QEMU_ENV_SRC "QTEST_QEMU_BINARY_SRC"
+#define QEMU_ENV_DST "QTEST_QEMU_BINARY_DST"
+#define MULTIFD_TEST_CHANNELS 4
+
+unsigned start_address;
+unsigned end_address;
+static QTestMigrationState src_state;
+static QTestMigrationState dst_state;
+static char *tmpfs;
+
+/*
+ * An initial 3 MB offset is used as that corresponds
+ * to ~1 sec of data transfer with our bandwidth setting.
+ */
+#define MAGIC_OFFSET_BASE (3 * 1024 * 1024)
+/*
+ * A further 1k is added to ensure we're not a multiple
+ * of TEST_MEM_PAGE_SIZE, thus avoid clash with writes
+ * from the migration guest workload.
+ */
+#define MAGIC_OFFSET_SHUFFLE 1024
+#define MAGIC_OFFSET (MAGIC_OFFSET_BASE + MAGIC_OFFSET_SHUFFLE)
+#define MAGIC_MARKER 0xFEED12345678CAFEULL
+
+
+/*
+ * 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 (unless we enabled suspend/resume)
+ */
+void wait_for_serial(const char *side)
+{
+ g_autofree char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
+ FILE *serialfile = fopen(serialpath, "r");
+
+ do {
+ int readvalue = fgetc(serialfile);
+
+ switch (readvalue) {
+ case 'A':
+ /* Fine */
+ break;
+
+ case 'B':
+ /* It's alive! */
+ fclose(serialfile);
+ return;
+
+ case EOF:
+ 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);
+}
+
+void migrate_prepare_for_dirty_mem(QTestState *from)
+{
+ /*
+ * The guest workflow iterates from start_address to
+ * end_address, writing 1 byte every TEST_MEM_PAGE_SIZE
+ * bytes.
+ *
+ * IOW, if we write to mem at a point which is NOT
+ * a multiple of TEST_MEM_PAGE_SIZE, our write won't
+ * conflict with the migration workflow.
+ *
+ * We put in a marker here, that we'll use to determine
+ * when the data has been transferred to the dst.
+ */
+ qtest_writeq(from, start_address + MAGIC_OFFSET, MAGIC_MARKER);
+}
+
+void migrate_wait_for_dirty_mem(QTestState *from, QTestState *to)
+{
+ uint64_t watch_address = start_address + MAGIC_OFFSET_BASE;
+ uint64_t marker_address = start_address + MAGIC_OFFSET;
+ uint8_t watch_byte;
+
+ /*
+ * Wait for the MAGIC_MARKER to get transferred, as an
+ * indicator that a migration pass has made some known
+ * amount of progress.
+ */
+ do {
+ usleep(1000 * 10);
+ } while (qtest_readq(to, marker_address) != MAGIC_MARKER);
+
+
+ /* If suspended, src only iterates once, and watch_byte may never change */
+ if (src_state.suspend_me) {
+ return;
+ }
+
+ /*
+ * Now ensure that already transferred bytes are
+ * dirty again from the guest workload. Note the
+ * guest byte value will wrap around and by chance
+ * match the original watch_byte. This is harmless
+ * as we'll eventually see a different value if we
+ * keep watching
+ */
+ watch_byte = qtest_readb(from, watch_address);
+ do {
+ usleep(1000 * 10);
+ } while (qtest_readb(from, watch_address) == watch_byte);
+}
+
+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)
+{
+ g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, filename);
+
+ unlink(path);
+}
+
+static QList *migrate_start_get_qmp_capabilities(const MigrateStart *args)
+{
+ QList *capabilities = NULL;
+
+ if (args->oob) {
+ capabilities = qlist_new();
+ qlist_append_str(capabilities, "oob");
+ }
+ return capabilities;
+}
+
+static void migrate_start_set_capabilities(QTestState *from, QTestState *to,
+ MigrateStart *args)
+{
+ /*
+ * MigrationCapability_lookup and MIGRATION_CAPABILITY_ constants
+ * are from qapi-types-migration.h.
+ */
+ for (uint8_t i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
+ if (!args->caps[i]) {
+ continue;
+ }
+ if (from) {
+ migrate_set_capability(from,
+ MigrationCapability_lookup.array[i], true);
+ }
+ if (to) {
+ migrate_set_capability(to,
+ MigrationCapability_lookup.array[i], true);
+ }
+ }
+
+ /*
+ * Always enable migration events. Libvirt always uses it, let's try
+ * to mimic as closer as that.
+ */
+ migrate_set_capability(from, "events", true);
+ if (!args->defer_target_connect) {
+ migrate_set_capability(to, "events", true);
+ }
+
+ /*
+ * Default number of channels should be fine for most
+ * tests. Individual tests can override by calling
+ * migrate_set_parameter() directly.
+ */
+ if (args->caps[MIGRATION_CAPABILITY_MULTIFD]) {
+ migrate_set_parameter_int(from, "multifd-channels",
+ MULTIFD_TEST_CHANNELS);
+ migrate_set_parameter_int(to, "multifd-channels",
+ MULTIFD_TEST_CHANNELS);
+ }
+
+ return;
+}
+
+int migrate_start(QTestState **from, QTestState **to, const char *uri,
+ MigrateStart *args)
+{
+ /* options for source and target */
+ g_autofree gchar *arch_opts = NULL;
+ g_autofree gchar *cmd_source = NULL;
+ g_autofree gchar *cmd_target = NULL;
+ const gchar *ignore_stderr;
+ g_autofree char *shmem_opts = NULL;
+ g_autofree char *shmem_path = NULL;
+ const char *kvm_opts = NULL;
+ const char *arch = qtest_get_arch();
+ const char *memory_size;
+ const char *machine_alias, *machine_opts = "";
+ g_autofree char *machine = NULL;
+ const char *bootpath;
+ g_autoptr(QList) capabilities = migrate_start_get_qmp_capabilities(args);
+ g_autofree char *memory_backend = NULL;
+ const char *events;
+
+ 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;
+ }
+ }
+
+ dst_state = (QTestMigrationState) { };
+ src_state = (QTestMigrationState) { };
+ bootpath = bootfile_create(arch, tmpfs, args->suspend_me);
+ src_state.suspend_me = args->suspend_me;
+
+ if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+ memory_size = "150M";
+
+ if (g_str_equal(arch, "i386")) {
+ machine_alias = "pc";
+ } else {
+ machine_alias = "q35";
+ }
+ arch_opts = g_strdup_printf(
+ "-drive if=none,id=d0,file=%s,format=raw "
+ "-device ide-hd,drive=d0,secs=1,cyls=1,heads=1", bootpath);
+ start_address = X86_TEST_MEM_START;
+ end_address = X86_TEST_MEM_END;
+ } else if (g_str_equal(arch, "s390x")) {
+ memory_size = "128M";
+ machine_alias = "s390-ccw-virtio";
+ arch_opts = g_strdup_printf("-bios %s", bootpath);
+ start_address = S390_TEST_MEM_START;
+ end_address = S390_TEST_MEM_END;
+ } else if (strcmp(arch, "ppc64") == 0) {
+ memory_size = "256M";
+ start_address = PPC_TEST_MEM_START;
+ end_address = PPC_TEST_MEM_END;
+ machine_alias = "pseries";
+ machine_opts = "vsmt=8";
+ arch_opts = g_strdup_printf(
+ "-nodefaults -machine " PSERIES_DEFAULT_CAPABILITIES " "
+ "-bios %s", bootpath);
+ } else if (strcmp(arch, "aarch64") == 0) {
+ memory_size = "150M";
+ machine_alias = "virt";
+ machine_opts = "gic-version=3";
+ arch_opts = g_strdup_printf("-cpu max -kernel %s", bootpath);
+ start_address = ARM_TEST_MEM_START;
+ end_address = ARM_TEST_MEM_END;
+ } else {
+ g_assert_not_reached();
+ }
+
+ if (!getenv("QTEST_LOG") && args->hide_stderr) {
+#ifndef _WIN32
+ ignore_stderr = "2>/dev/null";
+#else
+ /*
+ * On Windows the QEMU executable is created via CreateProcess() and
+ * IO redirection does not work, so don't bother adding IO redirection
+ * to the command line.
+ */
+ ignore_stderr = "";
+#endif
+ } 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);
+ }
+
+ if (args->memory_backend) {
+ memory_backend = g_strdup_printf(args->memory_backend, memory_size);
+ } else {
+ memory_backend = g_strdup_printf("-m %s ", memory_size);
+ }
+
+ if (args->use_dirty_ring) {
+ kvm_opts = ",dirty-ring-size=4096";
+ }
+
+ if (!qtest_has_machine(machine_alias)) {
+ g_autofree char *msg = g_strdup_printf("machine %s not supported", machine_alias);
+ g_test_skip(msg);
+ return -1;
+ }
+
+ machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC,
+ QEMU_ENV_DST);
+
+ g_test_message("Using machine type: %s", machine);
+
+ cmd_source = g_strdup_printf("-accel kvm%s -accel tcg "
+ "-machine %s,%s "
+ "-name source,debug-threads=on "
+ "%s "
+ "-serial file:%s/src_serial "
+ "%s %s %s %s",
+ kvm_opts ? kvm_opts : "",
+ machine, machine_opts,
+ memory_backend, tmpfs,
+ arch_opts ? arch_opts : "",
+ shmem_opts ? shmem_opts : "",
+ args->opts_source ? args->opts_source : "",
+ ignore_stderr);
+ if (!args->only_target) {
+ *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
+ qtest_qmp_set_event_callback(*from,
+ migrate_watch_for_events,
+ &src_state);
+ }
+
+ /*
+ * If the monitor connection is deferred, enable events on the command line
+ * so none are missed. This is for testing only, do not set migration
+ * options like this in general.
+ */
+ events = args->defer_target_connect ? "-global migration.x-events=on" : "";
+
+ cmd_target = g_strdup_printf("-accel kvm%s -accel tcg "
+ "-machine %s,%s "
+ "-name target,debug-threads=on "
+ "%s "
+ "-serial file:%s/dest_serial "
+ "-incoming %s "
+ "%s %s %s %s %s",
+ kvm_opts ? kvm_opts : "",
+ machine, machine_opts,
+ memory_backend, tmpfs, uri,
+ events,
+ arch_opts ? arch_opts : "",
+ shmem_opts ? shmem_opts : "",
+ args->opts_target ? args->opts_target : "",
+ ignore_stderr);
+ *to = qtest_init_ext(QEMU_ENV_DST, cmd_target, capabilities,
+ !args->defer_target_connect);
+ qtest_qmp_set_event_callback(*to,
+ migrate_watch_for_events,
+ &dst_state);
+
+ /*
+ * Remove shmem file immediately to avoid memory leak in test failed case.
+ * It's valid because QEMU has already opened this file
+ */
+ if (args->use_shmem) {
+ unlink(shmem_path);
+ }
+
+ migrate_start_set_capabilities(*from, *to, args);
+
+ return 0;
+}
+
+void 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_assert_success(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("migsocket");
+ cleanup("cpr.sock");
+ cleanup("src_serial");
+ cleanup("dest_serial");
+ cleanup(FILE_TEST_FILENAME);
+}
+
+static int migrate_postcopy_prepare(QTestState **from_ptr,
+ QTestState **to_ptr,
+ MigrateCommon *args)
+{
+ QTestState *from, *to;
+
+ /* set postcopy capabilities */
+ args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME] = true;
+ args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
+
+ if (migrate_start(&from, &to, "defer", &args->start)) {
+ return -1;
+ }
+
+ if (args->start_hook) {
+ args->postcopy_data = args->start_hook(from, to);
+ }
+
+ migrate_ensure_non_converge(from);
+ migrate_prepare_for_dirty_mem(from);
+ qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
+ " 'arguments': { "
+ " 'channels': [ { 'channel-type': 'main',"
+ " 'addr': { 'transport': 'socket',"
+ " 'type': 'inet',"
+ " 'host': '127.0.0.1',"
+ " 'port': '0' } } ] } }");
+
+ /* Wait for the first serial output from the source */
+ wait_for_serial("src_serial");
+ wait_for_suspend(from, &src_state);
+
+ migrate_qmp(from, to, NULL, NULL, "{}");
+
+ migrate_wait_for_dirty_mem(from, to);
+
+ *from_ptr = from;
+ *to_ptr = to;
+
+ return 0;
+}
+
+static void migrate_postcopy_complete(QTestState *from, QTestState *to,
+ MigrateCommon *args)
+{
+ MigrationTestEnv *env = migration_get_env();
+
+ wait_for_migration_complete(from);
+
+ if (args->start.suspend_me) {
+ /* wakeup succeeds only if guest is suspended */
+ qtest_qmp_assert_success(to, "{'execute': 'system_wakeup'}");
+ }
+
+ /* Make sure we get at least one "B" on destination */
+ wait_for_serial("dest_serial");
+
+ if (env->uffd_feature_thread_id) {
+ read_blocktime(to);
+ }
+
+ if (args->end_hook) {
+ args->end_hook(from, to, args->postcopy_data);
+ args->postcopy_data = NULL;
+ }
+
+ migrate_end(from, to, true);
+}
+
+void test_postcopy_common(MigrateCommon *args)
+{
+ QTestState *from, *to;
+
+ if (migrate_postcopy_prepare(&from, &to, args)) {
+ return;
+ }
+ migrate_postcopy_start(from, to, &src_state);
+ migrate_postcopy_complete(from, to, args);
+}
+
+static void wait_for_postcopy_status(QTestState *one, const char *status)
+{
+ wait_for_migration_status(one, status,
+ (const char * []) {
+ "failed", "active",
+ "completed", NULL
+ });
+}
+
+static void postcopy_recover_fail(QTestState *from, QTestState *to,
+ PostcopyRecoveryFailStage stage)
+{
+#ifndef _WIN32
+ bool fail_early = (stage == POSTCOPY_FAIL_CHANNEL_ESTABLISH);
+ int ret, pair1[2], pair2[2];
+ char c;
+
+ g_assert(stage > POSTCOPY_FAIL_NONE && stage < POSTCOPY_FAIL_MAX);
+
+ /* Create two unrelated socketpairs */
+ ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair1);
+ g_assert_cmpint(ret, ==, 0);
+
+ ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair2);
+ g_assert_cmpint(ret, ==, 0);
+
+ /*
+ * Give the guests unpaired ends of the sockets, so they'll all blocked
+ * at reading. This mimics a wrong channel established.
+ */
+ qtest_qmp_fds_assert_success(from, &pair1[0], 1,
+ "{ 'execute': 'getfd',"
+ " 'arguments': { 'fdname': 'fd-mig' }}");
+ qtest_qmp_fds_assert_success(to, &pair2[0], 1,
+ "{ 'execute': 'getfd',"
+ " 'arguments': { 'fdname': 'fd-mig' }}");
+
+ /*
+ * Write the 1st byte as QEMU_VM_COMMAND (0x8) for the dest socket, to
+ * emulate the 1st byte of a real recovery, but stops from there to
+ * keep dest QEMU in RECOVER. This is needed so that we can kick off
+ * the recover process on dest QEMU (by triggering the G_IO_IN event).
+ *
+ * NOTE: this trick is not needed on src QEMUs, because src doesn't
+ * rely on an pre-existing G_IO_IN event, so it will always trigger the
+ * upcoming recovery anyway even if it can read nothing.
+ */
+#define QEMU_VM_COMMAND 0x08
+ c = QEMU_VM_COMMAND;
+ ret = send(pair2[1], &c, 1, 0);
+ g_assert_cmpint(ret, ==, 1);
+
+ if (stage == POSTCOPY_FAIL_CHANNEL_ESTABLISH) {
+ /*
+ * This will make src QEMU to fail at an early stage when trying to
+ * resume later, where it shouldn't reach RECOVER stage at all.
+ */
+ close(pair1[1]);
+ }
+
+ migrate_recover(to, "fd:fd-mig");
+ migrate_qmp(from, to, "fd:fd-mig", NULL, "{'resume': true}");
+
+ /*
+ * Source QEMU has an extra RECOVER_SETUP phase, dest doesn't have it.
+ * Make sure it appears along the way.
+ */
+ migration_event_wait(from, "postcopy-recover-setup");
+
+ if (fail_early) {
+ /*
+ * When fails at reconnection, src QEMU will automatically goes
+ * back to PAUSED state. Making sure there is an event in this
+ * case: Libvirt relies on this to detect early reconnection
+ * errors.
+ */
+ migration_event_wait(from, "postcopy-paused");
+ } else {
+ /*
+ * We want to test "fail later" at RECOVER stage here. Make sure
+ * both QEMU instances will go into RECOVER stage first, then test
+ * kicking them out using migrate-pause.
+ *
+ * Explicitly check the RECOVER event on src, that's what Libvirt
+ * relies on, rather than polling.
+ */
+ migration_event_wait(from, "postcopy-recover");
+ wait_for_postcopy_status(from, "postcopy-recover");
+
+ /* Need an explicit kick on src QEMU in this case */
+ migrate_pause(from);
+ }
+
+ /*
+ * For all failure cases, we'll reach such states on both sides now.
+ * Check them.
+ */
+ wait_for_postcopy_status(from, "postcopy-paused");
+ wait_for_postcopy_status(to, "postcopy-recover");
+
+ /*
+ * Kick dest QEMU out too. This is normally not needed in reality
+ * because when the channel is shutdown it should also happen on src.
+ * However here we used separate socket pairs so we need to do that
+ * explicitly.
+ */
+ migrate_pause(to);
+ wait_for_postcopy_status(to, "postcopy-paused");
+
+ close(pair1[0]);
+ close(pair2[0]);
+ close(pair2[1]);
+
+ if (stage != POSTCOPY_FAIL_CHANNEL_ESTABLISH) {
+ close(pair1[1]);
+ }
+#endif
+}
+
+void test_postcopy_recovery_common(MigrateCommon *args)
+{
+ QTestState *from, *to;
+ g_autofree char *uri = NULL;
+
+ /*
+ * Always enable OOB QMP capability for recovery tests, migrate-recover is
+ * executed out-of-band
+ */
+ args->start.oob = true;
+
+ /* Always hide errors for postcopy recover tests since they're expected */
+ args->start.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, &src_state);
+
+ /*
+ * 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_postcopy_status(to, "postcopy-paused");
+ wait_for_postcopy_status(from, "postcopy-paused");
+
+ if (args->postcopy_recovery_fail_stage) {
+ /*
+ * Test when a wrong socket specified for recover, and then the
+ * ability to kick it out, and continue with a correct socket.
+ */
+ postcopy_recover_fail(from, to, args->postcopy_recovery_fail_stage);
+ /* continue with a good recovery */
+ }
+
+ /*
+ * 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
+ */
+ migrate_qmp(from, to, uri, NULL, "{'resume': true}");
+
+ /* Restore the postcopy bandwidth to unlimited */
+ migrate_set_parameter_int(from, "max-postcopy-bandwidth", 0);
+
+ migrate_postcopy_complete(from, to, args);
+}
+
+void test_precopy_common(MigrateCommon *args)
+{
+ QTestState *from, *to;
+ void *data_hook = NULL;
+ QObject *in_channels = NULL;
+ QObject *out_channels = NULL;
+
+ g_assert(!args->cpr_channel || args->connect_channels);
+
+ if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
+ return;
+ }
+
+ if (args->start_hook) {
+ data_hook = args->start_hook(from, to);
+ }
+
+ /* Wait for the first serial output from the source */
+ if (args->result == MIG_TEST_SUCCEED) {
+ wait_for_serial("src_serial");
+ wait_for_suspend(from, &src_state);
+ }
+
+ if (args->live) {
+ migrate_ensure_non_converge(from);
+ migrate_prepare_for_dirty_mem(from);
+ } else {
+ /*
+ * Testing non-live migration, we allow it to run at
+ * full speed to ensure short test case duration.
+ * For tests expected to fail, we don't need to
+ * change anything.
+ */
+ if (args->result == MIG_TEST_SUCCEED) {
+ qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
+ wait_for_stop(from, &src_state);
+ migrate_ensure_converge(from);
+ }
+ }
+
+ /*
+ * The cpr channel must be included in outgoing channels, but not in
+ * migrate-incoming channels.
+ */
+ if (args->connect_channels) {
+ if (args->start.defer_target_connect &&
+ !strcmp(args->listen_uri, "defer")) {
+ in_channels = qobject_from_json(args->connect_channels,
+ &error_abort);
+ }
+ out_channels = qobject_from_json(args->connect_channels, &error_abort);
+
+ if (args->cpr_channel) {
+ QList *channels_list = qobject_to(QList, out_channels);
+ QObject *obj = migrate_str_to_channel(args->cpr_channel);
+
+ qlist_append(channels_list, obj);
+ }
+ }
+
+ if (args->result == MIG_TEST_QMP_ERROR) {
+ migrate_qmp_fail(from, args->connect_uri, out_channels, "{}");
+ goto finish;
+ }
+
+ migrate_qmp(from, to, args->connect_uri, out_channels, "{}");
+
+ if (args->start.defer_target_connect) {
+ qtest_connect(to);
+ qtest_qmp_handshake(to, NULL);
+ if (!strcmp(args->listen_uri, "defer")) {
+ migrate_incoming_qmp(to, args->connect_uri, in_channels, "{}");
+ }
+ }
+
+ if (args->result != MIG_TEST_SUCCEED) {
+ bool allow_active = args->result == MIG_TEST_FAIL;
+ wait_for_migration_fail(from, allow_active);
+
+ if (args->result == MIG_TEST_FAIL_DEST_QUIT_ERR) {
+ qtest_set_expected_status(to, EXIT_FAILURE);
+ }
+ } else {
+ if (args->live) {
+ /*
+ * For initial iteration(s) we must do a full pass,
+ * but for the final iteration, we need only wait
+ * for some dirty mem before switching to converge
+ */
+ while (args->iterations > 1) {
+ wait_for_migration_pass(from, &src_state);
+ args->iterations--;
+ }
+ migrate_wait_for_dirty_mem(from, to);
+
+ migrate_ensure_converge(from);
+
+ /*
+ * We do this first, as it has a timeout to stop us
+ * hanging forever if migration didn't converge
+ */
+ wait_for_migration_complete(from);
+
+ wait_for_stop(from, &src_state);
+
+ } else {
+ wait_for_migration_complete(from);
+ /*
+ * Must wait for dst to finish reading all incoming
+ * data on the socket before issuing 'cont' otherwise
+ * it'll be ignored
+ */
+ wait_for_migration_complete(to);
+
+ qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}");
+ }
+
+ wait_for_resume(to, &dst_state);
+
+ if (args->start.suspend_me) {
+ /* wakeup succeeds only if guest is suspended */
+ qtest_qmp_assert_success(to, "{'execute': 'system_wakeup'}");
+ }
+
+ wait_for_serial("dest_serial");
+ }
+
+finish:
+ if (args->end_hook) {
+ args->end_hook(from, to, data_hook);
+ }
+
+ migrate_end(from, to, args->result == MIG_TEST_SUCCEED);
+}
+
+static void file_dirty_offset_region(void)
+{
+ g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
+ size_t size = FILE_TEST_OFFSET;
+ g_autofree char *data = g_new0(char, size);
+
+ memset(data, FILE_TEST_MARKER, size);
+ g_assert(g_file_set_contents(path, data, size, NULL));
+}
+
+static void file_check_offset_region(void)
+{
+ g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
+ size_t size = FILE_TEST_OFFSET;
+ g_autofree char *expected = g_new0(char, size);
+ g_autofree char *actual = NULL;
+ uint64_t *stream_start;
+
+ /*
+ * Ensure the skipped offset region's data has not been touched
+ * and the migration stream starts at the right place.
+ */
+
+ memset(expected, FILE_TEST_MARKER, size);
+
+ g_assert(g_file_get_contents(path, &actual, NULL, NULL));
+ g_assert(!memcmp(actual, expected, size));
+
+ stream_start = (uint64_t *)(actual + size);
+ g_assert_cmpint(cpu_to_be64(*stream_start) >> 32, ==, QEMU_VM_FILE_MAGIC);
+}
+
+void test_file_common(MigrateCommon *args, bool stop_src)
+{
+ QTestState *from, *to;
+ void *data_hook = NULL;
+ bool check_offset = false;
+
+ if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
+ return;
+ }
+
+ /*
+ * File migration is never live. We can keep the source VM running
+ * during migration, but the destination will not be running
+ * concurrently.
+ */
+ g_assert_false(args->live);
+
+ if (g_strrstr(args->connect_uri, "offset=")) {
+ check_offset = true;
+ /*
+ * This comes before the start_hook because it's equivalent to
+ * a management application creating the file and writing to
+ * it so hooks should expect the file to be already present.
+ */
+ file_dirty_offset_region();
+ }
+
+ if (args->start_hook) {
+ data_hook = args->start_hook(from, to);
+ }
+
+ migrate_ensure_converge(from);
+ wait_for_serial("src_serial");
+
+ if (stop_src) {
+ qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
+ wait_for_stop(from, &src_state);
+ }
+
+ if (args->result == MIG_TEST_QMP_ERROR) {
+ migrate_qmp_fail(from, args->connect_uri, NULL, "{}");
+ goto finish;
+ }
+
+ migrate_qmp(from, to, args->connect_uri, NULL, "{}");
+ wait_for_migration_complete(from);
+
+ /*
+ * We need to wait for the source to finish before starting the
+ * destination.
+ */
+ migrate_incoming_qmp(to, args->connect_uri, NULL, "{}");
+ wait_for_migration_complete(to);
+
+ if (stop_src) {
+ qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}");
+ }
+ wait_for_resume(to, &dst_state);
+
+ wait_for_serial("dest_serial");
+
+ if (check_offset) {
+ file_check_offset_region();
+ }
+
+finish:
+ if (args->end_hook) {
+ args->end_hook(from, to, data_hook);
+ }
+
+ migrate_end(from, to, args->result == MIG_TEST_SUCCEED);
+}
+
+void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from,
+ QTestState *to,
+ const char *method)
+{
+ migrate_set_parameter_str(from, "multifd-compression", method);
+ migrate_set_parameter_str(to, "multifd-compression", method);
+
+ /* Start incoming migration from the 1st socket */
+ migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}");
+
+ return NULL;
+}
+
+QTestMigrationState *get_src(void)
+{
+ return &src_state;
+}
+
+MigrationTestEnv *migration_get_env(void)
+{
+ static MigrationTestEnv *env;
+ g_autoptr(GError) err = NULL;
+
+ if (env) {
+ return env;
+ }
+
+ env = g_new0(MigrationTestEnv, 1);
+ env->qemu_src = getenv(QEMU_ENV_SRC);
+ env->qemu_dst = getenv(QEMU_ENV_DST);
+
+ /*
+ * The default QTEST_QEMU_BINARY must always be provided because
+ * that is what helpers use to query the accel type and
+ * architecture.
+ */
+ if (env->qemu_src && env->qemu_dst) {
+ g_test_message("Only one of %s, %s is allowed",
+ QEMU_ENV_SRC, QEMU_ENV_DST);
+ exit(1);
+ }
+
+ env->has_kvm = qtest_has_accel("kvm");
+ env->has_tcg = qtest_has_accel("tcg");
+
+ if (!env->has_tcg && !env->has_kvm) {
+ g_test_skip("No KVM or TCG accelerator available");
+ return env;
+ }
+
+ env->has_dirty_ring = kvm_dirty_ring_supported();
+ env->has_uffd = ufd_version_check(&env->uffd_feature_thread_id);
+ env->arch = qtest_get_arch();
+ env->is_x86 = !strcmp(env->arch, "i386") || !strcmp(env->arch, "x86_64");
+
+ env->tmpfs = g_dir_make_tmp("migration-test-XXXXXX", &err);
+ if (!env->tmpfs) {
+ g_test_message("Can't create temporary directory in %s: %s",
+ g_get_tmp_dir(), err->message);
+ }
+ g_assert(env->tmpfs);
+
+ tmpfs = env->tmpfs;
+
+ return env;
+}
+
+int migration_env_clean(MigrationTestEnv *env)
+{
+ char *tmpfs;
+ int ret = 0;
+
+ if (!env) {
+ return ret;
+ }
+
+ bootfile_delete();
+
+ tmpfs = env->tmpfs;
+ ret = rmdir(tmpfs);
+ if (ret != 0) {
+ g_test_message("unable to rmdir: path (%s): %s",
+ tmpfs, strerror(errno));
+ }
+ g_free(tmpfs);
+
+ return ret;
+}
diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
new file mode 100644
index 0000000..01e425e
--- /dev/null
+++ b/tests/qtest/migration/framework.h
@@ -0,0 +1,251 @@
+/*
+ * 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 TEST_FRAMEWORK_H
+#define TEST_FRAMEWORK_H
+
+#include "libqtest.h"
+#include <qapi/qapi-types-migration.h>
+
+#define FILE_TEST_FILENAME "migfile"
+#define FILE_TEST_OFFSET 0x1000
+#define FILE_TEST_MARKER 'X'
+
+typedef struct MigrationTestEnv {
+ bool has_kvm;
+ bool has_tcg;
+ bool has_uffd;
+ bool uffd_feature_thread_id;
+ bool has_dirty_ring;
+ bool is_x86;
+ bool full_set;
+ const char *arch;
+ const char *qemu_src;
+ const char *qemu_dst;
+ char *tmpfs;
+} MigrationTestEnv;
+
+MigrationTestEnv *migration_get_env(void);
+int migration_env_clean(MigrationTestEnv *env);
+
+/*
+ * A hook that runs after the src and dst QEMUs have been
+ * created, but before the migration is started. This can
+ * be used to set migration parameters and capabilities.
+ *
+ * Returns: NULL, or a pointer to opaque state to be
+ * later passed to the TestMigrateEndHook
+ */
+typedef void * (*TestMigrateStartHook)(QTestState *from,
+ QTestState *to);
+
+/*
+ * A hook that runs after the migration has finished,
+ * regardless of whether it succeeded or failed, but
+ * before QEMU has terminated (unless it self-terminated
+ * due to migration error)
+ *
+ * @opaque is a pointer to state previously returned
+ * by the TestMigrateStartHook if any, or NULL.
+ */
+typedef void (*TestMigrateEndHook)(QTestState *from,
+ QTestState *to,
+ void *opaque);
+
+/*
+ * Our goal is to ensure that we run a single full migration
+ * iteration, and also dirty memory, ensuring that at least
+ * one further iteration is required.
+ *
+ * We can't directly synchronize with the start of a migration
+ * so we have to apply some tricks monitoring memory that is
+ * transferred.
+ *
+ * Initially we set the migration bandwidth to an insanely
+ * low value, with tiny max downtime too. This basically
+ * guarantees migration will never complete.
+ *
+ * This will result in a test that is unacceptably slow though,
+ * so we can't let the entire migration pass run at this speed.
+ * Our intent is to let it run just long enough that we can
+ * prove data prior to the marker has been transferred *AND*
+ * also prove this transferred data is dirty again.
+ *
+ * Before migration starts, we write a 64-bit magic marker
+ * into a fixed location in the src VM RAM.
+ *
+ * Then watch dst memory until the marker appears. This is
+ * proof that start_address -> MAGIC_OFFSET_BASE has been
+ * transferred.
+ *
+ * Finally we go back to the source and read a byte just
+ * before the marker until we see it flip in value. This
+ * is proof that start_address -> MAGIC_OFFSET_BASE
+ * is now dirty again.
+ *
+ * IOW, we're guaranteed at least a 2nd migration pass
+ * at this point.
+ *
+ * We can now let migration run at full speed to finish
+ * the test
+ */
+typedef struct {
+ /*
+ * QTEST_LOG=1 may override this. When QTEST_LOG=1, we always dump errors
+ * unconditionally, because it means the user would like to be verbose.
+ */
+ bool hide_stderr;
+ bool use_shmem;
+ /* only launch the target process */
+ bool only_target;
+ /* Use dirty ring if true; dirty logging otherwise */
+ bool use_dirty_ring;
+ const char *opts_source;
+ const char *opts_target;
+ /* suspend the src before migrating to dest. */
+ bool suspend_me;
+ /* enable OOB QMP capability */
+ bool oob;
+ /*
+ * Format string for the main memory backend, containing one %s where the
+ * size is plugged in. If omitted, "-m %s" is used.
+ */
+ const char *memory_backend;
+
+ /* Do not connect to target monitor and qtest sockets in qtest_init */
+ bool defer_target_connect;
+
+ /*
+ * Migration capabilities to be set in both source and
+ * destination. For unilateral capabilities, use
+ * migration_set_capabilities().
+ */
+ bool caps[MIGRATION_CAPABILITY__MAX];
+} MigrateStart;
+
+typedef enum PostcopyRecoveryFailStage {
+ /*
+ * "no failure" must be 0 as it's the default. OTOH, real failure
+ * cases must be >0 to make sure they trigger by a "if" test.
+ */
+ POSTCOPY_FAIL_NONE = 0,
+ POSTCOPY_FAIL_CHANNEL_ESTABLISH,
+ POSTCOPY_FAIL_RECOVERY,
+ POSTCOPY_FAIL_MAX
+} PostcopyRecoveryFailStage;
+
+typedef struct {
+ /* Optional: fine tune start parameters */
+ MigrateStart start;
+
+ /* Required: the URI for the dst QEMU to listen on */
+ const char *listen_uri;
+
+ /*
+ * Optional: the URI for the src QEMU to connect to
+ * If NULL, then it will query the dst QEMU for its actual
+ * listening address and use that as the connect address.
+ * This allows for dynamically picking a free TCP port.
+ */
+ const char *connect_uri;
+
+ /*
+ * Optional: JSON-formatted list of src QEMU URIs. If a port is
+ * defined as '0' in any QDict key a value of '0' will be
+ * automatically converted to the correct destination port.
+ */
+ const char *connect_channels;
+
+ /* Optional: the cpr migration channel, in JSON or dotted keys format */
+ const char *cpr_channel;
+
+ /* Optional: callback to run at start to set migration parameters */
+ TestMigrateStartHook start_hook;
+ /* Optional: callback to run at finish to cleanup */
+ TestMigrateEndHook end_hook;
+
+ /*
+ * Optional: normally we expect the migration process to complete.
+ *
+ * There can be a variety of reasons and stages in which failure
+ * can happen during tests.
+ *
+ * If a failure is expected to happen at time of establishing
+ * the connection, then MIG_TEST_FAIL will indicate that the dst
+ * QEMU is expected to stay running and accept future migration
+ * connections.
+ *
+ * If a failure is expected to happen while processing the
+ * migration stream, then MIG_TEST_FAIL_DEST_QUIT_ERR will indicate
+ * that the dst QEMU is expected to quit with non-zero exit status
+ */
+ enum {
+ /* This test should succeed, the default */
+ MIG_TEST_SUCCEED = 0,
+ /* This test should fail, dest qemu should keep alive */
+ MIG_TEST_FAIL,
+ /* This test should fail, dest qemu should fail with abnormal status */
+ MIG_TEST_FAIL_DEST_QUIT_ERR,
+ /* The QMP command for this migration should fail with an error */
+ MIG_TEST_QMP_ERROR,
+ } result;
+
+ /*
+ * Optional: set number of migration passes to wait for, if live==true.
+ * If zero, then merely wait for a few MB of dirty data
+ */
+ unsigned int iterations;
+
+ /*
+ * Optional: whether the guest CPUs should be running during a precopy
+ * migration test. We used to always run with live but it took much
+ * longer so we reduced live tests to only the ones that have solid
+ * reason to be tested live-only. For each of the new test cases for
+ * precopy please provide justifications to use live explicitly (please
+ * refer to existing ones with live=true), or use live=off by default.
+ */
+ bool live;
+
+ /* Postcopy specific fields */
+ void *postcopy_data;
+ PostcopyRecoveryFailStage postcopy_recovery_fail_stage;
+} MigrateCommon;
+
+void wait_for_serial(const char *side);
+void migrate_prepare_for_dirty_mem(QTestState *from);
+void migrate_wait_for_dirty_mem(QTestState *from, QTestState *to);
+int migrate_start(QTestState **from, QTestState **to, const char *uri,
+ MigrateStart *args);
+void migrate_end(QTestState *from, QTestState *to, bool test_dest);
+
+void test_postcopy_common(MigrateCommon *args);
+void test_postcopy_recovery_common(MigrateCommon *args);
+void test_precopy_common(MigrateCommon *args);
+void test_file_common(MigrateCommon *args, bool stop_src);
+void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from,
+ QTestState *to,
+ const char *method);
+
+typedef struct QTestMigrationState QTestMigrationState;
+QTestMigrationState *get_src(void);
+
+#ifdef CONFIG_GNUTLS
+void migration_test_add_tls(MigrationTestEnv *env);
+#else
+static inline void migration_test_add_tls(MigrationTestEnv *env) {};
+#endif
+void migration_test_add_compression(MigrationTestEnv *env);
+void migration_test_add_postcopy(MigrationTestEnv *env);
+void migration_test_add_file(MigrationTestEnv *env);
+void migration_test_add_precopy(MigrationTestEnv *env);
+void migration_test_add_cpr(MigrationTestEnv *env);
+void migration_test_add_misc(MigrationTestEnv *env);
+
+#endif /* TEST_FRAMEWORK_H */
diff --git a/tests/migration/i386/Makefile b/tests/qtest/migration/i386/Makefile
index 37a72ae..37a72ae 100644
--- a/tests/migration/i386/Makefile
+++ b/tests/qtest/migration/i386/Makefile
diff --git a/tests/migration/i386/a-b-bootblock.S b/tests/qtest/migration/i386/a-b-bootblock.S
index 6f39eb6..6f39eb6 100644
--- a/tests/migration/i386/a-b-bootblock.S
+++ b/tests/qtest/migration/i386/a-b-bootblock.S
diff --git a/tests/migration/i386/a-b-bootblock.h b/tests/qtest/migration/i386/a-b-bootblock.h
index c83f871..c83f871 100644
--- a/tests/migration/i386/a-b-bootblock.h
+++ b/tests/qtest/migration/i386/a-b-bootblock.h
diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
new file mode 100644
index 0000000..fb59741
--- /dev/null
+++ b/tests/qtest/migration/migration-qmp.c
@@ -0,0 +1,520 @@
+/*
+ * QTest QMP helpers 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 "migration-qmp.h"
+#include "migration-util.h"
+#include "qapi/error.h"
+#include "qapi/qapi-types-migration.h"
+#include "qapi/qapi-visit-migration.h"
+#include "qobject/qdict.h"
+#include "qobject/qjson.h"
+#include "qobject/qlist.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/qobject-output-visitor.h"
+
+/*
+ * Number of seconds we wait when looking for migration
+ * status changes, to avoid test suite hanging forever
+ * when things go wrong. Needs to be higher enough to
+ * avoid false positives on loaded hosts.
+ */
+#define MIGRATION_STATUS_WAIT_TIMEOUT 120
+
+/*
+ * Wait for a "MIGRATION" event. This is what Libvirt uses to track
+ * migration status changes.
+ */
+void migration_event_wait(QTestState *s, const char *target)
+{
+ QDict *response, *data;
+ const char *status;
+ bool found;
+
+ do {
+ response = qtest_qmp_eventwait_ref(s, "MIGRATION");
+ data = qdict_get_qdict(response, "data");
+ g_assert(data);
+ status = qdict_get_str(data, "status");
+ found = (strcmp(status, target) == 0);
+ qobject_unref(response);
+ } while (!found);
+}
+
+/*
+ * Convert a string representing a single channel to an object.
+ * @str may be in JSON or dotted keys format.
+ */
+QObject *migrate_str_to_channel(const char *str)
+{
+ Visitor *v;
+ MigrationChannel *channel;
+ QObject *obj;
+
+ /* Create the channel */
+ v = qobject_input_visitor_new_str(str, "channel-type", &error_abort);
+ visit_type_MigrationChannel(v, NULL, &channel, &error_abort);
+ visit_free(v);
+
+ /* Create the object */
+ v = qobject_output_visitor_new(&obj);
+ visit_type_MigrationChannel(v, NULL, &channel, &error_abort);
+ visit_complete(v, &obj);
+ visit_free(v);
+
+ qapi_free_MigrationChannel(channel);
+ return obj;
+}
+
+void migrate_qmp_fail(QTestState *who, const char *uri,
+ QObject *channels, const char *fmt, ...)
+{
+ va_list ap;
+ QDict *args, *err;
+
+ va_start(ap, fmt);
+ args = qdict_from_vjsonf_nofail(fmt, ap);
+ va_end(ap);
+
+ g_assert(!qdict_haskey(args, "uri"));
+ if (uri) {
+ qdict_put_str(args, "uri", uri);
+ }
+
+ g_assert(!qdict_haskey(args, "channels"));
+ if (channels) {
+ qdict_put_obj(args, "channels", channels);
+ }
+
+ err = qtest_qmp_assert_failure_ref(
+ who, "{ 'execute': 'migrate', 'arguments': %p}", args);
+
+ g_assert(qdict_haskey(err, "desc"));
+
+ qobject_unref(err);
+}
+
+/*
+ * 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, QTestState *to, const char *uri,
+ QObject *channels, const char *fmt, ...)
+{
+ va_list ap;
+ QDict *args;
+ g_autofree char *connect_uri = NULL;
+
+ va_start(ap, fmt);
+ args = qdict_from_vjsonf_nofail(fmt, ap);
+ va_end(ap);
+
+ g_assert(!qdict_haskey(args, "uri"));
+ if (uri) {
+ qdict_put_str(args, "uri", uri);
+ } else if (!channels) {
+ connect_uri = migrate_get_connect_uri(to);
+ qdict_put_str(args, "uri", connect_uri);
+ }
+
+ g_assert(!qdict_haskey(args, "channels"));
+ if (channels) {
+ QList *channel_list = qobject_to(QList, channels);
+ migrate_set_ports(to, channel_list);
+ qdict_put_obj(args, "channels", channels);
+ }
+
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'migrate', 'arguments': %p}", args);
+}
+
+void migrate_set_capability(QTestState *who, const char *capability,
+ bool value)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'migrate-set-capabilities',"
+ "'arguments': { "
+ "'capabilities': [ { "
+ "'capability': %s, 'state': %i } ] } }",
+ capability, value);
+}
+
+void migrate_incoming_qmp(QTestState *to, const char *uri, QObject *channels,
+ 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"));
+ if (uri) {
+ qdict_put_str(args, "uri", uri);
+ }
+
+ g_assert(!qdict_haskey(args, "channels"));
+ if (channels) {
+ qdict_put_obj(args, "channels", channels);
+ }
+
+ /* This function relies on the event to work, make sure it's enabled */
+ migrate_set_capability(to, "events", true);
+
+ rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
+ args);
+
+ if (!qdict_haskey(rsp, "return")) {
+ g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(rsp), true);
+ g_test_message("%s", s->str);
+ }
+
+ g_assert(qdict_haskey(rsp, "return"));
+ qobject_unref(rsp);
+
+ migration_event_wait(to, "setup");
+}
+
+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)
+{
+ g_test_timer_start();
+ while (!check_migration_status(who, goal, ungoals)) {
+ usleep(1000);
+
+ g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT);
+ }
+}
+
+void wait_for_migration_complete(QTestState *who)
+{
+ wait_for_migration_status(who, "completed", NULL);
+}
+
+void wait_for_migration_fail(QTestState *from, bool allow_active)
+{
+ g_test_timer_start();
+ 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);
+
+ g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT);
+ } while (!failed);
+
+ /* Is the machine currently running? */
+ rsp_return = qtest_qmp_assert_success_ref(from,
+ "{ 'execute': 'query-status' }");
+ g_assert(qdict_haskey(rsp_return, "running"));
+ g_assert(qdict_get_bool(rsp_return, "running"));
+ qobject_unref(rsp_return);
+}
+
+void wait_for_stop(QTestState *who, QTestMigrationState *state)
+{
+ if (!state->stop_seen) {
+ qtest_qmp_eventwait(who, "STOP");
+ }
+}
+
+void wait_for_resume(QTestState *who, QTestMigrationState *state)
+{
+ if (!state->resume_seen) {
+ qtest_qmp_eventwait(who, "RESUME");
+ }
+}
+
+void wait_for_suspend(QTestState *who, QTestMigrationState *state)
+{
+ if (state->suspend_me && !state->suspend_seen) {
+ qtest_qmp_eventwait(who, "SUSPEND");
+ }
+}
+
+/*
+ * Note: caller is responsible to free the returned object via
+ * qobject_unref() after use
+ */
+QDict *migrate_query(QTestState *who)
+{
+ return qtest_qmp_assert_success_ref(who, "{ 'execute': 'query-migrate' }");
+}
+
+QDict *migrate_query_not_failed(QTestState *who)
+{
+ const char *status;
+ QDict *rsp = migrate_query(who);
+ status = qdict_get_str(rsp, "status");
+ if (g_str_equal(status, "failed")) {
+ g_printerr("query-migrate shows failed migration: %s\n",
+ qdict_get_str(rsp, "error-desc"));
+ }
+ g_assert(!g_str_equal(status, "failed"));
+ return rsp;
+}
+
+/*
+ * Note: caller is responsible to free the returned object via
+ * g_free() after use
+ */
+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;
+}
+
+int64_t read_ram_property_int(QTestState *who, const char *property)
+{
+ QDict *rsp_return, *rsp_ram;
+ int64_t result;
+
+ rsp_return = migrate_query_not_failed(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;
+}
+
+int64_t read_migrate_property_int(QTestState *who, const char *property)
+{
+ QDict *rsp_return;
+ int64_t result;
+
+ rsp_return = migrate_query_not_failed(who);
+ result = qdict_get_try_int(rsp_return, property, 0);
+ qobject_unref(rsp_return);
+ return result;
+}
+
+uint64_t get_migration_pass(QTestState *who)
+{
+ return read_ram_property_int(who, "dirty-sync-count");
+}
+
+void read_blocktime(QTestState *who)
+{
+ QDict *rsp_return;
+
+ rsp_return = migrate_query_not_failed(who);
+ g_assert(qdict_haskey(rsp_return, "postcopy-blocktime"));
+ qobject_unref(rsp_return);
+}
+
+/*
+ * Wait for two changes in the migration pass count, but bail if we stop.
+ */
+void wait_for_migration_pass(QTestState *who, QTestMigrationState *src_state)
+{
+ uint64_t pass, prev_pass = 0, changes = 0;
+
+ while (changes < 2 && !src_state->stop_seen && !src_state->suspend_seen) {
+ usleep(1000);
+ pass = get_migration_pass(who);
+ changes += (pass != prev_pass);
+ prev_pass = pass;
+ }
+}
+
+static long long migrate_get_parameter_int(QTestState *who,
+ const char *parameter)
+{
+ QDict *rsp;
+ long long result;
+
+ rsp = qtest_qmp_assert_success_ref(
+ 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);
+}
+
+void migrate_set_parameter_int(QTestState *who, const char *parameter,
+ long long value)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'migrate-set-parameters',"
+ "'arguments': { %s: %lld } }",
+ parameter, value);
+ migrate_check_parameter_int(who, parameter, value);
+}
+
+static char *migrate_get_parameter_str(QTestState *who, const char *parameter)
+{
+ QDict *rsp;
+ char *result;
+
+ rsp = qtest_qmp_assert_success_ref(
+ who, "{ 'execute': 'query-migrate-parameters' }");
+ result = g_strdup(qdict_get_str(rsp, parameter));
+ qobject_unref(rsp);
+ return result;
+}
+
+static void migrate_check_parameter_str(QTestState *who, const char *parameter,
+ const char *value)
+{
+ g_autofree char *result = migrate_get_parameter_str(who, parameter);
+ g_assert_cmpstr(result, ==, value);
+}
+
+void migrate_set_parameter_str(QTestState *who, const char *parameter,
+ const char *value)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'migrate-set-parameters',"
+ "'arguments': { %s: %s } }",
+ parameter, value);
+ migrate_check_parameter_str(who, parameter, value);
+}
+
+static long long migrate_get_parameter_bool(QTestState *who,
+ const char *parameter)
+{
+ QDict *rsp;
+ int result;
+
+ rsp = qtest_qmp_assert_success_ref(
+ who, "{ 'execute': 'query-migrate-parameters' }");
+ result = qdict_get_bool(rsp, parameter);
+ qobject_unref(rsp);
+ return !!result;
+}
+
+static void migrate_check_parameter_bool(QTestState *who, const char *parameter,
+ int value)
+{
+ int result;
+
+ result = migrate_get_parameter_bool(who, parameter);
+ g_assert_cmpint(result, ==, value);
+}
+
+void migrate_set_parameter_bool(QTestState *who, const char *parameter,
+ int value)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'migrate-set-parameters',"
+ "'arguments': { %s: %i } }",
+ parameter, value);
+ migrate_check_parameter_bool(who, parameter, value);
+}
+
+void migrate_ensure_non_converge(QTestState *who)
+{
+ /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
+ migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
+ migrate_set_parameter_int(who, "downtime-limit", 1);
+}
+
+void migrate_ensure_converge(QTestState *who)
+{
+ /* Should converge with 30s downtime + 1 gbs bandwidth limit */
+ migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
+ migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
+}
+
+void migrate_pause(QTestState *who)
+{
+ qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }");
+}
+
+void migrate_continue(QTestState *who, const char *state)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'migrate-continue',"
+ " 'arguments': { 'state': %s } }",
+ state);
+}
+
+void migrate_recover(QTestState *who, const char *uri)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'exec-oob': 'migrate-recover', "
+ " 'id': 'recover-cmd', "
+ " 'arguments': { 'uri': %s } }",
+ uri);
+}
+
+void migrate_cancel(QTestState *who)
+{
+ qtest_qmp_assert_success(who, "{ 'execute': 'migrate_cancel' }");
+}
+
+void migrate_postcopy_start(QTestState *from, QTestState *to,
+ QTestMigrationState *src_state)
+{
+ qtest_qmp_assert_success(from, "{ 'execute': 'migrate-start-postcopy' }");
+
+ wait_for_stop(from, src_state);
+ qtest_qmp_eventwait(to, "RESUME");
+}
diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
new file mode 100644
index 0000000..faa8181
--- /dev/null
+++ b/tests/qtest/migration/migration-qmp.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef MIGRATION_QMP_H
+#define MIGRATION_QMP_H
+
+#include "migration-util.h"
+
+QObject *migrate_str_to_channel(const char *str);
+
+G_GNUC_PRINTF(4, 5)
+void migrate_qmp_fail(QTestState *who, const char *uri,
+ QObject *channels, const char *fmt, ...);
+
+G_GNUC_PRINTF(5, 6)
+void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
+ QObject *channels, const char *fmt, ...);
+
+G_GNUC_PRINTF(4, 5)
+void migrate_incoming_qmp(QTestState *who, const char *uri,
+ QObject *channels, const char *fmt, ...);
+
+void migration_event_wait(QTestState *s, const char *target);
+void migrate_set_capability(QTestState *who, const char *capability,
+ bool value);
+int64_t read_ram_property_int(QTestState *who, const char *property);
+void migrate_set_parameter_int(QTestState *who, const char *parameter,
+ long long value);
+void wait_for_stop(QTestState *who, QTestMigrationState *state);
+void wait_for_resume(QTestState *who, QTestMigrationState *state);
+void wait_for_suspend(QTestState *who, QTestMigrationState *state);
+gchar *migrate_query_status(QTestState *who);
+int64_t read_migrate_property_int(QTestState *who, const char *property);
+uint64_t get_migration_pass(QTestState *who);
+void read_blocktime(QTestState *who);
+void wait_for_migration_pass(QTestState *who, QTestMigrationState *src_state);
+void migrate_set_parameter_str(QTestState *who, const char *parameter,
+ const char *value);
+void migrate_set_parameter_bool(QTestState *who, const char *parameter,
+ int value);
+void migrate_ensure_non_converge(QTestState *who);
+void migrate_ensure_converge(QTestState *who);
+void migrate_pause(QTestState *who);
+void migrate_continue(QTestState *who, const char *state);
+void migrate_recover(QTestState *who, const char *uri);
+void migrate_cancel(QTestState *who);
+void migrate_postcopy_start(QTestState *from, QTestState *to,
+ QTestMigrationState *src_state);
+
+#endif /* MIGRATION_QMP_H */
diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
new file mode 100644
index 0000000..642cf50
--- /dev/null
+++ b/tests/qtest/migration/migration-util.c
@@ -0,0 +1,398 @@
+/*
+ * QTest migration utilities
+ *
+ * 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 "qemu/ctype.h"
+#include "qapi/qapi-visit-sockets.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/error.h"
+#include "qobject/qlist.h"
+#include "qemu/cutils.h"
+#include "qemu/memalign.h"
+
+#include "migration/bootfile.h"
+#include "migration/migration-util.h"
+
+#if defined(__linux__)
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
+#endif
+
+/* for uffd_version_check() */
+#if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD)
+#include <sys/eventfd.h>
+#include "qemu/userfaultfd.h"
+#endif
+
+/* For dirty ring test; so far only x86_64 is supported */
+#if defined(__linux__) && defined(HOST_X86_64)
+#include "linux/kvm.h"
+#endif
+
+
+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("vsock:%s:%s",
+ addr->u.vsock.cid,
+ addr->u.vsock.port);
+ default:
+ return g_strdup("unknown address type");
+ }
+}
+
+static QDict *SocketAddress_to_qdict(SocketAddress *addr)
+{
+ QDict *dict = qdict_new();
+
+ switch (addr->type) {
+ case SOCKET_ADDRESS_TYPE_INET:
+ qdict_put_str(dict, "type", "inet");
+ qdict_put_str(dict, "host", addr->u.inet.host);
+ qdict_put_str(dict, "port", addr->u.inet.port);
+ break;
+ case SOCKET_ADDRESS_TYPE_UNIX:
+ qdict_put_str(dict, "type", "unix");
+ qdict_put_str(dict, "path", addr->u.q_unix.path);
+ break;
+ case SOCKET_ADDRESS_TYPE_FD:
+ qdict_put_str(dict, "type", "fd");
+ qdict_put_str(dict, "str", addr->u.fd.str);
+ break;
+ case SOCKET_ADDRESS_TYPE_VSOCK:
+ qdict_put_str(dict, "type", "vsock");
+ qdict_put_str(dict, "cid", addr->u.vsock.cid);
+ qdict_put_str(dict, "port", addr->u.vsock.port);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return dict;
+}
+
+static SocketAddressList *migrate_get_socket_address(QTestState *who)
+{
+ QDict *rsp;
+ SocketAddressList *addrs;
+ Visitor *iv = NULL;
+ QObject *object;
+
+ rsp = migrate_query(who);
+ object = qdict_get(rsp, "socket-address");
+
+ iv = qobject_input_visitor_new(object);
+ visit_type_SocketAddressList(iv, NULL, &addrs, &error_abort);
+ visit_free(iv);
+
+ qobject_unref(rsp);
+ return addrs;
+}
+
+char *migrate_get_connect_uri(QTestState *who)
+{
+ SocketAddressList *addrs;
+ char *connect_uri;
+
+ addrs = migrate_get_socket_address(who);
+ connect_uri = SocketAddress_to_str(addrs->value);
+
+ qapi_free_SocketAddressList(addrs);
+ return connect_uri;
+}
+
+static QDict *
+migrate_get_connect_qdict(QTestState *who)
+{
+ SocketAddressList *addrs;
+ QDict *connect_qdict;
+
+ addrs = migrate_get_socket_address(who);
+ connect_qdict = SocketAddress_to_qdict(addrs->value);
+
+ qapi_free_SocketAddressList(addrs);
+ return connect_qdict;
+}
+
+void migrate_set_ports(QTestState *to, QList *channel_list)
+{
+ g_autoptr(QDict) addr = NULL;
+ QListEntry *entry;
+ const char *addr_port = NULL;
+
+ QLIST_FOREACH_ENTRY(channel_list, entry) {
+ QDict *channel = qobject_to(QDict, qlist_entry_obj(entry));
+ QDict *addrdict = qdict_get_qdict(channel, "addr");
+
+ if (!qdict_haskey(addrdict, "port") ||
+ strcmp(qdict_get_str(addrdict, "port"), "0")) {
+ continue;
+ }
+
+ /*
+ * Fetch addr only if needed, so tests that are not yet connected to
+ * the monitor do not query it. Such tests cannot use port=0.
+ */
+ if (!addr) {
+ addr = migrate_get_connect_qdict(to);
+ }
+
+ if (qdict_haskey(addr, "port")) {
+ addr_port = qdict_get_str(addr, "port");
+ qdict_put_str(addrdict, "port", addr_port);
+ }
+ }
+}
+
+bool migrate_watch_for_events(QTestState *who, const char *name,
+ QDict *event, void *opaque)
+{
+ QTestMigrationState *state = opaque;
+
+ if (g_str_equal(name, "STOP")) {
+ state->stop_seen = true;
+ return true;
+ } else if (g_str_equal(name, "SUSPEND")) {
+ state->suspend_seen = true;
+ return true;
+ } else if (g_str_equal(name, "RESUME")) {
+ state->resume_seen = true;
+ return true;
+ }
+
+ return false;
+}
+
+char *find_common_machine_version(const char *mtype, const char *var1,
+ const char *var2)
+{
+ g_autofree char *type1 = qtest_resolve_machine_alias(var1, mtype);
+ g_autofree char *type2 = qtest_resolve_machine_alias(var2, mtype);
+
+ g_assert(type1 && type2);
+
+ if (g_str_equal(type1, type2)) {
+ /* either can be used */
+ return g_strdup(type1);
+ }
+
+ if (qtest_has_machine_with_env(var2, type1)) {
+ return g_strdup(type1);
+ }
+
+ if (qtest_has_machine_with_env(var1, type2)) {
+ return g_strdup(type2);
+ }
+
+ g_test_message("No common machine version for machine type '%s' between "
+ "binaries %s and %s", mtype, getenv(var1), getenv(var2));
+ g_assert_not_reached();
+}
+
+char *resolve_machine_version(const char *alias, const char *var1,
+ const char *var2)
+{
+ const char *mname = g_getenv("QTEST_QEMU_MACHINE_TYPE");
+ g_autofree char *machine_name = NULL;
+
+ if (mname) {
+ const char *dash = strrchr(mname, '-');
+ const char *dot = strrchr(mname, '.');
+
+ machine_name = g_strdup(mname);
+
+ if (dash && dot) {
+ assert(qtest_has_machine(machine_name));
+ return g_steal_pointer(&machine_name);
+ }
+ /* else: probably an alias, let it be resolved below */
+ } else {
+ /* use the hardcoded alias */
+ machine_name = g_strdup(alias);
+ }
+
+ return find_common_machine_version(machine_name, var1, var2);
+}
+
+typedef struct {
+ char *name;
+ void (*func)(void);
+ void (*func_full)(void *);
+} MigrationTest;
+
+static void migration_test_destroy(gpointer data)
+{
+ MigrationTest *test = (MigrationTest *)data;
+
+ g_free(test->name);
+ g_free(test);
+}
+
+static void migration_test_wrapper(const void *data)
+{
+ MigrationTest *test = (MigrationTest *)data;
+
+ g_test_message("Running /%s%s", qtest_get_arch(), test->name);
+ test->func();
+}
+
+void migration_test_add(const char *path, void (*fn)(void))
+{
+ MigrationTest *test = g_new0(MigrationTest, 1);
+
+ test->func = fn;
+ test->name = g_strdup(path);
+
+ qtest_add_data_func_full(path, test, migration_test_wrapper,
+ migration_test_destroy);
+}
+
+static void migration_test_wrapper_full(const void *data)
+{
+ MigrationTest *test = (MigrationTest *)data;
+
+ g_test_message("Running /%s%s", qtest_get_arch(), test->name);
+ test->func_full(test->name);
+}
+
+void migration_test_add_suffix(const char *path, const char *suffix,
+ void (*fn)(void *))
+{
+ MigrationTest *test = g_new0(MigrationTest, 1);
+
+ g_assert(g_str_has_suffix(path, "/"));
+ g_assert(!g_str_has_prefix(suffix, "/"));
+
+ test->func_full = fn;
+ test->name = g_strconcat(path, suffix, NULL);
+
+ qtest_add_data_func_full(test->name, test, migration_test_wrapper_full,
+ migration_test_destroy);
+}
+
+#ifdef O_DIRECT
+/*
+ * Probe for O_DIRECT support on the filesystem. Since this is used
+ * for tests, be conservative, if anything fails, assume it's
+ * unsupported.
+ */
+bool probe_o_direct_support(const char *tmpfs)
+{
+ g_autofree char *filename = g_strdup_printf("%s/probe-o-direct", tmpfs);
+ int fd, flags = O_CREAT | O_RDWR | O_TRUNC | O_DIRECT;
+ void *buf;
+ ssize_t ret, len;
+ uint64_t offset;
+
+ fd = open(filename, flags, 0660);
+ if (fd < 0) {
+ unlink(filename);
+ return false;
+ }
+
+ /*
+ * Using 1MB alignment as conservative choice to satisfy any
+ * plausible architecture default page size, and/or filesystem
+ * alignment restrictions.
+ */
+ len = 0x100000;
+ offset = 0x100000;
+
+ buf = qemu_try_memalign(len, len);
+ g_assert(buf);
+ memset(buf, 0, len);
+
+ ret = pwrite(fd, buf, len, offset);
+ unlink(filename);
+ g_free(buf);
+
+ if (ret < 0) {
+ return false;
+ }
+
+ return true;
+}
+#endif
+
+#if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD)
+bool ufd_version_check(bool *uffd_feature_thread_id)
+{
+ struct uffdio_api api_struct;
+ uint64_t ioctl_mask;
+
+ int ufd = uffd_open(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;
+ }
+
+ if (uffd_feature_thread_id) {
+ *uffd_feature_thread_id = api_struct.features & UFFD_FEATURE_THREAD_ID;
+ }
+
+ ioctl_mask = (1ULL << _UFFDIO_REGISTER |
+ 1ULL << _UFFDIO_UNREGISTER);
+ if ((api_struct.ioctls & ioctl_mask) != ioctl_mask) {
+ g_test_message("Skipping test: Missing userfault feature");
+ return false;
+ }
+
+ return true;
+}
+#else
+bool ufd_version_check(bool *uffd_feature_thread_id)
+{
+ g_test_message("Skipping test: Userfault not available (builtdtime)");
+ return false;
+}
+#endif
+
+bool kvm_dirty_ring_supported(void)
+{
+#if defined(__linux__) && defined(HOST_X86_64)
+ int ret, kvm_fd = open("/dev/kvm", O_RDONLY);
+
+ if (kvm_fd < 0) {
+ return false;
+ }
+
+ ret = ioctl(kvm_fd, KVM_CHECK_EXTENSION, KVM_CAP_DIRTY_LOG_RING);
+ close(kvm_fd);
+
+ /* We test with 4096 slots */
+ if (ret < 4096) {
+ return false;
+ }
+
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration/migration-util.h
index 72dba36..44815e9 100644
--- a/tests/qtest/migration-helpers.h
+++ b/tests/qtest/migration/migration-util.h
@@ -10,8 +10,8 @@
*
*/
-#ifndef MIGRATION_HELPERS_H
-#define MIGRATION_HELPERS_H
+#ifndef MIGRATION_UTIL_H
+#define MIGRATION_UTIL_H
#include "libqtest.h"
@@ -25,21 +25,6 @@ typedef struct QTestMigrationState {
bool migrate_watch_for_events(QTestState *who, const char *name,
QDict *event, void *opaque);
-G_GNUC_PRINTF(5, 6)
-void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
- const char *channels, const char *fmt, ...);
-
-G_GNUC_PRINTF(3, 4)
-void migrate_incoming_qmp(QTestState *who, const char *uri,
- const char *fmt, ...);
-
-G_GNUC_PRINTF(4, 5)
-void migrate_qmp_fail(QTestState *who, const char *uri,
- const char *channels, const char *fmt, ...);
-
-void migrate_set_capability(QTestState *who, const char *capability,
- bool value);
-
QDict *migrate_query(QTestState *who);
QDict *migrate_query_not_failed(QTestState *who);
@@ -62,7 +47,13 @@ static inline bool probe_o_direct_support(const char *tmpfs)
return false;
}
#endif
+
+bool ufd_version_check(bool *uffd_feature_thread_id);
+bool kvm_dirty_ring_supported(void);
void migration_test_add(const char *path, void (*fn)(void));
-void migration_event_wait(QTestState *s, const char *target);
+void migration_test_add_suffix(const char *path, const char *suffix,
+ void (*fn)(void *));
+char *migrate_get_connect_uri(QTestState *who);
+void migrate_set_ports(QTestState *to, QList *channel_list);
-#endif /* MIGRATION_HELPERS_H */
+#endif /* MIGRATION_UTIL_H */
diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
new file mode 100644
index 0000000..5499525
--- /dev/null
+++ b/tests/qtest/migration/misc-tests.c
@@ -0,0 +1,297 @@
+/*
+ * QTest testcases 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 "qapi/error.h"
+#include "qobject/qjson.h"
+#include "libqtest.h"
+#include "migration/framework.h"
+#include "migration/migration-qmp.h"
+#include "migration/migration-util.h"
+
+#define ANALYZE_SCRIPT "scripts/analyze-migration.py"
+
+static char *tmpfs;
+
+static void test_baddest(void)
+{
+ MigrateStart args = {
+ .hide_stderr = true
+ };
+ QTestState *from, *to;
+
+ if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) {
+ return;
+ }
+ migrate_qmp(from, to, "tcp:127.0.0.1:0", NULL, "{}");
+ wait_for_migration_fail(from, false);
+ migrate_end(from, to, false);
+}
+
+#ifndef _WIN32
+static void test_analyze_script(void)
+{
+ MigrateStart args = {
+ .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
+ };
+ QTestState *from, *to;
+ g_autofree char *uri = NULL;
+ g_autofree char *file = NULL;
+ int pid, wstatus;
+ const char *python = g_getenv("PYTHON");
+
+ if (!python) {
+ g_test_skip("PYTHON variable not set");
+ return;
+ }
+
+ /* dummy url */
+ if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) {
+ return;
+ }
+
+ /*
+ * Setting these two capabilities causes the "configuration"
+ * vmstate to include subsections for them. The script needs to
+ * parse those subsections properly.
+ */
+ migrate_set_capability(from, "validate-uuid", true);
+ migrate_set_capability(from, "x-ignore-shared", true);
+
+ file = g_strdup_printf("%s/migfile", tmpfs);
+ uri = g_strdup_printf("exec:cat > %s", file);
+
+ migrate_ensure_converge(from);
+ migrate_qmp(from, to, uri, NULL, "{}");
+ wait_for_migration_complete(from);
+
+ pid = fork();
+ if (!pid) {
+ close(1);
+ open("/dev/null", O_WRONLY);
+ execl(python, python, ANALYZE_SCRIPT, "-f", file, NULL);
+ g_assert_not_reached();
+ }
+
+ g_assert(waitpid(pid, &wstatus, 0) == pid);
+ if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) {
+ g_test_message("Failed to analyze the migration stream");
+ g_test_fail();
+ }
+ migrate_end(from, to, false);
+ unlink(file);
+}
+#endif
+
+static void test_ignore_shared(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ QTestState *from, *to;
+ MigrateStart args = {
+ .use_shmem = true,
+ .caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true,
+ };
+
+ if (migrate_start(&from, &to, uri, &args)) {
+ return;
+ }
+
+ migrate_ensure_non_converge(from);
+ migrate_prepare_for_dirty_mem(from);
+
+ /* Wait for the first serial output from the source */
+ wait_for_serial("src_serial");
+
+ migrate_qmp(from, to, uri, NULL, "{}");
+
+ migrate_wait_for_dirty_mem(from, to);
+
+ wait_for_stop(from, get_src());
+
+ 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"), <, 4 * 1024 * 1024);
+
+ migrate_end(from, to, true);
+}
+
+static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ QTestState *from, *to;
+
+ if (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, to, uri, NULL, "{}");
+
+ if (should_fail) {
+ qtest_set_expected_status(to, EXIT_FAILURE);
+ wait_for_migration_fail(from, true);
+ } else {
+ wait_for_migration_complete(from);
+ }
+
+ migrate_end(from, to, false);
+}
+
+static void test_validate_uuid(void)
+{
+ MigrateStart args = {
+ .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
+ .opts_target = "-uuid 11111111-1111-1111-1111-111111111111",
+ };
+
+ do_test_validate_uuid(&args, false);
+}
+
+static void test_validate_uuid_error(void)
+{
+ MigrateStart args = {
+ .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
+ .opts_target = "-uuid 22222222-2222-2222-2222-222222222222",
+ .hide_stderr = true,
+ };
+
+ do_test_validate_uuid(&args, true);
+}
+
+static void test_validate_uuid_src_not_set(void)
+{
+ MigrateStart args = {
+ .opts_target = "-uuid 22222222-2222-2222-2222-222222222222",
+ .hide_stderr = true,
+ };
+
+ do_test_validate_uuid(&args, false);
+}
+
+static void test_validate_uuid_dst_not_set(void)
+{
+ MigrateStart args = {
+ .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
+ .hide_stderr = true,
+ };
+
+ do_test_validate_uuid(&args, false);
+}
+
+static void do_test_validate_uri_channel(MigrateCommon *args)
+{
+ QTestState *from, *to;
+ QObject *channels;
+
+ if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
+ return;
+ }
+
+ /* Wait for the first serial output from the source */
+ wait_for_serial("src_serial");
+
+ /*
+ * 'uri' and 'channels' validation is checked even before the migration
+ * starts.
+ */
+ channels = args->connect_channels ?
+ qobject_from_json(args->connect_channels, &error_abort) :
+ NULL;
+ migrate_qmp_fail(from, args->connect_uri, channels, "{}");
+
+ migrate_end(from, to, false);
+}
+
+static void test_validate_uri_channels_both_set(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ },
+ .listen_uri = "defer",
+ .connect_uri = "tcp:127.0.0.1:0",
+ .connect_channels = ("[ { ""'channel-type': 'main',"
+ " 'addr': { 'transport': 'socket',"
+ " 'type': 'inet',"
+ " 'host': '127.0.0.1',"
+ " 'port': '0' } } ]"),
+ };
+
+ do_test_validate_uri_channel(&args);
+}
+
+static void test_validate_uri_channels_none_set(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ },
+ .listen_uri = "defer",
+ };
+
+ do_test_validate_uri_channel(&args);
+}
+
+static void migration_test_add_misc_smoke(MigrationTestEnv *env)
+{
+#ifndef _WIN32
+ migration_test_add("/migration/analyze-script", test_analyze_script);
+#endif
+}
+
+void migration_test_add_misc(MigrationTestEnv *env)
+{
+ tmpfs = env->tmpfs;
+
+ migration_test_add_misc_smoke(env);
+
+ if (!env->full_set) {
+ return;
+ }
+
+ migration_test_add("/migration/bad_dest", test_baddest);
+
+ /*
+ * Our CI system has problems with shared memory.
+ * Don't run this test until we find a workaround.
+ */
+ if (getenv("QEMU_TEST_FLAKY_TESTS")) {
+ migration_test_add("/migration/ignore-shared", test_ignore_shared);
+ }
+
+ migration_test_add("/migration/validate_uuid", test_validate_uuid);
+ migration_test_add("/migration/validate_uuid_error",
+ test_validate_uuid_error);
+ migration_test_add("/migration/validate_uuid_src_not_set",
+ test_validate_uuid_src_not_set);
+ migration_test_add("/migration/validate_uuid_dst_not_set",
+ test_validate_uuid_dst_not_set);
+ migration_test_add("/migration/validate_uri/channels/both_set",
+ test_validate_uri_channels_both_set);
+ migration_test_add("/migration/validate_uri/channels/none_set",
+ test_validate_uri_channels_none_set);
+}
diff --git a/tests/qtest/migration/postcopy-tests.c b/tests/qtest/migration/postcopy-tests.c
new file mode 100644
index 0000000..3773525
--- /dev/null
+++ b/tests/qtest/migration/postcopy-tests.c
@@ -0,0 +1,149 @@
+/*
+ * QTest testcases for postcopy 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 "migration/framework.h"
+#include "migration/migration-util.h"
+#include "qobject/qlist.h"
+#include "qemu/module.h"
+#include "qemu/option.h"
+#include "qemu/range.h"
+#include "qemu/sockets.h"
+
+static void test_postcopy(void)
+{
+ MigrateCommon args = { };
+
+ test_postcopy_common(&args);
+}
+
+static void test_postcopy_suspend(void)
+{
+ MigrateCommon args = {
+ .start.suspend_me = true,
+ };
+
+ test_postcopy_common(&args);
+}
+
+static void test_postcopy_preempt(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true,
+ },
+ };
+
+ test_postcopy_common(&args);
+}
+
+static void test_postcopy_recovery(void)
+{
+ MigrateCommon args = { };
+
+ test_postcopy_recovery_common(&args);
+}
+
+static void test_postcopy_recovery_fail_handshake(void)
+{
+ MigrateCommon args = {
+ .postcopy_recovery_fail_stage = POSTCOPY_FAIL_RECOVERY,
+ };
+
+ test_postcopy_recovery_common(&args);
+}
+
+static void test_postcopy_recovery_fail_reconnect(void)
+{
+ MigrateCommon args = {
+ .postcopy_recovery_fail_stage = POSTCOPY_FAIL_CHANNEL_ESTABLISH,
+ };
+
+ test_postcopy_recovery_common(&args);
+}
+
+static void test_postcopy_preempt_recovery(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true,
+ },
+ };
+
+ test_postcopy_recovery_common(&args);
+}
+
+static void migration_test_add_postcopy_smoke(MigrationTestEnv *env)
+{
+ if (env->has_uffd) {
+ migration_test_add("/migration/postcopy/plain", test_postcopy);
+ migration_test_add("/migration/postcopy/recovery/plain",
+ test_postcopy_recovery);
+ migration_test_add("/migration/postcopy/preempt/plain",
+ test_postcopy_preempt);
+ }
+}
+
+static void test_multifd_postcopy(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ };
+
+ test_postcopy_common(&args);
+}
+
+static void test_multifd_postcopy_preempt(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true,
+ },
+ };
+
+ test_postcopy_common(&args);
+}
+
+void migration_test_add_postcopy(MigrationTestEnv *env)
+{
+ migration_test_add_postcopy_smoke(env);
+
+ if (!env->full_set) {
+ return;
+ }
+
+ if (env->has_uffd) {
+ migration_test_add("/migration/postcopy/preempt/recovery/plain",
+ test_postcopy_preempt_recovery);
+
+ migration_test_add(
+ "/migration/postcopy/recovery/double-failures/handshake",
+ test_postcopy_recovery_fail_handshake);
+
+ migration_test_add(
+ "/migration/postcopy/recovery/double-failures/reconnect",
+ test_postcopy_recovery_fail_reconnect);
+
+ migration_test_add("/migration/multifd+postcopy/plain",
+ test_multifd_postcopy);
+ migration_test_add("/migration/multifd+postcopy/preempt/plain",
+ test_multifd_postcopy_preempt);
+ if (env->is_x86) {
+ migration_test_add("/migration/postcopy/suspend",
+ test_postcopy_suspend);
+ }
+ }
+}
diff --git a/tests/migration/ppc64/Makefile b/tests/qtest/migration/ppc64/Makefile
index a3a2d98..a3a2d98 100644
--- a/tests/migration/ppc64/Makefile
+++ b/tests/qtest/migration/ppc64/Makefile
diff --git a/tests/migration/ppc64/a-b-kernel.S b/tests/qtest/migration/ppc64/a-b-kernel.S
index 0613a8d..0613a8d 100644
--- a/tests/migration/ppc64/a-b-kernel.S
+++ b/tests/qtest/migration/ppc64/a-b-kernel.S
diff --git a/tests/migration/ppc64/a-b-kernel.h b/tests/qtest/migration/ppc64/a-b-kernel.h
index 673317e..673317e 100644
--- a/tests/migration/ppc64/a-b-kernel.h
+++ b/tests/qtest/migration/ppc64/a-b-kernel.h
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
new file mode 100644
index 0000000..bb38292
--- /dev/null
+++ b/tests/qtest/migration/precopy-tests.c
@@ -0,0 +1,1337 @@
+/*
+ * QTest testcase for precopy 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 "chardev/char.h"
+#include "crypto/tlscredspsk.h"
+#include "libqtest.h"
+#include "migration/bootfile.h"
+#include "migration/framework.h"
+#include "migration/migration-qmp.h"
+#include "migration/migration-util.h"
+#include "ppc-util.h"
+#include "qobject/qlist.h"
+#include "qapi-types-migration.h"
+#include "qemu/module.h"
+#include "qemu/option.h"
+#include "qemu/range.h"
+#include "qemu/sockets.h"
+
+
+/*
+ * Dirtylimit stop working if dirty page rate error
+ * value less than DIRTYLIMIT_TOLERANCE_RANGE
+ */
+#define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */
+
+static char *tmpfs;
+
+static void test_precopy_unix_plain(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateCommon args = {
+ .listen_uri = uri,
+ .connect_uri = uri,
+ /*
+ * The simplest use case of precopy, covering smoke tests of
+ * get-dirty-log dirty tracking.
+ */
+ .live = true,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_unix_suspend_live(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateCommon args = {
+ .listen_uri = uri,
+ .connect_uri = uri,
+ /*
+ * despite being live, the test is fast because the src
+ * suspends immediately.
+ */
+ .live = true,
+ .start.suspend_me = true,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_unix_suspend_notlive(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateCommon args = {
+ .listen_uri = uri,
+ .connect_uri = uri,
+ .start.suspend_me = true,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_unix_dirty_ring(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateCommon args = {
+ .start = {
+ .use_dirty_ring = true,
+ },
+ .listen_uri = uri,
+ .connect_uri = uri,
+ /*
+ * Besides the precopy/unix basic test, cover dirty ring interface
+ * rather than get-dirty-log.
+ */
+ .live = true,
+ };
+
+ test_precopy_common(&args);
+}
+
+#ifdef CONFIG_RDMA
+
+#include <sys/resource.h>
+
+/*
+ * During migration over RDMA, it will try to pin portions of guest memory,
+ * typically exceeding 100MB in this test, while the remainder will be
+ * transmitted as compressed zero pages.
+ *
+ * REQUIRED_MEMLOCK_SZ indicates the minimal mlock size in the current context.
+ */
+#define REQUIRED_MEMLOCK_SZ (128 << 20) /* 128MB */
+
+/* check 'ulimit -l' */
+static bool mlock_check(void)
+{
+ uid_t uid;
+ struct rlimit rlim;
+
+ uid = getuid();
+ if (uid == 0) {
+ return true;
+ }
+
+ if (getrlimit(RLIMIT_MEMLOCK, &rlim) != 0) {
+ return false;
+ }
+
+ return rlim.rlim_cur >= REQUIRED_MEMLOCK_SZ;
+}
+
+#define RDMA_MIGRATION_HELPER "scripts/rdma-migration-helper.sh"
+static int new_rdma_link(char *buffer, bool ipv6)
+{
+ char cmd[256];
+ bool verbose = g_getenv("QTEST_LOG");
+
+ snprintf(cmd, sizeof(cmd), "IP_FAMILY=%s %s detect %s",
+ ipv6 ? "ipv6" : "ipv4", RDMA_MIGRATION_HELPER,
+ verbose ? "" : "2>/dev/null");
+
+ FILE *pipe = popen(cmd, "r");
+ if (pipe == NULL) {
+ perror("Failed to run script");
+ return -1;
+ }
+
+ int idx = 0;
+ while (fgets(buffer + idx, 128 - idx, pipe) != NULL) {
+ idx += strlen(buffer);
+ }
+
+ int status = pclose(pipe);
+ if (status == -1) {
+ perror("Error reported by pclose()");
+ return -1;
+ } else if (WIFEXITED(status)) {
+ return WEXITSTATUS(status);
+ }
+
+ return -1;
+}
+
+static void __test_precopy_rdma_plain(bool ipv6)
+{
+ char buffer[128] = {};
+
+ if (!mlock_check()) {
+ g_test_skip("'ulimit -l' is too small, require >=128M");
+ return;
+ }
+
+ if (new_rdma_link(buffer, ipv6)) {
+ g_test_skip("No rdma link available\n"
+ "# To enable the test:\n"
+ "# Run \'" RDMA_MIGRATION_HELPER " setup\' with root to "
+ "setup a new rdma/rxe link and rerun the test\n"
+ "# Optional: run 'scripts/rdma-migration-helper.sh clean' "
+ "to revert the 'setup'");
+ return;
+ }
+
+ /*
+ * TODO: query a free port instead of hard code.
+ * 29200=('R'+'D'+'M'+'A')*100
+ **/
+ g_autofree char *uri = g_strdup_printf("rdma:%s:29200", buffer);
+
+ MigrateCommon args = {
+ .listen_uri = uri,
+ .connect_uri = uri,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_rdma_plain(void)
+{
+ __test_precopy_rdma_plain(false);
+}
+
+static void test_precopy_rdma_plain_ipv6(void)
+{
+ __test_precopy_rdma_plain(true);
+}
+#endif
+
+static void test_precopy_tcp_plain(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "tcp:127.0.0.1:0",
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_switchover_ack(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start = {
+ .caps[MIGRATION_CAPABILITY_RETURN_PATH] = true,
+ .caps[MIGRATION_CAPABILITY_SWITCHOVER_ACK] = true,
+ },
+ /*
+ * Source VM must be running in order to consider the switchover ACK
+ * when deciding to do switchover or not.
+ */
+ .live = true,
+ };
+
+ test_precopy_common(&args);
+}
+
+#ifndef _WIN32
+static void *migrate_hook_start_fd(QTestState *from,
+ QTestState *to)
+{
+ int ret;
+ int pair[2];
+
+ /* Create two connected sockets for migration */
+ ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair);
+ g_assert_cmpint(ret, ==, 0);
+
+ /* Send the 1st socket to the target */
+ qtest_qmp_fds_assert_success(to, &pair[0], 1,
+ "{ 'execute': 'getfd',"
+ " 'arguments': { 'fdname': 'fd-mig' }}");
+ close(pair[0]);
+
+ /* Start incoming migration from the 1st socket */
+ migrate_incoming_qmp(to, "fd:fd-mig", NULL, "{}");
+
+ /* Send the 2nd socket to the target */
+ qtest_qmp_fds_assert_success(from, &pair[1], 1,
+ "{ 'execute': 'getfd',"
+ " 'arguments': { 'fdname': 'fd-mig' }}");
+ close(pair[1]);
+
+ return NULL;
+}
+
+static void migrate_hook_end_fd(QTestState *from,
+ QTestState *to,
+ void *opaque)
+{
+ QDict *rsp;
+ const char *error_desc;
+
+ /* 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);
+}
+
+static void test_precopy_fd_socket(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .connect_uri = "fd:fd-mig",
+ .start_hook = migrate_hook_start_fd,
+ .end_hook = migrate_hook_end_fd,
+ };
+ test_precopy_common(&args);
+}
+
+static void *migrate_hook_start_precopy_fd_file(QTestState *from,
+ QTestState *to)
+{
+ g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
+ int src_flags = O_CREAT | O_RDWR;
+ int dst_flags = O_CREAT | O_RDWR;
+ int fds[2];
+
+ fds[0] = open(file, src_flags, 0660);
+ assert(fds[0] != -1);
+
+ fds[1] = open(file, dst_flags, 0660);
+ assert(fds[1] != -1);
+
+
+ qtest_qmp_fds_assert_success(to, &fds[0], 1,
+ "{ 'execute': 'getfd',"
+ " 'arguments': { 'fdname': 'fd-mig' }}");
+
+ qtest_qmp_fds_assert_success(from, &fds[1], 1,
+ "{ 'execute': 'getfd',"
+ " 'arguments': { 'fdname': 'fd-mig' }}");
+
+ close(fds[0]);
+ close(fds[1]);
+
+ return NULL;
+}
+
+static void test_precopy_fd_file(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .connect_uri = "fd:fd-mig",
+ .start_hook = migrate_hook_start_precopy_fd_file,
+ .end_hook = migrate_hook_end_fd,
+ };
+ test_file_common(&args, true);
+}
+#endif /* _WIN32 */
+
+/*
+ * The way auto_converge works, we need to do too many passes to
+ * run this test. Auto_converge logic is only run once every
+ * three iterations, so:
+ *
+ * - 3 iterations without auto_converge enabled
+ * - 3 iterations with pct = 5
+ * - 3 iterations with pct = 30
+ * - 3 iterations with pct = 55
+ * - 3 iterations with pct = 80
+ * - 3 iterations with pct = 95 (max(95, 80 + 25))
+ *
+ * To make things even worse, we need to run the initial stage at
+ * 3MB/s so we enter autoconverge even when host is (over)loaded.
+ */
+static void test_auto_converge(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateStart args = {};
+ QTestState *from, *to;
+ int64_t percentage;
+
+ /*
+ * We want the test to be stable and as fast as possible.
+ * E.g., with 1Gb/s bandwidth migration may pass without throttling,
+ * so we need to decrease a bandwidth.
+ */
+ const int64_t init_pct = 5, inc_pct = 25, max_pct = 95;
+ uint64_t prev_dirty_sync_cnt, dirty_sync_cnt;
+ int max_try_count, hit = 0;
+
+ if (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_ensure_non_converge(from);
+
+ /* 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, to, uri, NULL, "{}");
+
+ /* Wait for throttling begins */
+ percentage = 0;
+ do {
+ percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
+ if (percentage != 0) {
+ break;
+ }
+ usleep(20);
+ g_assert_false(get_src()->stop_seen);
+ } while (true);
+ /* The first percentage of throttling should be at least init_pct */
+ g_assert_cmpint(percentage, >=, init_pct);
+
+ /*
+ * End the loop when the dirty sync count greater than 1.
+ */
+ while ((dirty_sync_cnt = get_migration_pass(from)) < 2) {
+ usleep(1000 * 1000);
+ }
+
+ prev_dirty_sync_cnt = dirty_sync_cnt;
+
+ /*
+ * The RAMBlock dirty sync count must changes in 5 seconds, here we set
+ * the timeout to 10 seconds to ensure it changes.
+ *
+ * Note that migrate_ensure_non_converge set the max-bandwidth to 3MB/s,
+ * while the qtest mem is >= 100MB, one iteration takes at least 33s (100/3)
+ * to complete; this ensures that the RAMBlock dirty sync occurs.
+ */
+ max_try_count = 10;
+ while (--max_try_count) {
+ dirty_sync_cnt = get_migration_pass(from);
+ if (dirty_sync_cnt != prev_dirty_sync_cnt) {
+ hit = 1;
+ break;
+ }
+ prev_dirty_sync_cnt = dirty_sync_cnt;
+ sleep(1);
+ }
+ g_assert_cmpint(hit, ==, 1);
+
+ /* Now, when we tested that throttling works, let it converge */
+ migrate_ensure_converge(from);
+
+ /*
+ * 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);
+ migrate_continue(from, "pre-switchover");
+
+ qtest_qmp_eventwait(to, "RESUME");
+
+ wait_for_serial("dest_serial");
+ wait_for_migration_complete(from);
+
+ migrate_end(from, to, true);
+}
+
+static void *
+migrate_hook_start_precopy_tcp_multifd(QTestState *from,
+ QTestState *to)
+{
+ return migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+}
+
+static void *
+migrate_hook_start_precopy_tcp_multifd_zero_page_legacy(QTestState *from,
+ QTestState *to)
+{
+ migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+ migrate_set_parameter_str(from, "zero-page-detection", "legacy");
+ return NULL;
+}
+
+static void *
+migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState *from,
+ QTestState *to)
+{
+ migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+ migrate_set_parameter_str(from, "zero-page-detection", "none");
+ return NULL;
+}
+
+static void test_multifd_tcp_uri_none(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_precopy_tcp_multifd,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ /*
+ * Multifd is more complicated than most of the features, it
+ * directly takes guest page buffers when sending, make sure
+ * everything will work alright even if guest page is changing.
+ */
+ .live = true,
+ };
+ test_precopy_common(&args);
+}
+
+static void test_multifd_tcp_zero_page_legacy(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_precopy_tcp_multifd_zero_page_legacy,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ /*
+ * Multifd is more complicated than most of the features, it
+ * directly takes guest page buffers when sending, make sure
+ * everything will work alright even if guest page is changing.
+ */
+ .live = true,
+ };
+ test_precopy_common(&args);
+}
+
+static void test_multifd_tcp_no_zero_page(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_precopy_tcp_multifd_no_zero_page,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ /*
+ * Multifd is more complicated than most of the features, it
+ * directly takes guest page buffers when sending, make sure
+ * everything will work alright even if guest page is changing.
+ */
+ .live = true,
+ };
+ test_precopy_common(&args);
+}
+
+static void test_multifd_tcp_channels_none(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_precopy_tcp_multifd,
+ .live = true,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ .connect_channels = ("[ { 'channel-type': 'main',"
+ " 'addr': { 'transport': 'socket',"
+ " 'type': 'inet',"
+ " 'host': '127.0.0.1',"
+ " 'port': '0' } } ]"),
+ };
+ test_precopy_common(&args);
+}
+
+/*
+ * This test does:
+ * source target
+ * migrate_incoming
+ * migrate
+ * migrate_cancel
+ * launch another target
+ * migrate
+ *
+ * And see that it works
+ */
+static void test_multifd_tcp_cancel(bool postcopy_ram)
+{
+ MigrateStart args = {
+ .hide_stderr = true,
+ };
+ QTestState *from, *to, *to2;
+
+ if (migrate_start(&from, &to, "defer", &args)) {
+ return;
+ }
+
+ migrate_ensure_non_converge(from);
+ migrate_prepare_for_dirty_mem(from);
+
+ if (postcopy_ram) {
+ migrate_set_capability(from, "postcopy-ram", true);
+ migrate_set_capability(to, "postcopy-ram", true);
+ }
+
+ migrate_set_parameter_int(from, "multifd-channels", 16);
+ migrate_set_parameter_int(to, "multifd-channels", 16);
+
+ migrate_set_capability(from, "multifd", true);
+ migrate_set_capability(to, "multifd", true);
+
+ /* Start incoming migration from the 1st socket */
+ migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}");
+
+ /* Wait for the first serial output from the source */
+ wait_for_serial("src_serial");
+
+ migrate_qmp(from, to, NULL, NULL, "{}");
+
+ migrate_wait_for_dirty_mem(from, to);
+
+ migrate_cancel(from);
+
+ /* Make sure QEMU process "to" exited */
+ qtest_set_expected_status(to, EXIT_FAILURE);
+ qtest_wait_qemu(to);
+ qtest_quit(to);
+
+ /*
+ * Ensure the source QEMU finishes its cancellation process before we
+ * proceed with the setup of the next migration. The migrate_start()
+ * function and others might want to interact with the source in a way that
+ * is not possible while the migration is not canceled properly. For
+ * example, setting migration capabilities when the migration is still
+ * running leads to an error.
+ */
+ wait_for_migration_status(from, "cancelled", NULL);
+
+ args = (MigrateStart){
+ .only_target = true,
+ };
+
+ if (migrate_start(&from, &to2, "defer", &args)) {
+ return;
+ }
+
+ if (postcopy_ram) {
+ migrate_set_capability(to2, "postcopy-ram", true);
+ }
+
+ migrate_set_parameter_int(to2, "multifd-channels", 16);
+
+ migrate_set_capability(to2, "multifd", true);
+
+ /* Start incoming migration from the 1st socket */
+ migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", NULL, "{}");
+
+ migrate_ensure_non_converge(from);
+
+ migrate_qmp(from, to2, NULL, NULL, "{}");
+
+ migrate_wait_for_dirty_mem(from, to2);
+
+ migrate_ensure_converge(from);
+
+ wait_for_stop(from, get_src());
+ qtest_qmp_eventwait(to2, "RESUME");
+
+ wait_for_serial("dest_serial");
+ wait_for_migration_complete(from);
+ migrate_end(from, to2, true);
+}
+
+static void test_multifd_precopy_tcp_cancel(void)
+{
+ test_multifd_tcp_cancel(false);
+}
+
+static void test_multifd_postcopy_tcp_cancel(void)
+{
+ test_multifd_tcp_cancel(true);
+}
+
+static void test_cancel_src_after_failed(QTestState *from, QTestState *to,
+ const char *uri, const char *phase)
+{
+ /*
+ * No migrate_incoming_qmp() at the start to force source into
+ * failed state during migrate_qmp().
+ */
+
+ wait_for_serial("src_serial");
+ migrate_ensure_converge(from);
+
+ migrate_qmp(from, to, uri, NULL, "{}");
+
+ migration_event_wait(from, phase);
+ migrate_cancel(from);
+
+ /* cancelling will not move the migration out of 'failed' */
+
+ wait_for_migration_status(from, "failed",
+ (const char * []) { "completed", NULL });
+
+ /*
+ * Not waiting for the destination because it never started
+ * migration.
+ */
+}
+
+static void test_cancel_src_after_cancelled(QTestState *from, QTestState *to,
+ const char *uri, const char *phase)
+{
+ migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
+
+ wait_for_serial("src_serial");
+ migrate_ensure_converge(from);
+
+ migrate_qmp(from, to, uri, NULL, "{}");
+
+ /* To move to cancelled/cancelling */
+ migrate_cancel(from);
+ migration_event_wait(from, phase);
+
+ /* The migrate_cancel under test */
+ migrate_cancel(from);
+
+ wait_for_migration_status(from, "cancelled",
+ (const char * []) { "completed", NULL });
+
+ wait_for_migration_status(to, "failed",
+ (const char * []) { "completed", NULL });
+}
+
+static void test_cancel_src_after_complete(QTestState *from, QTestState *to,
+ const char *uri, const char *phase)
+{
+ migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
+
+ wait_for_serial("src_serial");
+ migrate_ensure_converge(from);
+
+ migrate_qmp(from, to, uri, NULL, "{}");
+
+ migration_event_wait(from, phase);
+ migrate_cancel(from);
+
+ /*
+ * qmp_migrate_cancel() exits early if migration is not running
+ * anymore, the status will not change to cancelled.
+ */
+ wait_for_migration_complete(from);
+ wait_for_migration_complete(to);
+}
+
+static void test_cancel_src_after_none(QTestState *from, QTestState *to,
+ const char *uri, const char *phase)
+{
+ /*
+ * Test that cancelling without a migration happening does not
+ * affect subsequent migrations
+ */
+ migrate_cancel(to);
+
+ wait_for_serial("src_serial");
+ migrate_cancel(from);
+
+ migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
+
+ migrate_ensure_converge(from);
+ migrate_qmp(from, to, uri, NULL, "{}");
+
+ wait_for_migration_complete(from);
+ wait_for_migration_complete(to);
+}
+
+static void test_cancel_src_pre_switchover(QTestState *from, QTestState *to,
+ const char *uri, const char *phase)
+{
+ migrate_set_capability(from, "pause-before-switchover", true);
+ migrate_set_capability(to, "pause-before-switchover", true);
+
+ migrate_set_capability(from, "multifd", true);
+ migrate_set_capability(to, "multifd", true);
+
+ migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
+
+ wait_for_serial("src_serial");
+ migrate_ensure_converge(from);
+
+ migrate_qmp(from, to, uri, NULL, "{}");
+
+ migration_event_wait(from, phase);
+ migrate_cancel(from);
+ migration_event_wait(from, "cancelling");
+
+ wait_for_migration_status(from, "cancelled",
+ (const char * []) { "completed", NULL });
+
+ wait_for_migration_status(to, "failed",
+ (const char * []) { "completed", NULL });
+}
+
+static void test_cancel_src_after_status(void *opaque)
+{
+ const char *test_path = opaque;
+ g_autofree char *phase = g_path_get_basename(test_path);
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ QTestState *from, *to;
+ MigrateStart args = {
+ .hide_stderr = true,
+ };
+
+ if (migrate_start(&from, &to, "defer", &args)) {
+ return;
+ }
+
+ if (g_str_equal(phase, "cancelling") ||
+ g_str_equal(phase, "cancelled")) {
+ test_cancel_src_after_cancelled(from, to, uri, phase);
+
+ } else if (g_str_equal(phase, "completed")) {
+ test_cancel_src_after_complete(from, to, uri, phase);
+
+ } else if (g_str_equal(phase, "failed")) {
+ test_cancel_src_after_failed(from, to, uri, phase);
+
+ } else if (g_str_equal(phase, "none")) {
+ test_cancel_src_after_none(from, to, uri, phase);
+
+ } else {
+ /* any state that comes before pre-switchover */
+ test_cancel_src_pre_switchover(from, to, uri, phase);
+ }
+
+ migrate_end(from, to, false);
+}
+
+static void calc_dirty_rate(QTestState *who, uint64_t calc_time)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'calc-dirty-rate',"
+ "'arguments': { "
+ "'calc-time': %" PRIu64 ","
+ "'mode': 'dirty-ring' }}",
+ calc_time);
+}
+
+static QDict *query_dirty_rate(QTestState *who)
+{
+ return qtest_qmp_assert_success_ref(who,
+ "{ 'execute': 'query-dirty-rate' }");
+}
+
+static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'set-vcpu-dirty-limit',"
+ "'arguments': { "
+ "'dirty-rate': %" PRIu64 " } }",
+ dirtyrate);
+}
+
+static void cancel_vcpu_dirty_limit(QTestState *who)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'cancel-vcpu-dirty-limit' }");
+}
+
+static QDict *query_vcpu_dirty_limit(QTestState *who)
+{
+ QDict *rsp;
+
+ rsp = qtest_qmp(who, "{ 'execute': 'query-vcpu-dirty-limit' }");
+ g_assert(!qdict_haskey(rsp, "error"));
+ g_assert(qdict_haskey(rsp, "return"));
+
+ return rsp;
+}
+
+static bool calc_dirtyrate_ready(QTestState *who)
+{
+ QDict *rsp_return;
+ const char *status;
+ bool ready;
+
+ rsp_return = query_dirty_rate(who);
+ g_assert(rsp_return);
+
+ status = qdict_get_str(rsp_return, "status");
+ g_assert(status);
+ ready = g_strcmp0(status, "measuring");
+ qobject_unref(rsp_return);
+
+ return ready;
+}
+
+static void wait_for_calc_dirtyrate_complete(QTestState *who,
+ int64_t time_s)
+{
+ int max_try_count = 10000;
+ usleep(time_s * 1000000);
+
+ while (!calc_dirtyrate_ready(who) && max_try_count--) {
+ usleep(1000);
+ }
+
+ /*
+ * Set the timeout with 10 s(max_try_count * 1000us),
+ * if dirtyrate measurement not complete, fail test.
+ */
+ g_assert_cmpint(max_try_count, !=, 0);
+}
+
+static int64_t get_dirty_rate(QTestState *who)
+{
+ QDict *rsp_return;
+ const char *status;
+ QList *rates;
+ const QListEntry *entry;
+ QDict *rate;
+ int64_t dirtyrate;
+
+ rsp_return = query_dirty_rate(who);
+ g_assert(rsp_return);
+
+ status = qdict_get_str(rsp_return, "status");
+ g_assert(status);
+ g_assert_cmpstr(status, ==, "measured");
+
+ rates = qdict_get_qlist(rsp_return, "vcpu-dirty-rate");
+ g_assert(rates && !qlist_empty(rates));
+
+ entry = qlist_first(rates);
+ g_assert(entry);
+
+ rate = qobject_to(QDict, qlist_entry_obj(entry));
+ g_assert(rate);
+
+ dirtyrate = qdict_get_try_int(rate, "dirty-rate", -1);
+
+ qobject_unref(rsp_return);
+ return dirtyrate;
+}
+
+static int64_t get_limit_rate(QTestState *who)
+{
+ QDict *rsp_return;
+ QList *rates;
+ const QListEntry *entry;
+ QDict *rate;
+ int64_t dirtyrate;
+
+ rsp_return = query_vcpu_dirty_limit(who);
+ g_assert(rsp_return);
+
+ rates = qdict_get_qlist(rsp_return, "return");
+ g_assert(rates && !qlist_empty(rates));
+
+ entry = qlist_first(rates);
+ g_assert(entry);
+
+ rate = qobject_to(QDict, qlist_entry_obj(entry));
+ g_assert(rate);
+
+ dirtyrate = qdict_get_try_int(rate, "limit-rate", -1);
+
+ qobject_unref(rsp_return);
+ return dirtyrate;
+}
+
+static QTestState *dirtylimit_start_vm(void)
+{
+ QTestState *vm = NULL;
+ g_autofree gchar *cmd = NULL;
+ const char *bootpath;
+
+ bootpath = bootfile_create(qtest_get_arch(), tmpfs, false);
+ cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 "
+ "-name dirtylimit-test,debug-threads=on "
+ "-m 150M -smp 1 "
+ "-serial file:%s/vm_serial "
+ "-drive file=%s,format=raw ",
+ tmpfs, bootpath);
+
+ vm = qtest_init(cmd);
+ return vm;
+}
+
+static void dirtylimit_stop_vm(QTestState *vm)
+{
+ g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, "vm_serial");
+
+ qtest_quit(vm);
+ unlink(path);
+}
+
+static void test_vcpu_dirty_limit(void)
+{
+ QTestState *vm;
+ int64_t origin_rate;
+ int64_t quota_rate;
+ int64_t rate ;
+ int max_try_count = 20;
+ int hit = 0;
+
+ /* Start vm for vcpu dirtylimit test */
+ vm = dirtylimit_start_vm();
+
+ /* Wait for the first serial output from the vm*/
+ wait_for_serial("vm_serial");
+
+ /* Do dirtyrate measurement with calc time equals 1s */
+ calc_dirty_rate(vm, 1);
+
+ /* Sleep calc time and wait for calc dirtyrate complete */
+ wait_for_calc_dirtyrate_complete(vm, 1);
+
+ /* Query original dirty page rate */
+ origin_rate = get_dirty_rate(vm);
+
+ /* VM booted from bootsect should dirty memory steadily */
+ assert(origin_rate != 0);
+
+ /* Setup quota dirty page rate at half of origin */
+ quota_rate = origin_rate / 2;
+
+ /* Set dirtylimit */
+ dirtylimit_set_all(vm, quota_rate);
+
+ /*
+ * Check if set-vcpu-dirty-limit and query-vcpu-dirty-limit
+ * works literally
+ */
+ g_assert_cmpint(quota_rate, ==, get_limit_rate(vm));
+
+ /* Sleep a bit to check if it take effect */
+ usleep(2000000);
+
+ /*
+ * Check if dirtylimit take effect realistically, set the
+ * timeout with 20 s(max_try_count * 1s), if dirtylimit
+ * doesn't take effect, fail test.
+ */
+ while (--max_try_count) {
+ calc_dirty_rate(vm, 1);
+ wait_for_calc_dirtyrate_complete(vm, 1);
+ rate = get_dirty_rate(vm);
+
+ /*
+ * Assume hitting if current rate is less
+ * than quota rate (within accepting error)
+ */
+ if (rate < (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
+ hit = 1;
+ break;
+ }
+ }
+
+ g_assert_cmpint(hit, ==, 1);
+
+ hit = 0;
+ max_try_count = 20;
+
+ /* Check if dirtylimit cancellation take effect */
+ cancel_vcpu_dirty_limit(vm);
+ while (--max_try_count) {
+ calc_dirty_rate(vm, 1);
+ wait_for_calc_dirtyrate_complete(vm, 1);
+ rate = get_dirty_rate(vm);
+
+ /*
+ * Assume dirtylimit be canceled if current rate is
+ * greater than quota rate (within accepting error)
+ */
+ if (rate > (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
+ hit = 1;
+ break;
+ }
+ }
+
+ g_assert_cmpint(hit, ==, 1);
+ dirtylimit_stop_vm(vm);
+}
+
+static void migrate_dirty_limit_wait_showup(QTestState *from,
+ const int64_t period,
+ const int64_t value)
+{
+ /* Enable dirty limit capability */
+ migrate_set_capability(from, "dirty-limit", true);
+
+ /* Set dirty limit parameters */
+ migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period);
+ migrate_set_parameter_int(from, "vcpu-dirty-limit", value);
+
+ /* Make sure migrate can't converge */
+ migrate_ensure_non_converge(from);
+
+ /* To check limit rate after precopy */
+ migrate_set_capability(from, "pause-before-switchover", true);
+
+ /* Wait for the serial output from the source */
+ wait_for_serial("src_serial");
+}
+
+/*
+ * This test does:
+ * source destination
+ * start vm
+ * start incoming vm
+ * migrate
+ * wait dirty limit to begin
+ * cancel migrate
+ * cancellation check
+ * restart incoming vm
+ * migrate
+ * wait dirty limit to begin
+ * wait pre-switchover event
+ * convergence condition check
+ *
+ * And see if dirty limit migration works correctly.
+ * This test case involves many passes, so it runs in slow mode only.
+ */
+static void test_dirty_limit(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ QTestState *from, *to;
+ int64_t remaining;
+ uint64_t throttle_us_per_full;
+ /*
+ * We want the test to be stable and as fast as possible.
+ * E.g., with 1Gb/s bandwidth migration may pass without dirty limit,
+ * so we need to decrease a bandwidth.
+ */
+ const int64_t dirtylimit_period = 1000, dirtylimit_value = 50;
+ 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;
+ int max_try_count = 10;
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ .use_dirty_ring = true,
+ },
+ .listen_uri = uri,
+ .connect_uri = uri,
+ };
+
+ /* Start src, dst vm */
+ if (migrate_start(&from, &to, args.listen_uri, &args.start)) {
+ return;
+ }
+
+ /* Prepare for dirty limit migration and wait src vm show up */
+ migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
+
+ /* Start migrate */
+ migrate_qmp(from, to, args.connect_uri, NULL, "{}");
+
+ /* Wait for dirty limit throttle begin */
+ throttle_us_per_full = 0;
+ while (throttle_us_per_full == 0) {
+ throttle_us_per_full =
+ read_migrate_property_int(from,
+ "dirty-limit-throttle-time-per-round");
+ usleep(100);
+ g_assert_false(get_src()->stop_seen);
+ }
+
+ /* Now cancel migrate and wait for dirty limit throttle switch off */
+ migrate_cancel(from);
+ wait_for_migration_status(from, "cancelled", NULL);
+
+ /* destination always fails after cancel */
+ migration_event_wait(to, "failed");
+ qtest_set_expected_status(to, EXIT_FAILURE);
+ qtest_quit(to);
+
+ /* Check if dirty limit throttle switched off, set timeout 1ms */
+ do {
+ throttle_us_per_full =
+ read_migrate_property_int(from,
+ "dirty-limit-throttle-time-per-round");
+ usleep(100);
+ g_assert_false(get_src()->stop_seen);
+ } while (throttle_us_per_full != 0 && --max_try_count);
+
+ /* Assert dirty limit is not in service */
+ g_assert_cmpint(throttle_us_per_full, ==, 0);
+
+ args = (MigrateCommon) {
+ .start = {
+ .only_target = true,
+ .use_dirty_ring = true,
+ },
+ .listen_uri = uri,
+ .connect_uri = uri,
+ };
+
+ /* Restart dst vm, src vm already show up so we needn't wait anymore */
+ if (migrate_start(&from, &to, args.listen_uri, &args.start)) {
+ return;
+ }
+
+ /* Start migrate */
+ migrate_qmp(from, to, args.connect_uri, NULL, "{}");
+
+ /* Wait for dirty limit throttle begin */
+ throttle_us_per_full = 0;
+ while (throttle_us_per_full == 0) {
+ throttle_us_per_full =
+ read_migrate_property_int(from,
+ "dirty-limit-throttle-time-per-round");
+ usleep(100);
+ g_assert_false(get_src()->stop_seen);
+ }
+
+ /*
+ * The dirty limit rate should equals the return value of
+ * query-vcpu-dirty-limit if dirty limit cap set
+ */
+ g_assert_cmpint(dirtylimit_value, ==, get_limit_rate(from));
+
+ /* Now, we have tested if dirty limit 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 if migration
+ * satisfy the convergence condition
+ */
+ wait_for_migration_status(from, "pre-switchover", NULL);
+
+ remaining = read_ram_property_int(from, "remaining");
+ g_assert_cmpint(remaining, <,
+ (expected_threshold + expected_threshold / 100));
+
+ migrate_continue(from, "pre-switchover");
+
+ qtest_qmp_eventwait(to, "RESUME");
+
+ wait_for_serial("dest_serial");
+ wait_for_migration_complete(from);
+
+ migrate_end(from, to, true);
+}
+
+static void migration_test_add_precopy_smoke(MigrationTestEnv *env)
+{
+ if (env->is_x86) {
+ migration_test_add("/migration/precopy/unix/suspend/live",
+ test_precopy_unix_suspend_live);
+ migration_test_add("/migration/precopy/unix/suspend/notlive",
+ test_precopy_unix_suspend_notlive);
+ }
+
+ migration_test_add("/migration/precopy/unix/plain",
+ test_precopy_unix_plain);
+
+ migration_test_add("/migration/precopy/tcp/plain", test_precopy_tcp_plain);
+ migration_test_add("/migration/multifd/tcp/uri/plain/none",
+ test_multifd_tcp_uri_none);
+ migration_test_add("/migration/multifd/tcp/plain/cancel",
+ test_multifd_precopy_tcp_cancel);
+ if (env->has_uffd) {
+ migration_test_add("/migration/multifd+postcopy/tcp/plain/cancel",
+ test_multifd_postcopy_tcp_cancel);
+ }
+
+#ifdef CONFIG_RDMA
+ migration_test_add("/migration/precopy/rdma/plain",
+ test_precopy_rdma_plain);
+ migration_test_add("/migration/precopy/rdma/plain/ipv6",
+ test_precopy_rdma_plain_ipv6);
+#endif
+}
+
+void migration_test_add_precopy(MigrationTestEnv *env)
+{
+ tmpfs = env->tmpfs;
+
+ migration_test_add_precopy_smoke(env);
+
+ if (!env->full_set) {
+ return;
+ }
+
+ migration_test_add("/migration/precopy/tcp/plain/switchover-ack",
+ test_precopy_tcp_switchover_ack);
+
+#ifndef _WIN32
+ migration_test_add("/migration/precopy/fd/tcp",
+ test_precopy_fd_socket);
+ migration_test_add("/migration/precopy/fd/file",
+ test_precopy_fd_file);
+#endif
+
+ /*
+ * See explanation why this test is slow on function definition
+ */
+ if (g_test_slow()) {
+ migration_test_add("/migration/auto_converge",
+ test_auto_converge);
+ if (g_str_equal(env->arch, "x86_64") &&
+ env->has_kvm && env->has_dirty_ring) {
+ migration_test_add("/dirty_limit",
+ test_dirty_limit);
+ }
+ }
+ migration_test_add("/migration/multifd/tcp/channels/plain/none",
+ test_multifd_tcp_channels_none);
+ migration_test_add("/migration/multifd/tcp/plain/zero-page/legacy",
+ test_multifd_tcp_zero_page_legacy);
+ migration_test_add("/migration/multifd/tcp/plain/zero-page/none",
+ test_multifd_tcp_no_zero_page);
+ if (g_str_equal(env->arch, "x86_64")
+ && env->has_kvm && env->has_dirty_ring) {
+
+ migration_test_add("/migration/dirty_ring",
+ test_precopy_unix_dirty_ring);
+ if (qtest_has_machine("pc") && g_test_slow()) {
+ migration_test_add("/migration/vcpu_dirty_limit",
+ test_vcpu_dirty_limit);
+ }
+ }
+
+ /* ensure new status don't go unnoticed */
+ assert(MIGRATION_STATUS__MAX == 15);
+
+ for (int i = MIGRATION_STATUS_NONE; i < MIGRATION_STATUS__MAX; i++) {
+ switch (i) {
+ case MIGRATION_STATUS_DEVICE: /* happens too fast */
+ case MIGRATION_STATUS_WAIT_UNPLUG: /* no support in tests */
+ case MIGRATION_STATUS_COLO: /* no support in tests */
+ case MIGRATION_STATUS_POSTCOPY_ACTIVE: /* postcopy can't be cancelled */
+ case MIGRATION_STATUS_POSTCOPY_PAUSED:
+ case MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP:
+ case MIGRATION_STATUS_POSTCOPY_RECOVER:
+ continue;
+ default:
+ migration_test_add_suffix("/migration/cancel/src/after/",
+ MigrationStatus_str(i),
+ test_cancel_src_after_status);
+ }
+ }
+}
diff --git a/tests/migration/s390x/Makefile b/tests/qtest/migration/s390x/Makefile
index 6671de2..6671de2 100644
--- a/tests/migration/s390x/Makefile
+++ b/tests/qtest/migration/s390x/Makefile
diff --git a/tests/migration/s390x/a-b-bios.c b/tests/qtest/migration/s390x/a-b-bios.c
index ff99a3e..ff99a3e 100644
--- a/tests/migration/s390x/a-b-bios.c
+++ b/tests/qtest/migration/s390x/a-b-bios.c
diff --git a/tests/migration/s390x/a-b-bios.h b/tests/qtest/migration/s390x/a-b-bios.h
index 96103da..96103da 100644
--- a/tests/migration/s390x/a-b-bios.h
+++ b/tests/qtest/migration/s390x/a-b-bios.h
diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
new file mode 100644
index 0000000..21e9fec
--- /dev/null
+++ b/tests/qtest/migration/tls-tests.c
@@ -0,0 +1,871 @@
+/*
+ * QTest testcases for TLS 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 "crypto/tlscredspsk.h"
+#include "libqtest.h"
+#include "migration/framework.h"
+#include "migration/migration-qmp.h"
+#include "migration/migration-util.h"
+
+#include "tests/unit/crypto-tls-psk-helpers.h"
+#ifdef CONFIG_TASN1
+# include "tests/unit/crypto-tls-x509-helpers.h"
+#endif /* CONFIG_TASN1 */
+
+
+struct TestMigrateTLSPSKData {
+ char *workdir;
+ char *workdiralt;
+ char *pskfile;
+ char *pskfilealt;
+};
+
+static char *tmpfs;
+
+static void *
+migrate_hook_start_tls_psk_common(QTestState *from,
+ QTestState *to,
+ bool mismatch)
+{
+ struct TestMigrateTLSPSKData *data =
+ g_new0(struct TestMigrateTLSPSKData, 1);
+
+ data->workdir = g_strdup_printf("%s/tlscredspsk0", tmpfs);
+ data->pskfile = g_strdup_printf("%s/%s", data->workdir,
+ QCRYPTO_TLS_CREDS_PSKFILE);
+ g_mkdir_with_parents(data->workdir, 0700);
+ test_tls_psk_init(data->pskfile);
+
+ if (mismatch) {
+ data->workdiralt = g_strdup_printf("%s/tlscredspskalt0", tmpfs);
+ data->pskfilealt = g_strdup_printf("%s/%s", data->workdiralt,
+ QCRYPTO_TLS_CREDS_PSKFILE);
+ g_mkdir_with_parents(data->workdiralt, 0700);
+ test_tls_psk_init_alt(data->pskfilealt);
+ }
+
+ qtest_qmp_assert_success(from,
+ "{ 'execute': 'object-add',"
+ " 'arguments': { 'qom-type': 'tls-creds-psk',"
+ " 'id': 'tlscredspsk0',"
+ " 'endpoint': 'client',"
+ " 'dir': %s,"
+ " 'username': 'qemu'} }",
+ data->workdir);
+
+ qtest_qmp_assert_success(to,
+ "{ 'execute': 'object-add',"
+ " 'arguments': { 'qom-type': 'tls-creds-psk',"
+ " 'id': 'tlscredspsk0',"
+ " 'endpoint': 'server',"
+ " 'dir': %s } }",
+ mismatch ? data->workdiralt : data->workdir);
+
+ migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0");
+ migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0");
+
+ return data;
+}
+
+static void *
+migrate_hook_start_tls_psk_match(QTestState *from,
+ QTestState *to)
+{
+ return migrate_hook_start_tls_psk_common(from, to, false);
+}
+
+static void *
+migrate_hook_start_tls_psk_mismatch(QTestState *from,
+ QTestState *to)
+{
+ return migrate_hook_start_tls_psk_common(from, to, true);
+}
+
+static void
+migrate_hook_end_tls_psk(QTestState *from,
+ QTestState *to,
+ void *opaque)
+{
+ struct TestMigrateTLSPSKData *data = opaque;
+
+ test_tls_psk_cleanup(data->pskfile);
+ if (data->pskfilealt) {
+ test_tls_psk_cleanup(data->pskfilealt);
+ }
+ rmdir(data->workdir);
+ if (data->workdiralt) {
+ rmdir(data->workdiralt);
+ }
+
+ g_free(data->workdiralt);
+ g_free(data->pskfilealt);
+ g_free(data->workdir);
+ g_free(data->pskfile);
+ g_free(data);
+}
+
+#ifdef CONFIG_TASN1
+typedef struct {
+ char *workdir;
+ char *keyfile;
+ char *cacert;
+ char *servercert;
+ char *serverkey;
+ char *clientcert;
+ char *clientkey;
+} TestMigrateTLSX509Data;
+
+typedef struct {
+ bool verifyclient;
+ bool clientcert;
+ bool hostileclient;
+ bool authzclient;
+ const char *certhostname;
+ const char *certipaddr;
+} TestMigrateTLSX509;
+
+static void *
+migrate_hook_start_tls_x509_common(QTestState *from,
+ QTestState *to,
+ TestMigrateTLSX509 *args)
+{
+ TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1);
+
+ data->workdir = g_strdup_printf("%s/tlscredsx5090", tmpfs);
+ data->keyfile = g_strdup_printf("%s/key.pem", data->workdir);
+
+ data->cacert = g_strdup_printf("%s/ca-cert.pem", data->workdir);
+ data->serverkey = g_strdup_printf("%s/server-key.pem", data->workdir);
+ data->servercert = g_strdup_printf("%s/server-cert.pem", data->workdir);
+ if (args->clientcert) {
+ data->clientkey = g_strdup_printf("%s/client-key.pem", data->workdir);
+ data->clientcert = g_strdup_printf("%s/client-cert.pem", data->workdir);
+ }
+
+ g_mkdir_with_parents(data->workdir, 0700);
+
+ test_tls_init(data->keyfile);
+#ifndef _WIN32
+ g_assert(link(data->keyfile, data->serverkey) == 0);
+#else
+ g_assert(CreateHardLink(data->serverkey, data->keyfile, NULL) != 0);
+#endif
+ if (args->clientcert) {
+#ifndef _WIN32
+ g_assert(link(data->keyfile, data->clientkey) == 0);
+#else
+ g_assert(CreateHardLink(data->clientkey, data->keyfile, NULL) != 0);
+#endif
+ }
+
+ TLS_ROOT_REQ_SIMPLE(cacertreq, data->cacert);
+ if (args->clientcert) {
+ TLS_CERT_REQ_SIMPLE_CLIENT(servercertreq, cacertreq,
+ args->hostileclient ?
+ QCRYPTO_TLS_TEST_CLIENT_HOSTILE_NAME :
+ QCRYPTO_TLS_TEST_CLIENT_NAME,
+ data->clientcert);
+ test_tls_deinit_cert(&servercertreq);
+ }
+
+ TLS_CERT_REQ_SIMPLE_SERVER(clientcertreq, cacertreq,
+ data->servercert,
+ args->certhostname,
+ args->certipaddr);
+ test_tls_deinit_cert(&clientcertreq);
+ test_tls_deinit_cert(&cacertreq);
+
+ qtest_qmp_assert_success(from,
+ "{ 'execute': 'object-add',"
+ " 'arguments': { 'qom-type': 'tls-creds-x509',"
+ " 'id': 'tlscredsx509client0',"
+ " 'endpoint': 'client',"
+ " 'dir': %s,"
+ " 'sanity-check': true,"
+ " 'verify-peer': true} }",
+ data->workdir);
+ migrate_set_parameter_str(from, "tls-creds", "tlscredsx509client0");
+ if (args->certhostname) {
+ migrate_set_parameter_str(from, "tls-hostname", args->certhostname);
+ }
+
+ qtest_qmp_assert_success(to,
+ "{ 'execute': 'object-add',"
+ " 'arguments': { 'qom-type': 'tls-creds-x509',"
+ " 'id': 'tlscredsx509server0',"
+ " 'endpoint': 'server',"
+ " 'dir': %s,"
+ " 'sanity-check': true,"
+ " 'verify-peer': %i} }",
+ data->workdir, args->verifyclient);
+ migrate_set_parameter_str(to, "tls-creds", "tlscredsx509server0");
+
+ if (args->authzclient) {
+ qtest_qmp_assert_success(to,
+ "{ 'execute': 'object-add',"
+ " 'arguments': { 'qom-type': 'authz-simple',"
+ " 'id': 'tlsauthz0',"
+ " 'identity': %s} }",
+ "CN=" QCRYPTO_TLS_TEST_CLIENT_NAME);
+ migrate_set_parameter_str(to, "tls-authz", "tlsauthz0");
+ }
+
+ return data;
+}
+
+/*
+ * The normal case: match server's cert hostname against
+ * whatever host we were telling QEMU to connect to (if any)
+ */
+static void *
+migrate_hook_start_tls_x509_default_host(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .verifyclient = true,
+ .clientcert = true,
+ .certipaddr = "127.0.0.1"
+ };
+ return migrate_hook_start_tls_x509_common(from, to, &args);
+}
+
+/*
+ * The unusual case: the server's cert is different from
+ * the address we're telling QEMU to connect to (if any),
+ * so we must give QEMU an explicit hostname to validate
+ */
+static void *
+migrate_hook_start_tls_x509_override_host(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .verifyclient = true,
+ .clientcert = true,
+ .certhostname = "qemu.org",
+ };
+ return migrate_hook_start_tls_x509_common(from, to, &args);
+}
+
+/*
+ * The unusual case: the server's cert is different from
+ * the address we're telling QEMU to connect to, and so we
+ * expect the client to reject the server
+ */
+static void *
+migrate_hook_start_tls_x509_mismatch_host(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .verifyclient = true,
+ .clientcert = true,
+ .certipaddr = "10.0.0.1",
+ };
+ return migrate_hook_start_tls_x509_common(from, to, &args);
+}
+
+static void *
+migrate_hook_start_tls_x509_friendly_client(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .verifyclient = true,
+ .clientcert = true,
+ .authzclient = true,
+ .certipaddr = "127.0.0.1",
+ };
+ return migrate_hook_start_tls_x509_common(from, to, &args);
+}
+
+static void *
+migrate_hook_start_tls_x509_hostile_client(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .verifyclient = true,
+ .clientcert = true,
+ .hostileclient = true,
+ .authzclient = true,
+ .certipaddr = "127.0.0.1",
+ };
+ return migrate_hook_start_tls_x509_common(from, to, &args);
+}
+
+/*
+ * The case with no client certificate presented,
+ * and no server verification
+ */
+static void *
+migrate_hook_start_tls_x509_allow_anon_client(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .certipaddr = "127.0.0.1",
+ };
+ return migrate_hook_start_tls_x509_common(from, to, &args);
+}
+
+/*
+ * The case with no client certificate presented,
+ * and server verification rejecting
+ */
+static void *
+migrate_hook_start_tls_x509_reject_anon_client(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .verifyclient = true,
+ .certipaddr = "127.0.0.1",
+ };
+ return migrate_hook_start_tls_x509_common(from, to, &args);
+}
+
+static void
+migrate_hook_end_tls_x509(QTestState *from,
+ QTestState *to,
+ void *opaque)
+{
+ TestMigrateTLSX509Data *data = opaque;
+
+ test_tls_cleanup(data->keyfile);
+ g_free(data->keyfile);
+
+ unlink(data->cacert);
+ g_free(data->cacert);
+ unlink(data->servercert);
+ g_free(data->servercert);
+ unlink(data->serverkey);
+ g_free(data->serverkey);
+
+ if (data->clientcert) {
+ unlink(data->clientcert);
+ g_free(data->clientcert);
+ }
+ if (data->clientkey) {
+ unlink(data->clientkey);
+ g_free(data->clientkey);
+ }
+
+ rmdir(data->workdir);
+ g_free(data->workdir);
+
+ g_free(data);
+}
+#endif /* CONFIG_TASN1 */
+
+static void test_postcopy_tls_psk(void)
+{
+ MigrateCommon args = {
+ .start_hook = migrate_hook_start_tls_psk_match,
+ .end_hook = migrate_hook_end_tls_psk,
+ };
+
+ test_postcopy_common(&args);
+}
+
+static void test_postcopy_preempt_tls_psk(void)
+{
+ MigrateCommon args = {
+ .start_hook = migrate_hook_start_tls_psk_match,
+ .end_hook = migrate_hook_end_tls_psk,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true,
+ },
+ };
+
+ test_postcopy_common(&args);
+}
+
+static void test_postcopy_recovery_tls_psk(void)
+{
+ MigrateCommon args = {
+ .start_hook = migrate_hook_start_tls_psk_match,
+ .end_hook = migrate_hook_end_tls_psk,
+ };
+
+ test_postcopy_recovery_common(&args);
+}
+
+static void test_multifd_postcopy_recovery_tls_psk(void)
+{
+ MigrateCommon args = {
+ .start_hook = migrate_hook_start_tls_psk_match,
+ .end_hook = migrate_hook_end_tls_psk,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ };
+
+ test_postcopy_recovery_common(&args);
+}
+
+/* This contains preempt+recovery+tls test altogether */
+static void test_postcopy_preempt_all(void)
+{
+ MigrateCommon args = {
+ .start_hook = migrate_hook_start_tls_psk_match,
+ .end_hook = migrate_hook_end_tls_psk,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true,
+ },
+ };
+
+ test_postcopy_recovery_common(&args);
+}
+
+static void test_multifd_postcopy_preempt_recovery_tls_psk(void)
+{
+ MigrateCommon args = {
+ .start_hook = migrate_hook_start_tls_psk_match,
+ .end_hook = migrate_hook_end_tls_psk,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true,
+ },
+ };
+
+ test_postcopy_recovery_common(&args);
+}
+
+static void test_precopy_unix_tls_psk(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = uri,
+ .start_hook = migrate_hook_start_tls_psk_match,
+ .end_hook = migrate_hook_end_tls_psk,
+ };
+
+ test_precopy_common(&args);
+}
+
+#ifdef CONFIG_TASN1
+static void test_precopy_unix_tls_x509_default_host(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ },
+ .connect_uri = uri,
+ .listen_uri = uri,
+ .start_hook = migrate_hook_start_tls_x509_default_host,
+ .end_hook = migrate_hook_end_tls_x509,
+ .result = MIG_TEST_FAIL_DEST_QUIT_ERR,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_unix_tls_x509_override_host(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = uri,
+ .start_hook = migrate_hook_start_tls_x509_override_host,
+ .end_hook = migrate_hook_end_tls_x509,
+ };
+
+ test_precopy_common(&args);
+}
+#endif /* CONFIG_TASN1 */
+
+static void test_precopy_tcp_tls_psk_match(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = migrate_hook_start_tls_psk_match,
+ .end_hook = migrate_hook_end_tls_psk,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_tls_psk_mismatch(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ },
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = migrate_hook_start_tls_psk_mismatch,
+ .end_hook = migrate_hook_end_tls_psk,
+ .result = MIG_TEST_FAIL,
+ };
+
+ test_precopy_common(&args);
+}
+
+#ifdef CONFIG_TASN1
+static void test_precopy_tcp_tls_x509_default_host(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = migrate_hook_start_tls_x509_default_host,
+ .end_hook = migrate_hook_end_tls_x509,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_tls_x509_override_host(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = migrate_hook_start_tls_x509_override_host,
+ .end_hook = migrate_hook_end_tls_x509,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_tls_x509_mismatch_host(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ },
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = migrate_hook_start_tls_x509_mismatch_host,
+ .end_hook = migrate_hook_end_tls_x509,
+ .result = MIG_TEST_FAIL_DEST_QUIT_ERR,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_tls_x509_friendly_client(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = migrate_hook_start_tls_x509_friendly_client,
+ .end_hook = migrate_hook_end_tls_x509,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_tls_x509_hostile_client(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ },
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = migrate_hook_start_tls_x509_hostile_client,
+ .end_hook = migrate_hook_end_tls_x509,
+ .result = MIG_TEST_FAIL,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_tls_x509_allow_anon_client(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = migrate_hook_start_tls_x509_allow_anon_client,
+ .end_hook = migrate_hook_end_tls_x509,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_tls_x509_reject_anon_client(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ },
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = migrate_hook_start_tls_x509_reject_anon_client,
+ .end_hook = migrate_hook_end_tls_x509,
+ .result = MIG_TEST_FAIL,
+ };
+
+ test_precopy_common(&args);
+}
+#endif /* CONFIG_TASN1 */
+
+static void *
+migrate_hook_start_multifd_tcp_tls_psk_match(QTestState *from,
+ QTestState *to)
+{
+ migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+ return migrate_hook_start_tls_psk_match(from, to);
+}
+
+static void *
+migrate_hook_start_multifd_tcp_tls_psk_mismatch(QTestState *from,
+ QTestState *to)
+{
+ migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+ return migrate_hook_start_tls_psk_mismatch(from, to);
+}
+
+#ifdef CONFIG_TASN1
+static void *
+migrate_hook_start_multifd_tls_x509_default_host(QTestState *from,
+ QTestState *to)
+{
+ migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+ return migrate_hook_start_tls_x509_default_host(from, to);
+}
+
+static void *
+migrate_hook_start_multifd_tls_x509_override_host(QTestState *from,
+ QTestState *to)
+{
+ migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+ return migrate_hook_start_tls_x509_override_host(from, to);
+}
+
+static void *
+migrate_hook_start_multifd_tls_x509_mismatch_host(QTestState *from,
+ QTestState *to)
+{
+ migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+ return migrate_hook_start_tls_x509_mismatch_host(from, to);
+}
+
+static void *
+migrate_hook_start_multifd_tls_x509_allow_anon_client(QTestState *from,
+ QTestState *to)
+{
+ migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+ return migrate_hook_start_tls_x509_allow_anon_client(from, to);
+}
+
+static void *
+migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from,
+ QTestState *to)
+{
+ migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+ return migrate_hook_start_tls_x509_reject_anon_client(from, to);
+}
+#endif /* CONFIG_TASN1 */
+
+static void test_multifd_tcp_tls_psk_match(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_multifd_tcp_tls_psk_match,
+ .end_hook = migrate_hook_end_tls_psk,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ };
+ test_precopy_common(&args);
+}
+
+static void test_multifd_tcp_tls_psk_mismatch(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch,
+ .end_hook = migrate_hook_end_tls_psk,
+ .result = MIG_TEST_FAIL,
+ };
+ test_precopy_common(&args);
+}
+
+static void test_multifd_postcopy_tcp_tls_psk_match(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ .caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true,
+ },
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_multifd_tcp_tls_psk_match,
+ .end_hook = migrate_hook_end_tls_psk,
+ };
+
+ test_precopy_common(&args);
+}
+
+#ifdef CONFIG_TASN1
+static void test_multifd_tcp_tls_x509_default_host(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_multifd_tls_x509_default_host,
+ .end_hook = migrate_hook_end_tls_x509,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ };
+ test_precopy_common(&args);
+}
+
+static void test_multifd_tcp_tls_x509_override_host(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_multifd_tls_x509_override_host,
+ .end_hook = migrate_hook_end_tls_x509,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ };
+ test_precopy_common(&args);
+}
+
+static void test_multifd_tcp_tls_x509_mismatch_host(void)
+{
+ /*
+ * This has different behaviour to the non-multifd case.
+ *
+ * In non-multifd case when client aborts due to mismatched
+ * cert host, the server has already started trying to load
+ * migration state, and so it exits with I/O failure.
+ *
+ * In multifd case when client aborts due to mismatched
+ * cert host, the server is still waiting for the other
+ * multifd connections to arrive so hasn't started trying
+ * to load migration state, and thus just aborts the migration
+ * without exiting.
+ */
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host,
+ .end_hook = migrate_hook_end_tls_x509,
+ .result = MIG_TEST_FAIL,
+ };
+ test_precopy_common(&args);
+}
+
+static void test_multifd_tcp_tls_x509_allow_anon_client(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client,
+ .end_hook = migrate_hook_end_tls_x509,
+ .start = {
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ };
+ test_precopy_common(&args);
+}
+
+static void test_multifd_tcp_tls_x509_reject_anon_client(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
+ },
+ .listen_uri = "defer",
+ .start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client,
+ .end_hook = migrate_hook_end_tls_x509,
+ .result = MIG_TEST_FAIL,
+ };
+ test_precopy_common(&args);
+}
+#endif /* CONFIG_TASN1 */
+
+static void migration_test_add_tls_smoke(MigrationTestEnv *env)
+{
+ migration_test_add("/migration/precopy/tcp/tls/psk/match",
+ test_precopy_tcp_tls_psk_match);
+}
+
+void migration_test_add_tls(MigrationTestEnv *env)
+{
+ tmpfs = env->tmpfs;
+
+ migration_test_add_tls_smoke(env);
+
+ if (!env->full_set) {
+ return;
+ }
+
+ migration_test_add("/migration/precopy/unix/tls/psk",
+ test_precopy_unix_tls_psk);
+
+ if (env->has_uffd) {
+ /*
+ * NOTE: psk test is enough for postcopy, as other types of TLS
+ * channels are tested under precopy. Here what we want to test is the
+ * general postcopy path that has TLS channel enabled.
+ */
+ migration_test_add("/migration/postcopy/tls/psk",
+ test_postcopy_tls_psk);
+ migration_test_add("/migration/postcopy/recovery/tls/psk",
+ test_postcopy_recovery_tls_psk);
+ migration_test_add("/migration/postcopy/preempt/tls/psk",
+ test_postcopy_preempt_tls_psk);
+ migration_test_add("/migration/postcopy/preempt/recovery/tls/psk",
+ test_postcopy_preempt_all);
+ migration_test_add("/migration/multifd+postcopy/recovery/tls/psk",
+ test_multifd_postcopy_recovery_tls_psk);
+ migration_test_add(
+ "/migration/multifd+postcopy/preempt/recovery/tls/psk",
+ test_multifd_postcopy_preempt_recovery_tls_psk);
+ }
+#ifdef CONFIG_TASN1
+ migration_test_add("/migration/precopy/unix/tls/x509/default-host",
+ test_precopy_unix_tls_x509_default_host);
+ migration_test_add("/migration/precopy/unix/tls/x509/override-host",
+ test_precopy_unix_tls_x509_override_host);
+#endif /* CONFIG_TASN1 */
+
+ migration_test_add("/migration/precopy/tcp/tls/psk/mismatch",
+ test_precopy_tcp_tls_psk_mismatch);
+#ifdef CONFIG_TASN1
+ migration_test_add("/migration/precopy/tcp/tls/x509/default-host",
+ test_precopy_tcp_tls_x509_default_host);
+ migration_test_add("/migration/precopy/tcp/tls/x509/override-host",
+ test_precopy_tcp_tls_x509_override_host);
+ migration_test_add("/migration/precopy/tcp/tls/x509/mismatch-host",
+ test_precopy_tcp_tls_x509_mismatch_host);
+ migration_test_add("/migration/precopy/tcp/tls/x509/friendly-client",
+ test_precopy_tcp_tls_x509_friendly_client);
+ migration_test_add("/migration/precopy/tcp/tls/x509/hostile-client",
+ test_precopy_tcp_tls_x509_hostile_client);
+ migration_test_add("/migration/precopy/tcp/tls/x509/allow-anon-client",
+ test_precopy_tcp_tls_x509_allow_anon_client);
+ migration_test_add("/migration/precopy/tcp/tls/x509/reject-anon-client",
+ test_precopy_tcp_tls_x509_reject_anon_client);
+#endif /* CONFIG_TASN1 */
+
+ migration_test_add("/migration/multifd/tcp/tls/psk/match",
+ test_multifd_tcp_tls_psk_match);
+ migration_test_add("/migration/multifd/tcp/tls/psk/mismatch",
+ test_multifd_tcp_tls_psk_mismatch);
+ if (env->has_uffd) {
+ migration_test_add("/migration/multifd+postcopy/tcp/tls/psk/match",
+ test_multifd_postcopy_tcp_tls_psk_match);
+ }
+#ifdef CONFIG_TASN1
+ migration_test_add("/migration/multifd/tcp/tls/x509/default-host",
+ test_multifd_tcp_tls_x509_default_host);
+ migration_test_add("/migration/multifd/tcp/tls/x509/override-host",
+ test_multifd_tcp_tls_x509_override_host);
+ migration_test_add("/migration/multifd/tcp/tls/x509/mismatch-host",
+ test_multifd_tcp_tls_x509_mismatch_host);
+ migration_test_add("/migration/multifd/tcp/tls/x509/allow-anon-client",
+ test_multifd_tcp_tls_x509_allow_anon_client);
+ migration_test_add("/migration/multifd/tcp/tls/x509/reject-anon-client",
+ test_multifd_tcp_tls_x509_reject_anon_client);
+#endif /* CONFIG_TASN1 */
+}
diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c
index fc7d119..b731af0 100644
--- a/tests/qtest/netdev-socket.c
+++ b/tests/qtest/netdev-socket.c
@@ -11,7 +11,7 @@
#include <glib/gstdio.h>
#include "../unit/socket-helpers.h"
#include "libqtest.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qstring.h"
#include "qemu/sockets.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qapi-visit-sockets.h"
@@ -204,7 +204,7 @@ static void test_stream_unix_reconnect(void)
qts1 = qtest_initf("-nodefaults -M none "
"-netdev stream,server=false,id=st0,addr.type=unix,"
- "addr.path=%s,reconnect=1", path);
+ "addr.path=%s,reconnect-ms=1000", path);
wait_stream_connected(qts0, "st0", &addr);
g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_UNIX);
diff --git a/tests/qtest/npcm7xx_adc-test.c b/tests/qtest/npcm7xx_adc-test.c
index e751a72..8bc89b8 100644
--- a/tests/qtest/npcm7xx_adc-test.c
+++ b/tests/qtest/npcm7xx_adc-test.c
@@ -18,7 +18,7 @@
#include "qemu/bitops.h"
#include "qemu/timer.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#define REF_HZ (25000000)
diff --git a/tests/qtest/npcm7xx_emc-test.c b/tests/qtest/npcm7xx_emc-test.c
index 2e1a1a6..eeedb27 100644
--- a/tests/qtest/npcm7xx_emc-test.c
+++ b/tests/qtest/npcm7xx_emc-test.c
@@ -16,8 +16,8 @@
#include "qemu/osdep.h"
#include "libqos/libqos.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qnum.h"
+#include "qobject/qdict.h"
+#include "qobject/qnum.h"
#include "qemu/bitops.h"
#include "qemu/iov.h"
diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c
index b53a43c..052ea87 100644
--- a/tests/qtest/npcm7xx_pwm-test.c
+++ b/tests/qtest/npcm7xx_pwm-test.c
@@ -17,8 +17,8 @@
#include "qemu/osdep.h"
#include "qemu/bitops.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qnum.h"
+#include "qobject/qdict.h"
+#include "qobject/qnum.h"
static int verbosity_level;
diff --git a/tests/qtest/npcm7xx_timer-test.c b/tests/qtest/npcm7xx_timer-test.c
index 58f58c2..4371104 100644
--- a/tests/qtest/npcm7xx_timer-test.c
+++ b/tests/qtest/npcm7xx_timer-test.c
@@ -465,7 +465,6 @@ static void test_periodic_interrupt(gconstpointer test_data)
int i;
tim_reset(td);
- clock_step_next();
tim_write_ticr(td, count);
tim_write_tcsr(td, CEN | IE | MODE_PERIODIC | PRESCALE(ps));
diff --git a/tests/qtest/npcm7xx_watchdog_timer-test.c b/tests/qtest/npcm7xx_watchdog_timer-test.c
index 981b853..521ea78 100644
--- a/tests/qtest/npcm7xx_watchdog_timer-test.c
+++ b/tests/qtest/npcm7xx_watchdog_timer-test.c
@@ -18,7 +18,7 @@
#include "qemu/timer.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#define WTCR_OFFSET 0x1c
#define REF_HZ (25000000)
diff --git a/tests/qtest/npcm_gmac-test.c b/tests/qtest/npcm_gmac-test.c
index c28b471..1317da2 100644
--- a/tests/qtest/npcm_gmac-test.c
+++ b/tests/qtest/npcm_gmac-test.c
@@ -36,7 +36,7 @@ typedef struct TestData {
const GMACModule *module;
} TestData;
-/* Values extracted from hw/arm/npcm7xx.c */
+/* Values extracted from hw/arm/npcm8xx.c */
static const GMACModule gmac_module_list[] = {
{
.irq = 14,
@@ -46,6 +46,14 @@ static const GMACModule gmac_module_list[] = {
.irq = 15,
.base_addr = 0xf0804000
},
+ {
+ .irq = 16,
+ .base_addr = 0xf0806000
+ },
+ {
+ .irq = 17,
+ .base_addr = 0xf0808000
+ }
};
/* Returns the index of the GMAC module. */
@@ -174,18 +182,32 @@ static uint32_t gmac_read(QTestState *qts, const GMACModule *mod,
return qtest_readl(qts, mod->base_addr + regno);
}
+static uint16_t pcs_read(QTestState *qts, const GMACModule *mod,
+ NPCMRegister regno)
+{
+ uint32_t write_value = (regno & 0x3ffe00) >> 9;
+ qtest_writel(qts, PCS_BASE_ADDRESS + NPCM_PCS_IND_AC_BA, write_value);
+ uint32_t read_offset = regno & 0x1ff;
+ return qtest_readl(qts, PCS_BASE_ADDRESS + read_offset);
+}
+
/* Check that GMAC registers are reset to default value */
static void test_init(gconstpointer test_data)
{
const TestData *td = test_data;
const GMACModule *mod = td->module;
- QTestState *qts = qtest_init("-machine npcm750-evb");
+ QTestState *qts = qtest_init("-machine npcm845-evb");
#define CHECK_REG32(regno, value) \
do { \
g_assert_cmphex(gmac_read(qts, mod, (regno)), ==, (value)); \
} while (0)
+#define CHECK_REG_PCS(regno, value) \
+ do { \
+ g_assert_cmphex(pcs_read(qts, mod, (regno)), ==, (value)); \
+ } while (0)
+
CHECK_REG32(NPCM_DMA_BUS_MODE, 0x00020100);
CHECK_REG32(NPCM_DMA_XMT_POLL_DEMAND, 0);
CHECK_REG32(NPCM_DMA_RCV_POLL_DEMAND, 0);
@@ -235,6 +257,63 @@ static void test_init(gconstpointer test_data)
CHECK_REG32(NPCM_GMAC_PTP_TAR, 0);
CHECK_REG32(NPCM_GMAC_PTP_TTSR, 0);
+ if (mod->base_addr == 0xf0802000) {
+ CHECK_REG_PCS(NPCM_PCS_SR_CTL_ID1, 0x699e);
+ CHECK_REG_PCS(NPCM_PCS_SR_CTL_ID2, 0);
+ CHECK_REG_PCS(NPCM_PCS_SR_CTL_STS, 0x8000);
+
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_CTRL, 0x1140);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_STS, 0x0109);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_DEV_ID1, 0x699e);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_DEV_ID2, 0x0ced0);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_AN_ADV, 0x0020);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_LP_BABL, 0);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_AN_EXPN, 0);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_EXT_STS, 0xc000);
+
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_ABL, 0x0003);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_LWR, 0x0038);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_UPR, 0);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_LWR, 0x0038);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_UPR, 0);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_LWR, 0x0058);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_UPR, 0);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_LWR, 0x0048);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_UPR, 0);
+
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MMD_DIG_CTRL1, 0x2400);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_AN_CTRL, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_AN_INTR_STS, 0x000a);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_TC, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_DBG_CTRL, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_MCTRL0, 0x899c);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_TXTIMER, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_RXTIMER, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_LINK_TIMER_CTRL, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_MCTRL1, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_STS, 0x0010);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_ICG_ERRCNT1, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MISC_STS, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_RX_LSTS, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_BSTCTRL0, 0x00a);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_LVLCTRL0, 0x007f);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_GENCTRL0, 0x0001);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_GENCTRL1, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_STS, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_GENCTRL0, 0x0100);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_GENCTRL1, 0x1100);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_LOS_CTRL0, 0x000e);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_CTRL0, 0x0100);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_CTRL1, 0x0032);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_STS, 0x0001);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL2, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_LVL_CTRL, 0x0019);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL0, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL1, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_CTRL2, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_ERRCNT_SEL, 0);
+ }
+
qtest_quit(qts);
}
@@ -242,7 +321,7 @@ static void gmac_add_test(const char *name, const TestData* td,
GTestDataFunc fn)
{
g_autofree char *full_name = g_strdup_printf(
- "npcm7xx_gmac/gmac[%d]/%s", gmac_module_index(td->module), name);
+ "npcm8xx_gmac/gmac[%d]/%s", gmac_module_index(td->module), name);
qtest_add_data_func(full_name, td, fn);
}
diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c
index ede4189..d657f38 100644
--- a/tests/qtest/numa-test.c
+++ b/tests/qtest/numa-test.c
@@ -11,8 +11,8 @@
#include "qemu/osdep.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
static char *make_cli(const GString *generic_cli, const char *test_cli)
{
@@ -162,7 +162,7 @@ static void pc_numa_cpu(const void *data)
} else if (socket == 1 && core == 1 && thread == 1) {
g_assert_cmpint(node, ==, 1);
} else {
- g_assert(false);
+ g_assert_not_reached();
}
qobject_unref(e);
}
@@ -207,7 +207,7 @@ static void spapr_numa_cpu(const void *data)
} else if (core == 3) {
g_assert_cmpint(node, ==, 1);
} else {
- g_assert(false);
+ g_assert_not_reached();
}
qobject_unref(e);
}
@@ -257,7 +257,7 @@ static void aarch64_numa_cpu(const void *data)
} else if (socket == 1 && cluster == 0 && core == 0 && thread == 0) {
g_assert_cmpint(node, ==, 0);
} else {
- g_assert(false);
+ g_assert_not_reached();
}
qobject_unref(e);
}
@@ -305,7 +305,7 @@ static void loongarch64_numa_cpu(const void *data)
} else if (socket == 1 && core == 0 && thread == 0) {
g_assert_cmpint(node, ==, 0);
} else {
- g_assert(false);
+ g_assert_not_reached();
}
qobject_unref(e);
}
@@ -367,7 +367,7 @@ static void pc_dynamic_cpu_cfg(const void *data)
} else if (socket == 1) {
g_assert_cmpint(node, ==, 0);
} else {
- g_assert(false);
+ g_assert_not_reached();
}
qobject_unref(e);
}
diff --git a/tests/qtest/pnv-host-i2c-test.c b/tests/qtest/pnv-host-i2c-test.c
index 7f64d59..51e613e 100644
--- a/tests/qtest/pnv-host-i2c-test.c
+++ b/tests/qtest/pnv-host-i2c-test.c
@@ -191,12 +191,10 @@ static uint8_t pnv_i2c_pca9554_read_pins(PnvI2cDev *dev)
{
uint8_t send_buf[1];
uint8_t recv_buf[1];
- uint8_t inputs;
send_buf[0] = PCA9554_INPUT;
pnv_i2c_send(dev, send_buf, 1);
pnv_i2c_recv(dev, recv_buf, 1);
- inputs = recv_buf[0];
- return inputs;
+ return recv_buf[0];
}
static void pnv_i2c_pca9554_flip_polarity(PnvI2cDev *dev)
diff --git a/tests/qtest/pnv-spi-seeprom-test.c b/tests/qtest/pnv-spi-seeprom-test.c
index 57f20af..600493c 100644
--- a/tests/qtest/pnv-spi-seeprom-test.c
+++ b/tests/qtest/pnv-spi-seeprom-test.c
@@ -92,7 +92,7 @@ static void test_spi_seeprom(const void *data)
qts = qtest_initf("-machine powernv10 -smp 2,cores=2,"
"threads=1 -accel tcg,thread=single -nographic "
"-blockdev node-name=pib_spic2,driver=file,"
- "filename=%s -device 25csm04,bus=pnv-spi-bus.2,cs=0,"
+ "filename=%s -device 25csm04,bus=chip0.spi.2,cs=0,"
"drive=pib_spic2", tmp_path);
spi_seeprom_transaction(qts, chip);
qtest_quit(qts);
diff --git a/tests/qtest/pnv-xive2-common.c b/tests/qtest/pnv-xive2-common.c
new file mode 100644
index 0000000..bf2bce00
--- /dev/null
+++ b/tests/qtest/pnv-xive2-common.c
@@ -0,0 +1,190 @@
+/*
+ * QTest testcase for PowerNV 10 interrupt controller (xive2)
+ * - Common functions for XIVE2 tests
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+#include "pnv-xive2-common.h"
+
+
+static uint64_t pnv_xscom_addr(uint32_t pcba)
+{
+ return P10_XSCOM_BASE | ((uint64_t) pcba << 3);
+}
+
+static uint64_t pnv_xive_xscom_addr(uint32_t reg)
+{
+ return pnv_xscom_addr(XIVE_XSCOM + reg);
+}
+
+uint64_t pnv_xive_xscom_read(QTestState *qts, uint32_t reg)
+{
+ return qtest_readq(qts, pnv_xive_xscom_addr(reg));
+}
+
+void pnv_xive_xscom_write(QTestState *qts, uint32_t reg, uint64_t val)
+{
+ qtest_writeq(qts, pnv_xive_xscom_addr(reg), val);
+}
+
+static void xive_get_struct(QTestState *qts, uint64_t src, void *dest,
+ size_t size)
+{
+ uint8_t *destination = (uint8_t *)dest;
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ *(destination + i) = qtest_readb(qts, src + i);
+ }
+}
+
+static void xive_copy_struct(QTestState *qts, void *src, uint64_t dest,
+ size_t size)
+{
+ uint8_t *source = (uint8_t *)src;
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ qtest_writeb(qts, dest + i, *(source + i));
+ }
+}
+
+uint64_t xive_get_queue_addr(uint32_t end_index)
+{
+ return XIVE_QUEUE_MEM + (uint64_t)end_index * XIVE_QUEUE_SIZE;
+}
+
+uint8_t get_esb(QTestState *qts, uint32_t index, uint8_t page,
+ uint32_t offset)
+{
+ uint64_t addr;
+
+ addr = XIVE_ESB_ADDR + ((uint64_t)index << (XIVE_PAGE_SHIFT + 1));
+ if (page == 1) {
+ addr += 1 << XIVE_PAGE_SHIFT;
+ }
+ return qtest_readb(qts, addr + offset);
+}
+
+void set_esb(QTestState *qts, uint32_t index, uint8_t page,
+ uint32_t offset, uint32_t val)
+{
+ uint64_t addr;
+
+ addr = XIVE_ESB_ADDR + ((uint64_t)index << (XIVE_PAGE_SHIFT + 1));
+ if (page == 1) {
+ addr += 1 << XIVE_PAGE_SHIFT;
+ }
+ return qtest_writel(qts, addr + offset, cpu_to_be32(val));
+}
+
+void get_nvp(QTestState *qts, uint32_t index, Xive2Nvp* nvp)
+{
+ uint64_t addr = XIVE_NVP_MEM + (uint64_t)index * sizeof(Xive2Nvp);
+ xive_get_struct(qts, addr, nvp, sizeof(Xive2Nvp));
+}
+
+void set_nvp(QTestState *qts, uint32_t index, uint8_t first)
+{
+ uint64_t nvp_addr;
+ Xive2Nvp nvp;
+ uint64_t report_addr;
+
+ nvp_addr = XIVE_NVP_MEM + (uint64_t)index * sizeof(Xive2Nvp);
+ report_addr = (XIVE_REPORT_MEM + (uint64_t)index * XIVE_REPORT_SIZE) >> 8;
+
+ memset(&nvp, 0, sizeof(nvp));
+ nvp.w0 = xive_set_field32(NVP2_W0_VALID, 0, 1);
+ nvp.w0 = xive_set_field32(NVP2_W0_PGOFIRST, nvp.w0, first);
+ nvp.w6 = xive_set_field32(NVP2_W6_REPORTING_LINE, nvp.w6,
+ (report_addr >> 24) & 0xfffffff);
+ nvp.w7 = xive_set_field32(NVP2_W7_REPORTING_LINE, nvp.w7,
+ report_addr & 0xffffff);
+ xive_copy_struct(qts, &nvp, nvp_addr, sizeof(nvp));
+}
+
+static uint64_t get_cl_pair_addr(Xive2Nvp *nvp)
+{
+ uint64_t upper = xive_get_field32(0x0fffffff, nvp->w6);
+ uint64_t lower = xive_get_field32(0xffffff00, nvp->w7);
+ return (upper << 32) | (lower << 8);
+}
+
+void get_cl_pair(QTestState *qts, Xive2Nvp *nvp, uint8_t *cl_pair)
+{
+ uint64_t addr = get_cl_pair_addr(nvp);
+ xive_get_struct(qts, addr, cl_pair, XIVE_REPORT_SIZE);
+}
+
+void set_cl_pair(QTestState *qts, Xive2Nvp *nvp, uint8_t *cl_pair)
+{
+ uint64_t addr = get_cl_pair_addr(nvp);
+ xive_copy_struct(qts, cl_pair, addr, XIVE_REPORT_SIZE);
+}
+
+void set_nvg(QTestState *qts, uint32_t index, uint8_t next)
+{
+ uint64_t nvg_addr;
+ Xive2Nvgc nvg;
+
+ nvg_addr = XIVE_NVG_MEM + (uint64_t)index * sizeof(Xive2Nvgc);
+
+ memset(&nvg, 0, sizeof(nvg));
+ nvg.w0 = xive_set_field32(NVGC2_W0_VALID, 0, 1);
+ nvg.w0 = xive_set_field32(NVGC2_W0_PGONEXT, nvg.w0, next);
+ xive_copy_struct(qts, &nvg, nvg_addr, sizeof(nvg));
+}
+
+void set_eas(QTestState *qts, uint32_t index, uint32_t end_index,
+ uint32_t data)
+{
+ uint64_t eas_addr;
+ Xive2Eas eas;
+
+ eas_addr = XIVE_EAS_MEM + (uint64_t)index * sizeof(Xive2Eas);
+
+ memset(&eas, 0, sizeof(eas));
+ eas.w = xive_set_field64(EAS2_VALID, 0, 1);
+ eas.w = xive_set_field64(EAS2_END_INDEX, eas.w, end_index);
+ eas.w = xive_set_field64(EAS2_END_DATA, eas.w, data);
+ xive_copy_struct(qts, &eas, eas_addr, sizeof(eas));
+}
+
+void set_end(QTestState *qts, uint32_t index, uint32_t nvp_index,
+ uint8_t priority, bool i)
+{
+ uint64_t end_addr, queue_addr, queue_hi, queue_lo;
+ uint8_t queue_size;
+ Xive2End end;
+
+ end_addr = XIVE_END_MEM + (uint64_t)index * sizeof(Xive2End);
+ queue_addr = xive_get_queue_addr(index);
+ queue_hi = (queue_addr >> 32) & END2_W2_EQ_ADDR_HI;
+ queue_lo = queue_addr & END2_W3_EQ_ADDR_LO;
+ queue_size = ctz16(XIVE_QUEUE_SIZE) - 12;
+
+ memset(&end, 0, sizeof(end));
+ end.w0 = xive_set_field32(END2_W0_VALID, 0, 1);
+ end.w0 = xive_set_field32(END2_W0_ENQUEUE, end.w0, 1);
+ end.w0 = xive_set_field32(END2_W0_UCOND_NOTIFY, end.w0, 1);
+ end.w0 = xive_set_field32(END2_W0_BACKLOG, end.w0, 1);
+
+ end.w1 = xive_set_field32(END2_W1_GENERATION, 0, 1);
+
+ end.w2 = cpu_to_be32(queue_hi);
+
+ end.w3 = cpu_to_be32(queue_lo);
+ end.w3 = xive_set_field32(END2_W3_QSIZE, end.w3, queue_size);
+
+ end.w6 = xive_set_field32(END2_W6_IGNORE, 0, i);
+ end.w6 = xive_set_field32(END2_W6_VP_OFFSET, end.w6, nvp_index);
+
+ end.w7 = xive_set_field32(END2_W7_F0_PRIORITY, 0, priority);
+ xive_copy_struct(qts, &end, end_addr, sizeof(end));
+}
+
diff --git a/tests/qtest/pnv-xive2-common.h b/tests/qtest/pnv-xive2-common.h
new file mode 100644
index 0000000..2077c05
--- /dev/null
+++ b/tests/qtest/pnv-xive2-common.h
@@ -0,0 +1,112 @@
+/*
+ * QTest testcase for PowerNV 10 interrupt controller (xive2)
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef TEST_PNV_XIVE2_COMMON_H
+#define TEST_PNV_XIVE2_COMMON_H
+
+#define PPC_BIT(bit) (0x8000000000000000ULL >> (bit))
+#define PPC_BIT32(bit) (0x80000000 >> (bit))
+#define PPC_BIT8(bit) (0x80 >> (bit))
+#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
+#define PPC_BITMASK32(bs, be) ((PPC_BIT32(bs) - PPC_BIT32(be)) | \
+ PPC_BIT32(bs))
+#include "qemu/bswap.h"
+#include "hw/intc/pnv_xive2_regs.h"
+#include "hw/ppc/xive_regs.h"
+#include "hw/ppc/xive2_regs.h"
+
+/*
+ * sizing:
+ * 128 interrupts
+ * => ESB BAR range: 16M
+ * 256 ENDs
+ * => END BAR range: 16M
+ * 256 VPs
+ * => NVPG,NVC BAR range: 32M
+ */
+#define MAX_IRQS 128
+#define MAX_ENDS 256
+#define MAX_VPS 256
+
+#define XIVE_PAGE_SHIFT 16
+
+#define XIVE_TRIGGER_PAGE 0
+#define XIVE_EOI_PAGE 1
+
+#define XIVE_IC_ADDR 0x0006030200000000ull
+#define XIVE_IC_TM_INDIRECT (XIVE_IC_ADDR + (256 << XIVE_PAGE_SHIFT))
+#define XIVE_IC_BAR ((0x3ull << 62) | XIVE_IC_ADDR)
+#define XIVE_TM_BAR 0xc006030203180000ull
+#define XIVE_ESB_ADDR 0x0006050000000000ull
+#define XIVE_ESB_BAR ((0x3ull << 62) | XIVE_ESB_ADDR)
+#define XIVE_END_BAR 0xc006060000000000ull
+#define XIVE_NVPG_ADDR 0x0006040000000000ull
+#define XIVE_NVPG_BAR ((0x3ull << 62) | XIVE_NVPG_ADDR)
+#define XIVE_NVC_ADDR 0x0006030208000000ull
+#define XIVE_NVC_BAR ((0x3ull << 62) | XIVE_NVC_ADDR)
+
+/*
+ * Memory layout
+ * A check is done when a table is configured to ensure that the max
+ * size of the resource fits in the table.
+ */
+#define XIVE_VST_SIZE 0x10000ull /* must be at least 4k */
+
+#define XIVE_MEM_START 0x10000000ull
+#define XIVE_ESB_MEM XIVE_MEM_START
+#define XIVE_EAS_MEM (XIVE_ESB_MEM + XIVE_VST_SIZE)
+#define XIVE_END_MEM (XIVE_EAS_MEM + XIVE_VST_SIZE)
+#define XIVE_NVP_MEM (XIVE_END_MEM + XIVE_VST_SIZE)
+#define XIVE_NVG_MEM (XIVE_NVP_MEM + XIVE_VST_SIZE)
+#define XIVE_NVC_MEM (XIVE_NVG_MEM + XIVE_VST_SIZE)
+#define XIVE_SYNC_MEM (XIVE_NVC_MEM + XIVE_VST_SIZE)
+#define XIVE_QUEUE_MEM (XIVE_SYNC_MEM + XIVE_VST_SIZE)
+#define XIVE_QUEUE_SIZE 4096 /* per End */
+#define XIVE_REPORT_MEM (XIVE_QUEUE_MEM + XIVE_QUEUE_SIZE * MAX_VPS)
+#define XIVE_REPORT_SIZE 256 /* two cache lines per NVP */
+#define XIVE_MEM_END (XIVE_REPORT_MEM + XIVE_REPORT_SIZE * MAX_VPS)
+
+#define P10_XSCOM_BASE 0x000603fc00000000ull
+#define XIVE_XSCOM 0x2010800ull
+
+#define XIVE_ESB_RESET 0b00
+#define XIVE_ESB_OFF 0b01
+#define XIVE_ESB_PENDING 0b10
+#define XIVE_ESB_QUEUED 0b11
+
+#define XIVE_ESB_GET 0x800
+#define XIVE_ESB_SET_PQ_00 0xc00 /* Load */
+#define XIVE_ESB_SET_PQ_01 0xd00 /* Load */
+#define XIVE_ESB_SET_PQ_10 0xe00 /* Load */
+#define XIVE_ESB_SET_PQ_11 0xf00 /* Load */
+
+#define XIVE_ESB_STORE_EOI 0x400 /* Store */
+
+
+extern uint64_t pnv_xive_xscom_read(QTestState *qts, uint32_t reg);
+extern void pnv_xive_xscom_write(QTestState *qts, uint32_t reg, uint64_t val);
+extern uint64_t xive_get_queue_addr(uint32_t end_index);
+extern uint8_t get_esb(QTestState *qts, uint32_t index, uint8_t page,
+ uint32_t offset);
+extern void set_esb(QTestState *qts, uint32_t index, uint8_t page,
+ uint32_t offset, uint32_t val);
+extern void get_nvp(QTestState *qts, uint32_t index, Xive2Nvp* nvp);
+extern void set_nvp(QTestState *qts, uint32_t index, uint8_t first);
+extern void get_cl_pair(QTestState *qts, Xive2Nvp *nvp, uint8_t *cl_pair);
+extern void set_cl_pair(QTestState *qts, Xive2Nvp *nvp, uint8_t *cl_pair);
+extern void set_nvg(QTestState *qts, uint32_t index, uint8_t next);
+extern void set_eas(QTestState *qts, uint32_t index, uint32_t end_index,
+ uint32_t data);
+extern void set_end(QTestState *qts, uint32_t index, uint32_t nvp_index,
+ uint8_t priority, bool i);
+
+
+void test_flush_sync_inject(QTestState *qts);
+void test_nvpg_bar(QTestState *qts);
+
+#endif /* TEST_PNV_XIVE2_COMMON_H */
diff --git a/tests/qtest/pnv-xive2-flush-sync.c b/tests/qtest/pnv-xive2-flush-sync.c
new file mode 100644
index 0000000..142826b
--- /dev/null
+++ b/tests/qtest/pnv-xive2-flush-sync.c
@@ -0,0 +1,205 @@
+/*
+ * QTest testcase for PowerNV 10 interrupt controller (xive2)
+ * - Test cache flush/queue sync injection
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+#include "pnv-xive2-common.h"
+#include "hw/intc/pnv_xive2_regs.h"
+#include "hw/ppc/xive_regs.h"
+#include "hw/ppc/xive2_regs.h"
+
+#define PNV_XIVE2_QUEUE_IPI 0x00
+#define PNV_XIVE2_QUEUE_HW 0x01
+#define PNV_XIVE2_QUEUE_NXC 0x02
+#define PNV_XIVE2_QUEUE_INT 0x03
+#define PNV_XIVE2_QUEUE_OS 0x04
+#define PNV_XIVE2_QUEUE_POOL 0x05
+#define PNV_XIVE2_QUEUE_HARD 0x06
+#define PNV_XIVE2_CACHE_ENDC 0x08
+#define PNV_XIVE2_CACHE_ESBC 0x09
+#define PNV_XIVE2_CACHE_EASC 0x0a
+#define PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO 0x10
+#define PNV_XIVE2_QUEUE_NXC_LD_LCL_CO 0x11
+#define PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI 0x12
+#define PNV_XIVE2_QUEUE_NXC_ST_LCL_CI 0x13
+#define PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI 0x14
+#define PNV_XIVE2_QUEUE_NXC_ST_RMT_CI 0x15
+#define PNV_XIVE2_CACHE_NXC 0x18
+
+#define PNV_XIVE2_SYNC_IPI 0x000
+#define PNV_XIVE2_SYNC_HW 0x080
+#define PNV_XIVE2_SYNC_NxC 0x100
+#define PNV_XIVE2_SYNC_INT 0x180
+#define PNV_XIVE2_SYNC_OS_ESC 0x200
+#define PNV_XIVE2_SYNC_POOL_ESC 0x280
+#define PNV_XIVE2_SYNC_HARD_ESC 0x300
+#define PNV_XIVE2_SYNC_NXC_LD_LCL_NCO 0x800
+#define PNV_XIVE2_SYNC_NXC_LD_LCL_CO 0x880
+#define PNV_XIVE2_SYNC_NXC_ST_LCL_NCI 0x900
+#define PNV_XIVE2_SYNC_NXC_ST_LCL_CI 0x980
+#define PNV_XIVE2_SYNC_NXC_ST_RMT_NCI 0xA00
+#define PNV_XIVE2_SYNC_NXC_ST_RMT_CI 0xA80
+
+
+static uint64_t get_sync_addr(uint32_t src_pir, int ic_topo_id, int type)
+{
+ int thread_nr = src_pir & 0x7f;
+ uint64_t addr = XIVE_SYNC_MEM + thread_nr * 512 + ic_topo_id * 32 + type;
+ return addr;
+}
+
+static uint8_t get_sync(QTestState *qts, uint32_t src_pir, int ic_topo_id,
+ int type)
+{
+ uint64_t addr = get_sync_addr(src_pir, ic_topo_id, type);
+ return qtest_readb(qts, addr);
+}
+
+static void clr_sync(QTestState *qts, uint32_t src_pir, int ic_topo_id,
+ int type)
+{
+ uint64_t addr = get_sync_addr(src_pir, ic_topo_id, type);
+ qtest_writeb(qts, addr, 0x0);
+}
+
+static void inject_cache_flush(QTestState *qts, int ic_topo_id,
+ uint64_t scom_addr)
+{
+ (void)ic_topo_id;
+ pnv_xive_xscom_write(qts, scom_addr, 0);
+}
+
+static void inject_queue_sync(QTestState *qts, int ic_topo_id, uint64_t offset)
+{
+ (void)ic_topo_id;
+ uint64_t addr = XIVE_IC_ADDR + (VST_SYNC << XIVE_PAGE_SHIFT) + offset;
+ qtest_writeq(qts, addr, 0);
+}
+
+static void inject_op(QTestState *qts, int ic_topo_id, int type)
+{
+ switch (type) {
+ case PNV_XIVE2_QUEUE_IPI:
+ inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_IPI);
+ break;
+ case PNV_XIVE2_QUEUE_HW:
+ inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_HW);
+ break;
+ case PNV_XIVE2_QUEUE_NXC:
+ inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NxC);
+ break;
+ case PNV_XIVE2_QUEUE_INT:
+ inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_INT);
+ break;
+ case PNV_XIVE2_QUEUE_OS:
+ inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_OS_ESC);
+ break;
+ case PNV_XIVE2_QUEUE_POOL:
+ inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_POOL_ESC);
+ break;
+ case PNV_XIVE2_QUEUE_HARD:
+ inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_HARD_ESC);
+ break;
+ case PNV_XIVE2_CACHE_ENDC:
+ inject_cache_flush(qts, ic_topo_id, X_VC_ENDC_FLUSH_INJECT);
+ break;
+ case PNV_XIVE2_CACHE_ESBC:
+ inject_cache_flush(qts, ic_topo_id, X_VC_ESBC_FLUSH_INJECT);
+ break;
+ case PNV_XIVE2_CACHE_EASC:
+ inject_cache_flush(qts, ic_topo_id, X_VC_EASC_FLUSH_INJECT);
+ break;
+ case PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO:
+ inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_LD_LCL_NCO);
+ break;
+ case PNV_XIVE2_QUEUE_NXC_LD_LCL_CO:
+ inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_LD_LCL_CO);
+ break;
+ case PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI:
+ inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_LCL_NCI);
+ break;
+ case PNV_XIVE2_QUEUE_NXC_ST_LCL_CI:
+ inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_LCL_CI);
+ break;
+ case PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI:
+ inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_RMT_NCI);
+ break;
+ case PNV_XIVE2_QUEUE_NXC_ST_RMT_CI:
+ inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_RMT_CI);
+ break;
+ case PNV_XIVE2_CACHE_NXC:
+ inject_cache_flush(qts, ic_topo_id, X_PC_NXC_FLUSH_INJECT);
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+}
+
+const uint8_t xive_inject_tests[] = {
+ PNV_XIVE2_QUEUE_IPI,
+ PNV_XIVE2_QUEUE_HW,
+ PNV_XIVE2_QUEUE_NXC,
+ PNV_XIVE2_QUEUE_INT,
+ PNV_XIVE2_QUEUE_OS,
+ PNV_XIVE2_QUEUE_POOL,
+ PNV_XIVE2_QUEUE_HARD,
+ PNV_XIVE2_CACHE_ENDC,
+ PNV_XIVE2_CACHE_ESBC,
+ PNV_XIVE2_CACHE_EASC,
+ PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO,
+ PNV_XIVE2_QUEUE_NXC_LD_LCL_CO,
+ PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI,
+ PNV_XIVE2_QUEUE_NXC_ST_LCL_CI,
+ PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI,
+ PNV_XIVE2_QUEUE_NXC_ST_RMT_CI,
+ PNV_XIVE2_CACHE_NXC,
+};
+
+void test_flush_sync_inject(QTestState *qts)
+{
+ int ic_topo_id = 0;
+
+ /*
+ * Writes performed by qtest are not done in the context of a thread.
+ * This means that QEMU XIVE code doesn't have a way to determine what
+ * thread is originating the write. In order to allow for some testing,
+ * QEMU XIVE code will assume a PIR of 0 when unable to determine the
+ * source thread for cache flush and queue sync inject operations.
+ * See hw/intc/pnv_xive2.c: pnv_xive2_inject_notify() for details.
+ */
+ int src_pir = 0;
+ int test_nr;
+ uint8_t byte;
+
+ g_test_message("=========================================================");
+ g_test_message("Starting cache flush/queue sync injection tests...");
+
+ for (test_nr = 0; test_nr < sizeof(xive_inject_tests);
+ test_nr++) {
+ int op_type = xive_inject_tests[test_nr];
+
+ g_test_message("Running test %d", test_nr);
+
+ /* start with status byte set to 0 */
+ clr_sync(qts, src_pir, ic_topo_id, op_type);
+ byte = get_sync(qts, src_pir, ic_topo_id, op_type);
+ g_assert_cmphex(byte, ==, 0);
+
+ /* request cache flush or queue sync operation */
+ inject_op(qts, ic_topo_id, op_type);
+
+ /* verify that status byte was written to 0xff */
+ byte = get_sync(qts, src_pir, ic_topo_id, op_type);
+ g_assert_cmphex(byte, ==, 0xff);
+
+ clr_sync(qts, src_pir, ic_topo_id, op_type);
+ }
+}
+
diff --git a/tests/qtest/pnv-xive2-nvpg_bar.c b/tests/qtest/pnv-xive2-nvpg_bar.c
new file mode 100644
index 0000000..6ac8d36
--- /dev/null
+++ b/tests/qtest/pnv-xive2-nvpg_bar.c
@@ -0,0 +1,152 @@
+/*
+ * QTest testcase for PowerNV 10 interrupt controller (xive2)
+ * - Test NVPG BAR MMIO operations
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+#include "pnv-xive2-common.h"
+
+#define NVPG_BACKLOG_OP_SHIFT 10
+#define NVPG_BACKLOG_PRIO_SHIFT 4
+
+#define XIVE_PRIORITY_MAX 7
+
+enum NVx {
+ NVP,
+ NVG,
+ NVC
+};
+
+typedef enum {
+ INCR_STORE = 0b100,
+ INCR_LOAD = 0b000,
+ DECR_STORE = 0b101,
+ DECR_LOAD = 0b001,
+ READ_x = 0b010,
+ READ_y = 0b011,
+} backlog_op;
+
+static uint32_t nvpg_backlog_op(QTestState *qts, backlog_op op,
+ enum NVx type, uint64_t index,
+ uint8_t priority, uint8_t delta)
+{
+ uint64_t addr, offset;
+ uint32_t count = 0;
+
+ switch (type) {
+ case NVP:
+ addr = XIVE_NVPG_ADDR + (index << (XIVE_PAGE_SHIFT + 1));
+ break;
+ case NVG:
+ addr = XIVE_NVPG_ADDR + (index << (XIVE_PAGE_SHIFT + 1)) +
+ (1 << XIVE_PAGE_SHIFT);
+ break;
+ case NVC:
+ addr = XIVE_NVC_ADDR + (index << XIVE_PAGE_SHIFT);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ offset = (op & 0b11) << NVPG_BACKLOG_OP_SHIFT;
+ offset |= priority << NVPG_BACKLOG_PRIO_SHIFT;
+ if (op >> 2) {
+ qtest_writeb(qts, addr + offset, delta);
+ } else {
+ count = qtest_readw(qts, addr + offset);
+ }
+ return count;
+}
+
+void test_nvpg_bar(QTestState *qts)
+{
+ uint32_t nvp_target = 0x11;
+ uint32_t group_target = 0x17; /* size 16 */
+ uint32_t vp_irq = 33, group_irq = 47;
+ uint32_t vp_end = 3, group_end = 97;
+ uint32_t vp_irq_data = 0x33333333;
+ uint32_t group_irq_data = 0x66666666;
+ uint8_t vp_priority = 0, group_priority = 5;
+ uint32_t vp_count[XIVE_PRIORITY_MAX + 1] = { 0 };
+ uint32_t group_count[XIVE_PRIORITY_MAX + 1] = { 0 };
+ uint32_t count, delta;
+ uint8_t i;
+
+ g_test_message("=========================================================");
+ g_test_message("Testing NVPG BAR operations");
+
+ set_nvg(qts, group_target, 0);
+ set_nvp(qts, nvp_target, 0x04);
+ set_nvp(qts, group_target, 0x04);
+
+ /*
+ * Setup: trigger a VP-specific interrupt and a group interrupt
+ * so that the backlog counters are initialized to something else
+ * than 0 for at least one priority level
+ */
+ set_eas(qts, vp_irq, vp_end, vp_irq_data);
+ set_end(qts, vp_end, nvp_target, vp_priority, false /* group */);
+
+ set_eas(qts, group_irq, group_end, group_irq_data);
+ set_end(qts, group_end, group_target, group_priority, true /* group */);
+
+ get_esb(qts, vp_irq, XIVE_EOI_PAGE, XIVE_ESB_SET_PQ_00);
+ set_esb(qts, vp_irq, XIVE_TRIGGER_PAGE, 0, 0);
+ vp_count[vp_priority]++;
+
+ get_esb(qts, group_irq, XIVE_EOI_PAGE, XIVE_ESB_SET_PQ_00);
+ set_esb(qts, group_irq, XIVE_TRIGGER_PAGE, 0, 0);
+ group_count[group_priority]++;
+
+ /* check the initial counters */
+ for (i = 0; i <= XIVE_PRIORITY_MAX; i++) {
+ count = nvpg_backlog_op(qts, READ_x, NVP, nvp_target, i, 0);
+ g_assert_cmpuint(count, ==, vp_count[i]);
+
+ count = nvpg_backlog_op(qts, READ_y, NVG, group_target, i, 0);
+ g_assert_cmpuint(count, ==, group_count[i]);
+ }
+
+ /* do a few ops on the VP. Counter can only be 0 and 1 */
+ vp_priority = 2;
+ delta = 7;
+ nvpg_backlog_op(qts, INCR_STORE, NVP, nvp_target, vp_priority, delta);
+ vp_count[vp_priority] = 1;
+ count = nvpg_backlog_op(qts, INCR_LOAD, NVP, nvp_target, vp_priority, 0);
+ g_assert_cmpuint(count, ==, vp_count[vp_priority]);
+ count = nvpg_backlog_op(qts, READ_y, NVP, nvp_target, vp_priority, 0);
+ g_assert_cmpuint(count, ==, vp_count[vp_priority]);
+
+ count = nvpg_backlog_op(qts, DECR_LOAD, NVP, nvp_target, vp_priority, 0);
+ g_assert_cmpuint(count, ==, vp_count[vp_priority]);
+ vp_count[vp_priority] = 0;
+ nvpg_backlog_op(qts, DECR_STORE, NVP, nvp_target, vp_priority, delta);
+ count = nvpg_backlog_op(qts, READ_x, NVP, nvp_target, vp_priority, 0);
+ g_assert_cmpuint(count, ==, vp_count[vp_priority]);
+
+ /* do a few ops on the group */
+ group_priority = 2;
+ delta = 9;
+ /* can't go negative */
+ nvpg_backlog_op(qts, DECR_STORE, NVG, group_target, group_priority, delta);
+ count = nvpg_backlog_op(qts, READ_y, NVG, group_target, group_priority, 0);
+ g_assert_cmpuint(count, ==, 0);
+ nvpg_backlog_op(qts, INCR_STORE, NVG, group_target, group_priority, delta);
+ group_count[group_priority] += delta;
+ count = nvpg_backlog_op(qts, INCR_LOAD, NVG, group_target,
+ group_priority, delta);
+ g_assert_cmpuint(count, ==, group_count[group_priority]);
+ group_count[group_priority]++;
+
+ count = nvpg_backlog_op(qts, DECR_LOAD, NVG, group_target,
+ group_priority, delta);
+ g_assert_cmpuint(count, ==, group_count[group_priority]);
+ group_count[group_priority]--;
+ count = nvpg_backlog_op(qts, READ_x, NVG, group_target, group_priority, 0);
+ g_assert_cmpuint(count, ==, group_count[group_priority]);
+}
diff --git a/tests/qtest/pnv-xive2-test.c b/tests/qtest/pnv-xive2-test.c
new file mode 100644
index 0000000..5313d4e
--- /dev/null
+++ b/tests/qtest/pnv-xive2-test.c
@@ -0,0 +1,585 @@
+/*
+ * QTest testcase for PowerNV 10 interrupt controller (xive2)
+ * - Test irq to hardware thread
+ * - Test 'Pull Thread Context to Odd Thread Reporting Line'
+ * - Test irq to hardware group
+ * - Test irq to hardware group going through backlog
+ * - Test irq to pool thread
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+#include "pnv-xive2-common.h"
+#include "hw/intc/pnv_xive2_regs.h"
+#include "hw/ppc/xive_regs.h"
+#include "hw/ppc/xive2_regs.h"
+
+#define SMT 4 /* some tests will break if less than 4 */
+
+
+static void set_table(QTestState *qts, uint64_t type, uint64_t addr)
+{
+ uint64_t vsd, size, log_size;
+
+ /*
+ * First, let's make sure that all the resources used fit in the
+ * given table.
+ */
+ switch (type) {
+ case VST_ESB:
+ size = MAX_IRQS / 4;
+ break;
+ case VST_EAS:
+ size = MAX_IRQS * 8;
+ break;
+ case VST_END:
+ size = MAX_ENDS * 32;
+ break;
+ case VST_NVP:
+ case VST_NVG:
+ case VST_NVC:
+ size = MAX_VPS * 32;
+ break;
+ case VST_SYNC:
+ size = 64 * 1024;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ g_assert_cmpuint(size, <=, XIVE_VST_SIZE);
+ log_size = ctzl(XIVE_VST_SIZE) - 12;
+
+ vsd = ((uint64_t) VSD_MODE_EXCLUSIVE) << 62 | addr | log_size;
+ pnv_xive_xscom_write(qts, X_VC_VSD_TABLE_ADDR, type << 48);
+ pnv_xive_xscom_write(qts, X_VC_VSD_TABLE_DATA, vsd);
+
+ if (type != VST_EAS && type != VST_IC && type != VST_ERQ) {
+ pnv_xive_xscom_write(qts, X_PC_VSD_TABLE_ADDR, type << 48);
+ pnv_xive_xscom_write(qts, X_PC_VSD_TABLE_DATA, vsd);
+ }
+}
+
+static void set_tima8(QTestState *qts, uint32_t pir, uint32_t offset,
+ uint8_t b)
+{
+ uint64_t ic_addr;
+
+ ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT);
+ qtest_writeb(qts, ic_addr + offset, b);
+}
+
+static void set_tima32(QTestState *qts, uint32_t pir, uint32_t offset,
+ uint32_t l)
+{
+ uint64_t ic_addr;
+
+ ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT);
+ qtest_writel(qts, ic_addr + offset, l);
+}
+
+static uint8_t get_tima8(QTestState *qts, uint32_t pir, uint32_t offset)
+{
+ uint64_t ic_addr;
+
+ ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT);
+ return qtest_readb(qts, ic_addr + offset);
+}
+
+static uint16_t get_tima16(QTestState *qts, uint32_t pir, uint32_t offset)
+{
+ uint64_t ic_addr;
+
+ ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT);
+ return qtest_readw(qts, ic_addr + offset);
+}
+
+static uint32_t get_tima32(QTestState *qts, uint32_t pir, uint32_t offset)
+{
+ uint64_t ic_addr;
+
+ ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT);
+ return qtest_readl(qts, ic_addr + offset);
+}
+
+static void reset_pool_threads(QTestState *qts)
+{
+ uint8_t first_group = 0;
+ int i;
+
+ for (i = 0; i < SMT; i++) {
+ uint32_t nvp_idx = 0x100 + i;
+ set_nvp(qts, nvp_idx, first_group);
+ set_tima32(qts, i, TM_QW2_HV_POOL + TM_WORD0, 0x000000ff);
+ set_tima32(qts, i, TM_QW2_HV_POOL + TM_WORD1, 0);
+ set_tima32(qts, i, TM_QW2_HV_POOL + TM_WORD2, TM_QW2W2_VP | nvp_idx);
+ }
+}
+
+static void reset_hw_threads(QTestState *qts)
+{
+ uint8_t first_group = 0;
+ uint32_t w1 = 0x000000ff;
+ int i;
+
+ if (SMT >= 4) {
+ /* define 2 groups of 2, part of a bigger group of size 4 */
+ set_nvg(qts, 0x80, 0x02);
+ set_nvg(qts, 0x82, 0x02);
+ set_nvg(qts, 0x81, 0);
+ first_group = 0x01;
+ w1 = 0x000300ff;
+ }
+
+ for (i = 0; i < SMT; i++) {
+ set_nvp(qts, 0x80 + i, first_group);
+ set_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD0, 0x00ff00ff);
+ set_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD1, w1);
+ set_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD2, 0x80000000);
+ }
+}
+
+static void reset_state(QTestState *qts)
+{
+ size_t mem_used = XIVE_MEM_END - XIVE_MEM_START;
+
+ qtest_memset(qts, XIVE_MEM_START, 0, mem_used);
+ reset_hw_threads(qts);
+ reset_pool_threads(qts);
+}
+
+static void init_xive(QTestState *qts)
+{
+ uint64_t val1, val2, range;
+
+ /*
+ * We can take a few shortcuts here, as we know the default values
+ * used for xive initialization
+ */
+
+ /*
+ * Set the BARs.
+ * We reuse the same values used by firmware to ease debug.
+ */
+ pnv_xive_xscom_write(qts, X_CQ_IC_BAR, XIVE_IC_BAR);
+ pnv_xive_xscom_write(qts, X_CQ_TM_BAR, XIVE_TM_BAR);
+
+ /* ESB and NVPG use 2 pages per resource. The others only one page */
+ range = (MAX_IRQS << 17) >> 25;
+ val1 = XIVE_ESB_BAR | range;
+ pnv_xive_xscom_write(qts, X_CQ_ESB_BAR, val1);
+
+ range = (MAX_ENDS << 16) >> 25;
+ val1 = XIVE_END_BAR | range;
+ pnv_xive_xscom_write(qts, X_CQ_END_BAR, val1);
+
+ range = (MAX_VPS << 17) >> 25;
+ val1 = XIVE_NVPG_BAR | range;
+ pnv_xive_xscom_write(qts, X_CQ_NVPG_BAR, val1);
+
+ range = (MAX_VPS << 16) >> 25;
+ val1 = XIVE_NVC_BAR | range;
+ pnv_xive_xscom_write(qts, X_CQ_NVC_BAR, val1);
+
+ /*
+ * Enable hw threads.
+ * We check the value written. Useless with current
+ * implementation, but it validates the xscom read path and it's
+ * what the hardware procedure says
+ */
+ val1 = 0xF000000000000000ull; /* core 0, 4 threads */
+ pnv_xive_xscom_write(qts, X_TCTXT_EN0, val1);
+ val2 = pnv_xive_xscom_read(qts, X_TCTXT_EN0);
+ g_assert_cmphex(val1, ==, val2);
+
+ /* Memory tables */
+ set_table(qts, VST_ESB, XIVE_ESB_MEM);
+ set_table(qts, VST_EAS, XIVE_EAS_MEM);
+ set_table(qts, VST_END, XIVE_END_MEM);
+ set_table(qts, VST_NVP, XIVE_NVP_MEM);
+ set_table(qts, VST_NVG, XIVE_NVG_MEM);
+ set_table(qts, VST_NVC, XIVE_NVC_MEM);
+ set_table(qts, VST_SYNC, XIVE_SYNC_MEM);
+
+ reset_hw_threads(qts);
+ reset_pool_threads(qts);
+}
+
+static void test_hw_irq(QTestState *qts)
+{
+ uint32_t irq = 2;
+ uint32_t irq_data = 0x600df00d;
+ uint32_t end_index = 5;
+ uint32_t target_pir = 1;
+ uint32_t target_nvp = 0x80 + target_pir;
+ uint8_t priority = 5;
+ uint32_t reg32;
+ uint16_t reg16;
+ uint8_t pq, nsr, cppr;
+
+ g_test_message("=========================================================");
+ g_test_message("Testing irq %d to hardware thread %d", irq, target_pir);
+
+ /* irq config */
+ set_eas(qts, irq, end_index, irq_data);
+ set_end(qts, end_index, target_nvp, priority, false /* group */);
+
+ /* enable and trigger irq */
+ get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_SET_PQ_00);
+ set_esb(qts, irq, XIVE_TRIGGER_PAGE, 0, 0);
+
+ /* check irq is raised on cpu */
+ pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
+ g_assert_cmpuint(pq, ==, XIVE_ESB_PENDING);
+
+ reg32 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0);
+ nsr = reg32 >> 24;
+ cppr = (reg32 >> 16) & 0xFF;
+ g_assert_cmphex(nsr, ==, 0x80);
+ g_assert_cmphex(cppr, ==, 0xFF);
+
+ /* ack the irq */
+ reg16 = get_tima16(qts, target_pir, TM_SPC_ACK_HV_REG);
+ nsr = reg16 >> 8;
+ cppr = reg16 & 0xFF;
+ g_assert_cmphex(nsr, ==, 0x80);
+ g_assert_cmphex(cppr, ==, priority);
+
+ /* check irq data is what was configured */
+ reg32 = qtest_readl(qts, xive_get_queue_addr(end_index));
+ g_assert_cmphex((reg32 & 0x7fffffff), ==, (irq_data & 0x7fffffff));
+
+ /* End Of Interrupt */
+ set_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_STORE_EOI, 0);
+ pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
+ g_assert_cmpuint(pq, ==, XIVE_ESB_RESET);
+
+ /* reset CPPR */
+ set_tima8(qts, target_pir, TM_QW3_HV_PHYS + TM_CPPR, 0xFF);
+ reg32 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0);
+ nsr = reg32 >> 24;
+ cppr = (reg32 >> 16) & 0xFF;
+ g_assert_cmphex(nsr, ==, 0x00);
+ g_assert_cmphex(cppr, ==, 0xFF);
+}
+
+static void test_pool_irq(QTestState *qts)
+{
+ uint32_t irq = 2;
+ uint32_t irq_data = 0x600d0d06;
+ uint32_t end_index = 5;
+ uint32_t target_pir = 1;
+ uint32_t target_nvp = 0x100 + target_pir;
+ uint8_t priority = 5;
+ uint32_t reg32;
+ uint16_t reg16;
+ uint8_t pq, nsr, cppr, ipb;
+
+ g_test_message("=========================================================");
+ g_test_message("Testing irq %d to pool thread %d", irq, target_pir);
+
+ /* irq config */
+ set_eas(qts, irq, end_index, irq_data);
+ set_end(qts, end_index, target_nvp, priority, false /* group */);
+
+ /* enable and trigger irq */
+ get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_SET_PQ_00);
+ set_esb(qts, irq, XIVE_TRIGGER_PAGE, 0, 0);
+
+ /* check irq is raised on cpu */
+ pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
+ g_assert_cmpuint(pq, ==, XIVE_ESB_PENDING);
+
+ /* check TIMA values in the PHYS ring (shared by POOL ring) */
+ reg32 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0);
+ nsr = reg32 >> 24;
+ cppr = (reg32 >> 16) & 0xFF;
+ g_assert_cmphex(nsr, ==, 0x40);
+ g_assert_cmphex(cppr, ==, 0xFF);
+
+ /* check TIMA values in the POOL ring */
+ reg32 = get_tima32(qts, target_pir, TM_QW2_HV_POOL + TM_WORD0);
+ nsr = reg32 >> 24;
+ cppr = (reg32 >> 16) & 0xFF;
+ ipb = (reg32 >> 8) & 0xFF;
+ g_assert_cmphex(nsr, ==, 0);
+ g_assert_cmphex(cppr, ==, 0);
+ g_assert_cmphex(ipb, ==, 0x80 >> priority);
+
+ /* ack the irq */
+ reg16 = get_tima16(qts, target_pir, TM_SPC_ACK_HV_REG);
+ nsr = reg16 >> 8;
+ cppr = reg16 & 0xFF;
+ g_assert_cmphex(nsr, ==, 0x40);
+ g_assert_cmphex(cppr, ==, priority);
+
+ /* check irq data is what was configured */
+ reg32 = qtest_readl(qts, xive_get_queue_addr(end_index));
+ g_assert_cmphex((reg32 & 0x7fffffff), ==, (irq_data & 0x7fffffff));
+
+ /* check IPB is cleared in the POOL ring */
+ reg32 = get_tima32(qts, target_pir, TM_QW2_HV_POOL + TM_WORD0);
+ ipb = (reg32 >> 8) & 0xFF;
+ g_assert_cmphex(ipb, ==, 0);
+
+ /* End Of Interrupt */
+ set_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_STORE_EOI, 0);
+ pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
+ g_assert_cmpuint(pq, ==, XIVE_ESB_RESET);
+
+ /* reset CPPR */
+ set_tima8(qts, target_pir, TM_QW3_HV_PHYS + TM_CPPR, 0xFF);
+ reg32 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0);
+ nsr = reg32 >> 24;
+ cppr = (reg32 >> 16) & 0xFF;
+ g_assert_cmphex(nsr, ==, 0x00);
+ g_assert_cmphex(cppr, ==, 0xFF);
+}
+
+#define XIVE_ODD_CL 0x80
+static void test_pull_thread_ctx_to_odd_thread_cl(QTestState *qts)
+{
+ uint32_t target_pir = 1;
+ uint32_t target_nvp = 0x80 + target_pir;
+ Xive2Nvp nvp;
+ uint8_t cl_pair[XIVE_REPORT_SIZE];
+ uint32_t qw1w0, qw3w0, qw1w2, qw2w2;
+ uint8_t qw3b8;
+ uint32_t cl_word;
+ uint32_t word2;
+
+ g_test_message("=========================================================");
+ g_test_message("Testing 'Pull Thread Context to Odd Thread Reporting " \
+ "Line'");
+
+ /* clear odd cache line prior to pull operation */
+ memset(cl_pair, 0, sizeof(cl_pair));
+ get_nvp(qts, target_nvp, &nvp);
+ set_cl_pair(qts, &nvp, cl_pair);
+
+ /* Read some values from TIMA that we expect to see in cacheline */
+ qw1w0 = get_tima32(qts, target_pir, TM_QW1_OS + TM_WORD0);
+ qw3w0 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0);
+ qw1w2 = get_tima32(qts, target_pir, TM_QW1_OS + TM_WORD2);
+ qw2w2 = get_tima32(qts, target_pir, TM_QW2_HV_POOL + TM_WORD2);
+ qw3b8 = get_tima8(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD2);
+
+ /* Execute the pull operation */
+ set_tima8(qts, target_pir, TM_SPC_PULL_PHYS_CTX_OL, 0);
+
+ /* Verify odd cache line values match TIMA after pull operation */
+ get_cl_pair(qts, &nvp, cl_pair);
+ memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW1_OS + TM_WORD0], 4);
+ g_assert_cmphex(qw1w0, ==, be32_to_cpu(cl_word));
+ memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW3_HV_PHYS + TM_WORD0], 4);
+ g_assert_cmphex(qw3w0, ==, be32_to_cpu(cl_word));
+ memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW1_OS + TM_WORD2], 4);
+ g_assert_cmphex(qw1w2, ==, be32_to_cpu(cl_word));
+ memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW2_HV_POOL + TM_WORD2], 4);
+ g_assert_cmphex(qw2w2, ==, be32_to_cpu(cl_word));
+ g_assert_cmphex(qw3b8, ==,
+ cl_pair[XIVE_ODD_CL + TM_QW3_HV_PHYS + TM_WORD2]);
+
+ /* Verify that all TIMA valid bits for target thread are cleared */
+ word2 = get_tima32(qts, target_pir, TM_QW1_OS + TM_WORD2);
+ g_assert_cmphex(xive_get_field32(TM_QW1W2_VO, word2), ==, 0);
+ word2 = get_tima32(qts, target_pir, TM_QW2_HV_POOL + TM_WORD2);
+ g_assert_cmphex(xive_get_field32(TM_QW2W2_VP, word2), ==, 0);
+ word2 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD2);
+ g_assert_cmphex(xive_get_field32(TM_QW3W2_VT, word2), ==, 0);
+}
+
+static void test_hw_group_irq(QTestState *qts)
+{
+ uint32_t irq = 100;
+ uint32_t irq_data = 0xdeadbeef;
+ uint32_t end_index = 23;
+ uint32_t chosen_one;
+ uint32_t target_nvp = 0x81; /* group size = 4 */
+ uint8_t priority = 6;
+ uint32_t reg32;
+ uint16_t reg16;
+ uint8_t pq, nsr, cppr;
+
+ g_test_message("=========================================================");
+ g_test_message("Testing irq %d to hardware group of size 4", irq);
+
+ /* irq config */
+ set_eas(qts, irq, end_index, irq_data);
+ set_end(qts, end_index, target_nvp, priority, true /* group */);
+
+ /* enable and trigger irq */
+ get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_SET_PQ_00);
+ set_esb(qts, irq, XIVE_TRIGGER_PAGE, 0, 0);
+
+ /* check irq is raised on cpu */
+ pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
+ g_assert_cmpuint(pq, ==, XIVE_ESB_PENDING);
+
+ /* find the targeted vCPU */
+ for (chosen_one = 0; chosen_one < SMT; chosen_one++) {
+ reg32 = get_tima32(qts, chosen_one, TM_QW3_HV_PHYS + TM_WORD0);
+ nsr = reg32 >> 24;
+ if (nsr == 0x82) {
+ break;
+ }
+ }
+ g_assert_cmphex(chosen_one, <, SMT);
+ cppr = (reg32 >> 16) & 0xFF;
+ g_assert_cmphex(nsr, ==, 0x82);
+ g_assert_cmphex(cppr, ==, 0xFF);
+
+ /* ack the irq */
+ reg16 = get_tima16(qts, chosen_one, TM_SPC_ACK_HV_REG);
+ nsr = reg16 >> 8;
+ cppr = reg16 & 0xFF;
+ g_assert_cmphex(nsr, ==, 0x82);
+ g_assert_cmphex(cppr, ==, priority);
+
+ /* check irq data is what was configured */
+ reg32 = qtest_readl(qts, xive_get_queue_addr(end_index));
+ g_assert_cmphex((reg32 & 0x7fffffff), ==, (irq_data & 0x7fffffff));
+
+ /* End Of Interrupt */
+ set_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_STORE_EOI, 0);
+ pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
+ g_assert_cmpuint(pq, ==, XIVE_ESB_RESET);
+
+ /* reset CPPR */
+ set_tima8(qts, chosen_one, TM_QW3_HV_PHYS + TM_CPPR, 0xFF);
+ reg32 = get_tima32(qts, chosen_one, TM_QW3_HV_PHYS + TM_WORD0);
+ nsr = reg32 >> 24;
+ cppr = (reg32 >> 16) & 0xFF;
+ g_assert_cmphex(nsr, ==, 0x00);
+ g_assert_cmphex(cppr, ==, 0xFF);
+}
+
+static void test_hw_group_irq_backlog(QTestState *qts)
+{
+ uint32_t irq = 31;
+ uint32_t irq_data = 0x01234567;
+ uint32_t end_index = 129;
+ uint32_t target_nvp = 0x81; /* group size = 4 */
+ uint32_t chosen_one = 3;
+ uint8_t blocking_priority, priority = 3;
+ uint32_t reg32;
+ uint16_t reg16;
+ uint8_t pq, nsr, cppr, lsmfb, i;
+
+ g_test_message("=========================================================");
+ g_test_message("Testing irq %d to hardware group of size 4 going " \
+ "through backlog",
+ irq);
+
+ /*
+ * set current priority of all threads in the group to something
+ * higher than what we're about to trigger
+ */
+ blocking_priority = priority - 1;
+ for (i = 0; i < SMT; i++) {
+ set_tima8(qts, i, TM_QW3_HV_PHYS + TM_CPPR, blocking_priority);
+ }
+
+ /* irq config */
+ set_eas(qts, irq, end_index, irq_data);
+ set_end(qts, end_index, target_nvp, priority, true /* group */);
+
+ /* enable and trigger irq */
+ get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_SET_PQ_00);
+ set_esb(qts, irq, XIVE_TRIGGER_PAGE, 0, 0);
+
+ /* check irq is raised on cpu */
+ pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
+ g_assert_cmpuint(pq, ==, XIVE_ESB_PENDING);
+
+ /* check no interrupt is pending on the 2 possible targets */
+ for (i = 0; i < SMT; i++) {
+ reg32 = get_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD0);
+ nsr = reg32 >> 24;
+ cppr = (reg32 >> 16) & 0xFF;
+ lsmfb = reg32 & 0xFF;
+ g_assert_cmphex(nsr, ==, 0x0);
+ g_assert_cmphex(cppr, ==, blocking_priority);
+ g_assert_cmphex(lsmfb, ==, priority);
+ }
+
+ /* lower priority of one thread */
+ set_tima8(qts, chosen_one, TM_QW3_HV_PHYS + TM_CPPR, priority + 1);
+
+ /* check backlogged interrupt is presented */
+ reg32 = get_tima32(qts, chosen_one, TM_QW3_HV_PHYS + TM_WORD0);
+ nsr = reg32 >> 24;
+ cppr = (reg32 >> 16) & 0xFF;
+ g_assert_cmphex(nsr, ==, 0x82);
+ g_assert_cmphex(cppr, ==, priority + 1);
+
+ /* ack the irq */
+ reg16 = get_tima16(qts, chosen_one, TM_SPC_ACK_HV_REG);
+ nsr = reg16 >> 8;
+ cppr = reg16 & 0xFF;
+ g_assert_cmphex(nsr, ==, 0x82);
+ g_assert_cmphex(cppr, ==, priority);
+
+ /* check irq data is what was configured */
+ reg32 = qtest_readl(qts, xive_get_queue_addr(end_index));
+ g_assert_cmphex((reg32 & 0x7fffffff), ==, (irq_data & 0x7fffffff));
+
+ /* End Of Interrupt */
+ set_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_STORE_EOI, 0);
+ pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
+ g_assert_cmpuint(pq, ==, XIVE_ESB_RESET);
+
+ /* reset CPPR */
+ set_tima8(qts, chosen_one, TM_QW3_HV_PHYS + TM_CPPR, 0xFF);
+ reg32 = get_tima32(qts, chosen_one, TM_QW3_HV_PHYS + TM_WORD0);
+ nsr = reg32 >> 24;
+ cppr = (reg32 >> 16) & 0xFF;
+ lsmfb = reg32 & 0xFF;
+ g_assert_cmphex(nsr, ==, 0x00);
+ g_assert_cmphex(cppr, ==, 0xFF);
+ g_assert_cmphex(lsmfb, ==, 0xFF);
+}
+
+static void test_xive(void)
+{
+ QTestState *qts;
+
+ qts = qtest_initf("-M powernv10 -smp %d,cores=1,threads=%d -nographic "
+ "-nodefaults -serial mon:stdio -S "
+ "-d guest_errors -trace '*xive*'",
+ SMT, SMT);
+ init_xive(qts);
+
+ test_hw_irq(qts);
+
+ /* omit reset_state here and use settings from test_hw_irq */
+ test_pull_thread_ctx_to_odd_thread_cl(qts);
+
+ reset_state(qts);
+ test_pool_irq(qts);
+
+ reset_state(qts);
+ test_hw_group_irq(qts);
+
+ reset_state(qts);
+ test_hw_group_irq_backlog(qts);
+
+ reset_state(qts);
+ test_flush_sync_inject(qts);
+
+ reset_state(qts);
+ test_nvpg_bar(qts);
+
+ qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ qtest_add_func("xive2", test_xive);
+ return g_test_run();
+}
diff --git a/tests/qtest/pvpanic-pci-test.c b/tests/qtest/pvpanic-pci-test.c
index dc021c2..f788a44 100644
--- a/tests/qtest/pvpanic-pci-test.c
+++ b/tests/qtest/pvpanic-pci-test.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "libqos/pci.h"
#include "libqos/pci-pc.h"
#include "hw/misc/pvpanic.h"
diff --git a/tests/qtest/pvpanic-test.c b/tests/qtest/pvpanic-test.c
index d49d2ba..5606baf 100644
--- a/tests/qtest/pvpanic-test.c
+++ b/tests/qtest/pvpanic-test.c
@@ -9,7 +9,7 @@
#include "qemu/osdep.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "hw/misc/pvpanic.h"
static void test_panic_nopause(void)
diff --git a/tests/qtest/q35-test.c b/tests/qtest/q35-test.c
index c922d81..62fff49 100644
--- a/tests/qtest/q35-test.c
+++ b/tests/qtest/q35-test.c
@@ -14,7 +14,7 @@
#include "libqos/pci.h"
#include "libqos/pci-pc.h"
#include "hw/pci-host/q35.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#define TSEG_SIZE_TEST_GUEST_RAM_MBYTES 128
@@ -83,7 +83,6 @@ static void test_smram_lock(void)
{
QPCIBus *pcibus;
QPCIDevice *pcidev;
- QDict *response;
QTestState *qts;
qts = qtest_init("-M q35");
@@ -107,10 +106,7 @@ static void test_smram_lock(void)
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);
+ qtest_system_reset(qts);
/* check open is settable again */
smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, false);
@@ -194,7 +190,6 @@ static void test_smram_smbase_lock(void)
{
QPCIBus *pcibus;
QPCIDevice *pcidev;
- QDict *response;
QTestState *qts;
int i;
@@ -237,10 +232,7 @@ static void test_smram_smbase_lock(void)
}
/* reset */
- response = qtest_qmp(qts, "{'execute': 'system_reset', 'arguments': {} }");
- g_assert(response);
- g_assert(!qdict_haskey(response, "error"));
- qobject_unref(response);
+ qtest_system_reset(qts);
/* check RAM at SMBASE is available after reset */
g_assert_cmpint(qtest_readb(qts, SMBASE), ==, SMRAM_TEST_PATTERN);
@@ -254,41 +246,6 @@ static void test_smram_smbase_lock(void)
qtest_quit(qts);
}
-static void test_without_smram_base(void)
-{
- QPCIBus *pcibus;
- QPCIDevice *pcidev;
- QTestState *qts;
- int i;
-
- qts = qtest_init("-M pc-q35-4.1");
-
- pcibus = qpci_new_pc(qts, NULL);
- g_assert(pcibus != NULL);
-
- pcidev = qpci_device_find(pcibus, 0);
- g_assert(pcidev != NULL);
-
- /* check that RAM is accessible */
- qtest_writeb(qts, SMBASE, SMRAM_TEST_PATTERN);
- g_assert_cmpint(qtest_readb(qts, SMBASE), ==, SMRAM_TEST_PATTERN);
-
- /* check that writing to 0x9c succeeds */
- for (i = 0; i <= 0xff; i++) {
- qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_F_SMBASE, i);
- g_assert(qpci_config_readb(pcidev, MCH_HOST_BRIDGE_F_SMBASE) == i);
- }
-
- /* check that RAM is still accessible */
- qtest_writeb(qts, SMBASE, SMRAM_TEST_PATTERN + 1);
- g_assert_cmpint(qtest_readb(qts, SMBASE), ==, (SMRAM_TEST_PATTERN + 1));
-
- g_free(pcidev);
- qpci_free_pc(pcibus);
-
- qtest_quit(qts);
-}
-
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
@@ -301,6 +258,6 @@ int main(int argc, char **argv)
qtest_add_data_func("/q35/tseg-size/ext/16mb", &tseg_ext_16mb,
test_tseg_size);
qtest_add_func("/q35/smram/smbase_lock", test_smram_smbase_lock);
- qtest_add_func("/q35/smram/legacy_smbase", test_without_smram_base);
+
return g_test_run();
}
diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
index 2c15f60..040d042 100644
--- a/tests/qtest/qmp-cmd-test.c
+++ b/tests/qtest/qmp-cmd-test.c
@@ -14,7 +14,7 @@
#include "libqtest.h"
#include "qapi/error.h"
#include "qapi/qapi-visit-introspect.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qapi/qobject-input-visitor.h"
const char common_args[] = "-nodefaults -machine none";
@@ -100,6 +100,7 @@ static bool query_is_ignored(const char *cmd)
/* Success depends on target arch: */
"query-cpu-definitions", /* arm, i386, ppc, s390x */
"query-gic-capabilities", /* arm */
+ "query-s390x-cpu-polarization", /* s390x */
/* Success depends on target-specific build configuration: */
"query-pci", /* CONFIG_PCI */
"x-query-virtio", /* CONFIG_VIRTIO */
diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c
index 22957fa..edf0886 100644
--- a/tests/qtest/qmp-test.c
+++ b/tests/qtest/qmp-test.c
@@ -14,10 +14,10 @@
#include "libqtest.h"
#include "qapi/error.h"
#include "qapi/qapi-visit-control.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
#include "qapi/qobject-input-visitor.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qstring.h"
const char common_args[] = "-nodefaults -machine none";
diff --git a/tests/qtest/qom-test.c b/tests/qtest/qom-test.c
index d677f87..27d70bc 100644
--- a/tests/qtest/qom-test.c
+++ b/tests/qtest/qom-test.c
@@ -9,8 +9,8 @@
#include "qemu/osdep.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
#include "qemu/cutils.h"
#include "libqtest.h"
@@ -88,6 +88,17 @@ static void test_machine(gconstpointer data)
qts = qtest_initf("-machine %s", machine);
+ if (g_test_slow()) {
+ /* Make sure we can get the machine class properties: */
+ g_autofree char *qom_machine = g_strdup_printf("%s-machine", machine);
+
+ response = qtest_qmp(qts, "{ 'execute': 'qom-list-properties',"
+ " 'arguments': { 'typename': %s } }",
+ qom_machine);
+ g_assert(response);
+ qobject_unref(response);
+ }
+
test_properties(qts, "/machine", true);
response = qtest_qmp(qts, "{ 'execute': 'quit' }");
diff --git a/tests/qtest/qos-test.c b/tests/qtest/qos-test.c
index 114f6be..abfd4b9 100644
--- a/tests/qtest/qos-test.c
+++ b/tests/qtest/qos-test.c
@@ -20,7 +20,7 @@
#include <getopt.h>
#include "libqtest-single.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qemu/module.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qapi-visit-machine.h"
@@ -103,8 +103,7 @@ static void restart_qemu_or_continue(char *path)
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");
+ qtest_system_reset(global_qtest);
}
}
diff --git a/tests/qtest/readconfig-test.c b/tests/qtest/readconfig-test.c
index 760f974..c6f32a4 100644
--- a/tests/qtest/readconfig-test.c
+++ b/tests/qtest/readconfig-test.c
@@ -13,10 +13,10 @@
#include "qapi/qapi-visit-machine.h"
#include "qapi/qapi-visit-qom.h"
#include "qapi/qapi-visit-ui.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
#include "qapi/qobject-input-visitor.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qstring.h"
#include "qemu/units.h"
static QTestState *qtest_init_with_config(const char *cfgdata)
diff --git a/tests/qtest/riscv-csr-test.c b/tests/qtest/riscv-csr-test.c
new file mode 100644
index 0000000..ff5c29e
--- /dev/null
+++ b/tests/qtest/riscv-csr-test.c
@@ -0,0 +1,56 @@
+/*
+ * QTest testcase for RISC-V CSRs
+ *
+ * Copyright (c) 2024 Syntacore.
+ *
+ * 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.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+#define CSR_MVENDORID 0xf11
+#define CSR_MISELECT 0x350
+
+static void run_test_csr(void)
+{
+ uint64_t res;
+ uint64_t val = 0;
+
+ QTestState *qts = qtest_init("-machine virt -cpu veyron-v1");
+
+ res = qtest_csr_call(qts, "get_csr", 0, CSR_MVENDORID, &val);
+
+ g_assert_cmpint(res, ==, 0);
+ g_assert_cmpint(val, ==, 0x61f);
+
+ val = 0xff;
+ res = qtest_csr_call(qts, "set_csr", 0, CSR_MISELECT, &val);
+
+ g_assert_cmpint(res, ==, 0);
+
+ val = 0;
+ res = qtest_csr_call(qts, "get_csr", 0, CSR_MISELECT, &val);
+
+ g_assert_cmpint(res, ==, 0);
+ g_assert_cmpint(val, ==, 0xff);
+
+ qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/cpu/csr", run_test_csr);
+
+ return g_test_run();
+}
diff --git a/tests/qtest/riscv-iommu-test.c b/tests/qtest/riscv-iommu-test.c
new file mode 100644
index 0000000..df0c781
--- /dev/null
+++ b/tests/qtest/riscv-iommu-test.c
@@ -0,0 +1,210 @@
+/*
+ * QTest testcase for RISC-V IOMMU
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "qemu/module.h"
+#include "libqos/qgraph.h"
+#include "libqos/riscv-iommu.h"
+#include "hw/pci/pci_regs.h"
+
+static uint32_t riscv_iommu_read_reg32(QRISCVIOMMU *r_iommu, int reg_offset)
+{
+ return qpci_io_readl(&r_iommu->dev, r_iommu->reg_bar, reg_offset);
+}
+
+static uint64_t riscv_iommu_read_reg64(QRISCVIOMMU *r_iommu, int reg_offset)
+{
+ return qpci_io_readq(&r_iommu->dev, r_iommu->reg_bar, reg_offset);
+}
+
+static void riscv_iommu_write_reg32(QRISCVIOMMU *r_iommu, int reg_offset,
+ uint32_t val)
+{
+ qpci_io_writel(&r_iommu->dev, r_iommu->reg_bar, reg_offset, val);
+}
+
+static void riscv_iommu_write_reg64(QRISCVIOMMU *r_iommu, int reg_offset,
+ uint64_t val)
+{
+ qpci_io_writeq(&r_iommu->dev, r_iommu->reg_bar, reg_offset, val);
+}
+
+static void test_pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+ QRISCVIOMMU *r_iommu = obj;
+ QPCIDevice *dev = &r_iommu->dev;
+ uint16_t vendorid, deviceid, classid;
+
+ vendorid = qpci_config_readw(dev, PCI_VENDOR_ID);
+ deviceid = qpci_config_readw(dev, PCI_DEVICE_ID);
+ classid = qpci_config_readw(dev, PCI_CLASS_DEVICE);
+
+ g_assert_cmpuint(vendorid, ==, RISCV_IOMMU_PCI_VENDOR_ID);
+ g_assert_cmpuint(deviceid, ==, RISCV_IOMMU_PCI_DEVICE_ID);
+ g_assert_cmpuint(classid, ==, RISCV_IOMMU_PCI_DEVICE_CLASS);
+}
+
+static void test_reg_reset(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+ QRISCVIOMMU *r_iommu = obj;
+ uint64_t cap;
+ uint32_t reg;
+
+ cap = riscv_iommu_read_reg64(r_iommu, RISCV_IOMMU_REG_CAP);
+ g_assert_cmpuint(cap & RISCV_IOMMU_CAP_VERSION, ==, 0x10);
+
+ reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_CQCSR);
+ g_assert_cmpuint(reg & RISCV_IOMMU_CQCSR_CQEN, ==, 0);
+ g_assert_cmpuint(reg & RISCV_IOMMU_CQCSR_CIE, ==, 0);
+ g_assert_cmpuint(reg & RISCV_IOMMU_CQCSR_CQON, ==, 0);
+ g_assert_cmpuint(reg & RISCV_IOMMU_CQCSR_BUSY, ==, 0);
+
+ reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_FQCSR);
+ g_assert_cmpuint(reg & RISCV_IOMMU_FQCSR_FQEN, ==, 0);
+ g_assert_cmpuint(reg & RISCV_IOMMU_FQCSR_FIE, ==, 0);
+ g_assert_cmpuint(reg & RISCV_IOMMU_FQCSR_FQON, ==, 0);
+ g_assert_cmpuint(reg & RISCV_IOMMU_FQCSR_BUSY, ==, 0);
+
+ reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_PQCSR);
+ g_assert_cmpuint(reg & RISCV_IOMMU_PQCSR_PQEN, ==, 0);
+ g_assert_cmpuint(reg & RISCV_IOMMU_PQCSR_PIE, ==, 0);
+ g_assert_cmpuint(reg & RISCV_IOMMU_PQCSR_PQON, ==, 0);
+ g_assert_cmpuint(reg & RISCV_IOMMU_PQCSR_BUSY, ==, 0);
+
+ reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_DDTP);
+ g_assert_cmpuint(reg & RISCV_IOMMU_DDTP_BUSY, ==, 0);
+ g_assert_cmpuint(reg & RISCV_IOMMU_DDTP_MODE, ==,
+ RISCV_IOMMU_DDTP_MODE_OFF);
+
+ reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_IPSR);
+ g_assert_cmpuint(reg, ==, 0);
+}
+
+/*
+ * Common timeout-based poll for CQCSR, FQCSR and PQCSR. All
+ * their ON bits are mapped as RISCV_IOMMU_QUEUE_ACTIVE (16),
+ */
+static void qtest_wait_for_queue_active(QRISCVIOMMU *r_iommu,
+ uint32_t queue_csr)
+{
+ QTestState *qts = global_qtest;
+ guint64 timeout_us = 2 * 1000 * 1000;
+ gint64 start_time = g_get_monotonic_time();
+ uint32_t reg;
+
+ for (;;) {
+ qtest_clock_step(qts, 100);
+
+ reg = riscv_iommu_read_reg32(r_iommu, queue_csr);
+ if (reg & RISCV_IOMMU_QUEUE_ACTIVE) {
+ break;
+ }
+ g_assert(g_get_monotonic_time() - start_time <= timeout_us);
+ }
+}
+
+/*
+ * Goes through the queue activation procedures of chapter 6.2,
+ * "Guidelines for initialization", of the RISCV-IOMMU spec.
+ */
+static void test_iommu_init_queues(void *obj, void *data,
+ QGuestAllocator *t_alloc)
+{
+ QRISCVIOMMU *r_iommu = obj;
+ uint64_t reg64, q_addr;
+ uint32_t reg;
+ int k = 2;
+
+ reg64 = riscv_iommu_read_reg64(r_iommu, RISCV_IOMMU_REG_CAP);
+ g_assert_cmpuint(reg64 & RISCV_IOMMU_CAP_VERSION, ==, 0x10);
+
+ /*
+ * Program the command queue. Write 0xF to civ, fiv, pmiv and
+ * piv. With the current PCI device impl we expect 2 writable
+ * bits for each (k = 2) since we have N = 4 total vectors (2^k).
+ */
+ riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_IVEC, 0xFFFF);
+ reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_IVEC);
+ g_assert_cmpuint(reg & RISCV_IOMMU_REG_IVEC_CIV, ==, 0x3);
+ g_assert_cmpuint(reg & RISCV_IOMMU_REG_IVEC_FIV, ==, 0x30);
+ g_assert_cmpuint(reg & RISCV_IOMMU_REG_IVEC_PMIV, ==, 0x300);
+ g_assert_cmpuint(reg & RISCV_IOMMU_REG_IVEC_PIV, ==, 0x3000);
+
+ /* Alloc a 4*16 bytes buffer and use it to set cqb */
+ q_addr = guest_alloc(t_alloc, 4 * 16);
+ reg64 = 0;
+ deposit64(reg64, RISCV_IOMMU_CQB_PPN_START,
+ RISCV_IOMMU_CQB_PPN_LEN, q_addr);
+ deposit64(reg64, RISCV_IOMMU_CQB_LOG2SZ_START,
+ RISCV_IOMMU_CQB_LOG2SZ_LEN, k - 1);
+ riscv_iommu_write_reg64(r_iommu, RISCV_IOMMU_REG_CQB, reg64);
+
+ /* cqt = 0, cqcsr.cqen = 1, poll cqcsr.cqon until it reads 1 */
+ riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_CQT, 0);
+
+ reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_CQCSR);
+ reg |= RISCV_IOMMU_CQCSR_CQEN;
+ riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_CQCSR, reg);
+
+ qtest_wait_for_queue_active(r_iommu, RISCV_IOMMU_REG_CQCSR);
+
+ /*
+ * Program the fault queue. Alloc a 4*32 bytes (instead of 4*16)
+ * buffer and use it to set fqb.
+ */
+ q_addr = guest_alloc(t_alloc, 4 * 32);
+ reg64 = 0;
+ deposit64(reg64, RISCV_IOMMU_FQB_PPN_START,
+ RISCV_IOMMU_FQB_PPN_LEN, q_addr);
+ deposit64(reg64, RISCV_IOMMU_FQB_LOG2SZ_START,
+ RISCV_IOMMU_FQB_LOG2SZ_LEN, k - 1);
+ riscv_iommu_write_reg64(r_iommu, RISCV_IOMMU_REG_FQB, reg64);
+
+ /* fqt = 0, fqcsr.fqen = 1, poll fqcsr.fqon until it reads 1 */
+ riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_FQT, 0);
+
+ reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_FQCSR);
+ reg |= RISCV_IOMMU_FQCSR_FQEN;
+ riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_FQCSR, reg);
+
+ qtest_wait_for_queue_active(r_iommu, RISCV_IOMMU_REG_FQCSR);
+
+ /*
+ * Program the page-request queue. Alloc a 4*16 bytes buffer
+ * and use it to set pqb.
+ */
+ q_addr = guest_alloc(t_alloc, 4 * 16);
+ reg64 = 0;
+ deposit64(reg64, RISCV_IOMMU_PQB_PPN_START,
+ RISCV_IOMMU_PQB_PPN_LEN, q_addr);
+ deposit64(reg64, RISCV_IOMMU_PQB_LOG2SZ_START,
+ RISCV_IOMMU_PQB_LOG2SZ_LEN, k - 1);
+ riscv_iommu_write_reg64(r_iommu, RISCV_IOMMU_REG_PQB, reg64);
+
+ /* pqt = 0, pqcsr.pqen = 1, poll pqcsr.pqon until it reads 1 */
+ riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_PQT, 0);
+
+ reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_PQCSR);
+ reg |= RISCV_IOMMU_PQCSR_PQEN;
+ riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_PQCSR, reg);
+
+ qtest_wait_for_queue_active(r_iommu, RISCV_IOMMU_REG_PQCSR);
+}
+
+static void register_riscv_iommu_test(void)
+{
+ qos_add_test("pci_config", "riscv-iommu-pci", test_pci_config, NULL);
+ qos_add_test("reg_reset", "riscv-iommu-pci", test_reg_reset, NULL);
+ qos_add_test("iommu_init_queues", "riscv-iommu-pci",
+ test_iommu_init_queues, NULL);
+}
+
+libqos_init(register_riscv_iommu_test);
diff --git a/tests/qtest/rs5c372-test.c b/tests/qtest/rs5c372-test.c
new file mode 100644
index 0000000..0f6a9b6
--- /dev/null
+++ b/tests/qtest/rs5c372-test.c
@@ -0,0 +1,43 @@
+/*
+ * QTest testcase for the RS5C372 RTC
+ *
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * Based on ds1338-test.c
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bcd.h"
+#include "libqos/i2c.h"
+
+#define RS5C372_ADDR 0x32
+
+static void rs5c372_read_date(void *obj, void *data, QGuestAllocator *alloc)
+{
+ QI2CDevice *i2cdev = obj;
+
+ uint8_t resp[0x10];
+ time_t now = time(NULL);
+ struct tm *utc = gmtime(&now);
+
+ i2c_read_block(i2cdev, 0, resp, sizeof(resp));
+
+ /* check retrieved time against local time */
+ g_assert_cmpuint(from_bcd(resp[5]), == , utc->tm_mday);
+ g_assert_cmpuint(from_bcd(resp[6]), == , 1 + utc->tm_mon);
+ g_assert_cmpuint(2000 + from_bcd(resp[7]), == , 1900 + utc->tm_year);
+}
+
+static void rs5c372_register_nodes(void)
+{
+ QOSGraphEdgeOptions opts = { };
+ add_qi2c_address(&opts, &(QI2CAddress) { RS5C372_ADDR });
+
+ qos_node_create_driver("rs5c372", i2c_device_create);
+ qos_node_consumes("rs5c372", "i2c-bus", &opts);
+ qos_add_test("read_date", "rs5c372", rs5c372_read_date, NULL);
+}
+
+libqos_init(rs5c372_register_nodes);
diff --git a/tests/qtest/rtl8139-test.c b/tests/qtest/rtl8139-test.c
index eedf90f..55f671f 100644
--- a/tests/qtest/rtl8139-test.c
+++ b/tests/qtest/rtl8139-test.c
@@ -65,7 +65,7 @@ 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)
+#define fatal(...) do { g_test_message(__VA_ARGS__); g_assert_not_reached(); } while (0)
static void test_timer(void)
{
diff --git a/tests/qtest/stm32l4x5.h b/tests/qtest/stm32l4x5.h
new file mode 100644
index 0000000..2d21cc6
--- /dev/null
+++ b/tests/qtest/stm32l4x5.h
@@ -0,0 +1,42 @@
+/*
+ * QTest testcase header for STM32L4X5 :
+ * used for consolidating common objects in stm32l4x5_*-test.c
+ *
+ * Copyright (c) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
+ * Copyright (c) 2024 Inès Varhol <ines.varhol@telecom-paris.fr>
+ *
+ * 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 "libqtest.h"
+
+/* copied from clock.h */
+#define CLOCK_PERIOD_1SEC (1000000000llu << 32)
+#define CLOCK_PERIOD_FROM_HZ(hz) (((hz) != 0) ? CLOCK_PERIOD_1SEC / (hz) : 0u)
+/*
+ * MSI (4 MHz) is used as system clock source after startup
+ * from Reset.
+ * AHB, APB1 and APB2 prescalers are set to 1 at reset.
+ */
+#define SYSCLK_PERIOD CLOCK_PERIOD_FROM_HZ(4000000)
+#define RCC_AHB2ENR 0x4002104C
+#define RCC_APB1ENR1 0x40021058
+#define RCC_APB1ENR2 0x4002105C
+#define RCC_APB2ENR 0x40021060
+
+
+static inline uint64_t get_clock_period(QTestState *qts, const char *path)
+{
+ uint64_t clock_period = 0;
+ QDict *r;
+
+ r = qtest_qmp(qts, "{ 'execute': 'qom-get', 'arguments':"
+ " { 'path': %s, 'property': 'qtest-clock-period'} }", path);
+ g_assert_false(qdict_haskey(r, "error"));
+ clock_period = qdict_get_int(r, "return");
+ qobject_unref(r);
+ return clock_period;
+}
+
+
diff --git a/tests/qtest/stm32l4x5_gpio-test.c b/tests/qtest/stm32l4x5_gpio-test.c
index 72a7823..3c6ea71 100644
--- a/tests/qtest/stm32l4x5_gpio-test.c
+++ b/tests/qtest/stm32l4x5_gpio-test.c
@@ -10,6 +10,7 @@
#include "qemu/osdep.h"
#include "libqtest-single.h"
+#include "stm32l4x5.h"
#define GPIO_BASE_ADDR 0x48000000
#define GPIO_SIZE 0x400
@@ -168,14 +169,6 @@ static uint32_t reset(uint32_t gpio, unsigned int offset)
return 0x0;
}
-static void system_reset(void)
-{
- QDict *r;
- r = qtest_qmp(global_qtest, "{'execute': 'system_reset'}");
- g_assert_false(qdict_haskey(r, "error"));
- qobject_unref(r);
-}
-
static void test_idr_reset_value(void)
{
/*
@@ -213,7 +206,7 @@ static void test_idr_reset_value(void)
gpio_writel(GPIO_H, OTYPER, 0xDEADBEEF);
gpio_writel(GPIO_H, PUPDR, 0xDEADBEEF);
- system_reset();
+ qtest_system_reset(global_qtest);
uint32_t moder = gpio_readl(GPIO_A, MODER);
uint32_t odr = gpio_readl(GPIO_A, ODR);
@@ -505,6 +498,26 @@ static void test_bsrr_brr(const void *data)
gpio_writel(gpio, ODR, reset(gpio, ODR));
}
+static void test_clock_enable(void)
+{
+ /*
+ * For each GPIO, enable its clock in RCC
+ * and check that its clock period changes to SYSCLK_PERIOD
+ */
+ unsigned int gpio_id;
+
+ for (uint32_t gpio = GPIO_A; gpio <= GPIO_H; gpio += GPIO_B - GPIO_A) {
+ gpio_id = get_gpio_id(gpio);
+ g_autofree char *path = g_strdup_printf("/machine/soc/gpio%c/clk",
+ gpio_id + 'a');
+ g_assert_cmpuint(get_clock_period(global_qtest, path), ==, 0);
+ /* Enable the gpio clock */
+ writel(RCC_AHB2ENR, readl(RCC_AHB2ENR) | (0x1 << gpio_id));
+ g_assert_cmpuint(get_clock_period(global_qtest, path), ==,
+ SYSCLK_PERIOD);
+ }
+}
+
int main(int argc, char **argv)
{
int ret;
@@ -556,6 +569,8 @@ int main(int argc, char **argv)
qtest_add_data_func("stm32l4x5/gpio/test_bsrr_brr2",
test_data(GPIO_D, 0),
test_bsrr_brr);
+ qtest_add_func("stm32l4x5/gpio/test_clock_enable",
+ test_clock_enable);
qtest_start("-machine b-l475e-iot01a");
ret = g_test_run();
diff --git a/tests/qtest/stm32l4x5_syscfg-test.c b/tests/qtest/stm32l4x5_syscfg-test.c
index 258417c..376c80e 100644
--- a/tests/qtest/stm32l4x5_syscfg-test.c
+++ b/tests/qtest/stm32l4x5_syscfg-test.c
@@ -10,6 +10,7 @@
#include "qemu/osdep.h"
#include "libqtest-single.h"
+#include "stm32l4x5.h"
#define SYSCFG_BASE_ADDR 0x40010000
#define SYSCFG_MEMRMP 0x00
@@ -26,7 +27,9 @@
#define INVALID_ADDR 0x2C
/* SoC forwards GPIOs to SysCfg */
-#define SYSCFG "/machine/soc"
+#define SOC "/machine/soc"
+#define SYSCFG "/machine/soc/syscfg"
+#define SYSCFG_CLK "/machine/soc/syscfg/clk"
#define EXTI "/machine/soc/exti"
static void syscfg_writel(unsigned int offset, uint32_t value)
@@ -41,15 +44,7 @@ static uint32_t syscfg_readl(unsigned int offset)
static void syscfg_set_irq(int num, int level)
{
- qtest_set_irq_in(global_qtest, SYSCFG, NULL, num, level);
-}
-
-static void system_reset(void)
-{
- QDict *response;
- response = qtest_qmp(global_qtest, "{'execute': 'system_reset'}");
- g_assert(qdict_haskey(response, "return"));
- qobject_unref(response);
+ qtest_set_irq_in(global_qtest, SOC, NULL, num, level);
}
static void test_reset(void)
@@ -179,7 +174,7 @@ static void test_set_only_bits(void)
syscfg_writel(SYSCFG_SWPR2, 0x00000000);
g_assert_cmphex(syscfg_readl(SYSCFG_SWPR2), ==, 0xFFFFFFFF);
- system_reset();
+ qtest_system_reset(global_qtest);
}
static void test_clear_only_bits(void)
@@ -191,7 +186,7 @@ static void test_clear_only_bits(void)
syscfg_writel(SYSCFG_CFGR1, 0x00000001);
g_assert_cmphex(syscfg_readl(SYSCFG_CFGR1), ==, 0x00000000);
- system_reset();
+ qtest_system_reset(global_qtest);
}
static void test_interrupt(void)
@@ -301,6 +296,17 @@ static void test_irq_gpio_multiplexer(void)
syscfg_writel(SYSCFG_EXTICR1, 0x00000000);
}
+static void test_clock_enable(void)
+{
+ g_assert_cmpuint(get_clock_period(global_qtest, SYSCFG_CLK), ==, 0);
+
+ /* Enable SYSCFG clock */
+ writel(RCC_APB2ENR, readl(RCC_APB2ENR) | (0x1 << 0));
+
+ g_assert_cmpuint(get_clock_period(global_qtest, SYSCFG_CLK), ==,
+ SYSCLK_PERIOD);
+}
+
int main(int argc, char **argv)
{
int ret;
@@ -325,6 +331,8 @@ int main(int argc, char **argv)
test_irq_pin_multiplexer);
qtest_add_func("stm32l4x5/syscfg/test_irq_gpio_multiplexer",
test_irq_gpio_multiplexer);
+ qtest_add_func("stm32l4x5/syscfg/test_clock_enable",
+ test_clock_enable);
qtest_start("-machine b-l475e-iot01a");
ret = g_test_run();
diff --git a/tests/qtest/stm32l4x5_usart-test.c b/tests/qtest/stm32l4x5_usart-test.c
index c175ff3..98a7472 100644
--- a/tests/qtest/stm32l4x5_usart-test.c
+++ b/tests/qtest/stm32l4x5_usart-test.c
@@ -12,6 +12,7 @@
#include "libqtest.h"
#include "hw/misc/stm32l4x5_rcc_internals.h"
#include "hw/registerfields.h"
+#include "stm32l4x5.h"
#define RCC_BASE_ADDR 0x40021000
/* Use USART 1 ADDR, assume the others work the same */
@@ -36,6 +37,8 @@ REG32(GTPR, 0x10)
REG32(RTOR, 0x14)
REG32(RQR, 0x18)
REG32(ISR, 0x1C)
+ FIELD(ISR, REACK, 22, 1)
+ FIELD(ISR, TEACK, 21, 1)
FIELD(ISR, TXE, 7, 1)
FIELD(ISR, RXNE, 5, 1)
FIELD(ISR, ORE, 3, 1)
@@ -191,7 +194,7 @@ static void init_uart(QTestState *qts)
/* Enable the transmitter, the receiver and the USART. */
qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
- R_CR1_UE_MASK | R_CR1_RE_MASK | R_CR1_TE_MASK);
+ cr1 | R_CR1_UE_MASK | R_CR1_RE_MASK | R_CR1_TE_MASK);
}
static void test_write_read(void)
@@ -298,10 +301,65 @@ static void test_send_str(void)
qtest_quit(qts);
}
-int main(int argc, char **argv)
+static void test_ack(void)
{
- int ret;
+ uint32_t cr1;
+ uint32_t isr;
+ QTestState *qts = qtest_init("-M b-l475e-iot01a");
+
+ init_uart(qts);
+
+ cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1));
+
+ /* Disable the transmitter and receiver. */
+ qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
+ cr1 & ~(R_CR1_RE_MASK | R_CR1_TE_MASK));
+
+ /* Test ISR ACK for transmitter and receiver disabled */
+ isr = qtest_readl(qts, (USART1_BASE_ADDR + A_ISR));
+ g_assert_false(isr & R_ISR_TEACK_MASK);
+ g_assert_false(isr & R_ISR_REACK_MASK);
+
+ /* Enable the transmitter and receiver. */
+ qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
+ cr1 | (R_CR1_RE_MASK | R_CR1_TE_MASK));
+
+ /* Test ISR ACK for transmitter and receiver disabled */
+ isr = qtest_readl(qts, (USART1_BASE_ADDR + A_ISR));
+ g_assert_true(isr & R_ISR_TEACK_MASK);
+ g_assert_true(isr & R_ISR_REACK_MASK);
+
+ qtest_quit(qts);
+}
+static void check_clock(QTestState *qts, const char *path, uint32_t rcc_reg,
+ uint32_t reg_offset)
+{
+ g_assert_cmpuint(get_clock_period(qts, path), ==, 0);
+ qtest_writel(qts, rcc_reg, qtest_readl(qts, rcc_reg) | (0x1 << reg_offset));
+ g_assert_cmpuint(get_clock_period(qts, path), ==, SYSCLK_PERIOD);
+}
+
+static void test_clock_enable(void)
+{
+ /*
+ * For each USART device, enable its clock in RCC
+ * and check that its clock frequency is SYSCLK_PERIOD
+ */
+ QTestState *qts = qtest_init("-M b-l475e-iot01a");
+
+ check_clock(qts, "machine/soc/usart[0]/clk", RCC_APB2ENR, 14);
+ check_clock(qts, "machine/soc/usart[1]/clk", RCC_APB1ENR1, 17);
+ check_clock(qts, "machine/soc/usart[2]/clk", RCC_APB1ENR1, 18);
+ check_clock(qts, "machine/soc/uart[0]/clk", RCC_APB1ENR1, 19);
+ check_clock(qts, "machine/soc/uart[1]/clk", RCC_APB1ENR1, 20);
+ check_clock(qts, "machine/soc/lpuart1/clk", RCC_APB1ENR2, 0);
+
+ qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
g_test_init(&argc, &argv, NULL);
g_test_set_nonfatal_assertions();
@@ -310,8 +368,8 @@ int main(int argc, char **argv)
qtest_add_func("stm32l4x5/usart/send_char", test_send_char);
qtest_add_func("stm32l4x5/usart/receive_str", test_receive_str);
qtest_add_func("stm32l4x5/usart/send_str", test_send_str);
- ret = g_test_run();
-
- return ret;
+ qtest_add_func("stm32l4x5/usart/ack", test_ack);
+ qtest_add_func("stm32l4x5/usart/clock_enable", test_clock_enable);
+ return g_test_run();
}
diff --git a/tests/qtest/tco-test.c b/tests/qtest/tco-test.c
index 0547d41..20ccefa 100644
--- a/tests/qtest/tco-test.c
+++ b/tests/qtest/tco-test.c
@@ -12,7 +12,7 @@
#include "libqtest.h"
#include "libqos/pci.h"
#include "libqos/pci-pc.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "hw/pci/pci_regs.h"
#include "hw/southbridge/ich9.h"
#include "hw/acpi/ich9.h"
diff --git a/tests/qtest/test-filter-mirror.c b/tests/qtest/test-filter-mirror.c
index f3865f7..723d2c2 100644
--- a/tests/qtest/test-filter-mirror.c
+++ b/tests/qtest/test-filter-mirror.c
@@ -10,7 +10,7 @@
#include "qemu/osdep.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qemu/iov.h"
#include "qemu/sockets.h"
#include "qemu/error-report.h"
diff --git a/tests/qtest/test-filter-redirector.c b/tests/qtest/test-filter-redirector.c
index a77d5fd..a996a80 100644
--- a/tests/qtest/test-filter-redirector.c
+++ b/tests/qtest/test-filter-redirector.c
@@ -52,7 +52,7 @@
#include "qemu/osdep.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qemu/iov.h"
#include "qemu/sockets.h"
#include "qemu/error-report.h"
diff --git a/tests/qtest/test-netfilter.c b/tests/qtest/test-netfilter.c
index b09ef7f..326d4bd 100644
--- a/tests/qtest/test-netfilter.c
+++ b/tests/qtest/test-netfilter.c
@@ -10,7 +10,7 @@
#include "qemu/osdep.h"
#include "libqtest-single.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
/* add a netfilter to a netdev and then remove it */
static void add_one_netfilter(void)
diff --git a/tests/qtest/test-x86-cpuid-compat.c b/tests/qtest/test-x86-cpuid-compat.c
index b9e7e5e..456e2af 100644
--- a/tests/qtest/test-x86-cpuid-compat.c
+++ b/tests/qtest/test-x86-cpuid-compat.c
@@ -1,8 +1,8 @@
#include "qemu/osdep.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qnum.h"
-#include "qapi/qmp/qbool.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
+#include "qobject/qnum.h"
+#include "qobject/qbool.h"
#include "libqtest-single.h"
static char *get_cpu0_qom_path(void)
@@ -193,7 +193,6 @@ static void add_feature_test(const char *name, const char *cpu,
args->bitnr = bitnr;
args->expected_value = expected_value;
qtest_add_data_func(name, args, test_feature_flag);
- return;
}
static void test_plus_minus_subprocess(void)
@@ -357,19 +356,6 @@ int main(int argc, char **argv)
"486", "xstore=on", "pc-i440fx-2.7",
"xlevel2", 0);
}
- /*
- * QEMU 2.3.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:
- */
- if (qtest_has_machine("pc-i440fx-2.3")) {
- add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.3/off",
- "Penryn", NULL, "pc-i440fx-2.3",
- "level", 4);
- add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.3/on",
- "Penryn", "erms=on", "pc-i440fx-2.3",
- "level", 7);
- }
if (qtest_has_machine("pc-i440fx-2.9")) {
add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.9/off",
"Conroe", NULL, "pc-i440fx-2.9",
@@ -379,25 +365,6 @@ int main(int argc, char **argv)
"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:
- */
- if (qtest_has_machine("pc-i440fx-2.3")) {
- add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.3",
- "SandyBridge", NULL, "pc-i440fx-2.3",
- "xlevel", 0x8000000a);
- }
- if (qtest_has_machine("pc-i440fx-2.4")) {
- add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-off",
- "SandyBridge", NULL, "pc-i440fx-2.4",
- "xlevel", 0x80000008);
- add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-on",
- "SandyBridge", "svm=on,npt=on", "pc-i440fx-2.4",
- "xlevel", 0x80000008);
- }
-
/* Test feature parsing */
add_feature_test("x86/cpuid/features/plus",
"486", "+arat",
diff --git a/tests/qtest/tmp105-test.c b/tests/qtest/tmp105-test.c
index 3678646..3b114a5 100644
--- a/tests/qtest/tmp105-test.c
+++ b/tests/qtest/tmp105-test.c
@@ -12,7 +12,7 @@
#include "libqtest-single.h"
#include "libqos/qgraph.h"
#include "libqos/i2c.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "hw/sensor/tmp105_regs.h"
#define TMP105_TEST_ID "tmp105-test"
@@ -100,9 +100,9 @@ static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc)
g_assert_cmphex(value, ==, 0x14f0);
i2c_set16(i2cdev, TMP105_REG_T_LOW, 0x1234);
- g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_LOW), ==, 0x1234);
+ g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_LOW), ==, 0x1230);
i2c_set16(i2cdev, TMP105_REG_T_HIGH, 0x4231);
- g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_HIGH), ==, 0x4231);
+ g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_HIGH), ==, 0x4230);
}
static void tmp105_register_nodes(void)
diff --git a/tests/qtest/tpm-emu.c b/tests/qtest/tpm-emu.c
index 2bf8ff4..9e4c200 100644
--- a/tests/qtest/tpm-emu.c
+++ b/tests/qtest/tpm-emu.c
@@ -16,8 +16,8 @@
#include "backends/tpm/tpm_ioctl.h"
#include "io/channel-socket.h"
#include "qapi/error.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qlist.h"
+#include "qobject/qstring.h"
#include "tpm-emu.h"
void tpm_emu_test_wait_cond(TPMTestState *s)
diff --git a/tests/qtest/tpm-emu.h b/tests/qtest/tpm-emu.h
index 712cee9..59c8009 100644
--- a/tests/qtest/tpm-emu.h
+++ b/tests/qtest/tpm-emu.h
@@ -21,7 +21,7 @@
#include "qemu/sockets.h"
#include "io/channel.h"
-#include "sysemu/tpm.h"
+#include "system/tpm.h"
#include "libqtest.h"
struct tpm_hdr {
diff --git a/tests/qtest/tpm-tests.c b/tests/qtest/tpm-tests.c
index fb94496..197714f 100644
--- a/tests/qtest/tpm-tests.c
+++ b/tests/qtest/tpm-tests.c
@@ -114,7 +114,7 @@ void tpm_test_swtpm_migration_test(const char *src_tpm_path,
sizeof(tpm_pcrread_resp));
tpm_util_migrate(src_qemu, uri);
- tpm_util_wait_for_migration_complete(src_qemu);
+ tpm_util_wait_for_migration_complete(dst_qemu);
tpm_util_pcrread(dst_qemu, tx, tpm_pcrread_resp,
sizeof(tpm_pcrread_resp));
diff --git a/tests/qtest/tpm-util.c b/tests/qtest/tpm-util.c
index 1c0319e..2cb2dd4 100644
--- a/tests/qtest/tpm-util.c
+++ b/tests/qtest/tpm-util.c
@@ -18,7 +18,7 @@
#include "hw/acpi/tpm.h"
#include "libqtest.h"
#include "tpm-util.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
void tpm_util_crb_transfer(QTestState *s,
const unsigned char *req, size_t req_size,
diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c
index 60199ab..4867ccf 100644
--- a/tests/qtest/ufs-test.c
+++ b/tests/qtest/ufs-test.c
@@ -8,13 +8,14 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
-#include "qemu/units.h"
#include "libqtest.h"
#include "libqos/qgraph.h"
#include "libqos/pci.h"
#include "scsi/constants.h"
#include "block/ufs.h"
+#include "qemu/bitmap.h"
+#define DWORD_BYTE 4
/* Test images sizes in Bytes */
#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
/* Timeout for various operations, in seconds. */
@@ -26,6 +27,12 @@
#define UTP_COMMAND_DESCRIPTOR_SIZE 4096
#define UTP_RESPONSE_UPIU_OFFSET 1024
#define UTP_PRDT_UPIU_OFFSET 2048
+#define UTRD_TEST_SLOT 0
+#define UFS_MAX_CMD_DESC 32
+/* Constants for MCQ */
+#define TEST_QID 0
+#define QUEUE_SIZE 32
+#define UFS_MCQ_MAX_QNUM 32
typedef struct QUfs QUfs;
@@ -34,12 +41,22 @@ struct QUfs {
QPCIDevice dev;
QPCIBar bar;
- uint64_t utrlba;
- uint64_t utmrlba;
+ DECLARE_BITMAP(cmd_desc_bitmap, UFS_MAX_CMD_DESC);
uint64_t cmd_desc_addr;
uint64_t data_buffer_addr;
bool enabled;
+ bool support_mcq;
+
+ /* for legacy doorbell mode */
+ uint64_t utrlba;
+
+ /* for mcq mode */
+ uint32_t maxq;
+ uint64_t sqlba[UFS_MCQ_MAX_QNUM];
+ uint64_t cqlba[UFS_MCQ_MAX_QNUM];
+ uint64_t sqdao[UFS_MCQ_MAX_QNUM];
+ uint64_t cqdao[UFS_MCQ_MAX_QNUM];
};
static inline uint32_t ufs_rreg(QUfs *ufs, size_t offset)
@@ -52,6 +69,24 @@ static inline void ufs_wreg(QUfs *ufs, size_t offset, uint32_t value)
qpci_io_writel(&ufs->dev, ufs->bar, offset, value);
}
+static int alloc_cmd_desc_slot(QUfs *ufs)
+{
+ int slot = find_first_zero_bit(ufs->cmd_desc_bitmap, UFS_MAX_CMD_DESC);
+ if (slot == UFS_MAX_CMD_DESC) {
+ g_assert_not_reached();
+ }
+ set_bit(slot, ufs->cmd_desc_bitmap);
+ return slot;
+}
+
+static void release_cmd_desc_slot(QUfs *ufs, int slot)
+{
+ if (!test_bit(slot, ufs->cmd_desc_bitmap)) {
+ g_assert_not_reached();
+ }
+ clear_bit(slot, ufs->cmd_desc_bitmap);
+}
+
static void ufs_wait_for_irq(QUfs *ufs)
{
uint64_t end_time;
@@ -64,14 +99,11 @@ static void ufs_wait_for_irq(QUfs *ufs)
} while (is == 0 && g_get_monotonic_time() < end_time);
}
-static UtpTransferReqDesc ufs_build_req_utrd(uint64_t cmd_desc_addr,
- uint8_t slot,
+static UtpTransferReqDesc ufs_build_req_utrd(uint64_t command_desc_base_addr,
uint32_t data_direction,
uint16_t prd_table_length)
{
UtpTransferReqDesc req = { 0 };
- uint64_t command_desc_base_addr =
- cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
req.header.dword_0 =
cpu_to_le32(1 << 28 | data_direction | UFS_UTP_REQ_DESC_INT_CMD);
@@ -88,54 +120,109 @@ static UtpTransferReqDesc ufs_build_req_utrd(uint64_t cmd_desc_addr,
return req;
}
-static void ufs_send_nop_out(QUfs *ufs, uint8_t slot,
- UtpTransferReqDesc *utrd_out, UtpUpiuRsp *rsp_out)
+static enum UtpOcsCodes
+__ufs_send_transfer_request_doorbell(QUfs *ufs, uint8_t lun,
+ const UtpTransferReqDesc *utrd)
{
- /* Build up utp transfer request descriptor */
- UtpTransferReqDesc utrd = ufs_build_req_utrd(ufs->cmd_desc_addr, slot,
- UFS_UTP_NO_DATA_TRANSFER, 0);
- uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
+ uint64_t utrd_addr =
+ ufs->utrlba + UTRD_TEST_SLOT * sizeof(UtpTransferReqDesc);
+ UtpTransferReqDesc utrd_result;
+
+ qtest_memwrite(ufs->dev.bus->qts, utrd_addr, utrd, sizeof(*utrd));
+
+ /* Ring the doorbell */
+ ufs_wreg(ufs, A_UTRLDBR, 1);
+ ufs_wait_for_irq(ufs);
+ g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
+ ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
+
+ /* Handle completed command */
+ qtest_memread(ufs->dev.bus->qts, utrd_addr, &utrd_result,
+ sizeof(utrd_result));
+ return le32_to_cpu(utrd_result.header.dword_2) & 0xf;
+}
+
+static enum UtpOcsCodes
+__ufs_send_transfer_request_mcq(QUfs *ufs, uint8_t lun,
+ const UtpTransferReqDesc *utrd)
+{
+ uint32_t sqtp = ufs_rreg(ufs, ufs->sqdao[TEST_QID] + 0x4);
+ uint64_t utrd_addr = ufs->sqlba[TEST_QID] + sqtp;
+ uint32_t cqhp;
+ uint64_t cqentry_addr;
+ UfsCqEntry cqentry;
+
+ qtest_memwrite(ufs->dev.bus->qts, utrd_addr, utrd, sizeof(*utrd));
+
+ /* Insert a new entry into the submission queue */
+ sqtp = ufs_rreg(ufs, ufs->sqdao[TEST_QID] + 0x4);
+ sqtp = (sqtp + sizeof(UfsSqEntry)) % (QUEUE_SIZE * sizeof(UfsSqEntry));
+ ufs_wreg(ufs, ufs->sqdao[TEST_QID] + 0x4, sqtp);
+ ufs_wait_for_irq(ufs);
+ g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, CQES));
+ ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, CQES, 1));
+
+ /* Handle the completed command from the completion queue */
+ cqhp = ufs_rreg(ufs, ufs->cqdao[TEST_QID]);
+ cqentry_addr = ufs->cqlba[TEST_QID] + cqhp;
+ qtest_memread(ufs->dev.bus->qts, cqentry_addr, &cqentry, sizeof(cqentry));
+ ufs_wreg(ufs, ufs->cqdao[TEST_QID], cqhp);
+
+ return cqentry.status;
+}
+
+static enum UtpOcsCodes
+ufs_send_transfer_request_sync(QUfs *ufs, uint8_t lun,
+ const UtpTransferReqDesc *utrd)
+{
+ if (ufs->support_mcq) {
+ return __ufs_send_transfer_request_mcq(ufs, lun, utrd);
+ }
+
+ return __ufs_send_transfer_request_doorbell(ufs, lun, utrd);
+}
+
+static enum UtpOcsCodes ufs_send_nop_out(QUfs *ufs, UtpUpiuRsp *rsp_out)
+{
+ int cmd_desc_slot = alloc_cmd_desc_slot(ufs);
uint64_t req_upiu_addr =
- ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
+ ufs->cmd_desc_addr + cmd_desc_slot * UTP_COMMAND_DESCRIPTOR_SIZE;
uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
- qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
/* Build up request upiu */
UtpUpiuReq req_upiu = { 0 };
req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_NOP_OUT;
- req_upiu.header.task_tag = slot;
+ req_upiu.header.task_tag = cmd_desc_slot;
qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
sizeof(req_upiu));
- /* Ring Doorbell */
- ufs_wreg(ufs, A_UTRLDBR, 1);
- ufs_wait_for_irq(ufs);
- g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
- ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
+ /* Build up utp transfer request descriptor */
+ UtpTransferReqDesc utrd =
+ ufs_build_req_utrd(req_upiu_addr, UFS_UTP_NO_DATA_TRANSFER, 0);
+
+ /* Send Transfer Request */
+ enum UtpOcsCodes ret = ufs_send_transfer_request_sync(ufs, 0, &utrd);
- qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
+ release_cmd_desc_slot(ufs, cmd_desc_slot);
+ return ret;
}
-static void ufs_send_query(QUfs *ufs, uint8_t slot, uint8_t query_function,
- uint8_t query_opcode, uint8_t idn, uint8_t index,
- uint8_t selector, uint32_t attr_value,
- UtpTransferReqDesc *utrd_out, UtpUpiuRsp *rsp_out)
+static enum UtpOcsCodes ufs_send_query(QUfs *ufs, uint8_t query_function,
+ uint8_t query_opcode, uint8_t idn,
+ uint8_t index, uint8_t selector,
+ uint32_t attr_value, UtpUpiuRsp *rsp_out)
{
- /* Build up utp transfer request descriptor */
- UtpTransferReqDesc utrd = ufs_build_req_utrd(ufs->cmd_desc_addr, slot,
- UFS_UTP_NO_DATA_TRANSFER, 0);
- uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
+ int cmd_desc_slot = alloc_cmd_desc_slot(ufs);
uint64_t req_upiu_addr =
- ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
+ ufs->cmd_desc_addr + cmd_desc_slot * UTP_COMMAND_DESCRIPTOR_SIZE;
uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
- qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
/* Build up request upiu */
UtpUpiuReq req_upiu = { 0 };
req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_QUERY_REQ;
req_upiu.header.query_func = query_function;
- req_upiu.header.task_tag = slot;
+ req_upiu.header.task_tag = cmd_desc_slot;
/*
* QEMU UFS does not currently support Write descriptor,
* so the value of data_segment_length is always 0.
@@ -145,27 +232,28 @@ static void ufs_send_query(QUfs *ufs, uint8_t slot, uint8_t query_function,
req_upiu.qr.idn = idn;
req_upiu.qr.index = index;
req_upiu.qr.selector = selector;
- req_upiu.qr.value = attr_value;
+ req_upiu.qr.value = cpu_to_be32(attr_value);
req_upiu.qr.length = UFS_QUERY_DESC_MAX_SIZE;
qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
sizeof(req_upiu));
- /* Ring Doorbell */
- ufs_wreg(ufs, A_UTRLDBR, 1);
- ufs_wait_for_irq(ufs);
- g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
- ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
+ /* Build up utp transfer request descriptor */
+ UtpTransferReqDesc utrd =
+ ufs_build_req_utrd(req_upiu_addr, UFS_UTP_NO_DATA_TRANSFER, 0);
+
+ /* Send Transfer Request */
+ enum UtpOcsCodes ret = ufs_send_transfer_request_sync(ufs, 0, &utrd);
- qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
+ release_cmd_desc_slot(ufs, cmd_desc_slot);
+ return ret;
}
-static void ufs_send_scsi_command(QUfs *ufs, uint8_t slot, uint8_t lun,
- const uint8_t *cdb, const uint8_t *data_in,
- size_t data_in_len, uint8_t *data_out,
- size_t data_out_len,
- UtpTransferReqDesc *utrd_out,
- UtpUpiuRsp *rsp_out)
+static enum UtpOcsCodes
+ufs_send_scsi_command(QUfs *ufs, uint8_t lun, const uint8_t *cdb,
+ const uint8_t *data_in, size_t data_in_len,
+ uint8_t *data_out, size_t data_out_len,
+ UtpUpiuRsp *rsp_out)
{
/* Build up PRDT */
@@ -175,8 +263,9 @@ static void ufs_send_scsi_command(QUfs *ufs, uint8_t slot, uint8_t lun,
uint8_t flags;
uint16_t prd_table_length, i;
uint32_t data_direction, data_len;
+ int cmd_desc_slot = alloc_cmd_desc_slot(ufs);
uint64_t req_upiu_addr =
- ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
+ ufs->cmd_desc_addr + cmd_desc_slot * UTP_COMMAND_DESCRIPTOR_SIZE;
uint64_t prdt_addr = req_upiu_addr + UTP_PRDT_UPIU_OFFSET;
g_assert_true(data_in_len < MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
@@ -218,36 +307,33 @@ static void ufs_send_scsi_command(QUfs *ufs, uint8_t slot, uint8_t lun,
qtest_memwrite(ufs->dev.bus->qts, prdt_addr, entries,
prd_table_length * sizeof(UfshcdSgEntry));
- /* Build up utp transfer request descriptor */
- UtpTransferReqDesc utrd = ufs_build_req_utrd(
- ufs->cmd_desc_addr, slot, data_direction, prd_table_length);
- uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
- qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
/* Build up request upiu */
UtpUpiuReq req_upiu = { 0 };
req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_COMMAND;
req_upiu.header.flags = flags;
req_upiu.header.lun = lun;
- req_upiu.header.task_tag = slot;
+ req_upiu.header.task_tag = cmd_desc_slot;
req_upiu.sc.exp_data_transfer_len = cpu_to_be32(data_len);
memcpy(req_upiu.sc.cdb, cdb, UFS_CDB_SIZE);
qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
sizeof(req_upiu));
- /* Ring Doorbell */
- ufs_wreg(ufs, A_UTRLDBR, 1);
- ufs_wait_for_irq(ufs);
- g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
- ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
+ /* Build up utp transfer request descriptor */
+ UtpTransferReqDesc utrd =
+ ufs_build_req_utrd(req_upiu_addr, data_direction, prd_table_length);
+
+ /* Send Transfer Request */
+ enum UtpOcsCodes ret = ufs_send_transfer_request_sync(ufs, lun, &utrd);
- qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
if (data_out_len) {
qtest_memread(ufs->dev.bus->qts, ufs->data_buffer_addr, data_out,
data_out_len);
}
+ release_cmd_desc_slot(ufs, cmd_desc_slot);
+ return ret;
}
/**
@@ -257,10 +343,10 @@ static void ufs_send_scsi_command(QUfs *ufs, uint8_t slot, uint8_t lun,
static void ufs_init(QUfs *ufs, QGuestAllocator *alloc)
{
uint64_t end_time;
- uint32_t nutrs, nutmrs;
+ uint32_t nutrs;
uint32_t hcs, is, ucmdarg2, cap;
uint32_t hce = 0, ie = 0;
- UtpTransferReqDesc utrd;
+ enum UtpOcsCodes ocs;
UtpUpiuRsp rsp_upiu;
ufs->bar = qpci_iomap(&ufs->dev, 0, NULL);
@@ -305,9 +391,12 @@ static void ufs_init(QUfs *ufs, QGuestAllocator *alloc)
hcs = ufs_rreg(ufs, A_HCS);
g_assert_true(FIELD_EX32(hcs, HCS, DP));
g_assert_true(FIELD_EX32(hcs, HCS, UTRLRDY));
- g_assert_true(FIELD_EX32(hcs, HCS, UTMRLRDY));
g_assert_true(FIELD_EX32(hcs, HCS, UCRDY));
+ /* Check MCQ support */
+ cap = ufs_rreg(ufs, A_CAP);
+ ufs->support_mcq = FIELD_EX32(cap, CAP, MCQS);
+
/* Enable all interrupt functions */
ie = FIELD_DP32(ie, IE, UTRCE, 1);
ie = FIELD_DP32(ie, IE, UEE, 1);
@@ -320,45 +409,89 @@ static void ufs_init(QUfs *ufs, QGuestAllocator *alloc)
ie = FIELD_DP32(ie, IE, HCFEE, 1);
ie = FIELD_DP32(ie, IE, SBFEE, 1);
ie = FIELD_DP32(ie, IE, CEFEE, 1);
+ if (ufs->support_mcq) {
+ ie = FIELD_DP32(ie, IE, CQEE, 1);
+ }
ufs_wreg(ufs, A_IE, ie);
ufs_wreg(ufs, A_UTRIACR, 0);
- /* Enable transfer request and task management request */
- cap = ufs_rreg(ufs, A_CAP);
- nutrs = FIELD_EX32(cap, CAP, NUTRS) + 1;
- nutmrs = FIELD_EX32(cap, CAP, NUTMRS) + 1;
+ /* Enable transfer request */
ufs->cmd_desc_addr =
- guest_alloc(alloc, nutrs * UTP_COMMAND_DESCRIPTOR_SIZE);
+ guest_alloc(alloc, UFS_MAX_CMD_DESC * UTP_COMMAND_DESCRIPTOR_SIZE);
ufs->data_buffer_addr =
guest_alloc(alloc, MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
- ufs->utrlba = guest_alloc(alloc, nutrs * sizeof(UtpTransferReqDesc));
- ufs->utmrlba = guest_alloc(alloc, nutmrs * sizeof(UtpTaskReqDesc));
- ufs_wreg(ufs, A_UTRLBA, ufs->utrlba & 0xffffffff);
- ufs_wreg(ufs, A_UTRLBAU, ufs->utrlba >> 32);
- ufs_wreg(ufs, A_UTMRLBA, ufs->utmrlba & 0xffffffff);
- ufs_wreg(ufs, A_UTMRLBAU, ufs->utmrlba >> 32);
- ufs_wreg(ufs, A_UTRLRSR, 1);
- ufs_wreg(ufs, A_UTMRLRSR, 1);
+ if (ufs->support_mcq) {
+ uint32_t mcqcap, qid, qcfgptr, mcq_reg_offset;
+ uint32_t cqattr = 0, sqattr = 0;
+
+ mcqcap = ufs_rreg(ufs, A_MCQCAP);
+ qcfgptr = FIELD_EX32(mcqcap, MCQCAP, QCFGPTR);
+ ufs->maxq = FIELD_EX32(mcqcap, MCQCAP, MAXQ) + 1;
+ for (qid = 0; qid < ufs->maxq; ++qid) {
+ ufs->sqlba[qid] =
+ guest_alloc(alloc, QUEUE_SIZE * sizeof(UtpTransferReqDesc));
+ ufs->cqlba[qid] =
+ guest_alloc(alloc, QUEUE_SIZE * sizeof(UtpTransferReqDesc));
+ mcq_reg_offset = qcfgptr * 0x200 + qid * 0x40;
+
+ ufs_wreg(ufs, mcq_reg_offset + A_SQLBA,
+ ufs->sqlba[qid] & 0xffffffff);
+ ufs_wreg(ufs, mcq_reg_offset + A_SQUBA, ufs->sqlba[qid] >> 32);
+ ufs_wreg(ufs, mcq_reg_offset + A_CQLBA,
+ ufs->cqlba[qid] & 0xffffffff);
+ ufs_wreg(ufs, mcq_reg_offset + A_CQUBA, ufs->cqlba[qid] >> 32);
+
+ /* Enable Completion Queue */
+ cqattr = FIELD_DP32(cqattr, CQATTR, CQEN, 1);
+ cqattr = FIELD_DP32(cqattr, CQATTR, SIZE,
+ QUEUE_SIZE * sizeof(UtpTransferReqDesc) /
+ DWORD_BYTE);
+ ufs_wreg(ufs, mcq_reg_offset + A_CQATTR, cqattr);
+
+ /* Enable Submission Queue */
+ sqattr = FIELD_DP32(sqattr, SQATTR, SQEN, 1);
+ sqattr = FIELD_DP32(sqattr, SQATTR, SIZE,
+ QUEUE_SIZE * sizeof(UtpTransferReqDesc) /
+ DWORD_BYTE);
+ sqattr = FIELD_DP32(sqattr, SQATTR, CQID, qid);
+ ufs_wreg(ufs, mcq_reg_offset + A_SQATTR, sqattr);
+
+ /* Cache head & tail pointer */
+ ufs->sqdao[qid] = ufs_rreg(ufs, mcq_reg_offset + A_SQDAO);
+ ufs->cqdao[qid] = ufs_rreg(ufs, mcq_reg_offset + A_CQDAO);
+ }
+ } else {
+ nutrs = FIELD_EX32(cap, CAP, NUTRS) + 1;
+ ufs->utrlba = guest_alloc(alloc, nutrs * sizeof(UtpTransferReqDesc));
+
+ ufs_wreg(ufs, A_UTRLBA, ufs->utrlba & 0xffffffff);
+ ufs_wreg(ufs, A_UTRLBAU, ufs->utrlba >> 32);
+ ufs_wreg(ufs, A_UTRLRSR, 1);
+ }
/* Send nop out to test transfer request */
- ufs_send_nop_out(ufs, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_nop_out(ufs, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
/* Set fDeviceInit flag via query request */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
- UFS_UPIU_QUERY_OPCODE_SET_FLAG,
- UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_SET_FLAG,
+ UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
/* Wait for device to reset */
end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
do {
qtest_clock_step(ufs->dev.bus->qts, 100);
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_FLAG,
- UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &utrd,
- &rsp_upiu);
+ ocs =
+ ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_FLAG,
+ UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==,
+ UFS_COMMAND_RESULT_SUCCESS);
} while (be32_to_cpu(rsp_upiu.qr.value) != 0 &&
g_get_monotonic_time() < end_time);
g_assert_cmpuint(be32_to_cpu(rsp_upiu.qr.value), ==, 0);
@@ -369,8 +502,15 @@ static void ufs_init(QUfs *ufs, QGuestAllocator *alloc)
static void ufs_exit(QUfs *ufs, QGuestAllocator *alloc)
{
if (ufs->enabled) {
- guest_free(alloc, ufs->utrlba);
- guest_free(alloc, ufs->utmrlba);
+ if (ufs->support_mcq) {
+ for (uint32_t qid = 0; qid < ufs->maxq; ++qid) {
+ guest_free(alloc, ufs->sqlba[qid]);
+ guest_free(alloc, ufs->cqlba[qid]);
+ }
+ } else {
+ guest_free(alloc, ufs->utrlba);
+ }
+
guest_free(alloc, ufs->cmd_desc_addr);
guest_free(alloc, ufs->data_buffer_addr);
}
@@ -433,15 +573,15 @@ static void ufstest_init(void *obj, void *data, QGuestAllocator *alloc)
const uint8_t request_sense_cdb[UFS_CDB_SIZE] = {
REQUEST_SENSE,
};
- UtpTransferReqDesc utrd;
+ enum UtpOcsCodes ocs;
UtpUpiuRsp rsp_upiu;
ufs_init(ufs, alloc);
/* Check REPORT_LUNS */
- ufs_send_scsi_command(ufs, 0, 0, report_luns_cdb, NULL, 0, buf, sizeof(buf),
- &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_scsi_command(ufs, 0, report_luns_cdb, NULL, 0, buf,
+ sizeof(buf), &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD);
/* LUN LIST LENGTH should be 8, in big endian */
g_assert_cmpuint(buf[3], ==, 8);
@@ -449,15 +589,15 @@ static void ufstest_init(void *obj, void *data, QGuestAllocator *alloc)
g_assert_cmpuint(buf[9], ==, 0);
/* Clear Unit Attention */
- ufs_send_scsi_command(ufs, 0, 0, request_sense_cdb, NULL, 0, buf,
- sizeof(buf), &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_scsi_command(ufs, 0, request_sense_cdb, NULL, 0, buf,
+ sizeof(buf), &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, CHECK_CONDITION);
/* Check TEST_UNIT_READY */
- ufs_send_scsi_command(ufs, 0, 0, test_unit_ready_cdb, NULL, 0, NULL, 0,
- &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_scsi_command(ufs, 0, test_unit_ready_cdb, NULL, 0, NULL, 0,
+ &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD);
ufs_exit(ufs, alloc);
@@ -499,22 +639,22 @@ static void ufstest_read_write(void *obj, void *data, QGuestAllocator *alloc)
WRITE_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
};
uint32_t block_size;
- UtpTransferReqDesc utrd;
+ enum UtpOcsCodes ocs;
UtpUpiuRsp rsp_upiu;
const int test_lun = 1;
ufs_init(ufs, alloc);
/* Clear Unit Attention */
- ufs_send_scsi_command(ufs, 0, test_lun, request_sense_cdb, NULL, 0,
- read_buf, sizeof(read_buf), &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_scsi_command(ufs, test_lun, request_sense_cdb, NULL, 0,
+ read_buf, sizeof(read_buf), &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, CHECK_CONDITION);
/* Read capacity */
- ufs_send_scsi_command(ufs, 0, test_lun, read_capacity_cdb, NULL, 0,
- read_buf, sizeof(read_buf), &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_scsi_command(ufs, test_lun, read_capacity_cdb, NULL, 0,
+ read_buf, sizeof(read_buf), &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
UFS_COMMAND_RESULT_SUCCESS);
block_size = ldl_be_p(&read_buf[8]);
@@ -522,16 +662,16 @@ static void ufstest_read_write(void *obj, void *data, QGuestAllocator *alloc)
/* Write data */
memset(write_buf, 0xab, block_size);
- ufs_send_scsi_command(ufs, 0, test_lun, write_cdb, write_buf, block_size,
- NULL, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_scsi_command(ufs, test_lun, write_cdb, write_buf, block_size,
+ NULL, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
UFS_COMMAND_RESULT_SUCCESS);
/* Read data and verify */
- ufs_send_scsi_command(ufs, 0, test_lun, read_cdb, NULL, 0, read_buf,
- block_size, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_scsi_command(ufs, test_lun, read_cdb, NULL, 0, read_buf,
+ block_size, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpint(memcmp(read_buf, write_buf, block_size), ==, 0);
@@ -544,76 +684,74 @@ static void ufstest_query_flag_request(void *obj, void *data,
{
QUfs *ufs = obj;
- UtpTransferReqDesc utrd;
+ enum UtpOcsCodes ocs;
UtpUpiuRsp rsp_upiu;
ufs_init(ufs, alloc);
/* Read read-only flag */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_FLAG,
- UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_FLAG,
+ UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_FLAG);
g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_FLAG_IDN_FDEVICEINIT);
g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0));
/* Flag Set, Clear, Toggle Test with fDeviceLifeSpanModeEn */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_FLAG,
- UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
- &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_FLAG,
+ UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0,
+ &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0));
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
- UFS_UPIU_QUERY_OPCODE_SET_FLAG,
- UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
- &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_SET_FLAG,
+ UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0,
+ &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(1));
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
- UFS_UPIU_QUERY_OPCODE_CLEAR_FLAG,
- UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
- &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_CLEAR_FLAG,
+ UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0,
+ &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0));
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
- UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG,
- UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
- &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG,
+ UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0,
+ &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(1));
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
- UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG,
- UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
- &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG,
+ UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0,
+ &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0));
/* Read Write-only Flag (Intended Failure) */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_FLAG,
- UFS_QUERY_FLAG_IDN_PURGE_ENABLE, 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
- UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_FLAG,
+ UFS_QUERY_FLAG_IDN_PURGE_ENABLE, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
g_assert_cmpuint(rsp_upiu.header.response, ==,
UFS_QUERY_RESULT_NOT_READABLE);
/* Write Read-Only Flag (Intended Failure) */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
- UFS_UPIU_QUERY_OPCODE_SET_FLAG, UFS_QUERY_FLAG_IDN_BUSY_RTC,
- 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
- UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_SET_FLAG,
+ UFS_QUERY_FLAG_IDN_BUSY_RTC, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
g_assert_cmpuint(rsp_upiu.header.response, ==,
UFS_QUERY_RESULT_NOT_WRITEABLE);
@@ -625,130 +763,146 @@ static void ufstest_query_attr_request(void *obj, void *data,
{
QUfs *ufs = obj;
- UtpTransferReqDesc utrd;
+ enum UtpOcsCodes ocs;
UtpUpiuRsp rsp_upiu;
ufs_init(ufs, alloc);
/* Read Readable Attributes*/
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_ATTR,
- UFS_QUERY_ATTR_IDN_BOOT_LU_EN, 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_BOOT_LU_EN, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_ATTR);
g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_ATTR_IDN_BOOT_LU_EN);
g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_ATTR,
- UFS_QUERY_ATTR_IDN_BKOPS_STATUS, 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_BKOPS_STATUS, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_CASE_ROUGH_TEMP, 0, 0, 0,
+ &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
+
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_HIGH_TEMP_BOUND, 0, 0, 0,
+ &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(160));
+
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_LOW_TEMP_BOUND, 0, 0, 0,
+ &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(60));
+
/* Write Writable Attributes & Read Again */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
- UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
- UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x03, &utrd,
- &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
+ UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x03,
+ &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03));
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
- UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
- UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0x07, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
+ UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0x07, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07));
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_ATTR,
- UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd,
- &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03));
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_ATTR,
- UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07));
/* Write Invalid Value (Intended Error) */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
- UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
- UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x10, &utrd,
- &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
- UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
+ UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x10,
+ &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
g_assert_cmpuint(rsp_upiu.header.response, ==,
UFS_QUERY_RESULT_INVALID_VALUE);
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_ATTR,
- UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd,
- &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03));
/* Read Write-Only Attribute (Intended Error) */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_ATTR,
- UFS_QUERY_ATTR_IDN_SECONDS_PASSED, 0, 0, 0, &utrd,
- &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
- UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_SECONDS_PASSED, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
g_assert_cmpuint(rsp_upiu.header.response, ==,
UFS_QUERY_RESULT_NOT_READABLE);
/* Write Read-Only Attribute (Intended Error) */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
- UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
- UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0x01, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
- UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
+ UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0x01, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
g_assert_cmpuint(rsp_upiu.header.response, ==,
UFS_QUERY_RESULT_NOT_WRITEABLE);
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_ATTR,
- UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
/* Reset Written Attributes */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
- UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
- UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd,
- &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
+ UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
- UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
- UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
+ UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_ATTR,
- UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd,
- &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_ATTR,
- UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
@@ -760,17 +914,17 @@ static void ufstest_query_desc_request(void *obj, void *data,
{
QUfs *ufs = obj;
- UtpTransferReqDesc utrd;
+ enum UtpOcsCodes ocs;
UtpUpiuRsp rsp_upiu;
ufs_init(ufs, alloc);
/* Write Descriptor is not supported yet */
/* Read Device Descriptor */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_DEVICE,
- 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_DEVICE, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_DESC);
g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_DESC_IDN_DEVICE);
@@ -780,126 +934,123 @@ static void ufstest_query_desc_request(void *obj, void *data,
/* Read Configuration Descriptor is not supported yet*/
/* Read Unit Descriptor */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 0,
- 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_UNIT, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor));
g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT);
g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 0);
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 1,
- 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_UNIT, 1, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor));
g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT);
g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 1);
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT,
- UFS_UPIU_RPMB_WLUN, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs =
+ ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT,
+ UFS_UPIU_RPMB_WLUN, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(RpmbUnitDescriptor));
g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT);
g_assert_cmpuint(rsp_upiu.qr.data[2], ==, UFS_UPIU_RPMB_WLUN);
/* Read Interconnect Descriptor */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC,
- UFS_QUERY_DESC_IDN_INTERCONNECT, 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_INTERCONNECT, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(InterconnectDescriptor));
g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_INTERCONNECT);
/* Read String Descriptor */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
- 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_STRING, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x12);
g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING);
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
- 1, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_STRING, 1, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x22);
g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING);
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
- 4, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_STRING, 4, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x0a);
g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING);
/* Read Geometry Descriptor */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_GEOMETRY,
- 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_GEOMETRY, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(GeometryDescriptor));
g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_GEOMETRY);
/* Read Power Descriptor */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_POWER, 0,
- 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_POWER, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.data[0], ==,
sizeof(PowerParametersDescriptor));
g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_POWER);
/* Read Health Descriptor */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_HEALTH,
- 0, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_HEALTH, 0, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceHealthDescriptor));
g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_HEALTH);
/* Invalid Index (Intended Failure) */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 4,
- 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
- UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_UNIT, 4, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
g_assert_cmpuint(rsp_upiu.header.response, ==,
UFS_QUERY_RESULT_INVALID_INDEX);
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
- 5, 0, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
- UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_STRING, 5, 0, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
g_assert_cmpuint(rsp_upiu.header.response, ==,
UFS_QUERY_RESULT_INVALID_INDEX);
/* Invalid Selector (Intended Failure) */
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_DEVICE,
- 0, 1, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
- UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_DEVICE, 0, 1, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
g_assert_cmpuint(rsp_upiu.header.response, ==,
UFS_QUERY_RESULT_INVALID_SELECTOR);
- ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
- UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
- 0, 1, 0, &utrd, &rsp_upiu);
- g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
- UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_STRING, 0, 1, 0, &rsp_upiu);
+ g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
g_assert_cmpuint(rsp_upiu.header.response, ==,
UFS_QUERY_RESULT_INVALID_SELECTOR);
@@ -947,12 +1098,16 @@ static void ufs_register_nodes(void)
QOSGraphEdgeOptions edge_opts = {
.before_cmd_line = "-blockdev null-co,node-name=drv0,read-zeroes=on",
.after_cmd_line = "-device ufs-lu,bus=ufs0,drive=drv0,lun=0",
- .extra_device_opts = "addr=04.0,id=ufs0,nutrs=32,nutmrs=8"
+ .extra_device_opts = "addr=04.0,id=ufs0"
};
- QOSGraphTestOptions io_test_opts = {
- .before = ufs_blk_test_setup,
- };
+ QOSGraphTestOptions io_test_opts = { .before = ufs_blk_test_setup,
+ .edge.extra_device_opts =
+ "mcq=false,nutrs=32,nutmrs=8" };
+
+ QOSGraphTestOptions mcq_test_opts = { .before = ufs_blk_test_setup,
+ .edge.extra_device_opts =
+ "mcq=true,mcq-maxq=1" };
add_qpci_address(&edge_opts, &(QPCIAddress){ .devfn = QPCI_DEVFN(4, 0) });
@@ -972,13 +1127,14 @@ static void ufs_register_nodes(void)
return;
}
qos_add_test("init", "ufs", ufstest_init, NULL);
- qos_add_test("read-write", "ufs", ufstest_read_write, &io_test_opts);
- qos_add_test("flag read-write", "ufs",
- ufstest_query_flag_request, &io_test_opts);
- qos_add_test("attr read-write", "ufs",
- ufstest_query_attr_request, &io_test_opts);
- qos_add_test("desc read-write", "ufs",
- ufstest_query_desc_request, &io_test_opts);
+ qos_add_test("legacy-read-write", "ufs", ufstest_read_write, &io_test_opts);
+ qos_add_test("mcq-read-write", "ufs", ufstest_read_write, &mcq_test_opts);
+ qos_add_test("query-flag", "ufs", ufstest_query_flag_request,
+ &io_test_opts);
+ qos_add_test("query-attribute", "ufs", ufstest_query_attr_request,
+ &io_test_opts);
+ qos_add_test("query-desciptor", "ufs", ufstest_query_desc_request,
+ &io_test_opts);
}
libqos_init(ufs_register_nodes);
diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c
index d607500..75cb3e4 100644
--- a/tests/qtest/vhost-user-test.c
+++ b/tests/qtest/vhost-user-test.c
@@ -12,7 +12,7 @@
#include "libqtest-single.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "qemu/range.h"
@@ -20,7 +20,7 @@
#include "chardev/char-fe.h"
#include "qemu/memfd.h"
#include "qemu/module.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "libqos/libqos.h"
#include "libqos/pci-pc.h"
#include "libqos/virtio-pci.h"
@@ -920,7 +920,7 @@ static void wait_for_rings_started(TestServer *s, size_t count)
static inline void test_server_connect(TestServer *server)
{
- test_server_create_chr(server, ",reconnect=1");
+ test_server_create_chr(server, ",reconnect-ms=1000");
}
static gboolean
@@ -1043,7 +1043,8 @@ static void test_multiqueue(void *obj, void *arg, QGuestAllocator *alloc)
static uint64_t vu_net_get_features(TestServer *s)
{
- uint64_t features = 0x1ULL << VHOST_F_LOG_ALL |
+ uint64_t features = 0x1ULL << VIRTIO_F_VERSION_1 |
+ 0x1ULL << VHOST_F_LOG_ALL |
0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
if (s->queues > 1) {
diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 3c8cd23..ac38ccf 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -20,6 +20,7 @@
#define tversion(...) v9fs_tversion((TVersionOpt) __VA_ARGS__)
#define tattach(...) v9fs_tattach((TAttachOpt) __VA_ARGS__)
#define tgetattr(...) v9fs_tgetattr((TGetAttrOpt) __VA_ARGS__)
+#define tsetattr(...) v9fs_tsetattr((TSetAttrOpt) __VA_ARGS__)
#define treaddir(...) v9fs_treaddir((TReadDirOpt) __VA_ARGS__)
#define tlopen(...) v9fs_tlopen((TLOpenOpt) __VA_ARGS__)
#define twrite(...) v9fs_twrite((TWriteOpt) __VA_ARGS__)
@@ -693,6 +694,64 @@ static void fs_unlinkat_hardlink(void *obj, void *data,
g_assert(stat(real_file, &st_real) == 0);
}
+static void fs_use_after_unlink(void *obj, void *data,
+ QGuestAllocator *t_alloc)
+{
+ QVirtio9P *v9p = obj;
+ v9fs_set_allocator(t_alloc);
+ static const uint32_t write_count = P9_MAX_SIZE / 2;
+ g_autofree char *real_file = virtio_9p_test_path("09/doa_file");
+ g_autofree char *buf = g_malloc0(write_count);
+ struct stat st_file;
+ struct v9fs_attr attr;
+ uint32_t fid_file;
+ uint32_t count;
+
+ tattach({ .client = v9p });
+
+ /* create a file "09/doa_file" and make sure it exists and is regular */
+ tmkdir({ .client = v9p, .atPath = "/", .name = "09" });
+ tlcreate({ .client = v9p, .atPath = "09", .name = "doa_file" });
+ g_assert(stat(real_file, &st_file) == 0);
+ g_assert((st_file.st_mode & S_IFMT) == S_IFREG);
+
+ /* request a FID for that regular file that we can work with next */
+ fid_file = twalk({
+ .client = v9p, .fid = 0, .path = "09/doa_file"
+ }).newfid;
+ g_assert(fid_file != 0);
+
+ /* now first open the file in write mode before ... */
+ tlopen({ .client = v9p, .fid = fid_file, .flags = O_WRONLY });
+ /* ... removing the file from file system */
+ tunlinkat({ .client = v9p, .atPath = "09", .name = "doa_file" });
+
+ /* file is removed, but we still have it open, so this should succeed */
+ tgetattr({
+ .client = v9p, .fid = fid_file, .request_mask = P9_GETATTR_BASIC,
+ .rgetattr.attr = &attr
+ });
+ count = twrite({
+ .client = v9p, .fid = fid_file, .offset = 0, .count = write_count,
+ .data = buf
+ }).count;
+ g_assert_cmpint(count, ==, write_count);
+
+ /* truncate file to (arbitrarily chosen) size 2001 */
+ tsetattr({
+ .client = v9p, .fid = fid_file, .attr = (v9fs_attr) {
+ .valid = P9_SETATTR_SIZE,
+ .size = 2001
+ }
+ });
+ /* truncate apparently succeeded, let's double-check the size */
+ tgetattr({
+ .client = v9p, .fid = fid_file, .request_mask = P9_GETATTR_BASIC,
+ .rgetattr.attr = &attr
+ });
+ g_assert_cmpint(attr.size, ==, 2001);
+}
+
static void cleanup_9p_local_driver(void *data)
{
/* remove previously created test dir when test is completed */
@@ -758,6 +817,8 @@ static void register_virtio_9p_test(void)
qos_add_test("local/hardlink_file", "virtio-9p", fs_hardlink_file, &opts);
qos_add_test("local/unlinkat_hardlink", "virtio-9p", fs_unlinkat_hardlink,
&opts);
+ qos_add_test("local/use_after_unlink", "virtio-9p", fs_use_after_unlink,
+ &opts);
}
libqos_init(register_virtio_9p_test);
diff --git a/tests/qtest/virtio-balloon-test.c b/tests/qtest/virtio-balloon-test.c
new file mode 100644
index 0000000..ecdd363
--- /dev/null
+++ b/tests/qtest/virtio-balloon-test.c
@@ -0,0 +1,57 @@
+/*
+ * QTest test cases for virtio balloon device
+ *
+ * Copyright (c) 2024 Gao Shiyuan <gaoshiyuan@baidu.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "standard-headers/linux/virtio_balloon.h"
+
+/*
+ * https://gitlab.com/qemu-project/qemu/-/issues/2576
+ * Used to trigger:
+ * virtio_address_space_lookup: Assertion `mrs.mr' failed.
+ */
+static void oss_fuzz_71649(void)
+{
+ QTestState *s = qtest_init("-device virtio-balloon -machine q35"
+ " -nodefaults");
+
+ qtest_outl(s, 0xcf8, 0x80000890);
+ qtest_outl(s, 0xcfc, 0x2);
+ qtest_outl(s, 0xcf8, 0x80000891);
+ qtest_inl(s, 0xcfc);
+ qtest_quit(s);
+}
+
+static void query_stats(void)
+{
+ QTestState *s = qtest_init("-device virtio-balloon,id=balloon"
+ " -nodefaults");
+ QDict *ret = qtest_qmp_assert_success_ref(
+ s,
+ "{ 'execute': 'qom-get', 'arguments': " \
+ "{ 'path': '/machine/peripheral/balloon', " \
+ " 'property': 'guest-stats' } }");
+ QDict *stats = qdict_get_qdict(ret, "stats");
+
+ /* We expect 1 entry in the dict for each known kernel stat */
+ assert(qdict_size(stats) == VIRTIO_BALLOON_S_NR);
+
+ qobject_unref(ret);
+ qtest_quit(s);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("virtio-balloon/oss_fuzz_71649", oss_fuzz_71649);
+ qtest_add_func("virtio-balloon/query-stats", query_stats);
+
+ return g_test_run();
+}
+
diff --git a/tests/qtest/virtio-iommu-test.c b/tests/qtest/virtio-iommu-test.c
index afb2259..98ffa27 100644
--- a/tests/qtest/virtio-iommu-test.c
+++ b/tests/qtest/virtio-iommu-test.c
@@ -105,7 +105,7 @@ static int send_map(QTestState *qts, QVirtioIOMMU *v_iommu,
QVirtQueue *vq = v_iommu->vq;
uint64_t ro_addr, wr_addr;
uint32_t free_head;
- struct virtio_iommu_req_map req;
+ struct virtio_iommu_req_map req = {};
size_t ro_size = sizeof(req) - sizeof(struct virtio_iommu_req_tail);
size_t wr_size = sizeof(struct virtio_iommu_req_tail);
struct virtio_iommu_req_tail buffer;
@@ -147,7 +147,7 @@ static int send_unmap(QTestState *qts, QVirtioIOMMU *v_iommu,
QVirtQueue *vq = v_iommu->vq;
uint64_t ro_addr, wr_addr;
uint32_t free_head;
- struct virtio_iommu_req_unmap req;
+ struct virtio_iommu_req_unmap req = {};
size_t ro_size = sizeof(req) - sizeof(struct virtio_iommu_req_tail);
size_t wr_size = sizeof(struct virtio_iommu_req_tail);
struct virtio_iommu_req_tail buffer;
diff --git a/tests/qtest/virtio-net-failover.c b/tests/qtest/virtio-net-failover.c
index 73dfabc..5baf81c 100644
--- a/tests/qtest/virtio-net-failover.c
+++ b/tests/qtest/virtio-net-failover.c
@@ -11,10 +11,11 @@
#include "libqtest.h"
#include "libqos/pci.h"
#include "libqos/pci-pc.h"
-#include "migration-helpers.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qjson.h"
+#include "migration/migration-qmp.h"
+#include "migration/migration-util.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
+#include "qobject/qjson.h"
#include "libqos/malloc-pc.h"
#include "libqos/virtio-pci.h"
#include "hw/pci/pci.h"
@@ -772,7 +773,7 @@ static void test_migrate_in(gconstpointer opaque)
check_one_card(qts, true, "standby0", MAC_STANDBY0);
check_one_card(qts, false, "primary0", MAC_PRIMARY0);
- migrate_incoming_qmp(qts, uri, "{}");
+ migrate_incoming_qmp(qts, uri, NULL, "{}");
resp = get_failover_negociated_event(qts);
g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
@@ -894,7 +895,7 @@ static void test_off_migrate_in(gconstpointer opaque)
check_one_card(qts, true, "standby0", MAC_STANDBY0);
check_one_card(qts, true, "primary0", MAC_PRIMARY0);
- migrate_incoming_qmp(qts, uri, "{}");
+ migrate_incoming_qmp(qts, uri, NULL, "{}");
check_one_card(qts, true, "standby0", MAC_STANDBY0);
check_one_card(qts, true, "primary0", MAC_PRIMARY0);
@@ -1021,7 +1022,7 @@ static void test_guest_off_migrate_in(gconstpointer opaque)
check_one_card(qts, true, "standby0", MAC_STANDBY0);
check_one_card(qts, false, "primary0", MAC_PRIMARY0);
- migrate_incoming_qmp(qts, uri, "{}");
+ migrate_incoming_qmp(qts, uri, NULL, "{}");
check_one_card(qts, true, "standby0", MAC_STANDBY0);
check_one_card(qts, false, "primary0", MAC_PRIMARY0);
@@ -1746,7 +1747,7 @@ static void test_multi_in(gconstpointer opaque)
check_one_card(qts, true, "standby1", MAC_STANDBY1);
check_one_card(qts, false, "primary1", MAC_PRIMARY1);
- migrate_incoming_qmp(qts, uri, "{}");
+ migrate_incoming_qmp(qts, uri, NULL, "{}");
resp = get_failover_negociated_event(qts);
g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
diff --git a/tests/qtest/virtio-net-test.c b/tests/qtest/virtio-net-test.c
index 2df75c9..60e5229 100644
--- a/tests/qtest/virtio-net-test.c
+++ b/tests/qtest/virtio-net-test.c
@@ -11,7 +11,7 @@
#include "libqtest-single.h"
#include "qemu/iov.h"
#include "qemu/module.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "hw/virtio/virtio-net.h"
#include "libqos/qgraph.h"
#include "libqos/virtio-net.h"
diff --git a/tests/qtest/vmcoreinfo-test.c b/tests/qtest/vmcoreinfo-test.c
new file mode 100644
index 0000000..dcf3b5a
--- /dev/null
+++ b/tests/qtest/vmcoreinfo-test.c
@@ -0,0 +1,90 @@
+/*
+ * qtest vmcoreinfo test case
+ *
+ * Copyright Red Hat. 2025.
+ *
+ * Authors:
+ * Ani Sinha <anisinha@redhat.com>
+ *
+ * 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/units.h"
+#include "libqos/libqos-pc.h"
+#include "libqtest.h"
+#include "standard-headers/linux/qemu_fw_cfg.h"
+#include "libqos/fw_cfg.h"
+#include "qemu/bswap.h"
+#include "hw/misc/vmcoreinfo.h"
+
+static void test_vmcoreinfo_write_basic(void)
+{
+ QFWCFG *fw_cfg;
+ QOSState *qs;
+ FWCfgVMCoreInfo info;
+ size_t filesize;
+ uint16_t guest_format;
+ uint16_t host_format;
+ uint32_t size;
+ uint64_t paddr;
+
+ qs = qtest_pc_boot("-device vmcoreinfo");
+ fw_cfg = pc_fw_cfg_init(qs->qts);
+
+ memset(&info, 0 , sizeof(info));
+ /* read vmcoreinfo and read back the host format */
+ filesize = qfw_cfg_read_file(fw_cfg, qs, FW_CFG_VMCOREINFO_FILENAME,
+ &info, sizeof(info));
+ g_assert_cmpint(filesize, ==, sizeof(info));
+
+ host_format = le16_to_cpu(info.host_format);
+ g_assert_cmpint(host_format, ==, FW_CFG_VMCOREINFO_FORMAT_ELF);
+
+ memset(&info, 0 , sizeof(info));
+ info.guest_format = cpu_to_le16(FW_CFG_VMCOREINFO_FORMAT_ELF);
+ info.size = cpu_to_le32(1 * MiB);
+ info.paddr = cpu_to_le64(0xffffff00);
+ info.host_format = cpu_to_le16(host_format);
+
+ /* write the values to the host */
+ filesize = qfw_cfg_write_file(fw_cfg, qs, FW_CFG_VMCOREINFO_FILENAME,
+ &info, sizeof(info));
+ g_assert_cmpint(filesize, ==, sizeof(info));
+
+ memset(&info, 0 , sizeof(info));
+
+ /* now read back the values we wrote and compare that they are the same */
+ filesize = qfw_cfg_read_file(fw_cfg, qs, FW_CFG_VMCOREINFO_FILENAME,
+ &info, sizeof(info));
+ g_assert_cmpint(filesize, ==, sizeof(info));
+
+ size = le32_to_cpu(info.size);
+ paddr = le64_to_cpu(info.paddr);
+ guest_format = le16_to_cpu(info.guest_format);
+
+ g_assert_cmpint(size, ==, 1 * MiB);
+ g_assert_cmpint(paddr, ==, 0xffffff00);
+ g_assert_cmpint(guest_format, ==, FW_CFG_VMCOREINFO_FORMAT_ELF);
+
+ pc_fw_cfg_uninit(fw_cfg);
+ qtest_shutdown(qs);
+}
+
+int main(int argc, char **argv)
+{
+ const char *arch = qtest_get_arch();
+
+ g_test_init(&argc, &argv, NULL);
+
+ if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) {
+ /* skip for non-x86 */
+ exit(EXIT_SUCCESS);
+ }
+
+ qtest_add_func("vmcoreinfo/basic-write",
+ test_vmcoreinfo_write_basic);
+
+ return g_test_run();
+}
diff --git a/tests/qtest/vmgenid-test.c b/tests/qtest/vmgenid-test.c
index 29fee9e..33e96b7 100644
--- a/tests/qtest/vmgenid-test.c
+++ b/tests/qtest/vmgenid-test.c
@@ -15,7 +15,7 @@
#include "boot-sector.h"
#include "acpi-utils.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#define VGID_GUID "324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87"
#define VMGENID_GUID_OFFSET 40 /* allow space for
@@ -61,7 +61,7 @@ static uint32_t acpi_find_vgia(QTestState *qts)
/* 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
+ * see docs/specs/vmgenid.rst for more details
*/
guid_offset = le32_to_cpu(vgia_val) + VMGENID_GUID_OFFSET;
g_free(table_aml);
diff --git a/tests/qtest/wdt_ib700-test.c b/tests/qtest/wdt_ib700-test.c
index 797288d..1754757 100644
--- a/tests/qtest/wdt_ib700-test.c
+++ b/tests/qtest/wdt_ib700-test.c
@@ -9,7 +9,7 @@
#include "qemu/osdep.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qemu/timer.h"
static void qmp_check_no_event(QTestState *s)
diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target
index 452a2cd..af68f11 100644
--- a/tests/tcg/Makefile.target
+++ b/tests/tcg/Makefile.target
@@ -90,6 +90,7 @@ CFLAGS=
LDFLAGS=
QEMU_OPTS=
+CHECK_PLUGIN_OUTPUT_COMMAND=
# If TCG debugging, or TCI is enabled things are a lot slower
@@ -102,9 +103,14 @@ ifeq ($(filter %-softmmu, $(TARGET)),)
# then the target. If there are common tests shared between
# sub-targets (e.g. ARM & AArch64) then it is up to
# $(TARGET_NAME)/Makefile.target to include the common parent
-# architecture in its VPATH.
+# architecture in its VPATH. However some targets are so minimal we
+# can't even build the multiarch tests.
+ifneq ($(filter $(TARGET_NAME),aarch64_be),)
+-include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.target
+else
-include $(SRC_PATH)/tests/tcg/multiarch/Makefile.target
-include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.target
+endif
# Add the common build options
CFLAGS+=-Wall -Werror -O0 -g -fno-strict-aliasing
@@ -145,17 +151,23 @@ ifeq ($(CONFIG_PLUGIN),y)
PLUGIN_SRC=$(SRC_PATH)/tests/tcg/plugins
PLUGIN_LIB=../plugins
VPATH+=$(PLUGIN_LIB)
-PLUGINS=$(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c)))
+# Some plugins need to be disabled for all tests to avoid exponential explosion.
+# For example, libpatch.so only needs to run against the arch-specific patch
+# target test, so we explicitly run it in the arch-specific Makefile.
+DISABLE_PLUGINS=libpatch.so
+PLUGINS=$(filter-out $(DISABLE_PLUGINS), \
+ $(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c))))
# We need to ensure expand the run-plugin-TEST-with-PLUGIN
# pre-requistes manually here as we can't use stems to handle it. We
# only expand MULTIARCH_TESTS which are common on most of our targets
# to avoid an exponential explosion as new tests are added. We also
# add some special helpers the run-plugin- rules can use below.
+# In more, extra tests can be added using ADDITIONAL_PLUGINS_TESTS variable.
ifneq ($(MULTIARCH_TESTS),)
$(foreach p,$(PLUGINS), \
- $(foreach t,$(MULTIARCH_TESTS),\
+ $(foreach t,$(MULTIARCH_TESTS) $(ADDITIONAL_PLUGINS_TESTS),\
$(eval run-plugin-$(t)-with-$(p): $t $p) \
$(eval RUN_TESTS+=run-plugin-$(t)-with-$(p))))
endif # MULTIARCH_TESTS
@@ -172,13 +184,17 @@ run-plugin-%-with-libmem.so: PLUGIN_ARGS=$(COMMA)inline=true
ifeq ($(filter %-softmmu, $(TARGET)),)
run-%: %
- $(call run-test, $<, $(QEMU) $(QEMU_OPTS) $<)
+ $(call run-test, $<, env QEMU=$(QEMU) $(QEMU) $(QEMU_OPTS) $<)
run-plugin-%:
- $(call run-test, $@, $(QEMU) $(QEMU_OPTS) \
+ $(call run-test, $@, env QEMU=$(QEMU) $(QEMU) $(QEMU_OPTS) \
-plugin $(PLUGIN_LIB)/$(call extract-plugin,$@)$(PLUGIN_ARGS) \
-d plugin -D $*.pout \
$(call strip-plugin,$<))
+ $(if $(CHECK_PLUGIN_OUTPUT_COMMAND), \
+ $(call quiet-command, $(CHECK_PLUGIN_OUTPUT_COMMAND) $*.pout, \
+ TEST, check plugin $(call extract-plugin,$@) output \
+ with $(call strip-plugin,$<)))
else
run-%: %
$(call run-test, $<, \
@@ -193,6 +209,10 @@ run-plugin-%:
-plugin $(PLUGIN_LIB)/$(call extract-plugin,$@)$(PLUGIN_ARGS) \
-d plugin -D $*.pout \
$(QEMU_OPTS) $(call strip-plugin,$<))
+ $(if $(CHECK_PLUGIN_OUTPUT_COMMAND), \
+ $(call quiet-command, $(CHECK_PLUGIN_OUTPUT_COMMAND) $*.pout, \
+ TEST, check plugin $(call extract-plugin,$@) output \
+ with $(call strip-plugin,$<)))
endif
gdb-%: %
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
index 139e04d..f7a7d2b 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -2,14 +2,22 @@
# Aarch64 system tests
#
-AARCH64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/aarch64/system
+AARCH64_SRC=$(SRC_PATH)/tests/tcg/aarch64
+AARCH64_SYSTEM_SRC=$(AARCH64_SRC)/system
+
VPATH+=$(AARCH64_SYSTEM_SRC)
# These objects provide the basic boot code and helper functions for all tests
CRT_OBJS=boot.o
-AARCH64_TEST_SRCS=$(wildcard $(AARCH64_SYSTEM_SRC)/*.c)
-AARCH64_TESTS = $(patsubst $(AARCH64_SYSTEM_SRC)/%.c, %, $(AARCH64_TEST_SRCS))
+AARCH64_TEST_C_SRCS=$(wildcard $(AARCH64_SYSTEM_SRC)/*.c)
+AARCH64_TEST_S_SRCS=$(AARCH64_SYSTEM_SRC)/mte.S
+
+AARCH64_C_TESTS = $(patsubst $(AARCH64_SYSTEM_SRC)/%.c, %, $(AARCH64_TEST_C_SRCS))
+AARCH64_S_TESTS = $(patsubst $(AARCH64_SYSTEM_SRC)/%.S, %, $(AARCH64_TEST_S_SRCS))
+
+AARCH64_TESTS = $(AARCH64_C_TESTS)
+AARCH64_TESTS += $(AARCH64_S_TESTS)
CRT_PATH=$(AARCH64_SYSTEM_SRC)
LINK_SCRIPT=$(AARCH64_SYSTEM_SRC)/kernel.ld
@@ -21,7 +29,8 @@ LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
config-cc.mak: Makefile
$(quiet-@)( \
- $(call cc-option,-march=armv8.3-a, CROSS_CC_HAS_ARMV8_3)) 3> config-cc.mak
+ $(call cc-option,-march=armv8.3-a, CROSS_CC_HAS_ARMV8_3); \
+ $(call cc-option,-march=armv8.5-a+memtag, CROSS_CC_HAS_ARMV8_MTE)) 3> config-cc.mak
-include config-cc.mak
# building head blobs
@@ -59,7 +68,8 @@ run-plugin-semiconsole-with-%: semiconsole
# vtimer test needs EL2
QEMU_EL2_MACHINE=-machine virt,virtualization=on,gic-version=2 -cpu cortex-a57 -smp 4
-run-vtimer: QEMU_OPTS=$(QEMU_EL2_MACHINE) $(QEMU_BASE_ARGS) -kernel
+QEMU_EL2_BASE_ARGS=-semihosting-config enable=on,target=native,chardev=output,arg="2"
+run-vtimer: QEMU_OPTS=$(QEMU_EL2_MACHINE) $(QEMU_EL2_BASE_ARGS) -kernel
# Simple Record/Replay Test
.PHONY: memory-record
@@ -82,9 +92,44 @@ EXTRA_RUNS+=run-memory-replay
ifneq ($(CROSS_CC_HAS_ARMV8_3),)
pauth-3: CFLAGS += $(CROSS_CC_HAS_ARMV8_3)
+# This test explicitly checks the output of the pauth operation so we
+# must force the use of the QARMA5 algorithm for it.
+run-pauth-3: QEMU_BASE_MACHINE=-M virt -cpu max,pauth-qarma5=on -display none
else
pauth-3:
$(call skip-test, "BUILD of $@", "missing compiler support")
run-pauth-3:
$(call skip-test, "RUN of pauth-3", "not built")
endif
+
+ifneq ($(CROSS_CC_HAS_ARMV8_MTE),)
+QEMU_MTE_ENABLED_MACHINE=-M virt,mte=on -cpu max -display none
+QEMU_OPTS_WITH_MTE_ON = $(QEMU_MTE_ENABLED_MACHINE) $(QEMU_BASE_ARGS) -kernel
+mte: CFLAGS+=-march=armv8.5-a+memtag
+mte: mte.S $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
+
+run-mte: QEMU_OPTS=$(QEMU_OPTS_WITH_MTE_ON)
+run-mte: mte
+
+ifeq ($(GDB_SUPPORTS_MTE_IN_BAREMETAL),y)
+run-gdbstub-mte: QEMU_OPTS=$(QEMU_OPTS_WITH_MTE_ON)
+run-gdbstub-mte: mte
+ $(call run-test, $@, $(GDB_SCRIPT) \
+ --output run-gdbstub-mte.out \
+ --gdb $(GDB) \
+ --qemu $(QEMU) --qargs "-chardev null$(COMMA)id=output $(QEMU_OPTS)" \
+ --bin $< --test $(AARCH64_SRC)/gdbstub/test-mte.py -- --mode=system, \
+ gdbstub MTE support)
+
+EXTRA_RUNS += run-gdbstub-mte
+else # !GDB_SUPPORTS_MTE_IN_BAREMETAL
+run-gdbstub-mte:
+ $(call skip-test "RUN of gdbstub-mte", "GDB does not support MTE in baremetal!")
+endif
+else # !CROSS_CC_HAS_ARMV8_MTE
+mte:
+ $(call skip-test, "BUILD of $@", "missing compiler support")
+run-mte:
+ $(call skip-test, "RUN of mte", "not build")
+endif
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
index 8cc62eb..16ddcf4 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -83,7 +83,8 @@ test-aes: CFLAGS += -O -march=armv8-a+aes
test-aes: test-aes-main.c.inc
# Vector SHA1
-sha1-vector: CFLAGS=-O3
+# Work around compiler false-positive warning, as we do for the 'sha1' test
+sha1-vector: CFLAGS=-O3 -Wno-stringop-overread
sha1-vector: sha1.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
run-sha1-vector: sha1-vector run-sha1
@@ -138,7 +139,8 @@ run-gdbstub-mte: mte-8
$(call run-test, $@, $(GDB_SCRIPT) \
--gdb $(GDB) \
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
- --bin $< --test $(AARCH64_SRC)/gdbstub/test-mte.py, \
+ --bin $< --test $(AARCH64_SRC)/gdbstub/test-mte.py \
+ -- --mode=user, \
gdbstub MTE support)
EXTRA_RUNS += run-gdbstub-mte
diff --git a/tests/tcg/aarch64/gdbstub/test-mte.py b/tests/tcg/aarch64/gdbstub/test-mte.py
index 66f9c25..9ad98e7 100644
--- a/tests/tcg/aarch64/gdbstub/test-mte.py
+++ b/tests/tcg/aarch64/gdbstub/test-mte.py
@@ -1,34 +1,59 @@
from __future__ import print_function
#
# Test GDB memory-tag commands that exercise the stubs for the qIsAddressTagged,
-# qMemTag, and QMemTag packets. Logical tag-only commands rely on local
-# operations, hence don't exercise any stub.
+# qMemTag, and QMemTag packets, which are used for manipulating allocation tags.
+# Logical tags-related commands rely on local operations, hence don't exercise
+# any stub and so are not used in this test.
#
-# The test consists in breaking just after a atag() call (which sets the
-# allocation tag -- see mte-8.c for details) and setting/getting tags in
-# different memory locations and ranges starting at the address of the array
-# 'a'.
+# The test consists in breaking just after a tag is set in a specific memory
+# chunk, and then using the GDB 'memory-tagging' subcommands to set/get tags in
+# different memory locations and ranges in the MTE-enabled memory chunk.
#
# This is launched via tests/guest-debug/run-test.py
#
-import gdb
+try:
+ import gdb
+except ModuleNotFoundError:
+ from sys import exit
+ exit("This script must be launched via tests/guest-debug/run-test.py!")
import re
-from test_gdbstub import main, report
+from sys import argv
+from test_gdbstub import arg_parser, main, report
-PATTERN_0 = "Memory tags for address 0x[0-9a-f]+ match \\(0x[0-9a-f]+\\)."
-PATTERN_1 = ".*(0x[0-9a-f]+)"
+PATTERN_0 = r"Memory tags for address 0x[0-9a-f]+ match \(0x[0-9a-f]+\)."
+PATTERN_1 = r".*(0x[0-9a-f]+)"
def run_test():
- gdb.execute("break 95", False, True)
+ p = arg_parser(prog="test-mte.py", description="TCG MTE tests.")
+ p.add_argument("--mode", help="Run test for QEMU system or user mode.",
+ required=True, choices=['system','user'])
+
+ args = p.parse_args(args=argv)
+
+ if args.mode == "system":
+ # Break address: where to break before performing the tests
+ # See mte.S for details about this label.
+ ba = "main_end"
+ # Tagged address: the start of the MTE-enabled memory chunk to be tested
+ # 'tagged_addr' (x1) is a pointer to the MTE-enabled page. See mte.S.
+ ta = "$x1"
+ else: # mode="user"
+ # Line 95 in mte-8.c
+ ba = "95"
+ # 'a' array. See mte-8.c
+ ta = "a"
+
+ gdb.execute(f"break {ba}", False, True)
gdb.execute("continue", False, True)
+
try:
- # Test if we can check correctly that the allocation tag for
- # array 'a' matches the logical tag after atag() is called.
- co = gdb.execute("memory-tag check a", False, True)
+ # Test if we can check correctly that the allocation tag for the address
+ # in {ta} matches the logical tag in {ta}.
+ co = gdb.execute(f"memory-tag check {ta}", False, True)
tags_match = re.findall(PATTERN_0, co, re.MULTILINE)
if tags_match:
report(True, f"{tags_match[0]}")
@@ -39,20 +64,20 @@ def run_test():
# tags rely on local operation and so don't exercise any stub.
# Set the allocation tag for the first granule (16 bytes) of
- # address starting at 'a' address to a known value, i.e. 0x04.
- gdb.execute("memory-tag set-allocation-tag a 1 04", False, True)
+ # address starting at {ta} address to a known value, i.e. 0x04.
+ gdb.execute(f"memory-tag set-allocation-tag {ta} 1 04", False, True)
# Then set the allocation tag for the second granule to a known
# value, i.e. 0x06. This tests that contiguous tag granules are
- # set correct and don't run over each other.
- gdb.execute("memory-tag set-allocation-tag a+16 1 06", False, True)
+ # set correctly and don't run over each other.
+ gdb.execute(f"memory-tag set-allocation-tag {ta}+16 1 06", False, True)
# Read the known values back and check if they remain the same.
- co = gdb.execute("memory-tag print-allocation-tag a", False, True)
+ co = gdb.execute(f"memory-tag print-allocation-tag {ta}", False, True)
first_tag = re.match(PATTERN_1, co)[1]
- co = gdb.execute("memory-tag print-allocation-tag a+16", False, True)
+ co = gdb.execute(f"memory-tag print-allocation-tag {ta}+16", False, True)
second_tag = re.match(PATTERN_1, co)[1]
if first_tag == "0x4" and second_tag == "0x6":
@@ -61,15 +86,15 @@ def run_test():
report(False, "Can't set/print allocation tags!")
# Now test fill pattern by setting a whole page with a pattern.
- gdb.execute("memory-tag set-allocation-tag a 4096 0a0b", False, True)
+ gdb.execute(f"memory-tag set-allocation-tag {ta} 4096 0a0b", False, True)
# And read back the tags of the last two granules in page so
# we also test if the pattern is set correctly up to the end of
# the page.
- co = gdb.execute("memory-tag print-allocation-tag a+4096-32", False, True)
+ co = gdb.execute(f"memory-tag print-allocation-tag {ta}+4096-32", False, True)
tag = re.match(PATTERN_1, co)[1]
- co = gdb.execute("memory-tag print-allocation-tag a+4096-16", False, True)
+ co = gdb.execute(f"memory-tag print-allocation-tag {ta}+4096-16", False, True)
last_tag = re.match(PATTERN_1, co)[1]
if tag == "0xa" and last_tag == "0xb":
@@ -78,8 +103,8 @@ def run_test():
report(False, "Fill pattern failed!")
except gdb.error:
- # This usually happens because a GDB version that does not
- # support memory tagging was used to run the test.
+ # This usually happens because a GDB version that does not support
+ # memory tagging was used to run the test.
report(False, "'memory-tag' command failed!")
diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S
index 501685d..8bfa4e4 100644
--- a/tests/tcg/aarch64/system/boot.S
+++ b/tests/tcg/aarch64/system/boot.S
@@ -16,6 +16,7 @@
#define semihosting_call hlt 0xf000
#define SYS_WRITEC 0x03 /* character to debug channel */
#define SYS_WRITE0 0x04 /* string to debug channel */
+#define SYS_GET_CMDLINE 0x15 /* get command line */
#define SYS_EXIT 0x18
.align 12
@@ -70,22 +71,172 @@ lower_a32_sync:
lower_a32_irq:
lower_a32_fiq:
lower_a32_serror:
+ adr x1, .unexp_excp
+exit_msg:
mov x0, SYS_WRITE0
- adr x1, .error
- semihosting_call
- mov x0, SYS_EXIT
- mov x1, 1
semihosting_call
+ mov x0, 1 /* EXIT_FAILURE */
+ bl _exit
/* never returns */
.section .rodata
-.error:
- .string "Terminated by exception.\n"
+.unexp_excp:
+ .string "Unexpected exception.\n"
+.high_el_msg:
+ .string "Started in lower EL than requested.\n"
+.unexp_el0:
+ .string "Started in invalid EL.\n"
+
+ .align 8
+.get_cmd:
+ .quad cmdline
+ .quad 128
.text
.align 4
.global __start
__start:
+ /*
+ * Initialise the stack for whatever EL we are in before
+ * anything else, we need it to be able to _exit cleanly.
+ * It's smaller than the stack we pass to the C code but we
+ * don't need much.
+ */
+ adrp x0, system_stack_end
+ add x0, x0, :lo12:system_stack_end
+ mov sp, x0
+
+ /*
+ * The test can set the semihosting command line to the target
+ * EL needed for the test. However if no semihosting args are set we will
+ * end up with -kernel/-append data (see semihosting_arg_fallback).
+ * Keep the normalised target in w11.
+ */
+ mov x0, SYS_GET_CMDLINE
+ adr x1, .get_cmd
+ semihosting_call
+ adrp x10, cmdline
+ add x10, x10, :lo12:cmdline
+ ldrb w11, [x10]
+
+ /* sanity check, normalise char to EL, clamp to 1 if outside range */
+ subs w11, w11, #'0'
+ b.lt el_default
+ cmp w11, #3
+ b.gt el_default
+ b 1f
+
+el_high:
+ adr x1, .high_el_msg
+ b exit_msg
+
+el_default:
+ mov w11, #1
+
+1:
+ /* Determine current Exception Level */
+ mrs x0, CurrentEL
+ lsr x0, x0, #2 /* CurrentEL[3:2] contains the current EL */
+
+ /* Are we already in a lower EL than we want? */
+ cmp w11, w0
+ bgt el_high
+
+ /* Branch based on current EL */
+ cmp x0, #3
+ b.eq setup_el3
+ cmp x0, #2
+ b.eq setup_el2
+ cmp x0, #1
+ b.eq at_testel /* Already at EL1, skip transition */
+
+ /* Should not be at EL0 - error out */
+ adr x1, .unexp_el0
+ b exit_msg
+
+setup_el3:
+ /* Ensure we trap if we get anything wrong */
+ adr x0, vector_table
+ msr vbar_el3, x0
+
+ /* Does the test want to be at EL3? */
+ cmp w11, #3
+ beq at_testel
+
+ /* Configure EL3 to for lower states (EL2 or EL1) */
+ mrs x0, scr_el3
+ orr x0, x0, #(1 << 10) /* RW = 1: EL2/EL1 execution state is AArch64 */
+ orr x0, x0, #(1 << 0) /* NS = 1: Non-secure state */
+ msr scr_el3, x0
+
+ /*
+ * We need to check if EL2 is actually enabled via ID_AA64PFR0_EL1,
+ * otherwise we should just jump straight to EL1.
+ */
+ mrs x0, id_aa64pfr0_el1
+ ubfx x0, x0, #8, #4 /* Extract EL2 field (bits 11:8) */
+ cbz x0, el2_not_present /* If field is 0 no EL2 */
+
+
+ /* Prepare SPSR for exception return to EL2 */
+ mov x0, #0x3c9 /* DAIF bits and EL2h mode (9) */
+ msr spsr_el3, x0
+
+ /* Set EL2 entry point */
+ adr x0, setup_el2
+ msr elr_el3, x0
+
+ /* Return to EL2 */
+ eret
+
+el2_not_present:
+ /* Initialize SCTLR_EL1 with reset value */
+ msr sctlr_el1, xzr
+
+ /* Set EL1 entry point */
+ adr x0, at_testel
+ msr elr_el3, x0
+
+ /* Prepare SPSR for exception return to EL1h with interrupts masked */
+ mov x0, #0x3c5 /* DAIF bits and EL1h mode (5) */
+ msr spsr_el3, x0
+
+ isb /* Synchronization barrier */
+ eret /* Jump to EL1 */
+
+setup_el2:
+ /* Ensure we trap if we get anything wrong */
+ adr x0, vector_table
+ msr vbar_el2, x0
+
+ /* Does the test want to be at EL2? */
+ cmp w11, #2
+ beq at_testel
+
+ /* Configure EL2 to allow transition to EL1 */
+ mrs x0, hcr_el2
+ orr x0, x0, #(1 << 31) /* RW = 1: EL1 execution state is AArch64 */
+ msr hcr_el2, x0
+
+ /* Initialize SCTLR_EL1 with reset value */
+ msr sctlr_el1, xzr
+
+ /* Set EL1 entry point */
+ adr x0, at_testel
+ msr elr_el2, x0
+
+ /* Prepare SPSR for exception return to EL1 */
+ mov x0, #(0x5 << 0) /* EL1h (SPx), with interrupts disabled */
+ msr spsr_el2, x0
+
+ /* Return to EL1 */
+ eret
+
+ /*
+ * At the target EL for the test, usually EL1. Note we still
+ * set everything up as if we were at EL1.
+ */
+at_testel:
/* Installs a table of exception vectors to catch and handle all
exceptions by terminating the process with a diagnostic. */
adr x0, vector_table
@@ -101,7 +252,7 @@ __start:
* maps RAM to the first Gb. The stage2 tables have two 2mb
* translation block entries covering a series of adjacent
* 4k pages.
- */
+ */
/* Stage 1 entry: indexed by IA[38:30] */
adr x1, . /* phys address */
@@ -135,6 +286,17 @@ __start:
orr x1, x1, x3
str x1, [x2] /* 2nd 2mb (.data & .bss)*/
+ /* Third block: at 'mte_page', set in kernel.ld */
+ adrp x1, mte_page
+ add x1, x1, :lo12:mte_page
+ bic x1, x1, #(1 << 21) - 1
+ and x4, x1, x5
+ add x2, x0, x4, lsr #(21 - 3)
+ /* attr(AF, NX, block, AttrIndx=Attr1) */
+ ldr x3, =(3 << 53) | 0x401 | (1 << 2)
+ orr x1, x1, x3
+ str x1, [x2]
+
/* Setup/enable the MMU. */
/*
@@ -188,7 +350,8 @@ __start:
orr x0, x0, #(3 << 16)
msr cpacr_el1, x0
- /* Setup some stack space and enter the test code.
+ /*
+ * Setup some stack space before we enter the test code.
* Assume everything except the return value is garbage when we
* return, we won't need it.
*/
@@ -223,6 +386,11 @@ __sys_outc:
ret
.data
+
+ .align 8
+cmdline:
+ .space 128, 0
+
.align 12
/* Translation table
@@ -236,6 +404,10 @@ ttb_stage2:
.space 4096, 0
.align 12
+system_stack:
+ .space 4096, 0
+system_stack_end:
+
stack:
.space 65536, 0
stack_end:
diff --git a/tests/tcg/aarch64/system/feat-xs.c b/tests/tcg/aarch64/system/feat-xs.c
new file mode 100644
index 0000000..f310fc8
--- /dev/null
+++ b/tests/tcg/aarch64/system/feat-xs.c
@@ -0,0 +1,27 @@
+/*
+ * FEAT_XS Test
+ *
+ * Copyright (c) 2024 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <minilib.h>
+#include <stdint.h>
+
+int main(void)
+{
+ uint64_t isar1;
+
+ asm volatile ("mrs %0, id_aa64isar1_el1" : "=r"(isar1));
+ if (((isar1 >> 56) & 0xf) < 1) {
+ ml_printf("FEAT_XS not supported by CPU");
+ return 1;
+ }
+ /* VMALLE1NXS */
+ asm volatile (".inst 0xd508971f");
+ /* VMALLE1OSNXS */
+ asm volatile (".inst 0xd508911f");
+
+ return 0;
+}
diff --git a/tests/tcg/aarch64/system/kernel.ld b/tests/tcg/aarch64/system/kernel.ld
index 7b3a76d..aef043e 100644
--- a/tests/tcg/aarch64/system/kernel.ld
+++ b/tests/tcg/aarch64/system/kernel.ld
@@ -1,23 +1,32 @@
ENTRY(__start)
-SECTIONS
-{
- /* virt machine, RAM starts at 1gb */
- . = (1 << 30);
+MEMORY {
+ /* On virt machine RAM starts at 1 GiB. */
+
+ /* Align text and rodata to the 1st 2 MiB chunk. */
+ TXT (rx) : ORIGIN = 1 << 30, LENGTH = 2M
+ /* Align r/w data to the 2nd 2 MiB chunk. */
+ DAT (rw) : ORIGIN = (1 << 30) + 2M, LENGTH = 2M
+ /* Align the MTE-enabled page to the 3rd 2 MiB chunk. */
+ TAG (rw) : ORIGIN = (1 << 30) + 4M, LENGTH = 2M
+}
+
+SECTIONS {
.text : {
*(.text)
- }
- .rodata : {
*(.rodata)
- }
- /* align r/w section to next 2mb */
- . = ALIGN(1 << 21);
+ } >TXT
.data : {
*(.data)
- }
- .bss : {
*(.bss)
- }
+ } >DAT
+ .tag : {
+ /*
+ * Symbol 'mte_page' is used in boot.S to setup the PTE and in the mte.S
+ * test as the address that the MTE instructions operate on.
+ */
+ mte_page = .;
+ } >TAG
/DISCARD/ : {
*(.ARM.attributes)
}
diff --git a/tests/tcg/aarch64/system/mte.S b/tests/tcg/aarch64/system/mte.S
new file mode 100644
index 0000000..b611240
--- /dev/null
+++ b/tests/tcg/aarch64/system/mte.S
@@ -0,0 +1,109 @@
+/*
+ * Code to help test the MTE gdbstubs in system mode.
+ *
+ * Copyright (c) 2024 Linaro Limited
+ *
+ * Author: Gustavo Romero <gustavo.romero@linaro.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#define addr x0 /* Ptr to the start of the MTE-enabled page. */
+#define tagged_addr x1 /* 'addr' ptr with a random-generated tag added. */
+#define tmp0 x2 /* Scratch register. */
+#define tmp1 x3 /* Scratch register. */
+#define tmp2 x4 /* Scratch register. */
+#define tmp3 x5 /* Sctatch register. */
+
+ .file "mte.S"
+
+ .text
+ .align 4
+
+ .globl main
+ .type main, @function
+
+main:
+ /*
+ * Set MAIR_EL1 (Memory Attribute Index Register). In boot.S, the
+ * attribute index for .mte_page is set to point to MAILR_EL field Attr1
+ * (AttrIndx=Attr1), so set Attr1 as Tagged Normal (MTE) to enable MTE
+ * on this page.
+ *
+ * Attr1 = 0xF0 => Tagged Normal (MTE)
+ */
+ mrs tmp0, mair_el1
+ orr tmp0, tmp0, (0xF0 << 8)
+ msr mair_el1, tmp0
+
+ /*
+ * Set TCR_EL1 (Translation Control Registers) to ignore the top byte
+ * in the translated addresses so it can be used to keep the tags.
+ *
+ * TBI0[37] = 0b1 => Top Byte ignored and used for tagged addresses
+ */
+ mrs tmp1, tcr_el1
+ orr tmp1, tmp1, (1 << 37)
+ msr tcr_el1, tmp1
+
+ /*
+ * Set SCTLR_EL1 (System Control Register) to enable the use of MTE
+ * insns., like stg & friends, and to enable synchronous exception in
+ * case of a tag mismatch, i.e., when the logical tag in 'tagged_addr'
+ * is different from the allocation tag related to 'addr' address.
+ *
+ * ATA[43] = 0b1 => Enable access to allocation tags at EL1
+ * TCF[41:40] = 0b01 => Tag Check Faults cause a synchronous exception
+ *
+ */
+ mrs tmp2, sctlr_el1
+ mov tmp3, (1 << 43) | (1 << 40)
+ orr tmp2, tmp2, tmp3
+ msr sctlr_el1, tmp2
+
+ isb
+
+ /*
+ * MTE-enabled page resides at the 3rd 2MB chunk in the second 1GB
+ * block, i.e., at 0x40400000 address. See .mte_page section in boot.S
+ * and kernel.ld (where the address is effectively computed).
+ *
+ * Load .mte_page address into 'addr' register.
+ */
+ adrp addr, mte_page
+ add addr, addr, :lo12:mte_page
+
+ /*
+ * Set GCR for random tag generation. 0xA5 is just a random value to set
+ * GCR != 0 so the tag generated by 'irg' insn. is not zero, which is
+ * more interesting for the tests than when tag is zero.
+ */
+ mov tmp0, 0xA5
+ msr gcr_el1, tmp0
+
+ /*
+ * Generate a logical tag, add it to 'addr' address and put it into
+ * 'tagged_addr'.
+ */
+ irg tagged_addr, addr
+
+ /*
+ * Store the generated tag to memory region pointed to by 'addr', i.e.
+ * set the allocation tag for granule at 'addr'. The tag is extracted
+ * by stg from tagged_addr pointer.
+ */
+ stg tagged_addr, [addr]
+
+ /*
+ * Store a random value (0xdeadbeef) to tagged_addr address. This must
+ * not cause any Tag Check Fault since logical tag in tagged_addr and
+ * allocation tag associated with the memory pointed by tagged_addr are
+ * set the same, otherwise something is off and the test fails -- an
+ * exception is generated.
+ */
+ ldr tmp1, =0xdeadbeef
+ str tmp1, [tagged_addr]
+
+ /* This label is used by GDB Python script test-mte.py. */
+main_end:
+ ret
diff --git a/tests/tcg/aarch64_be/Makefile.target b/tests/tcg/aarch64_be/Makefile.target
new file mode 100644
index 0000000..cbe5fa0
--- /dev/null
+++ b/tests/tcg/aarch64_be/Makefile.target
@@ -0,0 +1,17 @@
+# -*- Mode: makefile -*-
+#
+# A super basic AArch64 BE makefile. As we don't have any big-endian
+# libc available the best we can do is a basic Hello World.
+
+AARCH64BE_SRC=$(SRC_PATH)/tests/tcg/aarch64_be
+VPATH += $(AARCH64BE_SRC)
+
+AARCH64BE_TEST_SRCS=$(notdir $(wildcard $(AARCH64BE_SRC)/*.c))
+AARCH64BE_TESTS=$(AARCH64BE_TEST_SRCS:.c=)
+#MULTIARCH_TESTS = $(MULTIARCH_SRCS:.c=)
+
+# We need to specify big-endian cflags
+CFLAGS +=-mbig-endian -ffreestanding
+LDFLAGS +=-nostdlib
+
+TESTS += $(AARCH64BE_TESTS)
diff --git a/tests/tcg/aarch64_be/hello.c b/tests/tcg/aarch64_be/hello.c
new file mode 100644
index 0000000..a9b2ab4
--- /dev/null
+++ b/tests/tcg/aarch64_be/hello.c
@@ -0,0 +1,35 @@
+/*
+ * Non-libc syscall hello world for Aarch64 BE
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#define __NR_write 64
+#define __NR_exit 93
+
+int write(int fd, char *buf, int len)
+{
+ register int x0 __asm__("x0") = fd;
+ register char *x1 __asm__("x1") = buf;
+ register int x2 __asm__("x2") = len;
+ register int x8 __asm__("x8") = __NR_write;
+
+ asm volatile("svc #0" : : "r"(x0), "r"(x1), "r"(x2), "r"(x8));
+
+ return len;
+}
+
+void exit(int ret)
+{
+ register int x0 __asm__("x0") = ret;
+ register int x8 __asm__("x8") = __NR_exit;
+
+ asm volatile("svc #0" : : "r"(x0), "r"(x8));
+ __builtin_unreachable();
+}
+
+void _start(void)
+{
+ write(1, "Hello World\n", 12);
+ exit(0);
+}
diff --git a/tests/tcg/alpha/Makefile.softmmu-target b/tests/tcg/alpha/Makefile.softmmu-target
index a0eca4d..a944102 100644
--- a/tests/tcg/alpha/Makefile.softmmu-target
+++ b/tests/tcg/alpha/Makefile.softmmu-target
@@ -28,7 +28,7 @@ LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
-memory: CFLAGS+=-DCHECK_UNALIGNED=0
+memory: CFLAGS+=-DCHECK_UNALIGNED=0 -mbwx
# Running
QEMU_OPTS+=-serial chardev:output -kernel
diff --git a/tests/tcg/alpha/Makefile.target b/tests/tcg/alpha/Makefile.target
index fdd7ddf..36d8ed1 100644
--- a/tests/tcg/alpha/Makefile.target
+++ b/tests/tcg/alpha/Makefile.target
@@ -12,4 +12,7 @@ test-cmov: EXTRA_CFLAGS=-DTEST_CMOV
test-cmov: test-cond.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
+# Force generation of byte read/write
+test-plugin-mem-access: CFLAGS+=-mbwx
+
run-test-cmov: test-cmov
diff --git a/tests/tcg/arm/Makefile.target b/tests/tcg/arm/Makefile.target
index 06ddf3e..6189d7a 100644
--- a/tests/tcg/arm/Makefile.target
+++ b/tests/tcg/arm/Makefile.target
@@ -20,13 +20,6 @@ ARM_TESTS = hello-arm
hello-arm: CFLAGS+=-marm -ffreestanding -fno-stack-protector
hello-arm: LDFLAGS+=-nostdlib
-# IWMXT floating point extensions
-ARM_TESTS += test-arm-iwmmxt
-# Clang assembler does not support IWMXT, so use the external assembler.
-test-arm-iwmmxt: CFLAGS += -marm -march=iwmmxt -mabi=aapcs -mfpu=fpv4-sp-d16 $(CROSS_CC_HAS_FNIA)
-test-arm-iwmmxt: test-arm-iwmmxt.S
- $(CC) $(CFLAGS) -Wa,--noexecstack $< -o $@ $(LDFLAGS)
-
# Float-convert Tests
ARM_TESTS += fcvt
fcvt: LDFLAGS += -lm
@@ -68,7 +61,8 @@ endif
ARM_TESTS += commpage
# Vector SHA1
-sha1-vector: CFLAGS=-O3
+# Work around compiler false-positive warning, as we do for the 'sha1' test
+sha1-vector: CFLAGS=-O3 -Wno-stringop-overread
sha1-vector: sha1.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
run-sha1-vector: sha1-vector run-sha1
diff --git a/tests/tcg/arm/README b/tests/tcg/arm/README
index e630711..aceccc1 100644
--- a/tests/tcg/arm/README
+++ b/tests/tcg/arm/README
@@ -4,8 +4,3 @@ hello-arm
---------
A very simple inline assembly, write syscall based hello world
-
-test-arm-iwmmxt
----------------
-
-A simple test case for older iwmmxt extended ARMs
diff --git a/tests/tcg/arm/test-arm-iwmmxt.S b/tests/tcg/arm/test-arm-iwmmxt.S
deleted file mode 100644
index d647f94..0000000
--- a/tests/tcg/arm/test-arm-iwmmxt.S
+++ /dev/null
@@ -1,49 +0,0 @@
-@ Checks whether iwMMXt is functional.
-.code 32
-.globl main
-
-main:
-ldr r0, =data0
-ldr r1, =data1
-ldr r2, =data2
-#ifndef FPA
-wldrd wr0, [r0, #0]
-wldrd wr1, [r0, #8]
-wldrd wr2, [r1, #0]
-wldrd wr3, [r1, #8]
-wsubb wr2, wr2, wr0
-wsubb wr3, wr3, wr1
-wldrd wr0, [r2, #0]
-wldrd wr1, [r2, #8]
-waddb wr0, wr0, wr2
-waddb wr1, wr1, wr3
-wstrd wr0, [r2, #0]
-wstrd wr1, [r2, #8]
-#else
-ldfe f0, [r0, #0]
-ldfe f1, [r0, #8]
-ldfe f2, [r1, #0]
-ldfe f3, [r1, #8]
-adfdp f2, f2, f0
-adfdp f3, f3, f1
-ldfe f0, [r2, #0]
-ldfe f1, [r2, #8]
-adfd f0, f0, f2
-adfd f1, f1, f3
-stfe f0, [r2, #0]
-stfe f1, [r2, #8]
-#endif
-mov r0, #1
-mov r1, r2
-mov r2, #0x11
-swi #0x900004
-mov r0, #0
-swi #0x900001
-
-.data
-data0:
-.string "aaaabbbbccccdddd"
-data1:
-.string "bbbbccccddddeeee"
-data2:
-.string "hvLLWs\x1fsdrs9\x1fNJ-\n"
diff --git a/tests/tcg/cris/.gdbinit b/tests/tcg/cris/.gdbinit
deleted file mode 100644
index 5e8c1d3..0000000
--- a/tests/tcg/cris/.gdbinit
+++ /dev/null
@@ -1,11 +0,0 @@
-b main
-b _fail
-b exit
-display /i $pc
-display /x $srp
-display /x $r0
-display /x $r1
-display /x $r2
-display /x $r3
-display /x $r4
-display /t $ccs
diff --git a/tests/tcg/cris/Makefile.target b/tests/tcg/cris/Makefile.target
deleted file mode 100644
index 713e2a5..0000000
--- a/tests/tcg/cris/Makefile.target
+++ /dev/null
@@ -1,62 +0,0 @@
-# -*- Mode: makefile -*-
-#
-# Cris tests
-#
-# Currently we can only build the "bare" tests with the docker
-# supplied cross-compiler.
-#
-
-CRIS_SRC = $(SRC_PATH)/tests/tcg/cris/bare
-CRIS_ALL = $(wildcard $(CRIS_SRC)/*.s)
-CRIS_TESTS = $(patsubst $(CRIS_SRC)/%.s, %, $(CRIS_ALL))
-# Filter out common blobs and broken tests
-CRIS_BROKEN_TESTS = crt check_jsr
-# upstream GCC doesn't support v32
-CRIS_BROKEN_TESTS += check_mcp check_mulv32 check_addiv32 check_movpmv32
-CRIS_BROKEN_TESTS += check_movprv32 check_clearfv32 check_movemrv32 check_bas
-CRIS_BROKEN_TESTS += check_lapc check_movei
-# no sure why
-CRIS_BROKEN_TESTS += check_scc check_xarith
-
-CRIS_USABLE_TESTS = $(filter-out $(CRIS_BROKEN_TESTS), $(CRIS_TESTS))
-CRIS_RUNS = $(patsubst %, run-%, $(CRIS_USABLE_TESTS))
-
-# override the list of tests, as we can't build the multiarch tests
-TESTS = $(CRIS_USABLE_TESTS)
-EXTRA_RUNS =
-VPATH = $(CRIS_SRC)
-
-AS = $(CC) -x assembler-with-cpp
-LD = $(CC)
-
-# we rely on GCC inline:ing the stuff we tell it to in many places here.
-CFLAGS = -Winline -Wall -g -O2 -static -fno-stack-protector
-NOSTDFLAGS = -nostartfiles -nostdlib
-ASFLAGS += -mcpu=v10 -g -Wa,-I,$(SRC_PATH)/tests/tcg/cris/bare
-CRT_FILES = crt.o sys.o
-
-# stop make deleting crt files if build fails
-.PRECIOUS: $(CRT_FILES)
-
-%.o: %.c
- $(CC) -c $< -o $@
-
-%.o: %.s
- $(AS) $(ASFLAGS) -c $< -o $@
-
-%: %.s $(CRT_FILES)
- $(CC) $(ASFLAGS) $< -o $@ $(LDFLAGS) $(NOSTDFLAGS) $(CRT_FILES)
-
-# The default CPU breaks (possibly as it's max?) so force crisv17
-QEMU_OPTS=-cpu crisv17
-
-# Additional runners to run under GNU SIM
-CRIS_RUNS_ON_SIM=$(patsubst %, %-on-sim, $(CRIS_RUNS))
-SIMG:=cris-axis-linux-gnu-run
-
-# e.g.: make -f ../../tests/tcg/Makefile run-check_orm-on-sim
-run-%-on-sim:
- $(call run-test, $<, $(SIMG) $<)
-
-# We don't currently support the multiarch tests
-undefine MULTIARCH_TESTS
diff --git a/tests/tcg/cris/README b/tests/tcg/cris/README
deleted file mode 100644
index 2e65a76..0000000
--- a/tests/tcg/cris/README
+++ /dev/null
@@ -1 +0,0 @@
-Test-suite for the cris port. Heavily based on the test-suite for the CRIS port of sim by Hans-Peter Nilsson.
diff --git a/tests/tcg/cris/bare/check_addcv17.s b/tests/tcg/cris/bare/check_addcv17.s
deleted file mode 100644
index 52ef7a9..0000000
--- a/tests/tcg/cris/bare/check_addcv17.s
+++ /dev/null
@@ -1,65 +0,0 @@
-# mach: crisv17
-
- .include "testutils.inc"
-
- .macro addc Rs Rd inc=0
-# Create the instruction manually since there is no assembler support yet
- .word (\Rd << 12) | \Rs | (\inc << 10) | 0x09a0
- .endm
-
- start
-
- .data
-mem1:
- .dword 0x0
-mem2:
- .dword 0x12345678
-
- .text
- move.d mem1,r4
- clearf nzvc
- addc 4 3
- test_cc 0 1 0 0
- checkr3 0
-
- move.d mem1,r4
- clearf nzvc
- ax
- addc 4 3
- test_cc 0 0 0 0
- checkr3 0
-
- move.d mem1,r4
- clearf nzvc
- setf c
- addc 4 3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d mem2,r4
- moveq 2, r3
- clearf nzvc
- setf c
- addc 4 3
- test_cc 0 0 0 0
- checkr3 1234567b
-
- move.d mem2,r5
- clearf nzvc
- cmp.d r4,r5
- test_cc 0 1 0 0
-
- move.d mem2,r4
- moveq 2, r3
- clearf nzvc
- addc 4 3 inc=1
- test_cc 0 0 0 0
- checkr3 1234567a
-
- move.d mem2,r5
- clearf nzvc
- addq 4,r5
- cmp.d r4,r5
- test_cc 0 1 0 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_addi.s b/tests/tcg/cris/bare/check_addi.s
deleted file mode 100644
index a00dec0..0000000
--- a/tests/tcg/cris/bare/check_addi.s
+++ /dev/null
@@ -1,57 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 0\n1\n2\n4\nbe02460f\n69d035a6\nc16c14d4\n
-
- .include "testutils.inc"
- start
- moveq 0,r3
- moveq 0,r4
- clearf zcvn
- addi r4.b,r3
- test_cc 0 0 0 0
- checkr3 0
-
- moveq 0,r3
- moveq 1,r4
- setf zcvn
- addi r4.b,r3
- test_cc 1 1 1 1
- checkr3 1
-
- moveq 0,r3
- moveq 1,r4
- setf cv
- clearf zn
- addi r4.w,r3
- test_cc 0 0 1 1
- checkr3 2
-
- moveq 0,r3
- moveq 1,r4
- clearf cv
- setf zn
- addi r4.d,r3
- test_cc 1 1 0 0
- checkr3 4
-
- move.d 0x12345678,r3
- move.d 0xabcdef97,r4
- clearf cn
- setf zv
- addi r4.b,r3
- test_cc 0 1 1 0
- checkr3 be02460f
-
- move.d 0x12345678,r3
- move.d 0xabcdef97,r4
- setf cn
- clearf zv
- addi r4.w,r3
- test_cc 1 0 0 1
- checkr3 69d035a6
-
- move.d 0x12345678,r3
- move.d 0xabcdef97,r4
- addi r4.d,r3
- checkr3 c16c14d4
-
- quit
diff --git a/tests/tcg/cris/bare/check_addiv32.s b/tests/tcg/cris/bare/check_addiv32.s
deleted file mode 100644
index 20ba25d..0000000
--- a/tests/tcg/cris/bare/check_addiv32.s
+++ /dev/null
@@ -1,62 +0,0 @@
-# mach: crisv32
-# output: 4455aa77\n4455aa77\nee19ccff\nff22\n4455aa77\nff224455\n55aa77ff\n
-
- .include "testutils.inc"
- .data
-x:
- .dword 0x55aa77ff
- .dword 0xccff2244
- .dword 0x88ccee19
-
- start
- setf cv
- moveq -1,r0
- move.d x-32768,r5
- move.d 32769,r6
- addi r6.b,r5,acr
- test_cc 0 0 1 1
- move.d [acr],r3
- checkr3 4455aa77
-
- addu.w 32771,r5
- setf znvc
- moveq -1,r8
- addi r8.w,r5,acr
- test_cc 1 1 1 1
- move.d [acr],r3
- checkr3 4455aa77
-
- moveq 5,r10
- clearf znvc
- addi r10.b,acr,acr
- test_cc 0 0 0 0
- move.d [acr],r3
- checkr3 ee19ccff
-
- subq 1,r5
- move.d r5,r8
- subq 1,r8
- moveq 1,r9
- addi r9.d,r8,acr
- test_cc 0 0 0 0
- movu.w [acr],r3
- checkr3 ff22
-
- moveq -2,r11
- addi r11.w,acr,acr
- move.d [acr],r3
- checkr3 4455aa77
-
- moveq 5,r9
- addi r9.d,acr,acr
- subq 18,acr
- move.d [acr],r3
- checkr3 ff224455
-
- move.d -76789888/4,r12
- addi r12.d,r5,acr
- add.d 76789886,acr
- move.d [acr],r3
- checkr3 55aa77ff
-
- quit
diff --git a/tests/tcg/cris/bare/check_addm.s b/tests/tcg/cris/bare/check_addm.s
deleted file mode 100644
index efece9f..0000000
--- a/tests/tcg/cris/bare/check_addm.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n781344d0\n
-
- .include "testutils.inc"
- .data
-x:
- .dword 2,-1,0xffff,-1,0x5432f789
- .word 2,-1,0xffff,0xf789
- .byte 2,0xff,0x89
- .byte 0x7e
-
- start
- moveq -1,r3
- move.d x,r5
- add.d [r5+],r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- add.d [r5],r3
- test_cc 0 0 0 1
- addq 4,r5
- checkr3 1
-
- move.d 0xffff,r3
- add.d [r5+],r3
- test_cc 0 0 0 0
- checkr3 1fffe
-
- moveq -1,r3
- add.d [r5+],r3
- test_cc 1 0 0 1
- checkr3 fffffffe
-
- move.d 0x78134452,r3
- add.d [r5+],r3
- test_cc 1 0 1 0
- checkr3 cc463bdb
-
- moveq -1,r3
- add.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 ffff0001
-
- moveq 2,r3
- add.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xffff,r3
- add.w [r5],r3
- test_cc 1 0 0 1
- checkr3 fffe
-
- move.d 0xfedaffff,r3
- add.w [r5+],r3
- test_cc 1 0 0 1
- checkr3 fedafffe
-
- move.d 0x78134452,r3
- add.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 78133bdb
-
- moveq -1,r3
- add.b [r5],r3
- test_cc 0 0 0 1
- addq 1,r5
- checkr3 ffffff01
-
- moveq 2,r3
- add.b [r5],r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xff,r3
- add.b [r5],r3
- test_cc 1 0 0 1
- checkr3 fe
-
- move.d 0xfeda49ff,r3
- add.b [r5+],r3
- test_cc 1 0 0 1
- checkr3 feda49fe
-
- move.d 0x78134452,r3
- add.b [r5+],r3
- test_cc 1 0 0 0
- checkr3 781344db
-
- move.d 0x78134452,r3
- add.b [r5],r3
- test_cc 1 0 1 0
- checkr3 781344d0
-
- quit
diff --git a/tests/tcg/cris/bare/check_addq.s b/tests/tcg/cris/bare/check_addq.s
deleted file mode 100644
index e6f874f..0000000
--- a/tests/tcg/cris/bare/check_addq.s
+++ /dev/null
@@ -1,47 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n0\n1\n100\n10000\n47\n67\na6\n80000001\n
-
- .include "testutils.inc"
- start
- moveq -2,r3
- addq 1,r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- addq 1,r3
- test_cc 0 1 0 1
- checkr3 0
-
- addq 1,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xff,r3
- addq 1,r3
- test_cc 0 0 0 0
- checkr3 100
-
- move.d 0xffff,r3
- addq 1,r3
- test_cc 0 0 0 0
- checkr3 10000
-
- move.d 0x42,r3
- addq 5,r3
- test_cc 0 0 0 0
- checkr3 47
-
- addq 32,r3
- test_cc 0 0 0 0
- checkr3 67
-
- addq 63,r3
- test_cc 0 0 0 0
- checkr3 a6
-
- move.d 0x7ffffffe,r3
- addq 3,r3
- test_cc 1 0 1 0
- checkr3 80000001
-
- quit
diff --git a/tests/tcg/cris/bare/check_addr.s b/tests/tcg/cris/bare/check_addr.s
deleted file mode 100644
index 7f55cdc..0000000
--- a/tests/tcg/cris/bare/check_addr.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- add.d r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- moveq -1,r4
- add.d r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xffff,r4
- move.d r4,r3
- add.d r4,r3
- test_cc 0 0 0 0
- checkr3 1fffe
-
- moveq -1,r4
- move.d r4,r3
- add.d r4,r3
- test_cc 1 0 0 1
- checkr3 fffffffe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- add.d r4,r3
- test_cc 1 0 1 0
- checkr3 cc463bdb
-
- moveq -1,r3
- moveq 2,r4
- add.w r4,r3
- test_cc 0 0 0 1
- checkr3 ffff0001
-
- moveq 2,r3
- moveq -1,r4
- add.w r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xffff,r4
- move.d r4,r3
- add.w r4,r3
- test_cc 1 0 0 1
- checkr3 fffe
-
- move.d 0xfedaffff,r4
- move.d r4,r3
- add.w r4,r3
- test_cc 1 0 0 1
- checkr3 fedafffe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- add.w r4,r3
- test_cc 0 0 0 1
- checkr3 78133bdb
-
- moveq -1,r3
- moveq 2,r4
- add.b r4,r3
- test_cc 0 0 0 1
- checkr3 ffffff01
-
- moveq 2,r3
- moveq -1,r4
- add.b r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xff,r4
- move.d r4,r3
- add.b r4,r3
- test_cc 1 0 0 1
- checkr3 fe
-
- move.d 0xfeda49ff,r4
- move.d r4,r3
- add.b r4,r3
- test_cc 1 0 0 1
- checkr3 feda49fe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- add.b r4,r3
- test_cc 1 0 0 0
- checkr3 781344db
-
- quit
diff --git a/tests/tcg/cris/bare/check_addxc.s b/tests/tcg/cris/bare/check_addxc.s
deleted file mode 100644
index 09c8355..0000000
--- a/tests/tcg/cris/bare/check_addxc.s
+++ /dev/null
@@ -1,91 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n101\n10001\n100fe\n1fffe\nfffe\nfffe\nfffffffe\nfe\nfffffffe\n781344db\n781343db\n78143bdb\n78133bdb\n800000ed\n0\n
-
- .include "testutils.inc"
- start
- moveq 2,r3
- adds.b 0xff,r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- adds.w 0xffff,r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- addu.b 0xff,r3
- checkr3 101
-
- moveq 2,r3
- move.d 0xffffffff,r4
- addu.w -1,r3
- test_cc 0 0 0 0
- checkr3 10001
-
- move.d 0xffff,r3
- addu.b -1,r3
- test_cc 0 0 0 0
- checkr3 100fe
-
- move.d 0xffff,r3
- addu.w -1,r3
- test_cc 0 0 0 0
- checkr3 1fffe
-
- move.d 0xffff,r3
- adds.b 0xff,r3
- test_cc 0 0 0 1
- checkr3 fffe
-
- move.d 0xffff,r3
- adds.w 0xffff,r3
- test_cc 0 0 0 1
- checkr3 fffe
-
- moveq -1,r3
- adds.b 0xff,r3
- test_cc 1 0 0 1
- checkr3 fffffffe
-
- moveq -1,r3
- adds.w 0xff,r3
- test_cc 0 0 0 1
- checkr3 fe
-
- moveq -1,r3
- adds.w 0xffff,r3
- test_cc 1 0 0 1
- checkr3 fffffffe
-
- move.d 0x78134452,r3
- addu.b 0x89,r3
- test_cc 0 0 0 0
- checkr3 781344db
-
- move.d 0x78134452,r3
- adds.b 0x89,r3
- test_cc 0 0 0 1
- checkr3 781343db
-
- move.d 0x78134452,r3
- addu.w 0xf789,r3
- test_cc 0 0 0 0
- checkr3 78143bdb
-
- move.d 0x78134452,r3
- adds.w 0xf789,r3
- test_cc 0 0 0 1
- checkr3 78133bdb
-
- move.d 0x7fffffee,r3
- addu.b 0xff,r3
- test_cc 1 0 1 0
- checkr3 800000ed
-
- move.d 0x1,r3
- adds.w 0xffff,r3
- test_cc 0 1 0 1
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_addxm.s b/tests/tcg/cris/bare/check_addxm.s
deleted file mode 100644
index 7563494..0000000
--- a/tests/tcg/cris/bare/check_addxm.s
+++ /dev/null
@@ -1,106 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n101\n10001\n100fe\n1fffe\nfffe\nfffe\nfffffffe\nfe\nfffffffe\n781344db\n781343db\n78143bdb\n78133bdb\n800000ed\n0\n
-
- .include "testutils.inc"
- .data
-x:
- .byte 0xff
- .word 0xffff
- .word 0xff
- .word 0xffff
- .byte 0x89
- .word 0xf789
- .byte 0xff
- .word 0xffff
-
- start
- moveq 2,r3
- move.d x,r5
- adds.b [r5+],r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- adds.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- subq 3,r5
- addu.b [r5+],r3
- test_cc 0 0 0 0
- checkr3 101
-
- moveq 2,r3
- addu.w [r5+],r3
- subq 3,r5
- test_cc 0 0 0 0
- checkr3 10001
-
- move.d 0xffff,r3
- addu.b [r5],r3
- test_cc 0 0 0 0
- checkr3 100fe
-
- move.d 0xffff,r3
- addu.w [r5],r3
- test_cc 0 0 0 0
- checkr3 1fffe
-
- move.d 0xffff,r3
- adds.b [r5],r3
- test_cc 0 0 0 1
- checkr3 fffe
-
- move.d 0xffff,r3
- adds.w [r5],r3
- test_cc 0 0 0 1
- checkr3 fffe
-
- moveq -1,r3
- adds.b [r5],r3
- test_cc 1 0 0 1
- addq 3,r5
- checkr3 fffffffe
-
- moveq -1,r3
- adds.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 fe
-
- moveq -1,r3
- adds.w [r5+],r3
- test_cc 1 0 0 1
- checkr3 fffffffe
-
- move.d 0x78134452,r3
- addu.b [r5],r3
- test_cc 0 0 0 0
- checkr3 781344db
-
- move.d 0x78134452,r3
- adds.b [r5+],r3
- test_cc 0 0 0 1
- checkr3 781343db
-
- move.d 0x78134452,r3
- addu.w [r5],r3
- test_cc 0 0 0 0
- checkr3 78143bdb
-
- move.d 0x78134452,r3
- adds.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 78133bdb
-
- move.d 0x7fffffee,r3
- addu.b [r5+],r3
- test_cc 1 0 1 0
- checkr3 800000ed
-
- move.d 0x1,r3
- adds.w [r5+],r3
- test_cc 0 1 0 1
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_addxr.s b/tests/tcg/cris/bare/check_addxr.s
deleted file mode 100644
index 7f55cdc..0000000
--- a/tests/tcg/cris/bare/check_addxr.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- add.d r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- moveq -1,r4
- add.d r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xffff,r4
- move.d r4,r3
- add.d r4,r3
- test_cc 0 0 0 0
- checkr3 1fffe
-
- moveq -1,r4
- move.d r4,r3
- add.d r4,r3
- test_cc 1 0 0 1
- checkr3 fffffffe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- add.d r4,r3
- test_cc 1 0 1 0
- checkr3 cc463bdb
-
- moveq -1,r3
- moveq 2,r4
- add.w r4,r3
- test_cc 0 0 0 1
- checkr3 ffff0001
-
- moveq 2,r3
- moveq -1,r4
- add.w r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xffff,r4
- move.d r4,r3
- add.w r4,r3
- test_cc 1 0 0 1
- checkr3 fffe
-
- move.d 0xfedaffff,r4
- move.d r4,r3
- add.w r4,r3
- test_cc 1 0 0 1
- checkr3 fedafffe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- add.w r4,r3
- test_cc 0 0 0 1
- checkr3 78133bdb
-
- moveq -1,r3
- moveq 2,r4
- add.b r4,r3
- test_cc 0 0 0 1
- checkr3 ffffff01
-
- moveq 2,r3
- moveq -1,r4
- add.b r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xff,r4
- move.d r4,r3
- add.b r4,r3
- test_cc 1 0 0 1
- checkr3 fe
-
- move.d 0xfeda49ff,r4
- move.d r4,r3
- add.b r4,r3
- test_cc 1 0 0 1
- checkr3 feda49fe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- add.b r4,r3
- test_cc 1 0 0 0
- checkr3 781344db
-
- quit
diff --git a/tests/tcg/cris/bare/check_andc.s b/tests/tcg/cris/bare/check_andc.s
deleted file mode 100644
index a947b77..0000000
--- a/tests/tcg/cris/bare/check_andc.s
+++ /dev/null
@@ -1,80 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- and.d 2,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- and.d -1,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- and.d 0xffff,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r3
- and.d -1,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- and.d 0x5432f789,r3
- test_move_cc 0 0 0 0
- checkr3 50124400
-
- moveq -1,r3
- and.w 2,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0002
-
- moveq 2,r3
- and.w -1,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xfffff,r3
- and.w 0xffff,r3
- test_move_cc 1 0 0 0
- checkr3 fffff
-
- move.d 0xfedaffaf,r3
- and.w 0xff5f,r3
- test_move_cc 1 0 0 0
- checkr3 fedaff0f
-
- move.d 0x78134452,r3
- and.w 0xf789,r3
- test_move_cc 0 0 0 0
- checkr3 78134400
-
- moveq -1,r3
- and.b 2,r3
- test_move_cc 0 0 0 0
- checkr3 ffffff02
-
- moveq 2,r3
- and.b -1,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xfa7,r3
- and.b 0x5a,r3
- test_move_cc 0 0 0 0
- checkr3 f02
-
- move.d 0x78134453,r3
- and.b 0x89,r3
- test_move_cc 0 0 0 0
- checkr3 78134401
-
- and.b 0,r3
- test_move_cc 0 1 0 0
- checkr3 78134400
-
- quit
diff --git a/tests/tcg/cris/bare/check_andm.s b/tests/tcg/cris/bare/check_andm.s
deleted file mode 100644
index 9385886..0000000
--- a/tests/tcg/cris/bare/check_andm.s
+++ /dev/null
@@ -1,90 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n
-
- .include "testutils.inc"
- .data
-x:
- .dword 2,-1,0xffff,-1,0x5432f789
- .word 2,-1,0xffff,0xff5f,0xf789
- .byte 2,-1,0x5a,0x89,0
-
- start
- moveq -1,r3
- move.d x,r5
- and.d [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- and.d [r5],r3
- test_move_cc 0 0 0 0
- addq 4,r5
- checkr3 2
-
- move.d 0xffff,r3
- and.d [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r3
- and.d [r5+],r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- and.d [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 50124400
-
- moveq -1,r3
- and.w [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 ffff0002
-
- moveq 2,r3
- and.w [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xfffff,r3
- and.w [r5],r3
- test_move_cc 1 0 0 0
- addq 2,r5
- checkr3 fffff
-
- move.d 0xfedaffaf,r3
- and.w [r5+],r3
- test_move_cc 1 0 0 0
- checkr3 fedaff0f
-
- move.d 0x78134452,r3
- and.w [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 78134400
-
- moveq -1,r3
- and.b [r5],r3
- test_move_cc 0 0 0 0
- addq 1,r5
- checkr3 ffffff02
-
- moveq 2,r3
- and.b [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xfa7,r3
- and.b [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 f02
-
- move.d 0x78134453,r3
- and.b [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 78134401
-
- and.b [r5],r3
- test_move_cc 0 1 0 0
- checkr3 78134400
-
- quit
diff --git a/tests/tcg/cris/bare/check_andq.s b/tests/tcg/cris/bare/check_andq.s
deleted file mode 100644
index 55aa7b0..0000000
--- a/tests/tcg/cris/bare/check_andq.s
+++ /dev/null
@@ -1,46 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\nffff\nffffffff\n1f\nffffffe0\n78134452\n0\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- andq 2,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- andq -1,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- andq -1,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r3
- andq -1,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- andq 31,r3
- test_move_cc 0 0 0 0
- checkr3 1f
-
- moveq -1,r3
- andq -32,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffe0
-
- move.d 0x78134457,r3
- andq -14,r3
- test_move_cc 0 0 0 0
- checkr3 78134452
-
- moveq 0,r3
- andq -14,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_andr.s b/tests/tcg/cris/bare/check_andr.s
deleted file mode 100644
index 61aa1dc..0000000
--- a/tests/tcg/cris/bare/check_andr.s
+++ /dev/null
@@ -1,95 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- and.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- moveq -1,r4
- and.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r4
- move.d r4,r3
- and.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r4
- move.d r4,r3
- and.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- and.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 50124400
-
- moveq -1,r3
- moveq 2,r4
- and.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0002
-
- moveq 2,r3
- moveq -1,r4
- and.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xfffff,r3
- move.d 0xffff,r4
- and.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 fffff
-
- move.d 0xfedaffaf,r3
- move.d 0xff5f,r4
- and.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 fedaff0f
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- and.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 78134400
-
- moveq -1,r3
- moveq 2,r4
- and.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffffff02
-
- moveq 2,r3
- moveq -1,r4
- and.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0x5a,r4
- move.d 0xfa7,r3
- and.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 f02
-
- move.d 0x5432f789,r4
- move.d 0x78134453,r3
- and.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 78134401
-
- moveq 0,r7
- and.b r7,r3
- test_move_cc 0 1 0 0
- checkr3 78134400
-
- quit
diff --git a/tests/tcg/cris/bare/check_asr.s b/tests/tcg/cris/bare/check_asr.s
deleted file mode 100644
index 0a02ae6..0000000
--- a/tests/tcg/cris/bare/check_asr.s
+++ /dev/null
@@ -1,230 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n1\nffffffff\nffffffff\n5a67f\nffffffff\nffffffff\nffffffff\nf699fc67\nffffffff\n1\nffffffff\nffffffff\n5a67f\nda67ffff\nda67ffff\nda67ffff\nda67fc67\nffffffff\nffffffff\n1\nffffffff\nffffffff\n5a670007\nda67f1ff\nda67f1ff\nda67f1ff\nda67f1e7\nffffffff\nffffffff\n1\nffffffff\nffffffff\nffffffff\n5a67f1ff\n5a67f1f9\n0\n5a670000\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- asrq 0,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- asrq 1,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- asrq 31,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- asrq 15,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x5a67f19f,r3
- asrq 12,r3
- test_move_cc 0 0 0 0
- checkr3 5a67f
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 f699fc67
-
- moveq -1,r3
- moveq 0,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- asr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- moveq 31,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 15,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- asr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 5a67f
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67ffff
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67ffff
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67ffff
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67fc67
-
- moveq -1,r3
- moveq 0,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 1,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- asr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- moveq 31,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 15,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x5a67719f,r3
- moveq 12,r4
- asr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 5a670007
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67f1ff
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67f1ff
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67f1ff
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67f1e7
-
- moveq -1,r3
- moveq 0,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 1,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- asr.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- moveq 31,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 15,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 7,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
-; FIXME: was wrong.
- move.d 0x5a67f19f,r3
- moveq 12,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 5a67f1ff
-
-; FIXME: was wrong.
- move.d 0x5a67f19f,r3
- moveq 4,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 5a67f1f9
-
- move.d 0x5a67f19f,r3
- asrq 31,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0x5a67419f,r3
- moveq 16,r4
- asr.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 5a670000
-
- quit
diff --git a/tests/tcg/cris/bare/check_ba.s b/tests/tcg/cris/bare/check_ba.s
deleted file mode 100644
index 873a408..0000000
--- a/tests/tcg/cris/bare/check_ba.s
+++ /dev/null
@@ -1,93 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: a\n
-
-
- .set smalloffset,0
- .set largeoffset,0
-
-
- .macro fail
- jump _fail
- .endm
-
- .global main
-main:
- moveq 0,$r3
-
-; Short forward branch.
- ba 0f
- addq 1,$r3
- fail
-
-; Max short forward branch.
-1:
- ba 2f
- addq 1,$r3
- fail
-
-; Short backward branch.
-0:
- ba 1b
- addq 1,$r3
- fail
-
- .space 254-2+smalloffset+1b-.,0
- moveq 0,$r3
-
-2:
-; Transit branch (long).
- ba 3f
- addq 1,$r3
- fail
-
- moveq 0,$r3
-4:
-; Long forward branch.
- ba 5f
- addq 1,$r3
- fail
-
- .space 256-2-smalloffset+4b-.,0
-
- moveq 0,$r3
-
-; Max short backward branch.
-3:
- ba 4b
- addq 1,$r3
- fail
-
-5:
-; Max long forward branch.
- ba 6f
- addq 1,$r3
- fail
-
- .space 32766+largeoffset-2+5b-.,0
-
- moveq 0,$r3
-6:
-; Transit branch.
- ba 7f
- addq 1,$r3
- fail
-
- moveq 0,$r3
-9:
- jsr pass
- nop
-
-; Transit branch.
- moveq 0,$r3
-7:
- ba 8f
- addq 1,$r3
- fail
-
- .space 32768-largeoffset+9b-.,0
-
-8:
-; Max long backward branch.
- ba 9b
- addq 1,$r3
- fail
diff --git a/tests/tcg/cris/bare/check_bas.s b/tests/tcg/cris/bare/check_bas.s
deleted file mode 100644
index 11929d4..0000000
--- a/tests/tcg/cris/bare/check_bas.s
+++ /dev/null
@@ -1,102 +0,0 @@
-# mach: crisv32
-# output: 0\n0\n0\nfb349abc\n0\n12124243\n0\n0\neab5baad\n0\nefb37832\n
-
- .include "testutils.inc"
- start
-x:
- setf zncv
- bsr 0f
- nop
-0:
- test_cc 1 1 1 1
- move srp,r3
- sub.d 0b,r3
- checkr3 0
-
- bas 1f,mof
- moveq 0,r0
-6:
- nop
- quit
-
-2:
- move srp,r3
- sub.d 3f,r3
- checkr3 0
- move srp,r4
- subq 4,r4
- move.d [r4],r3
- checkr3 fb349abc
-
- basc 4f,mof
- nop
- .dword 0x12124243
-7:
- nop
- quit
-
-8:
- move mof,r3
- sub.d 7f,r3
- checkr3 0
-
- move mof,r4
- subq 4,r4
- move.d [r4],r3
- checkr3 eab5baad
-
- jasc 9f,mof
- nop
- .dword 0xefb37832
-0:
- quit
-
- quit
-9:
- move mof,r3
- sub.d 0b,r3
- checkr3 0
-
- move mof,r4
- subq 4,r4
- move.d [r4],r3
- checkr3 efb37832
-
- quit
-
-4:
- move mof,r3
- sub.d 7b,r3
- checkr3 0
- move mof,r4
- subq 4,r4
- move.d [r4],r3
- checkr3 12124243
- basc 5f,bz
- moveq 0,r3
- .dword 0x7634aeba
- quit
-
- .space 32770,0
-1:
- move mof,r3
- sub.d 6b,r3
- checkr3 0
-
- bsrc 2b
- nop
- .dword 0xfb349abc
-3:
-
- quit
-
-5:
- move mof,r3
- sub.d 7b,r3
- checkr3 0
- move.d 8b,r6
- jasc r6,mof
- nop
- .dword 0xeab5baad
-7:
- quit
diff --git a/tests/tcg/cris/bare/check_bcc.s b/tests/tcg/cris/bare/check_bcc.s
deleted file mode 100644
index c57ffa6..0000000
--- a/tests/tcg/cris/bare/check_bcc.s
+++ /dev/null
@@ -1,197 +0,0 @@
- .global main
- .type main, @function
-main:
- clearf nzvc
- setf nzv
- bcc 0f
- addq 1, $r3
- jump dofail
-
-0:
- clearf nzvc
- setf nzv
- bcs dofail
- addq 1,$r3
-
- clearf nzvc
- setf ncv
- bne 1f
- addq 1, $r3
-
-fail:
-dofail:
- jump _fail
-
-1:
- clearf nzvc
- setf ncv
- beq dofail
- addq 1,$r3
-
- clearf nzvc
- setf ncz
- bvc 2f
- addq 1,$r3
- jump dofail
-
-2:
- clearf nzvc
- setf ncz
- bvs dofail
- addq 1,$r3
-
- clearf nzvc
- setf vcz
- bpl 3f
- addq 1,$r3
- jump fail
-3:
- clearf nzvc
- setf vcz
- bmi dofail
- addq 1,$r3
-
- clearf nzvc
- setf nv
- bls dofail
- addq 1,$r3
-
- clearf nzvc
- setf nv
- bhi 4f
- addq 1,$r3
- jump dofail
-
-4:
- clearf nzvc
- setf zc
- bge 5f
- addq 1,$r3
- jump dofail
-
-5:
- clearf nzvc
- setf zc
- blt dofail
- addq 1,$r3
-
- clearf nzvc
- setf c
- bgt 6f
- addq 1,$r3
- jump fail
-
-6:
- clearf nzvc
- setf c
- ble dofail
- addq 1,$r3
-
-;;;;;;;;;;
-
- setf nzvc
- clearf nzv
- bcc dofail
- addq 1,$r3
-
- setf nzvc
- clearf nzv
- bcs 0f
- addq 1,$r3
- jump fail
-
-0:
- setf nzvc
- clearf ncv
- bne dofail
- addq 1,$r3
-
- setf nzvc
- clearf ncv
- beq 1f
- addq 1,$r3
- jump fail
-
-1:
- setf nzvc
- clearf ncz
- bvc dofail
- addq 1,$r3
-
- setf nzvc
- clearf ncz
- bvs 2f
- addq 1,$r3
- jump fail
-
-2:
- setf nzvc
- clearf vcz
- bpl dofail
- addq 1,$r3
-
- setf nzvc
- clearf vcz
- bmi 3f
- addq 1,$r3
- jump fail
-
-3:
- setf nzvc
- clearf nv
- bls 4f
- addq 1,$r3
- jump fail
-
-4:
- setf nzvc
- clearf nv
- bhi dofail
- addq 1,$r3
-
- setf zvc
- clearf nzc
- bge dofail
- addq 1,$r3
-
- setf nzc
- clearf vzc
- blt 5f
- addq 1,$r3
- jump fail
-
-5:
- setf nzvc
- clearf c
- bgt dofail
- addq 1,$r3
-
- setf nzvc
- clearf c
- ble 6f
- addq 1,$r3
- jump fail
-
-6:
- ; do a forward branch.
- ba 2f
- nop
- .fill 100
-1:
- ba 3f
- nop
- .fill 800
-2:
- ba 1b
- nop
- .fill 1024
-3:
-
- moveq 31, $r0
-1: bne 1b
- subq 1, $r0
-
- jsr pass
- moveq 0, $r10
- ret
- nop
diff --git a/tests/tcg/cris/bare/check_boundc.s b/tests/tcg/cris/bare/check_boundc.s
deleted file mode 100644
index fb9e5bc..0000000
--- a/tests/tcg/cris/bare/check_boundc.s
+++ /dev/null
@@ -1,101 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\nffff\nffffffff\n5432f789\n2\nffff\n2\nffff\nffff\nf789\n2\n2\nff\nff\nff\n89\n0\nff\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- bound.d 2,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- bound.d 0xffffffff,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- bound.d 0xffff,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r3
- bound.d 0xffffffff,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- bound.d 0x5432f789,r3
- test_move_cc 0 0 0 0
- checkr3 5432f789
-
- moveq -1,r3
- bound.w 2,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq -1,r3
- bound.w 0xffff,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq 2,r3
- bound.w 0xffff,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- bound.w 0xffff,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0xfedaffff,r3
- bound.w 0xffff,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0x78134452,r3
- bound.w 0xf789,r3
- test_move_cc 0 0 0 0
- checkr3 f789
-
- moveq -1,r3
- bound.b 2,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- bound.b 0xff,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq -1,r3
- bound.b 0xff,r3
- test_move_cc 0 0 0 0
- checkr3 ff
-
- move.d 0xff,r3
- bound.b 0xff,r3
- test_move_cc 0 0 0 0
- checkr3 ff
-
- move.d 0xfeda49ff,r3
- bound.b 0xff,r3
- test_move_cc 0 0 0 0
- checkr3 ff
-
- move.d 0x78134452,r3
- bound.b 0x89,r3
- test_move_cc 0 0 0 0
- checkr3 89
-
- bound.w 0,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0xffff,r3
- bound.b -1,r3
- test_move_cc 0 0 0 0
- checkr3 ff
-
- quit
diff --git a/tests/tcg/cris/bare/check_boundr.s b/tests/tcg/cris/bare/check_boundr.s
deleted file mode 100644
index 5c50cc5..0000000
--- a/tests/tcg/cris/bare/check_boundr.s
+++ /dev/null
@@ -1,125 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\nffff\nffffffff\n5432f789\n2\n2\nffff\nffff\nffff\nf789\n2\n2\nff\nff\n89\nfeda4953\nfeda4962\n0\n0\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- bound.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- moveq -1,r4
- bound.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r4
- move.d r4,r3
- bound.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r4
- move.d r4,r3
- bound.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- bound.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 5432f789
-
- moveq -1,r3
- moveq 2,r4
- bound.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- moveq -1,r4
- bound.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq -1,r3
- bound.w r3,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0xffff,r4
- move.d r4,r3
- bound.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0xfedaffff,r4
- move.d r4,r3
- bound.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- bound.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 f789
-
- moveq -1,r3
- moveq 2,r4
- bound.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- moveq -1,r4
- bound.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xff,r4
- move.d r4,r3
- bound.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 ff
-
- move.d 0xfeda49ff,r4
- move.d r4,r3
- bound.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 ff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- bound.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 89
-
- move.d 0xfeda4956,r3
- move.d 0xfeda4953,r4
- bound.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 feda4953
-
- move.d 0xfeda4962,r3
- move.d 0xfeda4963,r4
- bound.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 feda4962
-
- move.d 0xfeda4956,r3
- move.d 0,r4
- bound.d r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0xfeda4956,r4
- move.d 0,r3
- bound.d r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_btst.s b/tests/tcg/cris/bare/check_btst.s
deleted file mode 100644
index 485deb2..0000000
--- a/tests/tcg/cris/bare/check_btst.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1111\n
-
- .include "testutils.inc"
- start
- clearf nzvc
- moveq -1,r3
- .if 1 ;..asm.arch.cris.v32
- .else
- setf vc
- .endif
- btstq 0,r3
- test_cc 1 0 0 0
-
- moveq 2,r3
- btstq 1,r3
- test_cc 1 0 0 0
-
- moveq 4,r3
- btstq 1,r3
- test_cc 0 1 0 0
-
- moveq -1,r3
- btstq 31,r3
- test_cc 1 0 0 0
-
- move.d 0x5a67f19f,r3
- btstq 12,r3
- test_cc 1 0 0 0
-
- move.d 0xda67f19f,r3
- move.d 29,r4
- btst r4,r3
- test_cc 0 0 0 0
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- btst r4,r3
- test_cc 1 0 0 0
-
- move.d 0xda67f191,r3
- move.d 33,r4
- btst r4,r3
- test_cc 0 0 0 0
-
- moveq -1,r3
- moveq 0,r4
- btst r4,r3
- test_cc 1 0 0 0
-
- moveq 2,r3
- moveq 1,r4
- btst r4,r3
- test_cc 1 0 0 0
-
- moveq -1,r3
- moveq 31,r4
- btst r4,r3
- test_cc 1 0 0 0
-
- moveq 4,r3
- btstq 1,r3
- test_cc 0 1 0 0
-
- moveq -1,r3
- moveq 15,r4
- btst r4,r3
- test_cc 1 0 0 0
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- btst r4,r3
- test_cc 1 0 0 0
-
- move.d 0x5a678000,r3
- moveq 11,r4
- btst r4,r3
- test_cc 0 1 0 0
-
- move.d 0x5a67f19f,r3
- btst r3,r3
- test_cc 0 0 0 0
-
- move.d 0x1111,r3
- checkr3 1111
-
- ; check that X gets cleared and that only the NZ flags are touched.
- ;; move.d 0xff, $r0
- ;; move $r0, $ccs
- ;; btst r3,r3
- ;; move $ccs, $r0
- ;; and.d 0xff, $r0
- ;; cmp.d 0xe3, $r0
- ;; test_cc 0 1 0 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_clearfv32.s b/tests/tcg/cris/bare/check_clearfv32.s
deleted file mode 100644
index 4e91360..0000000
--- a/tests/tcg/cris/bare/check_clearfv32.s
+++ /dev/null
@@ -1,19 +0,0 @@
-# mach: crisv32
-# output: ef\nef\n
-
-; Check that "clearf x" doesn't trivially fail.
-
- .include "testutils.inc"
- start
- setf puixnzvc
- clearf x ; Actually, x would be cleared by almost-all other insns.
- move ccs,r3
- and.d 0xff, $r3
- checkr3 ef
-
- setf puixnzvc
- moveq 0, $r3 ; moveq should only clear the xflag.
- move ccs,r3
- and.d 0xff, $r3
- checkr3 ef
- quit
diff --git a/tests/tcg/cris/bare/check_clrjmp1.s b/tests/tcg/cris/bare/check_clrjmp1.s
deleted file mode 100644
index 45a7005..0000000
--- a/tests/tcg/cris/bare/check_clrjmp1.s
+++ /dev/null
@@ -1,36 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: ffffff00\n
-
-; A bug resulting in a non-effectual clear.b discovered running the GCC
-; testsuite; jump actually wrote to p0.
-
- .include "testutils.inc"
-
- start
- jump 1f
- nop
- .p2align 8
-1:
- move.d y,r4
-
- .if 0 ;0 == ..asm.arch.cris.v32
-; There was a bug causing this insn to set special register p0
-; (byte-clear) to 8 (low 8 bits of location after insn).
- jump [r4+]
- .endif
-
-1:
- move.d 0f,r4
-
-; The corresponding bug would cause this insn too, to set p0.
- jump r4
- nop
- quit
-0:
- moveq -1,r3
- clear.b r3
- checkr3 ffffff00
- quit
-
-y:
- .dword 1b
diff --git a/tests/tcg/cris/bare/check_cmp-2.s b/tests/tcg/cris/bare/check_cmp-2.s
deleted file mode 100644
index 414d370..0000000
--- a/tests/tcg/cris/bare/check_cmp-2.s
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-.include "testutils.inc"
-
- start
-
- move.d 4294967283, $r0
- move.d $r0, $r10
- cmp.d $r0, $r10
- beq 1f
- move.d $r10, $r3
- fail
-1:
- pass
- quit
diff --git a/tests/tcg/cris/bare/check_cmpc.s b/tests/tcg/cris/bare/check_cmpc.s
deleted file mode 100644
index 267c9ba..0000000
--- a/tests/tcg/cris/bare/check_cmpc.s
+++ /dev/null
@@ -1,86 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649282\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- cmp.d -2,r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- cmp.d 1,r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- cmp.d -0xffff,r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- moveq -1,r3
- cmp.d 1,r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- cmp.d -0x5432f789,r3
- test_cc 1 0 1 1
- checkr3 78134452
-
- moveq -1,r3
- cmp.w -2,r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- cmp.w 1,r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- cmp.w 1,r3
- test_cc 1 0 0 0
- checkr3 ffff
-
- move.d 0xfedaffff,r3
- cmp.w 1,r3
- test_cc 1 0 0 0
- checkr3 fedaffff
-
- move.d 0x78134452,r3
- cmp.w 0x877,r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- moveq -1,r3
- cmp.b -2,r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- cmp.b 1,r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xff,r3
- cmp.b 1,r3
- test_cc 1 0 0 0
- checkr3 ff
-
- move.d 0xfeda49ff,r3
- cmp.b 1,r3
- test_cc 1 0 0 0
- checkr3 feda49ff
-
- move.d 0x78134452,r3
- cmp.b 0x77,r3
- test_cc 1 0 0 1
- checkr3 78134452
-
- move.d 0x85649282,r3
- cmp.b 0x82,r3
- test_cc 0 1 0 0
- checkr3 85649282
-
- quit
diff --git a/tests/tcg/cris/bare/check_cmpm.s b/tests/tcg/cris/bare/check_cmpm.s
deleted file mode 100644
index e4dde15..0000000
--- a/tests/tcg/cris/bare/check_cmpm.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649222\n
-
- .include "testutils.inc"
- .data
-x:
- .dword -2,1,-0xffff,1,-0x5432f789
- .word -2,1,1,0x877
- .byte -2,1,0x77
- .byte 0x22
-
- start
- moveq -1,r3
- move.d x,r5
- cmp.d [r5+],r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- cmp.d [r5],r3
- test_cc 0 0 0 0
- addq 4,r5
- checkr3 2
-
- move.d 0xffff,r3
- cmp.d [r5+],r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- moveq -1,r3
- cmp.d [r5+],r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- cmp.d [r5+],r3
- test_cc 1 0 1 1
- checkr3 78134452
-
- moveq -1,r3
- cmp.w [r5+],r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- cmp.w [r5+],r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- cmp.w [r5],r3
- test_cc 1 0 0 0
- checkr3 ffff
-
- move.d 0xfedaffff,r3
- cmp.w [r5+],r3
- test_cc 1 0 0 0
- checkr3 fedaffff
-
- move.d 0x78134452,r3
- cmp.w [r5+],r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- moveq -1,r3
- cmp.b [r5],r3
- test_cc 0 0 0 0
- addq 1,r5
- checkr3 ffffffff
-
- moveq 2,r3
- cmp.b [r5],r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xff,r3
- cmp.b [r5],r3
- test_cc 1 0 0 0
- checkr3 ff
-
- move.d 0xfeda49ff,r3
- cmp.b [r5+],r3
- test_cc 1 0 0 0
- checkr3 feda49ff
-
- move.d 0x78134452,r3
- cmp.b [r5+],r3
- test_cc 1 0 0 1
- checkr3 78134452
-
- move.d 0x85649222,r3
- cmp.b [r5],r3
- test_cc 0 1 0 0
- checkr3 85649222
-
- quit
diff --git a/tests/tcg/cris/bare/check_cmpq.s b/tests/tcg/cris/bare/check_cmpq.s
deleted file mode 100644
index 5469141..0000000
--- a/tests/tcg/cris/bare/check_cmpq.s
+++ /dev/null
@@ -1,75 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1\n1f\n1f\nffffffe1\nffffffe1\nffffffe0\n0\n0\nffffffff\nffffffff\n10000\n100\n5678900\n
-
- .include "testutils.inc"
- start
- moveq 1,r3
- cmpq 1,r3
- test_cc 0 1 0 0
- checkr3 1
-
- cmpq -1,r3
- test_cc 0 0 0 1
- checkr3 1
-
- cmpq 31,r3
- test_cc 1 0 0 1
- checkr3 1
-
- moveq 31,r3
- cmpq 31,r3
- test_cc 0 1 0 0
- checkr3 1f
-
- cmpq -31,r3
- test_cc 0 0 0 1
- checkr3 1f
-
- movs.b -31,r3
- cmpq -31,r3
- test_cc 0 1 0 0
- checkr3 ffffffe1
-
- cmpq -32,r3
- test_cc 0 0 0 0
- checkr3 ffffffe1
-
- movs.b -32,r3
- cmpq -32,r3
- test_cc 0 1 0 0
- checkr3 ffffffe0
-
- moveq 0,r3
- cmpq 1,r3
- test_cc 1 0 0 1
- checkr3 0
-
- cmpq -32,r3
- test_cc 0 0 0 1
- checkr3 0
-
- moveq -1,r3
- cmpq 1,r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- cmpq -1,r3
- test_cc 0 1 0 0
- checkr3 ffffffff
-
- move.d 0x10000,r3
- cmpq 1,r3
- test_cc 0 0 0 0
- checkr3 10000
-
- move.d 0x100,r3
- cmpq 1,r3
- test_cc 0 0 0 0
- checkr3 100
-
- move.d 0x5678900,r3
- cmpq 7,r3
- test_cc 0 0 0 0
- checkr3 5678900
-
- quit
diff --git a/tests/tcg/cris/bare/check_cmpr.s b/tests/tcg/cris/bare/check_cmpr.s
deleted file mode 100644
index b30af7a..0000000
--- a/tests/tcg/cris/bare/check_cmpr.s
+++ /dev/null
@@ -1,102 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649222\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq -2,r4
- cmp.d r4,r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- cmp.d r4,r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- move.d -0xffff,r4
- cmp.d r4,r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- moveq 1,r4
- moveq -1,r3
- cmp.d r4,r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d -0x5432f789,r4
- move.d 0x78134452,r3
- cmp.d r4,r3
- test_cc 1 0 1 1
- checkr3 78134452
-
- moveq -1,r3
- moveq -2,r4
- cmp.w r4,r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- cmp.w r4,r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- move.d -0xffff,r4
- cmp.w r4,r3
- test_cc 1 0 0 0
- checkr3 ffff
-
- move.d 0xfedaffff,r3
- move.d -0xfedaffff,r4
- cmp.w r4,r3
- test_cc 1 0 0 0
- checkr3 fedaffff
-
- move.d -0x5432f789,r4
- move.d 0x78134452,r3
- cmp.w r4,r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- moveq -1,r3
- moveq -2,r4
- cmp.b r4,r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- cmp.b r4,r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d -0xff,r4
- move.d 0xff,r3
- cmp.b r4,r3
- test_cc 1 0 0 0
- checkr3 ff
-
- move.d -0xfeda49ff,r4
- move.d 0xfeda49ff,r3
- cmp.b r4,r3
- test_cc 1 0 0 0
- checkr3 feda49ff
-
- move.d -0x5432f789,r4
- move.d 0x78134452,r3
- cmp.b r4,r3
- test_cc 1 0 0 1
- checkr3 78134452
-
- move.d 0x85649222,r3
- move.d 0x77445622,r4
- cmp.b r4,r3
- test_cc 0 1 0 0
- checkr3 85649222
-
- quit
diff --git a/tests/tcg/cris/bare/check_cmpxc.s b/tests/tcg/cris/bare/check_cmpxc.s
deleted file mode 100644
index b237a93..0000000
--- a/tests/tcg/cris/bare/check_cmpxc.s
+++ /dev/null
@@ -1,92 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\n2\n2\nffff\nffff\nffff\nffff\nffffffff\nffffffff\nffffffff\n78134452\n78134452\n78134452\n78134452\n4452\n80000032\n
-
- .include "testutils.inc"
- start
- moveq 2,r3
- cmps.b 0xff,r3
- test_cc 0 0 0 1
- checkr3 2
-
- moveq 2,r3
- cmps.w 0xffff,r3
- test_cc 0 0 0 1
- checkr3 2
-
- moveq 2,r3
- cmpu.b 0xff,r3
- test_cc 1 0 0 1
- checkr3 2
-
- moveq 2,r3
- move.d 0xffffffff,r4
- cmpu.w -1,r3
- test_cc 1 0 0 1
- checkr3 2
-
- move.d 0xffff,r3
- cmpu.b -1,r3
- test_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0xffff,r3
- cmpu.w -1,r3
- test_cc 0 1 0 0
- checkr3 ffff
-
- move.d 0xffff,r3
- cmps.b 0xff,r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- move.d 0xffff,r3
- cmps.w 0xffff,r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- moveq -1,r3
- cmps.b 0xff,r3
- test_cc 0 1 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- cmps.w 0xff,r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- cmps.w 0xffff,r3
- test_cc 0 1 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- cmpu.b 0x89,r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- move.d 0x78134452,r3
- cmps.b 0x89,r3
- test_cc 0 0 0 1
- checkr3 78134452
-
- move.d 0x78134452,r3
- cmpu.w 0xf789,r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- move.d 0x78134452,r3
- cmps.w 0xf789,r3
- test_cc 0 0 0 1
- checkr3 78134452
-
- move.d 0x4452,r3
- cmps.w 0x8002,r3
- test_cc 0 0 0 1
- checkr3 4452
-
- move.d 0x80000032,r3
- cmpu.w 0x764,r3
- test_cc 0 0 1 0
- checkr3 80000032
-
- quit
diff --git a/tests/tcg/cris/bare/check_cmpxm.s b/tests/tcg/cris/bare/check_cmpxm.s
deleted file mode 100644
index 87ea5bf..0000000
--- a/tests/tcg/cris/bare/check_cmpxm.s
+++ /dev/null
@@ -1,106 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\n2\n2\nffff\nffff\nffff\nffff\nffffffff\nffffffff\nffffffff\n78134452\n78134452\n78134452\n78134452\n4452\n80000032\n
-
- .include "testutils.inc"
- .data
-x:
- .byte 0xff
- .word 0xffff
- .word 0xff
- .word 0xffff
- .byte 0x89
- .word 0xf789
- .word 0x8002
- .word 0x764
-
- start
- moveq 2,r3
- move.d x,r5
- cmps.b [r5+],r3
- test_cc 0 0 0 1
- checkr3 2
-
- moveq 2,r3
- cmps.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 2
-
- moveq 2,r3
- subq 3,r5
- cmpu.b [r5+],r3
- test_cc 1 0 0 1
- checkr3 2
-
- moveq 2,r3
- cmpu.w [r5+],r3
- test_cc 1 0 0 1
- subq 3,r5
- checkr3 2
-
- move.d 0xffff,r3
- cmpu.b [r5],r3
- test_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0xffff,r3
- cmpu.w [r5],r3
- test_cc 0 1 0 0
- checkr3 ffff
-
- move.d 0xffff,r3
- cmps.b [r5],r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- move.d 0xffff,r3
- cmps.w [r5],r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- moveq -1,r3
- cmps.b [r5],r3
- test_cc 0 1 0 0
- addq 3,r5
- checkr3 ffffffff
-
- moveq -1,r3
- cmps.w [r5+],r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- cmps.w [r5+],r3
- test_cc 0 1 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- cmpu.b [r5],r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- move.d 0x78134452,r3
- cmps.b [r5+],r3
- test_cc 0 0 0 1
- checkr3 78134452
-
- move.d 0x78134452,r3
- cmpu.w [r5],r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- move.d 0x78134452,r3
- cmps.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 78134452
-
- move.d 0x4452,r3
- cmps.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 4452
-
- move.d 0x80000032,r3
- cmpu.w [r5+],r3
- test_cc 0 0 1 0
- checkr3 80000032
-
- quit
diff --git a/tests/tcg/cris/bare/check_dstep.s b/tests/tcg/cris/bare/check_dstep.s
deleted file mode 100644
index bd43b83..0000000
--- a/tests/tcg/cris/bare/check_dstep.s
+++ /dev/null
@@ -1,42 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: fffffffc\n4\nffff\nfffffffe\n9bf3911b\n0\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- dstep r4,r3
- test_move_cc 1 0 0 0
- checkr3 fffffffc
-
- moveq 2,r3
- moveq -1,r4
- dstep r4,r3
- test_move_cc 0 0 0 0
- checkr3 4
-
- move.d 0xffff,r4
- move.d r4,r3
- dstep r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r4
- move.d r4,r3
- dstep r4,r3
- test_move_cc 1 0 0 0
- checkr3 fffffffe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- dstep r4,r3
- test_move_cc 1 0 0 0
- checkr3 9bf3911b
-
- move.d 0xffff,r3
- move.d 0x1fffe,r4
- dstep r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_jsr.s b/tests/tcg/cris/bare/check_jsr.s
deleted file mode 100644
index 1060237..0000000
--- a/tests/tcg/cris/bare/check_jsr.s
+++ /dev/null
@@ -1,85 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 0\n0\n0\n0\n0\n0\n
-
-# Test that jsr Rn and jsr [PC+] work.
-
- .include "testutils.inc"
- start
-x:
- move.d 0f,r6
- setf nzvc
- jsr r6
- .if 1; ..asm.arch.cris.v32
- nop
- .endif
-0:
- test_move_cc 1 1 1 1
- move srp,r3
- sub.d 0b,r3
- checkr3 0
-
- move.d 1f,r0
- setf nzvc
- jsr r0
- .if 1 ; ..asm.arch.cris.v32
- moveq 0,r0
- .endif
-6:
- nop
- quit
-
-2:
- test_move_cc 0 0 0 0
- move srp,r3
- sub.d 3f,r3
- checkr3 0
- jsr 4f
- .if 1 ; ..asm.arch.cris.v32
- nop
- .endif
-7:
- nop
- quit
-
-8:
- move srp,r3
- sub.d 7b,r3
- checkr3 0
- quit
-
-4:
- move srp,r3
- sub.d 7b,r3
- checkr3 0
- move.d 5f,r3
- jump r3
- .if 1; ..asm.arch.cris.v32
- moveq 0,r3
- .endif
- quit
-
- .space 32770,0
-1:
- test_move_cc 1 1 1 1
- move srp,r3
- sub.d 6b,r3
- checkr3 0
-
- clearf cznv
- jsr 2b
- .if 1; ..asm.arch.cris.v32
- nop
- .endif
-3:
-
- quit
-
-5:
- move srp,r3
- sub.d 7b,r3
- checkr3 0
- jump 8b
- .if 1 ; ..asm.arch.cris.v32
- nop
- .endif
- quit
diff --git a/tests/tcg/cris/bare/check_lapc.s b/tests/tcg/cris/bare/check_lapc.s
deleted file mode 100644
index 9a6150b..0000000
--- a/tests/tcg/cris/bare/check_lapc.s
+++ /dev/null
@@ -1,78 +0,0 @@
-# mach: crisv32
-# output: 0\n0\nfffffffa\nfffffffe\nffffffda\n1e\n1e\n0\n
-
-.include "testutils.inc"
-
-; To accommodate dumpr3 with more than one instruction, keep it
-; out of lapc operand ranges and difference calculations.
-
- start
- lapc.d 0f,r3
-0:
- sub.d .,r3
- checkr3 0
-
- lapcq 0f,r3
-0:
- sub.d .,r3
- checkr3 0
-
- lapc.d .,r3
- sub.d .,r3
- checkr3 fffffffa
-
- lapcq .,r3
- sub.d .,r3
- checkr3 fffffffe
-
-0:
- .rept 16
- nop
- .endr
- lapc.d 0b,r3
- sub.d .,r3
- checkr3 ffffffda
-
- setf zcvn
- lapc.d 0f,r3
- test_cc 1 1 1 1
- sub.d .,r3
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
-0:
- checkr3 1e
-0:
- lapcq 0f,r3
- sub.d 0b,r3
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
-0:
- checkr3 1e
- clearf cn
- setf zv
-1:
- lapcq .,r3
- test_cc 0 1 1 0
- sub.d 1b,r3
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_lsl.s b/tests/tcg/cris/bare/check_lsl.s
deleted file mode 100644
index 9e2ddd7..0000000
--- a/tests/tcg/cris/bare/check_lsl.s
+++ /dev/null
@@ -1,217 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n4\n80000000\nffff8000\n7f19f000\n80000000\n0\n0\n699fc67c\nffffffff\n4\n80000000\nffff8000\n7f19f000\nda670000\nda670000\nda670000\nda67c67c\nffffffff\nfffafffe\n4\nffff0000\nffff8000\n5a67f000\nda67f100\nda67f100\nda67f100\nda67f17c\nfff3faff\nfff3fafe\n4\nffffff00\nffffff00\nffffff80\n5a67f100\n5a67f1f0\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- lslq 0,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- lslq 1,r3
- test_move_cc 0 0 0 0
- checkr3 4
-
- moveq -1,r3
- lslq 31,r3
- test_move_cc 1 0 0 0
- checkr3 80000000
-
- moveq -1,r3
- lslq 15,r3
- test_move_cc 1 0 0 0
- checkr3 ffff8000
-
- move.d 0x5a67f19f,r3
- lslq 12,r3
- test_move_cc 0 0 0 0
- checkr3 7f19f000
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- lsl.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 80000000
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- lsl.d r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- lsl.d r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- lsl.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 699fc67c
-
- moveq -1,r3
- moveq 0,r4
- lsl.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- lsl.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 4
-
- moveq -1,r3
- moveq 31,r4
- lsl.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 80000000
-
- moveq -1,r3
- moveq 15,r4
- lsl.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffff8000
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- lsl.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 7f19f000
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- lsl.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 da670000
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- lsl.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 da670000
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- lsl.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 da670000
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- lsl.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67c67c
-
- moveq -1,r3
- moveq 0,r4
- lsl.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0xfffaffff,r3
- moveq 1,r4
- lsl.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 fffafffe
-
- moveq 2,r3
- moveq 1,r4
- lsl.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 4
-
- moveq -1,r3
- moveq 31,r4
- lsl.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffff0000
-
- moveq -1,r3
- moveq 15,r4
- lsl.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffff8000
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- lsl.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 5a67f000
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- lsl.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 da67f100
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- lsl.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 da67f100
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- lsl.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 da67f100
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- lsl.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 da67f17c
-
- move.d 0xfff3faff,r3
- moveq 0,r4
- lsl.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 fff3faff
-
- move.d 0xfff3faff,r3
- moveq 1,r4
- lsl.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 fff3fafe
-
- moveq 2,r3
- moveq 1,r4
- lsl.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 4
-
- moveq -1,r3
- moveq 31,r4
- lsl.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffffff00
-
- moveq -1,r3
- moveq 15,r4
- lsl.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffffff00
-
- moveq -1,r3
- moveq 7,r4
- lsl.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffff80
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- lsl.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 5a67f100
-
- move.d 0x5a67f19f,r3
- moveq 4,r4
- lsl.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 5a67f1f0
-
- quit
diff --git a/tests/tcg/cris/bare/check_lsr.s b/tests/tcg/cris/bare/check_lsr.s
deleted file mode 100644
index 18fdbef..0000000
--- a/tests/tcg/cris/bare/check_lsr.s
+++ /dev/null
@@ -1,218 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n1\n1\n1ffff\n5a67f\n1\n0\n0\n3699fc67\nffffffff\n1\n1\n1ffff\n5a67f\nda670000\nda670000\nda670000\nda673c67\nffffffff\nffff7fff\n1\nffff0000\nffff0001\n5a67000f\nda67f100\nda67f100\nda67f100\nda67f127\nffffffff\nffffff7f\n1\nffffff00\nffffff00\nffffff01\n5a67f100\n5a67f109\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- lsrq 0,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- lsrq 1,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- lsrq 31,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- lsrq 15,r3
- test_move_cc 0 0 0 0
- checkr3 1ffff
-
- move.d 0x5a67f19f,r3
- lsrq 12,r3
- test_move_cc 0 0 0 0
- checkr3 5a67f
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- lsr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- lsr.d r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- lsr.d r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- lsr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 3699fc67
-
- moveq -1,r3
- moveq 0,r4
- lsr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- lsr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- moveq 31,r4
- lsr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- moveq 15,r4
- lsr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 1ffff
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- lsr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 5a67f
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- lsr.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 da670000
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- lsr.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 da670000
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- lsr.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 da670000
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- lsr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 da673c67
-
- moveq -1,r3
- moveq 0,r4
- lsr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 1,r4
- lsr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff7fff
-
- moveq 2,r3
- moveq 1,r4
- lsr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
-;; FIXME: this was wrong. Z should be set.
- moveq -1,r3
- moveq 31,r4
- lsr.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffff0000
-
- moveq -1,r3
- moveq 15,r4
- lsr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0001
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- lsr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 5a67000f
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- lsr.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 da67f100
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- lsr.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 da67f100
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- lsr.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 da67f100
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- lsr.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 da67f127
-
- moveq -1,r3
- moveq 0,r4
- lsr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 1,r4
- lsr.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffffff7f
-
- moveq 2,r3
- moveq 1,r4
- lsr.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- moveq 31,r4
- lsr.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffffff00
-
- moveq -1,r3
- moveq 15,r4
- lsr.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffffff00
-
- moveq -1,r3
- moveq 7,r4
- lsr.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffffff01
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- lsr.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 5a67f100
-
- move.d 0x5a67f19f,r3
- moveq 4,r4
- lsr.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 5a67f109
-
- quit
diff --git a/tests/tcg/cris/bare/check_mcp.s b/tests/tcg/cris/bare/check_mcp.s
deleted file mode 100644
index e65ccdd..0000000
--- a/tests/tcg/cris/bare/check_mcp.s
+++ /dev/null
@@ -1,49 +0,0 @@
-# mach: crisv32
-# output: fffffffe\n1\n1ffff\nfffffffe\ncc463bdc\n4c463bdc\n0\n
-
- .include "testutils.inc"
- start
-
-; Set R, clear C.
- move 0x100,ccs
- moveq -5,r3
- move 2,mof
- mcp mof,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
-
- moveq 2,r3
- move -1,srp
- mcp srp,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move 0xffff,srp
- move srp,r3
- mcp srp,r3
- test_cc 0 0 0 0
- checkr3 1ffff
-
- move -1,mof
- move mof,r3
- mcp mof,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
-
- move 0x5432f789,mof
- move.d 0x78134452,r3
- mcp mof,r3
- test_cc 1 0 1 0
- checkr3 cc463bdc
-
- move 0x80000000,srp
- mcp srp,r3
- test_cc 0 0 1 0
- checkr3 4c463bdc
-
- move 0xb3b9c423,srp
- mcp srp,r3
- test_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movdelsr1.s b/tests/tcg/cris/bare/check_movdelsr1.s
deleted file mode 100644
index 300cc87..0000000
--- a/tests/tcg/cris/bare/check_movdelsr1.s
+++ /dev/null
@@ -1,33 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: aa117acd\n
-# output: eeaabb42\n
-
-; Bug with move to special register in delay slot, due to
-; special flush-insn-cache simulator use. Ordinary move worked;
-; special register caused branch to fail.
-
- .include "testutils.inc"
- start
- move -1,srp
-
- move.d 0xaa117acd,r1
- moveq 3,r9
- cmpq 1,r9
- bhi 0f
- move.d r1,r3
-
- fail
-0:
- checkr3 aa117acd
-
- move.d 0xeeaabb42,r1
- moveq 3,r9
- cmpq 1,r9
- bhi 0f
- move r1,srp
-
- fail
-0:
- move srp,r3
- checkr3 eeaabb42
- quit
diff --git a/tests/tcg/cris/bare/check_movecr.s b/tests/tcg/cris/bare/check_movecr.s
deleted file mode 100644
index da8ec26..0000000
--- a/tests/tcg/cris/bare/check_movecr.s
+++ /dev/null
@@ -1,37 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: ffffff42\n94\nffff4321\n9234\n76543210\n76540000\n
-
-; Move constant byte, word, dword to register. Check that no extension is
-; performed, that only part of the register is set.
-
- .include "testutils.inc"
- startnostack
- moveq -1,r3
- move.b 0x42,r3
- test_move_cc 0 0 0 0
- checkr3 ffffff42
-
- moveq 0,r3
- move.b 0x94,r3
- test_move_cc 1 0 0 0
- checkr3 94
-
- moveq -1,r3
- move.w 0x4321,r3
- test_move_cc 0 0 0 0
- checkr3 ffff4321
-
- moveq 0,r3
- move.w 0x9234,r3
- test_move_cc 1 0 0 0
- checkr3 9234
-
- move.d 0x76543210,r3
- test_move_cc 0 0 0 0
- checkr3 76543210
-
- move.w 0,r3
- test_move_cc 0 1 0 0
- checkr3 76540000
-
- quit
diff --git a/tests/tcg/cris/bare/check_movei.s b/tests/tcg/cris/bare/check_movei.s
deleted file mode 100644
index bbfa633..0000000
--- a/tests/tcg/cris/bare/check_movei.s
+++ /dev/null
@@ -1,50 +0,0 @@
-# mach: crisv32
-# output: fffffffe\n
-# output: fffffffe\n
-
-; Check basic integral-write semantics regarding flags.
-
- .include "testutils.inc"
- start
-
- move.d 0, $r3
-; A write that works. Check that flags are set correspondingly.
- move.d d,r4
- ;; store to bring it into the tlb with the right prot bits
- move.d r3,[r4]
- moveq -2,r5
- setf c
- clearf p
- move.d [r4],r3
- ax
- move.d r5,[r4]
- move.d [r4],r3
-
- bcc 0f
- nop
- fail
-
-0:
- checkr3 fffffffe
-
-; A write that fails; check flags too.
- move.d d,r4
- moveq 23,r5
- setf p
- clearf c
- move.d [r4],r3
- ax
- move.d r5,[r4]
- move.d [r4],r3
-
- bcs 0f
- nop
- fail
-
-0:
- checkr3 fffffffe
- quit
-
- .data
-d:
- .dword 42424242
diff --git a/tests/tcg/cris/bare/check_movemr.s b/tests/tcg/cris/bare/check_movemr.s
deleted file mode 100644
index 88489de..0000000
--- a/tests/tcg/cris/bare/check_movemr.s
+++ /dev/null
@@ -1,78 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 12345678\n10234567\n12345678\n12344567\n12344523\n76543210\nffffffaa\naa\n9911\nffff9911\n78\n56\n3456\n6712\n
-
- .include "testutils.inc"
- start
-
- .data
-mem1:
- .dword 0x12345678
-mem2:
- .word 0x4567
-mem3:
- .byte 0x23
- .dword 0x76543210
- .byte 0xaa,0x11,0x99
-
- .text
- move.d mem1,r2
- move.d [r2],r3
- test_move_cc 0 0 0 0
- checkr3 12345678
-
- move.d mem2,r3
- move.d [r3],r3
- test_move_cc 0 0 0 0
- checkr3 10234567
-
- move.d mem1,r2
- move.d [r2+],r3
- test_move_cc 0 0 0 0
- checkr3 12345678
-
- move.w [r2+],r3
- test_move_cc 0 0 0 0
- checkr3 12344567
-
- move.b [r2+],r3
- test_move_cc 0 0 0 0
- checkr3 12344523
-
- move.d [r2+],r3
- test_move_cc 0 0 0 0
- checkr3 76543210
-
- movs.b [r2],r3
- test_move_cc 1 0 0 0
- checkr3 ffffffaa
-
- movu.b [r2+],r3
- test_move_cc 0 0 0 0
- checkr3 aa
-
- movu.w [r2],r3
- test_move_cc 0 0 0 0
- checkr3 9911
-
- movs.w [r2+],r3
- test_move_cc 1 0 0 0
- checkr3 ffff9911
-
- move.d mem1,r13
- movs.b [r13+],r3
- test_move_cc 0 0 0 0
- checkr3 78
-
- movu.b [r13],r3
- test_move_cc 0 0 0 0
- checkr3 56
-
- movs.w [r13+],r3
- test_move_cc 0 0 0 0
- checkr3 3456
-
- movu.w [r13+],r3
- test_move_cc 0 0 0 0
- checkr3 6712
-
- quit
diff --git a/tests/tcg/cris/bare/check_movemrv32.s b/tests/tcg/cris/bare/check_movemrv32.s
deleted file mode 100644
index 53950ab..0000000
--- a/tests/tcg/cris/bare/check_movemrv32.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv32
-# output: 15\n7\n2\nffff1234\nb\n16\nf\n2\nffffffef\nf\nffff1234\nf\nfffffff4\nd\nfffffff2\n10\nfffffff2\nd\n
-
- .include "testutils.inc"
- .data
-x:
- .dword 8,9,10,11
-y:
- .dword -12,13,-14,15,16
-
- start
- moveq 7,r0
- moveq 2,r1
- move.d 0xffff1234,r2
- moveq 21,r3
- move.d x,r4
- setf zcvn
- movem r2,[r4+]
- test_cc 1 1 1 1
- subq 12,r4
-
- checkr3 15
-
- move.d [r4+],r3
- checkr3 7
-
- move.d [r4+],r3
- checkr3 2
-
- move.d [r4+],r3
- checkr3 ffff1234
-
- move.d [r4+],r3
- checkr3 b
-
- subq 16,r4
- moveq 22,r0
- moveq 15,r1
- clearf zcvn
- movem r0,[r4]
- test_cc 0 0 0 0
- move.d [r4+],r3
- checkr3 16
-
- move.d r1,r3
- checkr3 f
-
- move.d [r4+],r3
- checkr3 2
-
- subq 8,r4
- moveq 10,r2
- moveq -17,r0
- clearf zc
- setf vn
- movem r1,[r4]
- test_cc 1 0 1 0
- move.d [r4+],r3
- checkr3 ffffffef
-
- move.d [r4+],r3
- checkr3 f
-
- move.d [r4+],r3
- checkr3 ffff1234
-
- move.d y,r4
- setf zc
- clearf vn
- movem [r4+],r3
- test_cc 0 1 0 1
- checkr3 f
-
- move.d r0,r3
- checkr3 fffffff4
-
- move.d r1,r3
- checkr3 d
-
- move.d r2,r3
- checkr3 fffffff2
-
- move.d [r4],r3
- checkr3 10
-
- subq 8,r4
- setf zcvn
- movem [r4+],r0
- test_cc 1 1 1 1
- move.d r0,r3
- checkr3 fffffff2
-
- move.d r1,r3
- checkr3 d
-
- quit
diff --git a/tests/tcg/cris/bare/check_mover.s b/tests/tcg/cris/bare/check_mover.s
deleted file mode 100644
index b4db595..0000000
--- a/tests/tcg/cris/bare/check_mover.s
+++ /dev/null
@@ -1,28 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: ffffff05\nffff0005\n5\nffffff00\n
-
-; Move between registers. Check that just the subreg is copied.
-
- .include "testutils.inc"
- startnostack
- moveq -30,r3
- moveq 5,r4
- move.b r4,r3
- test_move_cc 0 0 0 0 ; FIXME
- checkr3 ffffff05
-
- move.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0005
-
- move.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq -1,r3
- moveq 0,r4
- move.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffffff00
-
- quit
diff --git a/tests/tcg/cris/bare/check_moverm.s b/tests/tcg/cris/bare/check_moverm.s
deleted file mode 100644
index eabc958..0000000
--- a/tests/tcg/cris/bare/check_moverm.s
+++ /dev/null
@@ -1,45 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 7823fec2\n10231879\n102318fe\n
-
- .include "testutils.inc"
- start
-
- .data
-mem1:
- .dword 0x12345678
-mem2:
- .word 0x4567
-mem3:
- .byte 0x23
- .dword 0x76543210
- .byte 0xaa,0x11,0x99
-
- .text
- move.d mem1,r2
- move.d 0x7823fec2,r4
- setf nzvc
- move.d r4,[r2+]
- test_cc 1 1 1 1
- subq 4,r2
- move.d [r2],r3
- checkr3 7823fec2
-
- move.d mem2,r3
- move.d 0x45231879,r4
- clearf nzvc
- move.w r4,[r3]
- test_cc 0 0 0 0
- move.d [r3],r3
- checkr3 10231879
-
- move.d mem2,r2
- moveq -2,r4
- clearf nc
- setf zv
- move.b r4,[r2+]
- test_cc 0 1 1 0
- subq 1,r2
- move.d [r2],r3
- checkr3 102318fe
-
- quit
diff --git a/tests/tcg/cris/bare/check_movmp.s b/tests/tcg/cris/bare/check_movmp.s
deleted file mode 100644
index 7fc11f0..0000000
--- a/tests/tcg/cris/bare/check_movmp.s
+++ /dev/null
@@ -1,131 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: ffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n
-
-# Test generic "move Ps,[]" and "move [],Pd" insns; the ones with
-# functionality common to all models.
-
- .include "testutils.inc"
- start
-
- .data
-filler:
- .byte 0xaa
- .word 0x4433
- .dword 0x55778866
- .byte 0xcc
-
- .text
-; Test that writing to zero-registers is a nop
- .if 0
- ; We used to just ignore the writes, but now an error is emitted. We
- ; keep the test-code but disabled, in case we need to change this again.
- move 0xaa,p0
- move 0x4433,p4
- move 0x55774433,p8
- .endif
-
- moveq -1,r3
- setf zcvn
- clear.b r3
- test_cc 1 1 1 1
- checkr3 ffffff00
-
- moveq -1,r3
- clearf zcvn
- clear.w r3
- test_cc 0 0 0 0
- checkr3 ffff0000
-
- moveq -1,r3
- clear.d r3
- checkr3 0
-
-; "Write" using ordinary memory references too.
- .if 0 ; See ".if 0" above.
- move.d filler,r6
- move [r6],p0
- move [r6],p4
- move [r6],p8
- .endif
-
-# ffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n
-
- moveq -1,r3
- clear.b r3
- checkr3 ffffff00
-
- moveq -1,r3
- clear.w r3
- checkr3 ffff0000
-
- moveq -1,r3
- clear.d r3
- checkr3 0
-
-; And postincremented.
- .if 0 ; See ".if 0" above.
- move [r6+],p0
- move [r6+],p4
- move [r6+],p8
- .endif
-
-# ffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n
-
- moveq -1,r3
- clear.b r3
- checkr3 ffffff00
-
- moveq -1,r3
- clear.w r3
- checkr3 ffff0000
-
- moveq -1,r3
- clear.d r3
- checkr3 0
-
-; Now see that we can write to the registers too.
-# bb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n
-; [PC+]
- move.d filler,r9
- move 0xbb113344,srp
- move srp,r3
- checkr3 bb113344
-
-; [R+]
- move [r9+],srp
- move srp,r3
- checkr3 664433aa
-
-; [R]
- move [r9],srp
- move srp,r3
- checkr3 cc557788
-
-; And check writing to memory, clear and srp.
-
- move.d filler,r9
- move 0xabcde012,srp
- setf zcvn
- move srp,[r9+]
- test_cc 1 1 1 1
- subq 4,r9
- move.d [r9],r3
- checkr3 abcde012
-
- clearf zcvn
- clear.b [r9]
- test_cc 0 0 0 0
- move.d [r9],r3
- checkr3 abcde000
-
- addq 2,r9
- clear.w [r9+]
- subq 2,r9
- move.d [r9],r3
- checkr3 77880000
-
- clear.d [r9]
- move.d [r9],r3
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movpmv32.s b/tests/tcg/cris/bare/check_movpmv32.s
deleted file mode 100644
index daf0970..0000000
--- a/tests/tcg/cris/bare/check_movpmv32.s
+++ /dev/null
@@ -1,35 +0,0 @@
-# mach: crisv32
-# output: 11223320\nbb113344\naa557711\n
-
-# Test v32-specific special registers. FIXME: more registers.
-
- .include "testutils.inc"
- start
- .data
-store:
- .dword 0x11223344
- .dword 0x77665544
-
- .text
- moveq -1,r3
- move.d store,r4
- move vr,[r4]
- move [r4+],mof
- move mof,r3
- checkr3 11223320
-
- moveq -1,r3
- clearf zcvn
- move 0xbb113344,mof
- test_cc 0 0 0 0
- move mof,r3
- checkr3 bb113344
-
- setf zcvn
- move 0xaa557711,mof
- test_cc 1 1 1 1
- move mof,[r4]
- move.d [r4],r3
- checkr3 aa557711
-
- quit
diff --git a/tests/tcg/cris/bare/check_movpr.s b/tests/tcg/cris/bare/check_movpr.s
deleted file mode 100644
index eef9bdb..0000000
--- a/tests/tcg/cris/bare/check_movpr.s
+++ /dev/null
@@ -1,28 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: ffffff00\nffff0000\n0\nbb113344\n
-
-# Test generic "move Ps,Rd" and "move Rs,Pd" insns; the ones with
-# functionality common to all models.
-
- .include "testutils.inc"
- start
- moveq -1,r3
- clear.b r3
- checkr3 ffffff00
-
- moveq -1,r3
- clear.w r3
- checkr3 ffff0000
-
- moveq -1,r3
- clear.d r3
- checkr3 0
-
- moveq -1,r3
- move.d 0xbb113344,r4
- setf zcvn
- move r4,srp
- move srp,r3
- test_cc 1 1 1 1
- checkr3 bb113344
- quit
diff --git a/tests/tcg/cris/bare/check_movprv32.s b/tests/tcg/cris/bare/check_movprv32.s
deleted file mode 100644
index d0d90e1..0000000
--- a/tests/tcg/cris/bare/check_movprv32.s
+++ /dev/null
@@ -1,21 +0,0 @@
-# mach: crisv32
-# output: ffffff20\nbb113344\n
-
-# Test v32-specific special registers. FIXME: more registers.
-
- .include "testutils.inc"
- start
- moveq -1,r3
- setf zcvn
- move vr,r3
- test_cc 1 1 1 1
- checkr3 ffffff20
-
- moveq -1,r3
- move.d 0xbb113344,r4
- clearf cvnz
- move r4,mof
- test_cc 0 0 0 0
- move mof,r3
- checkr3 bb113344
- quit
diff --git a/tests/tcg/cris/bare/check_movscr.s b/tests/tcg/cris/bare/check_movscr.s
deleted file mode 100644
index 53c8ce6..0000000
--- a/tests/tcg/cris/bare/check_movscr.s
+++ /dev/null
@@ -1,29 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 42\nffffff85\n7685\nffff8765\n0\n
-
-; Move constant byte, word, dword to register. Check that sign-extension
-; is performed.
-
- .include "testutils.inc"
- start
- moveq -1,r3
- movs.b 0x42,r3
- checkr3 42
-
- movs.b 0x85,r3
- test_move_cc 1 0 0 0
- checkr3 ffffff85
-
- movs.w 0x7685,r3
- test_move_cc 0 0 0 0
- checkr3 7685
-
- movs.w 0x8765,r3
- test_move_cc 1 0 0 0
- checkr3 ffff8765
-
- movs.w 0,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movsm.s b/tests/tcg/cris/bare/check_movsm.s
deleted file mode 100644
index 7074336..0000000
--- a/tests/tcg/cris/bare/check_movsm.s
+++ /dev/null
@@ -1,44 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 5\nfffffff5\n5\nfffffff5\n0\n
-
-; Movs between registers. Check that sign-extension is performed and the
-; full register is set.
-
- .include "testutils.inc"
-
- .data
-x:
- .byte 5,-11
- .word 5,-11
- .word 0
-
- start
- move.d x,r5
-
- moveq -1,r3
- movs.b [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq 0,r3
- movs.b [r5],r3
- test_move_cc 1 0 0 0
- addq 1,r5
- checkr3 fffffff5
-
- moveq -1,r3
- movs.w [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq 0,r3
- movs.w [r5],r3
- test_move_cc 1 0 0 0
- addq 2,r5
- checkr3 fffffff5
-
- movs.w [r5],r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movsr.s b/tests/tcg/cris/bare/check_movsr.s
deleted file mode 100644
index d1889a7..0000000
--- a/tests/tcg/cris/bare/check_movsr.s
+++ /dev/null
@@ -1,46 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 5\nfffffff5\n5\nfffffff5\n0\n
-
-; Movs between registers. Check that sign-extension is performed and the
-; full register is set.
-
- .include "testutils.inc"
- start
- moveq -1,r5
- moveq 5,r4
- move.b r4,r5
- moveq -1,r3
- movs.b r5,r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq 0,r5
- moveq -11,r4
- move.b r4,r5
- moveq 0,r3
- movs.b r5,r3
- test_move_cc 1 0 0 0
- checkr3 fffffff5
-
- moveq -1,r5
- moveq 5,r4
- move.w r4,r5
- moveq -1,r3
- movs.w r5,r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq 0,r5
- moveq -11,r4
- move.w r4,r5
- moveq 0,r3
- movs.w r5,r3
- test_move_cc 1 0 0 0
- checkr3 fffffff5
-
- moveq 0,r5
- movs.b r5,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movucr.s b/tests/tcg/cris/bare/check_movucr.s
deleted file mode 100644
index 7c8487d..0000000
--- a/tests/tcg/cris/bare/check_movucr.s
+++ /dev/null
@@ -1,33 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 42\n85\n7685\n8765\n0\n
-
-; Move constant byte, word, dword to register. Check that zero-extension
-; is performed.
-
- .include "testutils.inc"
- start
- moveq -1,r3
- movu.b 0x42,r3
- test_move_cc 0 0 0 0
- checkr3 42
-
- moveq -1,r3
- movu.b 0x85,r3
- test_move_cc 0 0 0 0
- checkr3 85
-
- moveq -1,r3
- movu.w 0x7685,r3
- test_move_cc 0 0 0 0
- checkr3 7685
-
- moveq -1,r3
- movu.w 0x8765,r3
- test_move_cc 0 0 0 0
- checkr3 8765
-
- movu.b 0,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movum.s b/tests/tcg/cris/bare/check_movum.s
deleted file mode 100644
index 038e539..0000000
--- a/tests/tcg/cris/bare/check_movum.s
+++ /dev/null
@@ -1,40 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 5\nf5\n5\nfff5\n0\n
-
-; Movu between registers. Check that zero-extension is performed and the
-; full register is set.
-
- .include "testutils.inc"
-
- .data
-x:
- .byte 5,-11
- .word 5,-11
- .word 0
-
- start
- move.d x,r5
-
- movu.b [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- movu.b [r5],r3
- test_move_cc 0 0 0 0
- addq 1,r5
- checkr3 f5
-
- movu.w [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- movu.w [r5],r3
- test_move_cc 0 0 0 0
- addq 2,r5
- checkr3 fff5
-
- movu.w [r5],r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movur.s b/tests/tcg/cris/bare/check_movur.s
deleted file mode 100644
index 3ecf475..0000000
--- a/tests/tcg/cris/bare/check_movur.s
+++ /dev/null
@@ -1,45 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 5\nf5\n5\nfff5\n0\n
-
-; Movu between registers. Check that zero-extension is performed and the
-; full register is set.
-
- .include "testutils.inc"
- start
- moveq -1,r5
- moveq 5,r4
- move.b r4,r5
- moveq -1,r3
- movu.b r5,r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq 0,r5
- moveq -11,r4
- move.b r4,r5
- moveq -1,r3
- movu.b r5,r3
- test_move_cc 0 0 0 0
- checkr3 f5
-
- moveq -1,r5
- moveq 5,r4
- move.w r4,r5
- moveq -1,r3
- movu.w r5,r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq 0,r5
- moveq -11,r4
- move.w r4,r5
- moveq -1,r3
- movu.w r5,r3
- test_move_cc 0 0 0 0
- checkr3 fff5
-
- movu.w 0,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_mulv32.s b/tests/tcg/cris/bare/check_mulv32.s
deleted file mode 100644
index f379358..0000000
--- a/tests/tcg/cris/bare/check_mulv32.s
+++ /dev/null
@@ -1,51 +0,0 @@
-# mach: crisv32
-# output: fffffffe\n
-# output: ffffffff\n
-# output: fffffffe\n
-# output: 1\n
-# output: fffffffe\n
-# output: ffffffff\n
-# output: fffffffe\n
-# output: 1\n
-
-; Check that carry is not modified on v32.
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- setf c
- muls.d r4,r3
- test_cc 1 0 0 1
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 2,r4
- setf c
- mulu.d r4,r3
- test_cc 0 0 1 1
- checkr3 fffffffe
- move mof,r3
- checkr3 1
-
- moveq -1,r3
- moveq 2,r4
- clearf c
- muls.d r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 2,r4
- clearf c
- mulu.d r4,r3
- test_cc 0 0 1 0
- checkr3 fffffffe
- move mof,r3
- checkr3 1
-
- quit
diff --git a/tests/tcg/cris/bare/check_mulx.s b/tests/tcg/cris/bare/check_mulx.s
deleted file mode 100644
index a7a1f82..0000000
--- a/tests/tcg/cris/bare/check_mulx.s
+++ /dev/null
@@ -1,257 +0,0 @@
-# mach: crisv10 crisv32
-# output: fffffffe\nffffffff\nfffffffe\n1\nfffffffe\nffffffff\nfffffffe\n1\nfffe0001\n0\nfffe0001\n0\n1\n0\n1\nfffffffe\n193eade2\n277e3a49\n193eade2\n277e3a49\nfffffffe\nffffffff\n1fffe\n0\nfffffffe\nffffffff\n1fffe\n0\n1\n0\nfffe0001\n0\nfdbdade2\nffffffff\n420fade2\n0\nfffffffe\nffffffff\n1fe\n0\nfffffffe\nffffffff\n1fe\n0\n1\n0\nfe01\n0\n1\n0\nfe01\n0\nffffd9e2\nffffffff\n2be2\n0\n0\n0\n0\n0\n
-
- .include "testutils.inc"
- start
-
- .align 4
- moveq -1,r3
- moveq 2,r4
- muls.d r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- .align 4
- moveq -1,r3
- moveq 2,r4
- mulu.d r4,r3
- test_cc 0 0 1 0
- checkr3 fffffffe
- move mof,r3
- checkr3 1
-
- .align 4
- moveq 2,r3
- moveq -1,r4
- muls.d r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- .align 4
- moveq 2,r3
- moveq -1,r4
- mulu.d r4,r3
- test_cc 0 0 1 0
- checkr3 fffffffe
- move mof,r3
- checkr3 1
-
- move.d 0xffff,r4
- move.d r4,r3
- muls.d r4,r3
- test_cc 0 0 1 0
- checkr3 fffe0001
- move mof,r3
- checkr3 0
-
- move.d 0xffff,r4
- move.d r4,r3
- mulu.d r4,r3
- test_cc 0 0 0 0
- checkr3 fffe0001
- move mof,r3
- checkr3 0
-
- moveq -1,r4
- move.d r4,r3
- muls.d r4,r3
- test_cc 0 0 0 0
- checkr3 1
- move mof,r3
- checkr3 0
-
- moveq -1,r4
- move.d r4,r3
- mulu.d r4,r3
- test_cc 1 0 1 0
- checkr3 1
- move mof,r3
- checkr3 fffffffe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- muls.d r4,r3
- test_cc 0 0 1 0
- checkr3 193eade2
- move mof,r3
- checkr3 277e3a49
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- mulu.d r4,r3
- test_cc 0 0 1 0
- checkr3 193eade2
- move mof,r3
- checkr3 277e3a49
-
- move.d 0xffff,r3
- moveq 2,r4
- muls.w r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 2,r4
- mulu.w r4,r3
- test_cc 0 0 0 0
- checkr3 1fffe
- move mof,r3
- checkr3 0
- nop
-
- moveq 2,r3
- move.d 0xffff,r4
- muls.w r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- moveq 2,r3
- moveq -1,r4
- mulu.w r4,r3
- test_cc 0 0 0 0
- checkr3 1fffe
- move mof,r3
- checkr3 0
-
- move.d 0xffff,r4
- move.d r4,r3
- muls.w r4,r3
- test_cc 0 0 0 0
- checkr3 1
- move mof,r3
- checkr3 0
-
- moveq -1,r4
- move.d r4,r3
- mulu.w r4,r3
- test_cc 0 0 0 0
- checkr3 fffe0001
- move mof,r3
- checkr3 0
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- muls.w r4,r3
- test_cc 1 0 0 0
- checkr3 fdbdade2
- move mof,r3
- checkr3 ffffffff
- nop
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- mulu.w r4,r3
- test_cc 0 0 0 0
- checkr3 420fade2
- move mof,r3
- checkr3 0
- nop
-
- move.d 0xff,r3
- moveq 2,r4
- muls.b r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 2,r4
- mulu.b r4,r3
- test_cc 0 0 0 0
- checkr3 1fe
- move mof,r3
- checkr3 0
-
- moveq 2,r3
- moveq -1,r4
- muls.b r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- moveq 2,r3
- moveq -1,r4
- mulu.b r4,r3
- test_cc 0 0 0 0
- checkr3 1fe
- move mof,r3
- checkr3 0
-
- move.d 0xff,r4
- move.d r4,r3
- muls.b r4,r3
- test_cc 0 0 0 0
- checkr3 1
- move mof,r3
- checkr3 0
- nop
-
- moveq -1,r4
- move.d r4,r3
- mulu.b r4,r3
- test_cc 0 0 0 0
- checkr3 fe01
- move mof,r3
- checkr3 0
- nop
-
- move.d 0xfeda49ff,r4
- move.d r4,r3
- muls.b r4,r3
- test_cc 0 0 0 0
- checkr3 1
- move mof,r3
- checkr3 0
- nop
-
- move.d 0xfeda49ff,r4
- move.d r4,r3
- mulu.b r4,r3
- test_cc 0 0 0 0
- checkr3 fe01
- move mof,r3
- checkr3 0
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- muls.b r4,r3
- test_cc 1 0 0 0
- checkr3 ffffd9e2
- move mof,r3
- checkr3 ffffffff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- mulu.b r4,r3
- test_cc 0 0 0 0
- checkr3 2be2
- move mof,r3
- checkr3 0
-
- moveq 0,r3
- move.d 0xf87f4aeb,r4
- muls.d r4,r3
- test_cc 0 1 0 0
- checkr3 0
- move mof,r3
- checkr3 0
-
- move.d 0xf87f4aeb,r3
- moveq 0,r4
- mulu.d r4,r3
- test_cc 0 1 0 0
- checkr3 0
- move mof,r3
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_neg.s b/tests/tcg/cris/bare/check_neg.s
deleted file mode 100644
index 963c4b6..0000000
--- a/tests/tcg/cris/bare/check_neg.s
+++ /dev/null
@@ -1,104 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\nffffffff\n0\n80000000\n1\nba987655\nffff\nffff\n0\n89ab8000\nffff0001\n45677655\nff\nff\n0\n89abae80\nffffff01\n45678955\n
-
- .include "testutils.inc"
- start
- moveq 0,r3
- moveq 1,r4
- neg.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 1,r3
- moveq 0,r4
- neg.d r3,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
-;; FIXME: this was wrong.
- moveq 0,r3
- neg.d r3,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0x80000000,r3
- neg.d r3,r3
- test_move_cc 1 0 0 0
- checkr3 80000000
-
- moveq -1,r3
- neg.d r3,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- move.d 0x456789ab,r3
- neg.d r3,r3
- test_move_cc 1 0 0 0
- checkr3 ba987655
-
- moveq 0,r3
- moveq 1,r4
- neg.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffff
-
- moveq 1,r3
- moveq 0,r4
- neg.w r3,r3
- test_move_cc 1 0 0 0
- checkr3 ffff
-
- moveq 0,r3
- neg.w r3,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0x89ab8000,r3
- neg.w r3,r3
- test_move_cc 1 0 0 0
- checkr3 89ab8000
-
- moveq -1,r3
- neg.w r3,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0001
-
- move.d 0x456789ab,r3
- neg.w r3,r3
- test_move_cc 0 0 0 0
- checkr3 45677655
-
- moveq 0,r3
- moveq 1,r4
- neg.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ff
-
- moveq 1,r3
- moveq 0,r4
- neg.b r3,r3
- test_move_cc 1 0 0 0
- checkr3 ff
-
- moveq 0,r3
- neg.b r3,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
-;; FIXME: was wrong.
- move.d 0x89abae80,r3
- neg.b r3,r3
- test_move_cc 1 0 0 1
- checkr3 89abae80
-
- moveq -1,r3
- neg.b r3,r3
- test_move_cc 0 0 0 0
- checkr3 ffffff01
-
- move.d 0x456789ab,r3
- neg.b r3,r3
- test_move_cc 0 0 0 0
- checkr3 45678955
-
- quit
diff --git a/tests/tcg/cris/bare/check_not.s b/tests/tcg/cris/bare/check_not.s
deleted file mode 100644
index 33bcf15..0000000
--- a/tests/tcg/cris/bare/check_not.s
+++ /dev/null
@@ -1,31 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: fffffffe\nfffffffd\nffff0f00\n0\n87ecbbad\n
-
- .include "testutils.inc"
- start
- moveq 1,r3
- not r3
- test_move_cc 1 0 0 0
- checkr3 fffffffe
-
- moveq 2,r3
- not r3
- test_move_cc 1 0 0 0
- checkr3 fffffffd
-
- move.d 0xf0ff,r3
- not r3
- test_move_cc 1 0 0 0
- checkr3 ffff0f00
-
- moveq -1,r3
- not r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0x78134452,r3
- not r3
- test_move_cc 1 0 0 0
- checkr3 87ecbbad
-
- quit
diff --git a/tests/tcg/cris/bare/check_orc.s b/tests/tcg/cris/bare/check_orc.s
deleted file mode 100644
index c733f03..0000000
--- a/tests/tcg/cris/bare/check_orc.s
+++ /dev/null
@@ -1,71 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n
-
- .include "testutils.inc"
- start
- moveq 1,r3
- or.d 2,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- moveq 2,r3
- or.d 1,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xf0ff,r3
- or.d 0xff0f,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r3
- or.d -1,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- or.d 0x5432f789,r3
- test_move_cc 0 0 0 0
- checkr3 7c33f7db
-
- move.d 0xffff0001,r3
- or.w 2,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0003
-
- moveq 2,r3
- or.w 1,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xfedaffaf,r3
- or.w 0xff5f,r3
- test_move_cc 1 0 0 0
- checkr3 fedaffff
-
- move.d 0x78134452,r3
- or.w 0xf789,r3
- test_move_cc 1 0 0 0
- checkr3 7813f7db
-
- moveq 1,r3
- or.b 2,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- moveq 2,r3
- or.b 1,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xfa3,r3
- or.b 0x4a,r3
- test_move_cc 1 0 0 0
- checkr3 feb
-
- move.d 0x78134453,r3
- or.b 0x89,r3
- test_move_cc 1 0 0 0
- checkr3 781344db
-
- quit
diff --git a/tests/tcg/cris/bare/check_orm.s b/tests/tcg/cris/bare/check_orm.s
deleted file mode 100644
index ee723a6..0000000
--- a/tests/tcg/cris/bare/check_orm.s
+++ /dev/null
@@ -1,75 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n
-
- .include "testutils.inc"
- .data
-x:
- .dword 2,1,0xff0f,-1,0x5432f789
- .word 2,1,0xff5f,0xf789
- .byte 2,1,0x4a,0x89
-
- start
- moveq 1,r3
- move.d x,r5
- or.d [r5+],r3
- checkr3 3
-
- moveq 2,r3
- or.d [r5],r3
- addq 4,r5
- checkr3 3
-
- move.d 0xf0ff,r3
- or.d [r5+],r3
- checkr3 ffff
-
- moveq -1,r3
- or.d [r5+],r3
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- or.d [r5+],r3
- checkr3 7c33f7db
-
- move.d 0xffff0001,r3
- or.w [r5+],r3
- checkr3 ffff0003
-
- moveq 2,r3
- or.w [r5],r3
- addq 2,r5
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xfedaffaf,r3
- or.w [r5+],r3
- test_move_cc 1 0 0 0
- checkr3 fedaffff
-
- move.d 0x78134452,r3
- or.w [r5+],r3
- test_move_cc 1 0 0 0
- checkr3 7813f7db
-
- moveq 1,r3
- or.b [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- moveq 2,r3
- or.b [r5],r3
- addq 1,r5
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xfa3,r3
- or.b [r5+],r3
- test_move_cc 1 0 0 0
- checkr3 feb
-
- move.d 0x78134453,r3
- or.b [r5],r3
- test_move_cc 1 0 0 0
- checkr3 781344db
-
- quit
diff --git a/tests/tcg/cris/bare/check_orq.s b/tests/tcg/cris/bare/check_orq.s
deleted file mode 100644
index 5060edc..0000000
--- a/tests/tcg/cris/bare/check_orq.s
+++ /dev/null
@@ -1,41 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 3\n3\nffffffff\nffffffff\n1f\nffffffe0\n7813445e\n
-
- .include "testutils.inc"
- start
- moveq 1,r3
- orq 2,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- moveq 2,r3
- orq 1,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xf0ff,r3
- orq -1,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 0,r3
- orq -1,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 0,r3
- orq 31,r3
- test_move_cc 0 0 0 0
- checkr3 1f
-
- moveq 0,r3
- orq -32,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffe0
-
- move.d 0x78134452,r3
- orq 12,r3
- test_move_cc 0 0 0 0
- checkr3 7813445e
-
- quit
diff --git a/tests/tcg/cris/bare/check_orr.s b/tests/tcg/cris/bare/check_orr.s
deleted file mode 100644
index a514c11..0000000
--- a/tests/tcg/cris/bare/check_orr.s
+++ /dev/null
@@ -1,84 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n
-
- .include "testutils.inc"
- start
- moveq 1,r3
- moveq 2,r4
- or.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- moveq 2,r3
- moveq 1,r4
- or.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xff0f,r4
- move.d 0xf0ff,r3
- or.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r4
- move.d r4,r3
- or.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- or.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 7c33f7db
-
- move.d 0xffff0001,r3
- moveq 2,r4
- or.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0003
-
- moveq 2,r3
- move.d 0xffff0001,r4
- or.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xfedaffaf,r3
- move.d 0xffffff5f,r4
- or.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 fedaffff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- or.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 7813f7db
-
- moveq 1,r3
- move.d 0xffffff02,r4
- or.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- moveq 2,r3
- moveq 1,r4
- or.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0x4a,r4
- move.d 0xfa3,r3
- or.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 feb
-
- move.d 0x5432f789,r4
- move.d 0x78134453,r3
- or.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 781344db
-
- quit
diff --git a/tests/tcg/cris/bare/check_ret.s b/tests/tcg/cris/bare/check_ret.s
deleted file mode 100644
index b44fb25..0000000
--- a/tests/tcg/cris/bare/check_ret.s
+++ /dev/null
@@ -1,25 +0,0 @@
-# mach: crisv3 crisv8 crisv10
-# output: 3\n
-
-# Test that ret works.
-
- .include "testutils.inc"
- start
-x:
- moveq 0,r3
- jsr z
-w:
- quit
-y:
- addq 1,r3
- checkr3 3
- quit
-
-z:
- addq 1,r3
- move srp,r2
- add.d y-w,r2
- move r2,srp
- ret
- addq 1,r3
- quit
diff --git a/tests/tcg/cris/bare/check_scc.s b/tests/tcg/cris/bare/check_scc.s
deleted file mode 100644
index 4a8674c..0000000
--- a/tests/tcg/cris/bare/check_scc.s
+++ /dev/null
@@ -1,95 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n0\n1\n0\n1\n0\n1\n0\n0\n1\n1\n0\n1\n0\n1\n0\n1\n0\n0\n1\n0\n1\n1\n0\n1\n0\n0\n1\n1\n0\n1\n1\n0\n
-
- .include "testutils.inc"
-
- .macro lcheckr3 v
- move $ccs, $r9
- checkr3 \v
- move $r9, $ccs
- .endm
-
- start
- clearf nzvc
- scc r3
- lcheckr3 1
- scs r3
- lcheckr3 0
- sne r3
- lcheckr3 1
- seq r3
- lcheckr3 0
- svc r3
- lcheckr3 1
- svs r3
- lcheckr3 0
- spl r3
- lcheckr3 1
- smi r3
- lcheckr3 0
- sls r3
- lcheckr3 0
- shi r3
- lcheckr3 1
- sge r3
- lcheckr3 1
- slt r3
- lcheckr3 0
- sgt r3
- lcheckr3 1
- sle r3
- lcheckr3 0
- sa r3
- lcheckr3 1
- setf nzvc
- scc r3
- lcheckr3 0
- scs r3
- lcheckr3 1
- sne r3
- lcheckr3 0
- svc r3
- lcheckr3 0
- svs r3
- lcheckr3 1
- spl r3
- lcheckr3 0
- smi r3
- lcheckr3 1
- sls r3
- lcheckr3 1
- shi r3
- lcheckr3 0
- sge r3
- lcheckr3 1
- slt r3
- lcheckr3 0
- sgt r3
- lcheckr3 0
- sle r3
- lcheckr3 1
- sa r3
- lcheckr3 1
- clearf n
- sge r3
- lcheckr3 0
- slt r3
- lcheckr3 1
-
- .if 1 ;..asm.arch.cris.v32
- setf p
- ssb r3
- .else
- moveq 1,r3
- .endif
- lcheckr3 1
-
- .if 1 ;..asm.arch.cris.v32
- clearf p
- ssb r3
- .else
- moveq 0,r3
- .endif
- lcheckr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_subc.s b/tests/tcg/cris/bare/check_subc.s
deleted file mode 100644
index e34b544..0000000
--- a/tests/tcg/cris/bare/check_subc.s
+++ /dev/null
@@ -1,87 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n
-
- .include "testutils.inc"
- start
-
- moveq -1,r3
- sub.d -2,r3
- test_cc 0 0 0 0
- checkr3 1
-
- moveq 2,r3
- sub.d 1,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xffff,r3
- sub.d -0xffff,r3
- test_cc 0 0 0 1
- checkr3 1fffe
-
- moveq -1,r3
- sub.d 1,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
-
- move.d 0x78134452,r3
- sub.d -0x5432f789,r3
- test_cc 1 0 1 1
- checkr3 cc463bdb
-
- moveq -1,r3
- sub.w -2,r3
- test_cc 0 0 0 0
- checkr3 ffff0001
-
- moveq 2,r3
- sub.w 1,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xffff,r3
- sub.w 1,r3
- test_cc 1 0 0 0
- checkr3 fffe
-
- move.d 0xfedaffff,r3
- sub.w 1,r3
- test_cc 1 0 0 0
- checkr3 fedafffe
-
- move.d 0x78134452,r3
- sub.w 0x877,r3
- test_cc 0 0 0 0
- checkr3 78133bdb
-
- moveq -1,r3
- sub.b -2,r3
- test_cc 0 0 0 0
- checkr3 ffffff01
-
- moveq 2,r3
- sub.b 1,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xff,r3
- sub.b 1,r3
- test_cc 1 0 0 0
- checkr3 fe
-
- move.d 0xfeda49ff,r3
- sub.b 1,r3
- test_cc 1 0 0 0
- checkr3 feda49fe
-
- move.d 0x78134452,r3
- sub.b 0x77,r3
- test_cc 1 0 0 1
- checkr3 781344db
-
- move.d 0x85649282,r3
- sub.b 0x82,r3
- test_cc 0 1 0 0
- checkr3 85649200
-
- quit
diff --git a/tests/tcg/cris/bare/check_subm.s b/tests/tcg/cris/bare/check_subm.s
deleted file mode 100644
index e07ea02..0000000
--- a/tests/tcg/cris/bare/check_subm.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n
-
- .include "testutils.inc"
- .data
-x:
- .dword -2,1,-0xffff,1,-0x5432f789
- .word -2,1,1,0x877
- .byte -2,1,0x77
- .byte 0x22
-
- start
- moveq -1,r3
- move.d x,r5
- sub.d [r5+],r3
- test_cc 0 0 0 0
- checkr3 1
-
- moveq 2,r3
- sub.d [r5],r3
- test_cc 0 0 0 0
- addq 4,r5
- checkr3 1
-
- move.d 0xffff,r3
- sub.d [r5+],r3
- test_cc 0 0 0 1
- checkr3 1fffe
-
- moveq -1,r3
- sub.d [r5+],r3
- test_cc 1 0 0 0
- checkr3 fffffffe
-
- move.d 0x78134452,r3
- sub.d [r5+],r3
- test_cc 1 0 1 1
- checkr3 cc463bdb
-
- moveq -1,r3
- sub.w [r5+],r3
- test_cc 0 0 0 0
- checkr3 ffff0001
-
- moveq 2,r3
- sub.w [r5+],r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xffff,r3
- sub.w [r5],r3
- test_cc 1 0 0 0
- checkr3 fffe
-
- move.d 0xfedaffff,r3
- sub.w [r5+],r3
- test_cc 1 0 0 0
- checkr3 fedafffe
-
- move.d 0x78134452,r3
- sub.w [r5+],r3
- test_cc 0 0 0 0
- checkr3 78133bdb
-
- moveq -1,r3
- sub.b [r5],r3
- test_cc 0 0 0 0
- addq 1,r5
- checkr3 ffffff01
-
- moveq 2,r3
- sub.b [r5],r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xff,r3
- sub.b [r5],r3
- test_cc 1 0 0 0
- checkr3 fe
-
- move.d 0xfeda49ff,r3
- sub.b [r5+],r3
- test_cc 1 0 0 0
- checkr3 feda49fe
-
- move.d 0x78134452,r3
- sub.b [r5+],r3
- test_cc 1 0 0 1
- checkr3 781344db
-
- move.d 0x85649222,r3
- sub.b [r5],r3
- test_cc 0 1 0 0
- checkr3 85649200
-
- quit
diff --git a/tests/tcg/cris/bare/check_subq.s b/tests/tcg/cris/bare/check_subq.s
deleted file mode 100644
index 9e34fa3..0000000
--- a/tests/tcg/cris/bare/check_subq.s
+++ /dev/null
@@ -1,52 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 0\nffffffff\nfffffffe\nffff\nff\n56788f9\n56788d9\n567889a\n0\n7ffffffc\n
-
- .include "testutils.inc"
- start
- moveq 1,r3
- subq 1,r3
- test_cc 0 1 0 0
- checkr3 0
-
- subq 1,r3
- test_cc 1 0 0 1
- checkr3 ffffffff
-
- subq 1,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
-
- move.d 0x10000,r3
- subq 1,r3
- test_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0x100,r3
- subq 1,r3
- test_cc 0 0 0 0
- checkr3 ff
-
- move.d 0x5678900,r3
- subq 7,r3
- test_cc 0 0 0 0
- checkr3 56788f9
-
- subq 32,r3
- test_cc 0 0 0 0
- checkr3 56788d9
-
- subq 63,r3
- test_cc 0 0 0 0
- checkr3 567889a
-
- move.d 34,r3
- subq 34,r3
- test_cc 0 1 0 0
- checkr3 0
-
- move.d 0x80000024,r3
- subq 40,r3
- test_cc 0 0 1 0
- checkr3 7ffffffc
-
- quit
diff --git a/tests/tcg/cris/bare/check_subr.s b/tests/tcg/cris/bare/check_subr.s
deleted file mode 100644
index 742fbc8..0000000
--- a/tests/tcg/cris/bare/check_subr.s
+++ /dev/null
@@ -1,102 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq -2,r4
- sub.d r4,r3
- test_cc 0 0 0 0
- checkr3 1
-
- moveq 2,r3
- moveq 1,r4
- sub.d r4,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xffff,r3
- move.d -0xffff,r4
- sub.d r4,r3
- test_cc 0 0 0 1
- checkr3 1fffe
-
- moveq 1,r4
- moveq -1,r3
- sub.d r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
-
- move.d -0x5432f789,r4
- move.d 0x78134452,r3
- sub.d r4,r3
- test_cc 1 0 1 1
- checkr3 cc463bdb
-
- moveq -1,r3
- moveq -2,r4
- sub.w r4,r3
- test_cc 0 0 0 0
- checkr3 ffff0001
-
- moveq 2,r3
- moveq 1,r4
- sub.w r4,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xffff,r3
- move.d -0xffff,r4
- sub.w r4,r3
- test_cc 1 0 0 0
- checkr3 fffe
-
- move.d 0xfedaffff,r3
- move.d -0xfedaffff,r4
- sub.w r4,r3
- test_cc 1 0 0 0
- checkr3 fedafffe
-
- move.d -0x5432f789,r4
- move.d 0x78134452,r3
- sub.w r4,r3
- test_cc 0 0 0 0
- checkr3 78133bdb
-
- moveq -1,r3
- moveq -2,r4
- sub.b r4,r3
- test_cc 0 0 0 0
- checkr3 ffffff01
-
- moveq 2,r3
- moveq 1,r4
- sub.b r4,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d -0xff,r4
- move.d 0xff,r3
- sub.b r4,r3
- test_cc 1 0 0 0
- checkr3 fe
-
- move.d -0xfeda49ff,r4
- move.d 0xfeda49ff,r3
- sub.b r4,r3
- test_cc 1 0 0 0
- checkr3 feda49fe
-
- move.d -0x5432f789,r4
- move.d 0x78134452,r3
- sub.b r4,r3
- test_cc 1 0 0 1
- checkr3 781344db
-
- move.d 0x85649222,r3
- move.d 0x77445622,r4
- sub.b r4,r3
- test_cc 0 1 0 0
- checkr3 85649200
-
- quit
diff --git a/tests/tcg/cris/bare/check_xarith.s b/tests/tcg/cris/bare/check_xarith.s
deleted file mode 100644
index 80038b2..0000000
--- a/tests/tcg/cris/bare/check_xarith.s
+++ /dev/null
@@ -1,72 +0,0 @@
-
-.include "testutils.inc"
-
- start
-
- moveq -1, $r0
- moveq 0, $r1
- addq 1, $r0
- ax
- addq 0, $r1
-
- move.d $r0, $r3
- checkr3 0
- move.d $r1, $r3
- checkr3 1
-
- move.d 0, $r0
- moveq -1, $r1
- subq 1, $r0
- ax
- subq 0, $r1
-
- move.d $r0, $r3
- checkr3 ffffffff
- move.d $r1, $r3
- checkr3 fffffffe
-
-
- moveq -1, $r0
- moveq -1, $r1
- cmpq -1, $r0
- ax
- cmpq -1, $r1
- beq 1f
- nop
- fail
-1:
- cmpq 0, $r0
- ax
- cmpq -1, $r1
- bne 1f
- nop
- fail
-1:
-
- ;; test for broken X sequence, run it several times.
- moveq 8, $r0
-1:
- moveq 0, $r3
- move.d $r0, $r1
- andq 1, $r1
- lslq 4, $r1
- moveq 1, $r2
- or.d $r1, $r2
- ba 2f
- move $r2, $ccs
-2:
- addq 0, $r3
- move.d $r0, $r4
- move.d $r1, $r5
- move.d $r2, $r6
- move.d $r3, $r7
- lsrq 4, $r1
- move.d $r1, $r8
- xor $r1, $r3
- checkr3 0
- subq 1, $r0
- bne 1b
- nop
-
- pass
- quit
diff --git a/tests/tcg/cris/bare/crt.s b/tests/tcg/cris/bare/crt.s
deleted file mode 100644
index af027d7..0000000
--- a/tests/tcg/cris/bare/crt.s
+++ /dev/null
@@ -1,13 +0,0 @@
- .data
-_stack_start:
- .space 8192, 0
-_stack_end:
- .text
- .global _start
-_start:
- move.d _stack_end, $sp
- jsr main
- nop
- moveq 0, $r10
- jump exit
- nop
diff --git a/tests/tcg/cris/bare/sys.c b/tests/tcg/cris/bare/sys.c
deleted file mode 100644
index 1644eec..0000000
--- a/tests/tcg/cris/bare/sys.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Helper functions for CRIS system tests
- *
- * There is no libc and only a limited set of headers.
- */
-
-#include <stddef.h>
-
-void exit(int status)
-{
- register unsigned int callno asm ("r9") = 1; /* NR_exit */
-
- asm volatile ("break 13\n"
- : /* no outputs */
- : "r" (callno)
- : "memory");
- while (1) {
- /* do nothing */
- };
-}
-
-size_t write(int fd, const void *buf, size_t count)
-{
- register unsigned int callno asm ("r9") = 4; /* NR_write */
- register unsigned int r10 asm ("r10") = fd;
- register const void *r11 asm ("r11") = buf;
- register size_t r12 asm ("r12") = count;
- register unsigned int r asm ("r10");
-
- asm volatile ("break 13\n"
- : "=r" (r)
- : "r" (callno), "0" (r10), "r" (r11), "r" (r12)
- : "memory");
-
- return r;
-}
-
-static inline int mystrlen(char *s)
-{
- int i = 0;
- while (s[i]) {
- i++;
- }
- return i;
-}
-
-
-void pass(void)
-{
- char s[] = "passed.\n";
- write(1, s, sizeof(s) - 1);
- exit(0);
-}
-
-void _fail(char *reason)
-{
- char s[] = "\nfailed: ";
- int len = mystrlen(reason);
- write(1, s, sizeof(s) - 1);
- write(1, reason, len);
- write(1, "\n", 1);
- exit(1);
-}
diff --git a/tests/tcg/cris/bare/testutils.inc b/tests/tcg/cris/bare/testutils.inc
deleted file mode 100644
index aa1641b..0000000
--- a/tests/tcg/cris/bare/testutils.inc
+++ /dev/null
@@ -1,117 +0,0 @@
- .syntax no_register_prefix
-
- .macro start
- .text
- .global main
-main:
- .endm
-
- .macro quit
- jump pass
- nop
- .endm
-
- .macro pass
- jump pass
- nop
- .endm
-
- .macro startnostack
- start
- .endm
-
- .macro fail
- .data
-99:
- .asciz " checkr3 failed\n"
- .text
- move.d 99b, $r10
- jsr _fail
- nop
- .endm
-
- .macro checkr3 val
- cmp.d 0x\val, $r3
- beq 100f
- nop
- .data
-99:
- .asciz "checkr3 failed\n"
- .text
- move.d 99b, $r10
- jsr _fail
- nop
-100:
- .endm
-
-; Test the condition codes
- .macro test_cc N Z V C
- .if \N
- bpl 9f
- nop
- .else
- bmi 9f
- nop
- .endif
- .if \Z
- bne 9f
- nop
- .else
- beq 9f
- nop
- .endif
- .if \V
- bvc 9f
- nop
- .else
- bvs 9f
- nop
- .endif
- .if \C
- bcc 9f
- nop
- .else
- bcs 9f
- nop
- .endif
- ba 8f
- nop
-9:
- .data
-99:
- .asciz "test_move_cc failed\n"
- .text
- move.d 99b, $r10
- jsr _fail
- nop
-8:
- .endm
-
-
- .macro test_move_cc N Z V C
- .if \N
- bpl 9f
- nop
- .else
- bmi 9f
- nop
- .endif
- .if \Z
- bne 9f
- nop
- .else
- beq 9f
- nop
- .endif
- ba 8f
- nop
-9:
- .data
-99:
- .asciz "test_move_cc failed\n"
- .text
- move.d 99b, $r10
- jsr _fail
- nop
-8:
- .endm
diff --git a/tests/tcg/cris/libc/check_abs.c b/tests/tcg/cris/libc/check_abs.c
deleted file mode 100644
index 08b67b6..0000000
--- a/tests/tcg/cris/libc/check_abs.c
+++ /dev/null
@@ -1,40 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-static always_inline int cris_abs(int n)
-{
- int r;
- asm ("abs\t%1, %0\n" : "=r" (r) : "r" (n));
- return r;
-}
-
-static always_inline void
-verify_abs(int val, int res,
- const int n, const int z, const int v, const int c)
-{
- int r;
-
- cris_tst_cc_init();
- r = cris_abs(val);
- cris_tst_cc(n, z, v, c);
- if (r != res)
- err();
-}
-
-int main(void)
-{
- verify_abs(-1, 1, 0, 0, 0, 0);
- verify_abs(0x80000000, 0x80000000, 1, 0, 0, 0);
- verify_abs(0x7fffffff, 0x7fffffff, 0, 0, 0, 0);
- verify_abs(42, 42, 0, 0, 0, 0);
- verify_abs(1, 1, 0, 0, 0, 0);
- verify_abs(0xffff, 0xffff, 0, 0, 0, 0);
- verify_abs(0xffff, 0xffff, 0, 0, 0, 0);
- verify_abs(-31, 0x1f, 0, 0, 0, 0);
- verify_abs(0, 0, 0, 1, 0, 0);
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_addc.c b/tests/tcg/cris/libc/check_addc.c
deleted file mode 100644
index fc3fb1f..0000000
--- a/tests/tcg/cris/libc/check_addc.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-static always_inline int cris_addc(int a, const int b)
-{
- asm ("addc\t%1, %0\n" : "+r" (a) : "r" (b));
- return a;
-}
-
-#define verify_addc(a, b, res, n, z, v, c) \
-{ \
- int r; \
- r = cris_addc((a), (b)); \
- cris_tst_cc((n), (z), (v), (c)); \
- if (r != (res)) \
- err(); \
-}
-
-int main(void)
-{
- cris_tst_cc_init();
- asm volatile ("clearf cz");
- verify_addc(0, 0, 0, 0, 0, 0, 0);
-
- cris_tst_cc_init();
- asm volatile ("setf z");
- verify_addc(0, 0, 0, 0, 1, 0, 0);
-
- cris_tst_cc_init();
- asm volatile ("setf cz");
- verify_addc(0, 0, 1, 0, 0, 0, 0);
- cris_tst_cc_init();
- asm volatile ("clearf c");
- verify_addc(-1, 2, 1, 0, 0, 0, 1);
-
- cris_tst_cc_init();
- asm volatile ("clearf nzv");
- asm volatile ("setf c");
- verify_addc(-1, 2, 2, 0, 0, 0, 1);
-
- cris_tst_cc_init();
- asm volatile ("setf c");
- verify_addc(0xffff, 0xffff, 0x1ffff, 0, 0, 0, 0);
-
- cris_tst_cc_init();
- asm volatile ("clearf nzvc");
- verify_addc(-1, -1, 0xfffffffe, 1, 0, 0, 1);
-
- cris_tst_cc_init();
- asm volatile ("setf c");
- verify_addc(0x78134452, 0x5432f789, 0xcc463bdc, 1, 0, 1, 0);
-
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_addcm.c b/tests/tcg/cris/libc/check_addcm.c
deleted file mode 100644
index b355ba1..0000000
--- a/tests/tcg/cris/libc/check_addcm.c
+++ /dev/null
@@ -1,85 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-/* need to avoid acr as source here. */
-static always_inline int cris_addc_m(int a, const int *b)
-{
- asm volatile ("addc [%1], %0\n" : "+r" (a) : "r" (b));
- return a;
-}
-
-/* 'b' is a crisv32 constrain to avoid postinc with $acr. */
-static always_inline int cris_addc_pi_m(int a, int **b)
-{
- asm volatile ("addc [%1+], %0\n" : "+r" (a), "+b" (*b));
- return a;
-}
-
-#define verify_addc_m(a, b, res, n, z, v, c) \
-{ \
- int r; \
- r = cris_addc_m((a), (b)); \
- cris_tst_cc((n), (z), (v), (c)); \
- if (r != (res)) \
- err(); \
-}
-
-#define verify_addc_pi_m(a, b, res, n, z, v, c) \
-{ \
- int r; \
- r = cris_addc_pi_m((a), (b)); \
- cris_tst_cc((n), (z), (v), (c)); \
- if (r != (res)) \
- err(); \
-}
-
-int x[] = { 0, 0, 2, -1, 0xffff, -1, 0x5432f789};
-
-int main(void)
-{
- int *p = (void *)&x[0];
-#if 1
- cris_tst_cc_init();
- asm volatile ("clearf cz");
- verify_addc_m(0, p, 0, 0, 0, 0, 0);
-
- cris_tst_cc_init();
- asm volatile ("setf z");
- verify_addc_m(0, p, 0, 0, 1, 0, 0);
-
- cris_tst_cc_init();
- asm volatile ("setf c");
- verify_addc_m(0, p, 1, 0, 0, 0, 0);
-
- cris_tst_cc_init();
- asm volatile ("clearf c");
- verify_addc_pi_m(0, &p, 0, 0, 1, 0, 0);
-
- p = &x[1];
- cris_tst_cc_init();
- asm volatile ("setf c");
- verify_addc_pi_m(0, &p, 1, 0, 0, 0, 0);
-
- if (p != &x[2])
- err();
-
- cris_tst_cc_init();
- asm volatile ("clearf c");
- verify_addc_pi_m(-1, &p, 1, 0, 0, 0, 1);
-
- if (p != &x[3])
- err();
-#endif
- p = &x[3];
- /* TODO: investigate why this one fails. */
- cris_tst_cc_init();
- asm volatile ("setf c");
- verify_addc_m(2, p, 2, 0, 0, 0, 1);
- p += 4;
-
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_addo.c b/tests/tcg/cris/libc/check_addo.c
deleted file mode 100644
index 4235e5f..0000000
--- a/tests/tcg/cris/libc/check_addo.c
+++ /dev/null
@@ -1,125 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-/* this would be better to do in asm, it's an orgy in GCC inline asm now. */
-
-#define cris_addo_b(o, v) \
- asm volatile ("addo.b\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr");
-#define cris_addo_w(o, v) \
- asm volatile ("addo.w\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr");
-#define cris_addo_d(o, v) \
- asm volatile ("addo.d\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr");
-#define cris_addo_pi_b(o, v) \
- asm volatile ("addo.b\t[%0+], %1, $acr\n" \
- : "+b" (o): "r" (v) : "acr");
-#define cris_addo_pi_w(o, v) \
- asm volatile ("addo.w\t[%0+], %1, $acr\n" \
- : "+b" (o): "r" (v) : "acr");
-#define cris_addo_pi_d(o, v) \
- asm volatile ("addo.d\t[%0+], %1, $acr\n" \
- : "+b" (o): "r" (v) : "acr");
-
-struct {
- uint32_t v1;
- uint16_t v2;
- uint32_t v3;
- uint8_t v4;
- uint8_t v5;
- uint16_t v6;
- uint32_t v7;
-} y = {
- 32769,
- -1,
- 5,
- 3, -4,
- 2,
- -76789887
-};
-
-static int x[3] = {0x55aa77ff, 0xccff2244, 0x88ccee19};
-
-int main(void)
-{
- int *r;
- unsigned char *t, *p;
-
- /* Note, this test-case will trig an unaligned access, partly
- to x[0] and to [x1]. */
- t = (unsigned char *)x;
- t -= 32768;
- p = (unsigned char *) &y.v1;
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_pi_d(p, t);
- cris_tst_cc(1, 1, 1, 1);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- if (*r != 0x4455aa77)
- err();
-
-
- t += 32770;
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_pi_w(p, t);
- cris_tst_cc(1, 1, 1, 1);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- if (*r != 0x4455aa77)
- err();
-
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_d(p, r);
- cris_tst_cc(1, 1, 1, 1);
- p += 4;
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- if (*r != 0xee19ccff)
- err();
-
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_pi_b(p, t);
- cris_tst_cc(0, 0, 0, 0);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- if (*(uint16_t*)r != 0xff22)
- err();
-
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_b(p, r);
- cris_tst_cc(1, 1, 1, 1);
- p += 1;
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- if (*r != 0x4455aa77)
- err();
-
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_w(p, r);
- cris_tst_cc(1, 1, 1, 1);
- p += 2;
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- if (*r != 0xff224455)
- err();
-
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_pi_d(p, t);
- cris_tst_cc(0, 0, 0, 0);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- r = (void*)(((char *)r) + 76789885);
- if (*r != 0x55aa77ff)
- err();
-
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_addoq.c b/tests/tcg/cris/libc/check_addoq.c
deleted file mode 100644
index ed509e2..0000000
--- a/tests/tcg/cris/libc/check_addoq.c
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-/* this would be better to do in asm, it's an orgy in GCC inline asm now. */
-
-/* ACR will be clobbered. */
-#define cris_addoq(o, v) \
- asm volatile ("addoq\t%1, %0, $acr\n" : : "r" (v), "i" (o) : "acr");
-
-
-int main(void)
-{
- int x[3] = {0x55aa77ff, 0xccff2244, 0x88ccee19};
- int *p, *t = x + 1;
-
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addoq(0, t);
- cris_tst_cc(1, 1, 1, 1);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (p));
- if (*p != 0xccff2244)
- err();
-
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addoq(4, t);
- cris_tst_cc(0, 0, 0, 0);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (p));
- if (*p != 0x88ccee19)
- err();
-
- cris_tst_cc_init();
- asm volatile ("clearf\tzvnc\n");
- cris_addoq(-8, t + 1);
- cris_tst_cc(0, 0, 0, 0);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (p));
- if (*p != 0x55aa77ff)
- err();
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_bound.c b/tests/tcg/cris/libc/check_bound.c
deleted file mode 100644
index d956ab9..0000000
--- a/tests/tcg/cris/libc/check_bound.c
+++ /dev/null
@@ -1,142 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-static always_inline int cris_bound_b(int v, int b)
-{
- int r = v;
- asm ("bound.b\t%1, %0\n" : "+r" (r) : "ri" (b));
- return r;
-}
-
-static always_inline int cris_bound_w(int v, int b)
-{
- int r = v;
- asm ("bound.w\t%1, %0\n" : "+r" (r) : "ri" (b));
- return r;
-}
-
-static always_inline int cris_bound_d(int v, int b)
-{
- int r = v;
- asm ("bound.d\t%1, %0\n" : "+r" (r) : "ri" (b));
- return r;
-}
-
-int main(void)
-{
- int r;
-
- cris_tst_cc_init();
- r = cris_bound_d(-1, 2);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 2)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_d(2, 0xffffffff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 2)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_d(0xffff, 0xffff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xffff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_d(-1, 0xffffffff);
- cris_tst_cc(1, 0, 0, 0);
- if (r != 0xffffffff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_d(0x78134452, 0x5432f789);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0x5432f789)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_w(-1, 2);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 2)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_w(-1, 0xffff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xffff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_w(2, 0xffff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 2)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_w(0xfedaffff, 0xffff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xffff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_w(0x78134452, 0xf789);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xf789)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(-1, 2);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 2)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(2, 0xff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 2)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(-1, 0xff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(0xff, 0xff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(0xfeda49ff, 0xff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(0x78134452, 0x89);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0x89)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_w(0x78134452, 0);
- cris_tst_cc(0, 1, 0, 0);
- if (r != 0)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(0xffff, -1);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xff)
- err();
-
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_ftag.c b/tests/tcg/cris/libc/check_ftag.c
deleted file mode 100644
index aaa5c97..0000000
--- a/tests/tcg/cris/libc/check_ftag.c
+++ /dev/null
@@ -1,37 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-static always_inline void cris_ftag_i(unsigned int x)
-{
- register unsigned int v asm("$r10") = x;
- asm ("ftagi\t[%0]\n" : : "r" (v) );
-}
-static always_inline void cris_ftag_d(unsigned int x)
-{
- register unsigned int v asm("$r10") = x;
- asm ("ftagd\t[%0]\n" : : "r" (v) );
-}
-static always_inline void cris_fidx_i(unsigned int x)
-{
- register unsigned int v asm("$r10") = x;
- asm ("fidxi\t[%0]\n" : : "r" (v) );
-}
-static always_inline void cris_fidx_d(unsigned int x)
-{
- register unsigned int v asm("$r10") = x;
- asm ("fidxd\t[%0]\n" : : "r" (v) );
-}
-
-
-int main(void)
-{
- cris_ftag_i(0);
- cris_ftag_d(0);
- cris_fidx_i(0);
- cris_fidx_d(0);
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_gcctorture_pr28634-1.c b/tests/tcg/cris/libc/check_gcctorture_pr28634-1.c
deleted file mode 100644
index 45ecd15..0000000
--- a/tests/tcg/cris/libc/check_gcctorture_pr28634-1.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/* PR rtl-optimization/28634. On targets with delayed branches,
- dbr_schedule could do the next iteration's addition in the
- branch delay slot, then subtract the value again if the branch
- wasn't taken. This can lead to rounding errors. */
-int x = -1;
-int y = 1;
-int
-main (void)
-{
- while (y > 0)
- y += x;
- if (y != x + 1)
- abort ();
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_gcctorture_pr28634.c b/tests/tcg/cris/libc/check_gcctorture_pr28634.c
deleted file mode 100644
index a0c5254..0000000
--- a/tests/tcg/cris/libc/check_gcctorture_pr28634.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/* PR rtl-optimization/28634. On targets with delayed branches,
- dbr_schedule could do the next iteration's addition in the
- branch delay slot, then subtract the value again if the branch
- wasn't taken. This can lead to rounding errors. */
-double x = -0x1.0p53;
-double y = 1;
-int
-main (void)
-{
- while (y > 0)
- y += x;
- if (y != x + 1)
- abort ();
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_glibc_kernelversion.c b/tests/tcg/cris/libc/check_glibc_kernelversion.c
deleted file mode 100644
index 7aada89..0000000
--- a/tests/tcg/cris/libc/check_glibc_kernelversion.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Check the lz insn.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-
-#define __LINUX_KERNEL_VERSION 131584
-
-#define DL_SYSDEP_OSCHECK(FATAL) \
- do { \
- /* Test whether the kernel is new enough. This test is only \
- performed if the library is not compiled to run on all \
- kernels. */ \
- if (__LINUX_KERNEL_VERSION > 0) \
- { \
- char bufmem[64]; \
- char *buf = bufmem; \
- unsigned int version; \
- int parts; \
- char *cp; \
- struct utsname uts; \
- \
- /* Try the uname syscall */ \
- if (__uname (&uts)) \
- { \
- /* This was not successful. Now try reading the /proc \
- filesystem. */ \
- ssize_t reslen; \
- int fd = __open ("/proc/sys/kernel/osrelease", O_RDONLY); \
- if (fd == -1 \
- || (reslen = __read (fd, bufmem, sizeof (bufmem))) <= 0) \
- /* This also didn't work. We give up since we cannot \
- make sure the library can actually work. */ \
- FATAL ("FATAL: cannot determine library version\n"); \
- __close (fd); \
- buf[MIN (reslen, (ssize_t) sizeof (bufmem) - 1)] = '\0'; \
- } \
- else \
- buf = uts.release; \
- \
- /* Now convert it into a number. The string consists of at most \
- three parts. */ \
- version = 0; \
- parts = 0; \
- cp = buf; \
- while ((*cp >= '0') && (*cp <= '9')) \
- { \
- unsigned int here = *cp++ - '0'; \
- \
- while ((*cp >= '0') && (*cp <= '9')) \
- { \
- here *= 10; \
- here += *cp++ - '0'; \
- } \
- \
- ++parts; \
- version <<= 8; \
- version |= here; \
- \
- if (*cp++ != '.') \
- /* Another part following? */ \
- break; \
- } \
- \
- if (parts < 3) \
- version <<= 8 * (3 - parts); \
- \
- /* Now we can test with the required version. */ \
- if (version < __LINUX_KERNEL_VERSION) \
- /* Not sufficient. */ \
- FATAL ("FATAL: kernel too old\n"); \
- \
- _dl_osversion = version; \
- } \
- } while (0)
-
-int main(void)
-{
- char bufmem[64] = "2.6.22";
- char *buf = bufmem;
- unsigned int version;
- int parts;
- char *cp;
-
- version = 0;
- parts = 0;
- cp = buf;
- while ((*cp >= '0') && (*cp <= '9'))
- {
- unsigned int here = *cp++ - '0';
-
- while ((*cp >= '0') && (*cp <= '9'))
- {
- here *= 10;
- here += *cp++ - '0';
- }
-
- ++parts;
- version <<= 8;
- version |= here;
-
- if (*cp++ != '.')
- /* Another part following? */
- break;
- }
-
- if (parts < 3)
- version <<= 8 * (3 - parts);
- if (version < __LINUX_KERNEL_VERSION)
- err();
- pass();
- exit(0);
-}
diff --git a/tests/tcg/cris/libc/check_hello.c b/tests/tcg/cris/libc/check_hello.c
deleted file mode 100644
index fb403ba..0000000
--- a/tests/tcg/cris/libc/check_hello.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-int main ()
-{
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_int64.c b/tests/tcg/cris/libc/check_int64.c
deleted file mode 100644
index 69caec1..0000000
--- a/tests/tcg/cris/libc/check_int64.c
+++ /dev/null
@@ -1,47 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-
-static always_inline int64_t add64(const int64_t a, const int64_t b)
-{
- return a + b;
-}
-
-static always_inline int64_t sub64(const int64_t a, const int64_t b)
-{
- return a - b;
-}
-
-int main(void)
-{
- int64_t a = 1;
- int64_t b = 2;
-
- /* FIXME: add some tests. */
- a = add64(a, b);
- if (a != 3)
- err();
-
- a = sub64(a, b);
- if (a != 1)
- err();
-
- a = add64(a, -4);
- if (a != -3)
- err();
-
- a = add64(a, 3);
- if (a != 0)
- err();
-
- a = 0;
- a = sub64(a, 1);
- if (a != -1)
- err();
-
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_lz.c b/tests/tcg/cris/libc/check_lz.c
deleted file mode 100644
index bf051a6..0000000
--- a/tests/tcg/cris/libc/check_lz.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-
-static always_inline int cris_lz(int x)
-{
- int r;
- asm ("lz\t%1, %0\n" : "=r" (r) : "r" (x));
- return r;
-}
-
-void check_lz(void)
-{
- int i;
-
- if (cris_lz(0) != 32)
- err();
- if (cris_lz(1) != 31)
- err();
- if (cris_lz(2) != 30)
- err();
- if (cris_lz(4) != 29)
- err();
- if (cris_lz(8) != 28)
- err();
-
- /* try all positions with a single bit. */
- for (i = 1; i < 32; i++) {
- if (cris_lz(1 << (i-1)) != (32 - i))
- err();
- }
-
- /* try all positions with all bits. */
- for (i = 1; i < 32; i++) {
- /* split up this computation to clarify it. */
- uint32_t val;
- val = (unsigned int)-1 >> (32 - i);
- if (cris_lz(val) != (32 - i))
- err();
- }
-}
-
-int main(void)
-{
- check_lz();
- pass();
- exit(0);
-}
diff --git a/tests/tcg/cris/libc/check_mapbrk.c b/tests/tcg/cris/libc/check_mapbrk.c
deleted file mode 100644
index 1aff762..0000000
--- a/tests/tcg/cris/libc/check_mapbrk.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-/* Basic sanity check that syscalls to implement malloc (brk, mmap2,
- munmap) are trivially functional. */
-
-int main ()
-{
- void *p1, *p2, *p3, *p4, *p5, *p6;
-
- if ((p1 = malloc (8100)) == NULL
- || (p2 = malloc (16300)) == NULL
- || (p3 = malloc (4000)) == NULL
- || (p4 = malloc (500)) == NULL
- || (p5 = malloc (1023*1024)) == NULL
- || (p6 = malloc (8191*1024)) == NULL)
- {
- printf ("fail\n");
- exit (1);
- }
-
- free (p1);
- free (p2);
- free (p3);
- free (p4);
- free (p5);
- free (p6);
-
- p1 = malloc (64000);
- if (p1 == NULL)
- {
- printf ("fail\n");
- exit (1);
- }
- free (p1);
-
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_mmap1.c b/tests/tcg/cris/libc/check_mmap1.c
deleted file mode 100644
index b803f0c..0000000
--- a/tests/tcg/cris/libc/check_mmap1.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-#notarget: cris*-*-elf
-*/
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/mman.h>
-
-int main (int argc, char *argv[])
-{
- int fd = open (argv[0], O_RDONLY);
- struct stat sb;
- int size;
- void *a;
- const char *str = "a string you'll only find in the program";
-
- if (fd == -1)
- {
- perror ("open");
- abort ();
- }
-
- if (fstat (fd, &sb) < 0)
- {
- perror ("fstat");
- abort ();
- }
-
- size = sb.st_size;
-
- /* We want to test mmapping a size that isn't exactly a page. */
- if ((size & 8191) == 0)
- size--;
-
- a = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
-
- if (memmem (a, size, str, strlen (str) + 1) == NULL)
- abort ();
-
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_mmap2.c b/tests/tcg/cris/libc/check_mmap2.c
deleted file mode 100644
index 35139a0..0000000
--- a/tests/tcg/cris/libc/check_mmap2.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-#notarget: cris*-*-elf
-*/
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/mman.h>
-
-int main (int argc, char *argv[])
-{
- int fd = open (argv[0], O_RDONLY);
- struct stat sb;
- int size;
- void *a;
- const char *str = "a string you'll only find in the program";
-
- if (fd == -1)
- {
- perror ("open");
- abort ();
- }
-
- if (fstat (fd, &sb) < 0)
- {
- perror ("fstat");
- abort ();
- }
-
- size = sb.st_size;
-
- /* We want to test mmapping a size that isn't exactly a page. */
- if ((size & 8191) == 0)
- size--;
-
- a = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
-
- if (memmem (a, size, str, strlen (str) + 1) == NULL)
- abort ();
-
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_mmap3.c b/tests/tcg/cris/libc/check_mmap3.c
deleted file mode 100644
index cb890ef..0000000
--- a/tests/tcg/cris/libc/check_mmap3.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-#notarget: cris*-*-elf
-*/
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <sys/mman.h>
-
-int main (int argc, char *argv[])
-{
- volatile unsigned char *a;
-
- /* Check that we can map a non-multiple of a page and still get a full page. */
- a = mmap (NULL, 0x4c, PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (a == NULL || a == (unsigned char *) -1)
- abort ();
-
- a[0] = 0xbe;
- a[8191] = 0xef;
- memset ((char *) a + 1, 0, 8190);
-
- if (a[0] != 0xbe || a[8191] != 0xef)
- abort ();
-
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_moveq.c b/tests/tcg/cris/libc/check_moveq.c
deleted file mode 100644
index 80f2dff..0000000
--- a/tests/tcg/cris/libc/check_moveq.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-#define cris_moveq(dst, src) \
- asm volatile ("moveq %1, %0\n" : "=r" (dst) : "i" (src));
-
-
-
-int main(void)
-{
- int t;
-
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_moveq(t, 10);
- cris_tst_cc(1, 1, 1, 1);
- if (t != 10)
- err();
-
- /* make sure moveq doesn't clobber the zflag. */
- cris_tst_cc_init();
- asm volatile ("setf vnc\n");
- asm volatile ("clearf z\n");
- cris_moveq(t, 0);
- cris_tst_cc(1, 0, 1, 1);
- if (t != 0)
- err();
-
- /* make sure moveq doesn't clobber the nflag.
- Also check large immediates */
- cris_tst_cc_init();
- asm volatile ("setf zvc\n");
- asm volatile ("clearf n\n");
- cris_moveq(t, -31);
- cris_tst_cc(0, 1, 1, 1);
- if (t != -31)
- err();
-
- cris_tst_cc_init();
- asm volatile ("setf nzvc\n");
- cris_moveq(t, 31);
- cris_tst_cc(1, 1, 1, 1);
- if (t != 31)
- err();
-
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_openpf1.c b/tests/tcg/cris/libc/check_openpf1.c
deleted file mode 100644
index 251d26e..0000000
--- a/tests/tcg/cris/libc/check_openpf1.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Check that --sysroot is applied to open(2).
-#sim: --sysroot=@exedir@
-
- We assume, with EXE being the name of the executable:
- - The simulator executes with cwd the same directory where the executable
- is located (so argv[0] contains a plain filename without directory
- components).
- - There's no /EXE on the host file system. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-int main (int argc, char *argv[])
-{
- char *fnam = argv[0];
- FILE *f;
- if (argv[0][0] != '/')
- {
- fnam = malloc (strlen (argv[0]) + 2);
- if (fnam == NULL)
- abort ();
- strcpy (fnam, "/");
- strcat (fnam, argv[0]);
- }
-
- f = fopen (fnam, "rb");
- if (f == NULL)
- abort ();
- fclose(f);
-
- /* Cover another execution path. */
- if (fopen ("/nonexistent", "rb") != NULL
- || errno != ENOENT)
- abort ();
- printf ("pass\n");
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_openpf2.c b/tests/tcg/cris/libc/check_openpf2.c
deleted file mode 100644
index 5d56189..0000000
--- a/tests/tcg/cris/libc/check_openpf2.c
+++ /dev/null
@@ -1,16 +0,0 @@
-/* Check that the simulator has chdir:ed to the --sysroot argument
-#sim: --sysroot=@srcdir@
- (or that --sysroot is applied to relative file paths). */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-int main (int argc, char *argv[])
-{
- FILE *f = fopen ("check_openpf2.c", "rb");
- if (f == NULL)
- abort ();
- fclose(f);
- printf ("pass\n");
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_openpf3.c b/tests/tcg/cris/libc/check_openpf3.c
deleted file mode 100644
index 557adee..0000000
--- a/tests/tcg/cris/libc/check_openpf3.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Basic file operations (rename, unlink); once without sysroot. We
- also test that the simulator has chdir:ed to PREFIX, when defined. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#ifndef PREFIX
-#define PREFIX
-#endif
-
-void err (const char *s)
-{
- perror (s);
- abort ();
-}
-
-int main (int argc, char *argv[])
-{
- FILE *f;
- struct stat buf;
-
- unlink (PREFIX "testfoo2.tmp");
-
- f = fopen ("testfoo1.tmp", "w");
- if (f == NULL)
- err ("open");
- fclose (f);
-
- if (rename (PREFIX "testfoo1.tmp", PREFIX "testfoo2.tmp") != 0)
- err ("rename");
-
- if (stat (PREFIX "testfoo2.tmp", &buf) != 0
- || !S_ISREG (buf.st_mode))
- err ("stat 1");
-
- if (stat ("testfoo2.tmp", &buf) != 0
- || !S_ISREG (buf.st_mode))
- err ("stat 2");
-
- if (unlink (PREFIX "testfoo2.tmp") != 0)
- err ("unlink");
-
- printf ("pass\n");
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_openpf5.c b/tests/tcg/cris/libc/check_openpf5.c
deleted file mode 100644
index 1f86ea2..0000000
--- a/tests/tcg/cris/libc/check_openpf5.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/* Check that TRT happens when error on too many opened files.
-#notarget: cris*-*-elf
-#sim: --sysroot=@exedir@
-*/
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
-
-int main (int argc, char *argv[])
-{
- int i;
- int filemax;
-
-#ifdef OPEN_MAX
- filemax = OPEN_MAX;
-#else
- filemax = sysconf (_SC_OPEN_MAX);
-#endif
-
- char *fn = malloc (strlen (argv[0]) + 2);
- if (fn == NULL)
- abort ();
- strcpy (fn, "/");
- strcat (fn, argv[0]);
-
- for (i = 0; i < filemax + 1; i++)
- {
- if (open (fn, O_RDONLY) < 0)
- {
- /* Shouldn't happen too early. */
- if (i < filemax - 3 - 1)
- {
- fprintf (stderr, "i: %d\n", i);
- abort ();
- }
- if (errno != EMFILE)
- {
- perror ("open");
- abort ();
- }
- goto ok;
- }
- }
- abort ();
-
-ok:
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_settls1.c b/tests/tcg/cris/libc/check_settls1.c
deleted file mode 100644
index 3abc3a9..0000000
--- a/tests/tcg/cris/libc/check_settls1.c
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <sys/syscall.h>
-
-#ifndef SYS_set_thread_area
-#define SYS_set_thread_area 243
-#endif
-
-int main (void)
-{
- unsigned long tp, old_tp;
- int ret;
-
- asm volatile ("move $pid,%0" : "=r" (old_tp));
- old_tp &= ~0xff;
-
- ret = syscall (SYS_set_thread_area, 0xf0);
- if (ret != -1 || errno != EINVAL) {
- syscall (SYS_set_thread_area, old_tp);
- perror ("Invalid thread area accepted:");
- abort();
- }
-
- ret = syscall (SYS_set_thread_area, 0xeddeed00);
- if (ret != 0) {
- perror ("Valid thread area not accepted: ");
- abort ();
- }
-
- asm volatile ("move $pid,%0" : "=r" (tp));
- tp &= ~0xff;
- syscall (SYS_set_thread_area, old_tp);
-
- if (tp != 0xeddeed00) {
- * (volatile int *) 0 = 0;
- perror ("tls2");
- abort ();
- }
-
- printf ("pass\n");
- return EXIT_SUCCESS;
-}
diff --git a/tests/tcg/cris/libc/check_sigalrm.c b/tests/tcg/cris/libc/check_sigalrm.c
deleted file mode 100644
index 39fa8d9..0000000
--- a/tests/tcg/cris/libc/check_sigalrm.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-
-#define MAGIC (0xdeadbeef)
-
-int s = 0;
-void sighandler(int sig)
-{
- s = MAGIC;
-}
-
-int main(int argc, char **argv)
-{
- int p;
-
- p = getpid();
- signal(SIGALRM, sighandler);
- kill(p, SIGALRM);
- if (s != MAGIC)
- return EXIT_FAILURE;
-
- printf ("passed\n");
- return EXIT_SUCCESS;
-}
diff --git a/tests/tcg/cris/libc/check_stat1.c b/tests/tcg/cris/libc/check_stat1.c
deleted file mode 100644
index 2e2cae5..0000000
--- a/tests/tcg/cris/libc/check_stat1.c
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int main (void)
-{
- struct stat buf;
-
- if (stat (".", &buf) != 0
- || !S_ISDIR (buf.st_mode))
- abort ();
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_stat2.c b/tests/tcg/cris/libc/check_stat2.c
deleted file mode 100644
index e36172e..0000000
--- a/tests/tcg/cris/libc/check_stat2.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-#notarget: cris*-*-elf
-*/
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int main (void)
-{
- struct stat buf;
-
- if (lstat (".", &buf) != 0
- || !S_ISDIR (buf.st_mode))
- abort ();
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_stat3.c b/tests/tcg/cris/libc/check_stat3.c
deleted file mode 100644
index 36a9d5d..0000000
--- a/tests/tcg/cris/libc/check_stat3.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Simulator options:
-#sim: --sysroot=@exedir@
-*/
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-int main (int argc, char *argv[])
-{
- char path[1024] = "/";
- struct stat buf;
-
- strncat(path, argv[0], sizeof(path) - 2);
- if (stat (".", &buf) != 0
- || !S_ISDIR (buf.st_mode))
- abort ();
- if (stat (path, &buf) != 0
- || !S_ISREG (buf.st_mode))
- abort ();
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_stat4.c b/tests/tcg/cris/libc/check_stat4.c
deleted file mode 100644
index 04f21fe..0000000
--- a/tests/tcg/cris/libc/check_stat4.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Simulator options:
-#notarget: cris*-*-elf
-#sim: --sysroot=@exedir@
-*/
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-int main (int argc, char *argv[])
-{
- char path[1024] = "/";
- struct stat buf;
-
- strncat(path, argv[0], sizeof(path) - 2);
- if (lstat (".", &buf) != 0
- || !S_ISDIR (buf.st_mode))
- abort ();
- if (lstat (path, &buf) != 0
- || !S_ISREG (buf.st_mode))
- abort ();
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_swap.c b/tests/tcg/cris/libc/check_swap.c
deleted file mode 100644
index 9a68c1e..0000000
--- a/tests/tcg/cris/libc/check_swap.c
+++ /dev/null
@@ -1,76 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-#define N 8
-#define W 4
-#define B 2
-#define R 1
-
-static always_inline int cris_swap(const int mode, int x)
-{
- switch (mode)
- {
- case N: asm ("swapn\t%0\n" : "+r" (x) : "0" (x)); break;
- case W: asm ("swapw\t%0\n" : "+r" (x) : "0" (x)); break;
- case B: asm ("swapb\t%0\n" : "+r" (x) : "0" (x)); break;
- case R: asm ("swapr\t%0\n" : "+r" (x) : "0" (x)); break;
- case B|R: asm ("swapbr\t%0\n" : "+r" (x) : "0" (x)); break;
- case W|R: asm ("swapwr\t%0\n" : "+r" (x) : "0" (x)); break;
- case W|B: asm ("swapwb\t%0\n" : "+r" (x) : "0" (x)); break;
- case W|B|R: asm ("swapwbr\t%0\n" : "+r" (x) : "0" (x)); break;
- case N|R: asm ("swapnr\t%0\n" : "+r" (x) : "0" (x)); break;
- case N|B: asm ("swapnb\t%0\n" : "+r" (x) : "0" (x)); break;
- case N|B|R: asm ("swapnbr\t%0\n" : "+r" (x) : "0" (x)); break;
- case N|W: asm ("swapnw\t%0\n" : "+r" (x) : "0" (x)); break;
- default:
- err();
- break;
- }
- return x;
-}
-
-/* Made this a macro to be able to pick up the location of the errors. */
-#define verify_swap(mode, val, expected, n, z) \
-do { \
- int r; \
- cris_tst_cc_init(); \
- r = cris_swap(mode, val); \
- cris_tst_mov_cc(n, z); \
- if (r != expected) \
- err(); \
-} while(0)
-
-void check_swap(void)
-{
- /* Some of these numbers are borrowed from GDB's cris sim
- testsuite. */
- if (cris_swap(N, 0) != 0xffffffff)
- err();
- if (cris_swap(W, 0x12345678) != 0x56781234)
- err();
- if (cris_swap(B, 0x12345678) != 0x34127856)
- err();
-
- verify_swap(R, 0x78134452, 0x1ec8224a, 0, 0);
- verify_swap(B, 0x78134452, 0x13785244, 0, 0);
- verify_swap(B|R, 0x78134452, 0xc81e4a22, 1, 0);
- verify_swap(W, 0x78134452, 0x44527813, 0, 0);
- verify_swap(W|R, 0x78134452, 0x224a1ec8, 0, 0);
- verify_swap(W|B|R, 0x78134452, 0x4a22c81e, 0, 0);
- verify_swap(N, 0x78134452, 0x87ecbbad, 1, 0);
- verify_swap(N|R, 0x78134452, 0xe137ddb5, 1, 0);
- verify_swap(N|B, 0x78134452, 0xec87adbb, 1, 0);
- verify_swap(N|B|R, 0x78134452, 0x37e1b5dd, 0, 0);
- verify_swap(N|W, 0x78134452, 0xbbad87ec, 1, 0);
- verify_swap(N|B|R, 0xffffffff, 0, 0, 1);
-}
-
-int main(void)
-{
- check_swap();
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_time2.c b/tests/tcg/cris/libc/check_time2.c
deleted file mode 100644
index 20b69b4..0000000
--- a/tests/tcg/cris/libc/check_time2.c
+++ /dev/null
@@ -1,18 +0,0 @@
-/* CB_SYS_time doesn't implement the Linux time syscall; the return
- value isn't written to the argument. */
-
-#include <time.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int
-main (void)
-{
- time_t x = (time_t) -1;
- time_t t = time (&x);
-
- if (t == (time_t) -1 || t != x)
- abort ();
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/crisutils.h b/tests/tcg/cris/libc/crisutils.h
deleted file mode 100644
index bbbe6c5..0000000
--- a/tests/tcg/cris/libc/crisutils.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef CRISUTILS_H
-#define CRISUTILS_H 1
-
-static char *tst_cc_loc = NULL;
-
-#define cris_tst_cc_init() \
-do { tst_cc_loc = "test_cc failed at " CURRENT_LOCATION; } while(0)
-
-/* We need a real symbol to signal error. */
-void _err(void) {
- if (!tst_cc_loc)
- tst_cc_loc = "tst_cc_failed\n";
- _fail(tst_cc_loc);
-}
-
-static always_inline void cris_tst_cc_n1(void)
-{
- asm volatile ("bpl _err\n"
- "nop\n");
-}
-static always_inline void cris_tst_cc_n0(void)
-{
- asm volatile ("bmi _err\n"
- "nop\n");
-}
-
-static always_inline void cris_tst_cc_z1(void)
-{
- asm volatile ("bne _err\n"
- "nop\n");
-}
-static always_inline void cris_tst_cc_z0(void)
-{
- asm volatile ("beq _err\n"
- "nop\n");
-}
-static always_inline void cris_tst_cc_v1(void)
-{
- asm volatile ("bvc _err\n"
- "nop\n");
-}
-static always_inline void cris_tst_cc_v0(void)
-{
- asm volatile ("bvs _err\n"
- "nop\n");
-}
-
-static always_inline void cris_tst_cc_c1(void)
-{
- asm volatile ("bcc _err\n"
- "nop\n");
-}
-static always_inline void cris_tst_cc_c0(void)
-{
- asm volatile ("bcs _err\n"
- "nop\n");
-}
-
-static always_inline void cris_tst_mov_cc(int n, int z)
-{
- if (n) cris_tst_cc_n1(); else cris_tst_cc_n0();
- if (z) cris_tst_cc_z1(); else cris_tst_cc_z0();
- asm volatile ("" : : "g" (_err));
-}
-
-static always_inline void cris_tst_cc(const int n, const int z,
- const int v, const int c)
-{
- if (n) cris_tst_cc_n1(); else cris_tst_cc_n0();
- if (z) cris_tst_cc_z1(); else cris_tst_cc_z0();
- if (v) cris_tst_cc_v1(); else cris_tst_cc_v0();
- if (c) cris_tst_cc_c1(); else cris_tst_cc_c0();
- asm volatile ("" : : "g" (_err));
-}
-
-#endif
diff --git a/tests/tcg/cris/libc/sys.h b/tests/tcg/cris/libc/sys.h
deleted file mode 100644
index 3dd47bb..0000000
--- a/tests/tcg/cris/libc/sys.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#include <unistd.h>
-
-#define STRINGIFY(x) #x
-#define TOSTRING(x) STRINGIFY(x)
-
-#define always_inline inline __attribute__((always_inline))
-
-#define CURRENT_LOCATION __FILE__ ":" TOSTRING(__LINE__)
-
-#define err() \
-{ \
- _fail("at " CURRENT_LOCATION " "); \
-}
-
-#define mb() asm volatile ("" : : : "memory")
-
-void pass(void);
-void _fail(char *reason);
diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target
index bbe2c44..f1df404 100644
--- a/tests/tcg/i386/Makefile.target
+++ b/tests/tcg/i386/Makefile.target
@@ -22,7 +22,7 @@ run-test-i386-sse-exceptions: QEMU_OPTS += -cpu max
test-i386-pcmpistri: CFLAGS += -msse4.2
run-test-i386-pcmpistri: QEMU_OPTS += -cpu max
-test-i386-bmi2: CFLAGS=-O2
+test-i386-bmi2: CFLAGS=-O2 -fwrapv
run-test-i386-bmi2: QEMU_OPTS += -cpu max
test-i386-adcox: CFLAGS=-O2
diff --git a/tests/tcg/i386/test-avx.c b/tests/tcg/i386/test-avx.c
index 230e6d8..80fe363 100644
--- a/tests/tcg/i386/test-avx.c
+++ b/tests/tcg/i386/test-avx.c
@@ -244,7 +244,7 @@ v4di indexd = {0x00000002ffffffcdull, 0xfffffff500000010ull,
0x0000003afffffff0ull, 0x000000000000000eull};
v4di gather_mem[0x20];
-_Static_assert(sizeof(gather_mem) == 1024);
+_Static_assert(sizeof(gather_mem) == 1024, "gather_mem not expected size");
void init_f16reg(v4di *r)
{
diff --git a/tests/tcg/i386/test-i386-adcox.c b/tests/tcg/i386/test-i386-adcox.c
index 16169ef..a717064 100644
--- a/tests/tcg/i386/test-i386-adcox.c
+++ b/tests/tcg/i386/test-i386-adcox.c
@@ -29,7 +29,7 @@ void test_adox_adcx(uint32_t in_c, uint32_t in_o, REG adcx_operand, REG adox_ope
"adcx %3, %1;"
"pushf; pop %0"
: "+r" (flags), "+r" (out_adcx), "+r" (out_adox)
- : "r" ((REG)-1), "0" (flags), "1" (out_adcx), "2" (out_adox));
+ : "r" ((REG) - 1), "0" (flags), "1" (out_adcx), "2" (out_adox));
assert(out_adcx == in_c + adcx_operand - 1);
assert(out_adox == in_o + adox_operand - 1);
@@ -53,8 +53,8 @@ void test_adcx_adox(uint32_t in_c, uint32_t in_o, REG adcx_operand, REG adox_ope
"adcx %3, %1;"
"adox %3, %2;"
"pushf; pop %0"
- : "+r" (flags), "+r" (out_adcx), "+r" (out_adox)
- : "r" ((REG)-1), "0" (flags), "1" (out_adcx), "2" (out_adox));
+ : "+r"(flags), "+r"(out_adcx), "+r"(out_adox)
+ : "r" ((REG)-1));
assert(out_adcx == in_c + adcx_operand - 1);
assert(out_adox == in_o + adox_operand - 1);
diff --git a/tests/tcg/loongarch64/system/kernel.ld b/tests/tcg/loongarch64/system/kernel.ld
index f1a7c01..56d8588 100644
--- a/tests/tcg/loongarch64/system/kernel.ld
+++ b/tests/tcg/loongarch64/system/kernel.ld
@@ -3,7 +3,7 @@ ENTRY(_start)
SECTIONS
{
/* Linux kernel legacy start address. */
- . = 0x9000000000200000;
+ . = 0x200000;
_text = .;
.text : {
*(.text)
diff --git a/tests/tcg/loongarch64/system/regdef.h b/tests/tcg/loongarch64/system/regdef.h
index faa09b2..b586b4e 100644
--- a/tests/tcg/loongarch64/system/regdef.h
+++ b/tests/tcg/loongarch64/system/regdef.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021 Loongson Technology Corporation Limited
*/
diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
index 5e3391e..45c9cfe 100644
--- a/tests/tcg/multiarch/Makefile.target
+++ b/tests/tcg/multiarch/Makefile.target
@@ -42,6 +42,17 @@ munmap-pthread: LDFLAGS+=-pthread
vma-pthread: CFLAGS+=-pthread
vma-pthread: LDFLAGS+=-pthread
+sigreturn-sigmask: CFLAGS+=-pthread
+sigreturn-sigmask: LDFLAGS+=-pthread
+
+# GCC versions 12/13/14/15 at least incorrectly complain about
+# "'SHA1Transform' reading 64 bytes from a region of size 0"; see the gcc bug
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106709
+# Since this is just a standard piece of library code we've borrowed for a
+# TCG test case, suppress the warning rather than trying to modify the
+# code to work around the compiler.
+sha1: CFLAGS+=-Wno-stringop-overread -Wno-unknown-warning-option
+
# The vma-pthread seems very sensitive on gitlab and we currently
# don't know if its exposing a real bug or the test is flaky.
ifneq ($(GITLAB_CI),)
@@ -127,6 +138,13 @@ run-gdbstub-follow-fork-mode-parent: follow-fork-mode
--bin $< --test $(MULTIARCH_SRC)/gdbstub/follow-fork-mode-parent.py, \
following parents on fork)
+run-gdbstub-late-attach: late-attach
+ $(call run-test, $@, env LATE_ATTACH_PY=1 $(GDB_SCRIPT) \
+ --gdb $(GDB) \
+ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" --no-suspend \
+ --bin $< --test $(MULTIARCH_SRC)/gdbstub/late-attach.py, \
+ attaching to a running process)
+
else
run-gdbstub-%:
$(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support")
@@ -136,7 +154,7 @@ EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \
run-gdbstub-registers run-gdbstub-prot-none \
run-gdbstub-catch-syscalls run-gdbstub-follow-fork-mode-child \
run-gdbstub-follow-fork-mode-parent \
- run-gdbstub-qxfer-siginfo-read
+ run-gdbstub-qxfer-siginfo-read run-gdbstub-late-attach
# ARM Compatible Semi Hosting Tests
#
@@ -170,5 +188,16 @@ run-plugin-semiconsole-with-%:
TESTS += semihosting semiconsole
endif
+# Test plugin memory access instrumentation
+run-plugin-test-plugin-mem-access-with-libmem.so: \
+ PLUGIN_ARGS=$(COMMA)print-accesses=true
+run-plugin-test-plugin-mem-access-with-libmem.so: \
+ CHECK_PLUGIN_OUTPUT_COMMAND= \
+ $(SRC_PATH)/tests/tcg/multiarch/check-plugin-output.sh \
+ $(QEMU) $<
+
+test-plugin-mem-access: CFLAGS+=-pthread -O0
+test-plugin-mem-access: LDFLAGS+=-pthread -O0
+
# Update TESTS
TESTS += $(MULTIARCH_TESTS)
diff --git a/tests/tcg/multiarch/check-plugin-output.sh b/tests/tcg/multiarch/check-plugin-output.sh
new file mode 100755
index 0000000..80607f0
--- /dev/null
+++ b/tests/tcg/multiarch/check-plugin-output.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+# This script runs a given executable using qemu, and compare its standard
+# output with an expected plugin output.
+# Each line of output is searched (as a regexp) in the expected plugin output.
+
+set -euo pipefail
+
+die()
+{
+ echo "$@" 1>&2
+ exit 1
+}
+
+check()
+{
+ file=$1
+ pattern=$2
+ grep "$pattern" "$file" > /dev/null || die "\"$pattern\" not found in $file"
+}
+
+[ $# -eq 3 ] || die "usage: qemu_bin exe plugin_out_file"
+
+qemu_bin=$1; shift
+exe=$1;shift
+plugin_out=$1; shift
+
+expected()
+{
+ $qemu_bin $exe ||
+ die "running $exe failed"
+}
+
+expected | while read line; do
+ check "$plugin_out" "$line"
+done
diff --git a/tests/tcg/multiarch/gdbstub/interrupt.py b/tests/tcg/multiarch/gdbstub/interrupt.py
index 90a45b5..2d5654d 100644
--- a/tests/tcg/multiarch/gdbstub/interrupt.py
+++ b/tests/tcg/multiarch/gdbstub/interrupt.py
@@ -8,7 +8,7 @@ from __future__ import print_function
#
import gdb
-from test_gdbstub import main, report
+from test_gdbstub import gdb_exit, main, report
def check_interrupt(thread):
@@ -49,7 +49,7 @@ def run_test():
"""
if len(gdb.selected_inferior().threads()) == 1:
print("SKIP: set to run on a single thread")
- exit(0)
+ gdb_exit(0)
gdb.execute("set scheduler-locking on")
for thread in gdb.selected_inferior().threads():
diff --git a/tests/tcg/multiarch/gdbstub/late-attach.py b/tests/tcg/multiarch/gdbstub/late-attach.py
new file mode 100644
index 0000000..1d40efb
--- /dev/null
+++ b/tests/tcg/multiarch/gdbstub/late-attach.py
@@ -0,0 +1,28 @@
+"""Test attaching GDB to a running process.
+
+SPDX-License-Identifier: GPL-2.0-or-later
+"""
+from test_gdbstub import main, report
+
+
+def run_test():
+ """Run through the tests one by one"""
+ try:
+ phase = gdb.parse_and_eval("phase").string()
+ except gdb.error:
+ # Assume the guest did not reach main().
+ phase = "start"
+
+ if phase == "start":
+ gdb.execute("break sigwait")
+ gdb.execute("continue")
+ phase = gdb.parse_and_eval("phase").string()
+ report(phase == "sigwait", "{} == \"sigwait\"".format(phase))
+
+ gdb.execute("signal SIGUSR1")
+
+ exitcode = int(gdb.parse_and_eval("$_exitcode"))
+ report(exitcode == 0, "{} == 0".format(exitcode))
+
+
+main(run_test)
diff --git a/tests/tcg/multiarch/gdbstub/prot-none.py b/tests/tcg/multiarch/gdbstub/prot-none.py
index 7e26458..51082a3 100644
--- a/tests/tcg/multiarch/gdbstub/prot-none.py
+++ b/tests/tcg/multiarch/gdbstub/prot-none.py
@@ -5,7 +5,7 @@ This runs as a sourced script (via -x, via run-test.py).
SPDX-License-Identifier: GPL-2.0-or-later
"""
import ctypes
-from test_gdbstub import main, report
+from test_gdbstub import gdb_exit, main, report
def probe_proc_self_mem():
@@ -22,7 +22,7 @@ def run_test():
"""Run through the tests one by one"""
if not probe_proc_self_mem():
print("SKIP: /proc/self/mem is not usable")
- exit(0)
+ gdb_exit(0)
gdb.Breakpoint("break_here")
gdb.execute("continue")
val = gdb.parse_and_eval("*(char[2] *)q").string()
diff --git a/tests/tcg/multiarch/gdbstub/test-proc-mappings.py b/tests/tcg/multiarch/gdbstub/test-proc-mappings.py
index 564613f..6eb6ebf 100644
--- a/tests/tcg/multiarch/gdbstub/test-proc-mappings.py
+++ b/tests/tcg/multiarch/gdbstub/test-proc-mappings.py
@@ -3,22 +3,17 @@
This runs as a sourced script (via -x, via run-test.py)."""
from __future__ import print_function
import gdb
-from test_gdbstub import main, report
+from test_gdbstub import gdb_exit, main, report
def run_test():
"""Run through the tests one by one"""
- try:
- mappings = gdb.execute("info proc mappings", False, True)
- except gdb.error as exc:
- exc_str = str(exc)
- if "Not supported on this target." in exc_str:
- # Detect failures due to an outstanding issue with how GDB handles
- # the x86_64 QEMU's target.xml, which does not contain the
- # definition of orig_rax. Skip the test in this case.
- print("SKIP: {}".format(exc_str))
- return
- raise
+ if gdb.selected_inferior().architecture().name() == "m68k":
+ # m68k GDB supports only GDB_OSABI_SVR4, but GDB_OSABI_LINUX is
+ # required for the info proc support (see set_gdbarch_info_proc()).
+ print("SKIP: m68k GDB does not support GDB_OSABI_LINUX")
+ gdb_exit(0)
+ mappings = gdb.execute("info proc mappings", False, True)
report(isinstance(mappings, str), "Fetched the mappings from the inferior")
# Broken with host page size > guest page size
# report("/sha1" in mappings, "Found the test binary name in the mappings")
diff --git a/tests/tcg/multiarch/late-attach.c b/tests/tcg/multiarch/late-attach.c
new file mode 100644
index 0000000..20a3640
--- /dev/null
+++ b/tests/tcg/multiarch/late-attach.c
@@ -0,0 +1,41 @@
+/*
+ * Test attaching GDB to a running process.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static const char *phase = "start";
+
+int main(void)
+{
+ sigset_t set;
+ int sig;
+
+ assert(sigfillset(&set) == 0);
+ assert(sigprocmask(SIG_BLOCK, &set, NULL) == 0);
+
+ /* Let GDB know it can send SIGUSR1. */
+ phase = "sigwait";
+ if (getenv("LATE_ATTACH_PY")) {
+ assert(sigwait(&set, &sig) == 0);
+ if (sig != SIGUSR1) {
+ fprintf(stderr, "Unexpected signal %d\n", sig);
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Check that the guest does not see host_interrupt_signal. */
+ assert(sigpending(&set) == 0);
+ for (sig = 1; sig < NSIG; sig++) {
+ if (sigismember(&set, sig)) {
+ fprintf(stderr, "Unexpected signal %d\n", sig);
+ return EXIT_FAILURE;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/tcg/multiarch/linux/linux-sigrtminmax.c b/tests/tcg/multiarch/linux/linux-sigrtminmax.c
new file mode 100644
index 0000000..a7059aa
--- /dev/null
+++ b/tests/tcg/multiarch/linux/linux-sigrtminmax.c
@@ -0,0 +1,74 @@
+/*
+ * Test the lowest and the highest real-time signals.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <assert.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* For hexagon and microblaze. */
+#ifndef __SIGRTMIN
+#define __SIGRTMIN 32
+#endif
+
+extern char **environ;
+
+static bool seen_sigrtmin, seen_sigrtmax;
+
+static void handle_signal(int sig)
+{
+ if (sig == SIGRTMIN) {
+ seen_sigrtmin = true;
+ } else if (sig == SIGRTMAX) {
+ seen_sigrtmax = true;
+ } else {
+ _exit(1);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ char *qemu = getenv("QEMU");
+ struct sigaction act;
+
+ assert(qemu);
+
+ if (!getenv("QEMU_RTSIG_MAP")) {
+ char **new_argv = malloc((argc + 2) + sizeof(char *));
+ int tsig1, hsig1, count1, tsig2, hsig2, count2;
+ char rt_sigmap[64];
+
+ /* Re-exec with a mapping that includes SIGRTMIN and SIGRTMAX. */
+ new_argv[0] = qemu;
+ memcpy(&new_argv[1], argv, (argc + 1) * sizeof(char *));
+ tsig1 = __SIGRTMIN;
+ /* The host must have a few signals starting from this one. */
+ hsig1 = 36;
+ count1 = SIGRTMIN - __SIGRTMIN + 1;
+ tsig2 = SIGRTMAX;
+ hsig2 = hsig1 + count1;
+ count2 = 1;
+ snprintf(rt_sigmap, sizeof(rt_sigmap), "%d %d %d,%d %d %d",
+ tsig1, hsig1, count1, tsig2, hsig2, count2);
+ setenv("QEMU_RTSIG_MAP", rt_sigmap, 0);
+ assert(execve(new_argv[0], new_argv, environ) == 0);
+ return EXIT_FAILURE;
+ }
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = handle_signal;
+ assert(sigaction(SIGRTMIN, &act, NULL) == 0);
+ assert(sigaction(SIGRTMAX, &act, NULL) == 0);
+
+ assert(kill(getpid(), SIGRTMIN) == 0);
+ assert(seen_sigrtmin);
+ assert(kill(getpid(), SIGRTMAX) == 0);
+ assert(seen_sigrtmax);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/tcg/multiarch/test-vma.c b/tests/tcg/multiarch/linux/test-vma.c
index 2893d60..2893d60 100644
--- a/tests/tcg/multiarch/test-vma.c
+++ b/tests/tcg/multiarch/linux/test-vma.c
diff --git a/tests/tcg/multiarch/sigreturn-sigmask.c b/tests/tcg/multiarch/sigreturn-sigmask.c
new file mode 100644
index 0000000..e6cc904
--- /dev/null
+++ b/tests/tcg/multiarch/sigreturn-sigmask.c
@@ -0,0 +1,51 @@
+/*
+ * Test that sigreturn() does not corrupt the signal mask.
+ * Block SIGUSR2 and handle SIGUSR1.
+ * Then sigwait() SIGUSR2, which relies on it remaining blocked.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <assert.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int seen_sig = -1;
+
+static void signal_func(int sig)
+{
+ seen_sig = sig;
+}
+
+static void *thread_func(void *arg)
+{
+ kill(getpid(), SIGUSR2);
+ return NULL;
+}
+
+int main(void)
+{
+ struct sigaction act = {
+ .sa_handler = signal_func,
+ };
+ pthread_t thread;
+ sigset_t set;
+ int sig;
+
+ assert(sigaction(SIGUSR1, &act, NULL) == 0);
+
+ assert(sigemptyset(&set) == 0);
+ assert(sigaddset(&set, SIGUSR2) == 0);
+ assert(sigprocmask(SIG_BLOCK, &set, NULL) == 0);
+
+ kill(getpid(), SIGUSR1);
+ assert(seen_sig == SIGUSR1);
+
+ assert(pthread_create(&thread, NULL, thread_func, NULL) == 0);
+ assert(sigwait(&set, &sig) == 0);
+ assert(sig == SIGUSR2);
+ assert(pthread_join(thread, NULL) == 0);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/tcg/multiarch/system/Makefile.softmmu-target b/tests/tcg/multiarch/system/Makefile.softmmu-target
index 32dc0f9..07be001 100644
--- a/tests/tcg/multiarch/system/Makefile.softmmu-target
+++ b/tests/tcg/multiarch/system/Makefile.softmmu-target
@@ -65,3 +65,9 @@ endif
MULTIARCH_RUNS += run-gdbstub-memory run-gdbstub-interrupt \
run-gdbstub-untimely-packet run-gdbstub-registers
+
+# Test plugin memory access instrumentation
+run-plugin-memory-with-libmem.so: \
+ PLUGIN_ARGS=$(COMMA)region-summary=true
+run-plugin-memory-with-libmem.so: \
+ CHECK_PLUGIN_OUTPUT_COMMAND=$(MULTIARCH_SYSTEM_SRC)/validate-memory-counts.py $@.out
diff --git a/tests/tcg/multiarch/system/memory.c b/tests/tcg/multiarch/system/memory.c
index 6eb2eb1..7508f6b 100644
--- a/tests/tcg/multiarch/system/memory.c
+++ b/tests/tcg/multiarch/system/memory.c
@@ -20,20 +20,28 @@
# error "Target does not specify CHECK_UNALIGNED"
#endif
+uint32_t test_read_count;
+uint32_t test_write_count;
+
#define MEM_PAGE_SIZE 4096 /* nominal 4k "pages" */
#define TEST_SIZE (MEM_PAGE_SIZE * 4) /* 4 pages */
#define ARRAY_SIZE(x) ((sizeof(x) / sizeof((x)[0])))
-__attribute__((aligned(MEM_PAGE_SIZE)))
+__attribute__((aligned(TEST_SIZE)))
static uint8_t test_data[TEST_SIZE];
typedef void (*init_ufn) (int offset);
typedef bool (*read_ufn) (int offset);
typedef bool (*read_sfn) (int offset, bool nf);
-static void pdot(int count)
+static void pdot(int count, bool write)
{
+ if (write) {
+ test_write_count++;
+ } else {
+ test_read_count++;
+ }
if (count % 128 == 0) {
ml_printf(".");
}
@@ -63,12 +71,14 @@ static void init_test_data_u8(int unused_offset)
int i;
(void)(unused_offset);
- ml_printf("Filling test area with u8:");
+ ml_printf("Filling test area with u8 (%p):", ptr);
+
for (i = 0; i < TEST_SIZE; i++) {
*ptr++ = BYTE_NEXT(count);
- pdot(i);
+ pdot(i, true);
}
- ml_printf("done\n");
+
+ ml_printf("done %d @ %p\n", i, ptr);
}
/*
@@ -91,10 +101,11 @@ static void init_test_data_s8(bool neg_first)
neg_first ? "neg first" : "pos first");
for (i = 0; i < TEST_SIZE / 2; i++) {
*ptr++ = get_byte(i, neg_first);
+ pdot(i, true);
*ptr++ = get_byte(i, !neg_first);
- pdot(i);
+ pdot(i, true);
}
- ml_printf("done\n");
+ ml_printf("done %d @ %p\n", i * 2, ptr);
}
/*
@@ -105,9 +116,19 @@ static void reset_start_data(int offset)
{
uint32_t *ptr = (uint32_t *) &test_data[0];
int i;
+
+ if (!offset) {
+ return;
+ }
+
+ ml_printf("Flushing %d bytes from %p: ", offset, ptr);
+
for (i = 0; i < offset; i++) {
*ptr++ = 0;
+ pdot(i, true);
}
+
+ ml_printf("done %d @ %p\n", i, ptr);
}
static void init_test_data_u16(int offset)
@@ -117,17 +138,17 @@ static void init_test_data_u16(int offset)
const int max = (TEST_SIZE - offset) / sizeof(word);
int i;
- ml_printf("Filling test area with u16 (offset %d, %p):", offset, ptr);
-
reset_start_data(offset);
+ ml_printf("Filling test area with u16 (offset %d, %p):", offset, ptr);
+
for (i = 0; i < max; i++) {
uint16_t low = BYTE_NEXT(count), high = BYTE_NEXT(count);
word = BYTE_SHIFT(high, 1) | BYTE_SHIFT(low, 0);
*ptr++ = word;
- pdot(i);
+ pdot(i, true);
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
}
static void init_test_data_u32(int offset)
@@ -137,21 +158,22 @@ static void init_test_data_u32(int offset)
const int max = (TEST_SIZE - offset) / sizeof(word);
int i;
- ml_printf("Filling test area with u32 (offset %d, %p):", offset, ptr);
-
reset_start_data(offset);
+ ml_printf("Filling test area with u32 (offset %d, %p):", offset, ptr);
+
for (i = 0; i < max; i++) {
uint32_t b4 = BYTE_NEXT(count), b3 = BYTE_NEXT(count);
uint32_t b2 = BYTE_NEXT(count), b1 = BYTE_NEXT(count);
word = BYTE_SHIFT(b1, 3) | BYTE_SHIFT(b2, 2) | BYTE_SHIFT(b3, 1) |
BYTE_SHIFT(b4, 0);
*ptr++ = word;
- pdot(i);
+ pdot(i, true);
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
}
+#if __SIZEOF_POINTER__ >= 8
static void init_test_data_u64(int offset)
{
uint8_t count = 0;
@@ -159,10 +181,10 @@ static void init_test_data_u64(int offset)
const int max = (TEST_SIZE - offset) / sizeof(word);
int i;
- ml_printf("Filling test area with u64 (offset %d, %p):", offset, ptr);
-
reset_start_data(offset);
+ ml_printf("Filling test area with u64 (offset %d, %p):", offset, ptr);
+
for (i = 0; i < max; i++) {
uint64_t b8 = BYTE_NEXT(count), b7 = BYTE_NEXT(count);
uint64_t b6 = BYTE_NEXT(count), b5 = BYTE_NEXT(count);
@@ -172,10 +194,11 @@ static void init_test_data_u64(int offset)
BYTE_SHIFT(b4, 4) | BYTE_SHIFT(b5, 3) | BYTE_SHIFT(b6, 2) |
BYTE_SHIFT(b7, 1) | BYTE_SHIFT(b8, 0);
*ptr++ = word;
- pdot(i);
+ pdot(i, true);
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
}
+#endif
static bool read_test_data_u16(int offset)
{
@@ -194,11 +217,11 @@ static bool read_test_data_u16(int offset)
ml_printf("Error %d < %d\n", high, low);
return false;
} else {
- pdot(i);
+ pdot(i, false);
}
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
return true;
}
@@ -236,13 +259,14 @@ static bool read_test_data_u32(int offset)
ml_printf("Error %d, %d, %d, %d", b1, b2, b3, b4);
return false;
} else {
- pdot(i);
+ pdot(i, false);
}
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
return true;
}
+#if __SIZEOF_POINTER__ >= 8
static bool read_test_data_u64(int offset)
{
uint64_t word, *ptr = (uint64_t *)&test_data[offset];
@@ -290,17 +314,22 @@ static bool read_test_data_u64(int offset)
b1, b2, b3, b4, b5, b6, b7, b8);
return false;
} else {
- pdot(i);
+ pdot(i, false);
}
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
return true;
}
+#endif
/* Read the test data and verify at various offsets */
-read_ufn read_ufns[] = { read_test_data_u16,
- read_test_data_u32,
- read_test_data_u64 };
+read_ufn read_ufns[] = {
+ read_test_data_u16,
+ read_test_data_u32,
+#if __SIZEOF_POINTER__ >= 8
+ read_test_data_u64
+#endif
+};
bool do_unsigned_reads(int start_off)
{
@@ -357,15 +386,17 @@ static bool read_test_data_s8(int offset, bool neg_first)
second = *ptr++;
if (neg_first && first < 0 && second > 0) {
- pdot(i);
+ pdot(i, false);
+ pdot(i, false);
} else if (!neg_first && first > 0 && second < 0) {
- pdot(i);
+ pdot(i, false);
+ pdot(i, false);
} else {
ml_printf("Error %d %c %d\n", first, neg_first ? '<' : '>', second);
return false;
}
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i * 2, ptr);
return true;
}
@@ -390,15 +421,15 @@ static bool read_test_data_s16(int offset, bool neg_first)
int32_t data = *ptr++;
if (neg_first && data < 0) {
- pdot(i);
+ pdot(i, false);
} else if (!neg_first && data > 0) {
- pdot(i);
+ pdot(i, false);
} else {
ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>');
return false;
}
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
return true;
}
@@ -423,15 +454,15 @@ static bool read_test_data_s32(int offset, bool neg_first)
int64_t data = *ptr++;
if (neg_first && data < 0) {
- pdot(i);
+ pdot(i, false);
} else if (!neg_first && data > 0) {
- pdot(i);
+ pdot(i, false);
} else {
ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>');
return false;
}
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
return true;
}
@@ -465,16 +496,23 @@ bool do_signed_reads(bool neg_first)
return ok;
}
-init_ufn init_ufns[] = { init_test_data_u8,
- init_test_data_u16,
- init_test_data_u32,
- init_test_data_u64 };
+init_ufn init_ufns[] = {
+ init_test_data_u8,
+ init_test_data_u16,
+ init_test_data_u32,
+#if __SIZEOF_POINTER__ >= 8
+ init_test_data_u64
+#endif
+};
int main(void)
{
int i;
bool ok = true;
+ ml_printf("Test data start: 0x%lx\n", (unsigned long)&test_data[0]);
+ ml_printf("Test data end: 0x%lx\n", (unsigned long)&test_data[TEST_SIZE]);
+
/* Run through the unsigned tests first */
for (i = 0; i < ARRAY_SIZE(init_ufns) && ok; i++) {
ok = do_unsigned_test(init_ufns[i]);
@@ -490,6 +528,8 @@ int main(void)
ok = do_signed_reads(true);
}
+ ml_printf("Test data read: %lu\n", (unsigned long)test_read_count);
+ ml_printf("Test data write: %lu\n", (unsigned long)test_write_count);
ml_printf("Test complete: %s\n", ok ? "PASSED" : "FAILED");
return ok ? 0 : -1;
}
diff --git a/tests/tcg/multiarch/system/validate-memory-counts.py b/tests/tcg/multiarch/system/validate-memory-counts.py
new file mode 100755
index 0000000..5b8bbf3
--- /dev/null
+++ b/tests/tcg/multiarch/system/validate-memory-counts.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+#
+# validate-memory-counts.py: check we instrumented memory properly
+#
+# This program takes two inputs:
+# - the mem plugin output
+# - the memory binary output
+#
+# Copyright (C) 2024 Linaro Ltd
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import sys
+from argparse import ArgumentParser
+
+def extract_counts(path):
+ """
+ Load the output from path and extract the lines containing:
+
+ Test data start: 0x40214000
+ Test data end: 0x40218001
+ Test data read: 2522280
+ Test data write: 262111
+
+ From the stream of data. Extract the values for use in the
+ validation function.
+ """
+ start_address = None
+ end_address = None
+ read_count = 0
+ write_count = 0
+ with open(path, 'r') as f:
+ for line in f:
+ if line.startswith("Test data start:"):
+ start_address = int(line.split(':')[1].strip(), 16)
+ elif line.startswith("Test data end:"):
+ end_address = int(line.split(':')[1].strip(), 16)
+ elif line.startswith("Test data read:"):
+ read_count = int(line.split(':')[1].strip())
+ elif line.startswith("Test data write:"):
+ write_count = int(line.split(':')[1].strip())
+ return start_address, end_address, read_count, write_count
+
+
+def parse_plugin_output(path, start, end):
+ """
+ Load the plugin output from path in the form of:
+
+ Region Base, Reads, Writes, Seen all
+ 0x0000000040004000, 31093, 0, false
+ 0x0000000040214000, 2522280, 278579, true
+ 0x0000000040000000, 137398, 0, false
+ 0x0000000040210000, 54727397, 33721956, false
+
+ And extract the ranges that match test data start and end and
+ return the results.
+ """
+ total_reads = 0
+ total_writes = 0
+ seen_all = False
+
+ with open(path, 'r') as f:
+ next(f) # Skip the header
+ for line in f:
+
+ if line.startswith("Region Base"):
+ continue
+
+ parts = line.strip().split(', ')
+ if len(parts) != 4:
+ continue
+
+ region_base = int(parts[0], 16)
+ reads = int(parts[1])
+ writes = int(parts[2])
+
+ if start <= region_base < end: # Checking if within range
+ total_reads += reads
+ total_writes += writes
+ seen_all = parts[3] == "true"
+
+ return total_reads, total_writes, seen_all
+
+def main() -> None:
+ """
+ Process the arguments, injest the program and plugin out and
+ verify they match up and report if they do not.
+ """
+ parser = ArgumentParser(description="Validate memory instrumentation")
+ parser.add_argument('test_output',
+ help="The output from the test itself")
+ parser.add_argument('plugin_output',
+ help="The output from memory plugin")
+ parser.add_argument('--bss-cleared',
+ action='store_true',
+ help='Assume bss was cleared (and adjusts counts).')
+
+ args = parser.parse_args()
+
+ # Extract counts from memory binary
+ start, end, exp_reads, exp_writes = extract_counts(args.test_output)
+
+ # Some targets clear BSS before running but the test doesn't know
+ # that so we adjust it by the size of the test region.
+ if args.bss_cleared:
+ exp_writes += 16384
+
+ if start is None or end is None:
+ print("Failed to test_data boundaries from output.")
+ sys.exit(1)
+
+ # Parse plugin output
+ preads, pwrites, seen_all = parse_plugin_output(args.plugin_output,
+ start, end)
+
+ if not seen_all:
+ print("Fail: didn't instrument all accesses to test_data.")
+ sys.exit(1)
+
+ # Compare and report
+ if preads == exp_reads and pwrites == exp_writes:
+ sys.exit(0)
+ else:
+ print("Fail: The memory reads and writes count does not match.")
+ print(f"Expected Reads: {exp_reads}, Actual Reads: {preads}")
+ print(f"Expected Writes: {exp_writes}, Actual Writes: {pwrites}")
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/tcg/multiarch/test-plugin-mem-access.c b/tests/tcg/multiarch/test-plugin-mem-access.c
new file mode 100644
index 0000000..057b9aa
--- /dev/null
+++ b/tests/tcg/multiarch/test-plugin-mem-access.c
@@ -0,0 +1,177 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Check if we detect all memory accesses expected using plugin API.
+ * Used in conjunction with ./check-plugin-mem-access.sh check script.
+ * Output of this program is the list of patterns expected in plugin output.
+ *
+ * 8,16,32 load/store are tested for all arch.
+ * 64,128 load/store are tested for aarch64/x64.
+ * atomic operations (8,16,32,64) are tested for x64 only.
+ */
+
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(__x86_64__)
+#include <emmintrin.h>
+#elif defined(__aarch64__)
+#include <arm_neon.h>
+#endif /* __x86_64__ */
+
+static void *data;
+
+/* ,store_u8,.*,8,store,0xf1 */
+#define PRINT_EXPECTED(function, type, value, action) \
+do { \
+ printf(",%s,.*,%d,%s,%s\n", \
+ #function, (int) sizeof(type) * 8, action, value); \
+} \
+while (0)
+
+#define DEFINE_STORE(name, type, value) \
+ \
+static void print_expected_store_##name(void) \
+{ \
+ PRINT_EXPECTED(store_##name, type, #value, "store"); \
+} \
+ \
+static void store_##name(void) \
+{ \
+ *((type *)data) = value; \
+ print_expected_store_##name(); \
+}
+
+#define DEFINE_ATOMIC_OP(name, type, value) \
+ \
+static void print_expected_atomic_op_##name(void) \
+{ \
+ PRINT_EXPECTED(atomic_op_##name, type, "0x0*42", "load"); \
+ PRINT_EXPECTED(atomic_op_##name, type, #value, "store"); \
+} \
+ \
+static void atomic_op_##name(void) \
+{ \
+ *((type *)data) = 0x42; \
+ __sync_val_compare_and_swap((type *)data, 0x42, value); \
+ print_expected_atomic_op_##name(); \
+}
+
+#define DEFINE_LOAD(name, type, value) \
+ \
+static void print_expected_load_##name(void) \
+{ \
+ PRINT_EXPECTED(load_##name, type, #value, "load"); \
+} \
+ \
+static void load_##name(void) \
+{ \
+ \
+ /* volatile forces load to be generated. */ \
+ volatile type src = *((type *) data); \
+ volatile type dest = src; \
+ (void)src, (void)dest; \
+ print_expected_load_##name(); \
+}
+
+DEFINE_STORE(u8, uint8_t, 0xf1)
+DEFINE_LOAD(u8, uint8_t, 0xf1)
+DEFINE_STORE(u16, uint16_t, 0xf123)
+DEFINE_LOAD(u16, uint16_t, 0xf123)
+DEFINE_STORE(u32, uint32_t, 0xff112233)
+DEFINE_LOAD(u32, uint32_t, 0xff112233)
+
+#if defined(__x86_64__) || defined(__aarch64__)
+DEFINE_STORE(u64, uint64_t, 0xf123456789abcdef)
+DEFINE_LOAD(u64, uint64_t, 0xf123456789abcdef)
+
+static void print_expected_store_u128(void)
+{
+ PRINT_EXPECTED(store_u128, __int128,
+ "0xf122334455667788f123456789abcdef", "store");
+}
+
+static void store_u128(void)
+{
+#ifdef __x86_64__
+ _mm_store_si128(data, _mm_set_epi32(0xf1223344, 0x55667788,
+ 0xf1234567, 0x89abcdef));
+#else
+ const uint32_t init[4] = {0x89abcdef, 0xf1234567, 0x55667788, 0xf1223344};
+ uint32x4_t vec = vld1q_u32(init);
+ vst1q_u32(data, vec);
+#endif /* __x86_64__ */
+ print_expected_store_u128();
+}
+
+static void print_expected_load_u128(void)
+{
+ PRINT_EXPECTED(load_u128, __int128,
+ "0xf122334455667788f123456789abcdef", "load");
+}
+
+static void load_u128(void)
+{
+#ifdef __x86_64__
+ __m128i var = _mm_load_si128(data);
+#else
+ uint32x4_t var = vld1q_u32(data);
+#endif
+ (void) var;
+ print_expected_load_u128();
+}
+#endif /* __x86_64__ || __aarch64__ */
+
+#if defined(__x86_64__)
+DEFINE_ATOMIC_OP(u8, uint8_t, 0xf1)
+DEFINE_ATOMIC_OP(u16, uint16_t, 0xf123)
+DEFINE_ATOMIC_OP(u32, uint32_t, 0xff112233)
+DEFINE_ATOMIC_OP(u64, uint64_t, 0xf123456789abcdef)
+#endif /* __x86_64__ */
+
+static void *f(void *p)
+{
+ return NULL;
+}
+
+int main(void)
+{
+ /*
+ * We force creation of a second thread to enable cpu flag CF_PARALLEL.
+ * This will generate atomic operations when needed.
+ */
+ pthread_t thread;
+ pthread_create(&thread, NULL, &f, NULL);
+ pthread_join(thread, NULL);
+
+ /* allocate storage up to 128 bits */
+ data = malloc(16);
+
+ store_u8();
+ load_u8();
+
+ store_u16();
+ load_u16();
+
+ store_u32();
+ load_u32();
+
+#if defined(__x86_64__) || defined(__aarch64__)
+ store_u64();
+ load_u64();
+
+ store_u128();
+ load_u128();
+#endif /* __x86_64__ || __aarch64__ */
+
+#if defined(__x86_64__)
+ atomic_op_u8();
+ atomic_op_u16();
+ atomic_op_u32();
+ atomic_op_u64();
+#endif /* __x86_64__ */
+
+ free(data);
+}
diff --git a/tests/tcg/plugins/insn.c b/tests/tcg/plugins/insn.c
index baf2d07..0c723cb 100644
--- a/tests/tcg/plugins/insn.c
+++ b/tests/tcg/plugins/insn.c
@@ -150,10 +150,8 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
insn, QEMU_PLUGIN_INLINE_ADD_U64, insn_count, 1);
} else {
- uint64_t vaddr = qemu_plugin_insn_vaddr(insn);
qemu_plugin_register_vcpu_insn_exec_cb(
- insn, vcpu_insn_exec_before, QEMU_PLUGIN_CB_NO_REGS,
- GUINT_TO_POINTER(vaddr));
+ insn, vcpu_insn_exec_before, QEMU_PLUGIN_CB_NO_REGS, NULL);
}
if (do_size) {
diff --git a/tests/tcg/plugins/mem.c b/tests/tcg/plugins/mem.c
index b650ddd..ca4e888 100644
--- a/tests/tcg/plugins/mem.c
+++ b/tests/tcg/plugins/mem.c
@@ -12,6 +12,15 @@
#include <stdio.h>
#include <glib.h>
+/*
+ * plugins should not include anything from QEMU aside from the
+ * API header. However as this is a test plugin to exercise the
+ * internals of QEMU and we want to avoid needless code duplication we
+ * do so here. bswap.h is pretty self-contained although it needs a
+ * few things provided by compiler.h.
+ */
+#include <compiler.h>
+#include <bswap.h>
#include <qemu-plugin.h>
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
@@ -21,13 +30,52 @@ typedef struct {
uint64_t io_count;
} CPUCount;
+typedef struct {
+ uint64_t vaddr;
+ const char *sym;
+} InsnInfo;
+
+/*
+ * For the "memory" system test we need to track accesses to
+ * individual regions. We mirror the data written to the region and
+ * then check when it is read that it matches up.
+ *
+ * We do this as regions rather than pages to save on complications
+ * with page crossing and the fact the test only cares about the
+ * test_data region.
+ */
+static uint64_t region_size = 4096 * 4;
+static uint64_t region_mask;
+
+typedef struct {
+ uint64_t region_address;
+ uint64_t reads;
+ uint64_t writes;
+ uint8_t *data;
+ /* Did we see every write and read with correct values? */
+ bool seen_all;
+} RegionInfo;
+
static struct qemu_plugin_scoreboard *counts;
static qemu_plugin_u64 mem_count;
static qemu_plugin_u64 io_count;
-static bool do_inline, do_callback;
+static bool do_inline, do_callback, do_print_accesses, do_region_summary;
static bool do_haddr;
static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW;
+
+static GMutex lock;
+static GHashTable *regions;
+
+static gint addr_order(gconstpointer a, gconstpointer b, gpointer d)
+{
+ RegionInfo *na = (RegionInfo *) a;
+ RegionInfo *nb = (RegionInfo *) b;
+
+ return na->region_address > nb->region_address ? 1 : -1;
+}
+
+
static void plugin_exit(qemu_plugin_id_t id, void *p)
{
g_autoptr(GString) out = g_string_new("");
@@ -41,9 +89,145 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
qemu_plugin_u64_sum(io_count));
}
qemu_plugin_outs(out->str);
+
+
+ if (do_region_summary) {
+ GList *counts = g_hash_table_get_values(regions);
+
+ counts = g_list_sort_with_data(counts, addr_order, NULL);
+
+ g_string_printf(out, "Region Base, Reads, Writes, Seen all\n");
+
+ if (counts && g_list_next(counts)) {
+ for (/* counts */; counts; counts = counts->next) {
+ RegionInfo *ri = (RegionInfo *) counts->data;
+
+ g_string_append_printf(out,
+ "0x%016"PRIx64", "
+ "%"PRId64", %"PRId64", %s\n",
+ ri->region_address,
+ ri->reads,
+ ri->writes,
+ ri->seen_all ? "true" : "false");
+ }
+ }
+ qemu_plugin_outs(out->str);
+ }
+
qemu_plugin_scoreboard_free(counts);
}
+/*
+ * Update the region tracking info for the access. We split up accesses
+ * that span regions even though the plugin infrastructure will deliver
+ * it as a single access.
+ */
+static void update_region_info(uint64_t region, uint64_t offset,
+ qemu_plugin_meminfo_t meminfo,
+ qemu_plugin_mem_value value,
+ unsigned size)
+{
+ bool be = qemu_plugin_mem_is_big_endian(meminfo);
+ bool is_store = qemu_plugin_mem_is_store(meminfo);
+ RegionInfo *ri;
+ bool unseen_data = false;
+
+ g_assert(offset + size <= region_size);
+
+ g_mutex_lock(&lock);
+ ri = (RegionInfo *) g_hash_table_lookup(regions, &region);
+
+ if (!ri) {
+ ri = g_new0(RegionInfo, 1);
+ ri->region_address = region;
+ ri->data = g_malloc0(region_size);
+ ri->seen_all = true;
+ g_hash_table_insert(regions, &ri->region_address, ri);
+ }
+
+ if (is_store) {
+ ri->writes++;
+ } else {
+ ri->reads++;
+ }
+
+ switch (value.type) {
+ case QEMU_PLUGIN_MEM_VALUE_U8:
+ if (is_store) {
+ ri->data[offset] = value.data.u8;
+ } else if (ri->data[offset] != value.data.u8) {
+ unseen_data = true;
+ }
+ break;
+ case QEMU_PLUGIN_MEM_VALUE_U16:
+ {
+ uint16_t *p = (uint16_t *) &ri->data[offset];
+ if (is_store) {
+ if (be) {
+ stw_be_p(p, value.data.u16);
+ } else {
+ stw_le_p(p, value.data.u16);
+ }
+ } else {
+ uint16_t val = be ? lduw_be_p(p) : lduw_le_p(p);
+ unseen_data = val != value.data.u16;
+ }
+ break;
+ }
+ case QEMU_PLUGIN_MEM_VALUE_U32:
+ {
+ uint32_t *p = (uint32_t *) &ri->data[offset];
+ if (is_store) {
+ if (be) {
+ stl_be_p(p, value.data.u32);
+ } else {
+ stl_le_p(p, value.data.u32);
+ }
+ } else {
+ uint32_t val = be ? ldl_be_p(p) : ldl_le_p(p);
+ unseen_data = val != value.data.u32;
+ }
+ break;
+ }
+ case QEMU_PLUGIN_MEM_VALUE_U64:
+ {
+ uint64_t *p = (uint64_t *) &ri->data[offset];
+ if (is_store) {
+ if (be) {
+ stq_be_p(p, value.data.u64);
+ } else {
+ stq_le_p(p, value.data.u64);
+ }
+ } else {
+ uint64_t val = be ? ldq_be_p(p) : ldq_le_p(p);
+ unseen_data = val != value.data.u64;
+ }
+ break;
+ }
+ case QEMU_PLUGIN_MEM_VALUE_U128:
+ /* non in test so skip */
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ /*
+ * This is expected for regions initialised by QEMU (.text etc) but we
+ * expect to see all data read and written to the test_data region
+ * of the memory test.
+ */
+ if (unseen_data && ri->seen_all) {
+ g_autoptr(GString) error = g_string_new("Warning: ");
+ g_string_append_printf(error, "0x%016"PRIx64":%"PRId64
+ " read an un-instrumented value\n",
+ region, offset);
+ qemu_plugin_outs(error->str);
+ ri->seen_all = false;
+ }
+
+ g_mutex_unlock(&lock);
+}
+
static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo,
uint64_t vaddr, void *udata)
{
@@ -58,6 +242,53 @@ static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo,
} else {
qemu_plugin_u64_add(mem_count, cpu_index, 1);
}
+
+ if (do_region_summary) {
+ uint64_t region = vaddr & ~region_mask;
+ uint64_t offset = vaddr & region_mask;
+ qemu_plugin_mem_value value = qemu_plugin_mem_get_value(meminfo);
+ unsigned size = 1 << qemu_plugin_mem_size_shift(meminfo);
+
+ update_region_info(region, offset, meminfo, value, size);
+ }
+}
+
+static void print_access(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo,
+ uint64_t vaddr, void *udata)
+{
+ InsnInfo *insn_info = udata;
+ unsigned size = 8 << qemu_plugin_mem_size_shift(meminfo);
+ const char *type = qemu_plugin_mem_is_store(meminfo) ? "store" : "load";
+ qemu_plugin_mem_value value = qemu_plugin_mem_get_value(meminfo);
+ uint64_t hwaddr =
+ qemu_plugin_hwaddr_phys_addr(qemu_plugin_get_hwaddr(meminfo, vaddr));
+ g_autoptr(GString) out = g_string_new("");
+ g_string_printf(out,
+ "0x%"PRIx64",%s,0x%"PRIx64",0x%"PRIx64",%d,%s,",
+ insn_info->vaddr, insn_info->sym,
+ vaddr, hwaddr, size, type);
+ switch (value.type) {
+ case QEMU_PLUGIN_MEM_VALUE_U8:
+ g_string_append_printf(out, "0x%02"PRIx8, value.data.u8);
+ break;
+ case QEMU_PLUGIN_MEM_VALUE_U16:
+ g_string_append_printf(out, "0x%04"PRIx16, value.data.u16);
+ break;
+ case QEMU_PLUGIN_MEM_VALUE_U32:
+ g_string_append_printf(out, "0x%08"PRIx32, value.data.u32);
+ break;
+ case QEMU_PLUGIN_MEM_VALUE_U64:
+ g_string_append_printf(out, "0x%016"PRIx64, value.data.u64);
+ break;
+ case QEMU_PLUGIN_MEM_VALUE_U128:
+ g_string_append_printf(out, "0x%016"PRIx64"%016"PRIx64,
+ value.data.u128.high, value.data.u128.low);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ g_string_append_printf(out, "\n");
+ qemu_plugin_outs(out->str);
}
static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
@@ -74,11 +305,21 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
QEMU_PLUGIN_INLINE_ADD_U64,
mem_count, 1);
}
- if (do_callback) {
+ if (do_callback || do_region_summary) {
qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem,
QEMU_PLUGIN_CB_NO_REGS,
rw, NULL);
}
+ if (do_print_accesses) {
+ /* we leak this pointer, to avoid locking to keep track of it */
+ InsnInfo *insn_info = g_malloc(sizeof(InsnInfo));
+ const char *sym = qemu_plugin_insn_symbol(insn);
+ insn_info->sym = sym ? sym : "";
+ insn_info->vaddr = qemu_plugin_insn_vaddr(insn);
+ qemu_plugin_register_vcpu_mem_cb(insn, print_access,
+ QEMU_PLUGIN_CB_NO_REGS,
+ rw, (void *) insn_info);
+ }
}
}
@@ -117,6 +358,18 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
return -1;
}
+ } else if (g_strcmp0(tokens[0], "print-accesses") == 0) {
+ if (!qemu_plugin_bool_parse(tokens[0], tokens[1],
+ &do_print_accesses)) {
+ fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
+ return -1;
+ }
+ } else if (g_strcmp0(tokens[0], "region-summary") == 0) {
+ if (!qemu_plugin_bool_parse(tokens[0], tokens[1],
+ &do_region_summary)) {
+ fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
+ return -1;
+ }
} else {
fprintf(stderr, "option parsing failed: %s\n", opt);
return -1;
@@ -129,6 +382,19 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
return -1;
}
+ if (do_print_accesses) {
+ g_autoptr(GString) out = g_string_new("");
+ g_string_printf(out,
+ "insn_vaddr,insn_symbol,mem_vaddr,mem_hwaddr,"
+ "access_size,access_type,mem_value\n");
+ qemu_plugin_outs(out->str);
+ }
+
+ if (do_region_summary) {
+ region_mask = (region_size - 1);
+ regions = g_hash_table_new(g_int64_hash, g_int64_equal);
+ }
+
counts = qemu_plugin_scoreboard_new(sizeof(CPUCount));
mem_count = qemu_plugin_scoreboard_u64_in_struct(
counts, CPUCount, mem_count);
diff --git a/tests/tcg/plugins/meson.build b/tests/tcg/plugins/meson.build
index f847849..61a007d 100644
--- a/tests/tcg/plugins/meson.build
+++ b/tests/tcg/plugins/meson.build
@@ -1,13 +1,12 @@
t = []
if get_option('plugins')
- foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'syscall']
+ foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'reset', 'syscall', 'patch']
if host_os == 'windows'
t += shared_module(i, files(i + '.c') + '../../../contrib/plugins/win32_linker.c',
include_directories: '../../../include/qemu',
link_depends: [win32_qemu_plugin_api_lib],
- link_args: ['-Lplugins', '-lqemu_plugin_api'],
+ link_args: win32_qemu_plugin_api_link_flags,
dependencies: glib)
-
else
t += shared_module(i, files(i + '.c'),
include_directories: '../../../include/qemu',
@@ -18,5 +17,7 @@ endif
if t.length() > 0
alias_target('test-plugins', t)
else
- run_target('test-plugins', command: find_program('true'))
+ run_target('test-plugins', command: [python, '-c', ''])
endif
+
+plugin_modules += t
diff --git a/tests/tcg/plugins/patch.c b/tests/tcg/plugins/patch.c
new file mode 100644
index 0000000..111c5c1
--- /dev/null
+++ b/tests/tcg/plugins/patch.c
@@ -0,0 +1,251 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This plugin patches instructions matching a pattern to a different
+ * instruction as they execute
+ *
+ */
+
+#include "glib.h"
+#include "glibconfig.h"
+
+#include <qemu-plugin.h>
+#include <string.h>
+#include <stdio.h>
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+static bool use_hwaddr;
+static GByteArray *target_data;
+static GByteArray *patch_data;
+
+/**
+ * Parse a string of hexadecimal digits into a GByteArray. The string must be
+ * even length
+ */
+static GByteArray *str_to_bytes(const char *str)
+{
+ size_t len = strlen(str);
+
+ if (len == 0 || len % 2 != 0) {
+ return NULL;
+ }
+
+ GByteArray *bytes = g_byte_array_new();
+ char byte[3] = {0};
+ guint8 value = 0;
+
+ for (size_t i = 0; i < len; i += 2) {
+ byte[0] = str[i];
+ byte[1] = str[i + 1];
+ value = (guint8)g_ascii_strtoull(byte, NULL, 16);
+ g_byte_array_append(bytes, &value, 1);
+ }
+
+ return bytes;
+}
+
+static void patch_hwaddr(unsigned int vcpu_index, void *userdata)
+{
+ uintptr_t addr = (uintptr_t) userdata;
+ g_autoptr(GString) str = g_string_new(NULL);
+ g_string_printf(str, "patching: @0x%"
+ PRIxPTR "\n",
+ addr);
+ qemu_plugin_outs(str->str);
+
+ enum qemu_plugin_hwaddr_operation_result result =
+ qemu_plugin_write_memory_hwaddr(addr, patch_data);
+
+
+ if (result != QEMU_PLUGIN_HWADDR_OPERATION_OK) {
+ g_autoptr(GString) errmsg = g_string_new(NULL);
+ g_string_printf(errmsg, "Failed to write memory: %d\n", result);
+ qemu_plugin_outs(errmsg->str);
+ return;
+ }
+
+ GByteArray *read_data = g_byte_array_new();
+
+ result = qemu_plugin_read_memory_hwaddr(addr, read_data,
+ patch_data->len);
+
+ qemu_plugin_outs("Reading memory...\n");
+
+ if (result != QEMU_PLUGIN_HWADDR_OPERATION_OK) {
+ g_autoptr(GString) errmsg = g_string_new(NULL);
+ g_string_printf(errmsg, "Failed to read memory: %d\n", result);
+ qemu_plugin_outs(errmsg->str);
+ return;
+ }
+
+ if (memcmp(patch_data->data, read_data->data, patch_data->len) != 0) {
+ qemu_plugin_outs("Failed to read back written data\n");
+ }
+
+ qemu_plugin_outs("Success!\n");
+
+ return;
+}
+
+static void patch_vaddr(unsigned int vcpu_index, void *userdata)
+{
+ uintptr_t addr = (uintptr_t) userdata;
+ uint64_t hwaddr = 0;
+ if (!qemu_plugin_translate_vaddr(addr, &hwaddr)) {
+ qemu_plugin_outs("Failed to translate vaddr\n");
+ return;
+ }
+ g_autoptr(GString) str = g_string_new(NULL);
+ g_string_printf(str, "patching: @0x%"
+ PRIxPTR " hw: @0x%" PRIx64 "\n",
+ addr, hwaddr);
+ qemu_plugin_outs(str->str);
+
+ qemu_plugin_outs("Writing memory (vaddr)...\n");
+
+ if (!qemu_plugin_write_memory_vaddr(addr, patch_data)) {
+ qemu_plugin_outs("Failed to write memory\n");
+ return;
+ }
+
+ qemu_plugin_outs("Reading memory (vaddr)...\n");
+
+ g_autoptr(GByteArray) read_data = g_byte_array_new();
+
+ if (!qemu_plugin_read_memory_vaddr(addr, read_data, patch_data->len)) {
+ qemu_plugin_outs("Failed to read memory\n");
+ return;
+ }
+
+ if (memcmp(patch_data->data, read_data->data, patch_data->len) != 0) {
+ qemu_plugin_outs("Failed to read back written data\n");
+ }
+
+ qemu_plugin_outs("Success!\n");
+
+ return;
+}
+
+/*
+ * Callback on translation of a translation block.
+ */
+static void vcpu_tb_trans_cb(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+ g_autoptr(GByteArray) insn_data = g_byte_array_new();
+ uintptr_t addr = 0;
+
+ for (size_t i = 0; i < qemu_plugin_tb_n_insns(tb); i++) {
+ struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
+ uint64_t vaddr = qemu_plugin_insn_vaddr(insn);
+
+ if (use_hwaddr) {
+ uint64_t hwaddr = 0;
+ if (!qemu_plugin_translate_vaddr(vaddr, &hwaddr)) {
+ qemu_plugin_outs("Failed to translate vaddr\n");
+ continue;
+ }
+ /*
+ * As we cannot emulate 64 bit systems on 32 bit hosts we
+ * should never see the top bits set, hence we can safely
+ * cast to uintptr_t.
+ */
+ g_assert(hwaddr <= UINTPTR_MAX);
+ addr = (uintptr_t) hwaddr;
+ } else {
+ g_assert(vaddr <= UINTPTR_MAX);
+ addr = (uintptr_t) vaddr;
+ }
+
+ g_byte_array_set_size(insn_data, qemu_plugin_insn_size(insn));
+ qemu_plugin_insn_data(insn, insn_data->data, insn_data->len);
+
+ if (insn_data->len >= target_data->len &&
+ !memcmp(insn_data->data, target_data->data,
+ MIN(target_data->len, insn_data->len))) {
+ if (use_hwaddr) {
+ qemu_plugin_register_vcpu_tb_exec_cb(tb, patch_hwaddr,
+ QEMU_PLUGIN_CB_NO_REGS,
+ (void *) addr);
+ } else {
+ qemu_plugin_register_vcpu_tb_exec_cb(tb, patch_vaddr,
+ QEMU_PLUGIN_CB_NO_REGS,
+ (void *) addr);
+ }
+ }
+ }
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: <lib>,target=<bytes>,patch=<new_bytes>"
+ "[,use_hwaddr=true|false]");
+}
+
+/*
+ * Called when the plugin is installed
+ */
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+ const qemu_info_t *info, int argc,
+ char **argv)
+{
+
+ use_hwaddr = true;
+ target_data = NULL;
+ patch_data = NULL;
+
+ if (argc > 4) {
+ usage();
+ return -1;
+ }
+
+ for (size_t i = 0; i < argc; i++) {
+ char *opt = argv[i];
+ g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
+ if (g_strcmp0(tokens[0], "use_hwaddr") == 0) {
+ if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &use_hwaddr)) {
+ fprintf(stderr,
+ "Failed to parse boolean argument use_hwaddr\n");
+ return -1;
+ }
+ } else if (g_strcmp0(tokens[0], "target") == 0) {
+ target_data = str_to_bytes(tokens[1]);
+ if (!target_data) {
+ fprintf(stderr,
+ "Failed to parse target bytes.\n");
+ return -1;
+ }
+ } else if (g_strcmp0(tokens[0], "patch") == 0) {
+ patch_data = str_to_bytes(tokens[1]);
+ if (!patch_data) {
+ fprintf(stderr, "Failed to parse patch bytes.\n");
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "Unknown argument: %s\n", tokens[0]);
+ usage();
+ return -1;
+ }
+ }
+
+ if (!target_data) {
+ fprintf(stderr, "target argument is required\n");
+ usage();
+ return -1;
+ }
+
+ if (!patch_data) {
+ fprintf(stderr, "patch argument is required\n");
+ usage();
+ return -1;
+ }
+
+ if (target_data->len != patch_data->len) {
+ fprintf(stderr, "Target and patch data must be the same length\n");
+ return -1;
+ }
+
+ qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans_cb);
+
+ return 0;
+}
diff --git a/tests/tcg/plugins/reset.c b/tests/tcg/plugins/reset.c
new file mode 100644
index 0000000..1be8be2
--- /dev/null
+++ b/tests/tcg/plugins/reset.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2025 Linaro Ltd
+ *
+ * Test the reset/uninstall cycle of a plugin.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <glib.h>
+
+#include <qemu-plugin.h>
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+static qemu_plugin_id_t plugin_id;
+static bool was_reset;
+static bool was_uninstalled;
+
+static void after_uninstall(qemu_plugin_id_t id)
+{
+ g_assert(was_reset && !was_uninstalled);
+ qemu_plugin_outs("uninstall done\n");
+ was_uninstalled = true;
+}
+
+static void tb_exec_after_reset(unsigned int vcpu_index, void *userdata)
+{
+ g_assert(was_reset && !was_uninstalled);
+ qemu_plugin_uninstall(plugin_id, after_uninstall);
+}
+
+static void tb_trans_after_reset(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+ g_assert(was_reset && !was_uninstalled);
+ qemu_plugin_register_vcpu_tb_exec_cb(tb, tb_exec_after_reset,
+ QEMU_PLUGIN_CB_NO_REGS, NULL);
+}
+
+static void after_reset(qemu_plugin_id_t id)
+{
+ g_assert(!was_reset && !was_uninstalled);
+ qemu_plugin_outs("reset done\n");
+ was_reset = true;
+ qemu_plugin_register_vcpu_tb_trans_cb(id, tb_trans_after_reset);
+}
+
+static void tb_exec_before_reset(unsigned int vcpu_index, void *userdata)
+{
+ g_assert(!was_reset && !was_uninstalled);
+ qemu_plugin_reset(plugin_id, after_reset);
+}
+
+static void tb_trans_before_reset(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+ g_assert(!was_reset && !was_uninstalled);
+ qemu_plugin_register_vcpu_tb_exec_cb(tb, tb_exec_before_reset,
+ QEMU_PLUGIN_CB_NO_REGS, NULL);
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+ const qemu_info_t *info,
+ int argc, char **argv)
+{
+ plugin_id = id;
+ qemu_plugin_register_vcpu_tb_trans_cb(id, tb_trans_before_reset);
+ return 0;
+}
+
+/* Since we uninstall the plugin, we can't use qemu_plugin_register_atexit_cb,
+ * so we use destructor attribute instead. */
+static void __attribute__((destructor)) on_plugin_exit(void)
+{
+ g_assert(was_reset && was_uninstalled);
+ qemu_plugin_outs("plugin exit\n");
+}
diff --git a/tests/tcg/plugins/syscall.c b/tests/tcg/plugins/syscall.c
index 72e1a5b..42801f5 100644
--- a/tests/tcg/plugins/syscall.c
+++ b/tests/tcg/plugins/syscall.c
@@ -22,23 +22,109 @@ typedef struct {
int64_t errors;
} SyscallStats;
+struct SyscallInfo {
+ const char *name;
+ int64_t write_sysno;
+};
+
+static const struct SyscallInfo arch_syscall_info[] = {
+ { "aarch64", 64 },
+ { "aarch64_be", 64 },
+ { "alpha", 4 },
+ { "arm", 4 },
+ { "armeb", 4 },
+ { "avr", -1 },
+ { "hexagon", 64 },
+ { "hppa", -1 },
+ { "i386", 4 },
+ { "loongarch64", -1 },
+ { "m68k", 4 },
+ { "microblaze", 4 },
+ { "microblazeel", 4 },
+ { "mips", 1 },
+ { "mips64", 1 },
+ { "mips64el", 1 },
+ { "mipsel", 1 },
+ { "mipsn32", 1 },
+ { "mipsn32el", 1 },
+ { "or1k", -1 },
+ { "ppc", 4 },
+ { "ppc64", 4 },
+ { "ppc64le", 4 },
+ { "riscv32", 64 },
+ { "riscv64", 64 },
+ { "rx", -1 },
+ { "s390x", -1 },
+ { "sh4", -1 },
+ { "sh4eb", -1 },
+ { "sparc", 4 },
+ { "sparc32plus", 4 },
+ { "sparc64", 4 },
+ { "tricore", -1 },
+ { "x86_64", 1 },
+ { "xtensa", 13 },
+ { "xtensaeb", 13 },
+ { NULL, -1 },
+};
+
static GMutex lock;
static GHashTable *statistics;
+static GByteArray *memory_buffer;
+static bool do_log_writes;
+static int64_t write_sysno = -1;
static SyscallStats *get_or_create_entry(int64_t num)
{
SyscallStats *entry =
- (SyscallStats *) g_hash_table_lookup(statistics, GINT_TO_POINTER(num));
+ (SyscallStats *) g_hash_table_lookup(statistics, &num);
if (!entry) {
entry = g_new0(SyscallStats, 1);
entry->num = num;
- g_hash_table_insert(statistics, GINT_TO_POINTER(num), (gpointer) entry);
+ g_hash_table_insert(statistics, &entry->num, entry);
}
return entry;
}
+/*
+ * Hex-dump a GByteArray to the QEMU plugin output in the format:
+ * 61 63 63 65 6c 09 09 20 20 20 66 70 75 09 09 09 | accel.....fpu...
+ * 20 6d 6f 64 75 6c 65 2d 63 6f 6d 6d 6f 6e 2e 63 | .module-common.c
+ */
+static void hexdump(const GByteArray *data)
+{
+ g_autoptr(GString) out = g_string_new("");
+
+ for (guint index = 0; index < data->len; index += 16) {
+ for (guint col = 0; col < 16; col++) {
+ if (index + col < data->len) {
+ g_string_append_printf(out, "%02x ", data->data[index + col]);
+ } else {
+ g_string_append(out, " ");
+ }
+ }
+
+ g_string_append(out, " | ");
+
+ for (guint col = 0; col < 16; col++) {
+ if (index + col >= data->len) {
+ break;
+ }
+
+ if (g_ascii_isgraph(data->data[index + col])) {
+ g_string_append_printf(out, "%c", data->data[index + col]);
+ } else {
+ g_string_append(out, ".");
+ }
+ }
+
+ g_string_append(out, "\n");
+ }
+
+ qemu_plugin_outs(out->str);
+}
+
static void vcpu_syscall(qemu_plugin_id_t id, unsigned int vcpu_index,
int64_t num, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5,
@@ -54,6 +140,14 @@ static void vcpu_syscall(qemu_plugin_id_t id, unsigned int vcpu_index,
g_autofree gchar *out = g_strdup_printf("syscall #%" PRIi64 "\n", num);
qemu_plugin_outs(out);
}
+
+ if (do_log_writes && num == write_sysno) {
+ if (qemu_plugin_read_memory_vaddr(a2, memory_buffer, a3)) {
+ hexdump(memory_buffer);
+ } else {
+ fprintf(stderr, "Error reading memory from vaddr %"PRIu64"\n", a2);
+ }
+ }
}
static void vcpu_syscall_ret(qemu_plugin_id_t id, unsigned int vcpu_idx,
@@ -86,7 +180,7 @@ static void print_entry(gpointer val, gpointer user_data)
qemu_plugin_outs(out);
}
-static gint comp_func(gconstpointer ea, gconstpointer eb)
+static gint comp_func(gconstpointer ea, gconstpointer eb, gpointer d)
{
SyscallStats *ent_a = (SyscallStats *) ea;
SyscallStats *ent_b = (SyscallStats *) eb;
@@ -103,7 +197,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
g_mutex_lock(&lock);
GList *entries = g_hash_table_get_values(statistics);
- entries = g_list_sort(entries, comp_func);
+ entries = g_list_sort_with_data(entries, comp_func, NULL);
qemu_plugin_outs("syscall no. calls errors\n");
g_list_foreach(entries, print_entry, NULL);
@@ -127,6 +221,10 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_print)) {
fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
}
+ } else if (g_strcmp0(tokens[0], "log_writes") == 0) {
+ if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_log_writes)) {
+ fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
+ }
} else {
fprintf(stderr, "unsupported argument: %s\n", argv[i]);
return -1;
@@ -134,7 +232,25 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
}
if (!do_print) {
- statistics = g_hash_table_new_full(NULL, g_direct_equal, NULL, g_free);
+ statistics = g_hash_table_new_full(g_int64_hash, g_int64_equal, NULL, g_free);
+ }
+
+ if (do_log_writes) {
+ for (const struct SyscallInfo *syscall_info = arch_syscall_info;
+ syscall_info->name != NULL; syscall_info++) {
+
+ if (g_strcmp0(syscall_info->name, info->target_name) == 0) {
+ write_sysno = syscall_info->write_sysno;
+ break;
+ }
+ }
+
+ if (write_sysno == -1) {
+ fprintf(stderr, "write syscall number not found\n");
+ return -1;
+ }
+
+ memory_buffer = g_byte_array_new();
}
qemu_plugin_register_vcpu_syscall_cb(id, vcpu_syscall);
diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target
index 509a20b..0d058b2 100644
--- a/tests/tcg/ppc64/Makefile.target
+++ b/tests/tcg/ppc64/Makefile.target
@@ -6,7 +6,7 @@ VPATH += $(SRC_PATH)/tests/tcg/ppc64
config-cc.mak: Makefile
$(quiet-@)( \
- $(call cc-option,-mpower8-vector, CROSS_CC_HAS_POWER8_VECTOR); \
+ $(call cc-option,-mcpu=power8, CROSS_CC_HAS_CPU_POWER8); \
$(call cc-option,-mpower10, CROSS_CC_HAS_POWER10)) 3> config-cc.mak
-include config-cc.mak
@@ -23,15 +23,15 @@ run-threadcount: threadcount
run-plugin-threadcount-with-%:
$(call skip-test, $<, "BROKEN (flaky with clang) ")
-ifneq ($(CROSS_CC_HAS_POWER8_VECTOR),)
+ifneq ($(CROSS_CC_HAS_CPU_POWER8),)
PPC64_TESTS=bcdsub non_signalling_xscv
endif
-$(PPC64_TESTS): CFLAGS += -mpower8-vector
+$(PPC64_TESTS): CFLAGS += -mcpu=power8
-ifneq ($(CROSS_CC_HAS_POWER8_VECTOR),)
+ifneq ($(CROSS_CC_HAS_CPU_POWER8),)
PPC64_TESTS += vsx_f2i_nan
endif
-vsx_f2i_nan: CFLAGS += -mpower8-vector -I$(SRC_PATH)/include
+vsx_f2i_nan: CFLAGS += -mcpu=power8 -I$(SRC_PATH)/include
PPC64_TESTS += mtfsf
PPC64_TESTS += mffsce
@@ -55,4 +55,9 @@ PPC64_TESTS += signal_save_restore_xer
PPC64_TESTS += xxspltw
PPC64_TESTS += test-aes
+# ppc64 ABI uses function descriptors, and thus, QEMU can't find symbol for a
+# given instruction. Thus, we don't check output of mem-access plugin.
+run-plugin-test-plugin-mem-access-with-libmem.so: \
+ CHECK_PLUGIN_OUTPUT_COMMAND=
+
TESTS += $(PPC64_TESTS)
diff --git a/tests/tcg/s390x/Makefile.softmmu-target b/tests/tcg/s390x/Makefile.softmmu-target
index f60f94b..8cd4667 100644
--- a/tests/tcg/s390x/Makefile.softmmu-target
+++ b/tests/tcg/s390x/Makefile.softmmu-target
@@ -1,8 +1,9 @@
S390X_SRC=$(SRC_PATH)/tests/tcg/s390x
VPATH+=$(S390X_SRC)
-QEMU_OPTS+=-action panic=exit-failure -nographic $(EXTFLAGS) -kernel
+# EXTFLAGS can be passed by the user, e.g. to override the --accel
+QEMU_OPTS+=-action panic=exit-failure -nographic -serial chardev:output $(EXTFLAGS) -kernel
LINK_SCRIPT=$(S390X_SRC)/softmmu.ld
-CFLAGS+=-ggdb -O0
+CFLAGS+=-ggdb -O0 -I$(SRC_PATH)/include/hw/s390x/ipl/
LDFLAGS=-nostdlib -static
%.o: %.S
@@ -41,8 +42,15 @@ $(ASM_TESTS): LDFLAGS += -Wl,-T$(LINK_SCRIPT) -Wl,--build-id=none
$(ASM_TESTS): $(LINK_SCRIPT)
TESTS += $(ASM_TESTS)
+MULTIARCH_TESTS += mvc-smc
S390X_MULTIARCH_RUNTIME_OBJS = head64.o console.o $(MINILIB_OBJS)
$(MULTIARCH_TESTS): $(S390X_MULTIARCH_RUNTIME_OBJS)
$(MULTIARCH_TESTS): LDFLAGS += $(S390X_MULTIARCH_RUNTIME_OBJS)
-$(MULTIARCH_TESTS): CFLAGS += $(MINILIB_INC)
+$(MULTIARCH_TESTS): CFLAGS += $(MINILIB_INC) \
+ -I$(SRC_PATH)/roms/SLOF/lib/libc/include/
memory: CFLAGS += -DCHECK_UNALIGNED=0
+
+# s390x clears the BSS section so we need to account for that
+run-plugin-memory-with-libmem.so: \
+ CHECK_PLUGIN_OUTPUT_COMMAND=$(MULTIARCH_SYSTEM_SRC)/validate-memory-counts.py \
+ --bss-cleared $@.out
diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target
index a8f86c9..da5fe71 100644
--- a/tests/tcg/s390x/Makefile.target
+++ b/tests/tcg/s390x/Makefile.target
@@ -48,6 +48,7 @@ TESTS+=lae
TESTS+=cvd
TESTS+=cvb
TESTS+=ts
+TESTS+=ex-smc
cdsg: CFLAGS+=-pthread
cdsg: LDFLAGS+=-pthread
@@ -73,8 +74,11 @@ $(Z13_TESTS): CFLAGS+=-march=z13 -O2
TESTS+=$(Z13_TESTS)
ifneq ($(CROSS_CC_HAS_Z14),)
-Z14_TESTS=vfminmax
+Z14_TESTS=fma vfminmax
+fma: float.h
+fma: LDFLAGS+=-lm
vfminmax: LDFLAGS+=-lm
+vfminmax: float.h
$(Z14_TESTS): CFLAGS+=-march=z14 -O2
TESTS+=$(Z14_TESTS)
endif
diff --git a/tests/tcg/s390x/console.c b/tests/tcg/s390x/console.c
index d43ce3f..6c26f04 100644
--- a/tests/tcg/s390x/console.c
+++ b/tests/tcg/s390x/console.c
@@ -4,7 +4,10 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
+
#include "../../../pc-bios/s390-ccw/sclp.c"
+#include "../../../roms/SLOF/lib/libc/string/memset.c"
+#include "../../../roms/SLOF/lib/libc/string/memcpy.c"
void __sys_outc(char c)
{
diff --git a/tests/tcg/s390x/ex-smc.c b/tests/tcg/s390x/ex-smc.c
new file mode 100644
index 0000000..f403640
--- /dev/null
+++ b/tests/tcg/s390x/ex-smc.c
@@ -0,0 +1,57 @@
+/*
+ * Test modifying an EXECUTE target.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <assert.h>
+#include <stdlib.h>
+
+/* Make sure we exercise the same EXECUTE instruction. */
+extern void execute(unsigned char *insn, unsigned char mask,
+ unsigned long *r1_r5);
+asm(".globl execute\n"
+ "execute:\n"
+ "lg %r1,0(%r4)\n"
+ "lg %r5,8(%r4)\n"
+ "ex %r3,0(%r2)\n"
+ "stg %r5,8(%r4)\n"
+ "stg %r1,0(%r4)\n"
+ "br %r14\n");
+
+/* Define an RWX EXECUTE target. */
+extern unsigned char lgfi[];
+asm(".pushsection .rwx,\"awx\",@progbits\n"
+ ".globl lgfi\n"
+ "lgfi: lgfi %r0,0\n"
+ ".popsection\n");
+
+int main(void)
+{
+ unsigned long r1_r5[2];
+
+ /* Create an initial TB. */
+ r1_r5[0] = -1;
+ r1_r5[1] = -1;
+ execute(lgfi, 1 << 4, r1_r5);
+ assert(r1_r5[0] == 0);
+ assert(r1_r5[1] == -1);
+
+ /* Test changing the mask. */
+ execute(lgfi, 5 << 4, r1_r5);
+ assert(r1_r5[0] == 0);
+ assert(r1_r5[1] == 0);
+
+ /* Test changing the target. */
+ lgfi[5] = 42;
+ execute(lgfi, 5 << 4, r1_r5);
+ assert(r1_r5[0] == 0);
+ assert(r1_r5[1] == 42);
+
+ /* Test changing both the mask and the target. */
+ lgfi[5] = 24;
+ execute(lgfi, 1 << 4, r1_r5);
+ assert(r1_r5[0] == 24);
+ assert(r1_r5[1] == 42);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/tcg/s390x/float.h b/tests/tcg/s390x/float.h
new file mode 100644
index 0000000..9d1682b
--- /dev/null
+++ b/tests/tcg/s390x/float.h
@@ -0,0 +1,104 @@
+/*
+ * Helpers for floating-point tests.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+/*
+ * Floating-point value classes.
+ */
+#define N_FORMATS 3
+#define CLASS_MINUS_INF 0
+#define CLASS_MINUS_FN 1
+#define CLASS_MINUS_ZERO 2
+#define CLASS_PLUS_ZERO 3
+#define CLASS_PLUS_FN 4
+#define CLASS_PLUS_INF 5
+#define CLASS_QNAN 6
+#define CLASS_SNAN 7
+#define N_SIGNED_CLASSES 8
+static const size_t float_sizes[N_FORMATS] = {
+ /* M4 == 2: short */ 4,
+ /* M4 == 3: long */ 8,
+ /* M4 == 4: extended */ 16,
+};
+static const size_t e_bits[N_FORMATS] = {
+ /* M4 == 2: short */ 8,
+ /* M4 == 3: long */ 11,
+ /* M4 == 4: extended */ 15,
+};
+struct float_class {
+ size_t n;
+ unsigned char v[2][16];
+};
+static const struct float_class signed_floats[N_FORMATS][N_SIGNED_CLASSES] = {
+ /* M4 == 2: short */
+ {
+ /* -inf */ {1, {{0xff, 0x80, 0x00, 0x00}}},
+ /* -Fn */ {2, {{0xc2, 0x28, 0x00, 0x00},
+ {0xc2, 0x29, 0x00, 0x00}}},
+ /* -0 */ {1, {{0x80, 0x00, 0x00, 0x00}}},
+ /* +0 */ {1, {{0x00, 0x00, 0x00, 0x00}}},
+ /* +Fn */ {2, {{0x42, 0x28, 0x00, 0x00},
+ {0x42, 0x2a, 0x00, 0x00}}},
+ /* +inf */ {1, {{0x7f, 0x80, 0x00, 0x00}}},
+ /* QNaN */ {2, {{0x7f, 0xff, 0xff, 0xff},
+ {0x7f, 0xff, 0xff, 0xfe}}},
+ /* SNaN */ {2, {{0x7f, 0xbf, 0xff, 0xff},
+ {0x7f, 0xbf, 0xff, 0xfd}}},
+ },
+
+ /* M4 == 3: long */
+ {
+ /* -inf */ {1, {{0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* -Fn */ {2, {{0xc0, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xc0, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* -0 */ {1, {{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* +0 */ {1, {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* +Fn */ {2, {{0x40, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x40, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* +inf */ {1, {{0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* QNaN */ {2, {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}}},
+ /* SNaN */ {2, {{0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd}}},
+ },
+
+ /* M4 == 4: extended */
+ {
+ /* -inf */ {1, {{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* -Fn */ {2, {{0xc0, 0x04, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xc0, 0x04, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* -0 */ {1, {{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* +0 */ {1, {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* +Fn */ {2, {{0x40, 0x04, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x40, 0x04, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* +inf */ {1, {{0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* QNaN */ {2, {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}}},
+ /* SNaN */ {2, {{0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd}}},
+ },
+};
+static const unsigned char default_nans[N_FORMATS][16] = {
+ /* M4 == 2: short */ {0x7f, 0xc0, 0x00, 0x00},
+ /* M4 == 3: long */ {0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ /* M4 == 4: extended */ {0x7f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+};
+
+static void dump_v(FILE *f, const void *v, size_t n)
+{
+ for (int i = 0; i < n; i++) {
+ fprintf(f, "%02x", ((const unsigned char *)v)[i]);
+ }
+}
+
+static void snan_to_qnan(char *v, int fmt)
+{
+ size_t bit = 1 + e_bits[fmt];
+ v[bit / 8] |= 1 << (7 - (bit % 8));
+}
+
+#endif
diff --git a/tests/tcg/s390x/fma.c b/tests/tcg/s390x/fma.c
new file mode 100644
index 0000000..6872f59
--- /dev/null
+++ b/tests/tcg/s390x/fma.c
@@ -0,0 +1,233 @@
+/*
+ * Test floating-point multiply-and-add instructions.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <fenv.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "float.h"
+
+union val {
+ float e;
+ double d;
+ long double x;
+ char buf[16];
+};
+
+/*
+ * PoP tables as close to the original as possible.
+ */
+static const char *table1[N_SIGNED_CLASSES][N_SIGNED_CLASSES] = {
+ /* -inf -Fn -0 +0 +Fn +inf QNaN SNaN */
+ {/* -inf */ "P(+inf)", "P(+inf)", "Xi: T(dNaN)", "Xi: T(dNaN)", "P(-inf)", "P(-inf)", "P(b)", "Xi: T(b*)"},
+ {/* -Fn */ "P(+inf)", "P(a*b)", "P(+0)", "P(-0)", "P(a*b)", "P(-inf)", "P(b)", "Xi: T(b*)"},
+ {/* -0 */ "Xi: T(dNaN)", "P(+0)", "P(+0)", "P(-0)", "P(-0)", "Xi: T(dNaN)", "P(b)", "Xi: T(b*)"},
+ {/* +0 */ "Xi: T(dNaN)", "P(-0)", "P(-0)", "P(+0)", "P(+0)", "Xi: T(dNaN)", "P(b)", "Xi: T(b*)"},
+ {/* +Fn */ "P(-inf)", "P(a*b)", "P(-0)", "P(+0)", "P(a*b)", "P(+inf)", "P(b)", "Xi: T(b*)"},
+ {/* +inf */ "P(-inf)", "P(-inf)", "Xi: T(dNaN)", "Xi: T(dNaN)", "P(+inf)", "P(+inf)", "P(b)", "Xi: T(b*)"},
+ {/* QNaN */ "P(a)", "P(a)", "P(a)", "P(a)", "P(a)", "P(a)", "P(a)", "Xi: T(b*)"},
+ {/* SNaN */ "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)"},
+};
+
+static const char *table2[N_SIGNED_CLASSES][N_SIGNED_CLASSES] = {
+ /* -inf -Fn -0 +0 +Fn +inf QNaN SNaN */
+ {/* -inf */ "T(-inf)", "T(-inf)", "T(-inf)", "T(-inf)", "T(-inf)", "Xi: T(dNaN)", "T(c)", "Xi: T(c*)"},
+ {/* -Fn */ "T(-inf)", "R(p+c)", "R(p)", "R(p)", "R(p+c)", "T(+inf)", "T(c)", "Xi: T(c*)"},
+ {/* -0 */ "T(-inf)", "R(c)", "T(-0)", "Rezd", "R(c)", "T(+inf)", "T(c)", "Xi: T(c*)"},
+ {/* +0 */ "T(-inf)", "R(c)", "Rezd", "T(+0)", "R(c)", "T(+inf)", "T(c)", "Xi: T(c*)"},
+ {/* +Fn */ "T(-inf)", "R(p+c)", "R(p)", "R(p)", "R(p+c)", "T(+inf)", "T(c)", "Xi: T(c*)"},
+ {/* +inf */ "Xi: T(dNaN)", "T(+inf)", "T(+inf)", "T(+inf)", "T(+inf)", "T(+inf)", "T(c)", "Xi: T(c*)"},
+ {/* QNaN */ "T(p)", "T(p)", "T(p)", "T(p)", "T(p)", "T(p)", "T(p)", "Xi: T(c*)"},
+ /* SNaN: can't happen */
+};
+
+static void interpret_tables(union val *r, bool *xi, int fmt,
+ int cls_a, const union val *a,
+ int cls_b, const union val *b,
+ int cls_c, const union val *c)
+{
+ const char *spec1 = table1[cls_a][cls_b];
+ const char *spec2;
+ union val p;
+ int cls_p;
+
+ *xi = false;
+
+ if (strcmp(spec1, "P(-inf)") == 0) {
+ cls_p = CLASS_MINUS_INF;
+ } else if (strcmp(spec1, "P(+inf)") == 0) {
+ cls_p = CLASS_PLUS_INF;
+ } else if (strcmp(spec1, "P(-0)") == 0) {
+ cls_p = CLASS_MINUS_ZERO;
+ } else if (strcmp(spec1, "P(+0)") == 0) {
+ cls_p = CLASS_PLUS_ZERO;
+ } else if (strcmp(spec1, "P(a)") == 0) {
+ cls_p = cls_a;
+ memcpy(&p, a, sizeof(p));
+ } else if (strcmp(spec1, "P(b)") == 0) {
+ cls_p = cls_b;
+ memcpy(&p, b, sizeof(p));
+ } else if (strcmp(spec1, "P(a*b)") == 0) {
+ /*
+ * In the general case splitting fma into multiplication and addition
+ * doesn't work, but this is the case with our test inputs.
+ */
+ cls_p = cls_a == cls_b ? CLASS_PLUS_FN : CLASS_MINUS_FN;
+ switch (fmt) {
+ case 0:
+ p.e = a->e * b->e;
+ break;
+ case 1:
+ p.d = a->d * b->d;
+ break;
+ case 2:
+ p.x = a->x * b->x;
+ break;
+ default:
+ fprintf(stderr, "Unsupported fmt: %d\n", fmt);
+ exit(1);
+ }
+ } else if (strcmp(spec1, "Xi: T(dNaN)") == 0) {
+ memcpy(r, default_nans[fmt], sizeof(*r));
+ *xi = true;
+ return;
+ } else if (strcmp(spec1, "Xi: T(a*)") == 0) {
+ memcpy(r, a, sizeof(*r));
+ snan_to_qnan(r->buf, fmt);
+ *xi = true;
+ return;
+ } else if (strcmp(spec1, "Xi: T(b*)") == 0) {
+ memcpy(r, b, sizeof(*r));
+ snan_to_qnan(r->buf, fmt);
+ *xi = true;
+ return;
+ } else {
+ fprintf(stderr, "Unsupported spec1: %s\n", spec1);
+ exit(1);
+ }
+
+ spec2 = table2[cls_p][cls_c];
+ if (strcmp(spec2, "T(-inf)") == 0) {
+ memcpy(r, signed_floats[fmt][CLASS_MINUS_INF].v[0], sizeof(*r));
+ } else if (strcmp(spec2, "T(+inf)") == 0) {
+ memcpy(r, signed_floats[fmt][CLASS_PLUS_INF].v[0], sizeof(*r));
+ } else if (strcmp(spec2, "T(-0)") == 0) {
+ memcpy(r, signed_floats[fmt][CLASS_MINUS_ZERO].v[0], sizeof(*r));
+ } else if (strcmp(spec2, "T(+0)") == 0 || strcmp(spec2, "Rezd") == 0) {
+ memcpy(r, signed_floats[fmt][CLASS_PLUS_ZERO].v[0], sizeof(*r));
+ } else if (strcmp(spec2, "R(c)") == 0 || strcmp(spec2, "T(c)") == 0) {
+ memcpy(r, c, sizeof(*r));
+ } else if (strcmp(spec2, "R(p)") == 0 || strcmp(spec2, "T(p)") == 0) {
+ memcpy(r, &p, sizeof(*r));
+ } else if (strcmp(spec2, "R(p+c)") == 0 || strcmp(spec2, "T(p+c)") == 0) {
+ switch (fmt) {
+ case 0:
+ r->e = p.e + c->e;
+ break;
+ case 1:
+ r->d = p.d + c->d;
+ break;
+ case 2:
+ r->x = p.x + c->x;
+ break;
+ default:
+ fprintf(stderr, "Unsupported fmt: %d\n", fmt);
+ exit(1);
+ }
+ } else if (strcmp(spec2, "Xi: T(dNaN)") == 0) {
+ memcpy(r, default_nans[fmt], sizeof(*r));
+ *xi = true;
+ } else if (strcmp(spec2, "Xi: T(c*)") == 0) {
+ memcpy(r, c, sizeof(*r));
+ snan_to_qnan(r->buf, fmt);
+ *xi = true;
+ } else {
+ fprintf(stderr, "Unsupported spec2: %s\n", spec2);
+ exit(1);
+ }
+}
+
+struct iter {
+ int fmt;
+ int cls[3];
+ int val[3];
+};
+
+static bool iter_next(struct iter *it)
+{
+ int i;
+
+ for (i = 2; i >= 0; i--) {
+ if (++it->val[i] != signed_floats[it->fmt][it->cls[i]].n) {
+ return true;
+ }
+ it->val[i] = 0;
+
+ if (++it->cls[i] != N_SIGNED_CLASSES) {
+ return true;
+ }
+ it->cls[i] = 0;
+ }
+
+ return ++it->fmt != N_FORMATS;
+}
+
+int main(void)
+{
+ int ret = EXIT_SUCCESS;
+ struct iter it = {};
+
+ do {
+ size_t n = float_sizes[it.fmt];
+ union val a, b, c, exp, res;
+ bool xi_exp, xi;
+
+ memcpy(&a, signed_floats[it.fmt][it.cls[0]].v[it.val[0]], sizeof(a));
+ memcpy(&b, signed_floats[it.fmt][it.cls[1]].v[it.val[1]], sizeof(b));
+ memcpy(&c, signed_floats[it.fmt][it.cls[2]].v[it.val[2]], sizeof(c));
+
+ interpret_tables(&exp, &xi_exp, it.fmt,
+ it.cls[1], &b, it.cls[2], &c, it.cls[0], &a);
+
+ memcpy(&res, &a, sizeof(res));
+ feclearexcept(FE_ALL_EXCEPT);
+ switch (it.fmt) {
+ case 0:
+ asm("maebr %[a],%[b],%[c]"
+ : [a] "+f" (res.e) : [b] "f" (b.e), [c] "f" (c.e));
+ break;
+ case 1:
+ asm("madbr %[a],%[b],%[c]"
+ : [a] "+f" (res.d) : [b] "f" (b.d), [c] "f" (c.d));
+ break;
+ case 2:
+ asm("wfmaxb %[a],%[c],%[b],%[a]"
+ : [a] "+v" (res.x) : [b] "v" (b.x), [c] "v" (c.x));
+ break;
+ default:
+ fprintf(stderr, "Unsupported fmt: %d\n", it.fmt);
+ exit(1);
+ }
+ xi = fetestexcept(FE_ALL_EXCEPT) == FE_INVALID;
+
+ if (memcmp(&res, &exp, n) != 0 || xi != xi_exp) {
+ fprintf(stderr, "[ FAILED ] ");
+ dump_v(stderr, &b, n);
+ fprintf(stderr, " * ");
+ dump_v(stderr, &c, n);
+ fprintf(stderr, " + ");
+ dump_v(stderr, &a, n);
+ fprintf(stderr, ": actual=");
+ dump_v(stderr, &res, n);
+ fprintf(stderr, "/%d, expected=", (int)xi);
+ dump_v(stderr, &exp, n);
+ fprintf(stderr, "/%d\n", (int)xi_exp);
+ ret = EXIT_FAILURE;
+ }
+ } while (iter_next(&it));
+
+ return ret;
+}
diff --git a/tests/tcg/s390x/mvc-smc.c b/tests/tcg/s390x/mvc-smc.c
new file mode 100644
index 0000000..d68f60c
--- /dev/null
+++ b/tests/tcg/s390x/mvc-smc.c
@@ -0,0 +1,82 @@
+/*
+ * Test modifying code using the MVC instruction.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <minilib.h>
+
+#define PAGE_SIZE 4096
+#define BR_14_SIZE 2
+#define RWX_OFFSET 2
+
+static unsigned char rw[PAGE_SIZE + BR_14_SIZE];
+static unsigned char rwx[RWX_OFFSET + sizeof(rw)]
+ __attribute__((aligned(PAGE_SIZE)));
+
+typedef unsigned long (*function_t)(unsigned long);
+
+static int emit_function(unsigned char *p, int n)
+{
+ int i = 0, val = 0;
+
+ while (i < n - 2) {
+ /* aghi %r2,1 */
+ p[i++] = 0xa7;
+ p[i++] = 0x2b;
+ p[i++] = 0x00;
+ p[i++] = 0x01;
+ val++;
+ }
+
+ /* br %r14 */
+ p[i++] = 0x07;
+ p[i++] = 0xfe;
+
+ return val;
+}
+
+static void memcpy_mvc(void *dest, void *src, unsigned long n)
+{
+ while (n >= 256) {
+ asm("mvc 0(256,%[dest]),0(%[src])"
+ :
+ : [dest] "a" (dest)
+ , [src] "a" (src)
+ : "memory");
+ dest += 256;
+ src += 256;
+ n -= 256;
+ }
+ asm("exrl %[n],0f\n"
+ "j 1f\n"
+ "0: mvc 0(1,%[dest]),0(%[src])\n"
+ "1:"
+ :
+ : [dest] "a" (dest)
+ , [src] "a" (src)
+ , [n] "a" (n)
+ : "memory");
+}
+
+int main(void)
+{
+ int expected, size;
+
+ /* Create a TB. */
+ size = sizeof(rwx) - RWX_OFFSET - 4;
+ expected = emit_function(rwx + RWX_OFFSET, size);
+ if (((function_t)(rwx + RWX_OFFSET))(0) != expected) {
+ return 1;
+ }
+
+ /* Overwrite the TB. */
+ size += 4;
+ expected = emit_function(rw, size);
+ memcpy_mvc(rwx + RWX_OFFSET, rw, size);
+ if (((function_t)(rwx + RWX_OFFSET))(0) != expected) {
+ return 2;
+ }
+
+ return 0;
+}
diff --git a/tests/tcg/s390x/vfminmax.c b/tests/tcg/s390x/vfminmax.c
index 22629df..e66285f 100644
--- a/tests/tcg/s390x/vfminmax.c
+++ b/tests/tcg/s390x/vfminmax.c
@@ -4,6 +4,8 @@
#include <stdio.h>
#include <string.h>
+#include "float.h"
+
/*
* vfmin/vfmax instruction execution.
*/
@@ -21,99 +23,22 @@ static void vfminmax(unsigned int op,
unsigned int m4, unsigned int m5, unsigned int m6,
void *v1, const void *v2, const void *v3)
{
- insn[3] = (m6 << 4) | m5;
- insn[4] = (m4 << 4) | 0x0e;
- insn[5] = op;
+ insn[3] = (m6 << 4) | m5;
+ insn[4] = (m4 << 4) | 0x0e;
+ insn[5] = op;
asm("vl %%v25,%[v2]\n"
"vl %%v26,%[v3]\n"
"ex 0,%[insn]\n"
"vst %%v24,%[v1]\n"
: [v1] "=m" (*(char (*)[16])v1)
- : [v2] "m" (*(char (*)[16])v2)
- , [v3] "m" (*(char (*)[16])v3)
- , [insn] "m"(insn)
+ : [v2] "m" (*(const char (*)[16])v2)
+ , [v3] "m" (*(const char (*)[16])v3)
+ , [insn] "m" (insn)
: "v24", "v25", "v26");
}
/*
- * Floating-point value classes.
- */
-#define N_FORMATS 3
-#define N_SIGNED_CLASSES 8
-static const size_t float_sizes[N_FORMATS] = {
- /* M4 == 2: short */ 4,
- /* M4 == 3: long */ 8,
- /* M4 == 4: extended */ 16,
-};
-static const size_t e_bits[N_FORMATS] = {
- /* M4 == 2: short */ 8,
- /* M4 == 3: long */ 11,
- /* M4 == 4: extended */ 15,
-};
-static const unsigned char signed_floats[N_FORMATS][N_SIGNED_CLASSES][2][16] = {
- /* M4 == 2: short */
- {
- /* -inf */ {{0xff, 0x80, 0x00, 0x00},
- {0xff, 0x80, 0x00, 0x00}},
- /* -Fn */ {{0xc2, 0x28, 0x00, 0x00},
- {0xc2, 0x29, 0x00, 0x00}},
- /* -0 */ {{0x80, 0x00, 0x00, 0x00},
- {0x80, 0x00, 0x00, 0x00}},
- /* +0 */ {{0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00}},
- /* +Fn */ {{0x42, 0x28, 0x00, 0x00},
- {0x42, 0x2a, 0x00, 0x00}},
- /* +inf */ {{0x7f, 0x80, 0x00, 0x00},
- {0x7f, 0x80, 0x00, 0x00}},
- /* QNaN */ {{0x7f, 0xff, 0xff, 0xff},
- {0x7f, 0xff, 0xff, 0xfe}},
- /* SNaN */ {{0x7f, 0xbf, 0xff, 0xff},
- {0x7f, 0xbf, 0xff, 0xfd}},
- },
-
- /* M4 == 3: long */
- {
- /* -inf */ {{0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
- /* -Fn */ {{0xc0, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0xc0, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
- /* -0 */ {{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
- /* +0 */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
- /* +Fn */ {{0x40, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x40, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
- /* +inf */ {{0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
- /* QNaN */ {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}},
- /* SNaN */ {{0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd}},
- },
-
- /* M4 == 4: extended */
- {
- /* -inf */ {{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
- /* -Fn */ {{0xc0, 0x04, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0xc0, 0x04, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
- /* -0 */ {{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
- /* +0 */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
- /* +Fn */ {{0x40, 0x04, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x40, 0x04, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
- /* +inf */ {{0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
- /* QNaN */ {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}},
- /* SNaN */ {{0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd}},
- },
-};
-
-/*
* PoP tables as close to the original as possible.
*/
struct signed_test {
@@ -285,13 +210,6 @@ struct signed_test {
},
};
-static void dump_v(FILE *f, const void *v, size_t n)
-{
- for (int i = 0; i < n; i++) {
- fprintf(f, "%02x", ((const unsigned char *)v)[i]);
- }
-}
-
static int signed_test(struct signed_test *test, int m4, int m5,
const void *v1_exp, bool xi_exp,
const void *v2, const void *v3)
@@ -320,10 +238,28 @@ static int signed_test(struct signed_test *test, int m4, int m5,
return 0;
}
-static void snan_to_qnan(char *v, int m4)
+struct iter {
+ int cls[2];
+ int val[2];
+};
+
+static bool iter_next(struct iter *it, int fmt)
{
- size_t bit = 1 + e_bits[m4 - 2];
- v[bit / 8] |= 1 << (7 - (bit % 8));
+ int i;
+
+ for (i = 1; i >= 0; i--) {
+ if (++it->val[i] != signed_floats[fmt][it->cls[i]].n) {
+ return true;
+ }
+ it->val[i] = 0;
+
+ if (++it->cls[i] != N_SIGNED_CLASSES) {
+ return true;
+ }
+ it->cls[i] = 0;
+ }
+
+ return false;
}
int main(void)
@@ -333,72 +269,71 @@ int main(void)
for (i = 0; i < sizeof(signed_tests) / sizeof(signed_tests[0]); i++) {
struct signed_test *test = &signed_tests[i];
- int m4;
+ int fmt;
- for (m4 = 2; m4 <= 4; m4++) {
- const unsigned char (*floats)[2][16] = signed_floats[m4 - 2];
- size_t float_size = float_sizes[m4 - 2];
+ for (fmt = 0; fmt < N_FORMATS; fmt++) {
+ size_t float_size = float_sizes[fmt];
+ int m4 = fmt + 2;
int m5;
for (m5 = 0; m5 <= 8; m5 += 8) {
char v1_exp[16], v2[16], v3[16];
bool xi_exp = false;
+ struct iter it = {};
int pos = 0;
- int i2;
- for (i2 = 0; i2 < N_SIGNED_CLASSES * 2; i2++) {
- int i3;
+ do {
+ const char *spec = test->table[it.cls[0]][it.cls[1]];
- for (i3 = 0; i3 < N_SIGNED_CLASSES * 2; i3++) {
- const char *spec = test->table[i2 / 2][i3 / 2];
+ memcpy(&v2[pos],
+ signed_floats[fmt][it.cls[0]].v[it.val[0]],
+ float_size);
+ memcpy(&v3[pos],
+ signed_floats[fmt][it.cls[1]].v[it.val[1]],
+ float_size);
+ if (strcmp(spec, "T(a)") == 0 ||
+ strcmp(spec, "Xi: T(a)") == 0) {
+ memcpy(&v1_exp[pos], &v2[pos], float_size);
+ } else if (strcmp(spec, "T(b)") == 0 ||
+ strcmp(spec, "Xi: T(b)") == 0) {
+ memcpy(&v1_exp[pos], &v3[pos], float_size);
+ } else if (strcmp(spec, "Xi: T(a*)") == 0) {
+ memcpy(&v1_exp[pos], &v2[pos], float_size);
+ snan_to_qnan(&v1_exp[pos], fmt);
+ } else if (strcmp(spec, "Xi: T(b*)") == 0) {
+ memcpy(&v1_exp[pos], &v3[pos], float_size);
+ snan_to_qnan(&v1_exp[pos], fmt);
+ } else if (strcmp(spec, "T(M(a,b))") == 0) {
+ /*
+ * Comparing floats is risky, since the compiler might
+ * generate the same instruction that we are testing.
+ * Compare ints instead. This works, because we get
+ * here only for +-Fn, and the corresponding test
+ * values have identical exponents.
+ */
+ int v2_int = *(int *)&v2[pos];
+ int v3_int = *(int *)&v3[pos];
- memcpy(&v2[pos], floats[i2 / 2][i2 % 2], float_size);
- memcpy(&v3[pos], floats[i3 / 2][i3 % 2], float_size);
- if (strcmp(spec, "T(a)") == 0 ||
- strcmp(spec, "Xi: T(a)") == 0) {
+ if ((v2_int < v3_int) ==
+ ((test->op == VFMIN) != (v2_int < 0))) {
memcpy(&v1_exp[pos], &v2[pos], float_size);
- } else if (strcmp(spec, "T(b)") == 0 ||
- strcmp(spec, "Xi: T(b)") == 0) {
- memcpy(&v1_exp[pos], &v3[pos], float_size);
- } else if (strcmp(spec, "Xi: T(a*)") == 0) {
- memcpy(&v1_exp[pos], &v2[pos], float_size);
- snan_to_qnan(&v1_exp[pos], m4);
- } else if (strcmp(spec, "Xi: T(b*)") == 0) {
- memcpy(&v1_exp[pos], &v3[pos], float_size);
- snan_to_qnan(&v1_exp[pos], m4);
- } else if (strcmp(spec, "T(M(a,b))") == 0) {
- /*
- * Comparing floats is risky, since the compiler
- * might generate the same instruction that we are
- * testing. Compare ints instead. This works,
- * because we get here only for +-Fn, and the
- * corresponding test values have identical
- * exponents.
- */
- int v2_int = *(int *)&v2[pos];
- int v3_int = *(int *)&v3[pos];
-
- if ((v2_int < v3_int) ==
- ((test->op == VFMIN) != (v2_int < 0))) {
- memcpy(&v1_exp[pos], &v2[pos], float_size);
- } else {
- memcpy(&v1_exp[pos], &v3[pos], float_size);
- }
} else {
- fprintf(stderr, "Unexpected spec: %s\n", spec);
- return 1;
+ memcpy(&v1_exp[pos], &v3[pos], float_size);
}
- xi_exp |= spec[0] == 'X';
- pos += float_size;
+ } else {
+ fprintf(stderr, "Unexpected spec: %s\n", spec);
+ return 1;
+ }
+ xi_exp |= spec[0] == 'X';
+ pos += float_size;
- if ((m5 & 8) || pos == 16) {
- ret |= signed_test(test, m4, m5,
- v1_exp, xi_exp, v2, v3);
- pos = 0;
- xi_exp = false;
- }
+ if ((m5 & 8) || pos == 16) {
+ ret |= signed_test(test, m4, m5,
+ v1_exp, xi_exp, v2, v3);
+ pos = 0;
+ xi_exp = false;
}
- }
+ } while (iter_next(&it, fmt));
if (pos != 0) {
ret |= signed_test(test, m4, m5, v1_exp, xi_exp, v2, v3);
diff --git a/tests/tcg/x86_64/Makefile.softmmu-target b/tests/tcg/x86_64/Makefile.softmmu-target
index ef6bcb4..3e30ca9 100644
--- a/tests/tcg/x86_64/Makefile.softmmu-target
+++ b/tests/tcg/x86_64/Makefile.softmmu-target
@@ -1,13 +1,11 @@
#
-# x86 system tests
-#
-# This currently builds only for i386. The common C code is built
-# with standard compiler flags however so we can support both by
-# adding additional boot files for x86_64.
+# x86_64 system tests
#
-I386_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/i386/system
X64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/x86_64/system
+X64_SYSTEM_TESTS=$(patsubst $(X64_SYSTEM_SRC)/%.c, %, $(wildcard $(X64_SYSTEM_SRC)/*.c))
+
+VPATH+=$(X64_SYSTEM_SRC)
# These objects provide the basic boot code and helper functions for all tests
CRT_OBJS=boot.o
@@ -18,7 +16,7 @@ LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_x86_64
CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
-TESTS+=$(MULTIARCH_TESTS)
+TESTS+=$(MULTIARCH_TESTS) $(X64_SYSTEM_TESTS)
EXTRA_RUNS+=$(MULTIARCH_RUNS)
# building head blobs
@@ -35,3 +33,12 @@ memory: CFLAGS+=-DCHECK_UNALIGNED=1
# Running
QEMU_OPTS+=-device isa-debugcon,chardev=output -device isa-debug-exit,iobase=0xf4,iosize=0x4 -kernel
+
+ifeq ($(CONFIG_PLUGIN),y)
+run-plugin-patch-target-with-libpatch.so: \
+ PLUGIN_ARGS=$(COMMA)target=ffc0$(COMMA)patch=9090$(COMMA)use_hwaddr=true
+run-plugin-patch-target-with-libpatch.so: \
+ CHECK_PLUGIN_OUTPUT_COMMAND=$(X64_SYSTEM_SRC)/validate-patch.py $@.out
+run-plugin-patch-target-with-libpatch.so: patch-target libpatch.so
+EXTRA_RUNS+=run-plugin-patch-target-with-libpatch.so
+endif
diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target
index 783ab5b..be20fc6 100644
--- a/tests/tcg/x86_64/Makefile.target
+++ b/tests/tcg/x86_64/Makefile.target
@@ -17,6 +17,8 @@ X86_64_TESTS += cmpxchg
X86_64_TESTS += adox
X86_64_TESTS += test-1648
X86_64_TESTS += test-2175
+X86_64_TESTS += cross-modifying-code
+X86_64_TESTS += fma
TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64
else
TESTS=$(MULTIARCH_TESTS)
@@ -27,6 +29,9 @@ adox: CFLAGS=-O2
run-test-i386-ssse3: QEMU_OPTS += -cpu max
run-plugin-test-i386-ssse3-%: QEMU_OPTS += -cpu max
+cross-modifying-code: CFLAGS+=-pthread
+cross-modifying-code: LDFLAGS+=-pthread
+
test-x86_64: LDFLAGS+=-lm -lc
test-x86_64: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
diff --git a/tests/tcg/x86_64/cross-modifying-code.c b/tests/tcg/x86_64/cross-modifying-code.c
new file mode 100644
index 0000000..2704df6
--- /dev/null
+++ b/tests/tcg/x86_64/cross-modifying-code.c
@@ -0,0 +1,80 @@
+/*
+ * Test patching code, running in one thread, from another thread.
+ *
+ * Intel SDM calls this "cross-modifying code" and recommends a special
+ * sequence, which requires both threads to cooperate.
+ *
+ * Linux kernel uses a different sequence that does not require cooperation and
+ * involves patching the first byte with int3.
+ *
+ * Finally, there is user-mode software out there that simply uses atomics, and
+ * that seems to be good enough in practice. Test that QEMU has no problems
+ * with this as well.
+ */
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+void add1_or_nop(long *x);
+asm(".pushsection .rwx,\"awx\",@progbits\n"
+ ".globl add1_or_nop\n"
+ /* addq $0x1,(%rdi) */
+ "add1_or_nop: .byte 0x48, 0x83, 0x07, 0x01\n"
+ "ret\n"
+ ".popsection\n");
+
+#define THREAD_WAIT 0
+#define THREAD_PATCH 1
+#define THREAD_STOP 2
+
+static void *thread_func(void *arg)
+{
+ int val = 0x0026748d; /* nop */
+
+ while (true) {
+ switch (__atomic_load_n((int *)arg, __ATOMIC_SEQ_CST)) {
+ case THREAD_WAIT:
+ break;
+ case THREAD_PATCH:
+ val = __atomic_exchange_n((int *)&add1_or_nop, val,
+ __ATOMIC_SEQ_CST);
+ break;
+ case THREAD_STOP:
+ return NULL;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ }
+ }
+}
+
+#define INITIAL 42
+#define COUNT 1000000
+
+int main(void)
+{
+ int command = THREAD_WAIT;
+ pthread_t thread;
+ long x = 0;
+ int err;
+ int i;
+
+ err = pthread_create(&thread, NULL, &thread_func, &command);
+ assert(err == 0);
+
+ __atomic_store_n(&command, THREAD_PATCH, __ATOMIC_SEQ_CST);
+ for (i = 0; i < COUNT; i++) {
+ add1_or_nop(&x);
+ }
+ __atomic_store_n(&command, THREAD_STOP, __ATOMIC_SEQ_CST);
+
+ err = pthread_join(thread, NULL);
+ assert(err == 0);
+
+ assert(x >= INITIAL);
+ assert(x <= INITIAL + COUNT);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/tcg/x86_64/fma.c b/tests/tcg/x86_64/fma.c
new file mode 100644
index 0000000..3421961
--- /dev/null
+++ b/tests/tcg/x86_64/fma.c
@@ -0,0 +1,116 @@
+/*
+ * Test some fused multiply add corner cases.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/*
+ * Perform one "n * m + a" operation using the vfmadd insn and return
+ * the result; on return *mxcsr_p is set to the bottom 6 bits of MXCSR
+ * (the Flag bits). If ftz is true then we set MXCSR.FTZ while doing
+ * the operation.
+ * We print the operation and its results to stdout.
+ */
+static uint64_t do_fmadd(uint64_t n, uint64_t m, uint64_t a,
+ bool ftz, uint32_t *mxcsr_p)
+{
+ uint64_t r;
+ uint32_t mxcsr = 0;
+ uint32_t ftz_bit = ftz ? (1 << 15) : 0;
+ uint32_t saved_mxcsr = 0;
+
+ asm volatile("stmxcsr %[saved_mxcsr]\n"
+ "stmxcsr %[mxcsr]\n"
+ "andl $0xffff7fc0, %[mxcsr]\n"
+ "orl %[ftz_bit], %[mxcsr]\n"
+ "ldmxcsr %[mxcsr]\n"
+ "movq %[a], %%xmm0\n"
+ "movq %[m], %%xmm1\n"
+ "movq %[n], %%xmm2\n"
+ /* xmm0 = xmm0 + xmm2 * xmm1 */
+ "vfmadd231sd %%xmm1, %%xmm2, %%xmm0\n"
+ "movq %%xmm0, %[r]\n"
+ "stmxcsr %[mxcsr]\n"
+ "ldmxcsr %[saved_mxcsr]\n"
+ : [r] "=r" (r), [mxcsr] "=m" (mxcsr),
+ [saved_mxcsr] "=m" (saved_mxcsr)
+ : [n] "r" (n), [m] "r" (m), [a] "r" (a),
+ [ftz_bit] "r" (ftz_bit)
+ : "xmm0", "xmm1", "xmm2");
+ *mxcsr_p = mxcsr & 0x3f;
+ printf("vfmadd132sd 0x%" PRIx64 " 0x%" PRIx64 " 0x%" PRIx64
+ " = 0x%" PRIx64 " MXCSR flags 0x%" PRIx32 "\n",
+ n, m, a, r, *mxcsr_p);
+ return r;
+}
+
+typedef struct testdata {
+ /* Input n, m, a */
+ uint64_t n;
+ uint64_t m;
+ uint64_t a;
+ bool ftz;
+ /* Expected result */
+ uint64_t expected_r;
+ /* Expected low 6 bits of MXCSR (the Flag bits) */
+ uint32_t expected_mxcsr;
+} testdata;
+
+static testdata tests[] = {
+ { 0, 0x7ff0000000000000, 0x7ff000000000aaaa, false, /* 0 * Inf + SNaN */
+ 0x7ff800000000aaaa, 1 }, /* Should be QNaN and does raise Invalid */
+ { 0, 0x7ff0000000000000, 0x7ff800000000aaaa, false, /* 0 * Inf + QNaN */
+ 0x7ff800000000aaaa, 0 }, /* Should be QNaN and does *not* raise Invalid */
+ /*
+ * These inputs give a result which is tiny before rounding but which
+ * becomes non-tiny after rounding. x86 is a "detect tininess after
+ * rounding" architecture, so it should give a non-denormal result and
+ * not set the Underflow flag (only the Precision flag for an inexact
+ * result).
+ */
+ { 0x3fdfffffffffffff, 0x001fffffffffffff, 0x801fffffffffffff, false,
+ 0x8010000000000000, 0x20 },
+ /*
+ * Flushing of denormal outputs to zero should also happen after
+ * rounding, so setting FTZ should not affect the result or the flags.
+ */
+ { 0x3fdfffffffffffff, 0x001fffffffffffff, 0x801fffffffffffff, true,
+ 0x8010000000000000, 0x20 }, /* Enabling FTZ shouldn't change flags */
+ /*
+ * normal * 0 + a denormal. With FTZ disabled this gives an exact
+ * result (equal to the input denormal) that has consumed the denormal.
+ */
+ { 0x3cc8000000000000, 0x0000000000000000, 0x8008000000000000, false,
+ 0x8008000000000000, 0x2 }, /* Denormal */
+ /*
+ * With FTZ enabled, this consumes the denormal, returns zero (because
+ * flushed) and indicates also Underflow and Precision.
+ */
+ { 0x3cc8000000000000, 0x0000000000000000, 0x8008000000000000, true,
+ 0x8000000000000000, 0x32 }, /* Precision, Underflow, Denormal */
+};
+
+int main(void)
+{
+ bool passed = true;
+ for (int i = 0; i < ARRAY_SIZE(tests); i++) {
+ uint32_t mxcsr;
+ uint64_t r = do_fmadd(tests[i].n, tests[i].m, tests[i].a,
+ tests[i].ftz, &mxcsr);
+ if (r != tests[i].expected_r) {
+ printf("expected result 0x%" PRIx64 "\n", tests[i].expected_r);
+ passed = false;
+ }
+ if (mxcsr != tests[i].expected_mxcsr) {
+ printf("expected MXCSR flags 0x%x\n", tests[i].expected_mxcsr);
+ passed = false;
+ }
+ }
+ return passed ? 0 : 1;
+}
diff --git a/tests/tcg/x86_64/system/patch-target.c b/tests/tcg/x86_64/system/patch-target.c
new file mode 100644
index 0000000..8c2b6f4
--- /dev/null
+++ b/tests/tcg/x86_64/system/patch-target.c
@@ -0,0 +1,22 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This test target increments a value 100 times. The patcher converts the
+ * inc instruction to a nop, so it only increments the value once.
+ *
+ */
+#include <minilib.h>
+
+int main(void)
+{
+ ml_printf("Running test...\n");
+ unsigned int x = 0;
+ for (int i = 0; i < 100; i++) {
+ asm volatile (
+ "inc %[x]"
+ : [x] "+a" (x)
+ );
+ }
+ ml_printf("Value: %d\n", x);
+ return 0;
+}
diff --git a/tests/tcg/x86_64/system/validate-patch.py b/tests/tcg/x86_64/system/validate-patch.py
new file mode 100755
index 0000000..700950e
--- /dev/null
+++ b/tests/tcg/x86_64/system/validate-patch.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+#
+# validate-patch.py: check the patch applies
+#
+# This program takes two inputs:
+# - the plugin output
+# - the binary output
+#
+# Copyright (C) 2024
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import sys
+from argparse import ArgumentParser
+
+def main() -> None:
+ """
+ Process the arguments, injest the program and plugin out and
+ verify they match up and report if they do not.
+ """
+ parser = ArgumentParser(description="Validate patch")
+ parser.add_argument('test_output',
+ help="The output from the test itself")
+ parser.add_argument('plugin_output',
+ help="The output from plugin")
+ args = parser.parse_args()
+
+ with open(args.test_output, 'r') as f:
+ test_data = f.read()
+ with open(args.plugin_output, 'r') as f:
+ plugin_data = f.read()
+ if "Value: 1" in test_data:
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
+
diff --git a/tests/uefi-test-tools/Makefile b/tests/uefi-test-tools/Makefile
index f4eaebd..8ee6fb3 100644
--- a/tests/uefi-test-tools/Makefile
+++ b/tests/uefi-test-tools/Makefile
@@ -12,7 +12,7 @@
edk2_dir := ../../roms/edk2
images_dir := ../data/uefi-boot-images
-emulation_targets := arm aarch64 i386 x86_64 riscv64
+emulation_targets := arm aarch64 i386 x86_64 riscv64 loongarch64
uefi_binaries := bios-tables-test
intermediate_suffixes := .efi .fat .iso.raw
@@ -56,7 +56,8 @@ Build/%.iso.raw: Build/%.fat
# stripped from, the argument.
map_arm_to_uefi = $(subst arm,ARM,$(1))
map_aarch64_to_uefi = $(subst aarch64,AA64,$(call map_arm_to_uefi,$(1)))
-map_riscv64_to_uefi = $(subst riscv64,RISCV64,$(call map_aarch64_to_uefi,$(1)))
+map_loongarch64_to_uefi = $(subst loongarch64,LOONGARCH64,$(call map_aarch64_to_uefi,$(1)))
+map_riscv64_to_uefi = $(subst riscv64,RISCV64,$(call map_loongarch64_to_uefi,$(1)))
map_i386_to_uefi = $(subst i386,IA32,$(call map_riscv64_to_uefi,$(1)))
map_x86_64_to_uefi = $(subst x86_64,X64,$(call map_i386_to_uefi,$(1)))
map_to_uefi = $(subst .,,$(call map_x86_64_to_uefi,$(1)))
diff --git a/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc b/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc
index 0902fd3..facf8df 100644
--- a/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc
+++ b/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc
@@ -19,7 +19,7 @@
PLATFORM_VERSION = 0.1
PLATFORM_NAME = UefiTestTools
SKUID_IDENTIFIER = DEFAULT
- SUPPORTED_ARCHITECTURES = ARM|AARCH64|IA32|X64|RISCV64
+ SUPPORTED_ARCHITECTURES = ARM|AARCH64|IA32|X64|RISCV64|LOONGARCH64
BUILD_TARGETS = DEBUG
[BuildOptions.IA32]
@@ -65,6 +65,10 @@
[LibraryClasses.RISCV64]
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+[LibraryClasses.LOONGARCH64]
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ StackCheckLib|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
+
[PcdsFixedAtBuild]
gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8040004F
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F
diff --git a/tests/uefi-test-tools/uefi-test-build.config b/tests/uefi-test-tools/uefi-test-build.config
index a4c61fc..8bf4826 100644
--- a/tests/uefi-test-tools/uefi-test-build.config
+++ b/tests/uefi-test-tools/uefi-test-build.config
@@ -22,6 +22,16 @@ arch = AARCH64
cpy1 = AARCH64/BiosTablesTest.efi bios-tables-test.aarch64.efi
####################################################################################
+# loongarch64
+
+[build.loongarch64]
+conf = UefiTestToolsPkg/UefiTestToolsPkg.dsc
+plat = UefiTestTools
+dest = ./Build
+arch = LOONGARCH64
+cpy1 = LOONGARCH64/BiosTablesTest.efi bios-tables-test.loongarch64.efi
+
+####################################################################################
# riscv64
[build.riscv64]
diff --git a/tests/unit/check-block-qdict.c b/tests/unit/check-block-qdict.c
index 751c58e..0036d85 100644
--- a/tests/unit/check-block-qdict.c
+++ b/tests/unit/check-block-qdict.c
@@ -9,8 +9,8 @@
#include "qemu/osdep.h"
#include "block/qdict.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qnum.h"
+#include "qobject/qlist.h"
+#include "qobject/qnum.h"
#include "qapi/error.h"
static void qdict_defaults_test(void)
diff --git a/tests/unit/check-qdict.c b/tests/unit/check-qdict.c
index b5efa85..a1312be 100644
--- a/tests/unit/check-qdict.c
+++ b/tests/unit/check-qdict.c
@@ -11,9 +11,9 @@
*/
#include "qemu/osdep.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qnum.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qdict.h"
+#include "qobject/qnum.h"
+#include "qobject/qstring.h"
/*
* Public Interface test-cases
diff --git a/tests/unit/check-qjson.c b/tests/unit/check-qjson.c
index a89293c..780a365 100644
--- a/tests/unit/check-qjson.c
+++ b/tests/unit/check-qjson.c
@@ -14,12 +14,12 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qapi/qmp/qbool.h"
-#include "qapi/qmp/qjson.h"
-#include "qapi/qmp/qlit.h"
-#include "qapi/qmp/qnull.h"
-#include "qapi/qmp/qnum.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qbool.h"
+#include "qobject/qjson.h"
+#include "qobject/qlit.h"
+#include "qobject/qnull.h"
+#include "qobject/qnum.h"
+#include "qobject/qstring.h"
#include "qemu/unicode.h"
static QString *from_json_str(const char *jstr, bool single, Error **errp)
diff --git a/tests/unit/check-qlist.c b/tests/unit/check-qlist.c
index 3cd0ccb..1388aee 100644
--- a/tests/unit/check-qlist.c
+++ b/tests/unit/check-qlist.c
@@ -11,8 +11,8 @@
*/
#include "qemu/osdep.h"
-#include "qapi/qmp/qnum.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qnum.h"
+#include "qobject/qlist.h"
/*
* Public Interface test-cases
diff --git a/tests/unit/check-qlit.c b/tests/unit/check-qlit.c
index bd6798d..ea7a0d9 100644
--- a/tests/unit/check-qlit.c
+++ b/tests/unit/check-qlit.c
@@ -9,12 +9,12 @@
#include "qemu/osdep.h"
-#include "qapi/qmp/qbool.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qlit.h"
-#include "qapi/qmp/qnum.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qbool.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
+#include "qobject/qlit.h"
+#include "qobject/qnum.h"
+#include "qobject/qstring.h"
static QLitObject qlit = QLIT_QDICT(((QLitDictEntry[]) {
{ "foo", QLIT_QNUM(42) },
diff --git a/tests/unit/check-qnull.c b/tests/unit/check-qnull.c
index 5ceacc6..724a66d 100644
--- a/tests/unit/check-qnull.c
+++ b/tests/unit/check-qnull.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "qapi/qmp/qnull.h"
+#include "qobject/qnull.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qobject-output-visitor.h"
#include "qapi/error.h"
diff --git a/tests/unit/check-qnum.c b/tests/unit/check-qnum.c
index bf7fe45..a40120e 100644
--- a/tests/unit/check-qnum.c
+++ b/tests/unit/check-qnum.c
@@ -14,7 +14,7 @@
#include "qemu/osdep.h"
-#include "qapi/qmp/qnum.h"
+#include "qobject/qnum.h"
/*
* Public Interface test-cases
diff --git a/tests/unit/check-qobject.c b/tests/unit/check-qobject.c
index 022b7c7..ccb2566 100644
--- a/tests/unit/check-qobject.c
+++ b/tests/unit/check-qobject.c
@@ -9,12 +9,12 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qapi/qmp/qbool.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qnull.h"
-#include "qapi/qmp/qnum.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qbool.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
+#include "qobject/qnull.h"
+#include "qobject/qnum.h"
+#include "qobject/qstring.h"
#include <math.h>
diff --git a/tests/unit/check-qom-interface.c b/tests/unit/check-qom-interface.c
index c99be97..86ae5f6 100644
--- a/tests/unit/check-qom-interface.c
+++ b/tests/unit/check-qom-interface.c
@@ -38,7 +38,7 @@ static const TypeInfo test_if_info = {
#define PATTERN 0xFAFBFCFD
-static void test_class_init(ObjectClass *oc, void *data)
+static void test_class_init(ObjectClass *oc, const void *data)
{
TestIfClass *tc = TEST_IF_CLASS(oc);
@@ -52,7 +52,7 @@ static const TypeInfo direct_impl_info = {
.name = TYPE_DIRECT_IMPL,
.parent = TYPE_OBJECT,
.class_init = test_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_TEST_IF },
{ }
}
diff --git a/tests/unit/check-qom-proplist.c b/tests/unit/check-qom-proplist.c
index 79d4a8b..ee3c6fb 100644
--- a/tests/unit/check-qom-proplist.c
+++ b/tests/unit/check-qom-proplist.c
@@ -22,8 +22,8 @@
#include "qapi/error.h"
#include "qapi/qobject-input-visitor.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qobject.h"
+#include "qobject/qdict.h"
+#include "qobject/qobject.h"
#include "qom/object.h"
#include "qemu/module.h"
#include "qemu/option.h"
@@ -135,7 +135,7 @@ static void dummy_init(Object *obj)
}
-static void dummy_class_init(ObjectClass *cls, void *data)
+static void dummy_class_init(ObjectClass *cls, const void *data)
{
object_class_property_add_str(cls, "sv",
dummy_get_sv,
@@ -164,7 +164,7 @@ static const TypeInfo dummy_info = {
.instance_finalize = dummy_finalize,
.class_size = sizeof(DummyObjectClass),
.class_init = dummy_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_USER_CREATABLE },
{ }
}
@@ -264,7 +264,7 @@ static void dummy_dev_unparent(Object *obj)
object_unparent(OBJECT(dev->bus));
}
-static void dummy_dev_class_init(ObjectClass *klass, void *opaque)
+static void dummy_dev_class_init(ObjectClass *klass, const void *opaque)
{
klass->unparent = dummy_dev_unparent;
}
@@ -288,7 +288,7 @@ static void dummy_bus_unparent(Object *obj)
object_unparent(OBJECT(bus->backend));
}
-static void dummy_bus_class_init(ObjectClass *klass, void *opaque)
+static void dummy_bus_class_init(ObjectClass *klass, const void *opaque)
{
klass->unparent = dummy_bus_unparent;
}
@@ -610,7 +610,7 @@ static void test_dummy_delchild(void)
static void test_qom_partial_path(void)
{
Object *root = object_get_objects_root();
- Object *cont1 = container_get(root, "/cont1");
+ Object *cont1 = object_property_add_new_container(root, "cont1");
Object *obj1 = object_new(TYPE_DUMMY);
Object *obj2a = object_new(TYPE_DUMMY);
Object *obj2b = object_new(TYPE_DUMMY);
diff --git a/tests/unit/check-qstring.c b/tests/unit/check-qstring.c
index bd861f4..2e6a005 100644
--- a/tests/unit/check-qstring.c
+++ b/tests/unit/check-qstring.c
@@ -11,7 +11,7 @@
*/
#include "qemu/osdep.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qstring.h"
/*
* Public Interface test-cases
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index 972d792..d5248ae 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -47,6 +47,7 @@ tests = {
'test-logging': [],
'test-qapi-util': [],
'test-interval-tree': [],
+ 'test-fifo': [],
}
if have_system or have_tools
@@ -115,7 +116,7 @@ if have_block
if host_os != 'windows'
tests += {
'test-image-locking': [testblock],
- 'test-nested-aio-poll': [testblock],
+ 'test-nested-aio-poll': [],
}
endif
if config_host_data.get('CONFIG_REPLICATION')
diff --git a/tests/unit/socket-helpers.c b/tests/unit/socket-helpers.c
index f3439cc..37db24f 100644
--- a/tests/unit/socket-helpers.c
+++ b/tests/unit/socket-helpers.c
@@ -170,5 +170,4 @@ void socket_check_afunix_support(bool *has_afunix)
if (*has_afunix) {
close(fd);
}
- return;
}
diff --git a/tests/unit/test-aio-multithread.c b/tests/unit/test-aio-multithread.c
index 08d4570..0ead6bf 100644
--- a/tests/unit/test-aio-multithread.c
+++ b/tests/unit/test-aio-multithread.c
@@ -305,7 +305,9 @@ static void mcs_mutex_lock(void)
prev = qatomic_xchg(&mutex_head, id);
if (prev != -1) {
qatomic_set(&nodes[prev].next, id);
- qemu_futex_wait(&nodes[id].locked, 1);
+ while (qatomic_read(&nodes[id].locked) == 1) {
+ qemu_futex_wait(&nodes[id].locked, 1);
+ }
}
}
@@ -328,7 +330,7 @@ static void mcs_mutex_unlock(void)
/* Wake up the next in line. */
next = qatomic_read(&nodes[id].next);
nodes[next].locked = 0;
- qemu_futex_wake(&nodes[next].locked, 1);
+ qemu_futex_wake_single(&nodes[next].locked);
}
static void test_multi_fair_mutex_entry(void *opaque)
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
index 6668804..59c2793 100644
--- a/tests/unit/test-bdrv-drain.c
+++ b/tests/unit/test-bdrv-drain.c
@@ -25,7 +25,7 @@
#include "qemu/osdep.h"
#include "block/block_int.h"
#include "block/blockjob_int.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "qapi/error.h"
#include "qemu/main-loop.h"
#include "iothread.h"
@@ -632,6 +632,8 @@ typedef struct TestBlockJob {
BlockDriverState *bs;
int run_ret;
int prepare_ret;
+
+ /* Accessed with atomics */
bool running;
bool should_complete;
} TestBlockJob;
@@ -667,10 +669,10 @@ static int coroutine_fn test_job_run(Job *job, Error **errp)
/* We are running the actual job code past the pause point in
* job_co_entry(). */
- s->running = true;
+ qatomic_set(&s->running, true);
job_transition_to_ready(&s->common.job);
- while (!s->should_complete) {
+ while (!qatomic_read(&s->should_complete)) {
/* Avoid job_sleep_ns() because it marks the job as !busy. We want to
* emulate some actual activity (probably some I/O) here so that drain
* has to wait for this activity to stop. */
@@ -685,7 +687,7 @@ static int coroutine_fn test_job_run(Job *job, Error **errp)
static void test_job_complete(Job *job, Error **errp)
{
TestBlockJob *s = container_of(job, TestBlockJob, common.job);
- s->should_complete = true;
+ qatomic_set(&s->should_complete, true);
}
BlockJobDriver test_job_driver = {
@@ -722,7 +724,7 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
BlockJob *job;
TestBlockJob *tjob;
IOThread *iothread = NULL;
- int ret;
+ int ret = -1;
src = bdrv_new_open_driver(&bdrv_test, "source", BDRV_O_RDWR,
&error_abort);
@@ -770,9 +772,11 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
tjob->bs = src;
job = &tjob->common;
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort);
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
switch (result) {
case TEST_JOB_SUCCESS:
@@ -791,7 +795,7 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
/* job_co_entry() is run in the I/O thread, wait for the actual job
* code to start (we don't want to catch the job in the pause point in
* job_co_entry(). */
- while (!tjob->running) {
+ while (!qatomic_read(&tjob->running)) {
aio_poll(qemu_get_aio_context(), false);
}
}
@@ -799,7 +803,7 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
WITH_JOB_LOCK_GUARD() {
g_assert_cmpint(job->job.pause_count, ==, 0);
g_assert_false(job->job.paused);
- g_assert_true(tjob->running);
+ g_assert_true(qatomic_read(&tjob->running));
g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */
}
@@ -825,7 +829,7 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
*
* paused is reset in the I/O thread, wait for it
*/
- while (job->job.paused) {
+ while (job_is_paused(&job->job)) {
aio_poll(qemu_get_aio_context(), false);
}
}
@@ -858,7 +862,7 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
*
* paused is reset in the I/O thread, wait for it
*/
- while (job->job.paused) {
+ while (job_is_paused(&job->job)) {
aio_poll(qemu_get_aio_context(), false);
}
}
@@ -951,11 +955,13 @@ static void bdrv_test_top_close(BlockDriverState *bs)
{
BdrvChild *c, *next_c;
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) {
bdrv_unref_child(bs, c);
}
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
}
static int coroutine_fn GRAPH_RDLOCK
@@ -1012,7 +1018,9 @@ static void coroutine_fn test_co_delete_by_drain(void *opaque)
bdrv_graph_co_rdlock();
QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) {
bdrv_graph_co_rdunlock();
+ bdrv_drain_all_begin();
bdrv_co_unref_child(bs, c);
+ bdrv_drain_all_end();
bdrv_graph_co_rdlock();
}
bdrv_graph_co_rdunlock();
@@ -1045,10 +1053,12 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
&error_abort);
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds,
BDRV_CHILD_DATA, &error_abort);
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
/* This child will be the one to pass to requests through to, and
* it will stall until a drain occurs */
@@ -1056,21 +1066,25 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
&error_abort);
child_bs->total_sectors = 65536 >> BDRV_SECTOR_BITS;
/* Takes our reference to child_bs */
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child",
&child_of_bds,
BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
&error_abort);
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
/* This child is just there to be deleted
* (for detach_instead_of_delete == true) */
null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
&error_abort);
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds, BDRV_CHILD_DATA,
&error_abort);
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
blk_insert_bs(blk, bs, &error_abort);
@@ -1153,6 +1167,7 @@ static void no_coroutine_fn detach_indirect_bh(void *opaque)
bdrv_dec_in_flight(data->child_b->bs);
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_unref_child(data->parent_b, data->child_b);
@@ -1161,6 +1176,7 @@ static void no_coroutine_fn detach_indirect_bh(void *opaque)
&child_of_bds, BDRV_CHILD_DATA,
&error_abort);
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
}
static void coroutine_mixed_fn detach_by_parent_aio_cb(void *opaque, int ret)
@@ -1258,6 +1274,7 @@ static void TSA_NO_TSA test_detach_indirect(bool by_parent_cb)
/* Set child relationships */
bdrv_ref(b);
bdrv_ref(a);
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_of_bds,
BDRV_CHILD_DATA, &error_abort);
@@ -1269,6 +1286,7 @@ static void TSA_NO_TSA test_detach_indirect(bool by_parent_cb)
by_parent_cb ? &child_of_bds : &detach_by_driver_cb_class,
BDRV_CHILD_DATA, &error_abort);
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
g_assert_cmpint(parent_a->refcnt, ==, 1);
g_assert_cmpint(parent_b->refcnt, ==, 1);
@@ -1394,14 +1412,10 @@ static void test_set_aio_context(void)
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
&error_abort);
- bdrv_drained_begin(bs);
bdrv_try_change_aio_context(bs, ctx_a, NULL, &error_abort);
- bdrv_drained_end(bs);
- bdrv_drained_begin(bs);
bdrv_try_change_aio_context(bs, ctx_b, NULL, &error_abort);
bdrv_try_change_aio_context(bs, qemu_get_aio_context(), NULL, &error_abort);
- bdrv_drained_end(bs);
bdrv_unref(bs);
iothread_join(a);
@@ -1411,10 +1425,12 @@ static void test_set_aio_context(void)
typedef struct TestDropBackingBlockJob {
BlockJob common;
- bool should_complete;
bool *did_complete;
BlockDriverState *detach_also;
BlockDriverState *bs;
+
+ /* Accessed with atomics */
+ bool should_complete;
} TestDropBackingBlockJob;
static int coroutine_fn test_drop_backing_job_run(Job *job, Error **errp)
@@ -1422,7 +1438,7 @@ static int coroutine_fn test_drop_backing_job_run(Job *job, Error **errp)
TestDropBackingBlockJob *s =
container_of(job, TestDropBackingBlockJob, common.job);
- while (!s->should_complete) {
+ while (!qatomic_read(&s->should_complete)) {
job_sleep_ns(job, 0);
}
@@ -1541,7 +1557,7 @@ static void test_blockjob_commit_by_drained_end(void)
job_start(&job->common.job);
- job->should_complete = true;
+ qatomic_set(&job->should_complete, true);
bdrv_drained_begin(bs_child);
g_assert(!job_has_completed);
bdrv_drained_end(bs_child);
@@ -1557,15 +1573,17 @@ static void test_blockjob_commit_by_drained_end(void)
typedef struct TestSimpleBlockJob {
BlockJob common;
- bool should_complete;
bool *did_complete;
+
+ /* Accessed with atomics */
+ bool should_complete;
} TestSimpleBlockJob;
static int coroutine_fn test_simple_job_run(Job *job, Error **errp)
{
TestSimpleBlockJob *s = container_of(job, TestSimpleBlockJob, common.job);
- while (!s->should_complete) {
+ while (!qatomic_read(&s->should_complete)) {
job_sleep_ns(job, 0);
}
@@ -1681,6 +1699,7 @@ static void test_drop_intermediate_poll(void)
* Establish the chain last, so the chain links are the first
* elements in the BDS.parents lists
*/
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
for (i = 0; i < 3; i++) {
if (i) {
@@ -1690,6 +1709,7 @@ static void test_drop_intermediate_poll(void)
}
}
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
job = block_job_create("job", &test_simple_job_driver, NULL, job_node,
0, BLK_PERM_ALL, 0, 0, NULL, NULL, &error_abort);
@@ -1700,7 +1720,7 @@ static void test_drop_intermediate_poll(void)
job->did_complete = &job_has_completed;
job_start(&job->common.job);
- job->should_complete = true;
+ qatomic_set(&job->should_complete, true);
g_assert(!job_has_completed);
ret = bdrv_drop_intermediate(chain[1], chain[0], NULL, false);
@@ -1936,10 +1956,12 @@ static void do_test_replace_child_mid_drain(int old_drain_count,
new_child_bs->total_sectors = 1;
bdrv_ref(old_child_bs);
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_attach_child(parent_bs, old_child_bs, "child", &child_of_bds,
BDRV_CHILD_COW, &error_abort);
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
parent_s->setup_completed = true;
for (i = 0; i < old_drain_count; i++) {
diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
index cafc023..7b03ebe 100644
--- a/tests/unit/test-bdrv-graph-mod.c
+++ b/tests/unit/test-bdrv-graph-mod.c
@@ -22,7 +22,7 @@
#include "qapi/error.h"
#include "qemu/main-loop.h"
#include "block/block_int.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
static BlockDriver bdrv_pass_through = {
.format_name = "pass-through",
@@ -137,10 +137,12 @@ static void test_update_perm_tree(void)
blk_insert_bs(root, bs, &error_abort);
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_attach_child(filter, bs, "child", &child_of_bds,
BDRV_CHILD_DATA, &error_abort);
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
ret = bdrv_append(filter, bs, NULL);
g_assert_cmpint(ret, <, 0);
@@ -204,11 +206,13 @@ static void test_should_update_child(void)
bdrv_set_backing_hd(target, bs, &error_abort);
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
g_assert(target->backing->bs == bs);
bdrv_attach_child(filter, target, "target", &child_of_bds,
BDRV_CHILD_DATA, &error_abort);
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
bdrv_append(filter, bs, &error_abort);
bdrv_graph_rdlock_main_loop();
@@ -244,6 +248,7 @@ static void test_parallel_exclusive_write(void)
bdrv_ref(base);
bdrv_ref(fl1);
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_attach_child(top, fl1, "backing", &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
@@ -257,6 +262,7 @@ static void test_parallel_exclusive_write(void)
bdrv_replace_node(fl1, fl2, &error_abort);
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
bdrv_drained_end(fl2);
bdrv_drained_end(fl1);
@@ -363,6 +369,7 @@ static void test_parallel_perm_update(void)
*/
bdrv_ref(base);
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_attach_child(top, ws, "file", &child_of_bds, BDRV_CHILD_DATA,
&error_abort);
@@ -377,6 +384,7 @@ static void test_parallel_perm_update(void)
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
&error_abort);
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
/* Select fl1 as first child to be active */
s->selected = c_fl1;
@@ -430,11 +438,13 @@ static void test_append_greedy_filter(void)
BlockDriverState *base = no_perm_node("base");
BlockDriverState *fl = exclusive_writer_node("fl1");
+ bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_attach_child(top, base, "backing", &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
&error_abort);
bdrv_graph_wrunlock();
+ bdrv_drain_all_end();
bdrv_append(fl, base, &error_abort);
bdrv_unref(fl);
diff --git a/tests/unit/test-block-backend.c b/tests/unit/test-block-backend.c
index 2fb1a44..4257b3f 100644
--- a/tests/unit/test-block-backend.c
+++ b/tests/unit/test-block-backend.c
@@ -24,7 +24,7 @@
#include "qemu/osdep.h"
#include "block/block.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "qapi/error.h"
#include "qemu/main-loop.h"
diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
index 3766d5d..e26b3be 100644
--- a/tests/unit/test-block-iothread.c
+++ b/tests/unit/test-block-iothread.c
@@ -26,9 +26,9 @@
#include "block/block.h"
#include "block/block_int-global-state.h"
#include "block/blockjob_int.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qemu/main-loop.h"
#include "iothread.h"
@@ -63,7 +63,7 @@ bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
}
static int coroutine_fn bdrv_test_co_block_status(BlockDriverState *bs,
- bool want_zero,
+ unsigned int mode,
int64_t offset, int64_t count,
int64_t *pnum, int64_t *map,
BlockDriverState **file)
@@ -745,7 +745,7 @@ static void test_propagate_mirror(void)
AioContext *main_ctx = qemu_get_aio_context();
BlockDriverState *src, *target, *filter;
BlockBackend *blk;
- Job *job;
+ Job *job = NULL;
Error *local_err = NULL;
/* Create src and target*/
diff --git a/tests/unit/test-blockjob-txn.c b/tests/unit/test-blockjob-txn.c
index d3b0bb2..118503a 100644
--- a/tests/unit/test-blockjob-txn.c
+++ b/tests/unit/test-blockjob-txn.c
@@ -14,8 +14,8 @@
#include "qapi/error.h"
#include "qemu/main-loop.h"
#include "block/blockjob_int.h"
-#include "sysemu/block-backend.h"
-#include "qapi/qmp/qdict.h"
+#include "system/block-backend.h"
+#include "qobject/qdict.h"
typedef struct {
BlockJob common;
diff --git a/tests/unit/test-blockjob.c b/tests/unit/test-blockjob.c
index fe3e0d2..abdbe4b 100644
--- a/tests/unit/test-blockjob.c
+++ b/tests/unit/test-blockjob.c
@@ -14,8 +14,8 @@
#include "qapi/error.h"
#include "qemu/main-loop.h"
#include "block/blockjob_int.h"
-#include "sysemu/block-backend.h"
-#include "qapi/qmp/qdict.h"
+#include "system/block-backend.h"
+#include "qobject/qdict.h"
#include "iothread.h"
static const BlockJobDriver test_block_job_driver = {
diff --git a/tests/unit/test-char.c b/tests/unit/test-char.c
index f273ce5..f30a39f 100644
--- a/tests/unit/test-char.c
+++ b/tests/unit/test-char.c
@@ -1,15 +1,16 @@
#include "qemu/osdep.h"
#include <glib/gstdio.h>
+#include "qapi/error.h"
#include "qemu/config-file.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/sockets.h"
#include "chardev/char-fe.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-char.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qom/qom-qobject.h"
#include "io/channel-socket.h"
#include "qapi/qobject-input-visitor.h"
@@ -184,6 +185,21 @@ static void char_mux_test(void)
char *data;
FeHandler h1 = { 0, false, 0, false, }, h2 = { 0, false, 0, false, };
CharBackend chr_be1, chr_be2;
+ Error *error = NULL;
+
+ /* Create mux and chardev to be immediately removed */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
+ qemu_opt_set(opts, "size", "128", &error_abort);
+ qemu_opt_set(opts, "mux", "on", &error_abort);
+ chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
+ g_assert_nonnull(chr);
+ qemu_opts_del(opts);
+
+ /* Remove just created mux and chardev */
+ qmp_chardev_remove("mux-label", &error_abort);
+ qmp_chardev_remove("mux-label-base", &error_abort);
opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
1, &error_abort);
@@ -334,9 +350,412 @@ static void char_mux_test(void)
g_free(data);
qemu_chr_fe_deinit(&chr_be1, false);
- qemu_chr_fe_deinit(&chr_be2, true);
+
+ qmp_chardev_remove("mux-label", &error);
+ g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'mux-label' is busy");
+ error_free(error);
+
+ qemu_chr_fe_deinit(&chr_be2, false);
+ qmp_chardev_remove("mux-label", &error_abort);
}
+static void char_hub_test(void)
+{
+ QemuOpts *opts;
+ Chardev *hub, *chr1, *chr2, *base;
+ char *data;
+ FeHandler h = { 0, false, 0, false, };
+ Error *error = NULL;
+ CharBackend chr_be;
+ int ret, i;
+
+#define RB_SIZE 128
+
+ /*
+ * Create invalid hub
+ * 1. Create hub without a 'chardevs.N' defined (expect error)
+ */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "hub", &error_abort);
+ hub = qemu_chr_new_from_opts(opts, NULL, &error);
+ g_assert_cmpstr(error_get_pretty(error), ==,
+ "hub: 'chardevs' list is not defined");
+ error_free(error);
+ error = NULL;
+ qemu_opts_del(opts);
+
+ /*
+ * Create invalid hub
+ * 1. Create chardev with embedded mux: 'mux=on'
+ * 2. Create hub which refers mux
+ * 3. Create hub which refers chardev already attached
+ * to the mux (already in use, expect error)
+ */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "chr0",
+ 1, &error_abort);
+ qemu_opt_set(opts, "mux", "on", &error_abort);
+ qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
+ qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort);
+ base = qemu_chr_new_from_opts(opts, NULL, &error_abort);
+ g_assert_nonnull(base);
+ qemu_opts_del(opts);
+
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "hub", &error_abort);
+ qemu_opt_set(opts, "chardevs.0", "chr0", &error_abort);
+ hub = qemu_chr_new_from_opts(opts, NULL, &error);
+ g_assert_cmpstr(error_get_pretty(error), ==,
+ "hub: multiplexers and hub devices can't be "
+ "stacked, check chardev 'chr0', chardev should "
+ "not be a hub device or have 'mux=on' enabled");
+ error_free(error);
+ error = NULL;
+ qemu_opts_del(opts);
+
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "hub", &error_abort);
+ qemu_opt_set(opts, "chardevs.0", "chr0-base", &error_abort);
+ hub = qemu_chr_new_from_opts(opts, NULL, &error);
+ g_assert_cmpstr(error_get_pretty(error), ==,
+ "chardev 'chr0-base' is already in use");
+ error_free(error);
+ error = NULL;
+ qemu_opts_del(opts);
+
+ /* Finalize chr0 */
+ qmp_chardev_remove("chr0", &error_abort);
+
+ /*
+ * Create invalid hub with more than maximum allowed backends
+ * 1. Create more than maximum allowed 'chardevs.%d' options for
+ * hub (expect error)
+ */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0",
+ 1, &error_abort);
+ for (i = 0; i < 10; i++) {
+ char key[32], val[32];
+
+ snprintf(key, sizeof(key), "chardevs.%d", i);
+ snprintf(val, sizeof(val), "chr%d", i);
+ qemu_opt_set(opts, key, val, &error);
+ if (error) {
+ char buf[64];
+
+ snprintf(buf, sizeof(buf), "Invalid parameter 'chardevs.%d'", i);
+ g_assert_cmpstr(error_get_pretty(error), ==, buf);
+ error_free(error);
+ break;
+ }
+ }
+ g_assert_nonnull(error);
+ error = NULL;
+ qemu_opts_del(opts);
+
+ /*
+ * Create hub with 2 backend chardevs and 1 frontend and perform
+ * data aggregation
+ * 1. Create 2 ringbuf backend chardevs
+ * 2. Create 1 frontend
+ * 3. Create hub which refers 2 backend chardevs
+ * 4. Attach hub to a frontend
+ * 5. Attach hub to a frontend second time (expect error)
+ * 6. Perform data aggregation
+ * 7. Remove chr1 ("chr1 is busy", expect error)
+ * 8. Remove hub0 ("hub0 is busy", expect error);
+ * 9. Finilize frontend, hub and backend chardevs in correct order
+ */
+
+ /* Create first chardev */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "chr1",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
+ qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort);
+ chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort);
+ g_assert_nonnull(chr1);
+ qemu_opts_del(opts);
+
+ /* Create second chardev */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "chr2",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
+ qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort);
+ chr2 = qemu_chr_new_from_opts(opts, NULL, &error_abort);
+ g_assert_nonnull(chr2);
+ qemu_opts_del(opts);
+
+ /* Create hub0 and refer 2 backend chardevs */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "hub", &error_abort);
+ qemu_opt_set(opts, "chardevs.0", "chr1", &error_abort);
+ qemu_opt_set(opts, "chardevs.1", "chr2", &error_abort);
+ hub = qemu_chr_new_from_opts(opts, NULL, &error_abort);
+ g_assert_nonnull(hub);
+ qemu_opts_del(opts);
+
+ /* Attach hub to a frontend */
+ qemu_chr_fe_init(&chr_be, hub, &error_abort);
+ qemu_chr_fe_set_handlers(&chr_be,
+ fe_can_read,
+ fe_read,
+ fe_event,
+ NULL,
+ &h,
+ NULL, true);
+
+ /* Fails second time */
+ qemu_chr_fe_init(&chr_be, hub, &error);
+ g_assert_cmpstr(error_get_pretty(error), ==, "chardev 'hub0' is already in use");
+ error_free(error);
+ error = NULL;
+
+ /* Write to backend, chr1 */
+ base = qemu_chr_find("chr1");
+ g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
+
+ qemu_chr_be_write(base, (void *)"hello", 6);
+ g_assert_cmpint(h.read_count, ==, 6);
+ g_assert_cmpstr(h.read_buf, ==, "hello");
+ h.read_count = 0;
+
+ /* Write to backend, chr2 */
+ base = qemu_chr_find("chr2");
+ g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
+
+ qemu_chr_be_write(base, (void *)"olleh", 6);
+ g_assert_cmpint(h.read_count, ==, 6);
+ g_assert_cmpstr(h.read_buf, ==, "olleh");
+ h.read_count = 0;
+
+ /* Write to frontend, chr_be */
+ ret = qemu_chr_fe_write(&chr_be, (void *)"heyhey", 6);
+ g_assert_cmpint(ret, ==, 6);
+
+ data = qmp_ringbuf_read("chr1", RB_SIZE, false, 0, &error_abort);
+ g_assert_cmpint(strlen(data), ==, 6);
+ g_assert_cmpstr(data, ==, "heyhey");
+ g_free(data);
+
+ data = qmp_ringbuf_read("chr2", RB_SIZE, false, 0, &error_abort);
+ g_assert_cmpint(strlen(data), ==, 6);
+ g_assert_cmpstr(data, ==, "heyhey");
+ g_free(data);
+
+ /* Can't be removed, depends on hub0 */
+ qmp_chardev_remove("chr1", &error);
+ g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'chr1' is busy");
+ error_free(error);
+ error = NULL;
+
+ /* Can't be removed, depends on frontend chr_be */
+ qmp_chardev_remove("hub0", &error);
+ g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'hub0' is busy");
+ error_free(error);
+ error = NULL;
+
+ /* Finalize frontend */
+ qemu_chr_fe_deinit(&chr_be, false);
+
+ /* Finalize hub0 */
+ qmp_chardev_remove("hub0", &error_abort);
+
+ /* Finalize backend chardevs */
+ qmp_chardev_remove("chr1", &error_abort);
+ qmp_chardev_remove("chr2", &error_abort);
+
+#ifndef _WIN32
+ /*
+ * Create 3 backend chardevs to simulate EAGAIN and watcher.
+ * Mainly copied from char_pipe_test().
+ * 1. Create 2 ringbuf backend chardevs
+ * 2. Create 1 pipe backend chardev
+ * 3. Create 1 frontend
+ * 4. Create hub which refers 2 backend chardevs
+ * 5. Attach hub to a frontend
+ * 6. Perform data aggregation and check watcher
+ * 7. Finilize frontend, hub and backend chardevs in correct order
+ */
+ {
+ gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
+ gchar *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL);
+ Chardev *chr3;
+ int fd, len;
+ char buf[128];
+
+ in = g_strdup_printf("%s.in", pipe);
+ if (mkfifo(in, 0600) < 0) {
+ abort();
+ }
+ out = g_strdup_printf("%s.out", pipe);
+ if (mkfifo(out, 0600) < 0) {
+ abort();
+ }
+
+ /* Create first chardev */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "chr1",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
+ qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort);
+ chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort);
+ g_assert_nonnull(chr1);
+ qemu_opts_del(opts);
+
+ /* Create second chardev */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "chr2",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
+ qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort);
+ chr2 = qemu_chr_new_from_opts(opts, NULL, &error_abort);
+ g_assert_nonnull(chr2);
+ qemu_opts_del(opts);
+
+ /* Create third chardev */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "chr3",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "pipe", &error_abort);
+ qemu_opt_set(opts, "path", pipe, &error_abort);
+ chr3 = qemu_chr_new_from_opts(opts, NULL, &error_abort);
+ g_assert_nonnull(chr3);
+
+ /* Create hub0 and refer 3 backend chardevs */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "hub", &error_abort);
+ qemu_opt_set(opts, "chardevs.0", "chr1", &error_abort);
+ qemu_opt_set(opts, "chardevs.1", "chr2", &error_abort);
+ qemu_opt_set(opts, "chardevs.2", "chr3", &error_abort);
+ hub = qemu_chr_new_from_opts(opts, NULL, &error_abort);
+ g_assert_nonnull(hub);
+ qemu_opts_del(opts);
+
+ /* Attach hub to a frontend */
+ qemu_chr_fe_init(&chr_be, hub, &error_abort);
+ qemu_chr_fe_set_handlers(&chr_be,
+ fe_can_read,
+ fe_read,
+ fe_event,
+ NULL,
+ &h,
+ NULL, true);
+
+ /* Write to frontend, chr_be */
+ ret = qemu_chr_fe_write(&chr_be, (void *)"thisis", 6);
+ g_assert_cmpint(ret, ==, 6);
+
+ data = qmp_ringbuf_read("chr1", RB_SIZE, false, 0, &error_abort);
+ g_assert_cmpint(strlen(data), ==, 6);
+ g_assert_cmpstr(data, ==, "thisis");
+ g_free(data);
+
+ data = qmp_ringbuf_read("chr2", RB_SIZE, false, 0, &error_abort);
+ g_assert_cmpint(strlen(data), ==, 6);
+ g_assert_cmpstr(data, ==, "thisis");
+ g_free(data);
+
+ fd = open(out, O_RDWR);
+ ret = read(fd, buf, sizeof(buf));
+ g_assert_cmpint(ret, ==, 6);
+ buf[ret] = 0;
+ g_assert_cmpstr(buf, ==, "thisis");
+ close(fd);
+
+ /* Add watch. 0 indicates no watches if nothing to wait for */
+ ret = qemu_chr_fe_add_watch(&chr_be, G_IO_OUT | G_IO_HUP,
+ NULL, NULL);
+ g_assert_cmpint(ret, ==, 0);
+
+ /*
+ * Write to frontend, chr_be, until EAGAIN. Make sure length is
+ * power of two to fit nicely the whole pipe buffer.
+ */
+ len = 0;
+ while ((ret = qemu_chr_fe_write(&chr_be, (void *)"thisisit", 8))
+ != -1) {
+ len += ret;
+ }
+ g_assert_cmpint(errno, ==, EAGAIN);
+
+ /* Further all writes should cause EAGAIN */
+ ret = qemu_chr_fe_write(&chr_be, (void *)"b", 1);
+ g_assert_cmpint(ret, ==, -1);
+ g_assert_cmpint(errno, ==, EAGAIN);
+
+ /*
+ * Add watch. Non 0 indicates we have a blocked chardev, which
+ * can wakes us up when write is possible.
+ */
+ ret = qemu_chr_fe_add_watch(&chr_be, G_IO_OUT | G_IO_HUP,
+ NULL, NULL);
+ g_assert_cmpint(ret, !=, 0);
+ g_source_remove(ret);
+
+ /* Drain pipe and ring buffers */
+ fd = open(out, O_RDWR);
+ while ((ret = read(fd, buf, MIN(sizeof(buf), len))) != -1 && len > 0) {
+ len -= ret;
+ }
+ close(fd);
+
+ data = qmp_ringbuf_read("chr1", RB_SIZE, false, 0, &error_abort);
+ g_assert_cmpint(strlen(data), ==, 128);
+ g_free(data);
+
+ data = qmp_ringbuf_read("chr2", RB_SIZE, false, 0, &error_abort);
+ g_assert_cmpint(strlen(data), ==, 128);
+ g_free(data);
+
+ /*
+ * Now we are good to go, first repeat "lost" sequence, which
+ * was already consumed and drained by the ring buffers, but
+ * pipe have not recieved that yet.
+ */
+ ret = qemu_chr_fe_write(&chr_be, (void *)"thisisit", 8);
+ g_assert_cmpint(ret, ==, 8);
+
+ ret = qemu_chr_fe_write(&chr_be, (void *)"streamisrestored", 16);
+ g_assert_cmpint(ret, ==, 16);
+
+ data = qmp_ringbuf_read("chr1", RB_SIZE, false, 0, &error_abort);
+ g_assert_cmpint(strlen(data), ==, 16);
+ /* Only last 16 bytes, see big comment above */
+ g_assert_cmpstr(data, ==, "streamisrestored");
+ g_free(data);
+
+ data = qmp_ringbuf_read("chr2", RB_SIZE, false, 0, &error_abort);
+ g_assert_cmpint(strlen(data), ==, 16);
+ /* Only last 16 bytes, see big comment above */
+ g_assert_cmpstr(data, ==, "streamisrestored");
+ g_free(data);
+
+ fd = open(out, O_RDWR);
+ ret = read(fd, buf, sizeof(buf));
+ g_assert_cmpint(ret, ==, 24);
+ buf[ret] = 0;
+ /* Both 8 and 16 bytes */
+ g_assert_cmpstr(buf, ==, "thisisitstreamisrestored");
+ close(fd);
+
+ g_free(in);
+ g_free(out);
+ g_free(tmp_path);
+ g_free(pipe);
+
+ /* Finalize frontend */
+ qemu_chr_fe_deinit(&chr_be, false);
+
+ /* Finalize hub0 */
+ qmp_chardev_remove("hub0", &error_abort);
+
+ /* Finalize backend chardevs */
+ qmp_chardev_remove("chr1", &error_abort);
+ qmp_chardev_remove("chr2", &error_abort);
+ qmp_chardev_remove("chr3", &error_abort);
+ }
+#endif
+}
static void websock_server_read(void *opaque, const uint8_t *buf, int size)
{
@@ -574,7 +993,7 @@ static void char_udp_test_internal(Chardev *reuse_chr, int sock)
struct sockaddr_in other;
SocketIdleData d = { 0, };
Chardev *chr;
- CharBackend *be;
+ CharBackend stack_be, *be = &stack_be;
socklen_t alen = sizeof(other);
int ret;
char buf[10];
@@ -590,7 +1009,6 @@ static void char_udp_test_internal(Chardev *reuse_chr, int sock)
chr = qemu_chr_new("client", tmp, NULL);
g_assert_nonnull(chr);
- be = g_alloca(sizeof(CharBackend));
qemu_chr_fe_init(be, chr, &error_abort);
}
@@ -1485,6 +1903,7 @@ int main(int argc, char **argv)
g_test_add_func("/char/invalid", char_invalid_test);
g_test_add_func("/char/ringbuf", char_ringbuf_test);
g_test_add_func("/char/mux", char_mux_test);
+ g_test_add_func("/char/hub", char_hub_test);
#ifdef _WIN32
g_test_add_func("/char/console/subprocess", char_console_test_subprocess);
g_test_add_func("/char/console", char_console_test);
@@ -1523,18 +1942,18 @@ int main(int argc, char **argv)
static CharSocketClientTestConfig client2 ## name = \
{ addr, NULL, true, false, char_socket_event }; \
static CharSocketClientTestConfig client3 ## name = \
- { addr, ",reconnect=1", false, false, char_socket_event }; \
+ { addr, ",reconnect-ms=1000", false, false, char_socket_event }; \
static CharSocketClientTestConfig client4 ## name = \
- { addr, ",reconnect=1", true, false, char_socket_event }; \
+ { addr, ",reconnect-ms=1000", true, false, char_socket_event }; \
static CharSocketClientTestConfig client5 ## name = \
{ addr, NULL, false, true, char_socket_event }; \
static CharSocketClientTestConfig client6 ## name = \
{ addr, NULL, true, true, char_socket_event }; \
static CharSocketClientTestConfig client7 ## name = \
- { addr, ",reconnect=1", true, false, \
+ { addr, ",reconnect-ms=1000", true, false, \
char_socket_event_with_error }; \
static CharSocketClientTestConfig client8 ## name = \
- { addr, ",reconnect=1", false, false, char_socket_event }; \
+ { addr, ",reconnect-ms=1000", false, false, char_socket_event };\
g_test_add_data_func("/char/socket/client/mainloop/" # name, \
&client1 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/wait-conn/" # name, \
diff --git a/tests/unit/test-crypto-afsplit.c b/tests/unit/test-crypto-afsplit.c
index 00a7c18..45e9046 100644
--- a/tests/unit/test-crypto-afsplit.c
+++ b/tests/unit/test-crypto-afsplit.c
@@ -26,7 +26,7 @@
typedef struct QCryptoAFSplitTestData QCryptoAFSplitTestData;
struct QCryptoAFSplitTestData {
const char *path;
- QCryptoHashAlgorithm hash;
+ QCryptoHashAlgo hash;
uint32_t stripes;
size_t blocklen;
const uint8_t *key;
@@ -36,7 +36,7 @@ struct QCryptoAFSplitTestData {
static QCryptoAFSplitTestData test_data[] = {
{
.path = "/crypto/afsplit/sha256/5",
- .hash = QCRYPTO_HASH_ALG_SHA256,
+ .hash = QCRYPTO_HASH_ALGO_SHA256,
.stripes = 5,
.blocklen = 32,
.key = (const uint8_t *)
@@ -68,7 +68,7 @@ static QCryptoAFSplitTestData test_data[] = {
},
{
.path = "/crypto/afsplit/sha256/5000",
- .hash = QCRYPTO_HASH_ALG_SHA256,
+ .hash = QCRYPTO_HASH_ALGO_SHA256,
.stripes = 5000,
.blocklen = 16,
.key = (const uint8_t *)
@@ -77,7 +77,7 @@ static QCryptoAFSplitTestData test_data[] = {
},
{
.path = "/crypto/afsplit/sha1/1000",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.stripes = 1000,
.blocklen = 32,
.key = (const uint8_t *)
@@ -88,7 +88,7 @@ static QCryptoAFSplitTestData test_data[] = {
},
{
.path = "/crypto/afsplit/sha256/big",
- .hash = QCRYPTO_HASH_ALG_SHA256,
+ .hash = QCRYPTO_HASH_ALGO_SHA256,
.stripes = 1000,
.blocklen = 64,
.key = (const uint8_t *)
diff --git a/tests/unit/test-crypto-akcipher.c b/tests/unit/test-crypto-akcipher.c
index 4f1f421..53c2211 100644
--- a/tests/unit/test-crypto-akcipher.c
+++ b/tests/unit/test-crypto-akcipher.c
@@ -692,7 +692,7 @@ struct QCryptoAkCipherTestData {
static QCryptoRSAKeyTestData rsakey_test_data[] = {
{
.path = "/crypto/akcipher/rsakey-1024-public",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = rsa1024_public_key,
.keylen = sizeof(rsa1024_public_key),
.is_valid_key = true,
@@ -700,7 +700,7 @@ static QCryptoRSAKeyTestData rsakey_test_data[] = {
},
{
.path = "/crypto/akcipher/rsakey-1024-private",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
.key = rsa1024_private_key,
.keylen = sizeof(rsa1024_private_key),
.is_valid_key = true,
@@ -708,7 +708,7 @@ static QCryptoRSAKeyTestData rsakey_test_data[] = {
},
{
.path = "/crypto/akcipher/rsakey-2048-public",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = rsa2048_public_key,
.keylen = sizeof(rsa2048_public_key),
.is_valid_key = true,
@@ -716,7 +716,7 @@ static QCryptoRSAKeyTestData rsakey_test_data[] = {
},
{
.path = "/crypto/akcipher/rsakey-2048-private",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
.key = rsa2048_private_key,
.keylen = sizeof(rsa2048_private_key),
.is_valid_key = true,
@@ -724,56 +724,56 @@ static QCryptoRSAKeyTestData rsakey_test_data[] = {
},
{
.path = "/crypto/akcipher/rsakey-public-lack-elem",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = rsa_public_key_lack_element,
.keylen = sizeof(rsa_public_key_lack_element),
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-private-lack-elem",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
.key = rsa_private_key_lack_element,
.keylen = sizeof(rsa_private_key_lack_element),
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-public-empty-elem",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = rsa_public_key_empty_element,
.keylen = sizeof(rsa_public_key_empty_element),
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-private-empty-elem",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
.key = rsa_private_key_empty_element,
.keylen = sizeof(rsa_private_key_empty_element),
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-public-empty-key",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = NULL,
.keylen = 0,
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-private-empty-key",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
.key = NULL,
.keylen = 0,
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-public-invalid-length-val",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = rsa_public_key_invalid_length_val,
.keylen = sizeof(rsa_public_key_invalid_length_val),
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-public-extra-elem",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = rsa_public_key_extra_elem,
.keylen = sizeof(rsa_public_key_extra_elem),
.is_valid_key = false,
@@ -785,9 +785,9 @@ static QCryptoAkCipherTestData akcipher_test_data[] = {
{
.path = "/crypto/akcipher/rsa1024-raw",
.opt = {
- .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .alg = QCRYPTO_AK_CIPHER_ALGO_RSA,
.u.rsa = {
- .padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW,
+ .padding_alg = QCRYPTO_RSA_PADDING_ALGO_RAW,
},
},
.pub_key = rsa1024_public_key,
@@ -805,10 +805,10 @@ static QCryptoAkCipherTestData akcipher_test_data[] = {
{
.path = "/crypto/akcipher/rsa1024-pkcs1",
.opt = {
- .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .alg = QCRYPTO_AK_CIPHER_ALGO_RSA,
.u.rsa = {
- .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1,
- .hash_alg = QCRYPTO_HASH_ALG_SHA1,
+ .padding_alg = QCRYPTO_RSA_PADDING_ALGO_PKCS1,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA1,
},
},
.pub_key = rsa1024_public_key,
@@ -830,9 +830,9 @@ static QCryptoAkCipherTestData akcipher_test_data[] = {
{
.path = "/crypto/akcipher/rsa2048-raw",
.opt = {
- .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .alg = QCRYPTO_AK_CIPHER_ALGO_RSA,
.u.rsa = {
- .padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW,
+ .padding_alg = QCRYPTO_RSA_PADDING_ALGO_RAW,
},
},
.pub_key = rsa2048_public_key,
@@ -850,10 +850,10 @@ static QCryptoAkCipherTestData akcipher_test_data[] = {
{
.path = "/crypto/akcipher/rsa2048-pkcs1",
.opt = {
- .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .alg = QCRYPTO_AK_CIPHER_ALGO_RSA,
.u.rsa = {
- .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1,
- .hash_alg = QCRYPTO_HASH_ALG_SHA1,
+ .padding_alg = QCRYPTO_RSA_PADDING_ALGO_PKCS1,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA1,
},
},
.pub_key = rsa2048_public_key,
@@ -885,12 +885,12 @@ static void test_akcipher(const void *opaque)
return;
}
pub_key = qcrypto_akcipher_new(&data->opt,
- QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
data->pub_key, data->pub_key_len,
&error_abort);
g_assert(pub_key != NULL);
priv_key = qcrypto_akcipher_new(&data->opt,
- QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
data->priv_key, data->priv_key_len,
&error_abort);
g_assert(priv_key != NULL);
@@ -944,10 +944,10 @@ static void test_rsakey(const void *opaque)
{
const QCryptoRSAKeyTestData *data = (const QCryptoRSAKeyTestData *)opaque;
QCryptoAkCipherOptions opt = {
- .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .alg = QCRYPTO_AK_CIPHER_ALGO_RSA,
.u.rsa = {
- .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1,
- .hash_alg = QCRYPTO_HASH_ALG_SHA1,
+ .padding_alg = QCRYPTO_RSA_PADDING_ALGO_PKCS1,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA1,
}
};
g_autoptr(QCryptoAkCipher) key = qcrypto_akcipher_new(
diff --git a/tests/unit/test-crypto-block.c b/tests/unit/test-crypto-block.c
index 42cfab6..3ac7f17 100644
--- a/tests/unit/test-crypto-block.c
+++ b/tests/unit/test-crypto-block.c
@@ -39,14 +39,14 @@
#endif
static QCryptoBlockCreateOptions qcow_create_opts = {
- .format = Q_CRYPTO_BLOCK_FORMAT_QCOW,
+ .format = QCRYPTO_BLOCK_FORMAT_QCOW,
.u.qcow = {
.key_secret = (char *)"sec0",
},
};
static QCryptoBlockOpenOptions qcow_open_opts = {
- .format = Q_CRYPTO_BLOCK_FORMAT_QCOW,
+ .format = QCRYPTO_BLOCK_FORMAT_QCOW,
.u.qcow = {
.key_secret = (char *)"sec0",
},
@@ -55,7 +55,7 @@ static QCryptoBlockOpenOptions qcow_open_opts = {
#ifdef TEST_LUKS
static QCryptoBlockOpenOptions luks_open_opts = {
- .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ .format = QCRYPTO_BLOCK_FORMAT_LUKS,
.u.luks = {
.key_secret = (char *)"sec0",
},
@@ -64,7 +64,7 @@ static QCryptoBlockOpenOptions luks_open_opts = {
/* Creation with all default values */
static QCryptoBlockCreateOptions luks_create_opts_default = {
- .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ .format = QCRYPTO_BLOCK_FORMAT_LUKS,
.u.luks = {
.key_secret = (char *)"sec0",
},
@@ -73,33 +73,33 @@ static QCryptoBlockCreateOptions luks_create_opts_default = {
/* ...and with explicit values */
static QCryptoBlockCreateOptions luks_create_opts_aes256_cbc_plain64 = {
- .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ .format = QCRYPTO_BLOCK_FORMAT_LUKS,
.u.luks = {
.key_secret = (char *)"sec0",
.has_cipher_alg = true,
- .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .cipher_alg = QCRYPTO_CIPHER_ALGO_AES_256,
.has_cipher_mode = true,
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
.has_ivgen_alg = true,
- .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivgen_alg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
},
};
static QCryptoBlockCreateOptions luks_create_opts_aes256_cbc_essiv = {
- .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ .format = QCRYPTO_BLOCK_FORMAT_LUKS,
.u.luks = {
.key_secret = (char *)"sec0",
.has_cipher_alg = true,
- .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .cipher_alg = QCRYPTO_CIPHER_ALGO_AES_256,
.has_cipher_mode = true,
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
.has_ivgen_alg = true,
- .ivgen_alg = QCRYPTO_IVGEN_ALG_ESSIV,
+ .ivgen_alg = QCRYPTO_IV_GEN_ALGO_ESSIV,
.has_ivgen_hash_alg = true,
- .ivgen_hash_alg = QCRYPTO_HASH_ALG_SHA256,
+ .ivgen_hash_alg = QCRYPTO_HASH_ALGO_SHA256,
.has_hash_alg = true,
- .hash_alg = QCRYPTO_HASH_ALG_SHA1,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA1,
},
};
#endif /* TEST_LUKS */
@@ -112,12 +112,12 @@ static struct QCryptoBlockTestData {
bool expect_header;
- QCryptoCipherAlgorithm cipher_alg;
+ QCryptoCipherAlgo cipher_alg;
QCryptoCipherMode cipher_mode;
- QCryptoHashAlgorithm hash_alg;
+ QCryptoHashAlgo hash_alg;
- QCryptoIVGenAlgorithm ivgen_alg;
- QCryptoHashAlgorithm ivgen_hash;
+ QCryptoIVGenAlgo ivgen_alg;
+ QCryptoHashAlgo ivgen_hash;
bool slow;
} test_data[] = {
@@ -128,10 +128,10 @@ static struct QCryptoBlockTestData {
.expect_header = false,
- .cipher_alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .cipher_alg = QCRYPTO_CIPHER_ALGO_AES_128,
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
- .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivgen_alg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
},
#ifdef TEST_LUKS
{
@@ -141,11 +141,11 @@ static struct QCryptoBlockTestData {
.expect_header = true,
- .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .cipher_alg = QCRYPTO_CIPHER_ALGO_AES_256,
.cipher_mode = QCRYPTO_CIPHER_MODE_XTS,
- .hash_alg = QCRYPTO_HASH_ALG_SHA256,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA256,
- .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivgen_alg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
.slow = true,
},
@@ -156,11 +156,11 @@ static struct QCryptoBlockTestData {
.expect_header = true,
- .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .cipher_alg = QCRYPTO_CIPHER_ALGO_AES_256,
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
- .hash_alg = QCRYPTO_HASH_ALG_SHA256,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA256,
- .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivgen_alg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
.slow = true,
},
@@ -171,12 +171,12 @@ static struct QCryptoBlockTestData {
.expect_header = true,
- .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .cipher_alg = QCRYPTO_CIPHER_ALGO_AES_256,
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
- .hash_alg = QCRYPTO_HASH_ALG_SHA1,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA1,
- .ivgen_alg = QCRYPTO_IVGEN_ALG_ESSIV,
- .ivgen_hash = QCRYPTO_HASH_ALG_SHA256,
+ .ivgen_alg = QCRYPTO_IV_GEN_ALGO_ESSIV,
+ .ivgen_hash = QCRYPTO_HASH_ALGO_SHA256,
.slow = true,
},
@@ -572,8 +572,15 @@ int main(int argc, char **argv)
g_assert(qcrypto_init(NULL) == 0);
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
- if (test_data[i].open_opts->format == Q_CRYPTO_BLOCK_FORMAT_LUKS &&
+ if (test_data[i].open_opts->format == QCRYPTO_BLOCK_FORMAT_LUKS &&
!qcrypto_hash_supports(test_data[i].hash_alg)) {
+ g_printerr("# skip unsupported %s\n",
+ QCryptoHashAlgo_str(test_data[i].hash_alg));
+ continue;
+ }
+ if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALGO_AES_128,
+ QCRYPTO_CIPHER_MODE_CBC)) {
+ g_printerr("# skip unsupported aes-128:cbc\n");
continue;
}
if (!test_data[i].slow ||
diff --git a/tests/unit/test-crypto-cipher.c b/tests/unit/test-crypto-cipher.c
index f5152e5..1331d55 100644
--- a/tests/unit/test-crypto-cipher.c
+++ b/tests/unit/test-crypto-cipher.c
@@ -27,7 +27,7 @@
typedef struct QCryptoCipherTestData QCryptoCipherTestData;
struct QCryptoCipherTestData {
const char *path;
- QCryptoCipherAlgorithm alg;
+ QCryptoCipherAlgo alg;
QCryptoCipherMode mode;
const char *key;
const char *plaintext;
@@ -43,7 +43,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.1.1 ECB-AES128.Encrypt */
.path = "/crypto/cipher/aes-ecb-128",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "2b7e151628aed2a6abf7158809cf4f3c",
.plaintext =
@@ -60,7 +60,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.1.3 ECB-AES192.Encrypt */
.path = "/crypto/cipher/aes-ecb-192",
- .alg = QCRYPTO_CIPHER_ALG_AES_192,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_192,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
.plaintext =
@@ -77,7 +77,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.1.5 ECB-AES256.Encrypt */
.path = "/crypto/cipher/aes-ecb-256",
- .alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_256,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key =
"603deb1015ca71be2b73aef0857d7781"
@@ -96,7 +96,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.2.1 CBC-AES128.Encrypt */
.path = "/crypto/cipher/aes-cbc-128",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key = "2b7e151628aed2a6abf7158809cf4f3c",
.iv = "000102030405060708090a0b0c0d0e0f",
@@ -114,7 +114,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.2.3 CBC-AES128.Encrypt */
.path = "/crypto/cipher/aes-cbc-192",
- .alg = QCRYPTO_CIPHER_ALG_AES_192,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_192,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
.iv = "000102030405060708090a0b0c0d0e0f",
@@ -132,7 +132,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.2.5 CBC-AES128.Encrypt */
.path = "/crypto/cipher/aes-cbc-256",
- .alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_256,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key =
"603deb1015ca71be2b73aef0857d7781"
@@ -156,7 +156,7 @@ static QCryptoCipherTestData test_data[] = {
* ciphertext in ECB and CBC modes
*/
.path = "/crypto/cipher/des-ecb-56-one-block",
- .alg = QCRYPTO_CIPHER_ALG_DES,
+ .alg = QCRYPTO_CIPHER_ALGO_DES,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "80c4a2e691d5b3f7",
.plaintext = "70617373776f7264",
@@ -165,7 +165,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* See previous comment */
.path = "/crypto/cipher/des-cbc-56-one-block",
- .alg = QCRYPTO_CIPHER_ALG_DES,
+ .alg = QCRYPTO_CIPHER_ALGO_DES,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key = "80c4a2e691d5b3f7",
.iv = "0000000000000000",
@@ -174,7 +174,7 @@ static QCryptoCipherTestData test_data[] = {
},
{
.path = "/crypto/cipher/des-ecb-56",
- .alg = QCRYPTO_CIPHER_ALG_DES,
+ .alg = QCRYPTO_CIPHER_ALGO_DES,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "80c4a2e691d5b3f7",
.plaintext =
@@ -191,7 +191,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* Borrowed from linux-kernel crypto/testmgr.h */
.path = "/crypto/cipher/3des-cbc",
- .alg = QCRYPTO_CIPHER_ALG_3DES,
+ .alg = QCRYPTO_CIPHER_ALGO_3DES,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key =
"e9c0ff2e760b6424444d995a12d640c0"
@@ -220,7 +220,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* Borrowed from linux-kernel crypto/testmgr.h */
.path = "/crypto/cipher/3des-ecb",
- .alg = QCRYPTO_CIPHER_ALG_3DES,
+ .alg = QCRYPTO_CIPHER_ALGO_3DES,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key =
"0123456789abcdef5555555555555555"
@@ -233,7 +233,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* Borrowed from linux-kernel crypto/testmgr.h */
.path = "/crypto/cipher/3des-ctr",
- .alg = QCRYPTO_CIPHER_ALG_3DES,
+ .alg = QCRYPTO_CIPHER_ALGO_3DES,
.mode = QCRYPTO_CIPHER_MODE_CTR,
.key =
"9cd6f39cb95a67005a67002dceeb2dce"
@@ -308,7 +308,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* RFC 2144, Appendix B.1 */
.path = "/crypto/cipher/cast5-128",
- .alg = QCRYPTO_CIPHER_ALG_CAST5_128,
+ .alg = QCRYPTO_CIPHER_ALGO_CAST5_128,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "0123456712345678234567893456789A",
.plaintext = "0123456789abcdef",
@@ -317,7 +317,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* libgcrypt serpent.c */
.path = "/crypto/cipher/serpent-128",
- .alg = QCRYPTO_CIPHER_ALG_SERPENT_128,
+ .alg = QCRYPTO_CIPHER_ALGO_SERPENT_128,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "00000000000000000000000000000000",
.plaintext = "d29d576fcea3a3a7ed9099f29273d78e",
@@ -326,7 +326,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* libgcrypt serpent.c */
.path = "/crypto/cipher/serpent-192",
- .alg = QCRYPTO_CIPHER_ALG_SERPENT_192,
+ .alg = QCRYPTO_CIPHER_ALGO_SERPENT_192,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "00000000000000000000000000000000"
"0000000000000000",
@@ -336,7 +336,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* libgcrypt serpent.c */
.path = "/crypto/cipher/serpent-256a",
- .alg = QCRYPTO_CIPHER_ALG_SERPENT_256,
+ .alg = QCRYPTO_CIPHER_ALGO_SERPENT_256,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "00000000000000000000000000000000"
"00000000000000000000000000000000",
@@ -346,7 +346,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* libgcrypt serpent.c */
.path = "/crypto/cipher/serpent-256b",
- .alg = QCRYPTO_CIPHER_ALG_SERPENT_256,
+ .alg = QCRYPTO_CIPHER_ALGO_SERPENT_256,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "00000000000000000000000000000000"
"00000000000000000000000000000000",
@@ -356,7 +356,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* Twofish paper "Known Answer Test" */
.path = "/crypto/cipher/twofish-128",
- .alg = QCRYPTO_CIPHER_ALG_TWOFISH_128,
+ .alg = QCRYPTO_CIPHER_ALGO_TWOFISH_128,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "d491db16e7b1c39e86cb086b789f5419",
.plaintext = "019f9809de1711858faac3a3ba20fbc3",
@@ -365,7 +365,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* Twofish paper "Known Answer Test", I=3 */
.path = "/crypto/cipher/twofish-192",
- .alg = QCRYPTO_CIPHER_ALG_TWOFISH_192,
+ .alg = QCRYPTO_CIPHER_ALGO_TWOFISH_192,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "88b2b2706b105e36b446bb6d731a1e88"
"efa71f788965bd44",
@@ -375,7 +375,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* Twofish paper "Known Answer Test", I=4 */
.path = "/crypto/cipher/twofish-256",
- .alg = QCRYPTO_CIPHER_ALG_TWOFISH_256,
+ .alg = QCRYPTO_CIPHER_ALGO_TWOFISH_256,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "d43bb7556ea32e46f2a282b7d45b4e0d"
"57ff739d4dc92c1bd7fc01700cc8216f",
@@ -386,7 +386,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* SM4, GB/T 32907-2016, Appendix A.1 */
.path = "/crypto/cipher/sm4",
- .alg = QCRYPTO_CIPHER_ALG_SM4,
+ .alg = QCRYPTO_CIPHER_ALGO_SM4,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "0123456789abcdeffedcba9876543210",
.plaintext =
@@ -398,7 +398,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* #1 32 byte key, 32 byte PTX */
.path = "/crypto/cipher/aes-xts-128-1",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"00000000000000000000000000000000"
@@ -415,7 +415,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* #2, 32 byte key, 32 byte PTX */
.path = "/crypto/cipher/aes-xts-128-2",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"11111111111111111111111111111111"
@@ -432,7 +432,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* #5 from xts.7, 32 byte key, 32 byte PTX */
.path = "/crypto/cipher/aes-xts-128-3",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0"
@@ -449,7 +449,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* #4, 32 byte key, 512 byte PTX */
.path = "/crypto/cipher/aes-xts-128-4",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"27182818284590452353602874713526"
@@ -528,7 +528,7 @@ static QCryptoCipherTestData test_data[] = {
* which is incompatible with XTS
*/
.path = "/crypto/cipher/cast5-xts-128",
- .alg = QCRYPTO_CIPHER_ALG_CAST5_128,
+ .alg = QCRYPTO_CIPHER_ALGO_CAST5_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"27182818284590452353602874713526"
@@ -537,7 +537,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.5.1 CTR-AES128.Encrypt */
.path = "/crypto/cipher/aes-ctr-128",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_CTR,
.key = "2b7e151628aed2a6abf7158809cf4f3c",
.iv = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
@@ -555,7 +555,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.5.3 CTR-AES192.Encrypt */
.path = "/crypto/cipher/aes-ctr-192",
- .alg = QCRYPTO_CIPHER_ALG_AES_192,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_192,
.mode = QCRYPTO_CIPHER_MODE_CTR,
.key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
.iv = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
@@ -573,7 +573,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.5.5 CTR-AES256.Encrypt */
.path = "/crypto/cipher/aes-ctr-256",
- .alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_256,
.mode = QCRYPTO_CIPHER_MODE_CTR,
.key = "603deb1015ca71be2b73aef0857d7781"
"1f352c073b6108d72d9810a30914dff4",
@@ -750,7 +750,7 @@ static void test_cipher_null_iv(void)
uint8_t ciphertext[32] = { 0 };
cipher = qcrypto_cipher_new(
- QCRYPTO_CIPHER_ALG_AES_256,
+ QCRYPTO_CIPHER_ALGO_AES_256,
QCRYPTO_CIPHER_MODE_CBC,
key, sizeof(key),
&error_abort);
@@ -779,7 +779,7 @@ static void test_cipher_short_plaintext(void)
int ret;
cipher = qcrypto_cipher_new(
- QCRYPTO_CIPHER_ALG_AES_256,
+ QCRYPTO_CIPHER_ALGO_AES_256,
QCRYPTO_CIPHER_MODE_CBC,
key, sizeof(key),
&error_abort);
@@ -823,16 +823,21 @@ int main(int argc, char **argv)
g_test_add_data_func(test_data[i].path, &test_data[i], test_cipher);
} else {
g_printerr("# skip unsupported %s:%s\n",
- QCryptoCipherAlgorithm_str(test_data[i].alg),
+ QCryptoCipherAlgo_str(test_data[i].alg),
QCryptoCipherMode_str(test_data[i].mode));
}
}
- g_test_add_func("/crypto/cipher/null-iv",
- test_cipher_null_iv);
+ if (qcrypto_cipher_supports(QCRYPTO_CIPHER_ALGO_AES_256,
+ QCRYPTO_CIPHER_MODE_CBC)) {
+ g_test_add_func("/crypto/cipher/null-iv",
+ test_cipher_null_iv);
- g_test_add_func("/crypto/cipher/short-plaintext",
- test_cipher_short_plaintext);
+ g_test_add_func("/crypto/cipher/short-plaintext",
+ test_cipher_short_plaintext);
+ } else {
+ g_printerr("# skip unsupported aes-256:cbc\n");
+ }
return g_test_run();
}
diff --git a/tests/unit/test-crypto-hash.c b/tests/unit/test-crypto-hash.c
index 1f4abb8..8fee159 100644
--- a/tests/unit/test-crypto-hash.c
+++ b/tests/unit/test-crypto-hash.c
@@ -1,6 +1,7 @@
/*
* QEMU Crypto hash algorithms
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -42,6 +43,9 @@
"63b54e4cb2d2032b393994aa263c0dbb" \
"e00a9f2fe9ef6037352232a1eec55ee7"
#define OUTPUT_RIPEMD160 "f3d658fad3fdfb2b52c9369cf0d441249ddfa8a0"
+#ifdef CONFIG_CRYPTO_SM3
+#define OUTPUT_SM3 "d4a97db105b477b84c4f20ec9c31a6c814e2705a0b83a5a89748d75f0ef456a1"
+#endif
#define OUTPUT_MD5_B64 "Yo0gY3FWMDWrjvYvSSveyQ=="
#define OUTPUT_SHA1_B64 "sudPJnWKOkIeUJzuBFJEt4dTzAI="
@@ -54,32 +58,45 @@
"7sVe5w=="
#define OUTPUT_RIPEMD160_B64 "89ZY+tP9+ytSyTac8NRBJJ3fqKA="
+#ifdef CONFIG_CRYPTO_SM3
+#define OUTPUT_SM3_B64 "1Kl9sQW0d7hMTyDsnDGmyBTicFoLg6Wol0jXXw70VqE="
+#endif
+
static const char *expected_outputs[] = {
- [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5,
- [QCRYPTO_HASH_ALG_SHA1] = OUTPUT_SHA1,
- [QCRYPTO_HASH_ALG_SHA224] = OUTPUT_SHA224,
- [QCRYPTO_HASH_ALG_SHA256] = OUTPUT_SHA256,
- [QCRYPTO_HASH_ALG_SHA384] = OUTPUT_SHA384,
- [QCRYPTO_HASH_ALG_SHA512] = OUTPUT_SHA512,
- [QCRYPTO_HASH_ALG_RIPEMD160] = OUTPUT_RIPEMD160,
+ [QCRYPTO_HASH_ALGO_MD5] = OUTPUT_MD5,
+ [QCRYPTO_HASH_ALGO_SHA1] = OUTPUT_SHA1,
+ [QCRYPTO_HASH_ALGO_SHA224] = OUTPUT_SHA224,
+ [QCRYPTO_HASH_ALGO_SHA256] = OUTPUT_SHA256,
+ [QCRYPTO_HASH_ALGO_SHA384] = OUTPUT_SHA384,
+ [QCRYPTO_HASH_ALGO_SHA512] = OUTPUT_SHA512,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = OUTPUT_RIPEMD160,
+#ifdef CONFIG_CRYPTO_SM3
+ [QCRYPTO_HASH_ALGO_SM3] = OUTPUT_SM3,
+#endif
};
static const char *expected_outputs_b64[] = {
- [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5_B64,
- [QCRYPTO_HASH_ALG_SHA1] = OUTPUT_SHA1_B64,
- [QCRYPTO_HASH_ALG_SHA224] = OUTPUT_SHA224_B64,
- [QCRYPTO_HASH_ALG_SHA256] = OUTPUT_SHA256_B64,
- [QCRYPTO_HASH_ALG_SHA384] = OUTPUT_SHA384_B64,
- [QCRYPTO_HASH_ALG_SHA512] = OUTPUT_SHA512_B64,
- [QCRYPTO_HASH_ALG_RIPEMD160] = OUTPUT_RIPEMD160_B64,
+ [QCRYPTO_HASH_ALGO_MD5] = OUTPUT_MD5_B64,
+ [QCRYPTO_HASH_ALGO_SHA1] = OUTPUT_SHA1_B64,
+ [QCRYPTO_HASH_ALGO_SHA224] = OUTPUT_SHA224_B64,
+ [QCRYPTO_HASH_ALGO_SHA256] = OUTPUT_SHA256_B64,
+ [QCRYPTO_HASH_ALGO_SHA384] = OUTPUT_SHA384_B64,
+ [QCRYPTO_HASH_ALGO_SHA512] = OUTPUT_SHA512_B64,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = OUTPUT_RIPEMD160_B64,
+#ifdef CONFIG_CRYPTO_SM3
+ [QCRYPTO_HASH_ALGO_SM3] = OUTPUT_SM3_B64,
+#endif
};
static const int expected_lens[] = {
- [QCRYPTO_HASH_ALG_MD5] = 16,
- [QCRYPTO_HASH_ALG_SHA1] = 20,
- [QCRYPTO_HASH_ALG_SHA224] = 28,
- [QCRYPTO_HASH_ALG_SHA256] = 32,
- [QCRYPTO_HASH_ALG_SHA384] = 48,
- [QCRYPTO_HASH_ALG_SHA512] = 64,
- [QCRYPTO_HASH_ALG_RIPEMD160] = 20,
+ [QCRYPTO_HASH_ALGO_MD5] = 16,
+ [QCRYPTO_HASH_ALGO_SHA1] = 20,
+ [QCRYPTO_HASH_ALGO_SHA224] = 28,
+ [QCRYPTO_HASH_ALGO_SHA256] = 32,
+ [QCRYPTO_HASH_ALGO_SHA384] = 48,
+ [QCRYPTO_HASH_ALGO_SHA512] = 64,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = 20,
+#ifdef CONFIG_CRYPTO_SM3
+ [QCRYPTO_HASH_ALGO_SM3] = 32,
+#endif
};
static const char hex[] = "0123456789abcdef";
@@ -122,7 +139,7 @@ static void test_hash_prealloc(void)
size_t i;
for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) {
- uint8_t *result;
+ uint8_t *result, *origresult;
size_t resultlen;
int ret;
size_t j;
@@ -132,7 +149,7 @@ static void test_hash_prealloc(void)
}
resultlen = expected_lens[i];
- result = g_new0(uint8_t, resultlen);
+ origresult = result = g_new0(uint8_t, resultlen);
ret = qcrypto_hash_bytes(i,
INPUT_TEXT,
@@ -141,7 +158,8 @@ static void test_hash_prealloc(void)
&resultlen,
&error_fatal);
g_assert(ret == 0);
-
+ /* Validate that our pre-allocated pointer was not replaced */
+ g_assert(result == origresult);
g_assert(resultlen == expected_lens[i]);
for (j = 0; j < resultlen; j++) {
g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]);
@@ -241,6 +259,50 @@ static void test_hash_base64(void)
}
}
+static void test_hash_accumulate(void)
+{
+ size_t i;
+
+ for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) {
+ g_autoptr(QCryptoHash) hash = NULL;
+ struct iovec iov[] = {
+ { .iov_base = (char *)INPUT_TEXT1, .iov_len = strlen(INPUT_TEXT1) },
+ { .iov_base = (char *)INPUT_TEXT2, .iov_len = strlen(INPUT_TEXT2) },
+ { .iov_base = (char *)INPUT_TEXT3, .iov_len = strlen(INPUT_TEXT3) },
+ };
+ g_autofree uint8_t *result = NULL;
+ size_t resultlen = 0;
+ int ret;
+ size_t j;
+
+ if (!qcrypto_hash_supports(i)) {
+ continue;
+ }
+
+ hash = qcrypto_hash_new(i, &error_fatal);
+ g_assert(hash != NULL);
+
+ /* Add each iovec to the hash context separately */
+ for (j = 0; j < G_N_ELEMENTS(iov); j++) {
+ ret = qcrypto_hash_updatev(hash,
+ &iov[j], 1,
+ &error_fatal);
+
+ g_assert(ret == 0);
+ }
+
+ ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen,
+ &error_fatal);
+
+ g_assert(ret == 0);
+ g_assert(resultlen == expected_lens[i]);
+ for (j = 0; j < resultlen; j++) {
+ g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]);
+ g_assert(expected_outputs[i][j * 2 + 1] == hex[result[j] & 0xf]);
+ }
+ }
+}
+
int main(int argc, char **argv)
{
int ret = qcrypto_init(&error_fatal);
@@ -252,5 +314,6 @@ int main(int argc, char **argv)
g_test_add_func("/crypto/hash/prealloc", test_hash_prealloc);
g_test_add_func("/crypto/hash/digest", test_hash_digest);
g_test_add_func("/crypto/hash/base64", test_hash_base64);
+ g_test_add_func("/crypto/hash/accumulate", test_hash_accumulate);
return g_test_run();
}
diff --git a/tests/unit/test-crypto-hmac.c b/tests/unit/test-crypto-hmac.c
index 23eb724..20c60eb 100644
--- a/tests/unit/test-crypto-hmac.c
+++ b/tests/unit/test-crypto-hmac.c
@@ -27,43 +27,43 @@
typedef struct QCryptoHmacTestData QCryptoHmacTestData;
struct QCryptoHmacTestData {
- QCryptoHashAlgorithm alg;
+ QCryptoHashAlgo alg;
const char *hex_digest;
};
static QCryptoHmacTestData test_data[] = {
{
- .alg = QCRYPTO_HASH_ALG_MD5,
+ .alg = QCRYPTO_HASH_ALGO_MD5,
.hex_digest =
"ede9cb83679ba82d88fbeae865b3f8fc",
},
{
- .alg = QCRYPTO_HASH_ALG_SHA1,
+ .alg = QCRYPTO_HASH_ALGO_SHA1,
.hex_digest =
"c7b5a631e3aac975c4ededfcd346e469"
"dbc5f2d1",
},
{
- .alg = QCRYPTO_HASH_ALG_SHA224,
+ .alg = QCRYPTO_HASH_ALGO_SHA224,
.hex_digest =
"5f768179dbb29ca722875d0f461a2e2f"
"597d0210340a84df1a8e9c63",
},
{
- .alg = QCRYPTO_HASH_ALG_SHA256,
+ .alg = QCRYPTO_HASH_ALGO_SHA256,
.hex_digest =
"3798f363c57afa6edaffe39016ca7bad"
"efd1e670afb0e3987194307dec3197db",
},
{
- .alg = QCRYPTO_HASH_ALG_SHA384,
+ .alg = QCRYPTO_HASH_ALGO_SHA384,
.hex_digest =
"d218680a6032d33dccd9882d6a6a7164"
"64f26623be257a9b2919b185294f4a49"
"9e54b190bfd6bc5cedd2cd05c7e65e82",
},
{
- .alg = QCRYPTO_HASH_ALG_SHA512,
+ .alg = QCRYPTO_HASH_ALGO_SHA512,
.hex_digest =
"835a4f5b3750b4c1fccfa88da2f746a4"
"900160c9f18964309bb736c13b59491b"
@@ -71,11 +71,19 @@ static QCryptoHmacTestData test_data[] = {
"94c4ba26862b2dadb59b7ede1d08d53e",
},
{
- .alg = QCRYPTO_HASH_ALG_RIPEMD160,
+ .alg = QCRYPTO_HASH_ALGO_RIPEMD160,
.hex_digest =
"94964ed4c1155b62b668c241d67279e5"
"8a711676",
},
+#ifdef CONFIG_CRYPTO_SM3
+ {
+ .alg = QCRYPTO_HASH_ALGO_SM3,
+ .hex_digest =
+ "760e3799332bc913819b930085360ddb"
+ "c05529261313d5b15b75bab4fd7ae91e",
+ },
+#endif
};
static const char hex[] = "0123456789abcdef";
@@ -126,7 +134,7 @@ static void test_hmac_prealloc(void)
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
QCryptoHmacTestData *data = &test_data[i];
QCryptoHmac *hmac = NULL;
- uint8_t *result = NULL;
+ uint8_t *result = NULL, *origresult = NULL;
size_t resultlen = 0;
const char *exp_output = NULL;
int ret;
@@ -139,7 +147,7 @@ static void test_hmac_prealloc(void)
exp_output = data->hex_digest;
resultlen = strlen(exp_output) / 2;
- result = g_new0(uint8_t, resultlen);
+ origresult = result = g_new0(uint8_t, resultlen);
hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY,
strlen(KEY), &error_fatal);
@@ -149,6 +157,8 @@ static void test_hmac_prealloc(void)
strlen(INPUT_TEXT), &result,
&resultlen, &error_fatal);
g_assert(ret == 0);
+ /* Validate that our pre-allocated pointer was not replaced */
+ g_assert(result == origresult);
exp_output = data->hex_digest;
for (j = 0; j < resultlen; j++) {
diff --git a/tests/unit/test-crypto-ivgen.c b/tests/unit/test-crypto-ivgen.c
index 29630ed..bc9ffe3 100644
--- a/tests/unit/test-crypto-ivgen.c
+++ b/tests/unit/test-crypto-ivgen.c
@@ -26,9 +26,9 @@
struct QCryptoIVGenTestData {
const char *path;
uint64_t sector;
- QCryptoIVGenAlgorithm ivalg;
- QCryptoHashAlgorithm hashalg;
- QCryptoCipherAlgorithm cipheralg;
+ QCryptoIVGenAlgo ivalg;
+ QCryptoHashAlgo hashalg;
+ QCryptoCipherAlgo cipheralg;
const uint8_t *key;
size_t nkey;
const uint8_t *iv;
@@ -38,7 +38,7 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/plain/1",
.sector = 0x1,
- .ivalg = QCRYPTO_IVGEN_ALG_PLAIN,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_PLAIN,
.iv = (const uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
@@ -47,7 +47,7 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/plain/1f2e3d4c",
.sector = 0x1f2e3d4cULL,
- .ivalg = QCRYPTO_IVGEN_ALG_PLAIN,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_PLAIN,
.iv = (const uint8_t *)"\x4c\x3d\x2e\x1f\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
@@ -56,7 +56,7 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/plain/1f2e3d4c5b6a7988",
.sector = 0x1f2e3d4c5b6a7988ULL,
- .ivalg = QCRYPTO_IVGEN_ALG_PLAIN,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_PLAIN,
.iv = (const uint8_t *)"\x88\x79\x6a\x5b\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
@@ -65,7 +65,7 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/plain64/1",
.sector = 0x1,
- .ivalg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
.iv = (const uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
@@ -74,7 +74,7 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/plain64/1f2e3d4c",
.sector = 0x1f2e3d4cULL,
- .ivalg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
.iv = (const uint8_t *)"\x4c\x3d\x2e\x1f\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
@@ -83,7 +83,7 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/plain64/1f2e3d4c5b6a7988",
.sector = 0x1f2e3d4c5b6a7988ULL,
- .ivalg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
.iv = (const uint8_t *)"\x88\x79\x6a\x5b\x4c\x3d\x2e\x1f"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
@@ -92,9 +92,9 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/essiv/1",
.sector = 0x1,
- .ivalg = QCRYPTO_IVGEN_ALG_ESSIV,
- .cipheralg = QCRYPTO_CIPHER_ALG_AES_128,
- .hashalg = QCRYPTO_HASH_ALG_SHA256,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_ESSIV,
+ .cipheralg = QCRYPTO_CIPHER_ALGO_AES_128,
+ .hashalg = QCRYPTO_HASH_ALGO_SHA256,
.key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.nkey = 16,
@@ -106,9 +106,9 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/essiv/1f2e3d4c",
.sector = 0x1f2e3d4cULL,
- .ivalg = QCRYPTO_IVGEN_ALG_ESSIV,
- .cipheralg = QCRYPTO_CIPHER_ALG_AES_128,
- .hashalg = QCRYPTO_HASH_ALG_SHA256,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_ESSIV,
+ .cipheralg = QCRYPTO_CIPHER_ALGO_AES_128,
+ .hashalg = QCRYPTO_HASH_ALGO_SHA256,
.key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.nkey = 16,
@@ -120,9 +120,9 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/essiv/1f2e3d4c5b6a7988",
.sector = 0x1f2e3d4c5b6a7988ULL,
- .ivalg = QCRYPTO_IVGEN_ALG_ESSIV,
- .cipheralg = QCRYPTO_CIPHER_ALG_AES_128,
- .hashalg = QCRYPTO_HASH_ALG_SHA256,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_ESSIV,
+ .cipheralg = QCRYPTO_CIPHER_ALGO_AES_128,
+ .hashalg = QCRYPTO_HASH_ALGO_SHA256,
.key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.nkey = 16,
@@ -166,7 +166,7 @@ int main(int argc, char **argv)
size_t i;
g_test_init(&argc, &argv, NULL);
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
- if (test_data[i].ivalg == QCRYPTO_IVGEN_ALG_ESSIV &&
+ if (test_data[i].ivalg == QCRYPTO_IV_GEN_ALGO_ESSIV &&
!qcrypto_hash_supports(test_data[i].hashalg)) {
continue;
}
diff --git a/tests/unit/test-crypto-pbkdf.c b/tests/unit/test-crypto-pbkdf.c
index 39264cb..ddb7244 100644
--- a/tests/unit/test-crypto-pbkdf.c
+++ b/tests/unit/test-crypto-pbkdf.c
@@ -25,13 +25,13 @@
#include <sys/resource.h>
#endif
-#if defined(_WIN32) || defined(RUSAGE_THREAD) || defined(CONFIG_DARWNI)
+#if defined(_WIN32) || defined(RUSAGE_THREAD) || defined(CONFIG_DARWIN)
#include "crypto/pbkdf.h"
typedef struct QCryptoPbkdfTestData QCryptoPbkdfTestData;
struct QCryptoPbkdfTestData {
const char *path;
- QCryptoHashAlgorithm hash;
+ QCryptoHashAlgo hash;
unsigned int iterations;
const char *key;
size_t nkey;
@@ -52,7 +52,7 @@ static QCryptoPbkdfTestData test_data[] = {
/* RFC 3962 test data */
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter1",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 1,
.key = "password",
.nkey = 8,
@@ -66,7 +66,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter2",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 2,
.key = "password",
.nkey = 8,
@@ -80,7 +80,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter1200a",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 1200,
.key = "password",
.nkey = 8,
@@ -94,7 +94,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter5",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 5,
.key = "password",
.nkey = 8,
@@ -108,7 +108,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter1200b",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
@@ -123,7 +123,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter1200c",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
@@ -138,7 +138,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter50",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 50,
.key = "\360\235\204\236", /* g-clef ("\xf09d849e) */
.nkey = 4,
@@ -154,7 +154,7 @@ static QCryptoPbkdfTestData test_data[] = {
/* RFC-6070 test data */
{
.path = "/crypto/pbkdf/rfc6070/sha1/iter1",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 1,
.key = "password",
.nkey = 8,
@@ -166,7 +166,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc6070/sha1/iter2",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 2,
.key = "password",
.nkey = 8,
@@ -178,7 +178,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc6070/sha1/iter4096",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 4096,
.key = "password",
.nkey = 8,
@@ -190,7 +190,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc6070/sha1/iter16777216",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 16777216,
.key = "password",
.nkey = 8,
@@ -203,7 +203,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc6070/sha1/iter4096a",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 4096,
.key = "passwordPASSWORDpassword",
.nkey = 24,
@@ -216,7 +216,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc6070/sha1/iter4096b",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 4096,
.key = "pass\0word",
.nkey = 9,
@@ -231,7 +231,7 @@ static QCryptoPbkdfTestData test_data[] = {
{
/* empty password test. */
.path = "/crypto/pbkdf/nonrfc/sha1/iter2",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 2,
.key = "",
.nkey = 0,
@@ -244,7 +244,7 @@ static QCryptoPbkdfTestData test_data[] = {
{
/* Password exceeds block size test */
.path = "/crypto/pbkdf/nonrfc/sha256/iter1200",
- .hash = QCRYPTO_HASH_ALG_SHA256,
+ .hash = QCRYPTO_HASH_ALGO_SHA256,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
@@ -259,7 +259,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/nonrfc/sha512/iter1200",
- .hash = QCRYPTO_HASH_ALG_SHA512,
+ .hash = QCRYPTO_HASH_ALGO_SHA512,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
@@ -276,7 +276,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/nonrfc/sha224/iter1200",
- .hash = QCRYPTO_HASH_ALG_SHA224,
+ .hash = QCRYPTO_HASH_ALGO_SHA224,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
@@ -293,7 +293,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/nonrfc/sha384/iter1200",
- .hash = QCRYPTO_HASH_ALG_SHA384,
+ .hash = QCRYPTO_HASH_ALGO_SHA384,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
@@ -310,7 +310,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/nonrfc/ripemd160/iter1200",
- .hash = QCRYPTO_HASH_ALG_RIPEMD160,
+ .hash = QCRYPTO_HASH_ALGO_RIPEMD160,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
@@ -325,10 +325,26 @@ static QCryptoPbkdfTestData test_data[] = {
"\xce\xbf\x91\x14\x8b\x5c\x48\x41",
.nout = 32
},
+#ifdef CONFIG_CRYPTO_SM3
+ {
+ .path = "/crypto/pbkdf/nonrfc/sm3/iter2",
+ .hash = QCRYPTO_HASH_ALGO_SM3,
+ .iterations = 2,
+ .key = "password",
+ .nkey = 8,
+ .salt = "ATHENA.MIT.EDUraeburn",
+ .nsalt = 21,
+ .out = "\x48\x71\x1b\x58\xa3\xcb\xce\x06"
+ "\xba\xad\x77\xa8\xb5\xb9\xd8\x07"
+ "\x6a\xe2\xb3\x5b\x95\xce\xc8\xce"
+ "\xe7\xb1\xcb\xee\x61\xdf\x04\xea",
+ .nout = 32
+ },
+#endif
#if 0
{
.path = "/crypto/pbkdf/nonrfc/whirlpool/iter1200",
- .hash = QCRYPTO_HASH_ALG_WHIRLPOOL,
+ .hash = QCRYPTO_HASH_ALGO_WHIRLPOOL,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
@@ -402,7 +418,7 @@ static void test_pbkdf_timing_sha256(void)
memset(key, 0x5d, sizeof(key));
memset(salt, 0x7c, sizeof(salt));
- iters = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALG_SHA256,
+ iters = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALGO_SHA256,
key, sizeof(key),
salt, sizeof(salt),
32,
@@ -431,7 +447,7 @@ int main(int argc, char **argv)
}
}
- if (g_test_slow() && qcrypto_pbkdf2_supports(QCRYPTO_HASH_ALG_SHA256)) {
+ if (g_test_slow() && qcrypto_pbkdf2_supports(QCRYPTO_HASH_ALGO_SHA256)) {
g_test_add_func("/crypt0/pbkdf/timing/sha256", test_pbkdf_timing_sha256);
}
diff --git a/tests/unit/test-crypto-secret.c b/tests/unit/test-crypto-secret.c
index ffd13ff..fc32a01 100644
--- a/tests/unit/test-crypto-secret.c
+++ b/tests/unit/test-crypto-secret.c
@@ -22,6 +22,7 @@
#include "crypto/init.h"
#include "crypto/secret.h"
+#include "crypto/cipher.h"
#include "qapi/error.h"
#include "qemu/module.h"
#if defined(CONFIG_KEYUTILS) && defined(CONFIG_SECRET_KEYRING)
@@ -597,18 +598,21 @@ int main(int argc, char **argv)
g_test_add_func("/crypto/secret/conv/utf8/base64",
test_secret_conv_utf8_base64);
- g_test_add_func("/crypto/secret/crypt/raw",
- test_secret_crypt_raw);
- g_test_add_func("/crypto/secret/crypt/base64",
- test_secret_crypt_base64);
- g_test_add_func("/crypto/secret/crypt/shortkey",
- test_secret_crypt_short_key);
- g_test_add_func("/crypto/secret/crypt/shortiv",
- test_secret_crypt_short_iv);
- g_test_add_func("/crypto/secret/crypt/missingiv",
- test_secret_crypt_missing_iv);
- g_test_add_func("/crypto/secret/crypt/badiv",
- test_secret_crypt_bad_iv);
+ if (qcrypto_cipher_supports(QCRYPTO_CIPHER_ALGO_AES_128,
+ QCRYPTO_CIPHER_MODE_CBC)) {
+ g_test_add_func("/crypto/secret/crypt/raw",
+ test_secret_crypt_raw);
+ g_test_add_func("/crypto/secret/crypt/base64",
+ test_secret_crypt_base64);
+ g_test_add_func("/crypto/secret/crypt/shortkey",
+ test_secret_crypt_short_key);
+ g_test_add_func("/crypto/secret/crypt/shortiv",
+ test_secret_crypt_short_iv);
+ g_test_add_func("/crypto/secret/crypt/missingiv",
+ test_secret_crypt_missing_iv);
+ g_test_add_func("/crypto/secret/crypt/badiv",
+ test_secret_crypt_bad_iv);
+ }
return g_test_run();
}
diff --git a/tests/unit/test-crypto-tlssession.c b/tests/unit/test-crypto-tlssession.c
index 3395f73..554054e 100644
--- a/tests/unit/test-crypto-tlssession.c
+++ b/tests/unit/test-crypto-tlssession.c
@@ -158,8 +158,7 @@ static void test_crypto_tls_session_psk(void)
rv = qcrypto_tls_session_handshake(serverSess,
&error_abort);
g_assert(rv >= 0);
- if (qcrypto_tls_session_get_handshake_status(serverSess) ==
- QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
+ if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
serverShake = true;
}
}
@@ -167,8 +166,7 @@ static void test_crypto_tls_session_psk(void)
rv = qcrypto_tls_session_handshake(clientSess,
&error_abort);
g_assert(rv >= 0);
- if (qcrypto_tls_session_get_handshake_status(clientSess) ==
- QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
+ if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
clientShake = true;
}
}
@@ -352,8 +350,7 @@ static void test_crypto_tls_session_x509(const void *opaque)
rv = qcrypto_tls_session_handshake(serverSess,
&error_abort);
g_assert(rv >= 0);
- if (qcrypto_tls_session_get_handshake_status(serverSess) ==
- QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
+ if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
serverShake = true;
}
}
@@ -361,8 +358,7 @@ static void test_crypto_tls_session_x509(const void *opaque)
rv = qcrypto_tls_session_handshake(clientSess,
&error_abort);
g_assert(rv >= 0);
- if (qcrypto_tls_session_get_handshake_status(clientSess) ==
- QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
+ if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
clientShake = true;
}
}
diff --git a/tests/unit/test-fifo.c b/tests/unit/test-fifo.c
new file mode 100644
index 0000000..14153c4
--- /dev/null
+++ b/tests/unit/test-fifo.c
@@ -0,0 +1,449 @@
+/*
+ * Fifo8 tests
+ *
+ * Copyright 2024 Mark Cave-Ayland
+ *
+ * Authors:
+ * Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "migration/vmstate.h"
+#include "qemu/fifo8.h"
+
+const VMStateInfo vmstate_info_uint32;
+const VMStateInfo vmstate_info_buffer;
+
+
+static void test_fifo8_pop_bufptr_wrap(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in1[] = { 0x1, 0x2, 0x3, 0x4 };
+ uint8_t data_in2[] = { 0x5, 0x6, 0x7, 0x8, 0x9, 0xa };
+ const uint8_t *buf;
+ uint32_t count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: [ . . . . . . . . ]
+ */
+
+ fifo8_push_all(&fifo, data_in1, sizeof(data_in1));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: [ 1 2 3 4 . . . . ]
+ */
+ buf = fifo8_pop_bufptr(&fifo, 2, &count);
+ /*
+ * head --v ]-- tail used = 2
+ * FIFO: [ 1 2 3 4 . . . . ]
+ * buf --^ count = 2
+ */
+ g_assert(count == 2);
+ g_assert(buf[0] == 0x1 && buf[1] == 0x2);
+
+ fifo8_push_all(&fifo, data_in2, sizeof(data_in2));
+ /*
+ * tail --]v-- head used = 8
+ * FIFO: [ 9 a 3 4 5 6 7 8 ]
+ */
+ buf = fifo8_pop_bufptr(&fifo, 8, &count);
+ /*
+ * head --v ]-- tail used = 2
+ * FIFO: [ 9 a 3 4 5 6 7 8 ]
+ * buf --^ count = 6
+ */
+ g_assert(count == 6);
+ g_assert(buf[0] == 0x3 && buf[1] == 0x4 && buf[2] == 0x5 &&
+ buf[3] == 0x6 && buf[4] == 0x7 && buf[5] == 0x8);
+
+ g_assert(fifo8_num_used(&fifo) == 2);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_pop_bufptr(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in[] = { 0x1, 0x2, 0x3, 0x4 };
+ const uint8_t *buf;
+ uint32_t count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: [ . . . . . . . . ]
+ */
+
+ fifo8_push_all(&fifo, data_in, sizeof(data_in));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: [ 1 2 3 4 . . . . ]
+ */
+ buf = fifo8_pop_bufptr(&fifo, 2, &count);
+ /*
+ * head --v ]-- tail used = 2
+ * FIFO: [ 1 2 3 4 . . . . ]
+ * buf --^ count = 2
+ */
+ g_assert(count == 2);
+ g_assert(buf[0] == 0x1 && buf[1] == 0x2);
+
+ g_assert(fifo8_num_used(&fifo) == 2);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_peek_bufptr_wrap(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in1[] = { 0x1, 0x2, 0x3, 0x4 };
+ uint8_t data_in2[] = { 0x5, 0x6, 0x7, 0x8, 0x9, 0xa };
+ const uint8_t *buf;
+ uint32_t count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in1, sizeof(data_in1));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ buf = fifo8_peek_bufptr(&fifo, 2, &count);
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ * buf: [ 1 2 ] count = 2
+ */
+ g_assert(count == 2);
+ g_assert(buf[0] == 0x1 && buf[1] == 0x2);
+
+ buf = fifo8_pop_bufptr(&fifo, 2, &count);
+ /*
+ * head --v ]-- tail used = 2
+ * FIFO: { 1 2 3 4 . . . . }
+ * buf: [ 1 2 ] count = 2
+ */
+ g_assert(count == 2);
+ g_assert(buf[0] == 0x1 && buf[1] == 0x2);
+ fifo8_push_all(&fifo, data_in2, sizeof(data_in2));
+ /*
+ * tail ---]v-- head used = 8
+ * FIFO: { 9 a 3 4 5 6 7 8 }
+ */
+
+ buf = fifo8_peek_bufptr(&fifo, 8, &count);
+ /*
+ * tail --]v-- head used = 8
+ * FIFO: { 9 a 3 4 5 6 7 8 }
+ * buf: [ 3 4 5 6 7 8 ] count = 6
+ */
+ g_assert(count == 6);
+ g_assert(buf[0] == 0x3 && buf[1] == 0x4 && buf[2] == 0x5 &&
+ buf[3] == 0x6 && buf[4] == 0x7 && buf[5] == 0x8);
+
+ g_assert(fifo8_num_used(&fifo) == 8);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_peek_bufptr(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in[] = { 0x1, 0x2, 0x3, 0x4 };
+ const uint8_t *buf;
+ uint32_t count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in, sizeof(data_in));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ buf = fifo8_peek_bufptr(&fifo, 2, &count);
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ * buf: [ 1 2 ] count = 2
+ */
+ g_assert(count == 2);
+ g_assert(buf[0] == 0x1 && buf[1] == 0x2);
+
+ g_assert(fifo8_num_used(&fifo) == 4);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_pop_buf_wrap(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in1[] = { 0x1, 0x2, 0x3, 0x4 };
+ uint8_t data_in2[] = { 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc };
+ uint8_t data_out[4];
+ int count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in1, sizeof(data_in1));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ fifo8_pop_buf(&fifo, NULL, 4);
+ /*
+ * tail --]v-- head used = 0
+ * FIFO: [ 1 2 3 4 . . . . ]
+ */
+
+ fifo8_push_all(&fifo, data_in2, sizeof(data_in2));
+ /*
+ * tail --]v-- head used = 8
+ * FIFO: { 9 a b c 5 6 7 8 }
+ */
+ count = fifo8_pop_buf(&fifo, NULL, 4);
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 9 a b c 5 6 7 8 }
+ */
+ g_assert(count == 4);
+ count = fifo8_pop_buf(&fifo, data_out, 4);
+ /*
+ * tail --]v-- head used = 0
+ * FIFO: { 9 a b c 5 6 7 8 }
+ */
+ g_assert(count == 4);
+ g_assert(data_out[0] == 0x9 && data_out[1] == 0xa &&
+ data_out[2] == 0xb && data_out[3] == 0xc);
+
+ g_assert(fifo8_num_used(&fifo) == 0);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_pop_buf(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in[] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 };
+ uint8_t data_out[] = { 0xff, 0xff, 0xff, 0xff };
+ int count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in, sizeof(data_in));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ count = fifo8_pop_buf(&fifo, NULL, 4);
+ /*
+ * tail --]v-- head used = 0
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ g_assert(count == 4);
+ count = fifo8_pop_buf(&fifo, data_out, 4);
+ g_assert(data_out[0] == 0x5 && data_out[1] == 0x6 &&
+ data_out[2] == 0x7 && data_out[3] == 0x8);
+
+ g_assert(fifo8_num_used(&fifo) == 0);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_peek_buf_wrap(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in1[] = { 0x1, 0x2, 0x3, 0x4 };
+ uint8_t data_in2[] = { 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc };
+ uint8_t data_out[8];
+ int count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in1, sizeof(data_in1));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ fifo8_pop_buf(&fifo, NULL, 4);
+ /*
+ * tail --]v-- head used = 0
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in2, sizeof(data_in2));
+ /*
+ * tail --]v-- head used = 8
+ * FIFO: { 9 a b c 5 6 7 8 }
+ */
+ count = fifo8_peek_buf(&fifo, NULL, 4);
+ g_assert(count == 4);
+ count = fifo8_peek_buf(&fifo, data_out, 4);
+ /*
+ * tail --]v-- head used = 8
+ * FIFO: { 9 a b c 5 6 7 8 }
+ * buf: [ 5 6 7 8 ] count = 4
+ */
+ g_assert(count == 4);
+ g_assert(data_out[0] == 0x5 && data_out[1] == 0x6 &&
+ data_out[2] == 0x7 && data_out[3] == 0x8);
+
+ count = fifo8_peek_buf(&fifo, data_out, 8);
+ /*
+ * tail --]v-- head used = 8
+ * FIFO: { 9 a b c 5 6 7 8 }
+ * buf: [ 5 6 7 8 9 a b c ] count = 8
+ */
+ g_assert(count == 8);
+ g_assert(data_out[0] == 0x5 && data_out[1] == 0x6 &&
+ data_out[2] == 0x7 && data_out[3] == 0x8);
+ g_assert(data_out[4] == 0x9 && data_out[5] == 0xa &&
+ data_out[6] == 0xb && data_out[7] == 0xc);
+
+ g_assert(fifo8_num_used(&fifo) == 8);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_peek_buf(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in[] = { 0x1, 0x2, 0x3, 0x4 };
+ uint8_t data_out[] = { 0xff, 0xff, 0xff, 0xff };
+ int count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in, sizeof(data_in));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ count = fifo8_peek_buf(&fifo, NULL, 4);
+ g_assert(count == 4);
+
+ g_assert(data_out[0] == 0xff && data_out[1] == 0xff &&
+ data_out[2] == 0xff && data_out[3] == 0xff);
+ count = fifo8_peek_buf(&fifo, data_out, 4);
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ * buf: [ 1 2 3 4 ] count = 4
+ */
+ g_assert(count == 4);
+ g_assert(data_out[0] == 0x1 && data_out[1] == 0x2 &&
+ data_out[2] == 0x3 && data_out[3] == 0x4);
+
+ g_assert(fifo8_num_used(&fifo) == 4);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_peek(void)
+{
+ Fifo8 fifo;
+ uint8_t c;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+ fifo8_push(&fifo, 0x1);
+ /*
+ * head --v]-- tail used = 1
+ * FIFO: { 1 . . . . . . . }
+ */
+ fifo8_push(&fifo, 0x2);
+ /*
+ * head --v ]-- tail used = 2
+ * FIFO: { 1 2 . . . . . . }
+ */
+
+ c = fifo8_peek(&fifo);
+ g_assert(c == 0x1);
+ fifo8_pop(&fifo);
+ /*
+ * head --v]-- tail used = 1
+ * FIFO: { 1 2 . . . . . . }
+ */
+ c = fifo8_peek(&fifo);
+ g_assert(c == 0x2);
+
+ g_assert(fifo8_num_used(&fifo) == 1);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_pushpop(void)
+{
+ Fifo8 fifo;
+ uint8_t c;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+ fifo8_push(&fifo, 0x1);
+ /*
+ * head --v]-- tail used = 1
+ * FIFO: { 1 . . . . . . . }
+ */
+ fifo8_push(&fifo, 0x2);
+ /*
+ * head --v ]-- tail used = 2
+ * FIFO: { 1 2 . . . . . . }
+ */
+
+ c = fifo8_pop(&fifo);
+ /*
+ * head --v]-- tail used = 1
+ * FIFO: { 1 2 . . . . . . }
+ */
+ g_assert(c == 0x1);
+ c = fifo8_pop(&fifo);
+ /*
+ * tail --]v-- head used = 0
+ * FIFO: { 1 2 . . . . . . }
+ */
+ g_assert(c == 0x2);
+
+ g_assert(fifo8_num_used(&fifo) == 0);
+ fifo8_destroy(&fifo);
+}
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/fifo8/pushpop", test_fifo8_pushpop);
+ g_test_add_func("/fifo8/peek", test_fifo8_peek);
+ g_test_add_func("/fifo8/peek_buf", test_fifo8_peek_buf);
+ g_test_add_func("/fifo8/peek_buf_wrap", test_fifo8_peek_buf_wrap);
+ g_test_add_func("/fifo8/pop_buf", test_fifo8_pop_buf);
+ g_test_add_func("/fifo8/pop_buf_wrap", test_fifo8_pop_buf_wrap);
+ g_test_add_func("/fifo8/peek_bufptr", test_fifo8_peek_bufptr);
+ g_test_add_func("/fifo8/peek_bufptr_wrap", test_fifo8_peek_bufptr_wrap);
+ g_test_add_func("/fifo8/pop_bufptr", test_fifo8_pop_bufptr);
+ g_test_add_func("/fifo8/pop_bufptr_wrap", test_fifo8_pop_bufptr_wrap);
+ return g_test_run();
+}
diff --git a/tests/unit/test-forward-visitor.c b/tests/unit/test-forward-visitor.c
index eea8ffc..aad1c89 100644
--- a/tests/unit/test-forward-visitor.c
+++ b/tests/unit/test-forward-visitor.c
@@ -12,8 +12,8 @@
#include "qapi/forward-visitor.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/error.h"
-#include "qapi/qmp/qobject.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qobject.h"
+#include "qobject/qdict.h"
#include "test-qapi-visit.h"
#include "qemu/keyval.h"
diff --git a/tests/unit/test-image-locking.c b/tests/unit/test-image-locking.c
index 2624cec..019195f 100644
--- a/tests/unit/test-image-locking.c
+++ b/tests/unit/test-image-locking.c
@@ -26,9 +26,9 @@
#include "qemu/osdep.h"
#include "block/block.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qemu/main-loop.h"
static BlockBackend *open_image(const char *path,
diff --git a/tests/unit/test-io-channel-socket.c b/tests/unit/test-io-channel-socket.c
index b964bb2..dc7be96 100644
--- a/tests/unit/test-io-channel-socket.c
+++ b/tests/unit/test-io-channel-socket.c
@@ -506,7 +506,7 @@ static void test_io_channel_unix_listen_cleanup(void)
{
QIOChannelSocket *ioc;
struct sockaddr_un un;
- int sock;
+ int sock, ret = 0;
#define TEST_SOCKET "test-io-channel-socket.sock"
@@ -519,7 +519,9 @@ static void test_io_channel_unix_listen_cleanup(void)
un.sun_family = AF_UNIX;
snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET);
unlink(TEST_SOCKET);
- bind(sock, (struct sockaddr *)&un, sizeof(un));
+ ret = bind(sock, (struct sockaddr *)&un, sizeof(un));
+ g_assert_cmpint(ret, ==, 0);
+
ioc->fd = sock;
ioc->localAddrLen = sizeof(ioc->localAddr);
getsockname(sock, (struct sockaddr *)&ioc->localAddr,
diff --git a/tests/unit/test-keyval.c b/tests/unit/test-keyval.c
index 4dc52c7..c6e8f4f 100644
--- a/tests/unit/test-keyval.c
+++ b/tests/unit/test-keyval.c
@@ -13,9 +13,9 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
+#include "qobject/qstring.h"
#include "qapi/qobject-input-visitor.h"
#include "test-qapi-visit.h"
#include "qemu/cutils.h"
diff --git a/tests/unit/test-qdev-global-props.c b/tests/unit/test-qdev-global-props.c
index c8862ca..3306276 100644
--- a/tests/unit/test-qdev-global-props.c
+++ b/tests/unit/test-qdev-global-props.c
@@ -46,13 +46,12 @@ struct MyType {
uint32_t prop2;
};
-static Property static_props[] = {
+static const Property static_props[] = {
DEFINE_PROP_UINT32("prop1", MyType, prop1, PROP_DEFAULT),
DEFINE_PROP_UINT32("prop2", MyType, prop2, PROP_DEFAULT),
- DEFINE_PROP_END_OF_LIST()
};
-static void static_prop_class_init(ObjectClass *oc, void *data)
+static void static_prop_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -72,6 +71,26 @@ static const TypeInfo subclass_type = {
.parent = TYPE_STATIC_PROPS,
};
+/*
+ * Initialize a fake machine, being prepared for future tests.
+ *
+ * All the tests later (even if to be run in subprocesses.. which will
+ * inherit the global states of the parent process) will try to create qdev
+ * and realize the device.
+ *
+ * Realization of such anonymous qdev (with no parent object) requires both
+ * the machine object and its "unattached" container to be at least present.
+ */
+static void test_init_machine(void)
+{
+ /* This is a fake machine - it doesn't need to be a machine object */
+ Object *machine = object_property_add_new_container(
+ object_get_root(), "machine");
+
+ /* This container must exist for anonymous qdevs to realize() */
+ object_property_add_new_container(machine, "unattached");
+}
+
/* Test simple static property setting to default value */
static void test_static_prop_subprocess(void)
{
@@ -158,7 +177,7 @@ static void dynamic_instance_init(Object *obj)
NULL, NULL);
}
-static void dynamic_class_init(ObjectClass *oc, void *data)
+static void dynamic_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -174,7 +193,7 @@ static const TypeInfo dynamic_prop_type = {
.class_init = dynamic_class_init,
};
-static void hotplug_class_init(ObjectClass *oc, void *data)
+static void hotplug_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -190,7 +209,7 @@ static const TypeInfo hotplug_type = {
.class_init = hotplug_class_init,
};
-static void nohotplug_class_init(ObjectClass *oc, void *data)
+static void nohotplug_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -295,6 +314,8 @@ int main(int argc, char **argv)
type_register_static(&nohotplug_type);
type_register_static(&nondevice_type);
+ test_init_machine();
+
g_test_add_func("/qdev/properties/static/default/subprocess",
test_static_prop_subprocess);
g_test_add_func("/qdev/properties/static/default",
diff --git a/tests/unit/test-qemu-opts.c b/tests/unit/test-qemu-opts.c
index 828d40e..8d03a69 100644
--- a/tests/unit/test-qemu-opts.c
+++ b/tests/unit/test-qemu-opts.c
@@ -12,8 +12,8 @@
#include "qemu/option.h"
#include "qemu/option_int.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qdict.h"
+#include "qobject/qstring.h"
#include "qemu/config-file.h"
diff --git a/tests/unit/test-qga.c b/tests/unit/test-qga.c
index 8cddf5d..587e30c 100644
--- a/tests/unit/test-qga.c
+++ b/tests/unit/test-qga.c
@@ -5,8 +5,8 @@
#include <sys/un.h>
#include "../qtest/libqtest.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
typedef struct {
char *test_dir;
@@ -332,6 +332,22 @@ static void test_qga_get_fsinfo(gconstpointer fix)
}
}
+static void test_qga_get_load(gconstpointer fix)
+{
+ const TestFixture *fixture = fix;
+ g_autoptr(QDict) ret = NULL;
+ QDict *load;
+
+ ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-load'}");
+ g_assert_nonnull(ret);
+ qmp_assert_no_error(ret);
+
+ load = qdict_get_qdict(ret, "return");
+ g_assert(qdict_haskey(load, "load1m"));
+ g_assert(qdict_haskey(load, "load5m"));
+ g_assert(qdict_haskey(load, "load15m"));
+}
+
static void test_qga_get_memory_block_info(gconstpointer fix)
{
const TestFixture *fixture = fix;
@@ -1105,6 +1121,7 @@ int main(int argc, char **argv)
g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus);
}
g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo);
+ g_test_add_data_func("/qga/get-load", &fix, test_qga_get_load);
g_test_add_data_func("/qga/get-memory-block-info", &fix,
test_qga_get_memory_block_info);
g_test_add_data_func("/qga/get-memory-blocks", &fix,
diff --git a/tests/unit/test-qgraph.c b/tests/unit/test-qgraph.c
index 334c76c..ca1d60f 100644
--- a/tests/unit/test-qgraph.c
+++ b/tests/unit/test-qgraph.c
@@ -44,7 +44,6 @@ static void *driverfunct(void *obj, QGuestAllocator *machine, void *arg)
static void testfunct(void *obj, void *arg, QGuestAllocator *alloc)
{
- return;
}
static void check_interface(const char *interface)
diff --git a/tests/unit/test-qmp-cmds.c b/tests/unit/test-qmp-cmds.c
index 6d52b4e..ad53886 100644
--- a/tests/unit/test-qmp-cmds.c
+++ b/tests/unit/test-qmp-cmds.c
@@ -1,9 +1,9 @@
#include "qemu/osdep.h"
#include "qapi/compat-policy.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qjson.h"
-#include "qapi/qmp/qnum.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qdict.h"
+#include "qobject/qjson.h"
+#include "qobject/qnum.h"
+#include "qobject/qstring.h"
#include "qapi/error.h"
#include "qapi/qobject-input-visitor.h"
#include "tests/test-qapi-types.h"
diff --git a/tests/unit/test-qmp-event.c b/tests/unit/test-qmp-event.c
index 08e95a3..2aac271 100644
--- a/tests/unit/test-qmp-event.c
+++ b/tests/unit/test-qmp-event.c
@@ -15,11 +15,11 @@
#include "qapi/compat-policy.h"
#include "qapi/error.h"
-#include "qapi/qmp/qbool.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qjson.h"
-#include "qapi/qmp/qnum.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qbool.h"
+#include "qobject/qdict.h"
+#include "qobject/qjson.h"
+#include "qobject/qnum.h"
+#include "qobject/qstring.h"
#include "qapi/qmp-event.h"
#include "test-qapi-events.h"
#include "test-qapi-emit-events.h"
diff --git a/tests/unit/test-qobject-input-visitor.c b/tests/unit/test-qobject-input-visitor.c
index 024e26c..84bdcdf 100644
--- a/tests/unit/test-qobject-input-visitor.c
+++ b/tests/unit/test-qobject-input-visitor.c
@@ -17,12 +17,12 @@
#include "qapi/qapi-visit-introspect.h"
#include "qapi/qobject-input-visitor.h"
#include "test-qapi-visit.h"
-#include "qapi/qmp/qbool.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qnull.h"
-#include "qapi/qmp/qnum.h"
-#include "qapi/qmp/qstring.h"
-#include "qapi/qmp/qjson.h"
+#include "qobject/qbool.h"
+#include "qobject/qdict.h"
+#include "qobject/qnull.h"
+#include "qobject/qnum.h"
+#include "qobject/qstring.h"
+#include "qobject/qjson.h"
#include "test-qapi-introspect.h"
#include "qapi/qapi-introspect.h"
@@ -720,7 +720,7 @@ static void test_visitor_in_union_in_union(TestInputVisitorData *data,
visit_type_TestUnionInUnion(v, NULL, &tmp, &error_abort);
g_assert_cmpint(tmp->type, ==, TEST_UNION_ENUM_VALUE_A);
- g_assert_cmpint(tmp->u.value_a.type_a, ==, TEST_UNION_ENUMA_VALUE_A1);
+ g_assert_cmpint(tmp->u.value_a.type_a, ==, TEST_UNION_ENUM_A_VALUE_A1);
g_assert_cmpint(tmp->u.value_a.u.value_a1.integer, ==, 2);
g_assert_cmpint(strcmp(tmp->u.value_a.u.value_a1.name, "fish"), ==, 0);
@@ -734,7 +734,7 @@ static void test_visitor_in_union_in_union(TestInputVisitorData *data,
visit_type_TestUnionInUnion(v, NULL, &tmp, &error_abort);
g_assert_cmpint(tmp->type, ==, TEST_UNION_ENUM_VALUE_A);
- g_assert_cmpint(tmp->u.value_a.type_a, ==, TEST_UNION_ENUMA_VALUE_A2);
+ g_assert_cmpint(tmp->u.value_a.type_a, ==, TEST_UNION_ENUM_A_VALUE_A2);
g_assert_cmpint(tmp->u.value_a.u.value_a2.integer, ==, 1729);
g_assert_cmpint(tmp->u.value_a.u.value_a2.size, ==, 87539319);
diff --git a/tests/unit/test-qobject-output-visitor.c b/tests/unit/test-qobject-output-visitor.c
index 1535b3a..407ab9e 100644
--- a/tests/unit/test-qobject-output-visitor.c
+++ b/tests/unit/test-qobject-output-visitor.c
@@ -15,12 +15,12 @@
#include "qapi/error.h"
#include "qapi/qobject-output-visitor.h"
#include "test-qapi-visit.h"
-#include "qapi/qmp/qbool.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qnull.h"
-#include "qapi/qmp/qnum.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qbool.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
+#include "qobject/qnull.h"
+#include "qobject/qnum.h"
+#include "qobject/qstring.h"
typedef struct TestOutputVisitorData {
Visitor *ov;
@@ -359,7 +359,7 @@ static void test_visitor_out_union_in_union(TestOutputVisitorData *data,
TestUnionInUnion *tmp = g_new0(TestUnionInUnion, 1);
tmp->type = TEST_UNION_ENUM_VALUE_A;
- tmp->u.value_a.type_a = TEST_UNION_ENUMA_VALUE_A1;
+ tmp->u.value_a.type_a = TEST_UNION_ENUM_A_VALUE_A1;
tmp->u.value_a.u.value_a1.integer = 42;
tmp->u.value_a.u.value_a1.name = g_strdup("fish");
@@ -377,7 +377,7 @@ static void test_visitor_out_union_in_union(TestOutputVisitorData *data,
visitor_reset(data);
tmp = g_new0(TestUnionInUnion, 1);
tmp->type = TEST_UNION_ENUM_VALUE_A;
- tmp->u.value_a.type_a = TEST_UNION_ENUMA_VALUE_A2;
+ tmp->u.value_a.type_a = TEST_UNION_ENUM_A_VALUE_A2;
tmp->u.value_a.u.value_a2.integer = 1729;
tmp->u.value_a.u.value_a2.size = 87539319;
diff --git a/tests/unit/test-replication.c b/tests/unit/test-replication.c
index 5d2003b..3aa98e6 100644
--- a/tests/unit/test-replication.c
+++ b/tests/unit/test-replication.c
@@ -11,13 +11,13 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qemu/option.h"
#include "qemu/main-loop.h"
#include "block/replication.h"
#include "block/block_int.h"
#include "block/qdict.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#define IMG_SIZE (64 * 1024 * 1024)
diff --git a/tests/unit/test-resv-mem.c b/tests/unit/test-resv-mem.c
index cd8f731..4de2d04 100644
--- a/tests/unit/test-resv-mem.c
+++ b/tests/unit/test-resv-mem.c
@@ -10,7 +10,7 @@
#include "qemu/osdep.h"
#include "qemu/range.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "qemu/reserved-region.h"
#define DEBUG 0
diff --git a/tests/unit/test-seccomp.c b/tests/unit/test-seccomp.c
index bab93fd..71d4083 100644
--- a/tests/unit/test-seccomp.c
+++ b/tests/unit/test-seccomp.c
@@ -21,7 +21,7 @@
#include "qemu/osdep.h"
#include "qemu/config-file.h"
#include "qemu/option.h"
-#include "sysemu/seccomp.h"
+#include "system/seccomp.h"
#include "qapi/error.h"
#include "qemu/module.h"
diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c
index f9bccb5..326045e 100644
--- a/tests/unit/test-smp-parse.c
+++ b/tests/unit/test-smp-parse.c
@@ -924,7 +924,7 @@ static void unsupported_params_init(const MachineClass *mc, SMPTestData *data)
}
}
-static void machine_base_class_init(ObjectClass *oc, void *data)
+static void machine_base_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -934,7 +934,8 @@ static void machine_base_class_init(ObjectClass *oc, void *data)
mc->name = g_strdup(SMP_MACHINE_NAME);
}
-static void machine_generic_invalid_class_init(ObjectClass *oc, void *data)
+static void machine_generic_invalid_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -943,21 +944,22 @@ static void machine_generic_invalid_class_init(ObjectClass *oc, void *data)
mc->max_cpus = MAX_CPUS - 1;
}
-static void machine_with_modules_class_init(ObjectClass *oc, void *data)
+static void machine_with_modules_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->smp_props.modules_supported = true;
}
-static void machine_with_dies_class_init(ObjectClass *oc, void *data)
+static void machine_with_dies_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->smp_props.dies_supported = true;
}
-static void machine_with_modules_dies_class_init(ObjectClass *oc, void *data)
+static void machine_with_modules_dies_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -965,28 +967,29 @@ static void machine_with_modules_dies_class_init(ObjectClass *oc, void *data)
mc->smp_props.dies_supported = true;
}
-static void machine_with_clusters_class_init(ObjectClass *oc, void *data)
+static void machine_with_clusters_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->smp_props.clusters_supported = true;
}
-static void machine_with_books_class_init(ObjectClass *oc, void *data)
+static void machine_with_books_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->smp_props.books_supported = true;
}
-static void machine_with_drawers_class_init(ObjectClass *oc, void *data)
+static void machine_with_drawers_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->smp_props.drawers_supported = true;
}
-static void machine_with_drawers_books_class_init(ObjectClass *oc, void *data)
+static void machine_with_drawers_books_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -994,7 +997,7 @@ static void machine_with_drawers_books_class_init(ObjectClass *oc, void *data)
mc->smp_props.books_supported = true;
}
-static void machine_full_topo_class_init(ObjectClass *oc, void *data)
+static void machine_full_topo_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
diff --git a/tests/unit/test-thread-pool.c b/tests/unit/test-thread-pool.c
index 1483e53..33407b5 100644
--- a/tests/unit/test-thread-pool.c
+++ b/tests/unit/test-thread-pool.c
@@ -43,10 +43,10 @@ static void done_cb(void *opaque, int ret)
active--;
}
-static void test_submit(void)
+static void test_submit_no_complete(void)
{
WorkerTestData data = { .n = 0 };
- thread_pool_submit(worker_cb, &data);
+ thread_pool_submit_aio(worker_cb, &data, NULL, NULL);
while (data.n == 0) {
aio_poll(ctx, true);
}
@@ -236,7 +236,7 @@ int main(int argc, char **argv)
ctx = qemu_get_current_aio_context();
g_test_init(&argc, &argv, NULL);
- g_test_add_func("/thread-pool/submit", test_submit);
+ g_test_add_func("/thread-pool/submit-no-complete", test_submit_no_complete);
g_test_add_func("/thread-pool/submit-aio", test_submit_aio);
g_test_add_func("/thread-pool/submit-co", test_submit_co);
g_test_add_func("/thread-pool/submit-many", test_submit_many);
diff --git a/tests/unit/test-throttle.c b/tests/unit/test-throttle.c
index 24032a0..dfa61c7 100644
--- a/tests/unit/test-throttle.c
+++ b/tests/unit/test-throttle.c
@@ -21,7 +21,7 @@
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "block/throttle-groups.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
static AioContext *ctx;
static LeakyBucket bkt;
diff --git a/tests/unit/test-timed-average.c b/tests/unit/test-timed-average.c
index 82c9250..747ed1e 100644
--- a/tests/unit/test-timed-average.c
+++ b/tests/unit/test-timed-average.c
@@ -11,7 +11,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/cpu-timers.h"
+#include "system/cpu-timers.h"
#include "qemu/timed-average.h"
/* This is the clock for QEMU_CLOCK_VIRTUAL */
diff --git a/tests/unit/test-util-sockets.c b/tests/unit/test-util-sockets.c
index 4c9dd0b..ee66d72 100644
--- a/tests/unit/test-util-sockets.c
+++ b/tests/unit/test-util-sockets.c
@@ -332,6 +332,220 @@ static void test_socket_unix_abstract(void)
#endif /* CONFIG_LINUX */
+static void inet_parse_test_helper(const char *str,
+ InetSocketAddress *exp_addr, bool success)
+{
+ InetSocketAddress addr;
+ Error *error = NULL;
+
+ int rc = inet_parse(&addr, str, &error);
+
+ if (success) {
+ if (error) {
+ error_report_err(error);
+ }
+ g_assert_cmpint(rc, ==, 0);
+ } else {
+ error_free(error);
+ g_assert_cmpint(rc, <, 0);
+ }
+ if (exp_addr != NULL) {
+ g_assert_cmpstr(addr.host, ==, exp_addr->host);
+ g_assert_cmpstr(addr.port, ==, exp_addr->port);
+ /* Own members: */
+ g_assert_cmpint(addr.has_numeric, ==, exp_addr->has_numeric);
+ g_assert_cmpint(addr.numeric, ==, exp_addr->numeric);
+ g_assert_cmpint(addr.has_to, ==, exp_addr->has_to);
+ g_assert_cmpint(addr.to, ==, exp_addr->to);
+ g_assert_cmpint(addr.has_ipv4, ==, exp_addr->has_ipv4);
+ g_assert_cmpint(addr.ipv4, ==, exp_addr->ipv4);
+ g_assert_cmpint(addr.has_ipv6, ==, exp_addr->has_ipv6);
+ g_assert_cmpint(addr.ipv6, ==, exp_addr->ipv6);
+ g_assert_cmpint(addr.has_keep_alive, ==, exp_addr->has_keep_alive);
+ g_assert_cmpint(addr.keep_alive, ==, exp_addr->keep_alive);
+#ifdef HAVE_TCP_KEEPCNT
+ g_assert_cmpint(addr.has_keep_alive_count, ==,
+ exp_addr->has_keep_alive_count);
+ g_assert_cmpint(addr.keep_alive_count, ==,
+ exp_addr->keep_alive_count);
+#endif
+#ifdef HAVE_TCP_KEEPIDLE
+ g_assert_cmpint(addr.has_keep_alive_idle, ==,
+ exp_addr->has_keep_alive_idle);
+ g_assert_cmpint(addr.keep_alive_idle, ==,
+ exp_addr->keep_alive_idle);
+#endif
+#ifdef HAVE_TCP_KEEPINTVL
+ g_assert_cmpint(addr.has_keep_alive_interval, ==,
+ exp_addr->has_keep_alive_interval);
+ g_assert_cmpint(addr.keep_alive_interval, ==,
+ exp_addr->keep_alive_interval);
+#endif
+#ifdef HAVE_IPPROTO_MPTCP
+ g_assert_cmpint(addr.has_mptcp, ==, exp_addr->has_mptcp);
+ g_assert_cmpint(addr.mptcp, ==, exp_addr->mptcp);
+#endif
+ }
+
+ g_free(addr.host);
+ g_free(addr.port);
+}
+
+static void test_inet_parse_nohost_good(void)
+{
+ char host[] = "";
+ char port[] = "5000";
+ InetSocketAddress exp_addr = {
+ .host = host,
+ .port = port,
+ };
+ inet_parse_test_helper(":5000", &exp_addr, true);
+}
+
+static void test_inet_parse_empty_bad(void)
+{
+ inet_parse_test_helper("", NULL, false);
+}
+
+static void test_inet_parse_only_colon_bad(void)
+{
+ inet_parse_test_helper(":", NULL, false);
+}
+
+static void test_inet_parse_ipv4_good(void)
+{
+ char host[] = "127.0.0.1";
+ char port[] = "5000";
+ InetSocketAddress exp_addr = {
+ .host = host,
+ .port = port,
+ };
+ inet_parse_test_helper("127.0.0.1:5000", &exp_addr, true);
+}
+
+static void test_inet_parse_ipv4_noport_bad(void)
+{
+ inet_parse_test_helper("127.0.0.1", NULL, false);
+}
+
+static void test_inet_parse_ipv6_good(void)
+{
+ char host[] = "::1";
+ char port[] = "5000";
+ InetSocketAddress exp_addr = {
+ .host = host,
+ .port = port,
+ };
+ inet_parse_test_helper("[::1]:5000", &exp_addr, true);
+}
+
+static void test_inet_parse_ipv6_noend_bad(void)
+{
+ inet_parse_test_helper("[::1", NULL, false);
+}
+
+static void test_inet_parse_ipv6_noport_bad(void)
+{
+ inet_parse_test_helper("[::1]:", NULL, false);
+}
+
+static void test_inet_parse_ipv6_empty_bad(void)
+{
+ inet_parse_test_helper("[]:5000", NULL, false);
+}
+
+static void test_inet_parse_hostname_good(void)
+{
+ char host[] = "localhost";
+ char port[] = "5000";
+ InetSocketAddress exp_addr = {
+ .host = host,
+ .port = port,
+ };
+ inet_parse_test_helper("localhost:5000", &exp_addr, true);
+}
+
+static void test_inet_parse_all_options_good(void)
+{
+ char host[] = "::1";
+ char port[] = "5000";
+ InetSocketAddress exp_addr = {
+ .host = host,
+ .port = port,
+ .has_numeric = true,
+ .numeric = true,
+ .has_to = true,
+ .to = 5006,
+ .has_ipv4 = true,
+ .ipv4 = false,
+ .has_ipv6 = true,
+ .ipv6 = true,
+ .has_keep_alive = true,
+ .keep_alive = true,
+#ifdef HAVE_TCP_KEEPCNT
+ .has_keep_alive_count = true,
+ .keep_alive_count = 10,
+#endif
+#ifdef HAVE_TCP_KEEPIDLE
+ .has_keep_alive_idle = true,
+ .keep_alive_idle = 60,
+#endif
+#ifdef HAVE_TCP_KEEPINTVL
+ .has_keep_alive_interval = true,
+ .keep_alive_interval = 30,
+#endif
+#ifdef HAVE_IPPROTO_MPTCP
+ .has_mptcp = true,
+ .mptcp = false,
+#endif
+ };
+ inet_parse_test_helper(
+ "[::1]:5000,numeric=on,to=5006,ipv4=off,ipv6=on,keep-alive=on"
+#ifdef HAVE_TCP_KEEPCNT
+ ",keep-alive-count=10"
+#endif
+#ifdef HAVE_TCP_KEEPIDLE
+ ",keep-alive-idle=60"
+#endif
+#ifdef HAVE_TCP_KEEPINTVL
+ ",keep-alive-interval=30"
+#endif
+#ifdef HAVE_IPPROTO_MPTCP
+ ",mptcp=off"
+#endif
+ , &exp_addr, true);
+}
+
+static void test_inet_parse_all_implicit_bool_good(void)
+{
+ char host[] = "::1";
+ char port[] = "5000";
+ InetSocketAddress exp_addr = {
+ .host = host,
+ .port = port,
+ .has_numeric = true,
+ .numeric = true,
+ .has_to = true,
+ .to = 5006,
+ .has_ipv4 = true,
+ .ipv4 = true,
+ .has_ipv6 = true,
+ .ipv6 = true,
+ .has_keep_alive = true,
+ .keep_alive = true,
+#ifdef HAVE_IPPROTO_MPTCP
+ .has_mptcp = true,
+ .mptcp = true,
+#endif
+ };
+ inet_parse_test_helper(
+ "[::1]:5000,numeric,to=5006,ipv4,ipv6,keep-alive"
+#ifdef HAVE_IPPROTO_MPTCP
+ ",mptcp"
+#endif
+ , &exp_addr, true);
+}
+
int main(int argc, char **argv)
{
bool has_ipv4, has_ipv6;
@@ -377,6 +591,31 @@ int main(int argc, char **argv)
test_socket_unix_abstract);
#endif
+ g_test_add_func("/util/socket/inet-parse/nohost-good",
+ test_inet_parse_nohost_good);
+ g_test_add_func("/util/socket/inet-parse/empty-bad",
+ test_inet_parse_empty_bad);
+ g_test_add_func("/util/socket/inet-parse/only-colon-bad",
+ test_inet_parse_only_colon_bad);
+ g_test_add_func("/util/socket/inet-parse/ipv4-good",
+ test_inet_parse_ipv4_good);
+ g_test_add_func("/util/socket/inet-parse/ipv4-noport-bad",
+ test_inet_parse_ipv4_noport_bad);
+ g_test_add_func("/util/socket/inet-parse/ipv6-good",
+ test_inet_parse_ipv6_good);
+ g_test_add_func("/util/socket/inet-parse/ipv6-noend-bad",
+ test_inet_parse_ipv6_noend_bad);
+ g_test_add_func("/util/socket/inet-parse/ipv6-noport-bad",
+ test_inet_parse_ipv6_noport_bad);
+ g_test_add_func("/util/socket/inet-parse/ipv6-empty-bad",
+ test_inet_parse_ipv6_empty_bad);
+ g_test_add_func("/util/socket/inet-parse/hostname-good",
+ test_inet_parse_hostname_good);
+ g_test_add_func("/util/socket/inet-parse/all-options-good",
+ test_inet_parse_all_options_good);
+ g_test_add_func("/util/socket/inet-parse/all-bare-bool-good",
+ test_inet_parse_all_implicit_bool_good);
+
end:
return g_test_run();
}
diff --git a/tests/unit/test-visitor-serialization.c b/tests/unit/test-visitor-serialization.c
index c2056c3..2d36599 100644
--- a/tests/unit/test-visitor-serialization.c
+++ b/tests/unit/test-visitor-serialization.c
@@ -16,8 +16,8 @@
#include "test-qapi-visit.h"
#include "qapi/error.h"
-#include "qapi/qmp/qjson.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qjson.h"
+#include "qobject/qstring.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qobject-output-visitor.h"
#include "qapi/string-input-visitor.h"
diff --git a/tests/unit/test-xs-node.c b/tests/unit/test-xs-node.c
index ac94e7e..2f447a7 100644
--- a/tests/unit/test-xs-node.c
+++ b/tests/unit/test-xs-node.c
@@ -212,7 +212,7 @@ static void compare_tx(gpointer key, gpointer val, gpointer opaque)
printf("Comparison failure in TX %u after serdes:\n", tx_id);
dump_ref("Original", t1->root, 0);
dump_ref("Deserialised", t2->root, 0);
- g_assert(0);
+ g_assert_not_reached();
}
g_assert(t1->nr_nodes == t2->nr_nodes);
}
@@ -257,7 +257,7 @@ static void check_serdes(XenstoreImplState *s)
printf("Comparison failure in main tree after serdes:\n");
dump_ref("Original", s->root, 0);
dump_ref("Deserialised", s2->root, 0);
- g_assert(0);
+ g_assert_not_reached();
}
nr_transactions1 = g_hash_table_size(s->transactions);
diff --git a/tests/unit/test-yank.c b/tests/unit/test-yank.c
index e6c036a..4acfb2f 100644
--- a/tests/unit/test-yank.c
+++ b/tests/unit/test-yank.c
@@ -14,7 +14,7 @@
#include "qemu/module.h"
#include "qemu/option.h"
#include "chardev/char-fe.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-char.h"
#include "qapi/qapi-types-char.h"
diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include
index 13ed80f..14188bb 100644
--- a/tests/vm/Makefile.include
+++ b/tests/vm/Makefile.include
@@ -64,23 +64,24 @@ endif
@echo " vm-boot-ssh-<guest> - Boot guest and login via ssh"
@echo
@echo "Special variables:"
- @echo " BUILD_TARGET=foo - Override the build target"
- @echo " DEBUG=1 - Enable verbose output on host and interactive debugging"
- @echo ' EXTRA_CONFIGURE_OPTS="..." - Pass to configure step'
- @echo " J=[0..9]* - Override the -jN parameter for make commands"
- @echo " LOG_CONSOLE=1 - Log console to file in: ~/.cache/qemu-vm "
- @echo " USE_TCG=1 - Use TCG for cross-arch images"
- @echo " QEMU=/path/to/qemu - Change path to QEMU binary"
+ @echo " BUILD_TARGET=foo - Override the build target"
+ @echo " DEBUG=1 - Enable verbose output on host and interactive debugging"
+ @echo " ROOT_USER=1 - Login as root user for interactive shell"
+ @echo ' EXTRA_CONFIGURE_OPTS="..." - Pass to configure step'
+ @echo " J=[0..9]* - Override the -jN parameter for make commands"
+ @echo " LOG_CONSOLE=1 - Log console to file in: ~/.cache/qemu-vm "
+ @echo " USE_TCG=1 - Use TCG for cross-arch images"
+ @echo " QEMU=/path/to/qemu - Change path to QEMU binary"
ifeq ($(HAVE_PYTHON_YAML),yes)
- @echo " QEMU_CONFIG=/path/conf.yml - Change path to VM configuration .yml file."
+ @echo " QEMU_CONFIG=/path/conf.yml - Change path to VM configuration .yml file."
else
@echo " (install python3-yaml to enable support for yaml file to configure a VM.)"
endif
- @echo " See conf_example_*.yml for file format details."
- @echo " QEMU_IMG=/path/to/qemu-img - Change path to qemu-img tool"
- @echo " QEMU_LOCAL=1 - Use QEMU binary local to this build."
- @echo " TARGET_LIST=a,b,c - Override target list in builds"
- @echo " V=1 - Enable verbose output on host and guest commands"
+ @echo " See conf_example_*.yml for file format details."
+ @echo " QEMU_IMG=/path/to/qemu-img - Change path to qemu-img tool"
+ @echo " QEMU_LOCAL=1 - Use QEMU binary local to this build."
+ @echo " TARGET_LIST=a,b,c - Override target list in builds"
+ @echo " V=1 - Enable verbose output on host and guest commands"
vm-build-all: $(addprefix vm-build-, $(IMAGES))
@@ -141,6 +142,6 @@ vm-boot-ssh-%: $(IMAGES_DIR)/%.img $(VM_VENV)
$(if $(EFI_AARCH64),--efi-aarch64 $(EFI_AARCH64)) \
$(if $(LOG_CONSOLE),--log-console) \
--image "$<" \
- --interactive \
+ $(if $(ROOT_USER),--interactive-root,-interactive) \
false, \
" VM-BOOT-SSH $*") || true
diff --git a/tests/vm/README b/tests/vm/README
index f9c04cc..14ac323 100644
--- a/tests/vm/README
+++ b/tests/vm/README
@@ -1 +1 @@
-See docs/devel/testing.rst for help.
+See docs/devel/testing/main.rst for help.
diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py
index 4a1af04..9e879e9 100644
--- a/tests/vm/basevm.py
+++ b/tests/vm/basevm.py
@@ -83,7 +83,7 @@ class BaseVM(object):
# command to halt the guest, can be overridden by subclasses
poweroff = "poweroff"
# Time to wait for shutdown to finish.
- shutdown_timeout_default = 30
+ shutdown_timeout_default = 90
# enable IPv6 networking
ipv6 = True
# This is the timeout on the wait for console bytes.
@@ -520,8 +520,7 @@ def get_qemu_path(arch, build_path=None):
if "QEMU" in os.environ:
qemu_path = os.environ["QEMU"]
elif build_path:
- qemu_path = os.path.join(build_path, arch + "-softmmu")
- qemu_path = os.path.join(qemu_path, "qemu-system-" + arch)
+ qemu_path = os.path.join(build_path, "qemu-system-" + arch)
else:
# Default is to use system path for qemu.
qemu_path = "qemu-system-" + arch
@@ -613,8 +612,11 @@ def parse_args(vmcls):
parser.add_argument("--source-path", default=None,
help="Path of source directory, "\
"for finding additional files. ")
- parser.add_argument("--interactive", "-I", action="store_true",
- help="Interactively run command")
+ int_ops = parser.add_mutually_exclusive_group()
+ int_ops.add_argument("--interactive", "-I", action="store_true",
+ help="Interactively run command")
+ int_ops.add_argument("--interactive-root", action="store_true",
+ help="Interactively run command as root")
parser.add_argument("--snapshot", "-s", action="store_true",
help="run tests with a snapshot")
parser.add_argument("--genisoimage", default="genisoimage",
@@ -676,6 +678,8 @@ def main(vmcls, config=None):
exitcode = 3
if args.interactive:
vm.ssh()
+ elif args.interactive_root:
+ vm.ssh_root()
if not args.snapshot:
vm.graceful_shutdown()
diff --git a/tests/vm/freebsd b/tests/vm/freebsd
index 1247f40..74b3b1e 100755
--- a/tests/vm/freebsd
+++ b/tests/vm/freebsd
@@ -28,8 +28,8 @@ class FreeBSDVM(basevm.BaseVM):
name = "freebsd"
arch = "x86_64"
- link = "https://download.freebsd.org/releases/CI-IMAGES/13.2-RELEASE/amd64/Latest/FreeBSD-13.2-RELEASE-amd64-BASIC-CI.raw.xz"
- csum = "a4fb3b6c7b75dd4d58fb0d75e4caf72844bffe0ca00e66459c028b198ffb3c0e"
+ link = "https://download.freebsd.org/releases/CI-IMAGES/14.1-RELEASE/amd64/Latest/FreeBSD-14.1-RELEASE-amd64-BASIC-CI.raw.xz"
+ csum = "202fe27a05427f0a86d3ebb97712745186f2776ccc4f70d95466dd99a0238ba5"
size = "20G"
BUILD_SCRIPT = """
@@ -39,7 +39,7 @@ class FreeBSDVM(basevm.BaseVM):
mkdir src build; cd src;
tar -xf /dev/vtbd1;
cd ../build;
- ../src/configure --python=python3.9 --extra-ldflags=-L/usr/local/lib \
+ ../src/configure --extra-ldflags=-L/usr/local/lib \
--extra-cflags=-I/usr/local/include {configure_opts};
gmake --output-sync -j{jobs} {target} {verbose};
"""
diff --git a/tests/vm/generated/freebsd.json b/tests/vm/generated/freebsd.json
index d5f0b62..c03e1cd 100644
--- a/tests/vm/generated/freebsd.json
+++ b/tests/vm/generated/freebsd.json
@@ -5,7 +5,7 @@
"make": "/usr/local/bin/gmake",
"ninja": "/usr/local/bin/ninja",
"packaging_command": "pkg",
- "pip3": "/usr/local/bin/pip-3.8",
+ "pip3": "/usr/local/bin/pip",
"pkgs": [
"alsa-lib",
"bash",
@@ -13,7 +13,7 @@
"bzip2",
"ca_root_nss",
"capstone4",
- "ccache",
+ "ccache4",
"cmocka",
"ctags",
"curl",
@@ -55,12 +55,14 @@
"py311-numpy",
"py311-pillow",
"py311-pip",
+ "py311-pyyaml",
"py311-sphinx",
"py311-sphinx_rtd_theme",
"py311-tomli",
- "py311-yaml",
"python3",
"rpm2cpio",
+ "rust",
+ "rust-bindgen-cli",
"sdl2",
"sdl2_image",
"snappy",
@@ -71,6 +73,7 @@
"usbredir",
"virglrenderer",
"vte3",
+ "vulkan-tools",
"xorriso",
"zstd"
],
diff --git a/tests/vm/openbsd b/tests/vm/openbsd
index 49cab08..2ea86a0 100755
--- a/tests/vm/openbsd
+++ b/tests/vm/openbsd
@@ -22,8 +22,8 @@ class OpenBSDVM(basevm.BaseVM):
name = "openbsd"
arch = "x86_64"
- link = "https://cdn.openbsd.org/pub/OpenBSD/7.5/amd64/install75.iso"
- csum = "034435c6e27405d5a7fafb058162943c194eb793dafdc412c08d49bb56b3892a"
+ link = "https://cdn.openbsd.org/pub/OpenBSD/7.7/amd64/install77.iso"
+ csum = "da0106e39463f015524dca806f407c37a9bdd17e6dfffe533b06a2dd2edd8a27"
size = "20G"
pkgs = [
# tools
@@ -32,7 +32,6 @@ class OpenBSDVM(basevm.BaseVM):
"pkgconf",
"bzip2", "xz",
"ninja",
- "py3-tomli",
# gnu tools
"bash",