xref: /openbmc/qemu/tests/avocado/tcg_plugins.py (revision 2df1eb27)
1# TCG Plugins tests
2#
3# These are a little more involved than the basic tests run by check-tcg.
4#
5# Copyright (c) 2021 Linaro
6#
7# Author:
8#  Alex Bennée <alex.bennee@linaro.org>
9#
10# SPDX-License-Identifier: GPL-2.0-or-later
11
12import tempfile
13import mmap
14import re
15
16from boot_linux_console import LinuxKernelTest
17
18
19class PluginKernelBase(LinuxKernelTest):
20    """
21    Boots a Linux kernel with a TCG plugin enabled.
22    """
23
24    timeout = 120
25    KERNEL_COMMON_COMMAND_LINE = 'printk.time=1 panic=-1 '
26
27    def run_vm(self, kernel_path, kernel_command_line,
28               plugin, plugin_log, console_pattern, args=None):
29
30        vm = self.get_vm()
31        vm.set_console()
32        vm.add_args('-kernel', kernel_path,
33                    '-append', kernel_command_line,
34                    '-plugin', plugin,
35                    '-d', 'plugin',
36                    '-D', plugin_log,
37                    '-net', 'none',
38                    '-no-reboot')
39        if args:
40            vm.add_args(*args)
41
42        try:
43            vm.launch()
44        except:
45            # TODO: probably fails because plugins not enabled but we
46            # can't currently probe for the feature.
47            self.cancel("TCG Plugins not enabled?")
48
49        self.wait_for_console_pattern(console_pattern, vm)
50        # ensure logs are flushed
51        vm.shutdown()
52
53
54class PluginKernelNormal(PluginKernelBase):
55
56    def _grab_aarch64_kernel(self):
57        kernel_url = ('https://storage.tuxboot.com/20230331/arm64/Image')
58        kernel_sha256 = 'ce95a7101a5fecebe0fe630deee6bd97b32ba41bc8754090e9ad8961ea8674c7'
59        kernel_path = self.fetch_asset(kernel_url,
60                                       asset_hash=kernel_sha256,
61                                       algorithm = "sha256")
62        return kernel_path
63
64    def test_aarch64_virt_insn(self):
65        """
66        :avocado: tags=accel:tcg
67        :avocado: tags=arch:aarch64
68        :avocado: tags=machine:virt
69        :avocado: tags=cpu:cortex-a53
70        """
71        kernel_path = self._grab_aarch64_kernel()
72        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
73                               'console=ttyAMA0')
74        console_pattern = 'Kernel panic - not syncing: VFS:'
75
76        plugin_log = tempfile.NamedTemporaryFile(mode="r+t", prefix="plugin",
77                                                 suffix=".log")
78
79        self.run_vm(kernel_path, kernel_command_line,
80                    "tests/plugin/libinsn.so", plugin_log.name,
81                    console_pattern)
82
83        with plugin_log as lf, \
84             mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s:
85
86            m = re.search(br"insns: (?P<count>\d+)", s)
87            if "count" not in m.groupdict():
88                self.fail("Failed to find instruction count")
89            else:
90                count = int(m.group("count"))
91                self.log.info(f"Counted: {count} instructions")
92
93
94    def test_aarch64_virt_insn_icount(self):
95        """
96        :avocado: tags=accel:tcg
97        :avocado: tags=arch:aarch64
98        :avocado: tags=machine:virt
99        :avocado: tags=cpu:cortex-a53
100        """
101        kernel_path = self._grab_aarch64_kernel()
102        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
103                               'console=ttyAMA0')
104        console_pattern = 'Kernel panic - not syncing: VFS:'
105
106        plugin_log = tempfile.NamedTemporaryFile(mode="r+t", prefix="plugin",
107                                                 suffix=".log")
108
109        self.run_vm(kernel_path, kernel_command_line,
110                    "tests/plugin/libinsn.so", plugin_log.name,
111                    console_pattern,
112                    args=('-icount', 'shift=1'))
113
114        with plugin_log as lf, \
115             mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s:
116
117            m = re.search(br"insns: (?P<count>\d+)", s)
118            if "count" not in m.groupdict():
119                self.fail("Failed to find instruction count")
120            else:
121                count = int(m.group("count"))
122                self.log.info(f"Counted: {count} instructions")
123
124    def test_aarch64_virt_mem_icount(self):
125        """
126        :avocado: tags=accel:tcg
127        :avocado: tags=arch:aarch64
128        :avocado: tags=machine:virt
129        :avocado: tags=cpu:cortex-a53
130        """
131        kernel_path = self._grab_aarch64_kernel()
132        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
133                               'console=ttyAMA0')
134        console_pattern = 'Kernel panic - not syncing: VFS:'
135
136        plugin_log = tempfile.NamedTemporaryFile(mode="r+t", prefix="plugin",
137                                                 suffix=".log")
138
139        self.run_vm(kernel_path, kernel_command_line,
140                    "tests/plugin/libmem.so,inline=true,callback=true", plugin_log.name,
141                    console_pattern,
142                    args=('-icount', 'shift=1'))
143
144        with plugin_log as lf, \
145             mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s:
146            m = re.findall(br"mem accesses: (?P<count>\d+)", s)
147            if m is None or len(m) != 2:
148                self.fail("no memory access counts found")
149            else:
150                inline = int(m[0])
151                callback = int(m[1])
152                if inline != callback:
153                    self.fail("mismatched access counts")
154                else:
155                    self.log.info(f"Counted {inline} memory accesses")
156