xref: /openbmc/qemu/tests/avocado/replay_kernel.py (revision 407bc4bf9027f7ac4333e47cd900d773b99a23e3)
1# Record/replay test that boots a Linux kernel
2#
3# Copyright (c) 2020 ISP RAS
4#
5# Author:
6#  Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
7#
8# This work is licensed under the terms of the GNU GPL, version 2 or
9# later.  See the COPYING file in the top-level directory.
10
11import os
12import lzma
13import shutil
14import logging
15import time
16import subprocess
17
18from avocado import skip
19from avocado import skipUnless
20from avocado import skipUnless
21from avocado_qemu import wait_for_console_pattern
22from avocado.utils import archive
23from avocado.utils import process
24from boot_linux_console import LinuxKernelTest
25
26class ReplayKernelBase(LinuxKernelTest):
27    """
28    Boots a Linux kernel in record mode and checks that the console
29    is operational and the kernel command line is properly passed
30    from QEMU to the kernel.
31    Then replays the same scenario and verifies, that QEMU correctly
32    terminates.
33    """
34
35    timeout = 180
36    KERNEL_COMMON_COMMAND_LINE = 'printk.time=1 panic=-1 '
37
38    def run_vm(self, kernel_path, kernel_command_line, console_pattern,
39               record, shift, args, replay_path):
40        # icount requires TCG to be available
41        self.require_accelerator('tcg')
42
43        logger = logging.getLogger('replay')
44        start_time = time.time()
45        vm = self.get_vm()
46        vm.set_console()
47        if record:
48            logger.info('recording the execution...')
49            mode = 'record'
50        else:
51            logger.info('replaying the execution...')
52            mode = 'replay'
53        vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' %
54                    (shift, mode, replay_path),
55                    '-kernel', kernel_path,
56                    '-append', kernel_command_line,
57                    '-net', 'none',
58                    '-no-reboot')
59        if args:
60            vm.add_args(*args)
61        vm.launch()
62        self.wait_for_console_pattern(console_pattern, vm)
63        if record:
64            vm.shutdown()
65            logger.info('finished the recording with log size %s bytes'
66                        % os.path.getsize(replay_path))
67            self.run_replay_dump(replay_path)
68            logger.info('successfully tested replay-dump.py')
69        else:
70            vm.wait()
71            logger.info('successfully finished the replay')
72        elapsed = time.time() - start_time
73        logger.info('elapsed time %.2f sec' % elapsed)
74        return elapsed
75
76    def run_replay_dump(self, replay_path):
77        try:
78            subprocess.check_call(["./scripts/replay-dump.py",
79                                   "-f", replay_path],
80                                  stdout=subprocess.DEVNULL)
81        except subprocess.CalledProcessError:
82            self.fail('replay-dump.py failed')
83
84    def run_rr(self, kernel_path, kernel_command_line, console_pattern,
85               shift=7, args=None):
86        replay_path = os.path.join(self.workdir, 'replay.bin')
87        t1 = self.run_vm(kernel_path, kernel_command_line, console_pattern,
88                         True, shift, args, replay_path)
89        t2 = self.run_vm(kernel_path, kernel_command_line, console_pattern,
90                         False, shift, args, replay_path)
91        logger = logging.getLogger('replay')
92        logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1))
93
94class ReplayKernelNormal(ReplayKernelBase):
95
96    def test_i386_pc(self):
97        """
98        :avocado: tags=arch:i386
99        :avocado: tags=machine:pc
100        """
101        kernel_url = ('https://storage.tuxboot.com/20230331/i386/bzImage')
102        kernel_hash = 'a3e5b32a354729e65910f5a1ffcda7c14a6c12a55e8213fb86e277f1b76ed956'
103        kernel_path = self.fetch_asset(kernel_url,
104                                       asset_hash=kernel_hash,
105                                       algorithm = "sha256")
106
107        kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
108        console_pattern = 'VFS: Cannot open root device'
109
110        self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
111
112    # See https://gitlab.com/qemu-project/qemu/-/issues/2094
113    @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'pc machine is unstable with replay')
114    def test_x86_64_pc(self):
115        """
116        :avocado: tags=arch:x86_64
117        :avocado: tags=machine:pc
118        :avocado: tags=flaky
119        """
120        kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
121                      '/linux/releases/29/Everything/x86_64/os/images/pxeboot'
122                      '/vmlinuz')
123        kernel_hash = '23bebd2680757891cf7adedb033532163a792495'
124        kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
125
126        kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
127        console_pattern = 'VFS: Cannot open root device'
128
129        self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
130
131    def test_x86_64_q35(self):
132        """
133        :avocado: tags=arch:x86_64
134        :avocado: tags=machine:q35
135        """
136        kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
137                      '/linux/releases/29/Everything/x86_64/os/images/pxeboot'
138                      '/vmlinuz')
139        kernel_hash = '23bebd2680757891cf7adedb033532163a792495'
140        kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
141
142        kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
143        console_pattern = 'VFS: Cannot open root device'
144
145        self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
146
147    def test_aarch64_virt(self):
148        """
149        :avocado: tags=arch:aarch64
150        :avocado: tags=machine:virt
151        :avocado: tags=cpu:cortex-a53
152        """
153        kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
154                      '/linux/releases/29/Everything/aarch64/os/images/pxeboot'
155                      '/vmlinuz')
156        kernel_hash = '8c73e469fc6ea06a58dc83a628fc695b693b8493'
157        kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
158
159        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
160                               'console=ttyAMA0')
161        console_pattern = 'VFS: Cannot open root device'
162
163        self.run_rr(kernel_path, kernel_command_line, console_pattern)
164
165    def test_arm_virt(self):
166        """
167        :avocado: tags=arch:arm
168        :avocado: tags=machine:virt
169        """
170        kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
171                      '/linux/releases/29/Everything/armhfp/os/images/pxeboot'
172                      '/vmlinuz')
173        kernel_hash = 'e9826d741b4fb04cadba8d4824d1ed3b7fb8b4d4'
174        kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
175
176        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
177                               'console=ttyAMA0')
178        console_pattern = 'VFS: Cannot open root device'
179
180        self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=1)
181
182    def test_arm_cubieboard_initrd(self):
183        """
184        :avocado: tags=arch:arm
185        :avocado: tags=machine:cubieboard
186        """
187        deb_url = ('https://apt.armbian.com/pool/main/l/'
188                   'linux-6.6.16/linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb')
189        deb_hash = 'f7c3c8c5432f765445dc6e7eab02f3bbe668256b'
190        deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
191        kernel_path = self.extract_from_deb(deb_path,
192                                            '/boot/vmlinuz-6.6.16-current-sunxi')
193        dtb_path = '/usr/lib/linux-image-6.6.16-current-sunxi/sun4i-a10-cubieboard.dtb'
194        dtb_path = self.extract_from_deb(deb_path, dtb_path)
195        initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
196                      '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
197                      'arm/rootfs-armv5.cpio.gz')
198        initrd_hash = '2b50f1873e113523967806f4da2afe385462ff9b'
199        initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
200        initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
201        archive.gzip_uncompress(initrd_path_gz, initrd_path)
202
203        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
204                               'console=ttyS0,115200 '
205                               'usbcore.nousb '
206                               'panic=-1 noreboot')
207        console_pattern = 'Boot successful.'
208        self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=1,
209                    args=('-dtb', dtb_path,
210                          '-initrd', initrd_path,
211                          '-no-reboot'))
212
213    def test_s390x_s390_ccw_virtio(self):
214        """
215        :avocado: tags=arch:s390x
216        :avocado: tags=machine:s390-ccw-virtio
217        """
218        kernel_url = ('https://archives.fedoraproject.org/pub/archive'
219                      '/fedora-secondary/releases/29/Everything/s390x/os/images'
220                      '/kernel.img')
221        kernel_hash = 'e8e8439103ef8053418ef062644ffd46a7919313'
222        kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
223
224        kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=sclp0'
225        console_pattern = 'Kernel command line: %s' % kernel_command_line
226        self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=9)
227
228    def test_alpha_clipper(self):
229        """
230        :avocado: tags=arch:alpha
231        :avocado: tags=machine:clipper
232        """
233        kernel_url = ('http://archive.debian.org/debian/dists/lenny/main/'
234                      'installer-alpha/20090123lenny10/images/cdrom/vmlinuz')
235        kernel_hash = '3a943149335529e2ed3e74d0d787b85fb5671ba3'
236        kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
237
238        uncompressed_kernel = archive.uncompress(kernel_path, self.workdir)
239
240        kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
241        console_pattern = 'Kernel command line: %s' % kernel_command_line
242        self.run_rr(uncompressed_kernel, kernel_command_line, console_pattern, shift=9,
243            args=('-nodefaults', ))
244
245    def test_ppc64_pseries(self):
246        """
247        :avocado: tags=arch:ppc64
248        :avocado: tags=machine:pseries
249        :avocado: tags=accel:tcg
250        """
251        kernel_url = ('https://archives.fedoraproject.org/pub/archive'
252                      '/fedora-secondary/releases/29/Everything/ppc64le/os'
253                      '/ppc/ppc64/vmlinuz')
254        kernel_hash = '3fe04abfc852b66653b8c3c897a59a689270bc77'
255        kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
256
257        kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=hvc0'
258        console_pattern = 'VFS: Cannot open root device'
259        self.run_rr(kernel_path, kernel_command_line, console_pattern)
260
261    def test_ppc64_powernv(self):
262        """
263        :avocado: tags=arch:ppc64
264        :avocado: tags=machine:powernv
265        :avocado: tags=accel:tcg
266        """
267        kernel_url = ('https://archives.fedoraproject.org/pub/archive'
268                      '/fedora-secondary/releases/29/Everything/ppc64le/os'
269                      '/ppc/ppc64/vmlinuz')
270        kernel_hash = '3fe04abfc852b66653b8c3c897a59a689270bc77'
271        kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
272
273        kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + \
274                              'console=tty0 console=hvc0'
275        console_pattern = 'VFS: Cannot open root device'
276        self.run_rr(kernel_path, kernel_command_line, console_pattern)
277
278    def test_m68k_q800(self):
279        """
280        :avocado: tags=arch:m68k
281        :avocado: tags=machine:q800
282        """
283        deb_url = ('https://snapshot.debian.org/archive/debian-ports'
284                   '/20191021T083923Z/pool-m68k/main'
285                   '/l/linux/kernel-image-5.3.0-1-m68k-di_5.3.7-1_m68k.udeb')
286        deb_hash = '044954bb9be4160a3ce81f8bc1b5e856b75cccd1'
287        deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
288        kernel_path = self.extract_from_deb(deb_path,
289                                            '/boot/vmlinux-5.3.0-1-m68k')
290
291        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
292                               'console=ttyS0 vga=off')
293        console_pattern = 'No filesystem could mount root'
294        self.run_rr(kernel_path, kernel_command_line, console_pattern)
295
296    def do_test_advcal_2018(self, file_path, kernel_name, args=None):
297        archive.extract(file_path, self.workdir)
298
299        for entry in os.scandir(self.workdir):
300            if entry.name.startswith('day') and entry.is_dir():
301                kernel_path = os.path.join(entry.path, kernel_name)
302                break
303
304        kernel_command_line = ''
305        console_pattern = 'QEMU advent calendar'
306        self.run_rr(kernel_path, kernel_command_line, console_pattern,
307                    args=args)
308
309    def test_arm_vexpressa9(self):
310        """
311        :avocado: tags=arch:arm
312        :avocado: tags=machine:vexpress-a9
313        """
314        tar_hash = '32b7677ce8b6f1471fb0059865f451169934245b'
315        tar_url = ('https://qemu-advcal.gitlab.io'
316                   '/qac-best-of-multiarch/download/day16.tar.xz')
317        file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
318        dtb_path = self.workdir + '/day16/vexpress-v2p-ca9.dtb'
319        self.do_test_advcal_2018(file_path, 'winter.zImage',
320                                 args=('-dtb', dtb_path))
321
322    def test_m68k_mcf5208evb(self):
323        """
324        :avocado: tags=arch:m68k
325        :avocado: tags=machine:mcf5208evb
326        """
327        tar_hash = 'ac688fd00561a2b6ce1359f9ff6aa2b98c9a570c'
328        tar_url = ('https://qemu-advcal.gitlab.io'
329                   '/qac-best-of-multiarch/download/day07.tar.xz')
330        file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
331        self.do_test_advcal_2018(file_path, 'sanity-clause.elf')
332
333    def test_microblaze_s3adsp1800(self):
334        """
335        :avocado: tags=arch:microblaze
336        :avocado: tags=machine:petalogix-s3adsp1800
337        """
338        tar_hash = '08bf3e3bfb6b6c7ce1e54ab65d54e189f2caf13f'
339        tar_url = ('https://qemu-advcal.gitlab.io'
340                   '/qac-best-of-multiarch/download/day17.tar.xz')
341        file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
342        self.do_test_advcal_2018(file_path, 'ballerina.bin')
343
344    def test_ppc64_e500(self):
345        """
346        :avocado: tags=arch:ppc64
347        :avocado: tags=machine:ppce500
348        :avocado: tags=cpu:e5500
349        """
350        tar_hash = '6951d86d644b302898da2fd701739c9406527fe1'
351        tar_url = ('https://qemu-advcal.gitlab.io'
352                   '/qac-best-of-multiarch/download/day19.tar.xz')
353        file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
354        self.do_test_advcal_2018(file_path, 'uImage')
355
356    def test_or1k_sim(self):
357        """
358        :avocado: tags=arch:or1k
359        :avocado: tags=machine:or1k-sim
360        """
361        tar_hash = '20334cdaf386108c530ff0badaecc955693027dd'
362        tar_url = ('https://qemu-advcal.gitlab.io'
363                   '/qac-best-of-multiarch/download/day20.tar.xz')
364        file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
365        self.do_test_advcal_2018(file_path, 'vmlinux')
366
367    def test_ppc_g3beige(self):
368        """
369        :avocado: tags=arch:ppc
370        :avocado: tags=machine:g3beige
371        """
372        tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc'
373        tar_url = ('https://qemu-advcal.gitlab.io'
374                   '/qac-best-of-multiarch/download/day15.tar.xz')
375        file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
376        self.do_test_advcal_2018(file_path, 'invaders.elf',
377                                 args=('-M', 'graphics=off'))
378
379    def test_ppc_mac99(self):
380        """
381        :avocado: tags=arch:ppc
382        :avocado: tags=machine:mac99
383        """
384        tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc'
385        tar_url = ('https://qemu-advcal.gitlab.io'
386                   '/qac-best-of-multiarch/download/day15.tar.xz')
387        file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
388        self.do_test_advcal_2018(file_path, 'invaders.elf',
389                                 args=('-M', 'graphics=off'))
390
391    def test_sparc_ss20(self):
392        """
393        :avocado: tags=arch:sparc
394        :avocado: tags=machine:SS-20
395        """
396        tar_hash = 'b18550d5d61c7615d989a06edace051017726a9f'
397        tar_url = ('https://qemu-advcal.gitlab.io'
398                   '/qac-best-of-multiarch/download/day11.tar.xz')
399        file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
400        self.do_test_advcal_2018(file_path, 'zImage.elf')
401
402    def test_xtensa_lx60(self):
403        """
404        :avocado: tags=arch:xtensa
405        :avocado: tags=machine:lx60
406        :avocado: tags=cpu:dc233c
407        """
408        tar_hash = '49e88d9933742f0164b60839886c9739cb7a0d34'
409        tar_url = ('https://qemu-advcal.gitlab.io'
410                   '/qac-best-of-multiarch/download/day02.tar.xz')
411        file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
412        self.do_test_advcal_2018(file_path, 'santas-sleigh-ride.elf')
413