1cce85725SThomas Huth#!/usr/bin/env python3 2cce85725SThomas Huth""" 3cce85725SThomas HuthCheck compatibility of virtio device types 4cce85725SThomas Huth""" 5cce85725SThomas Huth# Copyright (c) 2018 Red Hat, Inc. 6cce85725SThomas Huth# 7cce85725SThomas Huth# Author: 8cce85725SThomas Huth# Eduardo Habkost <ehabkost@redhat.com> 9cce85725SThomas Huth# 10cce85725SThomas Huth# This work is licensed under the terms of the GNU GPL, version 2 or 11cce85725SThomas Huth# later. See the COPYING file in the top-level directory. 12cce85725SThomas Huthimport sys 13cce85725SThomas Huthimport os 14cce85725SThomas Huth 15cce85725SThomas Huthfrom qemu.machine import QEMUMachine 16cce85725SThomas Huthfrom qemu_test import QemuSystemTest 17cce85725SThomas Huth 18cce85725SThomas Huth# Virtio Device IDs: 19cce85725SThomas HuthVIRTIO_NET = 1 20cce85725SThomas HuthVIRTIO_BLOCK = 2 21cce85725SThomas HuthVIRTIO_CONSOLE = 3 22cce85725SThomas HuthVIRTIO_RNG = 4 23cce85725SThomas HuthVIRTIO_BALLOON = 5 24cce85725SThomas HuthVIRTIO_RPMSG = 7 25cce85725SThomas HuthVIRTIO_SCSI = 8 26cce85725SThomas HuthVIRTIO_9P = 9 27cce85725SThomas HuthVIRTIO_RPROC_SERIAL = 11 28cce85725SThomas HuthVIRTIO_CAIF = 12 29cce85725SThomas HuthVIRTIO_GPU = 16 30cce85725SThomas HuthVIRTIO_INPUT = 18 31cce85725SThomas HuthVIRTIO_VSOCK = 19 32cce85725SThomas HuthVIRTIO_CRYPTO = 20 33cce85725SThomas Huth 34cce85725SThomas HuthPCI_VENDOR_ID_REDHAT_QUMRANET = 0x1af4 35cce85725SThomas Huth 36cce85725SThomas Huth# Device IDs for legacy/transitional devices: 37cce85725SThomas HuthPCI_LEGACY_DEVICE_IDS = { 38cce85725SThomas Huth VIRTIO_NET: 0x1000, 39cce85725SThomas Huth VIRTIO_BLOCK: 0x1001, 40cce85725SThomas Huth VIRTIO_BALLOON: 0x1002, 41cce85725SThomas Huth VIRTIO_CONSOLE: 0x1003, 42cce85725SThomas Huth VIRTIO_SCSI: 0x1004, 43cce85725SThomas Huth VIRTIO_RNG: 0x1005, 44cce85725SThomas Huth VIRTIO_9P: 0x1009, 45cce85725SThomas Huth VIRTIO_VSOCK: 0x1012, 46cce85725SThomas Huth} 47cce85725SThomas Huth 48cce85725SThomas Huthdef pci_modern_device_id(virtio_devid): 49cce85725SThomas Huth return virtio_devid + 0x1040 50cce85725SThomas Huth 51cce85725SThomas Huthdef devtype_implements(vm, devtype, implements): 52cce85725SThomas Huth return devtype in [d['name'] for d in 53cce85725SThomas Huth vm.cmd('qom-list-types', implements=implements)] 54cce85725SThomas Huth 55cce85725SThomas Huthdef get_pci_interfaces(vm, devtype): 56cce85725SThomas Huth interfaces = ('pci-express-device', 'conventional-pci-device') 57cce85725SThomas Huth return [i for i in interfaces if devtype_implements(vm, devtype, i)] 58cce85725SThomas Huth 59cce85725SThomas Huthclass VirtioVersionCheck(QemuSystemTest): 60cce85725SThomas Huth """ 61cce85725SThomas Huth Check if virtio-version-specific device types result in the 62cce85725SThomas Huth same device tree created by `disable-modern` and 63cce85725SThomas Huth `disable-legacy`. 64cce85725SThomas Huth """ 65cce85725SThomas Huth 66cce85725SThomas Huth # just in case there are failures, show larger diff: 67cce85725SThomas Huth maxDiff = 4096 68cce85725SThomas Huth 69cce85725SThomas Huth def run_device(self, devtype, opts=None, machine='pc'): 70cce85725SThomas Huth """ 71cce85725SThomas Huth Run QEMU with `-device DEVTYPE`, return device info from `query-pci` 72cce85725SThomas Huth """ 73cce85725SThomas Huth with QEMUMachine(self.qemu_bin) as vm: 74cce85725SThomas Huth vm.set_machine(machine) 75cce85725SThomas Huth if opts: 76cce85725SThomas Huth devtype += ',' + opts 77cce85725SThomas Huth vm.add_args('-device', '%s,id=devfortest' % (devtype)) 78cce85725SThomas Huth vm.add_args('-S') 79cce85725SThomas Huth vm.launch() 80cce85725SThomas Huth 81cce85725SThomas Huth pcibuses = vm.cmd('query-pci') 82cce85725SThomas Huth alldevs = [dev for bus in pcibuses for dev in bus['devices']] 83cce85725SThomas Huth devfortest = [dev for dev in alldevs 84cce85725SThomas Huth if dev['qdev_id'] == 'devfortest'] 85cce85725SThomas Huth return devfortest[0], get_pci_interfaces(vm, devtype) 86cce85725SThomas Huth 87cce85725SThomas Huth 88cce85725SThomas Huth def assert_devids(self, dev, devid, non_transitional=False): 89cce85725SThomas Huth self.assertEqual(dev['id']['vendor'], PCI_VENDOR_ID_REDHAT_QUMRANET) 90cce85725SThomas Huth self.assertEqual(dev['id']['device'], devid) 91cce85725SThomas Huth if non_transitional: 92cce85725SThomas Huth self.assertTrue(0x1040 <= dev['id']['device'] <= 0x107f) 93cce85725SThomas Huth self.assertGreaterEqual(dev['id']['subsystem'], 0x40) 94cce85725SThomas Huth 95cce85725SThomas Huth def check_all_variants(self, qemu_devtype, virtio_devid): 96cce85725SThomas Huth """Check if a virtio device type and its variants behave as expected""" 97cce85725SThomas Huth # Force modern mode: 98cce85725SThomas Huth dev_modern, _ = self.run_device(qemu_devtype, 99cce85725SThomas Huth 'disable-modern=off,disable-legacy=on') 100cce85725SThomas Huth self.assert_devids(dev_modern, pci_modern_device_id(virtio_devid), 101cce85725SThomas Huth non_transitional=True) 102cce85725SThomas Huth 103cce85725SThomas Huth # <prefix>-non-transitional device types should be 100% equivalent to 104cce85725SThomas Huth # <prefix>,disable-modern=off,disable-legacy=on 105cce85725SThomas Huth dev_1_0, nt_ifaces = self.run_device('%s-non-transitional' % (qemu_devtype)) 106cce85725SThomas Huth self.assertEqual(dev_modern, dev_1_0) 107cce85725SThomas Huth 108cce85725SThomas Huth # Force transitional mode: 109cce85725SThomas Huth dev_trans, _ = self.run_device(qemu_devtype, 110cce85725SThomas Huth 'disable-modern=off,disable-legacy=off') 111cce85725SThomas Huth self.assert_devids(dev_trans, PCI_LEGACY_DEVICE_IDS[virtio_devid]) 112cce85725SThomas Huth 113cce85725SThomas Huth # Force legacy mode: 114cce85725SThomas Huth dev_legacy, _ = self.run_device(qemu_devtype, 115cce85725SThomas Huth 'disable-modern=on,disable-legacy=off') 116cce85725SThomas Huth self.assert_devids(dev_legacy, PCI_LEGACY_DEVICE_IDS[virtio_devid]) 117cce85725SThomas Huth 118cce85725SThomas Huth # No options: default to transitional on PC machine-type: 119cce85725SThomas Huth no_opts_pc, generic_ifaces = self.run_device(qemu_devtype) 120cce85725SThomas Huth self.assertEqual(dev_trans, no_opts_pc) 121cce85725SThomas Huth 122cce85725SThomas Huth #TODO: check if plugging on a PCI Express bus will make the 123cce85725SThomas Huth # device non-transitional 124cce85725SThomas Huth #no_opts_q35 = self.run_device(qemu_devtype, machine='q35') 125cce85725SThomas Huth #self.assertEqual(dev_modern, no_opts_q35) 126cce85725SThomas Huth 127cce85725SThomas Huth # <prefix>-transitional device types should be 100% equivalent to 128cce85725SThomas Huth # <prefix>,disable-modern=off,disable-legacy=off 129cce85725SThomas Huth dev_trans, trans_ifaces = self.run_device('%s-transitional' % (qemu_devtype)) 130cce85725SThomas Huth self.assertEqual(dev_trans, dev_trans) 131cce85725SThomas Huth 132cce85725SThomas Huth # ensure the interface information is correct: 133cce85725SThomas Huth self.assertIn('conventional-pci-device', generic_ifaces) 134cce85725SThomas Huth self.assertIn('pci-express-device', generic_ifaces) 135cce85725SThomas Huth 136cce85725SThomas Huth self.assertIn('conventional-pci-device', nt_ifaces) 137cce85725SThomas Huth self.assertIn('pci-express-device', nt_ifaces) 138cce85725SThomas Huth 139cce85725SThomas Huth self.assertIn('conventional-pci-device', trans_ifaces) 140cce85725SThomas Huth self.assertNotIn('pci-express-device', trans_ifaces) 141cce85725SThomas Huth 142cce85725SThomas Huth 143cce85725SThomas Huth def test_conventional_devs(self): 144*c78ba434SThomas Huth self.set_machine('pc') 145cce85725SThomas Huth self.check_all_variants('virtio-net-pci', VIRTIO_NET) 146cce85725SThomas Huth # virtio-blk requires 'driver' parameter 147cce85725SThomas Huth #self.check_all_variants('virtio-blk-pci', VIRTIO_BLOCK) 148cce85725SThomas Huth self.check_all_variants('virtio-serial-pci', VIRTIO_CONSOLE) 149cce85725SThomas Huth self.check_all_variants('virtio-rng-pci', VIRTIO_RNG) 150cce85725SThomas Huth self.check_all_variants('virtio-balloon-pci', VIRTIO_BALLOON) 151cce85725SThomas Huth self.check_all_variants('virtio-scsi-pci', VIRTIO_SCSI) 152cce85725SThomas Huth # virtio-9p requires 'fsdev' parameter 153cce85725SThomas Huth #self.check_all_variants('virtio-9p-pci', VIRTIO_9P) 154cce85725SThomas Huth 155cce85725SThomas Huth def check_modern_only(self, qemu_devtype, virtio_devid): 156cce85725SThomas Huth """Check if a modern-only virtio device type behaves as expected""" 157cce85725SThomas Huth # Force modern mode: 158cce85725SThomas Huth dev_modern, _ = self.run_device(qemu_devtype, 159cce85725SThomas Huth 'disable-modern=off,disable-legacy=on') 160cce85725SThomas Huth self.assert_devids(dev_modern, pci_modern_device_id(virtio_devid), 161cce85725SThomas Huth non_transitional=True) 162cce85725SThomas Huth 163cce85725SThomas Huth # No options: should be modern anyway 164cce85725SThomas Huth dev_no_opts, ifaces = self.run_device(qemu_devtype) 165cce85725SThomas Huth self.assertEqual(dev_modern, dev_no_opts) 166cce85725SThomas Huth 167cce85725SThomas Huth self.assertIn('conventional-pci-device', ifaces) 168cce85725SThomas Huth self.assertIn('pci-express-device', ifaces) 169cce85725SThomas Huth 170cce85725SThomas Huth def test_modern_only_devs(self): 171*c78ba434SThomas Huth self.set_machine('pc') 172cce85725SThomas Huth self.check_modern_only('virtio-vga', VIRTIO_GPU) 173cce85725SThomas Huth self.check_modern_only('virtio-gpu-pci', VIRTIO_GPU) 174cce85725SThomas Huth self.check_modern_only('virtio-mouse-pci', VIRTIO_INPUT) 175cce85725SThomas Huth self.check_modern_only('virtio-tablet-pci', VIRTIO_INPUT) 176cce85725SThomas Huth self.check_modern_only('virtio-keyboard-pci', VIRTIO_INPUT) 177cce85725SThomas Huth 178cce85725SThomas Huthif __name__ == '__main__': 179cce85725SThomas Huth QemuSystemTest.main() 180