qemu/tests/functional/test_aarch64_smmu.py
Thomas Huth 5c2bae2155 tests/functional: Convert the SMMU test to the functional framework
This test was using cloudinit and a "dnf install" command in the guest
to exercise the NIC with SMMU enabled. Since we don't have the cloudinit
stuff in the functional framework and we should not rely on having access
to external networks (once our ASSETs have been cached), we rather boot
into the initrd first, manually mount the root disk and then use the
check_http_download() function from the functional framework here instead
for testing whether the network works as expected.

Unfortunately, there seems to be a small race when using the files
from Fedora 33: To enter the initrd shell, we have to send a "return"
once. But it does not seem to work if we send it too early. Using a
sleep(0.2) makes it work reliably for me, but to make it even more
unlikely to trigger this situation, let's better limit the Fedora 33
tests to only run with KVM.

Finally, while we're at it, we also add some lines for testing writes
to the hard disk, as we already do it in the test_intel_iommu test.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Message-ID: <20250414113031.151105-14-thuth@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
2025-04-23 07:51:25 +02:00

205 lines
8.8 KiB
Python
Executable file

#!/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
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):
self.require_accelerator("kvm")
self.require_netdev('user')
self.set_machine("virt")
self.vm.add_args('-m', '1G')
self.vm.add_args("-accel", "kvm")
self.vm.add_args("-cpu", "host")
self.vm.add_args("-machine", "iommu=smmuv3")
self.vm.add_args("-d", "guest_errors")
self.vm.add_args('-bios', os.path.join(BUILD_DIR, 'pc-bios',
'edk2-aarch64-code.fd'))
self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
self.vm.add_args('-object',
'rng-random,id=rng0,filename=/dev/urandom')
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()