1#!/usr/bin/env python3 2# 3# Functional test that boots an s390x Linux guest with ccw and PCI devices 4# attached and checks whether the devices are recognized by Linux 5# 6# Copyright (c) 2020 Red Hat, Inc. 7# 8# Author: 9# Cornelia Huck <cohuck@redhat.com> 10# 11# This work is licensed under the terms of the GNU GPL, version 2 or 12# later. See the COPYING file in the top-level directory. 13 14import os 15import tempfile 16 17from qemu_test import QemuSystemTest, Asset 18from qemu_test import exec_command_and_wait_for_pattern 19from qemu_test import wait_for_console_pattern 20from qemu_test.utils import lzma_uncompress 21 22class S390CCWVirtioMachine(QemuSystemTest): 23 KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' 24 25 timeout = 120 26 27 ASSET_BUSTER_KERNEL = Asset( 28 ('https://snapshot.debian.org/archive/debian/' 29 '20201126T092837Z/dists/buster/main/installer-s390x/' 30 '20190702+deb10u6/images/generic/kernel.debian'), 31 'd411d17c39ae7ad38d27534376cbe88b68b403c325739364122c2e6f1537e818') 32 ASSET_BUSTER_INITRD = Asset( 33 ('https://snapshot.debian.org/archive/debian/' 34 '20201126T092837Z/dists/buster/main/installer-s390x/' 35 '20190702+deb10u6/images/generic/initrd.debian'), 36 '836bbd0fe6a5ca81274c28c2b063ea315ce1868660866e9b60180c575fef9fd5') 37 38 ASSET_F31_KERNEL = Asset( 39 ('https://archives.fedoraproject.org/pub/archive' 40 '/fedora-secondary/releases/31/Server/s390x/os' 41 '/images/kernel.img'), 42 '480859574f3f44caa6cd35c62d70e1ac0609134e22ce2a954bbed9b110c06e0b') 43 ASSET_F31_INITRD = Asset( 44 ('https://archives.fedoraproject.org/pub/archive' 45 '/fedora-secondary/releases/31/Server/s390x/os' 46 '/images/initrd.img'), 47 '04c46095b2c49020b1c2327158898b7db747e4892ae319726192fb949716aa9c') 48 49 def wait_for_console_pattern(self, success_message, vm=None): 50 wait_for_console_pattern(self, success_message, 51 failure_message='Kernel panic - not syncing', 52 vm=vm) 53 54 def wait_for_crw_reports(self): 55 exec_command_and_wait_for_pattern(self, 56 'while ! (dmesg -c | grep CRW) ; do sleep 1 ; done', 57 'CRW reports') 58 59 dmesg_clear_count = 1 60 def clear_guest_dmesg(self): 61 exec_command_and_wait_for_pattern(self, 'dmesg -c > /dev/null; ' 62 r'echo dm_clear\ ' + str(self.dmesg_clear_count), 63 r'dm_clear ' + str(self.dmesg_clear_count)) 64 self.dmesg_clear_count += 1 65 66 def test_s390x_devices(self): 67 self.set_machine('s390-ccw-virtio') 68 69 kernel_path = self.ASSET_BUSTER_KERNEL.fetch() 70 initrd_path = self.ASSET_BUSTER_INITRD.fetch() 71 72 self.vm.set_console() 73 kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + 74 'console=sclp0 root=/dev/ram0 BOOT_DEBUG=3') 75 self.vm.add_args('-nographic', 76 '-kernel', kernel_path, 77 '-initrd', initrd_path, 78 '-append', kernel_command_line, 79 '-cpu', 'max,prno-trng=off', 80 '-device', 'virtio-net-ccw,devno=fe.1.1111', 81 '-device', 82 'virtio-rng-ccw,devno=fe.2.0000,max_revision=0,id=rn1', 83 '-device', 84 'virtio-rng-ccw,devno=fe.3.1234,max_revision=2,id=rn2', 85 '-device', 'zpci,uid=5,target=zzz', 86 '-device', 'virtio-net-pci,id=zzz', 87 '-device', 'zpci,uid=0xa,fid=12,target=serial', 88 '-device', 'virtio-serial-pci,id=serial', 89 '-device', 'virtio-balloon-ccw') 90 self.vm.launch() 91 92 shell_ready = "sh: can't access tty; job control turned off" 93 self.wait_for_console_pattern(shell_ready) 94 # first debug shell is too early, we need to wait for device detection 95 exec_command_and_wait_for_pattern(self, 'exit', shell_ready) 96 97 ccw_bus_ids="0.1.1111 0.2.0000 0.3.1234" 98 pci_bus_ids="0005:00:00.0 000a:00:00.0" 99 exec_command_and_wait_for_pattern(self, 'ls /sys/bus/ccw/devices/', 100 ccw_bus_ids) 101 exec_command_and_wait_for_pattern(self, 'ls /sys/bus/pci/devices/', 102 pci_bus_ids) 103 # check that the device at 0.2.0000 is in legacy mode, while the 104 # device at 0.3.1234 has the virtio-1 feature bit set 105 virtio_rng_features="00000000000000000000000000001100" + \ 106 "10000000000000000000000000000000" 107 virtio_rng_features_legacy="00000000000000000000000000001100" + \ 108 "00000000000000000000000000000000" 109 exec_command_and_wait_for_pattern(self, 110 'cat /sys/bus/ccw/devices/0.2.0000/virtio?/features', 111 virtio_rng_features_legacy) 112 exec_command_and_wait_for_pattern(self, 113 'cat /sys/bus/ccw/devices/0.3.1234/virtio?/features', 114 virtio_rng_features) 115 # check that /dev/hwrng works - and that it's gone after ejecting 116 exec_command_and_wait_for_pattern(self, 117 'dd if=/dev/hwrng of=/dev/null bs=1k count=10', 118 '10+0 records out') 119 self.clear_guest_dmesg() 120 self.vm.cmd('device_del', id='rn1') 121 self.wait_for_crw_reports() 122 self.clear_guest_dmesg() 123 self.vm.cmd('device_del', id='rn2') 124 self.wait_for_crw_reports() 125 exec_command_and_wait_for_pattern(self, 126 'dd if=/dev/hwrng of=/dev/null bs=1k count=10', 127 'dd: /dev/hwrng: No such device') 128 # verify that we indeed have virtio-net devices (without having the 129 # virtio-net driver handy) 130 exec_command_and_wait_for_pattern(self, 131 'cat /sys/bus/ccw/devices/0.1.1111/cutype', 132 '3832/01') 133 exec_command_and_wait_for_pattern(self, 134 r'cat /sys/bus/pci/devices/0005\:00\:00.0/subsystem_vendor', 135 r'0x1af4') 136 exec_command_and_wait_for_pattern(self, 137 r'cat /sys/bus/pci/devices/0005\:00\:00.0/subsystem_device', 138 r'0x0001') 139 # check fid propagation 140 exec_command_and_wait_for_pattern(self, 141 r'cat /sys/bus/pci/devices/000a\:00\:00.0/function_id', 142 r'0x0000000c') 143 # add another device 144 self.clear_guest_dmesg() 145 self.vm.cmd('device_add', driver='virtio-net-ccw', 146 devno='fe.0.4711', id='net_4711') 147 self.wait_for_crw_reports() 148 exec_command_and_wait_for_pattern(self, 'for i in 1 2 3 4 5 6 7 ; do ' 149 'if [ -e /sys/bus/ccw/devices/*4711 ]; then break; fi ;' 150 'sleep 1 ; done ; ls /sys/bus/ccw/devices/', 151 '0.0.4711') 152 # and detach it again 153 self.clear_guest_dmesg() 154 self.vm.cmd('device_del', id='net_4711') 155 self.vm.event_wait(name='DEVICE_DELETED', 156 match={'data': {'device': 'net_4711'}}) 157 self.wait_for_crw_reports() 158 exec_command_and_wait_for_pattern(self, 159 'ls /sys/bus/ccw/devices/0.0.4711', 160 'No such file or directory') 161 # test the virtio-balloon device 162 exec_command_and_wait_for_pattern(self, 'head -n 1 /proc/meminfo', 163 'MemTotal: 115640 kB') 164 self.vm.cmd('human-monitor-command', command_line='balloon 96') 165 exec_command_and_wait_for_pattern(self, 'head -n 1 /proc/meminfo', 166 'MemTotal: 82872 kB') 167 self.vm.cmd('human-monitor-command', command_line='balloon 128') 168 exec_command_and_wait_for_pattern(self, 'head -n 1 /proc/meminfo', 169 'MemTotal: 115640 kB') 170 171 172 def test_s390x_fedora(self): 173 self.set_machine('s390-ccw-virtio') 174 175 kernel_path = self.ASSET_F31_KERNEL.fetch() 176 177 initrd_path_xz = self.ASSET_F31_INITRD.fetch() 178 initrd_path = os.path.join(self.workdir, 'initrd-raw.img') 179 lzma_uncompress(initrd_path_xz, initrd_path) 180 181 self.vm.set_console() 182 kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + ' audit=0 ' 183 'rd.plymouth=0 plymouth.enable=0 rd.rescue') 184 self.vm.add_args('-nographic', 185 '-smp', '4', 186 '-m', '512', 187 '-name', 'Some Guest Name', 188 '-uuid', '30de4fd9-b4d5-409e-86a5-09b387f70bfa', 189 '-kernel', kernel_path, 190 '-initrd', initrd_path, 191 '-append', kernel_command_line, 192 '-device', 'zpci,uid=7,target=n', 193 '-device', 'virtio-net-pci,id=n,mac=02:ca:fe:fa:ce:12', 194 '-device', 'virtio-rng-ccw,devno=fe.1.9876', 195 '-device', 'virtio-gpu-ccw,devno=fe.2.5432') 196 self.vm.launch() 197 self.wait_for_console_pattern('Kernel command line: %s' 198 % kernel_command_line) 199 self.wait_for_console_pattern('Entering emergency mode') 200 201 # Some tests to see whether the CLI options have been considered: 202 self.log.info("Test whether QEMU CLI options have been considered") 203 exec_command_and_wait_for_pattern(self, 204 'while ! (dmesg | grep enP7p0s0) ; do sleep 1 ; done', 205 'virtio_net virtio0 enP7p0s0: renamed') 206 exec_command_and_wait_for_pattern(self, 'lspci', 207 '0007:00:00.0 Class 0200: Device 1af4:1000') 208 exec_command_and_wait_for_pattern(self, 209 'cat /sys/class/net/enP7p0s0/address', 210 '02:ca:fe:fa:ce:12') 211 exec_command_and_wait_for_pattern(self, 'lscss', '0.1.9876') 212 exec_command_and_wait_for_pattern(self, 'lscss', '0.2.5432') 213 exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo', 214 'processors : 4') 215 exec_command_and_wait_for_pattern(self, 'grep MemTotal /proc/meminfo', 216 'MemTotal: 499848 kB') 217 exec_command_and_wait_for_pattern(self, 'grep Name /proc/sysinfo', 218 'Extended Name: Some Guest Name') 219 exec_command_and_wait_for_pattern(self, 'grep UUID /proc/sysinfo', 220 '30de4fd9-b4d5-409e-86a5-09b387f70bfa') 221 222 # Disable blinking cursor, then write some stuff into the framebuffer. 223 # QEMU's PPM screendumps contain uncompressed 24-bit values, while the 224 # framebuffer uses 32-bit, so we pad our text with some spaces when 225 # writing to the framebuffer. Since the PPM is uncompressed, we then 226 # can simply read the written "magic bytes" back from the PPM file to 227 # check whether the framebuffer is working as expected. 228 # Unfortunately, this test is flaky, so we don't run it by default 229 if os.getenv('QEMU_TEST_FLAKY_TESTS'): 230 self.log.info("Test screendump of virtio-gpu device") 231 exec_command_and_wait_for_pattern(self, 232 'while ! (dmesg | grep gpudrmfb) ; do sleep 1 ; done', 233 'virtio_gpudrmfb frame buffer device') 234 exec_command_and_wait_for_pattern(self, 235 r'echo -e "\e[?25l" > /dev/tty0', ':/#') 236 exec_command_and_wait_for_pattern(self, 'for ((i=0;i<250;i++)); do ' 237 'echo " The qu ick fo x j ump s o ver a laz y d og" >> fox.txt;' 238 'done', 239 ':/#') 240 exec_command_and_wait_for_pattern(self, 241 'dd if=fox.txt of=/dev/fb0 bs=1000 oflag=sync,nocache ; rm fox.txt', 242 '12+0 records out') 243 with tempfile.NamedTemporaryFile(suffix='.ppm', 244 prefix='qemu-scrdump-') as ppmfile: 245 self.vm.cmd('screendump', filename=ppmfile.name) 246 ppmfile.seek(0) 247 line = ppmfile.readline() 248 self.assertEqual(line, b"P6\n") 249 line = ppmfile.readline() 250 self.assertEqual(line, b"1280 800\n") 251 line = ppmfile.readline() 252 self.assertEqual(line, b"255\n") 253 line = ppmfile.readline(256) 254 self.assertEqual(line, b"The quick fox jumps over a lazy dog\n") 255 else: 256 self.log.info("Skipped flaky screendump of virtio-gpu device test") 257 258 # Hot-plug a virtio-crypto device and see whether it gets accepted 259 self.log.info("Test hot-plug virtio-crypto device") 260 self.clear_guest_dmesg() 261 self.vm.cmd('object-add', qom_type='cryptodev-backend-builtin', 262 id='cbe0') 263 self.vm.cmd('device_add', driver='virtio-crypto-ccw', id='crypdev0', 264 cryptodev='cbe0', devno='fe.0.2342') 265 exec_command_and_wait_for_pattern(self, 266 'while ! (dmesg -c | grep Accelerator.device) ; do' 267 ' sleep 1 ; done', 'Accelerator device is ready') 268 exec_command_and_wait_for_pattern(self, 'lscss', '0.0.2342') 269 self.vm.cmd('device_del', id='crypdev0') 270 self.vm.cmd('object-del', id='cbe0') 271 exec_command_and_wait_for_pattern(self, 272 'while ! (dmesg -c | grep Start.virtcrypto_remove) ; do' 273 ' sleep 1 ; done', 'Start virtcrypto_remove.') 274 275if __name__ == '__main__': 276 QemuSystemTest.main() 277