xref: /openbmc/qemu/tests/avocado/replay_kernel.py (revision ee376948ebd9cf74b4456a7422e5073a72e4486a)
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