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