xref: /qemu/tests/avocado/tuxrun_baselines.py (revision 86d063fa)
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    def test_mips64(self):
274        """
275        :avocado: tags=arch:mips64
276        :avocado: tags=machine:malta
277        :avocado: tags=tuxboot:mips64
278        :avocado: tags=endian:big
279        :avocado: tags=image:vmlinux
280        :avocado: tags=root:sda
281        :avocado: tags=shutdown:nowait
282        """
283        self.common_tuxrun(drive="driver=ide-hd,bus=ide.0,unit=0")
284
285    def test_mips64el(self):
286        """
287        :avocado: tags=arch:mips64el
288        :avocado: tags=machine:malta
289        :avocado: tags=tuxboot:mips64el
290        :avocado: tags=image:vmlinux
291        :avocado: tags=root:sda
292        :avocado: tags=shutdown:nowait
293        """
294        self.common_tuxrun(drive="driver=ide-hd,bus=ide.0,unit=0")
295
296    def test_ppc32(self):
297        """
298        :avocado: tags=arch:ppc
299        :avocado: tags=machine:ppce500
300        :avocado: tags=cpu:e500mc
301        :avocado: tags=tuxboot:ppc32
302        :avocado: tags=image:uImage
303        :avocado: tags=shutdown:nowait
304        """
305        self.common_tuxrun(drive="virtio-blk-pci")
306
307    def test_ppc64(self):
308        """
309        :avocado: tags=arch:ppc64
310        :avocado: tags=machine:pseries
311        :avocado: tags=cpu:POWER8
312        :avocado: tags=endian:big
313        :avocado: tags=console:hvc0
314        :avocado: tags=tuxboot:ppc64
315        :avocado: tags=image:vmlinux
316        :avocado: tags=extradev:driver=spapr-vscsi
317        :avocado: tags=root:sda
318        """
319        self.common_tuxrun(drive="scsi-hd")
320
321    def test_ppc64le(self):
322        """
323        :avocado: tags=arch:ppc64
324        :avocado: tags=machine:pseries
325        :avocado: tags=cpu:POWER8
326        :avocado: tags=console:hvc0
327        :avocado: tags=tuxboot:ppc64le
328        :avocado: tags=image:vmlinux
329        :avocado: tags=extradev:driver=spapr-vscsi
330        :avocado: tags=root:sda
331        """
332        self.common_tuxrun(drive="scsi-hd")
333
334    def test_riscv32(self):
335        """
336        :avocado: tags=arch:riscv32
337        :avocado: tags=machine:virt
338        :avocado: tags=tuxboot:riscv32
339        """
340        self.common_tuxrun()
341
342    def test_riscv64(self):
343        """
344        :avocado: tags=arch:riscv64
345        :avocado: tags=machine:virt
346        :avocado: tags=tuxboot:riscv64
347        """
348        self.common_tuxrun()
349
350    def test_s390(self):
351        """
352        :avocado: tags=arch:s390x
353        :avocado: tags=endian:big
354        :avocado: tags=tuxboot:s390
355        :avocado: tags=image:bzImage
356        :avocado: tags=shutdown:nowait
357        """
358        self.common_tuxrun(drive="virtio-blk-ccw",
359                           haltmsg="Requesting system halt")
360
361    # Note: some segfaults caused by unaligned userspace access
362    @skipIf(os.getenv('GITLAB_CI'), 'Skipping unstable test on GitLab')
363    def test_sh4(self):
364        """
365        :avocado: tags=arch:sh4
366        :avocado: tags=machine:r2d
367        :avocado: tags=cpu:sh7785
368        :avocado: tags=tuxboot:sh4
369        :avocado: tags=image:zImage
370        :avocado: tags=root:sda
371        :avocado: tags=console:ttySC1
372        """
373        # The test is currently too unstable to do much in userspace
374        # so we skip common_tuxrun and do a minimal boot and shutdown.
375        (kernel, disk, dtb) = self.fetch_tuxrun_assets()
376
377        # the console comes on the second serial port
378        self.prepare_run(kernel, disk,
379                         "driver=ide-hd,bus=ide.0,unit=0",
380                         console_index=1)
381        self.vm.launch()
382
383        self.wait_for_console_pattern("Welcome to TuxTest")
384        time.sleep(0.1)
385        exec_command(self, 'root')
386        time.sleep(0.1)
387        exec_command_and_wait_for_pattern(self, 'halt',
388                                          "reboot: System halted")
389
390    def test_sparc64(self):
391        """
392        :avocado: tags=arch:sparc64
393        :avocado: tags=tuxboot:sparc64
394        :avocado: tags=image:vmlinux
395        :avocado: tags=root:sda
396        :avocado: tags=shutdown:nowait
397        """
398        self.common_tuxrun(drive="driver=ide-hd,bus=ide.0,unit=0")
399
400    def test_x86_64(self):
401        """
402        :avocado: tags=arch:x86_64
403        :avocado: tags=machine:q35
404        :avocado: tags=cpu:Nehalem
405        :avocado: tags=tuxboot:x86_64
406        :avocado: tags=image:bzImage
407        :avocado: tags=root:sda
408        :avocado: tags=shutdown:nowait
409        """
410        self.common_tuxrun(drive="driver=ide-hd,bus=ide.0,unit=0")
411