diff options
Diffstat (limited to 'tests/functional')
-rw-r--r-- | tests/functional/aarch64/meson.build | 49 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_aspeed_ast2700.py (renamed from tests/functional/test_aarch64_aspeed.py) | 102 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_aspeed_ast2700fc.py | 148 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_device_passthrough.py | 143 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_hotplug_pci.py | 72 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_imx8mp_evk.py | 68 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_kvm.py | 71 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_migration.py | 26 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_multiprocess.py | 31 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_raspi3.py (renamed from tests/functional/test_aarch64_raspi3.py) | 0 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_raspi4.py (renamed from tests/functional/test_aarch64_raspi4.py) | 0 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_replay.py | 51 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_reverse_debug.py | 36 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_rme_sbsaref.py | 77 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_rme_virt.py | 76 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_sbsaref.py (renamed from tests/functional/test_aarch64_sbsaref.py) | 5 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_sbsaref_alpine.py (renamed from tests/functional/test_aarch64_sbsaref_alpine.py) | 8 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_sbsaref_freebsd.py (renamed from tests/functional/test_aarch64_sbsaref_freebsd.py) | 15 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_smmu.py | 211 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_tcg_plugins.py (renamed from tests/functional/test_aarch64_tcg_plugins.py) | 1 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_tuxrun.py (renamed from tests/functional/test_aarch64_tuxrun.py) | 0 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_virt.py (renamed from tests/functional/test_aarch64_virt.py) | 12 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_virt_gpu.py (renamed from tests/functional/test_aarch64_virt_gpu.py) | 2 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_xen.py (renamed from tests/functional/test_aarch64_xen.py) | 1 | ||||
-rwxr-xr-x | tests/functional/aarch64/test_xlnx_versal.py (renamed from tests/functional/test_aarch64_xlnx_versal.py) | 12 | ||||
-rw-r--r-- | tests/functional/alpha/meson.build | 10 | ||||
-rwxr-xr-x | tests/functional/alpha/test_clipper.py (renamed from tests/functional/test_alpha_clipper.py) | 0 | ||||
-rwxr-xr-x | tests/functional/alpha/test_migration.py | 26 | ||||
-rwxr-xr-x | tests/functional/alpha/test_replay.py (renamed from tests/functional/test_alpha_replay.py) | 0 | ||||
-rw-r--r-- | tests/functional/arm/meson.build | 64 | ||||
-rwxr-xr-x | tests/functional/arm/test_aspeed_ast1030.py (renamed from tests/functional/test_arm_aspeed_ast1030.py) | 33 | ||||
-rwxr-xr-x | tests/functional/arm/test_aspeed_ast2500.py (renamed from tests/functional/test_arm_aspeed_ast2500.py) | 17 | ||||
-rwxr-xr-x | tests/functional/arm/test_aspeed_ast2600_buildroot.py (renamed from tests/functional/test_arm_aspeed_ast2600.py) | 61 | ||||
-rwxr-xr-x | tests/functional/arm/test_aspeed_ast2600_sdk.py | 94 | ||||
-rwxr-xr-x[-rw-r--r--] | tests/functional/arm/test_aspeed_bletchley.py (renamed from tests/functional/test_arm_aspeed_bletchley.py) | 4 | ||||
-rwxr-xr-x | tests/functional/arm/test_aspeed_catalina.py | 25 | ||||
-rwxr-xr-x | tests/functional/arm/test_aspeed_gb200nvl_bmc.py | 26 | ||||
-rwxr-xr-x | tests/functional/arm/test_aspeed_palmetto.py (renamed from tests/functional/test_arm_aspeed_palmetto.py) | 4 | ||||
-rwxr-xr-x | tests/functional/arm/test_aspeed_rainier.py (renamed from tests/functional/test_arm_aspeed_rainier.py) | 0 | ||||
-rwxr-xr-x | tests/functional/arm/test_aspeed_romulus.py (renamed from tests/functional/test_arm_aspeed_romulus.py) | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | tests/functional/arm/test_aspeed_witherspoon.py (renamed from tests/functional/test_arm_aspeed_witherspoon.py) | 4 | ||||
-rwxr-xr-x | tests/functional/arm/test_bflt.py (renamed from tests/functional/test_arm_bflt.py) | 0 | ||||
-rwxr-xr-x | tests/functional/arm/test_bpim2u.py (renamed from tests/functional/test_arm_bpim2u.py) | 2 | ||||
-rwxr-xr-x | tests/functional/arm/test_canona1100.py (renamed from tests/functional/test_arm_canona1100.py) | 0 | ||||
-rwxr-xr-x | tests/functional/arm/test_collie.py (renamed from tests/functional/test_arm_collie.py) | 0 | ||||
-rwxr-xr-x | tests/functional/arm/test_cubieboard.py (renamed from tests/functional/test_arm_cubieboard.py) | 4 | ||||
-rwxr-xr-x | tests/functional/arm/test_emcraft_sf2.py (renamed from tests/functional/test_arm_emcraft_sf2.py) | 0 | ||||
-rwxr-xr-x | tests/functional/arm/test_integratorcp.py (renamed from tests/functional/test_arm_integratorcp.py) | 9 | ||||
-rwxr-xr-x | tests/functional/arm/test_max78000fthr.py | 48 | ||||
-rwxr-xr-x | tests/functional/arm/test_microbit.py (renamed from tests/functional/test_arm_microbit.py) | 0 | ||||
-rwxr-xr-x | tests/functional/arm/test_migration.py | 26 | ||||
-rwxr-xr-x | tests/functional/arm/test_orangepi.py (renamed from tests/functional/test_arm_orangepi.py) | 2 | ||||
-rwxr-xr-x | tests/functional/arm/test_quanta_gsj.py (renamed from tests/functional/test_arm_quanta_gsj.py) | 2 | ||||
-rwxr-xr-x | tests/functional/arm/test_raspi2.py (renamed from tests/functional/test_arm_raspi2.py) | 0 | ||||
-rwxr-xr-x | tests/functional/arm/test_realview.py | 47 | ||||
-rwxr-xr-x | tests/functional/arm/test_replay.py (renamed from tests/functional/test_arm_replay.py) | 0 | ||||
-rwxr-xr-x | tests/functional/arm/test_smdkc210.py (renamed from tests/functional/test_arm_smdkc210.py) | 2 | ||||
-rwxr-xr-x | tests/functional/arm/test_stellaris.py | 48 | ||||
-rwxr-xr-x | tests/functional/arm/test_sx1.py (renamed from tests/functional/test_arm_sx1.py) | 0 | ||||
-rwxr-xr-x | tests/functional/arm/test_tuxrun.py (renamed from tests/functional/test_arm_tuxrun.py) | 0 | ||||
-rwxr-xr-x | tests/functional/arm/test_vexpress.py (renamed from tests/functional/test_arm_vexpress.py) | 0 | ||||
-rwxr-xr-x | tests/functional/arm/test_virt.py (renamed from tests/functional/test_arm_virt.py) | 0 | ||||
-rw-r--r-- | tests/functional/aspeed.py | 19 | ||||
-rw-r--r-- | tests/functional/avr/meson.build | 6 | ||||
-rwxr-xr-x | tests/functional/avr/test_mega2560.py (renamed from tests/functional/test_avr_mega2560.py) | 11 | ||||
-rwxr-xr-x | tests/functional/avr/test_uno.py | 32 | ||||
-rw-r--r-- | tests/functional/generic/meson.build | 14 | ||||
-rwxr-xr-x | tests/functional/generic/test_empty_cpu_model.py (renamed from tests/functional/test_empty_cpu_model.py) | 0 | ||||
-rwxr-xr-x | tests/functional/generic/test_info_usernet.py (renamed from tests/functional/test_info_usernet.py) | 0 | ||||
-rwxr-xr-x | tests/functional/generic/test_version.py (renamed from tests/functional/test_version.py) | 0 | ||||
-rwxr-xr-x | tests/functional/generic/test_vmstate.py | 67 | ||||
-rwxr-xr-x | tests/functional/generic/test_vnc.py (renamed from tests/functional/test_vnc.py) | 10 | ||||
-rw-r--r-- | tests/functional/hppa/meson.build | 9 | ||||
-rwxr-xr-x | tests/functional/hppa/test_cdboot.py | 38 | ||||
-rwxr-xr-x | tests/functional/hppa/test_seabios.py (renamed from tests/functional/test_hppa_seabios.py) | 2 | ||||
-rw-r--r-- | tests/functional/i386/meson.build | 10 | ||||
-rwxr-xr-x | tests/functional/i386/test_migration.py | 26 | ||||
-rwxr-xr-x | tests/functional/i386/test_replay.py | 28 | ||||
-rwxr-xr-x | tests/functional/i386/test_tuxrun.py (renamed from tests/functional/test_i386_tuxrun.py) | 0 | ||||
-rw-r--r-- | tests/functional/loongarch64/meson.build | 5 | ||||
-rwxr-xr-x | tests/functional/loongarch64/test_virt.py (renamed from tests/functional/test_loongarch64_virt.py) | 0 | ||||
-rw-r--r-- | tests/functional/m68k/meson.build | 13 | ||||
-rwxr-xr-x | tests/functional/m68k/test_mcf5208evb.py (renamed from tests/functional/test_m68k_mcf5208evb.py) | 0 | ||||
-rwxr-xr-x | tests/functional/m68k/test_nextcube.py (renamed from tests/functional/test_m68k_nextcube.py) | 26 | ||||
-rwxr-xr-x | tests/functional/m68k/test_q800.py (renamed from tests/functional/test_m68k_q800.py) | 3 | ||||
-rwxr-xr-x | tests/functional/m68k/test_replay.py (renamed from tests/functional/test_m68k_replay.py) | 3 | ||||
-rwxr-xr-x | tests/functional/m68k/test_tuxrun.py (renamed from tests/functional/test_m68k_tuxrun.py) | 0 | ||||
-rw-r--r-- | tests/functional/meson.build | 362 | ||||
-rw-r--r-- | tests/functional/microblaze/meson.build | 6 | ||||
-rwxr-xr-x | tests/functional/microblaze/test_replay.py (renamed from tests/functional/test_microblaze_replay.py) | 0 | ||||
-rwxr-xr-x | tests/functional/microblaze/test_s3adsp1800.py (renamed from tests/functional/test_microblaze_s3adsp1800.py) | 18 | ||||
-rw-r--r-- | tests/functional/microblazeel/meson.build | 5 | ||||
-rwxr-xr-x | tests/functional/microblazeel/test_s3adsp1800.py (renamed from tests/functional/test_microblazeel_s3adsp1800.py) | 8 | ||||
-rw-r--r--[-rwxr-xr-x] | tests/functional/migration.py (renamed from tests/functional/test_migration.py) | 38 | ||||
-rw-r--r-- | tests/functional/mips/meson.build | 11 | ||||
-rwxr-xr-x | tests/functional/mips/test_malta.py | 196 | ||||
-rwxr-xr-x | tests/functional/mips/test_replay.py (renamed from tests/functional/test_mips_replay.py) | 2 | ||||
-rwxr-xr-x | tests/functional/mips/test_tuxrun.py (renamed from tests/functional/test_mips_tuxrun.py) | 0 | ||||
-rw-r--r-- | tests/functional/mips64/meson.build | 10 | ||||
-rwxr-xr-x | tests/functional/mips64/test_malta.py | 35 | ||||
-rwxr-xr-x | tests/functional/mips64/test_tuxrun.py (renamed from tests/functional/test_mips64_tuxrun.py) | 0 | ||||
-rw-r--r-- | tests/functional/mips64el/meson.build | 14 | ||||
-rwxr-xr-x | tests/functional/mips64el/test_fuloong2e.py (renamed from tests/functional/test_mips64el_fuloong2e.py) | 0 | ||||
-rwxr-xr-x | tests/functional/mips64el/test_loongson3v.py (renamed from tests/functional/test_mips64el_loongson3v.py) | 0 | ||||
-rwxr-xr-x | tests/functional/mips64el/test_malta.py (renamed from tests/functional/test_mips64el_malta.py) | 33 | ||||
-rwxr-xr-x | tests/functional/mips64el/test_replay.py (renamed from tests/functional/test_mips64el_replay.py) | 6 | ||||
-rwxr-xr-x | tests/functional/mips64el/test_tuxrun.py (renamed from tests/functional/test_mips64el_tuxrun.py) | 0 | ||||
-rw-r--r-- | tests/functional/mipsel/meson.build | 12 | ||||
-rwxr-xr-x | tests/functional/mipsel/test_malta.py (renamed from tests/functional/test_mipsel_malta.py) | 22 | ||||
-rwxr-xr-x[-rw-r--r--] | tests/functional/mipsel/test_replay.py (renamed from tests/functional/test_mipsel_replay.py) | 2 | ||||
-rwxr-xr-x | tests/functional/mipsel/test_tuxrun.py (renamed from tests/functional/test_mipsel_tuxrun.py) | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | tests/functional/multiprocess.py (renamed from tests/functional/test_multiprocess.py) | 41 | ||||
-rw-r--r-- | tests/functional/or1k/meson.build | 6 | ||||
-rwxr-xr-x | tests/functional/or1k/test_replay.py (renamed from tests/functional/test_or1k_replay.py) | 0 | ||||
-rwxr-xr-x | tests/functional/or1k/test_sim.py (renamed from tests/functional/test_or1k_sim.py) | 0 | ||||
-rw-r--r-- | tests/functional/ppc/meson.build | 23 | ||||
-rwxr-xr-x | tests/functional/ppc/test_40p.py (renamed from tests/functional/test_ppc_40p.py) | 0 | ||||
-rwxr-xr-x | tests/functional/ppc/test_74xx.py (renamed from tests/functional/test_ppc_74xx.py) | 0 | ||||
-rwxr-xr-x | tests/functional/ppc/test_amiga.py (renamed from tests/functional/test_ppc_amiga.py) | 0 | ||||
-rwxr-xr-x | tests/functional/ppc/test_bamboo.py | 48 | ||||
-rwxr-xr-x | tests/functional/ppc/test_mac.py (renamed from tests/functional/test_ppc_mac.py) | 0 | ||||
-rwxr-xr-x | tests/functional/ppc/test_migration.py | 26 | ||||
-rwxr-xr-x | tests/functional/ppc/test_mpc8544ds.py (renamed from tests/functional/test_ppc_mpc8544ds.py) | 0 | ||||
-rw-r--r-- | tests/functional/ppc/test_ppe42.py | 79 | ||||
-rwxr-xr-x | tests/functional/ppc/test_replay.py (renamed from tests/functional/test_ppc_replay.py) | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tests/functional/ppc/test_sam460ex.py (renamed from tests/functional/test_ppc_sam460ex.py) | 0 | ||||
-rwxr-xr-x | tests/functional/ppc/test_tuxrun.py (renamed from tests/functional/test_ppc_tuxrun.py) | 0 | ||||
-rwxr-xr-x | tests/functional/ppc/test_virtex_ml507.py (renamed from tests/functional/test_ppc_virtex_ml507.py) | 0 | ||||
-rw-r--r-- | tests/functional/ppc64/meson.build | 26 | ||||
-rwxr-xr-x | tests/functional/ppc64/test_e500.py (renamed from tests/functional/test_ppc64_e500.py) | 0 | ||||
-rwxr-xr-x | tests/functional/ppc64/test_hv.py (renamed from tests/functional/test_ppc64_hv.py) | 8 | ||||
-rwxr-xr-x | tests/functional/ppc64/test_mac99.py (renamed from tests/functional/test_ppc64_mac99.py) | 0 | ||||
-rwxr-xr-x | tests/functional/ppc64/test_migration.py | 26 | ||||
-rwxr-xr-x | tests/functional/ppc64/test_powernv.py (renamed from tests/functional/test_ppc64_powernv.py) | 34 | ||||
-rwxr-xr-x | tests/functional/ppc64/test_pseries.py (renamed from tests/functional/test_ppc64_pseries.py) | 1 | ||||
-rwxr-xr-x | tests/functional/ppc64/test_replay.py (renamed from tests/functional/test_ppc64_replay.py) | 0 | ||||
-rwxr-xr-x | tests/functional/ppc64/test_reverse_debug.py | 38 | ||||
-rwxr-xr-x | tests/functional/ppc64/test_tuxrun.py (renamed from tests/functional/test_ppc64_tuxrun.py) | 0 | ||||
-rw-r--r-- | tests/functional/qemu_test/__init__.py | 4 | ||||
-rw-r--r-- | tests/functional/qemu_test/asset.py | 25 | ||||
-rw-r--r-- | tests/functional/qemu_test/cmd.py | 67 | ||||
-rw-r--r-- | tests/functional/qemu_test/decorators.py | 51 | ||||
-rw-r--r-- | tests/functional/qemu_test/gdb.py | 86 | ||||
-rw-r--r-- | tests/functional/qemu_test/ports.py | 8 | ||||
-rw-r--r-- | tests/functional/qemu_test/testcase.py | 29 | ||||
-rw-r--r-- | tests/functional/qemu_test/tuxruntest.py | 11 | ||||
-rw-r--r-- | tests/functional/qemu_test/uncompress.py | 2 | ||||
-rw-r--r-- | tests/functional/replay_kernel.py | 16 | ||||
-rw-r--r-- | tests/functional/reverse_debugging.py | 202 | ||||
-rw-r--r-- | tests/functional/riscv32/meson.build | 10 | ||||
-rwxr-xr-x | tests/functional/riscv32/test_migration.py | 26 | ||||
-rwxr-xr-x | tests/functional/riscv32/test_opensbi.py | 10 | ||||
-rwxr-xr-x | tests/functional/riscv32/test_tuxrun.py (renamed from tests/functional/test_riscv32_tuxrun.py) | 0 | ||||
-rw-r--r-- | tests/functional/riscv64/meson.build | 15 | ||||
-rwxr-xr-x | tests/functional/riscv64/test_migration.py | 26 | ||||
-rwxr-xr-x | tests/functional/riscv64/test_opensbi.py (renamed from tests/functional/test_riscv_opensbi.py) | 0 | ||||
-rwxr-xr-x | tests/functional/riscv64/test_sifive_u.py | 63 | ||||
-rwxr-xr-x | tests/functional/riscv64/test_tuxrun.py (renamed from tests/functional/test_riscv64_tuxrun.py) | 0 | ||||
-rw-r--r-- | tests/functional/rx/meson.build | 5 | ||||
-rwxr-xr-x | tests/functional/rx/test_gdbsim.py (renamed from tests/functional/test_rx_gdbsim.py) | 0 | ||||
-rw-r--r-- | tests/functional/s390x/meson.build | 17 | ||||
-rwxr-xr-x | tests/functional/s390x/test_ccw_virtio.py (renamed from tests/functional/test_s390x_ccw_virtio.py) | 0 | ||||
-rwxr-xr-x | tests/functional/s390x/test_pxelinux.py | 130 | ||||
-rwxr-xr-x | tests/functional/s390x/test_replay.py (renamed from tests/functional/test_s390x_replay.py) | 0 | ||||
-rwxr-xr-x | tests/functional/s390x/test_topology.py (renamed from tests/functional/test_s390x_topology.py) | 12 | ||||
-rwxr-xr-x | tests/functional/s390x/test_tuxrun.py (renamed from tests/functional/test_s390x_tuxrun.py) | 1 | ||||
-rw-r--r-- | tests/functional/sh4/meson.build | 10 | ||||
-rwxr-xr-x | tests/functional/sh4/test_r2d.py (renamed from tests/functional/test_sh4_r2d.py) | 0 | ||||
-rwxr-xr-x | tests/functional/sh4/test_tuxrun.py (renamed from tests/functional/test_sh4_tuxrun.py) | 0 | ||||
-rw-r--r-- | tests/functional/sh4eb/meson.build | 5 | ||||
-rwxr-xr-x | tests/functional/sh4eb/test_r2d.py (renamed from tests/functional/test_sh4eb_r2d.py) | 0 | ||||
-rw-r--r-- | tests/functional/sparc/meson.build | 10 | ||||
-rwxr-xr-x | tests/functional/sparc/test_migration.py | 26 | ||||
-rwxr-xr-x | tests/functional/sparc/test_replay.py (renamed from tests/functional/test_sparc_replay.py) | 0 | ||||
-rwxr-xr-x | tests/functional/sparc/test_sun4m.py (renamed from tests/functional/test_sparc_sun4m.py) | 0 | ||||
-rw-r--r-- | tests/functional/sparc64/meson.build | 10 | ||||
-rwxr-xr-x | tests/functional/sparc64/test_migration.py | 26 | ||||
-rwxr-xr-x | tests/functional/sparc64/test_sun4u.py (renamed from tests/functional/test_sparc64_sun4u.py) | 0 | ||||
-rwxr-xr-x | tests/functional/sparc64/test_tuxrun.py (renamed from tests/functional/test_sparc64_tuxrun.py) | 1 | ||||
-rwxr-xr-x | tests/functional/test_aarch64_replay.py | 30 | ||||
-rwxr-xr-x | tests/functional/test_aarch64_rme_sbsaref.py | 71 | ||||
-rwxr-xr-x | tests/functional/test_aarch64_rme_virt.py | 101 | ||||
-rwxr-xr-x | tests/functional/test_mips_malta.py | 94 | ||||
-rwxr-xr-x | tests/functional/test_ppc_bamboo.py | 44 | ||||
-rwxr-xr-x | tests/functional/test_x86_64_replay.py | 35 | ||||
-rw-r--r-- | tests/functional/x86_64/meson.build | 39 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_acpi_bits.py (renamed from tests/functional/test_acpi_bits.py) | 31 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_bad_vmstate.py | 58 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_cpu_model_versions.py (renamed from tests/functional/test_x86_cpu_model_versions.py) | 110 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_cpu_queries.py (renamed from tests/functional/test_cpu_queries.py) | 0 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_hotplug_blk.py (renamed from tests/functional/test_x86_64_hotplug_blk.py) | 0 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_hotplug_cpu.py (renamed from tests/functional/test_x86_64_hotplug_cpu.py) | 0 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_intel_iommu.py (renamed from tests/functional/test_intel_iommu.py) | 0 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_kvm_xen.py (renamed from tests/functional/test_x86_64_kvm_xen.py) | 2 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_linux_initrd.py (renamed from tests/functional/test_linux_initrd.py) | 0 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_mem_addr_space.py (renamed from tests/functional/test_mem_addr_space.py) | 63 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_memlock.py | 80 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_migration.py | 26 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_multiprocess.py | 31 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_netdev_ethtool.py (renamed from tests/functional/test_netdev_ethtool.py) | 0 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_pc_cpu_hotplug_props.py (renamed from tests/functional/test_pc_cpu_hotplug_props.py) | 1 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_replay.py | 58 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_reverse_debug.py | 31 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_tuxrun.py (renamed from tests/functional/test_x86_64_tuxrun.py) | 0 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_vfio_user_client.py | 201 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_virtio_balloon.py (renamed from tests/functional/test_virtio_balloon.py) | 0 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_virtio_gpu.py (renamed from tests/functional/test_virtio_gpu.py) | 2 | ||||
-rwxr-xr-x | tests/functional/x86_64/test_virtio_version.py (renamed from tests/functional/test_virtio_version.py) | 0 | ||||
-rw-r--r-- | tests/functional/xtensa/meson.build | 6 | ||||
-rwxr-xr-x | tests/functional/xtensa/test_lx60.py (renamed from tests/functional/test_xtensa_lx60.py) | 0 | ||||
-rwxr-xr-x | tests/functional/xtensa/test_replay.py (renamed from tests/functional/test_xtensa_replay.py) | 0 |
211 files changed, 4097 insertions, 1158 deletions
diff --git a/tests/functional/aarch64/meson.build b/tests/functional/aarch64/meson.build new file mode 100644 index 0000000..5ad52f9 --- /dev/null +++ b/tests/functional/aarch64/meson.build @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +test_aarch64_timeouts = { + 'aspeed_ast2700' : 600, + 'aspeed_ast2700fc' : 600, + 'device_passthrough' : 720, + 'imx8mp_evk' : 240, + 'raspi4' : 480, + 'reverse_debug' : 180, + 'rme_virt' : 1200, + 'rme_sbsaref' : 1200, + 'sbsaref_alpine' : 1200, + 'sbsaref_freebsd' : 720, + 'smmu' : 720, + 'tuxrun' : 240, + 'virt' : 360, + 'virt_gpu' : 480, +} + +tests_aarch64_system_quick = [ + 'migration', + 'vmstate', +] + +tests_aarch64_system_thorough = [ + 'aspeed_ast2700', + 'aspeed_ast2700fc', + 'device_passthrough', + 'hotplug_pci', + 'imx8mp_evk', + 'kvm', + 'multiprocess', + 'raspi3', + 'raspi4', + 'replay', + 'reverse_debug', + 'rme_virt', + 'rme_sbsaref', + 'sbsaref', + 'sbsaref_alpine', + 'sbsaref_freebsd', + 'smmu', + 'tcg_plugins', + 'tuxrun', + 'virt', + 'virt_gpu', + 'xen', + 'xlnx_versal', +] diff --git a/tests/functional/test_aarch64_aspeed.py b/tests/functional/aarch64/test_aspeed_ast2700.py index c25c966..0ced1a2 100755 --- a/tests/functional/test_aarch64_aspeed.py +++ b/tests/functional/aarch64/test_aspeed_ast2700.py @@ -18,22 +18,64 @@ 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_start(self): 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, 'Linux version ') + + def verify_openbmc_boot_and_login(self, name): + self.verify_openbmc_boot_start() - ASSET_SDK_V905_AST2700 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.05/ast2700-a0-default-obmc.tar.gz', - 'cfbbd1cce72f2a3b73b9080c41eecdadebb7077fba4f7806d72ac99f3e84b74a') + 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_V905_AST2700A1 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.05/ast2700-default-obmc.tar.gz', - 'c1f4496aec06743c812a6e9a1a18d032f34d62f3ddb6956e924fef62aa2046a5') + ASSET_SDK_V908_AST2700A1 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.08/ast2700-default-obmc.tar.gz', + 'eac3dc409b7ea3cd4b03d4792d3cebd469792ad893cb51e1d15f0fc20bd1e2cd') + + 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_ast2700_pcie_test(self): + exec_command_and_wait_for_pattern(self, + 'lspci -s 0002:00:00.0', + '0002:00:00.0 PCI bridge: ' + 'ASPEED Technology, Inc. AST1150 PCI-to-PCI Bridge') + exec_command_and_wait_for_pattern(self, + 'lspci -s 0002:01:00.0', + '0002:01:00.0 Ethernet controller: ' + 'Intel Corporation 82574L Gigabit Network Connection') + exec_command_and_wait_for_pattern(self, + 'ip addr show dev eth2', + 'inet 10.0.2.15/24') def start_ast2700_test(self, name): num_cpu = 4 @@ -73,38 +115,36 @@ class AST2x00MachineSDK(QemuSystemTest): f'loader,addr=0x430000000,cpu-num={i}') self.vm.add_args('-smp', str(num_cpu)) - self.vm.add_args('-device', - 'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test') self.do_test_aarch64_aspeed_sdk_start( self.scratch_file(name, 'image-bmc')) - 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}:~#') - - 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 test_aarch64_ast2700_evb_sdk_v09_05(self): - self.set_machine('ast2700-evb') - - self.archive_extract(self.ASSET_SDK_V905_AST2700) - self.start_ast2700_test('ast2700-a0-default') + 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_ast2700a1_evb_sdk_v09_05(self): + def test_aarch64_ast2700a1_evb_sdk_v09_08(self): self.set_machine('ast2700a1-evb') + self.require_netdev('user') - self.archive_extract(self.ASSET_SDK_V905_AST2700A1) + self.archive_extract(self.ASSET_SDK_V908_AST2700A1) + self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.2') + self.vm.add_args('-netdev', 'user,id=net1') self.start_ast2700_test('ast2700-default') + self.verify_openbmc_boot_and_login('ast2700-default') + self.do_ast2700_i2c_test() + self.do_ast2700_pcie_test() + + def test_aarch64_ast2700a1_evb_sdk_vbootrom_v09_08(self): + self.set_machine('ast2700a1-evb') + self.require_netdev('user') + self.archive_extract(self.ASSET_SDK_V908_AST2700A1) + self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.2') + self.vm.add_args('-netdev', 'user,id=net1') + self.start_ast2700_test_vbootrom('ast2700-default') + self.verify_vbootrom_firmware_flow() + self.verify_openbmc_boot_start() if __name__ == '__main__': QemuSystemTest.main() diff --git a/tests/functional/aarch64/test_aspeed_ast2700fc.py b/tests/functional/aarch64/test_aspeed_ast2700fc.py new file mode 100755 index 0000000..28b6661 --- /dev/null +++ b/tests/functional/aarch64/test_aspeed_ast2700fc.py @@ -0,0 +1,148 @@ +#!/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('-device', 'e1000e,netdev=net1,bus=pcie.2') + self.vm.add_args('-netdev', 'user,id=net1') + 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_ast2700_pcie_test(self): + exec_command_and_wait_for_pattern(self, + 'lspci -s 0002:00:00.0', + '0002:00:00.0 PCI bridge: ' + 'ASPEED Technology, Inc. AST1150 PCI-to-PCI Bridge') + exec_command_and_wait_for_pattern(self, + 'lspci -s 0002:01:00.0', + '0002:01:00.0 Ethernet controller: ' + 'Intel Corporation 82574L Gigabit Network Connection') + + 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_ast2700_pcie_test() + self.do_ast2700fc_ssp_test() + self.do_ast2700fc_tsp_test() + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/functional/aarch64/test_device_passthrough.py b/tests/functional/aarch64/test_device_passthrough.py new file mode 100755 index 0000000..05a3f52 --- /dev/null +++ b/tests/functional/aarch64/test_device_passthrough.py @@ -0,0 +1,143 @@ +#!/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 + +from os.path import join + +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/tree/device_passthrough + # $ ./build.sh && ./archive_artifacts.sh out.tar.xz + # + # 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://github.com/pbo-linaro/qemu-linux-stack/' + 'releases/download/build/device_passthrough-a9612a2.tar.xz'), + 'f7d2f70912e7231986e6e293e1a2c4786dd02bec113a7acb6bfc619e96155455') + + # 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 = self.ASSET_DEVICE_PASSTHROUGH_STACK.fetch() + self.archive_extract(stack_path_tar, format="tar") + + stack = self.scratch_file('out') + kernel = join(stack, 'Image.gz') + rootfs_host = join(stack, 'host.ext4') + disk_vfio = join(stack, 'disk_vfio') + disk_iommufd = join(stack, 'disk_iommufd') + guest_cmd = join(stack, 'guest.sh') + nested_guest_cmd = 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/aarch64/test_hotplug_pci.py b/tests/functional/aarch64/test_hotplug_pci.py new file mode 100755 index 0000000..bf67720 --- /dev/null +++ b/tests/functional/aarch64/test_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/trixie/main/installer-arm64/' + '20250803/images/netboot/debian-installer/arm64/linux'), + '93a6e4f9627d759375d28f863437a86a0659e125792a435f8e526dda006b7d5e') + + ASSET_INITRD = Asset( + ('https://ftp.debian.org/debian/dists/trixie/main/installer-arm64/' + '20250803/images/netboot/debian-installer/arm64/initrd.gz'), + 'f6c78af7078ca67638ef3a50c926cd3c1485673243f8b37952e6bd854d6ba007') + + 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/aarch64/test_imx8mp_evk.py b/tests/functional/aarch64/test_imx8mp_evk.py new file mode 100755 index 0000000..99ddcde --- /dev/null +++ b/tests/functional/aarch64/test_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/aarch64/test_kvm.py b/tests/functional/aarch64/test_kvm.py new file mode 100755 index 0000000..9fb9286 --- /dev/null +++ b/tests/functional/aarch64/test_kvm.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# +# Functional test that runs subsets of kvm-unit-tests on Aarch64. +# These can run on TCG and any accelerator supporting nested +# virtualisation. +# +# Copyright (c) 2025 Linaro +# +# Author: +# Alex Bennée <alex.bennee@linaro.org> +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import Asset +from qemu_test import exec_command_and_wait_for_pattern as ec_and_wait +from qemu_test.linuxkernel import LinuxKernelTest + + +class Aarch64VirtKVMTests(LinuxKernelTest): + + ASSET_KVM_TEST_KERNEL = Asset( + 'https://fileserver.linaro.org/s/HmjaxXXYHYSqbes/' + 'download?path=%2F&files=' + 'image-with-kvm-tool-and-unit-tests.gz', + '34de4aaea90db5da42729e7d28b77f392c37a2f4da859f889a5234aaf0970696') + + # make it easier to detect successful return to shell + PS1 = 'RES=[$?] # ' + OK_CMD = 'RES=[0] # ' + + # base of tests + KUT_BASE = "/usr/share/kvm-unit-tests/" + + def _launch_guest(self, kvm_mode="nvhe"): + + self.set_machine('virt') + kernel_path = self.ASSET_KVM_TEST_KERNEL.fetch() + + self.vm.set_console() + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + f"console=ttyAMA0 kvm-arm.mode={kvm_mode}") + + self.vm.add_args("-cpu", "cortex-a72") + self.vm.add_args("-machine", "virt,gic-version=3,virtualization=on", + '-kernel', kernel_path, + '-append', kernel_command_line) + self.vm.add_args("-smp", "2", "-m", "320") + + self.vm.launch() + + self.wait_for_console_pattern('buildroot login:') + ec_and_wait(self, 'root', '#') + ec_and_wait(self, f"export PS1='{self.PS1}'", self.OK_CMD) + + # this is just a smoketest, we don't run all the tests in the image + def _smoketest_kvm(self): + ec_and_wait(self, f"{self.KUT_BASE}/selftest-setup", self.OK_CMD) + ec_and_wait(self, f"{self.KUT_BASE}/selftest-smp", self.OK_CMD) + ec_and_wait(self, f"{self.KUT_BASE}/selftest-vectors-kernel", self.OK_CMD) + ec_and_wait(self, f"{self.KUT_BASE}/selftest-vectors-user", self.OK_CMD) + + def test_aarch64_nvhe_selftest(self): + self._launch_guest("nvhe") + self._smoketest_kvm() + + def test_aarch64_vhe_selftest(self): + self._launch_guest("vhe") + self._smoketest_kvm() + +if __name__ == '__main__': + LinuxKernelTest.main() diff --git a/tests/functional/aarch64/test_migration.py b/tests/functional/aarch64/test_migration.py new file mode 100755 index 0000000..70267e7 --- /dev/null +++ b/tests/functional/aarch64/test_migration.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# aarch64 migration test + +from migration import MigrationTest + + +class Aarch64MigrationTest(MigrationTest): + + def test_migration_with_tcp_localhost(self): + self.set_machine('quanta-gsj') + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.set_machine('quanta-gsj') + self.migration_with_unix() + + def test_migration_with_exec(self): + self.set_machine('quanta-gsj') + self.migration_with_exec() + + +if __name__ == '__main__': + MigrationTest.main() diff --git a/tests/functional/aarch64/test_multiprocess.py b/tests/functional/aarch64/test_multiprocess.py new file mode 100755 index 0000000..1c6e45e --- /dev/null +++ b/tests/functional/aarch64/test_multiprocess.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Test for multiprocess qemu on aarch64 + +from multiprocess import Multiprocess +from qemu_test import Asset + + +class Aarch64Multiprocess(Multiprocess): + + 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 test_multiprocess(self): + kernel_command_line = (self.KERNEL_COMMON_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') + + +if __name__ == '__main__': + Multiprocess.main() diff --git a/tests/functional/test_aarch64_raspi3.py b/tests/functional/aarch64/test_raspi3.py index 74f6630..74f6630 100755 --- a/tests/functional/test_aarch64_raspi3.py +++ b/tests/functional/aarch64/test_raspi3.py diff --git a/tests/functional/test_aarch64_raspi4.py b/tests/functional/aarch64/test_raspi4.py index 7a4302b..7a4302b 100755 --- a/tests/functional/test_aarch64_raspi4.py +++ b/tests/functional/aarch64/test_raspi4.py diff --git a/tests/functional/aarch64/test_replay.py b/tests/functional/aarch64/test_replay.py new file mode 100755 index 0000000..db12e76 --- /dev/null +++ b/tests/functional/aarch64/test_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/aarch64/test_reverse_debug.py b/tests/functional/aarch64/test_reverse_debug.py new file mode 100755 index 0000000..ec3348c --- /dev/null +++ b/tests/functional/aarch64/test_reverse_debug.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Reverse debugging test for aarch64 +# +# Copyright (c) 2020 ISP RAS +# Copyright (c) 2025 Linaro Limited +# +# Author: +# Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru> +# Gustavo Romero <gustavo.romero@linaro.org> (Run without Avocado) +# +# 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, skipFlakyTest +from reverse_debugging import ReverseDebugging + + +class ReverseDebugging_AArch64(ReverseDebugging): + + ASSET_KERNEL = Asset( + ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' + 'releases/29/Everything/aarch64/os/images/pxeboot/vmlinuz'), + '7e1430b81c26bdd0da025eeb8fbd77b5dc961da4364af26e771bd39f379cbbf7') + + def test_aarch64_virt(self): + self.set_machine('virt') + self.cpu = 'cortex-a53' + kernel_path = self.ASSET_KERNEL.fetch() + self.reverse_debugging(gdb_arch='aarch64', args=('-kernel', kernel_path)) + + +if __name__ == '__main__': + ReverseDebugging.main() diff --git a/tests/functional/aarch64/test_rme_sbsaref.py b/tests/functional/aarch64/test_rme_sbsaref.py new file mode 100755 index 0000000..6f92858 --- /dev/null +++ b/tests/functional/aarch64/test_rme_sbsaref.py @@ -0,0 +1,77 @@ +#!/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 os.path import join +import shutil + +from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern +from qemu_test import exec_command_and_wait_for_pattern + + +class Aarch64RMESbsaRefMachine(QemuSystemTest): + + # Stack is inspired from: + # https://linaro.atlassian.net/wiki/spaces/QEMU/pages/29051027459/ + # https://github.com/pbo-linaro/qemu-linux-stack/tree/rme_sbsa_release + # ./build.sh && ./archive_artifacts.sh out.tar.xz + ASSET_RME_STACK_SBSA = Asset( + ('https://github.com/pbo-linaro/qemu-linux-stack/' + 'releases/download/build/rme_sbsa_release-6a2dfc5.tar.xz'), + '5adba482aa069912292a8da746c6b21268224d9d81c97fe7c0bed690579ebdcb') + + # 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 = self.ASSET_RME_STACK_SBSA.fetch() + self.archive_extract(stack_path_tar, format="tar") + + rme_stack = self.scratch_file('.') + pflash0 = join(rme_stack, 'out', 'SBSA_FLASH0.fd') + pflash1 = join(rme_stack, 'out', 'SBSA_FLASH1.fd') + rootfs = join(rme_stack, 'out', 'host.ext4') + + efi = join(rme_stack, 'out', 'EFI') + os.makedirs(efi, exist_ok=True) + shutil.copyfile(join(rme_stack, 'out', 'Image'), join(efi, 'Image')) + with open(join(efi, 'startup.nsh'), 'w') as startup: + startup.write('fs0:Image nokaslr root=/dev/vda rw init=/init --' + ' /host/out/lkvm run --realm' + ' -m 256m' + ' --restricted_mem' + ' --kernel /host/out/Image' + ' --disk /host/out/guest.ext4' + ' --params "root=/dev/vda rw init=/init"') + + self.vm.add_args('-cpu', 'max,x-rme=on') + self.vm.add_args('-smp', '2') + 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:{efi},format=raw') + self.vm.add_args('-drive', f'format=raw,file={rootfs},if=virtio') + self.vm.add_args('-virtfs', + f'local,path={rme_stack}/,mount_tag=host,' + 'security_model=mapped,readonly=off') + self.vm.launch() + # Wait for host and guest VM boot to complete. + wait_for_console_pattern(self, 'root@guest', + failure_message='Kernel panic') + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/functional/aarch64/test_rme_virt.py b/tests/functional/aarch64/test_rme_virt.py new file mode 100755 index 0000000..5e23773 --- /dev/null +++ b/tests/functional/aarch64/test_rme_virt.py @@ -0,0 +1,76 @@ +#!/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 + +from os.path import join + +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 + +class Aarch64RMEVirtMachine(QemuSystemTest): + + # Stack is inspired from: + # https://linaro.atlassian.net/wiki/spaces/QEMU/pages/29051027459/ + # https://github.com/pbo-linaro/qemu-linux-stack/tree/rme_release + # ./build.sh && ./archive_artifacts.sh out.tar.xz + ASSET_RME_STACK_VIRT = Asset( + ('https://github.com/pbo-linaro/qemu-linux-stack/' + 'releases/download/build/rme_release-56bc99e.tar.xz'), + '0e3dc6b8a4b828dbae09c951a40dcb710eded084b32432b50c69cf4173ffa4be') + + # 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 = self.ASSET_RME_STACK_VIRT.fetch() + self.archive_extract(stack_path_tar, format="tar") + + rme_stack = self.scratch_file('.') + kernel = join(rme_stack, 'out', 'Image') + bios = join(rme_stack, 'out', 'flash.bin') + rootfs = join(rme_stack, 'out', 'host.ext4') + + self.vm.add_args('-cpu', 'max,x-rme=on') + self.vm.add_args('-smp', '2') + 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,file={rootfs},if=virtio') + self.vm.add_args('-virtfs', + f'local,path={rme_stack}/,mount_tag=host,' + 'security_model=mapped,readonly=off') + # We need to add nokaslr to avoid triggering this sporadic bug: + # https://gitlab.com/qemu-project/qemu/-/issues/2823 + self.vm.add_args('-append', + 'nokaslr root=/dev/vda rw init=/init --' + ' /host/out/lkvm run --realm' + ' -m 256m' + ' --restricted_mem' + ' --kernel /host/out/Image' + ' --disk /host/out/guest.ext4' + ' --params "root=/dev/vda rw init=/init"') + + self.vm.launch() + # Wait for host and guest VM boot to complete. + wait_for_console_pattern(self, 'root@guest', + failure_message='Kernel panic') + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/functional/test_aarch64_sbsaref.py b/tests/functional/aarch64/test_sbsaref.py index e6a55ae..d3402f5 100755 --- a/tests/functional/test_aarch64_sbsaref.py +++ b/tests/functional/aarch64/test_sbsaref.py @@ -40,8 +40,6 @@ def fetch_firmware(test): with open(path, "ab+") as fd: fd.truncate(256 << 20) # Expand volumes to 256MiB - test.set_machine('sbsa-ref') - test.vm.set_console() test.vm.add_args( "-drive", f"if=pflash,file={fs0_path},format=raw", "-drive", f"if=pflash,file={fs1_path},format=raw", @@ -68,8 +66,11 @@ class Aarch64SbsarefMachine(QemuSystemTest): def test_sbsaref_edk2_firmware(self): + self.set_machine('sbsa-ref') + fetch_firmware(self) + self.vm.set_console() self.vm.add_args('-cpu', 'cortex-a57') self.vm.launch() diff --git a/tests/functional/test_aarch64_sbsaref_alpine.py b/tests/functional/aarch64/test_sbsaref_alpine.py index c660cc7..abb8f51 100755 --- a/tests/functional/test_aarch64_sbsaref_alpine.py +++ b/tests/functional/aarch64/test_sbsaref_alpine.py @@ -10,12 +10,9 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os - from qemu_test import QemuSystemTest, Asset, skipSlowTest from qemu_test import wait_for_console_pattern -from unittest import skipUnless -from test_aarch64_sbsaref import fetch_firmware +from test_sbsaref import fetch_firmware class Aarch64SbsarefAlpine(QemuSystemTest): @@ -29,8 +26,9 @@ class Aarch64SbsarefAlpine(QemuSystemTest): # 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): - fetch_firmware(self) + self.set_machine('sbsa-ref') + fetch_firmware(self) iso_path = self.ASSET_ALPINE_ISO.fetch() self.vm.set_console() diff --git a/tests/functional/test_aarch64_sbsaref_freebsd.py b/tests/functional/aarch64/test_sbsaref_freebsd.py index bd6728d..3b942f7 100755 --- a/tests/functional/test_aarch64_sbsaref_freebsd.py +++ b/tests/functional/aarch64/test_sbsaref_freebsd.py @@ -10,27 +10,26 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os - from qemu_test import QemuSystemTest, Asset, skipSlowTest from qemu_test import wait_for_console_pattern -from test_aarch64_sbsaref import fetch_firmware +from test_sbsaref import fetch_firmware class Aarch64SbsarefFreeBSD(QemuSystemTest): ASSET_FREEBSD_ISO = Asset( - ('https://download.freebsd.org/releases/arm64/aarch64/ISO-IMAGES/' - '14.1/FreeBSD-14.1-RELEASE-arm64-aarch64-bootonly.iso'), - '44cdbae275ef1bb6dab1d5fbb59473d4f741e1c8ea8a80fd9e906b531d6ad461') + ('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): - fetch_firmware(self) + self.set_machine('sbsa-ref') - img_path = self.ASSET_FREEBSD_ISO.fetch() + fetch_firmware(self) + img_path = self.uncompress(self.ASSET_FREEBSD_ISO) self.vm.set_console() self.vm.add_args( diff --git a/tests/functional/aarch64/test_smmu.py b/tests/functional/aarch64/test_smmu.py new file mode 100755 index 0000000..e0f4a92 --- /dev/null +++ b/tests/functional/aarch64/test_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/functional/test_aarch64_tcg_plugins.py b/tests/functional/aarch64/test_tcg_plugins.py index 4ea71f5..cb7e929 100755 --- a/tests/functional/test_aarch64_tcg_plugins.py +++ b/tests/functional/aarch64/test_tcg_plugins.py @@ -13,7 +13,6 @@ import tempfile import mmap -import os import re from qemu.machine.machine import VMLaunchFailure diff --git a/tests/functional/test_aarch64_tuxrun.py b/tests/functional/aarch64/test_tuxrun.py index 75adc8a..75adc8a 100755 --- a/tests/functional/test_aarch64_tuxrun.py +++ b/tests/functional/aarch64/test_tuxrun.py diff --git a/tests/functional/test_aarch64_virt.py b/tests/functional/aarch64/test_virt.py index 884aad7..63071f9 100755 --- a/tests/functional/test_aarch64_virt.py +++ b/tests/functional/aarch64/test_virt.py @@ -13,12 +13,8 @@ import logging from subprocess import check_call, DEVNULL -from qemu.machine.machine import VMLaunchFailure - -from qemu_test import QemuSystemTest, Asset -from qemu_test import exec_command, exec_command_and_wait_for_pattern -from qemu_test import wait_for_console_pattern -from qemu_test import skipIfMissingCommands, get_qemu_img +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): @@ -76,8 +72,6 @@ class Aarch64VirtMachine(QemuSystemTest): self.set_machine('virt') self.require_accelerator("tcg") - logger = logging.getLogger('aarch64_virt') - kernel_path = self.ASSET_KERNEL.fetch() self.vm.set_console() @@ -95,7 +89,7 @@ class Aarch64VirtMachine(QemuSystemTest): 'rng-random,id=rng0,filename=/dev/urandom') # Also add a scratch block device - logger.info('creating scratch qcow2 image') + self.log.info('creating scratch qcow2 image') image_path = self.scratch_file('scratch.qcow2') qemu_img = get_qemu_img(self) check_call([qemu_img, 'create', '-f', 'qcow2', image_path, '8M'], diff --git a/tests/functional/test_aarch64_virt_gpu.py b/tests/functional/aarch64/test_virt_gpu.py index 3844727..4e50887 100755 --- a/tests/functional/test_aarch64_virt_gpu.py +++ b/tests/functional/aarch64/test_virt_gpu.py @@ -76,6 +76,8 @@ class Aarch64VirtGPUMachine(LinuxKernelTest): 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") + elif "eglInitialize failed: EGL_NOT_INITIALIZED" in excp.output: + self.skipTest("EGL failed to initialize on this host") else: self.log.info("unhandled launch failure: %s", excp.output) raise excp diff --git a/tests/functional/test_aarch64_xen.py b/tests/functional/aarch64/test_xen.py index 3399042..261d796 100755 --- a/tests/functional/test_aarch64_xen.py +++ b/tests/functional/aarch64/test_xen.py @@ -33,6 +33,7 @@ class BootXen(LinuxKernelTest): """ 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() diff --git a/tests/functional/test_aarch64_xlnx_versal.py b/tests/functional/aarch64/test_xlnx_versal.py index 4b9c49e..45aa6e1 100755 --- a/tests/functional/test_aarch64_xlnx_versal.py +++ b/tests/functional/aarch64/test_xlnx_versal.py @@ -6,7 +6,7 @@ from qemu_test import LinuxKernelTest, Asset -class XlnxVersalVirtMachine(LinuxKernelTest): +class AmdVersalVirtMachine(LinuxKernelTest): ASSET_KERNEL = Asset( ('http://ports.ubuntu.com/ubuntu-ports/dists/bionic-updates/main/' @@ -20,8 +20,8 @@ class XlnxVersalVirtMachine(LinuxKernelTest): '/ubuntu-installer/arm64/initrd.gz'), 'e7a5e716b6f516d8be315c06e7331aaf16994fe4222e0e7cfb34bc015698929e') - def test_aarch64_xlnx_versal_virt(self): - self.set_machine('xlnx-versal-virt') + def common_aarch64_amd_versal_virt(self, machine): + self.set_machine(machine) kernel_path = self.ASSET_KERNEL.fetch() initrd_path = self.ASSET_INITRD.fetch() @@ -33,5 +33,11 @@ class XlnxVersalVirtMachine(LinuxKernelTest): self.vm.launch() self.wait_for_console_pattern('Checked W+X mappings: passed') + def test_aarch64_amd_versal_virt(self): + self.common_aarch64_amd_versal_virt('amd-versal-virt') + + def test_aarch64_amd_versal2_virt(self): + self.common_aarch64_amd_versal_virt('amd-versal2-virt') + if __name__ == '__main__': LinuxKernelTest.main() diff --git a/tests/functional/alpha/meson.build b/tests/functional/alpha/meson.build new file mode 100644 index 0000000..26a5b3f --- /dev/null +++ b/tests/functional/alpha/meson.build @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_alpha_system_quick = [ + 'migration', +] + +tests_alpha_system_thorough = [ + 'clipper', + 'replay', +] diff --git a/tests/functional/test_alpha_clipper.py b/tests/functional/alpha/test_clipper.py index c5d7181..c5d7181 100755 --- a/tests/functional/test_alpha_clipper.py +++ b/tests/functional/alpha/test_clipper.py diff --git a/tests/functional/alpha/test_migration.py b/tests/functional/alpha/test_migration.py new file mode 100755 index 0000000..f11b523 --- /dev/null +++ b/tests/functional/alpha/test_migration.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Alpha migration test + +from migration import MigrationTest + + +class AlphaMigrationTest(MigrationTest): + + def test_migration_with_tcp_localhost(self): + self.set_machine('clipper') + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.set_machine('clipper') + self.migration_with_unix() + + def test_migration_with_exec(self): + self.set_machine('clipper') + self.migration_with_exec() + + +if __name__ == '__main__': + MigrationTest.main() diff --git a/tests/functional/test_alpha_replay.py b/tests/functional/alpha/test_replay.py index 24a17ef..24a17ef 100755 --- a/tests/functional/test_alpha_replay.py +++ b/tests/functional/alpha/test_replay.py diff --git a/tests/functional/arm/meson.build b/tests/functional/arm/meson.build new file mode 100644 index 0000000..d1ed076 --- /dev/null +++ b/tests/functional/arm/meson.build @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +test_arm_timeouts = { + 'aspeed_palmetto' : 120, + 'aspeed_romulus' : 120, + 'aspeed_witherspoon' : 120, + 'aspeed_ast2500' : 720, + 'aspeed_ast2600_buildroot' : 720, + 'aspeed_ast2600_sdk' : 1200, + 'aspeed_bletchley' : 480, + 'aspeed_catalina' : 480, + 'aspeed_gb200nvl_bmc' : 480, + 'aspeed_rainier' : 480, + 'bpim2u' : 500, + 'collie' : 180, + 'cubieboard' : 360, + 'orangepi' : 540, + 'quanta_gsj' : 240, + 'raspi2' : 120, + 'replay' : 240, + 'tuxrun' : 240, + 'sx1' : 360, +} + +tests_arm_system_quick = [ + 'migration', +] + +tests_arm_system_thorough = [ + 'aspeed_ast1030', + 'aspeed_palmetto', + 'aspeed_romulus', + 'aspeed_witherspoon', + 'aspeed_ast2500', + 'aspeed_ast2600_buildroot', + 'aspeed_ast2600_sdk', + 'aspeed_bletchley', + 'aspeed_catalina', + 'aspeed_gb200nvl_bmc', + 'aspeed_rainier', + 'bpim2u', + 'canona1100', + 'collie', + 'cubieboard', + 'emcraft_sf2', + 'integratorcp', + 'max78000fthr', + 'microbit', + 'orangepi', + 'quanta_gsj', + 'raspi2', + 'realview', + 'replay', + 'smdkc210', + 'stellaris', + 'sx1', + 'vexpress', + 'virt', + 'tuxrun', +] + +tests_arm_linuxuser_thorough = [ + 'bflt', +] diff --git a/tests/functional/test_arm_aspeed_ast1030.py b/tests/functional/arm/test_aspeed_ast1030.py index d45d9f7..60e2b02 100755 --- a/tests/functional/test_arm_aspeed_ast1030.py +++ b/tests/functional/arm/test_aspeed_ast1030.py @@ -7,22 +7,23 @@ # SPDX-License-Identifier: GPL-2.0-or-later from qemu_test import LinuxKernelTest, Asset +from aspeed import AspeedTest from qemu_test import exec_command_and_wait_for_pattern -class AST1030Machine(LinuxKernelTest): +class AST1030Machine(AspeedTest): - ASSET_ZEPHYR_1_04 = Asset( + ASSET_ZEPHYR_3_03 = Asset( ('https://github.com/AspeedTech-BMC' - '/zephyr/releases/download/v00.01.04/ast1030-evb-demo.zip'), - '4ac6210adcbc61294927918707c6762483fd844dde5e07f3ba834ad1f91434d3') + '/zephyr/releases/download/v00.03.03/ast1030-evb-demo.zip'), + '27cd73cdee6374bceb4ee58b3ace87989fa3f0684f4e612510804b588b24d4e0') - def test_ast1030_zephyros_1_04(self): + def test_arm_ast1030_zephyros_3_03(self): self.set_machine('ast1030-evb') kernel_name = "ast1030-evb-demo/zephyr.elf" kernel_file = self.archive_extract( - self.ASSET_ZEPHYR_1_04, member=kernel_name) + self.ASSET_ZEPHYR_3_03, member=kernel_name) self.vm.set_console() self.vm.add_args('-kernel', kernel_file, '-nographic') @@ -36,7 +37,7 @@ class AST1030Machine(LinuxKernelTest): '/zephyr/releases/download/v00.01.07/ast1030-evb-demo.zip'), 'ad52e27959746988afaed8429bf4e12ab988c05c4d07c9d90e13ec6f7be4574c') - def test_ast1030_zephyros_1_07(self): + def test_arm_ast1030_zephyros_1_07(self): self.set_machine('ast1030-evb') kernel_name = "ast1030-evb-demo/zephyr.bin" @@ -68,6 +69,22 @@ class AST1030Machine(LinuxKernelTest): 'kernel uptime', ]: exec_command_and_wait_for_pattern(self, shell_cmd, "uart:~$") + def test_arm_ast1030_otp_blockdev_device(self): + self.vm.set_machine("ast1030-evb") + + kernel_name = "ast1030-evb-demo/zephyr.elf" + kernel_file = self.archive_extract(self.ASSET_ZEPHYR_3_03, + member=kernel_name) + otp_img = self.generate_otpmem_image() + + self.vm.set_console() + self.vm.add_args( + "-kernel", kernel_file, + "-blockdev", f"driver=file,filename={otp_img},node-name=otp", + "-global", "aspeed-otp.drive=otp", + ) + self.vm.launch() + self.wait_for_console_pattern("Booting Zephyr OS") if __name__ == '__main__': - LinuxKernelTest.main() + AspeedTest.main() diff --git a/tests/functional/test_arm_aspeed_ast2500.py b/tests/functional/arm/test_aspeed_ast2500.py index 1ffba6c..5efd104 100755 --- a/tests/functional/test_arm_aspeed_ast2500.py +++ b/tests/functional/arm/test_aspeed_ast2500.py @@ -4,9 +4,8 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -from qemu_test import Asset +from qemu_test import Asset, exec_command_and_wait_for_pattern from aspeed import AspeedTest -from qemu_test import exec_command_and_wait_for_pattern class AST2500Machine(AspeedTest): @@ -22,30 +21,30 @@ class AST2500Machine(AspeedTest): 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'); + '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'); + '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); + 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_V806_AST2500 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v08.06/ast2500-default-obmc.tar.gz', - 'e1755f3cadff69190438c688d52dd0f0d399b70a1e14b1d3d5540fc4851d38ca') + ASSET_SDK_V908_AST2500 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.08/ast2500-default-obmc.tar.gz', + 'c0a2ba169efd19be5eb77c50ec2a6afd9d826e196a0be3432f969fc72d4b7c0e') def test_arm_ast2500_evb_sdk(self): self.set_machine('ast2500-evb') - self.archive_extract(self.ASSET_SDK_V806_AST2500) + self.archive_extract(self.ASSET_SDK_V908_AST2500) self.do_test_arm_aspeed_sdk_start( self.scratch_file("ast2500-default", "image-bmc")) diff --git a/tests/functional/test_arm_aspeed_ast2600.py b/tests/functional/arm/test_aspeed_ast2600_buildroot.py index 6ae4ed6..51f2676 100755 --- a/tests/functional/test_arm_aspeed_ast2600.py +++ b/tests/functional/arm/test_aspeed_ast2600_buildroot.py @@ -27,38 +27,38 @@ class AST2600Machine(AspeedTest): 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'); + 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test') self.vm.add_args('-device', - 'ds1338,bus=aspeed.i2c.bus.3,address=0x32'); + 'ds1338,bus=aspeed.i2c.bus.3,address=0x32') self.vm.add_args('-device', - 'i2c-echo,bus=aspeed.i2c.bus.3,address=0x42'); + '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'); + '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); + 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'); + '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, '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'); + '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', '#'); + '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'); + '0000000 ffaa ffff ffff ffff ffff ffff ffff ffff') self.do_test_arm_aspeed_buildroot_poweroff() ASSET_BR2_202302_AST2600_TPM_FLASH = Asset( @@ -90,50 +90,13 @@ class AST2600Machine(AspeedTest): 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)'); + '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'); + 'B804724EA13F52A9072BA87FE8FDCC497DFC9DF9AA15B9088694639C431688E0') self.do_test_arm_aspeed_buildroot_poweroff() - ASSET_SDK_V806_AST2600_A2 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v08.06/ast2600-a2-obmc.tar.gz', - '9083506135f622d5e7351fcf7d4e1c7125cee5ba16141220c0ba88931f3681a4') - - def test_arm_ast2600_evb_sdk(self): - self.set_machine('ast2600-evb') - - self.archive_extract(self.ASSET_SDK_V806_AST2600_A2) - - 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-a2", "image-bmc")) - - self.wait_for_console_pattern('ast2600-a2 login:') - - exec_command_and_wait_for_pattern(self, 'root', 'Password:') - exec_command_and_wait_for_pattern(self, '0penBmc', 'root@ast2600-a2:~#') - - 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/arm/test_aspeed_ast2600_sdk.py b/tests/functional/arm/test_aspeed_ast2600_sdk.py new file mode 100755 index 0000000..e3d4ed0 --- /dev/null +++ b/tests/functional/arm/test_aspeed_ast2600_sdk.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +# +# Functional test that boots the ASPEED machines +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import os +import time + +from qemu_test import Asset +from aspeed import AspeedTest +from qemu_test import exec_command_and_wait_for_pattern + + +class AST2600Machine(AspeedTest): + + ASSET_SDK_V908_AST2600 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.08/ast2600-default-obmc.tar.gz', + 'a0414f14ad696550efe083c2156dbeda855c08cc9ae7f40fe1b41bf292295f82') + + def do_ast2600_pcie_test(self): + exec_command_and_wait_for_pattern(self, + 'lspci -s 80:00.0', + '80:00.0 Host bridge: ' + 'ASPEED Technology, Inc. Device 2600') + exec_command_and_wait_for_pattern(self, + 'lspci -s 80:08.0', + '80:08.0 PCI bridge: ' + 'ASPEED Technology, Inc. AST1150 PCI-to-PCI Bridge') + exec_command_and_wait_for_pattern(self, + 'lspci -s 81:00.0', + '81:00.0 Ethernet controller: ' + 'Intel Corporation 82574L Gigabit Network Connection') + exec_command_and_wait_for_pattern(self, + 'ip addr show dev eth4', + 'inet 10.0.2.15/24') + + def test_arm_ast2600_evb_sdk(self): + self.set_machine('ast2600-evb') + self.require_netdev('user') + + self.archive_extract(self.ASSET_SDK_V908_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.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.0') + self.vm.add_args('-netdev', 'user,id=net1') + 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) + self.do_ast2600_pcie_test() + + def test_arm_ast2600_otp_blockdev_device(self): + self.vm.set_machine("ast2600-evb") + + image_path = self.archive_extract(self.ASSET_SDK_V908_AST2600) + otp_img = self.generate_otpmem_image() + + self.vm.set_console() + self.vm.add_args( + "-blockdev", f"driver=file,filename={otp_img},node-name=otp", + "-global", "aspeed-otp.drive=otp", + ) + self.do_test_arm_aspeed_sdk_start( + self.scratch_file("ast2600-default", "image-bmc")) + self.wait_for_console_pattern("ast2600-default login:") + + +if __name__ == '__main__': + AspeedTest.main() diff --git a/tests/functional/test_arm_aspeed_bletchley.py b/tests/functional/arm/test_aspeed_bletchley.py index 0da856c..5a60b24 100644..100755 --- a/tests/functional/test_arm_aspeed_bletchley.py +++ b/tests/functional/arm/test_aspeed_bletchley.py @@ -12,14 +12,14 @@ 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'); + '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'); + soc='AST2600 rev A3') if __name__ == '__main__': AspeedTest.main() diff --git a/tests/functional/arm/test_aspeed_catalina.py b/tests/functional/arm/test_aspeed_catalina.py new file mode 100755 index 0000000..dc2f24e --- /dev/null +++ b/tests/functional/arm/test_aspeed_catalina.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 CatalinaMachine(AspeedTest): + + ASSET_CATALINA_FLASH = Asset( + 'https://github.com/legoater/qemu-aspeed-boot/raw/a866feb5ef81245b4827a214584bf6bcc72939f6/images/catalina-bmc/obmc-phosphor-image-catalina-20250619123021.static.mtd.xz', + '287402e1ba021991e06be1d098f509444a02a3d81a73a932f66528b159e864f9') + + def test_arm_ast2600_catalina_openbmc(self): + image_path = self.uncompress(self.ASSET_CATALINA_FLASH) + + self.do_test_arm_aspeed_openbmc('catalina-bmc', image=image_path, + uboot='2019.04', cpu_id='0xf00', + soc='AST2600 rev A3') + +if __name__ == '__main__': + AspeedTest.main() diff --git a/tests/functional/arm/test_aspeed_gb200nvl_bmc.py b/tests/functional/arm/test_aspeed_gb200nvl_bmc.py new file mode 100755 index 0000000..8e8e3f0 --- /dev/null +++ b/tests/functional/arm/test_aspeed_gb200nvl_bmc.py @@ -0,0 +1,26 @@ +#!/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 GB200Machine(AspeedTest): + + ASSET_GB200_FLASH = Asset( + 'https://github.com/legoater/qemu-aspeed-boot/raw/refs/heads/master/images/gb200nvl-obmc/obmc-phosphor-image-gb200nvl-obmc-20250702182348.static.mtd.xz', + 'b84819317cb3dc762895ad507705978ef000bfc77c50c33a63bdd37921db0dbc') + + def test_arm_aspeed_gb200_openbmc(self): + image_path = self.uncompress(self.ASSET_GB200_FLASH) + + self.do_test_arm_aspeed_openbmc('gb200nvl-bmc', image=image_path, + uboot='2019.04', cpu_id='0xf00', + soc='AST2600 rev A3', + image_hostname='gb200nvl-obmc') + +if __name__ == '__main__': + AspeedTest.main() diff --git a/tests/functional/test_arm_aspeed_palmetto.py b/tests/functional/arm/test_aspeed_palmetto.py index 35d832b..ff0b821 100755 --- a/tests/functional/test_arm_aspeed_palmetto.py +++ b/tests/functional/arm/test_aspeed_palmetto.py @@ -12,14 +12,14 @@ 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'); + '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'); + soc='AST2400 rev A1') if __name__ == '__main__': AspeedTest.main() diff --git a/tests/functional/test_arm_aspeed_rainier.py b/tests/functional/arm/test_aspeed_rainier.py index 602d619..602d619 100755 --- a/tests/functional/test_arm_aspeed_rainier.py +++ b/tests/functional/arm/test_aspeed_rainier.py diff --git a/tests/functional/test_arm_aspeed_romulus.py b/tests/functional/arm/test_aspeed_romulus.py index b97ed95..0447212 100755 --- a/tests/functional/test_arm_aspeed_romulus.py +++ b/tests/functional/arm/test_aspeed_romulus.py @@ -12,14 +12,14 @@ 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'); + '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'); + soc='AST2500 rev A1') if __name__ == '__main__': AspeedTest.main() diff --git a/tests/functional/test_arm_aspeed_witherspoon.py b/tests/functional/arm/test_aspeed_witherspoon.py index ea1ce89..51a2d47 100644..100755 --- a/tests/functional/test_arm_aspeed_witherspoon.py +++ b/tests/functional/arm/test_aspeed_witherspoon.py @@ -12,14 +12,14 @@ 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'); + '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'); + soc='AST2500 rev A1') if __name__ == '__main__': AspeedTest.main() diff --git a/tests/functional/test_arm_bflt.py b/tests/functional/arm/test_bflt.py index f273fc8..f273fc8 100755 --- a/tests/functional/test_arm_bflt.py +++ b/tests/functional/arm/test_bflt.py diff --git a/tests/functional/test_arm_bpim2u.py b/tests/functional/arm/test_bpim2u.py index 8de6ccb..8bed64b 100755 --- a/tests/functional/test_arm_bpim2u.py +++ b/tests/functional/arm/test_bpim2u.py @@ -163,7 +163,7 @@ class BananaPiMachine(LinuxKernelTest): 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 ...'); + exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...') self.wait_for_console_pattern( 'Please press Enter to activate this console.') diff --git a/tests/functional/test_arm_canona1100.py b/tests/functional/arm/test_canona1100.py index 21a1a59..21a1a59 100755 --- a/tests/functional/test_arm_canona1100.py +++ b/tests/functional/arm/test_canona1100.py diff --git a/tests/functional/test_arm_collie.py b/tests/functional/arm/test_collie.py index fe1be3d..fe1be3d 100755 --- a/tests/functional/test_arm_collie.py +++ b/tests/functional/arm/test_collie.py diff --git a/tests/functional/test_arm_cubieboard.py b/tests/functional/arm/test_cubieboard.py index b87a281..b536c2f 100755 --- a/tests/functional/test_arm_cubieboard.py +++ b/tests/functional/arm/test_cubieboard.py @@ -4,8 +4,6 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os - 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 @@ -128,7 +126,7 @@ class CubieboardMachine(LinuxKernelTest): 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 ...'); + exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...') self.wait_for_console_pattern( 'Please press Enter to activate this console.') diff --git a/tests/functional/test_arm_emcraft_sf2.py b/tests/functional/arm/test_emcraft_sf2.py index f9f3f06..f9f3f06 100755 --- a/tests/functional/test_arm_emcraft_sf2.py +++ b/tests/functional/arm/test_emcraft_sf2.py diff --git a/tests/functional/test_arm_integratorcp.py b/tests/functional/arm/test_integratorcp.py index a85b339..23ae919 100755 --- a/tests/functional/test_arm_integratorcp.py +++ b/tests/functional/arm/test_integratorcp.py @@ -73,9 +73,10 @@ class IntegratorMachine(QemuSystemTest): 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) - logger = logging.getLogger('framebuffer') + res = self.vm.cmd('human-monitor-command', + command_line='screendump %s' % screendump_path) + if 'unknown command' in res: + self.skipTest('screendump not available') cpu_count = 1 match_threshold = 0.92 @@ -86,7 +87,7 @@ class IntegratorMachine(QemuSystemTest): loc = np.where(result >= match_threshold) tux_count = 0 for tux_count, pt in enumerate(zip(*loc[::-1]), start=1): - logger.debug('found Tux at position [x, y] = %s', pt) + self.log.debug('found Tux at position [x, y] = %s', pt) self.assertGreaterEqual(tux_count, cpu_count) if __name__ == '__main__': diff --git a/tests/functional/arm/test_max78000fthr.py b/tests/functional/arm/test_max78000fthr.py new file mode 100755 index 0000000..a82980b --- /dev/null +++ b/tests/functional/arm/test_max78000fthr.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# +# Functional test that checks the max78000fthr machine. +# Tests ICC, GCR, TRNG, AES, and UART +# +# 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 Max78000Machine(QemuSystemTest): + + ASSET_FW = Asset( + 'https://github.com/JacksonDonaldson/max78000Test/raw/main/build/max78000.bin', + '86940b4bf60931bc6a8aa5db4b9f7f3cf8f64dbbd7ac534647980e536cf3adf7') + + def test_fthr(self): + self.set_machine('max78000fthr') + fw_path = self.ASSET_FW.fetch() + self.vm.set_console() + self.vm.add_args('-kernel', fw_path) + self.vm.add_args('-device', "loader,file=" + fw_path + ",addr=0x10000000") + self.vm.launch() + + wait_for_console_pattern(self, 'started') + + # i -> prints instruction cache values + exec_command_and_wait_for_pattern(self, 'i', 'CTRL: 00010001') + + # r -> gcr resets the machine + exec_command_and_wait_for_pattern(self, 'r', 'started') + + # z -> sets some memory, then has gcr zero it + exec_command_and_wait_for_pattern(self, 'z', 'initial value: 12345678') + wait_for_console_pattern(self, "after memz: 00000000") + + # t -> runs trng + exec_command_and_wait_for_pattern(self, 't', 'random data:') + + # a -> runs aes + exec_command_and_wait_for_pattern(self, 'a', + 'encrypted to : a47ca9dd e0df4c86 a070af6e 91710dec') + wait_for_console_pattern(self, + 'encrypted to : cab7a28e bf456751 9049fcea 8960494b') + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/functional/test_arm_microbit.py b/tests/functional/arm/test_microbit.py index 68ea4e7..68ea4e7 100755 --- a/tests/functional/test_arm_microbit.py +++ b/tests/functional/arm/test_microbit.py diff --git a/tests/functional/arm/test_migration.py b/tests/functional/arm/test_migration.py new file mode 100755 index 0000000..0aa89f4 --- /dev/null +++ b/tests/functional/arm/test_migration.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# arm migration test + +from migration import MigrationTest + + +class ArmMigrationTest(MigrationTest): + + def test_migration_with_tcp_localhost(self): + self.set_machine('npcm750-evb') + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.set_machine('npcm750-evb') + self.migration_with_unix() + + def test_migration_with_exec(self): + self.set_machine('npcm750-evb') + self.migration_with_exec() + + +if __name__ == '__main__': + MigrationTest.main() diff --git a/tests/functional/test_arm_orangepi.py b/tests/functional/arm/test_orangepi.py index 1815f56..f9bfa8c 100755 --- a/tests/functional/test_arm_orangepi.py +++ b/tests/functional/arm/test_orangepi.py @@ -174,7 +174,7 @@ class OrangePiMachine(LinuxKernelTest): 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 ...'); + exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...') self.wait_for_console_pattern('systemd[1]: Hostname set ' + 'to <orangepipc>') diff --git a/tests/functional/test_arm_quanta_gsj.py b/tests/functional/arm/test_quanta_gsj.py index da60aeb..cb0545f 100755 --- a/tests/functional/test_arm_quanta_gsj.py +++ b/tests/functional/arm/test_quanta_gsj.py @@ -4,8 +4,6 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os - from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern from qemu_test import interrupt_interactive_console_until_pattern, skipSlowTest diff --git a/tests/functional/test_arm_raspi2.py b/tests/functional/arm/test_raspi2.py index d3c7aaa..d3c7aaa 100755 --- a/tests/functional/test_arm_raspi2.py +++ b/tests/functional/arm/test_raspi2.py diff --git a/tests/functional/arm/test_realview.py b/tests/functional/arm/test_realview.py new file mode 100755 index 0000000..82cc964 --- /dev/null +++ b/tests/functional/arm/test_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/arm/test_replay.py index e002e6a..e002e6a 100755 --- a/tests/functional/test_arm_replay.py +++ b/tests/functional/arm/test_replay.py diff --git a/tests/functional/test_arm_smdkc210.py b/tests/functional/arm/test_smdkc210.py index 0fda45c..3154e7f 100755 --- a/tests/functional/test_arm_smdkc210.py +++ b/tests/functional/arm/test_smdkc210.py @@ -4,8 +4,6 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os - from qemu_test import LinuxKernelTest, Asset diff --git a/tests/functional/arm/test_stellaris.py b/tests/functional/arm/test_stellaris.py new file mode 100755 index 0000000..cbd21cb --- /dev/null +++ b/tests/functional/arm/test_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/arm/test_sx1.py index 25800b3..25800b3 100755 --- a/tests/functional/test_arm_sx1.py +++ b/tests/functional/arm/test_sx1.py diff --git a/tests/functional/test_arm_tuxrun.py b/tests/functional/arm/test_tuxrun.py index 4ac85f4..4ac85f4 100755 --- a/tests/functional/test_arm_tuxrun.py +++ b/tests/functional/arm/test_tuxrun.py diff --git a/tests/functional/test_arm_vexpress.py b/tests/functional/arm/test_vexpress.py index 6b11552..6b11552 100755 --- a/tests/functional/test_arm_vexpress.py +++ b/tests/functional/arm/test_vexpress.py diff --git a/tests/functional/test_arm_virt.py b/tests/functional/arm/test_virt.py index 7b65491..7b65491 100755 --- a/tests/functional/test_arm_virt.py +++ b/tests/functional/arm/test_virt.py diff --git a/tests/functional/aspeed.py b/tests/functional/aspeed.py index 77dc893..47e84e0 100644 --- a/tests/functional/aspeed.py +++ b/tests/functional/aspeed.py @@ -8,8 +8,13 @@ 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') + cpu_id='0x0', soc='AST2500 rev A1', + image_hostname=None): + # Allow for the image hostname to not end in "-bmc" + if image_hostname is not None: + hostname = image_hostname + else: + hostname = machine.removesuffix('-bmc') self.set_machine(machine) self.vm.set_console() @@ -44,7 +49,7 @@ class AspeedTest(LinuxKernelTest): def do_test_arm_aspeed_buildroot_poweroff(self): exec_command_and_wait_for_pattern(self, 'poweroff', - 'System halted'); + 'System halted') def do_test_arm_aspeed_sdk_start(self, image): self.require_netdev('user') @@ -56,3 +61,11 @@ class AspeedTest(LinuxKernelTest): 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 ...') + + def generate_otpmem_image(self): + path = self.scratch_file("otpmem.img") + pattern = b'\x00\x00\x00\x00\xff\xff\xff\xff' * (16 * 1024 // 8) + with open(path, "wb") as f: + f.write(pattern) + return path + diff --git a/tests/functional/avr/meson.build b/tests/functional/avr/meson.build new file mode 100644 index 0000000..7a2cb70 --- /dev/null +++ b/tests/functional/avr/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_avr_system_thorough = [ + 'mega2560', + 'uno', +] diff --git a/tests/functional/test_avr_mega2560.py b/tests/functional/avr/test_mega2560.py index 8e47b42..6359b72 100755 --- a/tests/functional/test_avr_mega2560.py +++ b/tests/functional/avr/test_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/avr/test_uno.py b/tests/functional/avr/test_uno.py new file mode 100755 index 0000000..adb3b73 --- /dev/null +++ b/tests/functional/avr/test_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/generic/meson.build b/tests/functional/generic/meson.build new file mode 100644 index 0000000..013cc96 --- /dev/null +++ b/tests/functional/generic/meson.build @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_generic_system = [ + 'empty_cpu_model', + 'info_usernet', + 'version', + 'vnc', +] + +tests_generic_linuxuser = [ +] + +tests_generic_bsduser = [ +] diff --git a/tests/functional/test_empty_cpu_model.py b/tests/functional/generic/test_empty_cpu_model.py index 0081b06..0081b06 100755 --- a/tests/functional/test_empty_cpu_model.py +++ b/tests/functional/generic/test_empty_cpu_model.py diff --git a/tests/functional/test_info_usernet.py b/tests/functional/generic/test_info_usernet.py index e8cbc37..e8cbc37 100755 --- a/tests/functional/test_info_usernet.py +++ b/tests/functional/generic/test_info_usernet.py diff --git a/tests/functional/test_version.py b/tests/functional/generic/test_version.py index 3ab3b67..3ab3b67 100755 --- a/tests/functional/test_version.py +++ b/tests/functional/generic/test_version.py diff --git a/tests/functional/generic/test_vmstate.py b/tests/functional/generic/test_vmstate.py new file mode 100755 index 0000000..387ff54 --- /dev/null +++ b/tests/functional/generic/test_vmstate.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +'''This test runs the vmstate-static-checker script with the current QEMU''' + +import subprocess + +from qemu_test import QemuSystemTest, skipFlakyTest + + +@skipFlakyTest("vmstate-static-checker can produce false positives") +class VmStateTest(QemuSystemTest): + ''' + This test helps to check whether there are problems between old + reference data and the current QEMU + ''' + + def test_vmstate_7_2(self): + '''Check reference data from QEMU v7.2''' + + target_machine = { + 'aarch64': 'virt-7.2', + 'm68k': 'virt-7.2', + 'ppc64': 'pseries-7.2', + 's390x': 's390-ccw-virtio-7.2', + 'x86_64': 'pc-q35-7.2', + } + self.set_machine(target_machine[self.arch]) + + # Run QEMU to get the current vmstate json file: + dst_json = self.scratch_file('dest.json') + self.log.info('Dumping vmstate from %s', self.qemu_bin) + cp = subprocess.run([self.qemu_bin, '-nodefaults', + '-M', target_machine[self.arch], + '-dump-vmstate', dst_json], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, check=True) + if cp.stdout: + self.log.info('QEMU output: %s', cp.stdout) + + # Check whether the old vmstate json file is still compatible: + src_json = self.data_file('..', 'data', 'vmstate-static-checker', + self.arch, + target_machine[self.arch] + '.json') + self.log.info('Comparing vmstate with %s', src_json) + checkerscript = self.data_file('..', '..', 'scripts', + 'vmstate-static-checker.py') + cp = subprocess.run([checkerscript, '-s', src_json, '-d', dst_json], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, check=False) + if cp.returncode != 0: + self.fail('Running vmstate-static-checker failed:\n' + cp.stdout + + '\nThis either means that there is a migration bug ' + 'that needs to be fixed, or\nvmstate-static-checker.py ' + 'needs to be improved (e.g. extend the changed_names\n' + 'in case a field has been renamed), or drop the ' + 'problematic field from\n' + src_json + + '\nin case the script cannot be fixed easily.') + if cp.stdout: + self.log.warning('vmstate-static-checker output: %s', cp.stdout) + + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/functional/test_vnc.py b/tests/functional/generic/test_vnc.py index 8c9953b..f1dd159 100755 --- a/tests/functional/test_vnc.py +++ b/tests/functional/generic/test_vnc.py @@ -11,12 +11,12 @@ # later. See the COPYING file in the top-level directory. import socket -from typing import List -from qemu.machine.machine import VMLaunchFailure +from qemu.machine.machine import VMLaunchFailure from qemu_test import QemuSystemTest from qemu_test.ports import Ports + VNC_ADDR = '127.0.0.1' def check_connect(port: int) -> bool: @@ -31,6 +31,7 @@ def check_connect(port: int) -> bool: class Vnc(QemuSystemTest): def test_no_vnc_change_password(self): + self.set_machine('none') self.vm.add_args('-nodefaults', '-S') self.vm.launch() @@ -55,11 +56,14 @@ class Vnc(QemuSystemTest): 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.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']) @@ -72,6 +76,7 @@ class Vnc(QemuSystemTest): 'Could not set password') def test_change_password(self): + 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']) @@ -101,6 +106,7 @@ class Vnc(QemuSystemTest): 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) diff --git a/tests/functional/hppa/meson.build b/tests/functional/hppa/meson.build new file mode 100644 index 0000000..df2f7cc --- /dev/null +++ b/tests/functional/hppa/meson.build @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_hppa_system_quick = [ + 'seabios', +] + +tests_hppa_system_thorough = [ + 'cdboot', +] diff --git a/tests/functional/hppa/test_cdboot.py b/tests/functional/hppa/test_cdboot.py new file mode 100755 index 0000000..84421e8 --- /dev/null +++ b/tests/functional/hppa/test_cdboot.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# +# CD boot test for HPPA 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 HppaCdBoot(QemuSystemTest): + + ASSET_CD = Asset( + ('https://github.com/philmd/qemu-testing-blob/raw/ec1b741/' + 'hppa/hp9000/712/C7120023.frm'), + '32c612ad2074516986bdc27768903c561fa92af2ca48e5ac3f3359ade1c42f70') + + def test_cdboot(self): + self.set_machine('B160L') + cdrom_path = self.ASSET_CD.fetch() + + self.vm.set_console() + self.vm.add_args('-cdrom', cdrom_path, + '-boot', 'd', + '-no-reboot') + self.vm.launch() + wait_for_console_pattern(self, 'Unrecognized MODEL TYPE = 502') + wait_for_console_pattern(self, 'UPDATE PAUSED>') + + exec_command_and_wait_for_pattern(self, 'exit\r', 'UPDATE>') + exec_command_and_wait_for_pattern(self, 'ls\r', 'IMAGE1B') + wait_for_console_pattern(self, 'UPDATE>') + exec_command_and_wait_for_pattern(self, 'exit\r', + 'THIS UTILITY WILL NOW RESET THE SYSTEM.....') + + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/functional/test_hppa_seabios.py b/tests/functional/hppa/test_seabios.py index a44d1a3..661b246 100755 --- a/tests/functional/test_hppa_seabios.py +++ b/tests/functional/hppa/test_seabios.py @@ -17,9 +17,9 @@ class HppaSeabios(QemuSystemTest): 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() - self.machine wait_for_console_pattern(self, f'SeaBIOS PA-RISC {bits}-bit Firmware') wait_for_console_pattern(self, f'Emulated machine: HP {mach} ({bits}-bit') diff --git a/tests/functional/i386/meson.build b/tests/functional/i386/meson.build new file mode 100644 index 0000000..23d8c21 --- /dev/null +++ b/tests/functional/i386/meson.build @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_i386_system_quick = [ + 'migration', +] + +tests_i386_system_thorough = [ + 'replay', + 'tuxrun', +] diff --git a/tests/functional/i386/test_migration.py b/tests/functional/i386/test_migration.py new file mode 100755 index 0000000..a57f316 --- /dev/null +++ b/tests/functional/i386/test_migration.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# i386 migration test + +from migration import MigrationTest + + +class I386MigrationTest(MigrationTest): + + def test_migration_with_tcp_localhost(self): + self.set_machine('isapc') + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.set_machine('isapc') + self.migration_with_unix() + + def test_migration_with_exec(self): + self.set_machine('isapc') + self.migration_with_exec() + + +if __name__ == '__main__': + MigrationTest.main() diff --git a/tests/functional/i386/test_replay.py b/tests/functional/i386/test_replay.py new file mode 100755 index 0000000..7c4c260 --- /dev/null +++ b/tests/functional/i386/test_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/i386/test_tuxrun.py index f3ccf11..f3ccf11 100755 --- a/tests/functional/test_i386_tuxrun.py +++ b/tests/functional/i386/test_tuxrun.py diff --git a/tests/functional/loongarch64/meson.build b/tests/functional/loongarch64/meson.build new file mode 100644 index 0000000..d168717 --- /dev/null +++ b/tests/functional/loongarch64/meson.build @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_loongarch64_system_thorough = [ + 'virt', +] diff --git a/tests/functional/test_loongarch64_virt.py b/tests/functional/loongarch64/test_virt.py index b7d9abf..b7d9abf 100755 --- a/tests/functional/test_loongarch64_virt.py +++ b/tests/functional/loongarch64/test_virt.py diff --git a/tests/functional/m68k/meson.build b/tests/functional/m68k/meson.build new file mode 100644 index 0000000..679faaf --- /dev/null +++ b/tests/functional/m68k/meson.build @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_m68k_system_quick = [ + 'vmstate', +] + +tests_m68k_system_thorough = [ + 'mcf5208evb', + 'nextcube', + 'replay', + 'q800', + 'tuxrun', +] diff --git a/tests/functional/test_m68k_mcf5208evb.py b/tests/functional/m68k/test_mcf5208evb.py index c7d1998..c7d1998 100755 --- a/tests/functional/test_m68k_mcf5208evb.py +++ b/tests/functional/m68k/test_mcf5208evb.py diff --git a/tests/functional/test_m68k_nextcube.py b/tests/functional/m68k/test_nextcube.py index ff773a7..e5e1c69 100755 --- a/tests/functional/test_m68k_nextcube.py +++ b/tests/functional/m68k/test_nextcube.py @@ -29,11 +29,20 @@ class NextCubeMachine(QemuSystemTest): self.vm.launch() self.log.info('VM launched, waiting for display') - # TODO: wait for the 'displaysurface_create 1120x832' trace-event. - time.sleep(2) + # Wait for the FPU test to finish, then the display is available, too: + while True: + res = self.vm.cmd('human-monitor-command', + command_line='info registers') + if ("F0 = 400e 8400000000000000" in res and + "F1 = 400e 83ff000000000000" in res and + "F2 = 400e 83ff000000000000" in res): + break + time.sleep(0.1) - 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') @skipIfMissingImports("PIL") def test_bootrom_framebuffer_size(self): @@ -42,7 +51,8 @@ class NextCubeMachine(QemuSystemTest): self.check_bootrom_framebuffer(screenshot_path) from PIL import Image - width, height = Image.open(screenshot_path).size + with Image.open(screenshot_path) as image: + width, height = image.size self.assertEqual(width, 1120) self.assertEqual(height, 832) @@ -53,10 +63,10 @@ class NextCubeMachine(QemuSystemTest): self.check_bootrom_framebuffer(screenshot_path) lines = tesseract_ocr(screenshot_path) text = '\n'.join(lines) + self.assertIn('Backplane slot', text) + self.assertIn('Ethernet address', text) self.assertIn('Testing the FPU', text) - self.assertIn('System test failed. Error code', text) - self.assertIn('Boot command', text) - self.assertIn('Next>', text) + if __name__ == '__main__': QemuSystemTest.main() diff --git a/tests/functional/test_m68k_q800.py b/tests/functional/m68k/test_q800.py index 400b7ae..b3e6553 100755 --- a/tests/functional/test_m68k_q800.py +++ b/tests/functional/m68k/test_q800.py @@ -25,7 +25,8 @@ class Q800MachineTest(LinuxKernelTest): kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0 vga=off') self.vm.add_args('-kernel', kernel_path, - '-append', kernel_command_line) + '-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) diff --git a/tests/functional/test_m68k_replay.py b/tests/functional/m68k/test_replay.py index 18c1db5..213d6ae 100755 --- a/tests/functional/test_m68k_replay.py +++ b/tests/functional/m68k/test_replay.py @@ -24,7 +24,8 @@ class M68kReplay(ReplayKernelBase): 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) + 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', diff --git a/tests/functional/test_m68k_tuxrun.py b/tests/functional/m68k/test_tuxrun.py index 7eacba1..7eacba1 100755 --- a/tests/functional/test_m68k_tuxrun.py +++ b/tests/functional/m68k/test_tuxrun.py diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 0f8be30..725630d 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -9,315 +9,34 @@ if get_option('tcg_interpreter') subdir_done() endif -# Timeouts for individual tests that can be slow e.g. with debugging enabled -test_timeouts = { - 'aarch64_aspeed' : 600, - 'aarch64_raspi4' : 480, - 'aarch64_rme_virt' : 1200, - 'aarch64_rme_sbsaref' : 1200, - 'aarch64_sbsaref_alpine' : 1200, - 'aarch64_sbsaref_freebsd' : 720, - 'aarch64_tuxrun' : 240, - 'aarch64_virt' : 360, - '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' : 120, - 'mipsel_replay' : 480, - 'mips64el_replay' : 180, - 'netdev_ethtool' : 180, - 'ppc_40p' : 240, - 'ppc64_hv' : 1000, - '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 = [ - 'empty_cpu_model', - 'info_usernet', - 'version', -] - -tests_generic_linuxuser = [ -] - -tests_generic_bsduser = [ -] - -tests_aarch64_system_quick = [ - 'migration', -] - -tests_aarch64_system_thorough = [ - 'aarch64_aspeed', - 'aarch64_raspi3', - 'aarch64_raspi4', - 'aarch64_replay', - 'aarch64_rme_virt', - 'aarch64_rme_sbsaref', - 'aarch64_sbsaref', - 'aarch64_sbsaref_alpine', - 'aarch64_sbsaref_freebsd', - '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_replay', - 'arm_smdkc210', - 'arm_sx1', - 'arm_vexpress', - 'arm_virt', - 'arm_tuxrun', -] - -tests_arm_linuxuser_thorough = [ - 'arm_bflt', -] - -tests_avr_system_thorough = [ - 'avr_mega2560', -] - -tests_hppa_system_quick = [ - 'hppa_seabios', -] - -tests_i386_system_quick = [ - 'migration', -] - -tests_i386_system_thorough = [ - 'i386_tuxrun', -] - -tests_loongarch64_system_thorough = [ - 'loongarch64_virt', -] - -tests_m68k_system_thorough = [ - 'm68k_mcf5208evb', - 'm68k_nextcube', - 'm68k_replay', - 'm68k_q800', - 'm68k_tuxrun', -] - -tests_microblaze_system_thorough = [ - 'microblaze_replay', - 'microblaze_s3adsp1800' -] - -tests_microblazeel_system_thorough = [ - 'microblazeel_s3adsp1800' -] - -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_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_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_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 = [ - 'rx_gdbsim', -] - -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', -] - -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_tuxrun', -] - -tests_xtensa_system_thorough = [ - 'xtensa_lx60', - 'xtensa_replay', -] +subdir('aarch64') +subdir('alpha') +subdir('arm') +subdir('avr') +subdir('hppa') +subdir('i386') +subdir('loongarch64') +subdir('m68k') +subdir('microblaze') +subdir('microblazeel') +subdir('mips') +subdir('mipsel') +subdir('mips64') +subdir('mips64el') +subdir('or1k') +subdir('ppc') +subdir('ppc64') +subdir('riscv32') +subdir('riscv64') +subdir('rx') +subdir('s390x') +subdir('sh4') +subdir('sh4eb') +subdir('sparc') +subdir('sparc64') +subdir('x86_64') +subdir('xtensa') +subdir('generic') precache_all = [] foreach speed : ['quick', 'thorough'] @@ -347,7 +66,7 @@ foreach speed : ['quick', 'thorough'] target_tests = get_variable('tests_' + target_base + '_' + sysmode + '_' + speed, []) endif - test_deps = roms + test_deps = [roms, keymap_targets] test_env = environment() if have_tools test_env.set('QEMU_TEST_QEMU_IMG', meson.global_build_root() / 'qemu-img') @@ -358,9 +77,19 @@ foreach speed : ['quick', 'thorough'] test_env.set('PYTHONPATH', meson.project_source_root() / 'python:' + meson.current_source_dir()) + # Define the GDB environment variable if gdb is available. + gdb = get_option('gdb') + if gdb != '' + test_env.set('QEMU_TEST_GDB', gdb) + endif + foreach test : target_tests testname = '@0@-@1@'.format(target_base, test) - testfile = 'test_' + test + '.py' + if fs.exists('generic' / 'test_' + test + '.py') + testfile = 'generic' / 'test_' + test + '.py' + else + testfile = target_base / 'test_' + test + '.py' + endif testpath = meson.current_source_dir() / testfile teststamp = testname + '.tstamp' test_precache_env = environment() @@ -374,6 +103,11 @@ foreach speed : ['quick', 'thorough'] build_by_default: false, env: test_precache_env) precache_all += precache + if is_variable('test_' + target_base + '_timeouts') + time_out = get_variable('test_' + target_base + '_timeouts').get(test, 90) + else + time_out = 90 + endif # Ideally we would add 'precache' to 'depends' here, such that # 'build_by_default: false' lets the pre-caching automatically @@ -389,8 +123,8 @@ foreach speed : ['quick', 'thorough'] env: test_env, args: [testpath], protocol: 'tap', - timeout: test_timeouts.get(test, 90), - priority: test_timeouts.get(test, 90), + timeout: time_out, + priority: time_out, suite: suites) endforeach endforeach @@ -398,4 +132,4 @@ endforeach run_target('precache-functional', depends: precache_all, - command: ['true']) + command: [python, '-c', '']) diff --git a/tests/functional/microblaze/meson.build b/tests/functional/microblaze/meson.build new file mode 100644 index 0000000..8069ca9 --- /dev/null +++ b/tests/functional/microblaze/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_microblaze_system_thorough = [ + 'replay', + 's3adsp1800' +] diff --git a/tests/functional/test_microblaze_replay.py b/tests/functional/microblaze/test_replay.py index 7484c41..7484c41 100755 --- a/tests/functional/test_microblaze_replay.py +++ b/tests/functional/microblaze/test_replay.py diff --git a/tests/functional/test_microblaze_s3adsp1800.py b/tests/functional/microblaze/test_s3adsp1800.py index c93fa14..f093b16 100755 --- a/tests/functional/test_microblaze_s3adsp1800.py +++ b/tests/functional/microblaze/test_s3adsp1800.py @@ -25,12 +25,14 @@ class MicroblazeMachine(QemuSystemTest): ('http://www.qemu-advent-calendar.org/2023/download/day13.tar.gz'), 'b9b3d43c5dd79db88ada495cc6e0d1f591153fe41355e925d791fbf44de50c22') - def do_ballerina_be_test(self, machine): - self.set_machine(machine) + def do_ballerina_be_test(self, force_endianness=False): + self.set_machine('petalogix-s3adsp1800') self.archive_extract(self.ASSET_IMAGE_BE) self.vm.set_console() 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') @@ -39,12 +41,14 @@ 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, machine): + def do_xmaton_le_test(self, force_endianness=False): self.require_netdev('user') - self.set_machine(machine) + 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() @@ -59,9 +63,13 @@ class MicroblazeMachine(QemuSystemTest): 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('petalogix-s3adsp1800') + self.do_ballerina_be_test() + + def test_microblaze_s3adsp1800_legacy_le(self): + self.do_xmaton_le_test(force_endianness=True) if __name__ == '__main__': diff --git a/tests/functional/microblazeel/meson.build b/tests/functional/microblazeel/meson.build new file mode 100644 index 0000000..27619dc --- /dev/null +++ b/tests/functional/microblazeel/meson.build @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_microblazeel_system_thorough = [ + 's3adsp1800' +] diff --git a/tests/functional/test_microblazeel_s3adsp1800.py b/tests/functional/microblazeel/test_s3adsp1800.py index ab59941..75ce885 100755 --- a/tests/functional/test_microblazeel_s3adsp1800.py +++ b/tests/functional/microblazeel/test_s3adsp1800.py @@ -7,15 +7,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. -from test_microblaze_s3adsp1800 import MicroblazeMachine +from microblaze.test_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('petalogix-s3adsp1800') + self.do_xmaton_le_test() + + def test_microblaze_s3adsp1800_legacy_be(self): + self.do_ballerina_be_test(force_endianness=True) if __name__ == '__main__': diff --git a/tests/functional/test_migration.py b/tests/functional/migration.py index 181223a..0739554 100755..100644 --- a/tests/functional/test_migration.py +++ b/tests/functional/migration.py @@ -1,6 +1,6 @@ -#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later # -# Migration test +# Migration test base class # # Copyright (c) 2019 Red Hat, Inc. # @@ -11,14 +11,13 @@ # 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 import time -from qemu_test import QemuSystemTest, skipIfMissingCommands +from qemu_test import QemuSystemTest, which from qemu_test.ports import Ports + class MigrationTest(QemuSystemTest): timeout = 10 @@ -42,24 +41,7 @@ class MigrationTest(QemuSystemTest): 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() @@ -77,23 +59,21 @@ class MigrationTest(QemuSystemTest): self.skipTest('Failed to find a free port') return port - def test_migration_with_tcp_localhost(self): + def 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): + 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) - @skipIfMissingCommands('ncat') - def test_migration_with_exec(self): + def migration_with_exec(self): + if not which('ncat'): + self.skipTest('ncat is not available') 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/mips/meson.build b/tests/functional/mips/meson.build new file mode 100644 index 0000000..49aaf53 --- /dev/null +++ b/tests/functional/mips/meson.build @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +test_mips_timeouts = { + 'malta' : 480, +} + +tests_mips_system_thorough = [ + 'malta', + 'replay', + 'tuxrun', +] diff --git a/tests/functional/mips/test_malta.py b/tests/functional/mips/test_malta.py new file mode 100755 index 0000000..30279f0 --- /dev/null +++ b/tests/functional/mips/test_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/mips/test_replay.py index eda031c..4327481 100755 --- a/tests/functional/test_mips_replay.py +++ b/tests/functional/mips/test_replay.py @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -from qemu_test import Asset, skipSlowTest, exec_command_and_wait_for_pattern +from qemu_test import Asset, skipSlowTest from replay_kernel import ReplayKernelBase diff --git a/tests/functional/test_mips_tuxrun.py b/tests/functional/mips/test_tuxrun.py index 6771dbd..6771dbd 100755 --- a/tests/functional/test_mips_tuxrun.py +++ b/tests/functional/mips/test_tuxrun.py diff --git a/tests/functional/mips64/meson.build b/tests/functional/mips64/meson.build new file mode 100644 index 0000000..3ff2118 --- /dev/null +++ b/tests/functional/mips64/meson.build @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +test_mips64_timeouts = { + 'malta' : 240, +} + +tests_mips64_system_thorough = [ + 'malta', + 'tuxrun', +] diff --git a/tests/functional/mips64/test_malta.py b/tests/functional/mips64/test_malta.py new file mode 100755 index 0000000..a553d3c --- /dev/null +++ b/tests/functional/mips64/test_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 mips.test_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/mips64/test_tuxrun.py index 0e4c659..0e4c659 100755 --- a/tests/functional/test_mips64_tuxrun.py +++ b/tests/functional/mips64/test_tuxrun.py diff --git a/tests/functional/mips64el/meson.build b/tests/functional/mips64el/meson.build new file mode 100644 index 0000000..69ec501 --- /dev/null +++ b/tests/functional/mips64el/meson.build @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +test_mips64el_timeouts = { + 'malta' : 420, + 'replay' : 180, +} + +tests_mips64el_system_thorough = [ + 'fuloong2e', + 'loongson3v', + 'malta', + 'replay', + 'tuxrun', +] diff --git a/tests/functional/test_mips64el_fuloong2e.py b/tests/functional/mips64el/test_fuloong2e.py index 35e500b..35e500b 100755 --- a/tests/functional/test_mips64el_fuloong2e.py +++ b/tests/functional/mips64el/test_fuloong2e.py diff --git a/tests/functional/test_mips64el_loongson3v.py b/tests/functional/mips64el/test_loongson3v.py index f85371e..f85371e 100755 --- a/tests/functional/test_mips64el_loongson3v.py +++ b/tests/functional/mips64el/test_loongson3v.py diff --git a/tests/functional/test_mips64el_malta.py b/tests/functional/mips64el/test_malta.py index a8da15a..170147b 100755 --- a/tests/functional/test_mips64el_malta.py +++ b/tests/functional/mips64el/test_malta.py @@ -16,6 +16,8 @@ from qemu_test import LinuxKernelTest, Asset from qemu_test import exec_command_and_wait_for_pattern from qemu_test import skipIfMissingImports, skipFlakyTest, skipUntrustedTest +from mips.test_malta import mips_check_wheezy + class MaltaMachineConsole(LinuxKernelTest): @@ -90,6 +92,26 @@ class MaltaMachineConsole(LinuxKernelTest): # 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): @@ -133,9 +155,10 @@ class MaltaMachineFramebuffer(LinuxKernelTest): 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') - self.vm.cmd('human-monitor-command', - command_line='screendump %s' % screendump_path) - logger = logging.getLogger('framebuffer') + res = self.vm.cmd('human-monitor-command', + command_line='screendump %s' % screendump_path) + if 'unknown command' in res: + self.skipTest('screendump not available') match_threshold = 0.95 screendump_bgr = cv2.imread(screendump_path, cv2.IMREAD_COLOR) @@ -147,7 +170,7 @@ class MaltaMachineFramebuffer(LinuxKernelTest): 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) + self.log.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: @@ -167,7 +190,7 @@ class MaltaMachineFramebuffer(LinuxKernelTest): self.do_test_i6400_framebuffer_logo(8) -from test_mipsel_malta import MaltaMachineYAMON +from mipsel.test_malta import MaltaMachineYAMON if __name__ == '__main__': LinuxKernelTest.main() diff --git a/tests/functional/test_mips64el_replay.py b/tests/functional/mips64el/test_replay.py index 4f63d7f..26a6ccf 100755 --- a/tests/functional/test_mips64el_replay.py +++ b/tests/functional/mips64el/test_replay.py @@ -4,11 +4,7 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os -import logging - -from qemu_test import Asset, exec_command_and_wait_for_pattern -from qemu_test import skipIfMissingImports, skipFlakyTest, skipUntrustedTest +from qemu_test import Asset, skipUntrustedTest from replay_kernel import ReplayKernelBase diff --git a/tests/functional/test_mips64el_tuxrun.py b/tests/functional/mips64el/test_tuxrun.py index 0a24757..0a24757 100755 --- a/tests/functional/test_mips64el_tuxrun.py +++ b/tests/functional/mips64el/test_tuxrun.py diff --git a/tests/functional/mipsel/meson.build b/tests/functional/mipsel/meson.build new file mode 100644 index 0000000..8bfdf06 --- /dev/null +++ b/tests/functional/mipsel/meson.build @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +test_mipsel_timeouts = { + 'malta' : 420, + 'replay' : 480, +} + +tests_mipsel_system_thorough = [ + 'malta', + 'replay', + 'tuxrun', +] diff --git a/tests/functional/test_mipsel_malta.py b/tests/functional/mipsel/test_malta.py index fe9c3a1..427e163 100755 --- a/tests/functional/test_mipsel_malta.py +++ b/tests/functional/mipsel/test_malta.py @@ -13,6 +13,8 @@ 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 mips.test_malta import mips_check_wheezy + class MaltaMachineConsole(LinuxKernelTest): @@ -57,6 +59,26 @@ class MaltaMachineConsole(LinuxKernelTest): 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): diff --git a/tests/functional/test_mipsel_replay.py b/tests/functional/mipsel/test_replay.py index 0a330de..5f4796c 100644..100755 --- a/tests/functional/test_mipsel_replay.py +++ b/tests/functional/mipsel/test_replay.py @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -from qemu_test import Asset, wait_for_console_pattern, skipSlowTest +from qemu_test import Asset, skipSlowTest from replay_kernel import ReplayKernelBase diff --git a/tests/functional/test_mipsel_tuxrun.py b/tests/functional/mipsel/test_tuxrun.py index d4b39ba..d4b39ba 100755 --- a/tests/functional/test_mipsel_tuxrun.py +++ b/tests/functional/mipsel/test_tuxrun.py diff --git a/tests/functional/test_multiprocess.py b/tests/functional/multiprocess.py index 751cf10..6a06c1e 100755..100644 --- a/tests/functional/test_multiprocess.py +++ b/tests/functional/multiprocess.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later # # Test for multiprocess qemu # @@ -9,33 +9,13 @@ import os import socket -from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern +from qemu_test import QemuSystemTest, 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""" @@ -83,18 +63,5 @@ class Multiprocess(QemuSystemTest): '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() + proxy_sock.close() + remote_sock.close() diff --git a/tests/functional/or1k/meson.build b/tests/functional/or1k/meson.build new file mode 100644 index 0000000..e246e2a --- /dev/null +++ b/tests/functional/or1k/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_or1k_system_thorough = [ + 'replay', + 'sim', +] diff --git a/tests/functional/test_or1k_replay.py b/tests/functional/or1k/test_replay.py index 2b60a93..2b60a93 100755 --- a/tests/functional/test_or1k_replay.py +++ b/tests/functional/or1k/test_replay.py diff --git a/tests/functional/test_or1k_sim.py b/tests/functional/or1k/test_sim.py index f9f0b69..f9f0b69 100755 --- a/tests/functional/test_or1k_sim.py +++ b/tests/functional/or1k/test_sim.py diff --git a/tests/functional/ppc/meson.build b/tests/functional/ppc/meson.build new file mode 100644 index 0000000..ae061fe --- /dev/null +++ b/tests/functional/ppc/meson.build @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +test_ppc_timeouts = { + '40p' : 240, +} + +tests_ppc_system_quick = [ + 'migration', + '74xx', +] + +tests_ppc_system_thorough = [ + '40p', + 'amiga', + 'bamboo', + 'mac', + 'mpc8544ds', + 'ppe42', + 'replay', + 'sam460ex', + 'tuxrun', + 'virtex_ml507', +] diff --git a/tests/functional/test_ppc_40p.py b/tests/functional/ppc/test_40p.py index 614972a..614972a 100755 --- a/tests/functional/test_ppc_40p.py +++ b/tests/functional/ppc/test_40p.py diff --git a/tests/functional/test_ppc_74xx.py b/tests/functional/ppc/test_74xx.py index 5386016..5386016 100755 --- a/tests/functional/test_ppc_74xx.py +++ b/tests/functional/ppc/test_74xx.py diff --git a/tests/functional/test_ppc_amiga.py b/tests/functional/ppc/test_amiga.py index 8600e2e..8600e2e 100755 --- a/tests/functional/test_ppc_amiga.py +++ b/tests/functional/ppc/test_amiga.py diff --git a/tests/functional/ppc/test_bamboo.py b/tests/functional/ppc/test_bamboo.py new file mode 100755 index 0000000..c634ae7 --- /dev/null +++ b/tests/functional/ppc/test_bamboo.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# +# Test that Linux kernel boots on the ppc bamboo board and check the console +# +# Copyright (c) 2021 Red Hat +# +# 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 BambooMachine(QemuSystemTest): + + timeout = 90 + + ASSET_KERNEL = Asset( + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/' + 'buildroot/qemu_ppc_bamboo-2023.11-8-gdcd9f0f6eb-20240105/vmlinux'), + 'a2e12eb45b73491ac62fc0bbeb68dead0dc5c0f22cf83146558389209b420ad1') + ASSET_INITRD = Asset( + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/' + 'buildroot/qemu_ppc_bamboo-2023.11-8-gdcd9f0f6eb-20240105/rootfs.cpio'), + 'd2a36bdb8763b389765dc8c29d4904cec2bd001c587f92e85ab9eb10d5ddda54') + + def test_ppc_bamboo(self): + self.set_machine('bamboo') + self.require_accelerator("tcg") + self.require_netdev('user') + + kernel = self.ASSET_KERNEL.fetch() + initrd = self.ASSET_INITRD.fetch() + + self.vm.set_console() + self.vm.add_args('-kernel', kernel, + '-initrd', initrd, + '-nic', 'user,model=virtio-net-pci,restrict=on') + self.vm.launch() + wait_for_console_pattern(self, 'buildroot login:') + exec_command_and_wait_for_pattern(self, 'root', '#') + exec_command_and_wait_for_pattern(self, 'ping -c1 10.0.2.2', + '1 packets transmitted, 1 packets received, 0% packet loss') + exec_command_and_wait_for_pattern(self, 'halt', 'System Halted') + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/functional/test_ppc_mac.py b/tests/functional/ppc/test_mac.py index 9e4bc1a..9e4bc1a 100755 --- a/tests/functional/test_ppc_mac.py +++ b/tests/functional/ppc/test_mac.py diff --git a/tests/functional/ppc/test_migration.py b/tests/functional/ppc/test_migration.py new file mode 100755 index 0000000..a869282 --- /dev/null +++ b/tests/functional/ppc/test_migration.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# ppc migration test + +from migration import MigrationTest + + +class PpcMigrationTest(MigrationTest): + + def test_migration_with_tcp_localhost(self): + self.set_machine('sam460ex') + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.set_machine('sam460ex') + self.migration_with_unix() + + def test_migration_with_exec(self): + self.set_machine('sam460ex') + self.migration_with_exec() + + +if __name__ == '__main__': + MigrationTest.main() diff --git a/tests/functional/test_ppc_mpc8544ds.py b/tests/functional/ppc/test_mpc8544ds.py index 0715410..0715410 100755 --- a/tests/functional/test_ppc_mpc8544ds.py +++ b/tests/functional/ppc/test_mpc8544ds.py diff --git a/tests/functional/ppc/test_ppe42.py b/tests/functional/ppc/test_ppe42.py new file mode 100644 index 0000000..26bbe11 --- /dev/null +++ b/tests/functional/ppc/test_ppe42.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# +# Functional tests for the IBM PPE42 processor +# +# Copyright (c) 2025, IBM Corporation +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import QemuSystemTest, Asset +import asyncio + +class Ppe42Machine(QemuSystemTest): + + timeout = 90 + poll_period = 1.0 + + ASSET_PPE42_TEST_IMAGE = Asset( + ('https://github.com/milesg-github/ppe42-tests/raw/refs/heads/main/' + 'images/ppe42-test.out'), + '03c1ac0fb7f6c025102a02776a93b35101dae7c14b75e4eab36a337e39042ea8') + + def _test_completed(self): + self.log.info("Checking for test completion...") + try: + output = self.vm.cmd('human-monitor-command', + command_line='info registers') + except Exception as err: + self.log.debug(f"'info registers' cmd failed due to {err=}," + " {type(err)=}") + raise + + self.log.info(output) + if "NIP fff80200" in output: + self.log.info("<test completed>") + return True + else: + self.log.info("<test not completed>") + return False + + def _wait_pass_fail(self, timeout): + while not self._test_completed(): + if timeout >= self.poll_period: + timeout = timeout - self.poll_period + self.log.info(f"Waiting {self.poll_period} seconds for test" + " to complete...") + e = None + try: + e = self.vm.event_wait('STOP', self.poll_period) + + except asyncio.TimeoutError: + self.log.info("Poll period ended.") + pass + + except Exception as err: + self.log.debug(f"event_wait() failed due to {err=}," + " {type(err)=}") + raise + + if e != None: + self.log.debug(f"Execution stopped: {e}") + self.log.debug("Exiting due to test failure") + self.fail("Failure detected!") + break + else: + self.fail("Timed out waiting for test completion.") + + def test_ppe42_instructions(self): + self.set_machine('ppe42_machine') + self.require_accelerator("tcg") + image_path = self.ASSET_PPE42_TEST_IMAGE.fetch() + self.vm.add_args('-nographic') + self.vm.add_args('-device', f'loader,file={image_path}') + self.vm.add_args('-device', 'loader,addr=0xfff80040,cpu-num=0') + self.vm.add_args('-action', 'panic=pause') + self.vm.launch() + self._wait_pass_fail(self.timeout) + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/functional/test_ppc_replay.py b/tests/functional/ppc/test_replay.py index 8382070..8382070 100755 --- a/tests/functional/test_ppc_replay.py +++ b/tests/functional/ppc/test_replay.py diff --git a/tests/functional/test_ppc_sam460ex.py b/tests/functional/ppc/test_sam460ex.py index 31cf9dd..31cf9dd 100644..100755 --- a/tests/functional/test_ppc_sam460ex.py +++ b/tests/functional/ppc/test_sam460ex.py diff --git a/tests/functional/test_ppc_tuxrun.py b/tests/functional/ppc/test_tuxrun.py index 5458a7f..5458a7f 100755 --- a/tests/functional/test_ppc_tuxrun.py +++ b/tests/functional/ppc/test_tuxrun.py diff --git a/tests/functional/test_ppc_virtex_ml507.py b/tests/functional/ppc/test_virtex_ml507.py index 8fe4354..8fe4354 100755 --- a/tests/functional/test_ppc_virtex_ml507.py +++ b/tests/functional/ppc/test_virtex_ml507.py diff --git a/tests/functional/ppc64/meson.build b/tests/functional/ppc64/meson.build new file mode 100644 index 0000000..1fa0a70 --- /dev/null +++ b/tests/functional/ppc64/meson.build @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +test_ppc64_timeouts = { + 'hv' : 1000, + 'mac99' : 120, + 'powernv' : 480, + 'pseries' : 480, + 'replay' : 210, + 'tuxrun' : 420, +} + +tests_ppc64_system_quick = [ + 'migration', + 'vmstate', +] + +tests_ppc64_system_thorough = [ + 'e500', + 'hv', + 'mac99', + 'powernv', + 'pseries', + 'replay', + 'reverse_debug', + 'tuxrun', +] diff --git a/tests/functional/test_ppc64_e500.py b/tests/functional/ppc64/test_e500.py index f5fcad9..f5fcad9 100755 --- a/tests/functional/test_ppc64_e500.py +++ b/tests/functional/ppc64/test_e500.py diff --git a/tests/functional/test_ppc64_hv.py b/tests/functional/ppc64/test_hv.py index 1920e91..d87f440 100755 --- a/tests/functional/test_ppc64_hv.py +++ b/tests/functional/ppc64/test_hv.py @@ -9,14 +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. +import os +import subprocess + +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 -import os -import time -import subprocess -from datetime import datetime # 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, diff --git a/tests/functional/test_ppc64_mac99.py b/tests/functional/ppc64/test_mac99.py index dfd9c01..dfd9c01 100755 --- a/tests/functional/test_ppc64_mac99.py +++ b/tests/functional/ppc64/test_mac99.py diff --git a/tests/functional/ppc64/test_migration.py b/tests/functional/ppc64/test_migration.py new file mode 100755 index 0000000..5dfdaaf --- /dev/null +++ b/tests/functional/ppc64/test_migration.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# ppc migration test + +from migration import MigrationTest + + +class PpcMigrationTest(MigrationTest): + + def test_migration_with_tcp_localhost(self): + self.set_machine('mac99') + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.set_machine('mac99') + self.migration_with_unix() + + def test_migration_with_exec(self): + self.set_machine('mac99') + self.migration_with_exec() + + +if __name__ == '__main__': + MigrationTest.main() diff --git a/tests/functional/test_ppc64_powernv.py b/tests/functional/ppc64/test_powernv.py index 685e217..9ada832 100755 --- a/tests/functional/test_ppc64_powernv.py +++ b/tests/functional/ppc64/test_powernv.py @@ -18,9 +18,14 @@ class powernvMachine(LinuxKernelTest): good_message = 'VFS: Cannot open root device' ASSET_KERNEL = Asset( - ('https://archives.fedoraproject.org/pub/archive/fedora-secondary/' - 'releases/29/Everything/ppc64le/os/ppc/ppc64/vmlinuz'), - '383c2f5c23bc0d9d32680c3924d3fd7ee25cc5ef97091ac1aa5e1d853422fc5f') + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/' + 'buildroot/qemu_ppc64le_powernv8-2025.02/vmlinux'), + '6fd29aff9ad4362511ea5d0acbb510667c7031928e97d64ec15bbc5daf4b8151') + + ASSET_INITRD = Asset( + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/' + 'buildroot/qemu_ppc64le_powernv8-2025.02/rootfs.ext2'), + 'aee2192b692077c4bde31cb56ce474424b358f17cec323d5c94af3970c9aada2') def do_test_linux_boot(self, command_line = KERNEL_COMMON_COMMAND_LINE): self.require_accelerator("tcg") @@ -78,27 +83,24 @@ class powernvMachine(LinuxKernelTest): 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() + kernel_path = self.ASSET_KERNEL.fetch() + initrd_path = self.ASSET_INITRD.fetch() self.vm.set_console() self.vm.add_args('-kernel', kernel_path, - '-append', 'console=tty0 console=hvc0', + '-drive', + f'file={initrd_path},format=raw,if=none,id=drive0,readonly=on', + '-append', 'root=/dev/nvme0n1 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', 'nvme,drive=drive0,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") + self.wait_for_console_pattern("INIT: Starting kernel at ") + self.wait_for_console_pattern("Run /sbin/init as init process") # Device detection output driven by udev probing is sometimes cut off # from console output, suspect S14silence-console init script. @@ -114,5 +116,9 @@ class powernvMachine(LinuxKernelTest): self.set_machine('powernv10') self.do_test_ppc64_powernv('P10') + def test_powernv11(self): + self.set_machine('powernv11') + self.do_test_ppc64_powernv('Power11') + if __name__ == '__main__': LinuxKernelTest.main() diff --git a/tests/functional/test_ppc64_pseries.py b/tests/functional/ppc64/test_pseries.py index fdc404e..6705793 100755 --- a/tests/functional/test_ppc64_pseries.py +++ b/tests/functional/ppc64/test_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/ppc64/test_replay.py index e8c9c4b..e8c9c4b 100755 --- a/tests/functional/test_ppc64_replay.py +++ b/tests/functional/ppc64/test_replay.py diff --git a/tests/functional/ppc64/test_reverse_debug.py b/tests/functional/ppc64/test_reverse_debug.py new file mode 100755 index 0000000..69551fb --- /dev/null +++ b/tests/functional/ppc64/test_reverse_debug.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Reverse debugging test for ppc64 +# +# Copyright (c) 2020 ISP RAS +# Copyright (c) 2025 Linaro Limited +# +# Author: +# Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru> +# Gustavo Romero <gustavo.romero@linaro.org> (Run without Avocado) +# +# 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 skipFlakyTest +from reverse_debugging import ReverseDebugging + + +class ReverseDebugging_ppc64(ReverseDebugging): + + @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.reverse_debugging(gdb_arch='powerpc:common64') + + @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/1992") + def test_ppc64_powernv(self): + self.set_machine('powernv') + self.reverse_debugging(gdb_arch='powerpc:common64') + + +if __name__ == '__main__': + ReverseDebugging.main() diff --git a/tests/functional/test_ppc64_tuxrun.py b/tests/functional/ppc64/test_tuxrun.py index e8f79c6..e8f79c6 100755 --- a/tests/functional/test_ppc64_tuxrun.py +++ b/tests/functional/ppc64/test_tuxrun.py diff --git a/tests/functional/qemu_test/__init__.py b/tests/functional/qemu_test/__init__.py index 45f7bef..3201935 100644 --- a/tests/functional/qemu_test/__init__.py +++ b/tests/functional/qemu_test/__init__.py @@ -15,6 +15,8 @@ from .testcase import QemuBaseTest, QemuUserTest, QemuSystemTest from .linuxkernel import LinuxKernelTest from .decorators import skipIfMissingCommands, skipIfNotMachine, \ skipFlakyTest, skipUntrustedTest, skipBigDataTest, skipSlowTest, \ - skipIfMissingImports + skipIfMissingImports, skipIfOperatingSystem, skipLockedMemoryTest, \ + skipIfMissingEnv from .archive import archive_extract from .uncompress import uncompress +from .gdb import GDB diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py index 704b84d..f666125 100644 --- a/tests/functional/qemu_test/asset.py +++ b/tests/functional/qemu_test/asset.py @@ -15,7 +15,7 @@ import urllib.request from time import sleep from pathlib import Path from shutil import copyfileobj -from urllib.error import HTTPError +from urllib.error import HTTPError, URLError class AssetError(Exception): def __init__(self, asset, msg, transient=False): @@ -72,6 +72,10 @@ class Asset: return self.hash == hl.hexdigest() def valid(self): + if os.getenv("QEMU_TEST_REFRESH_CACHE", None) is not None: + self.log.info("Force refresh of asset %s", self.url) + return False + return self.cache_file.exists() and self._check(self.cache_file) def fetchable(self): @@ -167,9 +171,25 @@ class Asset: raise AssetError(self, "Unable to download: " "HTTP error %d" % e.code) continue + except URLError as e: + # This is typically a network/service level error + # eg urlopen error [Errno 110] Connection timed out> + tmp_cache_file.unlink() + self.log.error("Unable to download %s: URL error %s", + self.url, e.reason) + raise AssetError(self, "Unable to download: URL error %s" % + e.reason, transient=True) + except ConnectionError as e: + # A socket connection failure, such as dropped conn + # or refused conn + tmp_cache_file.unlink() + self.log.error("Unable to download %s: Connection error %s", + self.url, e) + continue except Exception as e: tmp_cache_file.unlink() - raise AssetError(self, "Unable to download: " % e) + raise AssetError(self, "Unable to download: %s" % e, + transient=True) if not os.path.exists(tmp_cache_file): raise AssetError(self, "Download retries exceeded", transient=True) @@ -205,7 +225,6 @@ class Asset: log.addHandler(handler) for name, asset in vars(test.__class__).items(): if name.startswith("ASSET_") and type(asset) == Asset: - log.info("Attempting to cache '%s'" % asset) try: asset.fetch() except AssetError as e: diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py index dc5f422..f544566 100644 --- a/tests/functional/qemu_test/cmd.py +++ b/tests/functional/qemu_test/cmd.py @@ -45,13 +45,16 @@ def is_readable_executable_file(path): # If end of line is seen, with neither @success or @failure # return False # +# In both cases, also return the contents of the line (in bytes) +# up to that point. +# # 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: + if not c: done = True test.fail( f"EOF in console, expected '{success}'") @@ -76,10 +79,23 @@ def _console_read_line_until_match(test, vm, success, failure): except: console_logger.debug(msg) - return done + return done, msg def _console_interaction(test, success_message, failure_message, send_string, keep_sending=False, vm=None): + """ + Interact with the console until either message is seen. + + :param success_message: if this message appears, finish interaction + :param failure_message: if this message appears, test fails + :param send_string: a string to send to the console before trying + to read a new line + :param keep_sending: keep sending the send string each time + :param vm: the VM to interact with + + :return: The collected output (in bytes form). + """ + assert not keep_sending or send_string assert success_message or send_string @@ -101,6 +117,8 @@ def _console_interaction(test, success_message, failure_message, if failure_message is not None: failure_message_b = failure_message.encode() + out = bytes([]) + while True: if send_string: vm.console_socket.sendall(send_string.encode()) @@ -113,14 +131,21 @@ def _console_interaction(test, success_message, failure_message, break continue - if _console_read_line_until_match(test, vm, - success_message_b, - failure_message_b): + done, line = _console_read_line_until_match(test, vm, + success_message_b, + failure_message_b) + + out += line + + if done: break + return out + def interrupt_interactive_console_until_pattern(test, success_message, failure_message=None, - interrupt_string='\r'): + interrupt_string='\r', + vm=None): """ 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: @@ -140,10 +165,13 @@ def interrupt_interactive_console_until_pattern(test, success_message, :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 + :param vm: VM to use + + :return: The collected output (in bytes form). """ assert success_message - _console_interaction(test, success_message, failure_message, - interrupt_string, True) + return _console_interaction(test, success_message, failure_message, + interrupt_string, True, vm=vm) def wait_for_console_pattern(test, success_message, failure_message=None, vm=None): @@ -155,11 +183,15 @@ def wait_for_console_pattern(test, success_message, failure_message=None, :type test: :class:`qemu_test.QemuSystemTest` :param success_message: if this message appears, test succeeds :param failure_message: if this message appears, test fails + :param vm: VM to use + + :return: The collected output (in bytes form). """ assert success_message - _console_interaction(test, success_message, failure_message, None, vm=vm) + return _console_interaction(test, success_message, failure_message, + None, vm=vm) -def exec_command(test, command): +def exec_command(test, command, vm=None): """ Send a command to a console (appending CRLF characters), while logging the content. @@ -167,12 +199,16 @@ def exec_command(test, command): :param test: a test containing a VM. :type test: :class:`qemu_test.QemuSystemTest` :param command: the command to send + :param vm: VM to use :type command: str + + :return: The collected output (in bytes form). """ - _console_interaction(test, None, None, command + '\r') + return _console_interaction(test, None, None, command + '\r', vm=vm) def exec_command_and_wait_for_pattern(test, command, - success_message, failure_message=None): + success_message, failure_message=None, + vm=None): """ Send a command to a console (appending CRLF characters), then wait for success_message to appear on the console, while logging the. @@ -184,9 +220,14 @@ def exec_command_and_wait_for_pattern(test, command, :param command: the command to send :param success_message: if this message appears, test succeeds :param failure_message: if this message appears, test fails + :param vm: VM to use + + :return: The collected output (in bytes form). """ assert success_message - _console_interaction(test, success_message, failure_message, command + '\r') + + return _console_interaction(test, success_message, failure_message, + command + '\r', vm=vm) def get_qemu_img(test): test.log.debug('Looking for and selecting a qemu-img binary') diff --git a/tests/functional/qemu_test/decorators.py b/tests/functional/qemu_test/decorators.py index 1651eb7..b239295 100644 --- a/tests/functional/qemu_test/decorators.py +++ b/tests/functional/qemu_test/decorators.py @@ -5,11 +5,30 @@ import importlib import os import platform -from unittest import skipUnless +import resource +from unittest import skipIf, skipUnless from .cmd import which ''' +Decorator to skip execution of a test if the provided +environment variables are not set. +Example: + + @skipIfMissingEnv("QEMU_ENV_VAR0", "QEMU_ENV_VAR1") +''' +def skipIfMissingEnv(*vars_): + missing_vars = [] + for var in vars_: + if os.getenv(var) == None: + missing_vars.append(var) + + has_vars = True if len(missing_vars) == 0 else False + + return skipUnless(has_vars, f"Missing env var(s): {', '.join(missing_vars)}") + +''' + Decorator to skip execution of a test if the list of command binaries is not available in $PATH. Example: @@ -28,6 +47,19 @@ def skipIfMissingCommands(*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 @@ -118,3 +150,20 @@ def skipIfMissingImports(*args): 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/gdb.py b/tests/functional/qemu_test/gdb.py new file mode 100644 index 0000000..558d476 --- /dev/null +++ b/tests/functional/qemu_test/gdb.py @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# A simple interface module built around pygdbmi for handling GDB commands. +# +# Copyright (c) 2025 Linaro Limited +# +# Author: +# Gustavo Romero <gustavo.romero@linaro.org> +# + +import re + + +class GDB: + """Provides methods to run and capture GDB command output.""" + + + def __init__(self, gdb_path, echo=True, suffix='# ', prompt="$ "): + from pygdbmi.gdbcontroller import GdbController + from pygdbmi.constants import GdbTimeoutError + type(self).TimeoutError = GdbTimeoutError + + gdb_cmd = [gdb_path, "-q", "--interpreter=mi2"] + self.gdbmi = GdbController(gdb_cmd) + self.echo = echo + self.suffix = suffix + self.prompt = prompt + self.response = None + self.cmd_output = None + + + def get_payload(self, response, kind): + output = [] + for o in response: + # Unpack payloads of the same type. + _type, _, payload, *_ = o.values() + if _type == kind: + output += [payload] + + # Some output lines do not end with \n but begin with it, + # so remove the leading \n and merge them with the next line + # that ends with \n. + lines = [line.lstrip('\n') for line in output] + lines = "".join(lines) + lines = lines.splitlines(keepends=True) + + return lines + + + def cli(self, cmd, timeout=32.0): + self.response = self.gdbmi.write(cmd, timeout_sec=timeout) + self.cmd_output = self.get_payload(self.response, kind="console") + if self.echo: + print(self.suffix + self.prompt + cmd) + + if len(self.cmd_output) > 0: + cmd_output = self.suffix.join(self.cmd_output) + print(self.suffix + cmd_output, end="") + + return self + + + def get_addr(self): + address_pattern = r"0x[0-9A-Fa-f]+" + cmd_output = "".join(self.cmd_output) # Concat output lines. + + match = re.search(address_pattern, cmd_output) + + return int(match[0], 16) if match else None + + + def get_log(self): + r = self.get_payload(self.response, kind="log") + r = "".join(r) + + return r + + + def get_console(self): + r = "".join(self.cmd_output) + + return r + + + def exit(self): + self.gdbmi.exit() diff --git a/tests/functional/qemu_test/ports.py b/tests/functional/qemu_test/ports.py index cc39939..81174a6 100644 --- a/tests/functional/qemu_test/ports.py +++ b/tests/functional/qemu_test/ports.py @@ -10,12 +10,11 @@ import fcntl import os import socket -import sys -import tempfile from .config import BUILD_DIR from typing import List + class Ports(): PORTS_ADDR = '127.0.0.1' @@ -24,8 +23,9 @@ class Ports(): 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) + lock_file = os.path.join(BUILD_DIR, "tests", "functional", + f".port_lock.{self.PORTS_START}") + self.lock_fh = os.open(lock_file, os.O_CREAT, mode=0o666) fcntl.flock(self.lock_fh, fcntl.LOCK_EX) return self diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index 50c401b..2c0abde 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -19,11 +19,12 @@ import shutil from subprocess import run import sys import tempfile +import warnings 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 @@ -204,6 +205,10 @@ class QemuBaseTest(unittest.TestCase): self.outputdir = self.build_file('tests', 'functional', self.arch, self.id()) self.workdir = os.path.join(self.outputdir, 'scratch') + if os.path.exists(self.workdir): + # Purge as safety net in case of unclean termination of + # previous test, or use of QEMU_TEST_KEEP_SCRATCH + shutil.rmtree(self.workdir) os.makedirs(self.workdir, exist_ok=True) self.log_filename = self.log_file('base.log') @@ -232,8 +237,13 @@ class QemuBaseTest(unittest.TestCase): self.socketdir = None self.machinelog.removeHandler(self._log_fh) self.log.removeHandler(self._log_fh) + self._log_fh.close() + @staticmethod def main(): + warnings.simplefilter("default") + os.environ["PYTHONWARNINGS"] = "default" + path = os.path.basename(sys.argv[0])[:-3] cache = os.environ.get("QEMU_TEST_PRECACHE", None) @@ -244,14 +254,15 @@ class QemuBaseTest(unittest.TestCase): tr = pycotap.TAPTestRunner(message_log = pycotap.LogMode.LogToError, test_output_log = pycotap.LogMode.LogToError) res = unittest.main(module = None, testRunner = tr, exit = False, - argv=["__dummy__", path]) + argv=[sys.argv[0], path] + sys.argv[1:]) + failed = {} for (test, message) in res.result.errors + res.result.failures: - - if hasattr(test, "log_filename"): + if hasattr(test, "log_filename") and not test.id() in failed: 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) + failed[test.id()] = True sys.exit(not res.result.wasSuccessful()) @@ -317,7 +328,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) @@ -395,6 +408,10 @@ class QemuSystemTest(QemuBaseTest): def tearDown(self): for vm in self._vms.values(): - vm.shutdown() + try: + vm.shutdown() + except Exception as ex: + self.log.error("Failed to teardown VM: %s" % ex) logging.getLogger('console').removeHandler(self._console_log_fh) + self._console_log_fh.close() super().tearDown() diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py index ad74156..6c442ff 100644 --- a/tests/functional/qemu_test/tuxruntest.py +++ b/tests/functional/qemu_test/tuxruntest.py @@ -10,8 +10,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later import os -import stat -from subprocess import check_call, DEVNULL from qemu_test import QemuSystemTest from qemu_test import exec_command_and_wait_for_pattern @@ -77,12 +75,12 @@ class TuxRunBaselineTest(QemuSystemTest): 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.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', kcmd_line, + '-append', self.kcmd_line, '-blockdev', blockdev) # Sometimes we need extra devices attached @@ -103,6 +101,7 @@ class TuxRunBaselineTest(QemuSystemTest): 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) diff --git a/tests/functional/qemu_test/uncompress.py b/tests/functional/qemu_test/uncompress.py index ce79da1..b7ef8f7 100644 --- a/tests/functional/qemu_test/uncompress.py +++ b/tests/functional/qemu_test/uncompress.py @@ -13,7 +13,7 @@ import os import stat import shutil from urllib.parse import urlparse -from subprocess import run, CalledProcessError, DEVNULL +from subprocess import run, CalledProcessError from .asset import Asset diff --git a/tests/functional/replay_kernel.py b/tests/functional/replay_kernel.py index 80795eb..acb1d29 100644 --- a/tests/functional/replay_kernel.py +++ b/tests/functional/replay_kernel.py @@ -32,15 +32,14 @@ class ReplayKernelBase(LinuxKernelTest): # 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...') + self.log.info('recording the execution...') mode = 'record' else: - logger.info('replaying the execution...') + self.log.info('replaying the execution...') mode = 'replay' vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' % (shift, mode, replay_path), @@ -54,15 +53,15 @@ class ReplayKernelBase(LinuxKernelTest): self.wait_for_console_pattern(console_pattern, vm) if record: vm.shutdown() - logger.info('finished the recording with log size %s bytes' + self.log.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') + self.log.info('successfully tested replay-dump.py') else: vm.wait() - logger.info('successfully finished the replay') + self.log.info('successfully finished the replay') elapsed = time.time() - start_time - logger.info('elapsed time %.2f sec' % elapsed) + self.log.info('elapsed time %.2f sec' % elapsed) return elapsed def run_replay_dump(self, replay_path): @@ -80,5 +79,4 @@ class ReplayKernelBase(LinuxKernelTest): 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)) + self.log.info('replay overhead {:.2%}'.format(t2 / t1 - 1)) diff --git a/tests/functional/reverse_debugging.py b/tests/functional/reverse_debugging.py new file mode 100644 index 0000000..68cfcb3 --- /dev/null +++ b/tests/functional/reverse_debugging.py @@ -0,0 +1,202 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Reverse debugging test +# +# Copyright (c) 2020 ISP RAS +# Copyright (c) 2025 Linaro Limited +# +# Author: +# Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru> +# Gustavo Romero <gustavo.romero@linaro.org> (Run without Avocado) +# +# 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 +from subprocess import check_output + +from qemu_test import LinuxKernelTest, get_qemu_img, GDB, \ + skipIfMissingEnv, skipIfMissingImports +from qemu_test.ports import Ports + + +class ReverseDebugging(LinuxKernelTest): + """ + Test GDB reverse debugging commands: reverse step and reverse continue. + Recording saves the execution of some instructions and makes an initial + VM snapshot to allow reverse execution. + Replay saves the order of the first instructions and then checks that they + are executed backwards in the correct order. + After that the execution is replayed to the end, and reverse continue + command is checked by setting several breakpoints, and asserting + that the execution is stopped at the last of them. + """ + + STEPS = 10 + + def run_vm(self, record, shift, args, replay_path, image_path, port): + logger = logging.getLogger('replay') + vm = self.get_vm(name='record' 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('-gdb', 'tcp::%d' % port, '-S') + vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s,rrsnapshot=init' % + (shift, mode, replay_path), + '-net', 'none') + vm.add_args('-drive', 'file=%s,if=none' % image_path) + if args: + vm.add_args(*args) + vm.launch() + return vm + + @staticmethod + def get_pc(gdb: GDB): + return gdb.cli("print $pc").get_addr() + + @staticmethod + def vm_get_icount(vm): + return vm.qmp('query-replay')['return']['icount'] + + @skipIfMissingImports("pygdbmi") # Required by GDB class + @skipIfMissingEnv("QEMU_TEST_GDB") + def reverse_debugging(self, gdb_arch, shift=7, args=None): + from qemu_test import GDB + + 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 = 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') + out = check_output([qemu_img, 'create', '-f', 'qcow2', image_path, '128M'], + encoding='utf8') + logger.info("qemu-img: %s" % out) + + replay_path = os.path.join(self.workdir, 'replay.bin') + + # record the log + 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) + vm.shutdown() + + logger.info("recorded log with %s+ steps" % last_icount) + + # replay and run debug commands + with Ports() as ports: + port = ports.find_free_port() + vm = self.run_vm(False, shift, args, replay_path, image_path, port) + + try: + logger.info('Connecting to gdbstub...') + self.reverse_debugging_run(vm, port, gdb_arch, last_icount) + logger.info('Test passed.') + except GDB.TimeoutError: + # Convert a GDB timeout exception into a unittest failure exception. + raise self.failureException("Timeout while connecting to or " + "communicating with gdbstub...") from None + except Exception: + # Re-throw exceptions from unittest, like the ones caused by fail(), + # skipTest(), etc. + raise + + def reverse_debugging_run(self, vm, port, gdb_arch, last_icount): + logger = logging.getLogger('replay') + + gdb_cmd = os.getenv('QEMU_TEST_GDB') + gdb = GDB(gdb_cmd) + + r = gdb.cli("set architecture").get_log() + if gdb_arch not in r: + self.skipTest(f"GDB does not support arch '{gdb_arch}'") + + gdb.cli("set debug remote 1") + + c = gdb.cli(f"target remote localhost:{port}").get_console() + if not f"Remote debugging using localhost:{port}" in c: + self.fail("Could not connect to gdbstub!") + + # Remote debug messages are in 'log' payloads. + r = gdb.get_log() + if 'ReverseStep+' not in r: + self.fail('Reverse step is not supported by QEMU') + if 'ReverseContinue+' not in r: + self.fail('Reverse continue is not supported by QEMU') + + gdb.cli("set debug remote 0") + + logger.info('stepping forward') + steps = [] + # record first instruction addresses + for _ in range(self.STEPS): + pc = self.get_pc(gdb) + logger.info('saving position %x' % pc) + steps.append(pc) + gdb.cli("stepi") + + # visit the recorded instruction in reverse order + logger.info('stepping backward') + for addr in steps[::-1]: + logger.info('found position %x' % addr) + gdb.cli("reverse-stepi") + pc = self.get_pc(gdb) + if pc != addr: + logger.info('Invalid PC (read %x instead of %x)' % (pc, addr)) + self.fail('Reverse stepping failed!') + + # visit the recorded instruction in forward order + logger.info('stepping forward') + for addr in steps: + logger.info('found position %x' % addr) + pc = self.get_pc(gdb) + if pc != addr: + logger.info('Invalid PC (read %x instead of %x)' % (pc, addr)) + self.fail('Forward stepping failed!') + gdb.cli("stepi") + + # set breakpoints for the instructions just stepped over + logger.info('setting breakpoints') + for addr in steps: + gdb.cli(f"break *{hex(addr)}") + + # this may hit a breakpoint if first instructions are executed + # again + logger.info('continuing execution') + vm.qmp('replay-break', icount=last_icount - 1) + # continue - will return after pausing + # This can stop at the end of the replay-break and gdb gets a SIGINT, + # or by re-executing one of the breakpoints and gdb stops at a + # breakpoint. + gdb.cli("continue") + + if self.vm_get_icount(vm) == last_icount - 1: + logger.info('reached the end (icount %s)' % (last_icount - 1)) + else: + logger.info('hit a breakpoint again at %x (icount %s)' % + (self.get_pc(gdb), self.vm_get_icount(vm))) + + logger.info('running reverse continue to reach %x' % steps[-1]) + # reverse continue - will return after stopping at the breakpoint + gdb.cli("reverse-continue") + + # assume that none of the first instructions is executed again + # breaking the order of the breakpoints + pc = self.get_pc(gdb) + if pc != steps[-1]: + self.fail("'reverse-continue' did not hit the first PC in reverse order!") + + logger.info('successfully reached %x' % steps[-1]) + + logger.info('exiting gdb and qemu') + gdb.exit() + vm.shutdown() diff --git a/tests/functional/riscv32/meson.build b/tests/functional/riscv32/meson.build new file mode 100644 index 0000000..f3ebbb8 --- /dev/null +++ b/tests/functional/riscv32/meson.build @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_riscv32_system_quick = [ + 'migration', + 'opensbi', +] + +tests_riscv32_system_thorough = [ + 'tuxrun', +] diff --git a/tests/functional/riscv32/test_migration.py b/tests/functional/riscv32/test_migration.py new file mode 100755 index 0000000..30acbbe --- /dev/null +++ b/tests/functional/riscv32/test_migration.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# riscv32 migration test + +from migration import MigrationTest + + +class Rv32MigrationTest(MigrationTest): + + def test_migration_with_tcp_localhost(self): + self.set_machine('spike') + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.set_machine('virt') + self.migration_with_unix() + + def test_migration_with_exec(self): + self.set_machine('spike') + self.migration_with_exec() + + +if __name__ == '__main__': + MigrationTest.main() diff --git a/tests/functional/riscv32/test_opensbi.py b/tests/functional/riscv32/test_opensbi.py new file mode 100755 index 0000000..d1ac706 --- /dev/null +++ b/tests/functional/riscv32/test_opensbi.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Reuse the 64-bit OpenSBI test for RISC-V 32-bit machines + +from riscv64.test_opensbi import RiscvOpenSBI + +if __name__ == '__main__': + RiscvOpenSBI.main() diff --git a/tests/functional/test_riscv32_tuxrun.py b/tests/functional/riscv32/test_tuxrun.py index 3c57020..3c57020 100755 --- a/tests/functional/test_riscv32_tuxrun.py +++ b/tests/functional/riscv32/test_tuxrun.py diff --git a/tests/functional/riscv64/meson.build b/tests/functional/riscv64/meson.build new file mode 100644 index 0000000..c1704d9 --- /dev/null +++ b/tests/functional/riscv64/meson.build @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +test_riscv64_timeouts = { + 'tuxrun' : 120, +} + +tests_riscv64_system_quick = [ + 'migration', + 'opensbi', +] + +tests_riscv64_system_thorough = [ + 'sifive_u', + 'tuxrun', +] diff --git a/tests/functional/riscv64/test_migration.py b/tests/functional/riscv64/test_migration.py new file mode 100755 index 0000000..2d613a2 --- /dev/null +++ b/tests/functional/riscv64/test_migration.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# riscv64 migration test + +from migration import MigrationTest + + +class Rv64MigrationTest(MigrationTest): + + def test_migration_with_tcp_localhost(self): + self.set_machine('virt') + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.set_machine('spike') + self.migration_with_unix() + + def test_migration_with_exec(self): + self.set_machine('virt') + self.migration_with_exec() + + +if __name__ == '__main__': + MigrationTest.main() diff --git a/tests/functional/test_riscv_opensbi.py b/tests/functional/riscv64/test_opensbi.py index d077e40..d077e40 100755 --- a/tests/functional/test_riscv_opensbi.py +++ b/tests/functional/riscv64/test_opensbi.py diff --git a/tests/functional/riscv64/test_sifive_u.py b/tests/functional/riscv64/test_sifive_u.py new file mode 100755 index 0000000..358ff0d --- /dev/null +++ b/tests/functional/riscv64/test_sifive_u.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# +# Functional test that boots a Linux kernel on a Sifive U machine +# and checks the console +# +# Copyright (c) Linaro Ltd. +# +# Author: +# Philippe Mathieu-Daudé +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import os + +from qemu_test import Asset, LinuxKernelTest +from qemu_test import skipIfMissingCommands + + +class SifiveU(LinuxKernelTest): + + ASSET_KERNEL = Asset( + 'https://storage.tuxboot.com/buildroot/20241119/riscv64/Image', + '2bd8132a3bf21570290042324fff48c987f42f2a00c08de979f43f0662ebadba') + ASSET_ROOTFS = Asset( + ('https://github.com/groeck/linux-build-test/raw/' + '9819da19e6eef291686fdd7b029ea00e764dc62f/rootfs/riscv64/' + 'rootfs.ext2.gz'), + 'b6ed95610310b7956f9bf20c4c9c0c05fea647900df441da9dfe767d24e8b28b') + + def do_test_riscv64_sifive_u_mmc_spi(self, connect_card): + self.set_machine('sifive_u') + kernel_path = self.ASSET_KERNEL.fetch() + rootfs_path = self.uncompress(self.ASSET_ROOTFS) + + self.vm.set_console() + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'earlycon=sbi console=ttySIF0 ' + 'root=/dev/mmcblk0 ') + self.vm.add_args('-kernel', kernel_path, + '-append', kernel_command_line, + '-no-reboot') + if connect_card: + kernel_command_line += 'panic=-1 noreboot rootwait ' + self.vm.add_args('-drive', f'file={rootfs_path},if=sd,format=raw') + pattern = 'Boot successful.' + else: + kernel_command_line += 'panic=0 noreboot ' + pattern = 'Cannot open root device "mmcblk0" or unknown-block(0,0)' + + self.vm.launch() + self.wait_for_console_pattern(pattern) + + os.remove(rootfs_path) + + def test_riscv64_sifive_u_nommc_spi(self): + self.do_test_riscv64_sifive_u_mmc_spi(False) + + def test_riscv64_sifive_u_mmc_spi(self): + self.do_test_riscv64_sifive_u_mmc_spi(True) + + +if __name__ == '__main__': + LinuxKernelTest.main() diff --git a/tests/functional/test_riscv64_tuxrun.py b/tests/functional/riscv64/test_tuxrun.py index 0d8de36..0d8de36 100755 --- a/tests/functional/test_riscv64_tuxrun.py +++ b/tests/functional/riscv64/test_tuxrun.py diff --git a/tests/functional/rx/meson.build b/tests/functional/rx/meson.build new file mode 100644 index 0000000..6af83a9 --- /dev/null +++ b/tests/functional/rx/meson.build @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_rx_system_thorough = [ + 'gdbsim', +] diff --git a/tests/functional/test_rx_gdbsim.py b/tests/functional/rx/test_gdbsim.py index 4924579..4924579 100755 --- a/tests/functional/test_rx_gdbsim.py +++ b/tests/functional/rx/test_gdbsim.py diff --git a/tests/functional/s390x/meson.build b/tests/functional/s390x/meson.build new file mode 100644 index 0000000..70cd36e --- /dev/null +++ b/tests/functional/s390x/meson.build @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +test_s390x_timeouts = { + 'ccw_virtio' : 420, +} + +tests_s390x_system_quick = [ + 'vmstate', +] + +tests_s390x_system_thorough = [ + 'ccw_virtio', + 'pxelinux', + 'replay', + 'topology', + 'tuxrun', +] diff --git a/tests/functional/test_s390x_ccw_virtio.py b/tests/functional/s390x/test_ccw_virtio.py index 453711a..453711a 100755 --- a/tests/functional/test_s390x_ccw_virtio.py +++ b/tests/functional/s390x/test_ccw_virtio.py diff --git a/tests/functional/s390x/test_pxelinux.py b/tests/functional/s390x/test_pxelinux.py new file mode 100755 index 0000000..c00cce6 --- /dev/null +++ b/tests/functional/s390x/test_pxelinux.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +''' +Functional test that checks the pxelinux.cfg network booting of a s390x VM +(TFTP booting without config file is already tested by the pxe qtest, so +we don't repeat that here). +''' + +import os +import shutil + +from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern + + +PXELINUX_CFG_CONTENTS='''# pxelinux.cfg style config file +default Debian +label Nonexisting +kernel kernel.notavailable +initrd initrd.notavailable +label Debian +kernel kernel.debian +initrd initrd.debian +append testoption=teststring +label Fedora +kernel kernel.fedora +''' + +class S390PxeLinux(QemuSystemTest): + ''' + Test various ways of booting via a pxelinux.cfg file, for details see: + https://wiki.syslinux.org/wiki/index.php?title=PXELINUX#Configuration + ''' + + ASSET_DEBIAN_KERNEL = Asset( + ('https://snapshot.debian.org/archive/debian/' + '20201126T092837Z/dists/buster/main/installer-s390x/' + '20190702+deb10u6/images/generic/kernel.debian'), + 'd411d17c39ae7ad38d27534376cbe88b68b403c325739364122c2e6f1537e818') + + ASSET_DEBIAN_INITRD = Asset( + ('https://snapshot.debian.org/archive/debian/' + '20201126T092837Z/dists/buster/main/installer-s390x/' + '20190702+deb10u6/images/generic/initrd.debian'), + '836bbd0fe6a5ca81274c28c2b063ea315ce1868660866e9b60180c575fef9fd5') + + ASSET_FEDORA_KERNEL = Asset( + ('https://archives.fedoraproject.org/pub/archive' + '/fedora-secondary/releases/31/Server/s390x/os' + '/images/kernel.img'), + '480859574f3f44caa6cd35c62d70e1ac0609134e22ce2a954bbed9b110c06e0b') + + def pxelinux_launch(self, pl_name='default', extra_opts=None): + '''Create a pxelinux.cfg file in the right location and launch QEMU''' + self.require_netdev('user') + self.set_machine('s390-ccw-virtio') + + debian_kernel = self.ASSET_DEBIAN_KERNEL.fetch() + debian_initrd = self.ASSET_DEBIAN_INITRD.fetch() + fedora_kernel = self.ASSET_FEDORA_KERNEL.fetch() + + # Prepare a folder for the TFTP "server": + tftpdir = self.scratch_file('tftp') + shutil.rmtree(tftpdir, ignore_errors=True) # Remove stale stuff + os.mkdir(tftpdir) + shutil.copy(debian_kernel, os.path.join(tftpdir, 'kernel.debian')) + shutil.copy(debian_initrd, os.path.join(tftpdir, 'initrd.debian')) + shutil.copy(fedora_kernel, os.path.join(tftpdir, 'kernel.fedora')) + + pxelinuxdir = self.scratch_file('tftp', 'pxelinux.cfg') + os.mkdir(pxelinuxdir) + + cfg_fname = self.scratch_file('tftp', 'pxelinux.cfg', pl_name) + with open(cfg_fname, 'w', encoding='utf-8') as f: + f.write(PXELINUX_CFG_CONTENTS) + + virtio_net_dev = 'virtio-net-ccw,netdev=n1,bootindex=1' + if extra_opts: + virtio_net_dev += ',' + extra_opts + + self.vm.add_args('-m', '384', + '-netdev', f'user,id=n1,tftp={tftpdir}', + '-device', virtio_net_dev) + self.vm.set_console() + self.vm.launch() + + + def test_default(self): + '''Check whether the guest uses the "default" file name''' + self.pxelinux_launch() + # The kernel prints its arguments to the console, so we can use + # this to check whether the kernel parameters are correctly handled: + wait_for_console_pattern(self, 'testoption=teststring') + # Now also check that we've successfully loaded the initrd: + wait_for_console_pattern(self, 'Unpacking initramfs...') + wait_for_console_pattern(self, 'Run /init as init process') + + def test_mac(self): + '''Check whether the guest uses file name based on its MAC address''' + self.pxelinux_launch(pl_name='01-02-ca-fe-ba-be-42', + extra_opts='mac=02:ca:fe:ba:be:42,loadparm=3') + wait_for_console_pattern(self, 'Linux version 5.3.7-301.fc31.s390x') + + def test_uuid(self): + '''Check whether the guest uses file name based on its UUID''' + # Also add a non-bootable disk to check the fallback to network boot: + self.vm.add_args('-blockdev', 'null-co,size=65536,node-name=d1', + '-device', 'virtio-blk,drive=d1,bootindex=0,loadparm=1', + '-uuid', '550e8400-e29b-11d4-a716-446655441234') + self.pxelinux_launch(pl_name='550e8400-e29b-11d4-a716-446655441234') + wait_for_console_pattern(self, 'Debian 4.19.146-1 (2020-09-17)') + + def test_ip(self): + '''Check whether the guest uses file name based on its IP address''' + self.vm.add_args('-M', 'loadparm=3') + self.pxelinux_launch(pl_name='0A00020F') + wait_for_console_pattern(self, 'Linux version 5.3.7-301.fc31.s390x') + + def test_menu(self): + '''Check whether the boot menu works for pxelinux.cfg booting''' + self.vm.add_args('-boot', 'menu=on,splash-time=10') + self.pxelinux_launch(pl_name='0A00') + wait_for_console_pattern(self, '[1] Nonexisting') + wait_for_console_pattern(self, '[2] Debian') + wait_for_console_pattern(self, '[3] Fedora') + wait_for_console_pattern(self, 'Debian 4.19.146-1 (2020-09-17)') + + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/functional/test_s390x_replay.py b/tests/functional/s390x/test_replay.py index 33b5843..33b5843 100755 --- a/tests/functional/test_s390x_replay.py +++ b/tests/functional/s390x/test_replay.py diff --git a/tests/functional/test_s390x_topology.py b/tests/functional/s390x/test_topology.py index eefd972..1b5dc65 100755 --- a/tests/functional/test_s390x_topology.py +++ b/tests/functional/s390x/test_topology.py @@ -217,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) @@ -283,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) @@ -310,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") @@ -360,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/s390x/test_tuxrun.py index a7db4bf..8df3c68 100755 --- a/tests/functional/test_s390x_tuxrun.py +++ b/tests/functional/s390x/test_tuxrun.py @@ -24,6 +24,7 @@ class TuxRunS390xTest(TuxRunBaselineTest): '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, diff --git a/tests/functional/sh4/meson.build b/tests/functional/sh4/meson.build new file mode 100644 index 0000000..56f824e --- /dev/null +++ b/tests/functional/sh4/meson.build @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +test_sh4_timeouts = { + 'tuxrun' : 240, +} + +tests_sh4_system_thorough = [ + 'r2d', + 'tuxrun', +] diff --git a/tests/functional/test_sh4_r2d.py b/tests/functional/sh4/test_r2d.py index 03a64837..03a64837 100755 --- a/tests/functional/test_sh4_r2d.py +++ b/tests/functional/sh4/test_r2d.py diff --git a/tests/functional/test_sh4_tuxrun.py b/tests/functional/sh4/test_tuxrun.py index 1748f8c..1748f8c 100755 --- a/tests/functional/test_sh4_tuxrun.py +++ b/tests/functional/sh4/test_tuxrun.py diff --git a/tests/functional/sh4eb/meson.build b/tests/functional/sh4eb/meson.build new file mode 100644 index 0000000..25e9a6e --- /dev/null +++ b/tests/functional/sh4eb/meson.build @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_sh4eb_system_thorough = [ + 'r2d', +] diff --git a/tests/functional/test_sh4eb_r2d.py b/tests/functional/sh4eb/test_r2d.py index 473093b..473093b 100755 --- a/tests/functional/test_sh4eb_r2d.py +++ b/tests/functional/sh4eb/test_r2d.py diff --git a/tests/functional/sparc/meson.build b/tests/functional/sparc/meson.build new file mode 100644 index 0000000..88732be --- /dev/null +++ b/tests/functional/sparc/meson.build @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_sparc_system_quick = [ + 'migration', +] + +tests_sparc_system_thorough = [ + 'replay', + 'sun4m', +] diff --git a/tests/functional/sparc/test_migration.py b/tests/functional/sparc/test_migration.py new file mode 100755 index 0000000..dd6d578 --- /dev/null +++ b/tests/functional/sparc/test_migration.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Sparc migration test + +from migration import MigrationTest + + +class SparcMigrationTest(MigrationTest): + + def test_migration_with_tcp_localhost(self): + self.set_machine('SS-4') + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.set_machine('SS-5') + self.migration_with_unix() + + def test_migration_with_exec(self): + self.set_machine('SS-4') + self.migration_with_exec() + + +if __name__ == '__main__': + MigrationTest.main() diff --git a/tests/functional/test_sparc_replay.py b/tests/functional/sparc/test_replay.py index 865d648..865d648 100755 --- a/tests/functional/test_sparc_replay.py +++ b/tests/functional/sparc/test_replay.py diff --git a/tests/functional/test_sparc_sun4m.py b/tests/functional/sparc/test_sun4m.py index 7cd28eb..7cd28eb 100755 --- a/tests/functional/test_sparc_sun4m.py +++ b/tests/functional/sparc/test_sun4m.py diff --git a/tests/functional/sparc64/meson.build b/tests/functional/sparc64/meson.build new file mode 100644 index 0000000..2e04e7d --- /dev/null +++ b/tests/functional/sparc64/meson.build @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_sparc64_system_quick = [ + 'migration', +] + +tests_sparc64_system_thorough = [ + 'sun4u', + 'tuxrun', +] diff --git a/tests/functional/sparc64/test_migration.py b/tests/functional/sparc64/test_migration.py new file mode 100755 index 0000000..a8a6c73 --- /dev/null +++ b/tests/functional/sparc64/test_migration.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Sparc64 migration test + +from migration import MigrationTest + + +class Sparc64MigrationTest(MigrationTest): + + def test_migration_with_tcp_localhost(self): + self.set_machine('sun4u') + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.set_machine('sun4u') + self.migration_with_unix() + + def test_migration_with_exec(self): + self.set_machine('sun4u') + self.migration_with_exec() + + +if __name__ == '__main__': + MigrationTest.main() diff --git a/tests/functional/test_sparc64_sun4u.py b/tests/functional/sparc64/test_sun4u.py index 27ac289..27ac289 100755 --- a/tests/functional/test_sparc64_sun4u.py +++ b/tests/functional/sparc64/test_sun4u.py diff --git a/tests/functional/test_sparc64_tuxrun.py b/tests/functional/sparc64/test_tuxrun.py index 3be08d6..0d7b43d 100755 --- a/tests/functional/test_sparc64_tuxrun.py +++ b/tests/functional/sparc64/test_tuxrun.py @@ -24,6 +24,7 @@ class TuxRunSparc64Test(TuxRunBaselineTest): '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, diff --git a/tests/functional/test_aarch64_replay.py b/tests/functional/test_aarch64_replay.py deleted file mode 100755 index 04cde43..0000000 --- a/tests/functional/test_aarch64_replay.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/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 qemu_test import Asset -from replay_kernel import ReplayKernelBase - - -class Aarch64Replay(ReplayKernelBase): - - ASSET_KERNEL = Asset( - ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' - 'releases/29/Everything/aarch64/os/images/pxeboot/vmlinuz'), - '7e1430b81c26bdd0da025eeb8fbd77b5dc961da4364af26e771bd39f379cbbf7') - - def test_aarch64_virt(self): - 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 = '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_aarch64_rme_sbsaref.py b/tests/functional/test_aarch64_rme_sbsaref.py deleted file mode 100755 index 0f4f610..0000000 --- a/tests/functional/test_aarch64_rme_sbsaref.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/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 time -import os -import logging - -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 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 deleted file mode 100755 index f4ad4d3..0000000 --- a/tests/functional/test_aarch64_rme_virt.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/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 time -import os -import logging - -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') - self.vm.add_args('-append', 'root=/dev/vda') - - 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_mips_malta.py b/tests/functional/test_mips_malta.py deleted file mode 100755 index 9697c7d..0000000 --- a/tests/functional/test_mips_malta.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/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 - -from qemu_test import LinuxKernelTest, Asset -from qemu_test import exec_command_and_wait_for_pattern - - -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', - 'Debian') - - 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() - - -if __name__ == '__main__': - LinuxKernelTest.main() diff --git a/tests/functional/test_ppc_bamboo.py b/tests/functional/test_ppc_bamboo.py deleted file mode 100755 index fddcc24..0000000 --- a/tests/functional/test_ppc_bamboo.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python3 -# -# Test that Linux kernel boots on the ppc bamboo board and check the console -# -# Copyright (c) 2021 Red Hat -# -# 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 BambooMachine(QemuSystemTest): - - timeout = 90 - - ASSET_IMAGE = Asset( - ('http://landley.net/aboriginal/downloads/binaries/' - 'system-image-powerpc-440fp.tar.gz'), - 'c12b58f841c775a0e6df4832a55afe6b74814d1565d08ddeafc1fb949a075c5e') - - def test_ppc_bamboo(self): - self.set_machine('bamboo') - self.require_accelerator("tcg") - self.require_netdev('user') - self.archive_extract(self.ASSET_IMAGE) - self.vm.set_console() - 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') - exec_command_and_wait_for_pattern(self, 'ping 10.0.2.2', - '10.0.2.2 is alive!') - exec_command_and_wait_for_pattern(self, 'halt', 'System Halted') - -if __name__ == '__main__': - QemuSystemTest.main() diff --git a/tests/functional/test_x86_64_replay.py b/tests/functional/test_x86_64_replay.py deleted file mode 100755 index 180f23a..0000000 --- a/tests/functional/test_x86_64_replay.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/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 qemu_test import Asset, skipFlakyTest -from replay_kernel import ReplayKernelBase - - -class X86Replay(ReplayKernelBase): - - ASSET_KERNEL = Asset( - ('https://archives.fedoraproject.org/pub/archive/fedora/linux' - '/releases/29/Everything/x86_64/os/images/pxeboot/vmlinuz'), - '8f237d84712b1b411baf3af2aeaaee10b9aae8e345ec265b87ab3a39639eb143') - - def do_test_x86(self, machine): - self.set_machine(machine) - 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) - - @skipFlakyTest('https://gitlab.com/qemu-project/qemu/-/issues/2094') - def test_pc(self): - self.do_test_x86('pc') - - def test_q35(self): - self.do_test_x86('q35') - - -if __name__ == '__main__': - ReplayKernelBase.main() diff --git a/tests/functional/x86_64/meson.build b/tests/functional/x86_64/meson.build new file mode 100644 index 0000000..f78eec5 --- /dev/null +++ b/tests/functional/x86_64/meson.build @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +test_x86_64_timeouts = { + 'acpi_bits' : 420, + 'intel_iommu': 300, + 'kvm_xen' : 180, + 'netdev_ethtool' : 180, + 'replay' : 480, + 'virtio_balloon': 120, +} + +tests_x86_64_system_quick = [ + 'bad_vmstate', + 'cpu_model_versions', + 'cpu_queries', + 'mem_addr_space', + 'memlock', + 'migration', + 'pc_cpu_hotplug_props', + 'virtio_version', + 'vmstate', +] + +tests_x86_64_system_thorough = [ + 'acpi_bits', + 'hotplug_blk', + 'hotplug_cpu', + 'intel_iommu', + 'kvm_xen', + 'linux_initrd', + 'multiprocess', + 'netdev_ethtool', + 'replay', + 'reverse_debug', + 'tuxrun', + 'vfio_user_client', + 'virtio_balloon', + 'virtio_gpu', +] diff --git a/tests/functional/test_acpi_bits.py b/tests/functional/x86_64/test_acpi_bits.py index 8e0563a..9a28165 100755 --- a/tests/functional/test_acpi_bits.py +++ b/tests/functional/x86_64/test_acpi_bits.py @@ -121,10 +121,10 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute self._debugcon_log = 'debugcon-log.txt' def _print_log(self, log): - self.logger.info('\nlogs from biosbits follows:') - self.logger.info('==========================================\n') - self.logger.info(log) - self.logger.info('==========================================\n') + self.log.info('\nlogs from biosbits follows:') + self.log.info('==========================================\n') + self.log.info(log) + self.log.info('==========================================\n') def copy_bits_config(self): """ copies the bios bits config file into bits. @@ -138,8 +138,8 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute self.assertTrue(os.path.exists(bits_config_file)) self.assertTrue(os.path.exists(target_config_dir)) shutil.copy2(bits_config_file, target_config_dir) - self.logger.info('copied config file %s to %s', - bits_config_file, target_config_dir) + self.log.info('copied config file %s to %s', + bits_config_file, target_config_dir) def copy_test_scripts(self): """copies the python test scripts into bits. """ @@ -163,8 +163,8 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute newfilename = os.path.splitext(filename)[0] + '.py' shutil.copy2(os.path.join(bits_test_dir, filename), os.path.join(target_test_dir, newfilename)) - self.logger.info('copied test file %s to %s', - filename, target_test_dir) + self.log.info('copied test file %s to %s', + filename, target_test_dir) # now remove the pyc test file if it exists, otherwise the # changes in the python test script won't be executed. @@ -172,9 +172,9 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute if os.access(os.path.join(target_test_dir, testfile_pyc), os.F_OK): os.remove(os.path.join(target_test_dir, testfile_pyc)) - self.logger.info('removed compiled file %s', - os.path.join(target_test_dir, - testfile_pyc)) + self.log.info('removed compiled file %s', + os.path.join(target_test_dir, + testfile_pyc)) def fix_mkrescue(self, mkrescue): """ grub-mkrescue is a bash script with two variables, 'prefix' and @@ -216,7 +216,7 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute self.fix_mkrescue(mkrescue_script) - self.logger.info('using grub-mkrescue for generating biosbits iso ...') + self.log.info('using grub-mkrescue for generating biosbits iso ...') try: if os.getenv('V') or os.getenv('BITS_DEBUG'): @@ -225,7 +225,7 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=True) - self.logger.info("grub-mkrescue output %s" % proc.stdout) + self.log.info("grub-mkrescue output %s" % proc.stdout) else: subprocess.check_call([mkrescue_script, '-o', iso_file, bits_dir], @@ -238,11 +238,10 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute self.assertTrue(os.access(iso_file, os.R_OK)) - self.logger.info('iso file %s successfully generated.', iso_file) + self.log.info('iso file %s successfully generated.', iso_file) def setUp(self): # pylint: disable=arguments-differ super().setUp() - self.logger = self.log prebuiltDir = self.scratch_file('prebuilt') if not os.path.isdir(prebuiltDir): @@ -333,7 +332,7 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute # in batch mode and then automatically initiate a vm shutdown. self._vm.event_wait('SHUTDOWN', timeout=BITS_TIMEOUT) self._vm.wait(timeout=None) - self.logger.debug("Checking console output ...") + self.log.debug("Checking console output ...") self.parse_log() if __name__ == '__main__': diff --git a/tests/functional/x86_64/test_bad_vmstate.py b/tests/functional/x86_64/test_bad_vmstate.py new file mode 100755 index 0000000..40098a8 --- /dev/null +++ b/tests/functional/x86_64/test_bad_vmstate.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +'''Test whether the vmstate-static-checker script detects problems correctly''' + +import subprocess + +from qemu_test import QemuBaseTest + + +EXPECTED_OUTPUT='''Warning: checking incompatible machine types: "pc-i440fx-2.1", "pc-i440fx-2.2" +Section "fw_cfg" does not exist in dest +Section "fusbh200-ehci-usb" version error: 2 > 1 +Section "fusbh200-ehci-usb", Description "ehci-core": expected field "usbsts", got "usbsts_pending"; skipping rest +Section "pci-serial-4x" Description "pci-serial-multi": Entry "Fields" missing +Section "intel-hda-generic", Description "intel-hda", Field "pci": missing description +Section "cfi.pflash01": Entry "Description" missing +Section "megasas", Description "PCIDevice": expected field "irq_state", while dest has no further fields +Section "PIIX3-xen" Description "PIIX3": minimum version error: 1 < 2 +Section "PIIX3-xen" Description "PIIX3": Entry "Subsections" missing +Section "tpci200": Description "tpci200" missing, got "tpci2002" instead; skipping +Section "sun-fdtwo" Description "fdc": version error: 2 > 1 +Section "sun-fdtwo", Description "fdrive": Subsection "fdrive/media_rate" not found +Section "usb-kbd" Description "usb-kbd" Field "kbd.keycodes" size mismatch: 4 , 2 +''' + +class BadVmStateTest(QemuBaseTest): + '''Test class for testing vmstat-static-checker script with bad input''' + + def test_checker(self): + """ + Test whether the checker script correctly detects the changes + between dump1.json and dump2.json. + """ + src_json = self.data_file('..', 'data', 'vmstate-static-checker', + 'dump1.json') + dst_json = self.data_file('..', 'data', 'vmstate-static-checker', + 'dump2.json') + checkerscript = self.data_file('..', '..', 'scripts', + 'vmstate-static-checker.py') + + self.log.info('Comparing %s with %s', src_json, dst_json) + cp = subprocess.run([checkerscript, '-s', src_json, '-d', dst_json], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, check=False) + if cp.returncode != 13: + self.fail('Unexpected return code of vmstate-static-checker: ' + + cp.returncode) + if cp.stdout != EXPECTED_OUTPUT: + self.log.info('vmstate-static-checker output:\n%s', cp.stdout) + self.log.info('expected output:\n%s', EXPECTED_OUTPUT) + self.fail('Unexpected vmstate-static-checker output!') + + +if __name__ == '__main__': + QemuBaseTest.main() diff --git a/tests/functional/test_x86_cpu_model_versions.py b/tests/functional/x86_64/test_cpu_model_versions.py index bd18acd..36c968f 100755 --- a/tests/functional/test_x86_cpu_model_versions.py +++ b/tests/functional/x86_64/test_cpu_model_versions.py @@ -72,44 +72,11 @@ class X86CPUModelAliases(QemuSystemTest): self.assertNotIn("EPYC-IBPB-v1", cpus, "EPYC-IBPB shouldn't be versioned") - def test_4_0_alias_compatibility(self): - """ - Check if pc-*-4.0 unversioned CPU model won't be reported as aliases - """ - self.set_machine('pc-i440fx-4.0') - # pc-*-4.0 won't expose non-versioned CPU models as aliases - # We do this to help management software to keep compatibility - # with older QEMU versions that didn't have the versioned CPU model - self.vm.add_args('-S') - self.vm.launch() - cpus = dict((m['name'], m) for m in - self.vm.cmd('query-cpu-definitions')) - - self.assertFalse(cpus['Cascadelake-Server']['static'], - 'unversioned Cascadelake-Server CPU model must not be static') - self.assertNotIn('alias-of', cpus['Cascadelake-Server'], - 'Cascadelake-Server must not be an alias') - self.assertNotIn('alias-of', cpus['Cascadelake-Server-v1'], - 'Cascadelake-Server-v1 must not be an alias') - - self.assertFalse(cpus['qemu64']['static'], - 'unversioned qemu64 CPU model must not be static') - self.assertNotIn('alias-of', cpus['qemu64'], - 'qemu64 must not be an alias') - self.assertNotIn('alias-of', cpus['qemu64-v1'], - 'qemu64-v1 must not be an alias') - - self.validate_variant_aliases(cpus) - - # On pc-*-4.0, no CPU model should be reported as an alias: - for name,c in cpus.items(): - self.assertNotIn('alias-of', c, "%s shouldn't be an alias" % (name)) - - def test_4_1_alias(self): + def test_unversioned_alias(self): """ Check if unversioned CPU model is an alias pointing to right version """ - self.set_machine('pc-i440fx-4.1') + self.set_machine('pc') self.vm.add_args('-S') self.vm.launch() @@ -133,7 +100,7 @@ class X86CPUModelAliases(QemuSystemTest): self.validate_variant_aliases(cpus) - # On pc-*-4.1, -noTSX and -IBRS models should be aliases: + # On recent PC machines, -noTSX and -IBRS models should be aliases: self.assertEqual(cpus["Haswell"].get('alias-of'), "Haswell-v1", "Haswell must be an alias") @@ -247,8 +214,8 @@ class CascadelakeArchCapabilities(QemuSystemTest): cpu_path = self.vm.cmd('query-cpus-fast')[0].get('qom-path') return self.vm.cmd('qom-get', path=cpu_path, property=prop) - def test_4_1(self): - self.set_machine('pc-i440fx-4.1') + def test(self): + self.set_machine('pc') # machine-type only: self.vm.add_args('-S') self.set_vm_arg('-cpu', @@ -256,80 +223,27 @@ class CascadelakeArchCapabilities(QemuSystemTest): 'enforce=off') self.vm.launch() self.assertFalse(self.get_cpu_prop('arch-capabilities'), - 'pc-i440fx-4.1 + Cascadelake-Server should not have arch-capabilities') - - def test_4_0(self): - self.set_machine('pc-i440fx-4.0') - self.vm.add_args('-S') - self.set_vm_arg('-cpu', - 'Cascadelake-Server,x-force-features=on,check=off,' - 'enforce=off') - self.vm.launch() - self.assertFalse(self.get_cpu_prop('arch-capabilities'), - 'pc-i440fx-4.0 + Cascadelake-Server should not have arch-capabilities') - - def test_set_4_0(self): - self.set_machine('pc-i440fx-4.0') - # command line must override machine-type if CPU model is not versioned: - self.vm.add_args('-S') - self.set_vm_arg('-cpu', - 'Cascadelake-Server,x-force-features=on,check=off,' - 'enforce=off,+arch-capabilities') - self.vm.launch() - self.assertTrue(self.get_cpu_prop('arch-capabilities'), - 'pc-i440fx-4.0 + Cascadelake-Server,+arch-capabilities should have arch-capabilities') + 'pc + Cascadelake-Server should not have arch-capabilities') - def test_unset_4_1(self): - self.set_machine('pc-i440fx-4.1') + def test_unset(self): + self.set_machine('pc') self.vm.add_args('-S') self.set_vm_arg('-cpu', 'Cascadelake-Server,x-force-features=on,check=off,' 'enforce=off,-arch-capabilities') self.vm.launch() self.assertFalse(self.get_cpu_prop('arch-capabilities'), - 'pc-i440fx-4.1 + Cascadelake-Server,-arch-capabilities should not have arch-capabilities') - - def test_v1_4_0(self): - self.set_machine('pc-i440fx-4.0') - # versioned CPU model overrides machine-type: - self.vm.add_args('-S') - self.set_vm_arg('-cpu', - 'Cascadelake-Server-v1,x-force-features=on,check=off,' - 'enforce=off') - self.vm.launch() - self.assertFalse(self.get_cpu_prop('arch-capabilities'), - 'pc-i440fx-4.0 + Cascadelake-Server-v1 should not have arch-capabilities') - - def test_v2_4_0(self): - self.set_machine('pc-i440fx-4.0') - self.vm.add_args('-S') - self.set_vm_arg('-cpu', - 'Cascadelake-Server-v2,x-force-features=on,check=off,' - 'enforce=off') - self.vm.launch() - self.assertTrue(self.get_cpu_prop('arch-capabilities'), - 'pc-i440fx-4.0 + Cascadelake-Server-v2 should have arch-capabilities') - - def test_v1_set_4_0(self): - self.set_machine('pc-i440fx-4.0') - # command line must override machine-type and versioned CPU model: - self.vm.add_args('-S') - self.set_vm_arg('-cpu', - 'Cascadelake-Server-v1,x-force-features=on,check=off,' - 'enforce=off,+arch-capabilities') - self.vm.launch() - self.assertTrue(self.get_cpu_prop('arch-capabilities'), - 'pc-i440fx-4.0 + Cascadelake-Server-v1,+arch-capabilities should have arch-capabilities') + 'pc + Cascadelake-Server,-arch-capabilities should not have arch-capabilities') - def test_v2_unset_4_1(self): - self.set_machine('pc-i440fx-4.1') + def test_v2_unset(self): + self.set_machine('pc') self.vm.add_args('-S') self.set_vm_arg('-cpu', 'Cascadelake-Server-v2,x-force-features=on,check=off,' 'enforce=off,-arch-capabilities') self.vm.launch() self.assertFalse(self.get_cpu_prop('arch-capabilities'), - 'pc-i440fx-4.1 + Cascadelake-Server-v2,-arch-capabilities should not have arch-capabilities') + 'pc + Cascadelake-Server-v2,-arch-capabilities should not have arch-capabilities') if __name__ == '__main__': QemuSystemTest.main() diff --git a/tests/functional/test_cpu_queries.py b/tests/functional/x86_64/test_cpu_queries.py index b1122a0..b1122a0 100755 --- a/tests/functional/test_cpu_queries.py +++ b/tests/functional/x86_64/test_cpu_queries.py diff --git a/tests/functional/test_x86_64_hotplug_blk.py b/tests/functional/x86_64/test_hotplug_blk.py index 7ddbfef..7ddbfef 100755 --- a/tests/functional/test_x86_64_hotplug_blk.py +++ b/tests/functional/x86_64/test_hotplug_blk.py diff --git a/tests/functional/test_x86_64_hotplug_cpu.py b/tests/functional/x86_64/test_hotplug_cpu.py index 7b9200a..7b9200a 100755 --- a/tests/functional/test_x86_64_hotplug_cpu.py +++ b/tests/functional/x86_64/test_hotplug_cpu.py diff --git a/tests/functional/test_intel_iommu.py b/tests/functional/x86_64/test_intel_iommu.py index 62268d6..62268d6 100755 --- a/tests/functional/test_intel_iommu.py +++ b/tests/functional/x86_64/test_intel_iommu.py diff --git a/tests/functional/test_x86_64_kvm_xen.py b/tests/functional/x86_64/test_kvm_xen.py index c6abf6b..a5d4450 100755 --- a/tests/functional/test_x86_64_kvm_xen.py +++ b/tests/functional/x86_64/test_kvm_xen.py @@ -11,8 +11,6 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os - from qemu.machine import machine from qemu_test import QemuSystemTest, Asset, exec_command_and_wait_for_pattern diff --git a/tests/functional/test_linux_initrd.py b/tests/functional/x86_64/test_linux_initrd.py index 2207f83..2207f83 100755 --- a/tests/functional/test_linux_initrd.py +++ b/tests/functional/x86_64/test_linux_initrd.py diff --git a/tests/functional/test_mem_addr_space.py b/tests/functional/x86_64/test_mem_addr_space.py index 2d9d31e..61b4a19 100755 --- a/tests/functional/test_mem_addr_space.py +++ b/tests/functional/x86_64/test_mem_addr_space.py @@ -58,8 +58,8 @@ class MemAddrCheck(QemuSystemTest): should start fine. """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'q35', '-m', - '512,slots=1,maxmem=59.6G', + 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') @@ -76,8 +76,8 @@ class MemAddrCheck(QemuSystemTest): with pse36 above. """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'q35', '-m', - '512,slots=1,maxmem=59.6G', + 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') @@ -93,8 +93,8 @@ class MemAddrCheck(QemuSystemTest): same options as the failing case above with pse36 cpu feature. """ self.ensure_64bit_binary() - self.vm.add_args('-machine', 'q35', '-m', - '512,slots=1,maxmem=59.5G', + 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') @@ -111,8 +111,8 @@ class MemAddrCheck(QemuSystemTest): with the same options as the case above. """ self.ensure_64bit_binary() - self.vm.add_args('-machine', 'q35', '-m', - '512,slots=1,maxmem=59.5G', + 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') @@ -128,8 +128,8 @@ class MemAddrCheck(QemuSystemTest): with pse36 ON. """ self.ensure_64bit_binary() - self.vm.add_args('-machine', 'q35', '-m', - '512,slots=1,maxmem=59.5G', + 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') @@ -148,8 +148,8 @@ class MemAddrCheck(QemuSystemTest): above 4 GiB due to the PCI hole and simplicity. """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'q35', '-m', - '512,slots=1,maxmem=4G', + 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') @@ -176,8 +176,8 @@ class MemAddrCheck(QemuSystemTest): make QEMU fail with the error message. """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'pc-q35-7.0', '-m', - '512,slots=1,maxmem=988G', + 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') @@ -197,8 +197,8 @@ class MemAddrCheck(QemuSystemTest): than 988 GiB). """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'pc-q35-7.1', '-m', - '512,slots=1,maxmem=976G', + 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') @@ -214,8 +214,8 @@ class MemAddrCheck(QemuSystemTest): successfully start when maxmem is < 988G. """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'pc-q35-7.0', '-m', - '512,slots=1,maxmem=987.5G', + 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') @@ -231,8 +231,8 @@ class MemAddrCheck(QemuSystemTest): successfully start when maxmem is < 976G. """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'pc-q35-7.1', '-m', - '512,slots=1,maxmem=975.5G', + 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') @@ -249,9 +249,9 @@ class MemAddrCheck(QemuSystemTest): "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') @@ -274,9 +274,9 @@ class MemAddrCheck(QemuSystemTest): 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') @@ -293,9 +293,9 @@ class MemAddrCheck(QemuSystemTest): 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') @@ -314,12 +314,12 @@ class MemAddrCheck(QemuSystemTest): 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() @@ -333,9 +333,10 @@ class MemAddrCheck(QemuSystemTest): 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/x86_64/test_memlock.py b/tests/functional/x86_64/test_memlock.py new file mode 100755 index 0000000..81bce80 --- /dev/null +++ b/tests/functional/x86_64/test_memlock.py @@ -0,0 +1,80 @@ +#!/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()) + + # libgcrypt may mlock a few pages + self.assertTrue(status['VmLck'] < 32) + + 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/x86_64/test_migration.py b/tests/functional/x86_64/test_migration.py new file mode 100755 index 0000000..f3a517a --- /dev/null +++ b/tests/functional/x86_64/test_migration.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# x86_64 migration test + +from migration import MigrationTest + + +class X8664MigrationTest(MigrationTest): + + def test_migration_with_tcp_localhost(self): + self.set_machine('microvm') + self.migration_with_tcp_localhost() + + def test_migration_with_unix(self): + self.set_machine('microvm') + self.migration_with_unix() + + def test_migration_with_exec(self): + self.set_machine('microvm') + self.migration_with_exec() + + +if __name__ == '__main__': + MigrationTest.main() diff --git a/tests/functional/x86_64/test_multiprocess.py b/tests/functional/x86_64/test_multiprocess.py new file mode 100755 index 0000000..756629d --- /dev/null +++ b/tests/functional/x86_64/test_multiprocess.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Test for multiprocess qemu on x86 + +from multiprocess import Multiprocess +from qemu_test import Asset + + +class X86Multiprocess(Multiprocess): + + 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') + + def test_multiprocess(self): + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyS0 rdinit=/bin/bash') + self.do_test(self.ASSET_KERNEL_X86, self.ASSET_INITRD_X86, + kernel_command_line, 'pc') + + +if __name__ == '__main__': + Multiprocess.main() diff --git a/tests/functional/test_netdev_ethtool.py b/tests/functional/x86_64/test_netdev_ethtool.py index ee1a397..ee1a397 100755 --- a/tests/functional/test_netdev_ethtool.py +++ b/tests/functional/x86_64/test_netdev_ethtool.py diff --git a/tests/functional/test_pc_cpu_hotplug_props.py b/tests/functional/x86_64/test_pc_cpu_hotplug_props.py index 9d5a37c..2bed8ad 100755 --- a/tests/functional/test_pc_cpu_hotplug_props.py +++ b/tests/functional/x86_64/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/x86_64/test_replay.py b/tests/functional/x86_64/test_replay.py new file mode 100755 index 0000000..27287d4 --- /dev/null +++ b/tests/functional/x86_64/test_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/x86_64/test_reverse_debug.py b/tests/functional/x86_64/test_reverse_debug.py new file mode 100755 index 0000000..2b31ae8 --- /dev/null +++ b/tests/functional/x86_64/test_reverse_debug.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Reverse debugging test for x86_64 +# +# Copyright (c) 2020 ISP RAS +# Copyright (c) 2025 Linaro Limited +# +# Author: +# Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru> +# Gustavo Romero <gustavo.romero@linaro.org> (Run without Avocado) +# +# 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 skipFlakyTest +from reverse_debugging import ReverseDebugging + + +class ReverseDebugging_X86_64(ReverseDebugging): + + @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(gdb_arch='x86-64') + + +if __name__ == '__main__': + ReverseDebugging.main() diff --git a/tests/functional/test_x86_64_tuxrun.py b/tests/functional/x86_64/test_tuxrun.py index fcbc62b..fcbc62b 100755 --- a/tests/functional/test_x86_64_tuxrun.py +++ b/tests/functional/x86_64/test_tuxrun.py diff --git a/tests/functional/x86_64/test_vfio_user_client.py b/tests/functional/x86_64/test_vfio_user_client.py new file mode 100755 index 0000000..8bc16e5 --- /dev/null +++ b/tests/functional/x86_64/test_vfio_user_client.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2025 Nutanix, Inc. +# +# Author: +# Mark Cave-Ayland <mark.caveayland@nutanix.com> +# John Levon <john.levon@nutanix.com> +# +# SPDX-License-Identifier: GPL-2.0-or-later +""" +Check basic vfio-user-pci client functionality. The test starts two VMs: + + - the server VM runs the libvfio-user "gpio" example server inside it, + piping vfio-user traffic between a local UNIX socket and a virtio-serial + port. On the host, the virtio-serial port is backed by a local socket. + + - the client VM loads the gpio-pci-idio-16 kernel module, with the + vfio-user client connecting to the above local UNIX socket. + +This way, we don't depend on trying to run a vfio-user server on the host +itself. + +Once both VMs are running, we run some basic configuration on the gpio device +and verify that the server is logging the expected out. As this is consistent +given the same VM images, we just do a simple direct comparison. +""" + +import os + +from qemu_test import Asset +from qemu_test import QemuSystemTest +from qemu_test import exec_command_and_wait_for_pattern +from qemu_test import wait_for_console_pattern + +# Exact output can vary, so we just sample for some expected lines. +EXPECTED_SERVER_LINES = [ + "gpio: adding DMA region [0, 0xc0000) offset=0 flags=0x3", + "gpio: devinfo flags 0x3, num_regions 9, num_irqs 5", + "gpio: region_info[0] offset 0 flags 0 size 0 argsz 32", + "gpio: region_info[1] offset 0 flags 0 size 0 argsz 32", + "gpio: region_info[2] offset 0 flags 0x3 size 256 argsz 32", + "gpio: region_info[3] offset 0 flags 0 size 0 argsz 32", + "gpio: region_info[4] offset 0 flags 0 size 0 argsz 32", + "gpio: region_info[5] offset 0 flags 0 size 0 argsz 32", + "gpio: region_info[7] offset 0 flags 0x3 size 256 argsz 32", + "gpio: region7: read 256 bytes at 0", + "gpio: region7: read 0 from (0x30:4)", + "gpio: cleared EROM", + "gpio: I/O space enabled", + "gpio: memory space enabled", + "gpio: SERR# enabled", + "gpio: region7: wrote 0x103 to (0x4:2)", + "gpio: I/O space enabled", + "gpio: memory space enabled", +] + +class VfioUserClient(QemuSystemTest): + """vfio-user testing class.""" + + ASSET_REPO = 'https://github.com/mcayland-ntx/libvfio-user-test' + + ASSET_KERNEL = Asset( + f'{ASSET_REPO}/raw/refs/heads/main/images/bzImage', + '40292fa6ce95d516e26bccf5974e138d0db65a6de0bc540cabae060fe9dea605' + ) + + ASSET_ROOTFS = Asset( + f'{ASSET_REPO}/raw/refs/heads/main/images/rootfs.ext2', + 'e1e3abae8aebb8e6e77f08b1c531caeacf46250c94c815655c6bbea59fc3d1c1' + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.kernel_path = None + self.rootfs_path = None + + def configure_server_vm_args(self, server_vm, sock_path): + """ + Configuration for the server VM. Set up virtio-serial device backed by + the given socket path. + """ + server_vm.add_args('-kernel', self.kernel_path) + server_vm.add_args('-append', 'console=ttyS0 root=/dev/sda') + server_vm.add_args('-drive', + f"file={self.rootfs_path},if=ide,format=raw,id=drv0") + server_vm.add_args('-snapshot') + server_vm.add_args('-chardev', + f"socket,id=sock0,path={sock_path},telnet=off,server=on,wait=off") + server_vm.add_args('-device', 'virtio-serial') + server_vm.add_args('-device', + 'virtserialport,chardev=sock0,name=org.fedoraproject.port.0') + + def configure_client_vm_args(self, client_vm, sock_path): + """ + Configuration for the client VM. Point the vfio-user-pci device to the + socket path configured above. + """ + + client_vm.add_args('-kernel', self.kernel_path) + client_vm.add_args('-append', 'console=ttyS0 root=/dev/sda') + client_vm.add_args('-drive', + f'file={self.rootfs_path},if=ide,format=raw,id=drv0') + client_vm.add_args('-snapshot') + client_vm.add_args('-device', + '{"driver":"vfio-user-pci",' + + '"socket":{"path": "%s", "type": "unix"}}' % sock_path) + + def setup_vfio_user_pci_server(self, server_vm): + """ + Start the libvfio-user server within the server VM, and arrange + for data to shuttle between its socket and the virtio serial port. + """ + wait_for_console_pattern(self, 'login:', None, server_vm) + exec_command_and_wait_for_pattern(self, 'root', '#', None, server_vm) + + exec_command_and_wait_for_pattern(self, + 'gpio-pci-idio-16 -v /tmp/vfio-user.sock >/var/tmp/gpio.out 2>&1 &', + '#', None, server_vm) + + # wait for libvfio-user socket to appear + while True: + out = exec_command_and_wait_for_pattern(self, + 'ls --color=no /tmp/vfio-user.sock', '#', None, server_vm) + ls_out = out.decode().splitlines()[1].strip() + if ls_out == "/tmp/vfio-user.sock": + break + + exec_command_and_wait_for_pattern(self, + 'socat UNIX-CONNECT:/tmp/vfio-user.sock /dev/vport0p1,ignoreeof ' + + ' &', '#', None, server_vm) + + def test_vfio_user_pci(self): + """Run basic sanity test.""" + + self.set_machine('pc') + self.require_device('virtio-serial') + self.require_device('vfio-user-pci') + + self.kernel_path = self.ASSET_KERNEL.fetch() + self.rootfs_path = self.ASSET_ROOTFS.fetch() + + sock_dir = self.socket_dir() + socket_path = os.path.join(sock_dir.name, 'vfio-user.sock') + + server_vm = self.get_vm(name='server') + server_vm.set_console() + self.configure_server_vm_args(server_vm, socket_path) + + server_vm.launch() + + self.log.debug('starting libvfio-user server') + + self.setup_vfio_user_pci_server(server_vm) + + client_vm = self.get_vm(name="client") + client_vm.set_console() + self.configure_client_vm_args(client_vm, socket_path) + + try: + client_vm.launch() + except: + self.log.error('client VM failed to start, dumping server logs') + exec_command_and_wait_for_pattern(self, 'cat /var/tmp/gpio.out', + '#', None, server_vm) + raise + + self.log.debug('waiting for client VM boot') + + wait_for_console_pattern(self, 'login:', None, client_vm) + exec_command_and_wait_for_pattern(self, 'root', '#', None, client_vm) + + # + # Here, we'd like to actually interact with the gpio device a little + # more as described at: + # + # https://github.com/nutanix/libvfio-user/blob/master/docs/qemu.md + # + # Unfortunately, the buildroot Linux kernel has some undiagnosed issue + # so we don't get /sys/class/gpio. Nonetheless just the basic + # initialization and setup is enough for basic testing of vfio-user. + # + + self.log.debug('collecting libvfio-user server output') + + out = exec_command_and_wait_for_pattern(self, + 'cat /var/tmp/gpio.out', + 'gpio: region2: wrote 0 to (0x1:1)', + None, server_vm) + + gpio_server_out = [s for s in out.decode().splitlines() + if s.startswith("gpio:")] + + for line in EXPECTED_SERVER_LINES: + if line not in gpio_server_out: + self.log.error(f'Missing server debug line: {line}') + self.fail(False) + + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/functional/test_virtio_balloon.py b/tests/functional/x86_64/test_virtio_balloon.py index 5877b6c..5877b6c 100755 --- a/tests/functional/test_virtio_balloon.py +++ b/tests/functional/x86_64/test_virtio_balloon.py diff --git a/tests/functional/test_virtio_gpu.py b/tests/functional/x86_64/test_virtio_gpu.py index 81c9156..be96de2 100755 --- a/tests/functional/test_virtio_gpu.py +++ b/tests/functional/x86_64/test_virtio_gpu.py @@ -108,6 +108,7 @@ class VirtioGPUx86(QemuSystemTest): shell=False, close_fds=False, ) + self._vug_log_file.close() self.vm.set_console() self.vm.add_args("-cpu", "host") @@ -135,6 +136,7 @@ class VirtioGPUx86(QemuSystemTest): "features: +virgl +edid") self.vm.shutdown() qemu_sock.close() + vug_sock.close() vugp.terminate() vugp.wait() diff --git a/tests/functional/test_virtio_version.py b/tests/functional/x86_64/test_virtio_version.py index a5ea732..a5ea732 100755 --- a/tests/functional/test_virtio_version.py +++ b/tests/functional/x86_64/test_virtio_version.py diff --git a/tests/functional/xtensa/meson.build b/tests/functional/xtensa/meson.build new file mode 100644 index 0000000..d61d82a --- /dev/null +++ b/tests/functional/xtensa/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +tests_xtensa_system_thorough = [ + 'lx60', + 'replay', +] diff --git a/tests/functional/test_xtensa_lx60.py b/tests/functional/xtensa/test_lx60.py index 147c920..147c920 100755 --- a/tests/functional/test_xtensa_lx60.py +++ b/tests/functional/xtensa/test_lx60.py diff --git a/tests/functional/test_xtensa_replay.py b/tests/functional/xtensa/test_replay.py index eb00a3b..eb00a3b 100755 --- a/tests/functional/test_xtensa_replay.py +++ b/tests/functional/xtensa/test_replay.py |