1#!/usr/bin/env python3 2# 3# SPDX-License-Identifier: GPL-2.0-or-later 4# 5# SMMUv3 Functional tests 6# 7# Copyright (c) 2021 Red Hat, Inc. 8# 9# Author: 10# Eric Auger <eric.auger@redhat.com> 11# 12# This work is licensed under the terms of the GNU GPL, version 2 or 13# later. See the COPYING file in the top-level directory. 14 15import os 16import time 17 18from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern 19from qemu_test import BUILD_DIR 20from qemu.utils import kvm_available, hvf_available 21 22 23class SMMU(LinuxKernelTest): 24 25 default_kernel_params = ('earlyprintk=pl011,0x9000000 no_timer_check ' 26 'printk.time=1 rd_NO_PLYMOUTH net.ifnames=0 ' 27 'console=ttyAMA0 rd.rescue') 28 IOMMU_ADDON = ',iommu_platform=on,disable-modern=off,disable-legacy=on' 29 kernel_path = None 30 initrd_path = None 31 kernel_params = None 32 33 GUEST_PORT = 8080 34 35 def set_up_boot(self, path): 36 self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,' + 37 'drive=drv0,id=virtio-disk0,bootindex=1,' 38 'werror=stop,rerror=stop' + self.IOMMU_ADDON) 39 self.vm.add_args('-drive', 40 f'file={path},if=none,cache=writethrough,id=drv0,snapshot=on') 41 42 self.vm.add_args('-netdev', 43 'user,id=n1,hostfwd=tcp:127.0.0.1:0-:%d' % 44 self.GUEST_PORT) 45 self.vm.add_args('-device', 'virtio-net,netdev=n1' + self.IOMMU_ADDON) 46 47 def common_vm_setup(self, kernel, initrd, disk): 48 if hvf_available(self.qemu_bin): 49 accel = "hvf" 50 elif kvm_available(self.qemu_bin): 51 accel = "kvm" 52 else: 53 self.skipTest("Neither HVF nor KVM accelerator is available") 54 self.require_accelerator(accel) 55 self.require_netdev('user') 56 self.set_machine("virt") 57 self.vm.add_args('-m', '1G') 58 self.vm.add_args("-accel", accel) 59 self.vm.add_args("-cpu", "host") 60 self.vm.add_args("-machine", "iommu=smmuv3") 61 self.vm.add_args("-d", "guest_errors") 62 self.vm.add_args('-bios', os.path.join(BUILD_DIR, 'pc-bios', 63 'edk2-aarch64-code.fd')) 64 self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0') 65 self.vm.add_args('-object', 66 'rng-random,id=rng0,filename=/dev/urandom') 67 68 self.kernel_path = kernel.fetch() 69 self.initrd_path = initrd.fetch() 70 self.set_up_boot(disk.fetch()) 71 72 def run_and_check(self, filename, hashsum): 73 self.vm.add_args('-initrd', self.initrd_path) 74 self.vm.add_args('-append', self.kernel_params) 75 self.launch_kernel(self.kernel_path, initrd=self.initrd_path, 76 wait_for='attach it to a bug report.') 77 prompt = '# ' 78 # Fedora 33 requires 'return' to be pressed to enter the shell. 79 # There seems to be a small race between detecting the previous ':' 80 # and sending the newline, so we need to add a small delay here. 81 self.wait_for_console_pattern(':') 82 time.sleep(0.2) 83 exec_command_and_wait_for_pattern(self, '\n', prompt) 84 exec_command_and_wait_for_pattern(self, 'cat /proc/cmdline', 85 self.kernel_params) 86 87 # Checking for SMMU enablement: 88 self.log.info("Checking whether SMMU has been enabled...") 89 exec_command_and_wait_for_pattern(self, 'dmesg | grep smmu', 90 'arm-smmu-v3') 91 self.wait_for_console_pattern(prompt) 92 exec_command_and_wait_for_pattern(self, 93 'find /sys/kernel/iommu_groups/ -type l', 94 'devices/0000:00:') 95 self.wait_for_console_pattern(prompt) 96 97 # Copy a file (checked later), umount afterwards to drop disk cache: 98 self.log.info("Checking hard disk...") 99 exec_command_and_wait_for_pattern(self, 100 "while ! (dmesg -c | grep vda:) ; do sleep 1 ; done", 101 "vda2") 102 exec_command_and_wait_for_pattern(self, 'mount /dev/vda2 /sysroot', 103 'mounted filesystem') 104 exec_command_and_wait_for_pattern(self, 'cp /bin/vi /sysroot/root/vi', 105 prompt) 106 exec_command_and_wait_for_pattern(self, 'umount /sysroot', prompt) 107 # Switch from initrd to the cloud image filesystem: 108 exec_command_and_wait_for_pattern(self, 'mount /dev/vda2 /sysroot', 109 prompt) 110 exec_command_and_wait_for_pattern(self, 111 ('for d in dev proc sys run ; do ' 112 'mount -o bind /$d /sysroot/$d ; done'), prompt) 113 exec_command_and_wait_for_pattern(self, 'chroot /sysroot', prompt) 114 # Check files on the hard disk: 115 exec_command_and_wait_for_pattern(self, 116 ('if diff -q /root/vi /usr/bin/vi ; then echo "file" "ok" ; ' 117 'else echo "files differ"; fi'), 'file ok') 118 self.wait_for_console_pattern(prompt) 119 exec_command_and_wait_for_pattern(self, f'sha256sum {filename}', 120 hashsum) 121 122 # Check virtio-net via HTTP: 123 exec_command_and_wait_for_pattern(self, 'dhclient eth0', prompt) 124 self.check_http_download(filename, hashsum, self.GUEST_PORT) 125 126 127 # 5.3 kernel without RIL # 128 129 ASSET_KERNEL_F31 = Asset( 130 ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' 131 'releases/31/Server/aarch64/os/images/pxeboot/vmlinuz'), 132 '3ae07fcafbfc8e4abeb693035a74fe10698faae15e9ccd48882a9167800c1527') 133 134 ASSET_INITRD_F31 = Asset( 135 ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' 136 'releases/31/Server/aarch64/os/images/pxeboot/initrd.img'), 137 '9f3146b28bc531c689f3c5f114cb74e4bd7bd548e0ba19fa77921d8bd256755a') 138 139 ASSET_DISK_F31 = Asset( 140 ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases' 141 '/31/Cloud/aarch64/images/Fedora-Cloud-Base-31-1.9.aarch64.qcow2'), 142 '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49') 143 144 F31_FILENAME = '/boot/initramfs-5.3.7-301.fc31.aarch64.img' 145 F31_HSUM = '1a4beec6607d94df73d9dd1b4985c9c23dd0fdcf4e6ca1351d477f190df7bef9' 146 147 def test_smmu_noril(self): 148 self.common_vm_setup(self.ASSET_KERNEL_F31, self.ASSET_INITRD_F31, 149 self.ASSET_DISK_F31) 150 self.kernel_params = self.default_kernel_params 151 self.run_and_check(self.F31_FILENAME, self.F31_HSUM) 152 153 def test_smmu_noril_passthrough(self): 154 self.common_vm_setup(self.ASSET_KERNEL_F31, self.ASSET_INITRD_F31, 155 self.ASSET_DISK_F31) 156 self.kernel_params = (self.default_kernel_params + 157 ' iommu.passthrough=on') 158 self.run_and_check(self.F31_FILENAME, self.F31_HSUM) 159 160 def test_smmu_noril_nostrict(self): 161 self.common_vm_setup(self.ASSET_KERNEL_F31, self.ASSET_INITRD_F31, 162 self.ASSET_DISK_F31) 163 self.kernel_params = (self.default_kernel_params + 164 ' iommu.strict=0') 165 self.run_and_check(self.F31_FILENAME, self.F31_HSUM) 166 167 168 # 5.8 kernel featuring range invalidation 169 # >= v5.7 kernel 170 171 ASSET_KERNEL_F33 = Asset( 172 ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' 173 'releases/33/Server/aarch64/os/images/pxeboot/vmlinuz'), 174 'd8b1e6f7241f339d8e7609c456cf0461ffa4583ed07e0b55c7d1d8a0c154aa89') 175 176 ASSET_INITRD_F33 = Asset( 177 ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' 178 'releases/33/Server/aarch64/os/images/pxeboot/initrd.img'), 179 '92513f55295c2c16a777f7b6c35ccd70a438e9e1e40b6ba39e0e60900615b3df') 180 181 ASSET_DISK_F33 = Asset( 182 ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases' 183 '/33/Cloud/aarch64/images/Fedora-Cloud-Base-33-1.2.aarch64.qcow2'), 184 'e7f75cdfd523fe5ac2ca9eeece68edc1a81f386a17f969c1d1c7c87031008a6b') 185 186 F33_FILENAME = '/boot/initramfs-5.8.15-301.fc33.aarch64.img' 187 F33_HSUM = '079cfad0caa82e84c8ca1fb0897a4999dd769f262216099f518619e807a550d9' 188 189 def test_smmu_ril(self): 190 self.common_vm_setup(self.ASSET_KERNEL_F33, self.ASSET_INITRD_F33, 191 self.ASSET_DISK_F33) 192 self.kernel_params = self.default_kernel_params 193 self.run_and_check(self.F33_FILENAME, self.F33_HSUM) 194 195 def test_smmu_ril_passthrough(self): 196 self.common_vm_setup(self.ASSET_KERNEL_F33, self.ASSET_INITRD_F33, 197 self.ASSET_DISK_F33) 198 self.kernel_params = (self.default_kernel_params + 199 ' iommu.passthrough=on') 200 self.run_and_check(self.F33_FILENAME, self.F33_HSUM) 201 202 def test_smmu_ril_nostrict(self): 203 self.common_vm_setup(self.ASSET_KERNEL_F33, self.ASSET_INITRD_F33, 204 self.ASSET_DISK_F33) 205 self.kernel_params = (self.default_kernel_params + 206 ' iommu.strict=0') 207 self.run_and_check(self.F33_FILENAME, self.F33_HSUM) 208 209 210if __name__ == '__main__': 211 LinuxKernelTest.main() 212