1*c1b24f0fSThomas Huth# Functional test that boots known good tuxboot images the same way 2*c1b24f0fSThomas Huth# that tuxrun (www.tuxrun.org) does. This tool is used by things like 3*c1b24f0fSThomas Huth# the LKFT project to run regression tests on kernels. 4*c1b24f0fSThomas Huth# 5*c1b24f0fSThomas Huth# Copyright (c) 2023 Linaro Ltd. 6*c1b24f0fSThomas Huth# 7*c1b24f0fSThomas Huth# Author: 8*c1b24f0fSThomas Huth# Alex Bennée <alex.bennee@linaro.org> 9*c1b24f0fSThomas Huth# 10*c1b24f0fSThomas Huth# SPDX-License-Identifier: GPL-2.0-or-later 11*c1b24f0fSThomas Huth 12*c1b24f0fSThomas Huthimport os 13*c1b24f0fSThomas Huthimport time 14*c1b24f0fSThomas Huth 15*c1b24f0fSThomas Huthfrom qemu_test import QemuSystemTest 16*c1b24f0fSThomas Huthfrom qemu_test import exec_command, exec_command_and_wait_for_pattern 17*c1b24f0fSThomas Huthfrom qemu_test import wait_for_console_pattern 18*c1b24f0fSThomas Huthfrom qemu_test import has_cmd, run_cmd, get_qemu_img 19*c1b24f0fSThomas Huth 20*c1b24f0fSThomas Huthclass TuxRunBaselineTest(QemuSystemTest): 21*c1b24f0fSThomas Huth 22*c1b24f0fSThomas Huth KERNEL_COMMON_COMMAND_LINE = 'printk.time=0' 23*c1b24f0fSThomas Huth # Tests are ~10-40s, allow for --debug/--enable-gcov overhead 24*c1b24f0fSThomas Huth timeout = 100 25*c1b24f0fSThomas Huth 26*c1b24f0fSThomas Huth def get_tag(self, tagname, default=None): 27*c1b24f0fSThomas Huth """ 28*c1b24f0fSThomas Huth Get the metadata tag or return the default. 29*c1b24f0fSThomas Huth """ 30*c1b24f0fSThomas Huth utag = self._get_unique_tag_val(tagname) 31*c1b24f0fSThomas Huth print(f"{tagname}/{default} -> {utag}") 32*c1b24f0fSThomas Huth if utag: 33*c1b24f0fSThomas Huth return utag 34*c1b24f0fSThomas Huth 35*c1b24f0fSThomas Huth return default 36*c1b24f0fSThomas Huth 37*c1b24f0fSThomas Huth def setUp(self): 38*c1b24f0fSThomas Huth super().setUp() 39*c1b24f0fSThomas Huth 40*c1b24f0fSThomas Huth # We need zstd for all the tuxrun tests 41*c1b24f0fSThomas Huth # See https://github.com/avocado-framework/avocado/issues/5609 42*c1b24f0fSThomas Huth (has_zstd, msg) = has_cmd('zstd') 43*c1b24f0fSThomas Huth if has_zstd is False: 44*c1b24f0fSThomas Huth self.skipTest(msg) 45*c1b24f0fSThomas Huth self.zstd = 'zstd' 46*c1b24f0fSThomas Huth 47*c1b24f0fSThomas Huth # Pre-init TuxRun specific settings: Most machines work with 48*c1b24f0fSThomas Huth # reasonable defaults but we sometimes need to tweak the 49*c1b24f0fSThomas Huth # config. To avoid open coding everything we store all these 50*c1b24f0fSThomas Huth # details in the metadata for each test. 51*c1b24f0fSThomas Huth 52*c1b24f0fSThomas Huth # The tuxboot tag matches the root directory 53*c1b24f0fSThomas Huth self.tuxboot = self.arch 54*c1b24f0fSThomas Huth 55*c1b24f0fSThomas Huth # Most Linux's use ttyS0 for their serial port 56*c1b24f0fSThomas Huth self.console = "ttyS0" 57*c1b24f0fSThomas Huth 58*c1b24f0fSThomas Huth # Does the machine shutdown QEMU nicely on "halt" 59*c1b24f0fSThomas Huth self.wait_for_shutdown = True 60*c1b24f0fSThomas Huth 61*c1b24f0fSThomas Huth self.root = "vda" 62*c1b24f0fSThomas Huth 63*c1b24f0fSThomas Huth # Occasionally we need extra devices to hook things up 64*c1b24f0fSThomas Huth self.extradev = None 65*c1b24f0fSThomas Huth 66*c1b24f0fSThomas Huth self.qemu_img = get_qemu_img(self) 67*c1b24f0fSThomas Huth 68*c1b24f0fSThomas Huth def wait_for_console_pattern(self, success_message, vm=None): 69*c1b24f0fSThomas Huth wait_for_console_pattern(self, success_message, 70*c1b24f0fSThomas Huth failure_message='Kernel panic - not syncing', 71*c1b24f0fSThomas Huth vm=vm) 72*c1b24f0fSThomas Huth 73*c1b24f0fSThomas Huth def fetch_tuxrun_assets(self, kernel_asset, rootfs_asset, dtb_asset=None): 74*c1b24f0fSThomas Huth """ 75*c1b24f0fSThomas Huth Fetch the TuxBoot assets. 76*c1b24f0fSThomas Huth """ 77*c1b24f0fSThomas Huth kernel_image = kernel_asset.fetch() 78*c1b24f0fSThomas Huth disk_image_zst = rootfs_asset.fetch() 79*c1b24f0fSThomas Huth 80*c1b24f0fSThomas Huth run_cmd([self.zstd, "-f", "-d", disk_image_zst, 81*c1b24f0fSThomas Huth "-o", self.workdir + "/rootfs.ext4"]) 82*c1b24f0fSThomas Huth 83*c1b24f0fSThomas Huth dtb = dtb_asset.fetch() if dtb_asset is not None else None 84*c1b24f0fSThomas Huth 85*c1b24f0fSThomas Huth return (kernel_image, self.workdir + "/rootfs.ext4", dtb) 86*c1b24f0fSThomas Huth 87*c1b24f0fSThomas Huth def prepare_run(self, kernel, disk, drive, dtb=None, console_index=0): 88*c1b24f0fSThomas Huth """ 89*c1b24f0fSThomas Huth Setup to run and add the common parameters to the system 90*c1b24f0fSThomas Huth """ 91*c1b24f0fSThomas Huth self.vm.set_console(console_index=console_index) 92*c1b24f0fSThomas Huth 93*c1b24f0fSThomas Huth # all block devices are raw ext4's 94*c1b24f0fSThomas Huth blockdev = "driver=raw,file.driver=file," \ 95*c1b24f0fSThomas Huth + f"file.filename={disk},node-name=hd0" 96*c1b24f0fSThomas Huth 97*c1b24f0fSThomas Huth kcmd_line = self.KERNEL_COMMON_COMMAND_LINE 98*c1b24f0fSThomas Huth kcmd_line += f" root=/dev/{self.root}" 99*c1b24f0fSThomas Huth kcmd_line += f" console={self.console}" 100*c1b24f0fSThomas Huth 101*c1b24f0fSThomas Huth self.vm.add_args('-kernel', kernel, 102*c1b24f0fSThomas Huth '-append', kcmd_line, 103*c1b24f0fSThomas Huth '-blockdev', blockdev) 104*c1b24f0fSThomas Huth 105*c1b24f0fSThomas Huth # Sometimes we need extra devices attached 106*c1b24f0fSThomas Huth if self.extradev: 107*c1b24f0fSThomas Huth self.vm.add_args('-device', self.extradev) 108*c1b24f0fSThomas Huth 109*c1b24f0fSThomas Huth self.vm.add_args('-device', 110*c1b24f0fSThomas Huth f"{drive},drive=hd0") 111*c1b24f0fSThomas Huth 112*c1b24f0fSThomas Huth # Some machines need an explicit DTB 113*c1b24f0fSThomas Huth if dtb: 114*c1b24f0fSThomas Huth self.vm.add_args('-dtb', dtb) 115*c1b24f0fSThomas Huth 116*c1b24f0fSThomas Huth def run_tuxtest_tests(self, haltmsg): 117*c1b24f0fSThomas Huth """ 118*c1b24f0fSThomas Huth Wait for the system to boot up, wait for the login prompt and 119*c1b24f0fSThomas Huth then do a few things on the console. Trigger a shutdown and 120*c1b24f0fSThomas Huth wait to exit cleanly. 121*c1b24f0fSThomas Huth """ 122*c1b24f0fSThomas Huth self.wait_for_console_pattern("Welcome to TuxTest") 123*c1b24f0fSThomas Huth time.sleep(0.2) 124*c1b24f0fSThomas Huth exec_command(self, 'root') 125*c1b24f0fSThomas Huth time.sleep(0.2) 126*c1b24f0fSThomas Huth exec_command(self, 'cat /proc/interrupts') 127*c1b24f0fSThomas Huth time.sleep(0.1) 128*c1b24f0fSThomas Huth exec_command(self, 'cat /proc/self/maps') 129*c1b24f0fSThomas Huth time.sleep(0.1) 130*c1b24f0fSThomas Huth exec_command(self, 'uname -a') 131*c1b24f0fSThomas Huth time.sleep(0.1) 132*c1b24f0fSThomas Huth exec_command_and_wait_for_pattern(self, 'halt', haltmsg) 133*c1b24f0fSThomas Huth 134*c1b24f0fSThomas Huth # Wait for VM to shut down gracefully if it can 135*c1b24f0fSThomas Huth if self.wait_for_shutdown: 136*c1b24f0fSThomas Huth self.vm.wait() 137*c1b24f0fSThomas Huth else: 138*c1b24f0fSThomas Huth self.vm.shutdown() 139*c1b24f0fSThomas Huth 140*c1b24f0fSThomas Huth def common_tuxrun(self, 141*c1b24f0fSThomas Huth kernel_asset, 142*c1b24f0fSThomas Huth rootfs_asset, 143*c1b24f0fSThomas Huth dtb_asset=None, 144*c1b24f0fSThomas Huth drive="virtio-blk-device", 145*c1b24f0fSThomas Huth haltmsg="reboot: System halted", 146*c1b24f0fSThomas Huth console_index=0): 147*c1b24f0fSThomas Huth """ 148*c1b24f0fSThomas Huth Common path for LKFT tests. Unless we need to do something 149*c1b24f0fSThomas Huth special with the command line we can process most things using 150*c1b24f0fSThomas Huth the tag metadata. 151*c1b24f0fSThomas Huth """ 152*c1b24f0fSThomas Huth (kernel, disk, dtb) = self.fetch_tuxrun_assets(kernel_asset, rootfs_asset, 153*c1b24f0fSThomas Huth dtb_asset) 154*c1b24f0fSThomas Huth 155*c1b24f0fSThomas Huth self.prepare_run(kernel, disk, drive, dtb, console_index) 156*c1b24f0fSThomas Huth self.vm.launch() 157*c1b24f0fSThomas Huth self.run_tuxtest_tests(haltmsg) 158*c1b24f0fSThomas Huth os.remove(disk) 159