| 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # virtio-gpu tests |
| 4 | # |
| 5 | # This work is licensed under the terms of the GNU GPL, version 2 or |
| 6 | # later. See the COPYING file in the top-level directory. |
| 7 | |
| 8 | import os |
| 9 | import socket |
| 10 | import subprocess |
| 11 | |
| 12 | from qemu_test import QemuSystemTest, Asset |
| 13 | from qemu_test import wait_for_console_pattern |
| 14 | from qemu_test import exec_command_and_wait_for_pattern |
| 15 | from qemu_test import is_readable_executable_file |
| 16 | |
| 17 | from qemu.machine.machine import VMLaunchFailure |
| 18 | |
| 19 | |
| 20 | def pick_default_vug_bin(test): |
| 21 | bld_dir_path = test.build_file("contrib", "vhost-user-gpu", "vhost-user-gpu") |
| 22 | if is_readable_executable_file(bld_dir_path): |
| 23 | return bld_dir_path |
| 24 | return None |
| 25 | |
| 26 | |
| 27 | class VirtioGPUx86(QemuSystemTest): |
| 28 | |
| 29 | KERNEL_COMMAND_LINE = "printk.time=0 console=ttyS0 rdinit=/bin/bash" |
| 30 | ASSET_KERNEL = Asset( |
| 31 | ("https://archives.fedoraproject.org/pub/archive/fedora" |
| 32 | "/linux/releases/33/Everything/x86_64/os/images" |
| 33 | "/pxeboot/vmlinuz"), |
| 34 | '2dc5fb5cfe9ac278fa45640f3602d9b7a08cc189ed63fd9b162b07073e4df397') |
| 35 | ASSET_INITRD = Asset( |
| 36 | ("https://archives.fedoraproject.org/pub/archive/fedora" |
| 37 | "/linux/releases/33/Everything/x86_64/os/images" |
| 38 | "/pxeboot/initrd.img"), |
| 39 | 'c49b97f893a5349e4883452178763e402bdc5caa8845b226a2d1329b5f356045') |
| 40 | |
| 41 | def wait_for_console_pattern(self, success_message, vm=None): |
| 42 | wait_for_console_pattern( |
| 43 | self, |
| 44 | success_message, |
| 45 | failure_message="Kernel panic - not syncing", |
| 46 | vm=vm, |
| 47 | ) |
| 48 | |
| 49 | def test_virtio_vga_virgl(self): |
| 50 | self.require_accelerator('kvm') |
| 51 | self.require_device('virtio-vga-gl') |
| 52 | |
| 53 | kernel_path = self.ASSET_KERNEL.fetch() |
| 54 | initrd_path = self.ASSET_INITRD.fetch() |
| 55 | |
| 56 | self.vm.set_console() |
| 57 | self.vm.add_args("-cpu", "host") |
| 58 | self.vm.add_args("-m", "2G") |
| 59 | self.vm.add_args("-machine", "pc,accel=kvm") |
| 60 | self.vm.add_args("-device", "virtio-vga-gl") |
| 61 | self.vm.add_args("-display", "egl-headless") |
| 62 | self.vm.add_args( |
| 63 | "-kernel", |
| 64 | kernel_path, |
| 65 | "-initrd", |
| 66 | initrd_path, |
| 67 | "-append", |
| 68 | self.KERNEL_COMMAND_LINE, |
| 69 | ) |
| 70 | try: |
| 71 | self.vm.launch() |
| 72 | except VMLaunchFailure: |
| 73 | # TODO: probably fails because we are missing the VirGL features |
| 74 | self.skipTest("VirGL not enabled?") |
| 75 | |
| 76 | self.wait_for_console_pattern("as init process") |
| 77 | exec_command_and_wait_for_pattern( |
| 78 | self, "/usr/sbin/modprobe virtio_gpu", "features: +virgl +edid" |
| 79 | ) |
| 80 | |
| 81 | def test_vhost_user_vga_virgl(self): |
| 82 | self.require_accelerator('kvm') |
| 83 | self.require_device('vhost-user-vga') |
| 84 | |
| 85 | vug = pick_default_vug_bin(self) |
| 86 | if not vug: |
| 87 | self.skipTest("Could not find vhost-user-gpu") |
| 88 | |
| 89 | kernel_path = self.ASSET_KERNEL.fetch() |
| 90 | initrd_path = self.ASSET_INITRD.fetch() |
| 91 | |
| 92 | # Create socketpair to connect proxy and remote processes |
| 93 | qemu_sock, vug_sock = socket.socketpair( |
| 94 | socket.AF_UNIX, socket.SOCK_STREAM |
| 95 | ) |
| 96 | os.set_inheritable(qemu_sock.fileno(), True) |
| 97 | os.set_inheritable(vug_sock.fileno(), True) |
| 98 | |
| 99 | vug_log_path = self.log_file("vhost-user-gpu.log") |
| 100 | self.log.info('Complete vhost-user-gpu.log file can be found at %s', |
| 101 | vug_log_path) |
| 102 | with open(vug_log_path, "wb") as vug_log_file: |
| 103 | with subprocess.Popen([vug, "--virgl", f"--fd={vug_sock.fileno()}"], |
| 104 | stdin=subprocess.DEVNULL, |
| 105 | stdout=vug_log_file, |
| 106 | stderr=subprocess.STDOUT, |
| 107 | shell=False, |
| 108 | close_fds=False) as vugp: |
| 109 | self._test_vhost_user_vga_virgl(qemu_sock, |
| 110 | kernel_path, initrd_path) |
| 111 | qemu_sock.close() |
| 112 | vug_sock.close() |
| 113 | vugp.terminate() |
| 114 | |
| 115 | def _test_vhost_user_vga_virgl(self, qemu_sock, kernel_path, initrd_path): |
| 116 | self.vm.set_console() |
| 117 | self.vm.add_args("-cpu", "host") |
| 118 | self.vm.add_args("-m", "2G") |
| 119 | self.vm.add_args("-object", "memory-backend-memfd,id=mem,size=2G") |
| 120 | self.vm.add_args("-machine", "pc,memory-backend=mem,accel=kvm") |
| 121 | self.vm.add_args("-chardev", f"socket,id=vug,fd={qemu_sock.fileno()}") |
| 122 | self.vm.add_args("-device", "vhost-user-vga,chardev=vug") |
| 123 | self.vm.add_args("-display", "egl-headless") |
| 124 | self.vm.add_args( |
| 125 | "-kernel", |
| 126 | kernel_path, |
| 127 | "-initrd", |
| 128 | initrd_path, |
| 129 | "-append", |
| 130 | self.KERNEL_COMMAND_LINE, |
| 131 | ) |
| 132 | try: |
| 133 | self.vm.launch() |
| 134 | except VMLaunchFailure: |
| 135 | # TODO: probably fails because we are missing the VirGL features |
| 136 | self.skipTest("VirGL not enabled?") |
| 137 | self.wait_for_console_pattern("as init process") |
| 138 | exec_command_and_wait_for_pattern(self, "/usr/sbin/modprobe virtio_gpu", |
| 139 | "features: +virgl +edid") |
| 140 | self.vm.shutdown() |
| 141 | |
| 142 | |
| 143 | if __name__ == '__main__': |
| 144 | QemuSystemTest.main() |