xref: /qemu/tests/avocado/tuxrun_baselines.py (revision 8635a3a1)
1# Functional test that boots known good tuxboot images the same way
2# that tuxrun (www.tuxrun.org) does. This tool is used by things like
3# the LKFT project to run regression tests on kernels.
4#
5# Copyright (c) 2023 Linaro Ltd.
6#
7# Author:
8#  Alex Bennée <alex.bennee@linaro.org>
9#
10# SPDX-License-Identifier: GPL-2.0-or-later
11
12import os
13import time
14
15from avocado import skip, skipIf
16from avocado_qemu import QemuSystemTest
17from avocado_qemu import exec_command, exec_command_and_wait_for_pattern
18from avocado_qemu import wait_for_console_pattern
19from avocado.utils import process
20from avocado.utils.path import find_command
21
22class TuxRunBaselineTest(QemuSystemTest):
23    """
24    :avocado: tags=accel:tcg
25    """
26
27    KERNEL_COMMON_COMMAND_LINE = 'printk.time=0'
28    # Tests are ~10-40s, allow for --debug/--enable-gcov overhead
29    timeout = 100
30
31    def get_tag(self, tagname, default=None):
32        """
33        Get the metadata tag or return the default.
34        """
35        utag = self._get_unique_tag_val(tagname)
36        print(f"{tagname}/{default} -> {utag}")
37        if utag:
38            return utag
39
40        return default
41
42    def setUp(self):
43        super().setUp()
44
45        # We need zstd for all the tuxrun tests
46        # See https://github.com/avocado-framework/avocado/issues/5609
47        zstd = find_command('zstd', False)
48        if zstd is False:
49            self.cancel('Could not find "zstd", which is required to '
50                        'decompress rootfs')
51        self.zstd = zstd
52
53        # Process the TuxRun specific tags, most machines work with
54        # reasonable defaults but we sometimes need to tweak the
55        # config. To avoid open coding everything we store all these
56        # details in the metadata for each test.
57
58        # The tuxboot tag matches the root directory
59        self.tuxboot = self.get_tag('tuxboot')
60
61        # Most Linux's use ttyS0 for their serial port
62        self.console = self.get_tag('console', "ttyS0")
63
64        # Does the machine shutdown QEMU nicely on "halt"
65        self.shutdown = self.get_tag('shutdown')
66
67        # The name of the kernel Image file
68        self.image = self.get_tag('image', "Image")
69
70        self.root = self.get_tag('root', "vda")
71
72        # Occasionally we need extra devices to hook things up
73        self.extradev = self.get_tag('extradev')
74
75    def wait_for_console_pattern(self, success_message, vm=None):
76        wait_for_console_pattern(self, success_message,
77                                 failure_message='Kernel panic - not syncing',
78                                 vm=vm)
79
80    def fetch_tuxrun_assets(self, dt=None):
81        """
82        Fetch the TuxBoot assets. They are stored in a standard way so we
83        use the per-test tags to fetch details.
84        """
85        base_url = f"https://storage.tuxboot.com/{self.tuxboot}/"
86        kernel_image =  self.fetch_asset(base_url + self.image)
87        disk_image_zst = self.fetch_asset(base_url + "rootfs.ext4.zst")
88
89        cmd = f"{self.zstd} -d {disk_image_zst} -o {self.workdir}/rootfs.ext4"
90        process.run(cmd)
91
92        if dt:
93            dtb = self.fetch_asset(base_url + dt)
94        else:
95            dtb = None
96
97        return (kernel_image, self.workdir + "/rootfs.ext4", dtb)
98
99    def prepare_run(self, kernel, disk, drive, dtb=None, console_index=0):
100        """
101        Setup to run and add the common parameters to the system
102        """
103        self.vm.set_console(console_index=console_index)
104
105        # all block devices are raw ext4's
106        blockdev = "driver=raw,file.driver=file," \
107            + f"file.filename={disk},node-name=hd0"
108
109        kcmd_line = self.KERNEL_COMMON_COMMAND_LINE
110        kcmd_line += f" root=/dev/{self.root}"
111        kcmd_line += f" console={self.console}"
112
113        self.vm.add_args('-kernel', kernel,
114                         '-append', kcmd_line,
115                         '-blockdev', blockdev)
116
117        # Sometimes we need extra devices attached
118        if self.extradev:
119            self.vm.add_args('-device', self.extradev)
120
121        self.vm.add_args('-device',
122                         f"{drive},drive=hd0")
123
124        # Some machines need an explicit DTB
125        if dtb:
126            self.vm.add_args('-dtb', dtb)
127
128    def run_tuxtest_tests(self, haltmsg):
129        """
130        Wait for the system to boot up, wait for the login prompt and
131        then do a few things on the console. Trigger a shutdown and
132        wait to exit cleanly.
133        """
134        self.wait_for_console_pattern("Welcome to TuxTest")
135        time.sleep(0.2)
136        exec_command(self, 'root')
137        time.sleep(0.2)
138        exec_command(self, 'cat /proc/interrupts')
139        time.sleep(0.1)
140        exec_command(self, 'cat /proc/self/maps')
141        time.sleep(0.1)
142        exec_command(self, 'uname -a')
143        time.sleep(0.1)
144        exec_command_and_wait_for_pattern(self, 'halt', haltmsg)
145
146        # Wait for VM to shut down gracefully if it can
147        if self.shutdown == "nowait":
148            self.vm.shutdown()
149        else:
150            self.vm.wait()
151
152    def common_tuxrun(self, dt=None,
153                      drive="virtio-blk-device",
154                      haltmsg="reboot: System halted",
155                      console_index=0):
156        """
157        Common path for LKFT tests. Unless we need to do something
158        special with the command line we can process most things using
159        the tag metadata.
160        """
161        (kernel, disk, dtb) = self.fetch_tuxrun_assets(dt)
162
163        self.prepare_run(kernel, disk, drive, dtb, console_index)
164        self.vm.launch()
165        self.run_tuxtest_tests(haltmsg)
166
167    #
168    # The tests themselves. The configuration is derived from how
169    # tuxrun invokes qemu (with minor tweaks like using -blockdev
170    # consistently). The tuxrun equivalent is something like:
171    #
172    # tuxrun --device qemu-{ARCH} \
173    #        --kernel https://storage.tuxboot.com/{TUXBOOT}/{IMAGE}
174    #
175
176    def test_arm64(self):
177        """
178        :avocado: tags=arch:aarch64
179        :avocado: tags=cpu:cortex-a57
180        :avocado: tags=machine:virt
181        :avocado: tags=tuxboot:arm64
182        :avocado: tags=console:ttyAMA0
183        :avocado: tags=shutdown:nowait
184        """
185        self.common_tuxrun()
186
187    def test_arm64be(self):
188        """
189        :avocado: tags=arch:aarch64
190        :avocado: tags=cpu:cortex-a57
191        :avocado: tags=endian:big
192        :avocado: tags=machine:virt
193        :avocado: tags=tuxboot:arm64be
194        :avocado: tags=console:ttyAMA0
195        :avocado: tags=shutdown:nowait
196        """
197        self.common_tuxrun()
198
199    def test_armv5(self):
200        """
201        :avocado: tags=arch:arm
202        :avocado: tags=cpu:arm926
203        :avocado: tags=machine:versatilepb
204        :avocado: tags=tuxboot:armv5
205        :avocado: tags=image:zImage
206        :avocado: tags=console:ttyAMA0
207        :avocado: tags=shutdown:nowait
208        """
209        self.common_tuxrun(drive="virtio-blk-pci",
210                           dt="versatile-pb.dtb")
211
212    def test_armv7(self):
213        """
214        :avocado: tags=arch:arm
215        :avocado: tags=cpu:cortex-a15
216        :avocado: tags=machine:virt
217        :avocado: tags=tuxboot:armv7
218        :avocado: tags=image:zImage
219        :avocado: tags=console:ttyAMA0
220        :avocado: tags=shutdown:nowait
221        """
222        self.common_tuxrun()
223
224    def test_armv7be(self):
225        """
226        :avocado: tags=arch:arm
227        :avocado: tags=cpu:cortex-a15
228        :avocado: tags=endian:big
229        :avocado: tags=machine:virt
230        :avocado: tags=tuxboot:armv7be
231        :avocado: tags=image:zImage
232        :avocado: tags=console:ttyAMA0
233        :avocado: tags=shutdown:nowait
234        """
235        self.common_tuxrun()
236
237    def test_i386(self):
238        """
239        :avocado: tags=arch:i386
240        :avocado: tags=cpu:coreduo
241        :avocado: tags=machine:q35
242        :avocado: tags=tuxboot:i386
243        :avocado: tags=image:bzImage
244        :avocado: tags=shutdown:nowait
245        """
246        self.common_tuxrun(drive="virtio-blk-pci")
247
248    def test_mips32(self):
249        """
250        :avocado: tags=arch:mips
251        :avocado: tags=machine:malta
252        :avocado: tags=cpu:mips32r6-generic
253        :avocado: tags=endian:big
254        :avocado: tags=tuxboot:mips32
255        :avocado: tags=image:vmlinux
256        :avocado: tags=root:sda
257        :avocado: tags=shutdown:nowait
258        """
259        self.common_tuxrun(drive="driver=ide-hd,bus=ide.0,unit=0")
260
261    def test_mips32el(self):
262        """
263        :avocado: tags=arch:mipsel
264        :avocado: tags=machine:malta
265        :avocado: tags=cpu:mips32r6-generic
266        :avocado: tags=tuxboot:mips32el
267        :avocado: tags=image:vmlinux
268        :avocado: tags=root:sda
269        :avocado: tags=shutdown:nowait
270        """
271        self.common_tuxrun(drive="driver=ide-hd,bus=ide.0,unit=0")
272
273    @skip("QEMU currently broken") # regression against stable QEMU
274    def test_mips64(self):
275        """
276        :avocado: tags=arch:mips64
277        :avocado: tags=machine:malta
278        :avocado: tags=tuxboot:mips64
279        :avocado: tags=endian:big
280        :avocado: tags=image:vmlinux
281        :avocado: tags=root:sda
282        :avocado: tags=shutdown:nowait
283        """
284        self.common_tuxrun(drive="driver=ide-hd,bus=ide.0,unit=0")
285
286    def test_mips64el(self):
287        """
288        :avocado: tags=arch:mips64el
289        :avocado: tags=machine:malta
290        :avocado: tags=tuxboot:mips64el
291        :avocado: tags=image:vmlinux
292        :avocado: tags=root:sda
293        :avocado: tags=shutdown:nowait
294        """
295        self.common_tuxrun(drive="driver=ide-hd,bus=ide.0,unit=0")
296
297    def test_ppc32(self):
298        """
299        :avocado: tags=arch:ppc
300        :avocado: tags=machine:ppce500
301        :avocado: tags=cpu:e500mc
302        :avocado: tags=tuxboot:ppc32
303        :avocado: tags=image:uImage
304        :avocado: tags=shutdown:nowait
305        """
306        self.common_tuxrun(drive="virtio-blk-pci")
307
308    def test_ppc64(self):
309        """
310        :avocado: tags=arch:ppc64
311        :avocado: tags=machine:pseries
312        :avocado: tags=cpu:POWER8
313        :avocado: tags=endian:big
314        :avocado: tags=console:hvc0
315        :avocado: tags=tuxboot:ppc64
316        :avocado: tags=image:vmlinux
317        :avocado: tags=extradev:driver=spapr-vscsi
318        :avocado: tags=root:sda
319        """
320        self.common_tuxrun(drive="scsi-hd")
321
322    def test_ppc64le(self):
323        """
324        :avocado: tags=arch:ppc64
325        :avocado: tags=machine:pseries
326        :avocado: tags=cpu:POWER8
327        :avocado: tags=console:hvc0
328        :avocado: tags=tuxboot:ppc64le
329        :avocado: tags=image:vmlinux
330        :avocado: tags=extradev:driver=spapr-vscsi
331        :avocado: tags=root:sda
332        """
333        self.common_tuxrun(drive="scsi-hd")
334
335    def test_riscv32(self):
336        """
337        :avocado: tags=arch:riscv32
338        :avocado: tags=machine:virt
339        :avocado: tags=tuxboot:riscv32
340        """
341        self.common_tuxrun()
342
343    def test_riscv64(self):
344        """
345        :avocado: tags=arch:riscv64
346        :avocado: tags=machine:virt
347        :avocado: tags=tuxboot:riscv64
348        """
349        self.common_tuxrun()
350
351    def test_s390(self):
352        """
353        :avocado: tags=arch:s390x
354        :avocado: tags=endian:big
355        :avocado: tags=tuxboot:s390
356        :avocado: tags=image:bzImage
357        :avocado: tags=shutdown:nowait
358        """
359        self.common_tuxrun(drive="virtio-blk-ccw",
360                           haltmsg="Requesting system halt")
361
362    # Note: some segfaults caused by unaligned userspace access
363    @skipIf(os.getenv('GITLAB_CI'), 'Skipping unstable test on GitLab')
364    def test_sh4(self):
365        """
366        :avocado: tags=arch:sh4
367        :avocado: tags=machine:r2d
368        :avocado: tags=cpu:sh7785
369        :avocado: tags=tuxboot:sh4
370        :avocado: tags=image:zImage
371        :avocado: tags=root:sda
372        :avocado: tags=console:ttySC1
373        """
374        # The test is currently too unstable to do much in userspace
375        # so we skip common_tuxrun and do a minimal boot and shutdown.
376        (kernel, disk, dtb) = self.fetch_tuxrun_assets()
377
378        # the console comes on the second serial port
379        self.prepare_run(kernel, disk,
380                         "driver=ide-hd,bus=ide.0,unit=0",
381                         console_index=1)
382        self.vm.launch()
383
384        self.wait_for_console_pattern("Welcome to TuxTest")
385        time.sleep(0.1)
386        exec_command(self, 'root')
387        time.sleep(0.1)
388        exec_command_and_wait_for_pattern(self, 'halt',
389                                          "reboot: System halted")
390
391    def test_sparc64(self):
392        """
393        :avocado: tags=arch:sparc64
394        :avocado: tags=tuxboot:sparc64
395        :avocado: tags=image:vmlinux
396        :avocado: tags=root:sda
397        :avocado: tags=shutdown:nowait
398        """
399        self.common_tuxrun(drive="driver=ide-hd,bus=ide.0,unit=0")
400
401    def test_x86_64(self):
402        """
403        :avocado: tags=arch:x86_64
404        :avocado: tags=machine:q35
405        :avocado: tags=cpu:Nehalem
406        :avocado: tags=tuxboot:x86_64
407        :avocado: tags=image:bzImage
408        :avocado: tags=root:sda
409        :avocado: tags=shutdown:nowait
410        """
411        self.common_tuxrun(drive="driver=ide-hd,bus=ide.0,unit=0")
412