xref: /openbmc/qemu/tests/avocado/tcg_plugins.py (revision 6016b7b4)
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 = ('http://security.debian.org/'
58                      'debian-security/pool/updates/main/l/linux-signed-arm64/'
59                      'linux-image-4.19.0-12-arm64_4.19.152-1_arm64.deb')
60        kernel_sha1 = '2036c2792f80ac9c4ccaae742b2e0a28385b6010'
61        kernel_deb = self.fetch_asset(kernel_url, asset_hash=kernel_sha1)
62        kernel_path = self.extract_from_deb(kernel_deb,
63                                            "/boot/vmlinuz-4.19.0-12-arm64")
64        return kernel_path
65
66    def test_aarch64_virt_insn(self):
67        """
68        :avocado: tags=accel:tcg
69        :avocado: tags=arch:aarch64
70        :avocado: tags=machine:virt
71        :avocado: tags=cpu:cortex-a53
72        """
73        kernel_path = self._grab_aarch64_kernel()
74        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
75                               'console=ttyAMA0')
76        console_pattern = 'Kernel panic - not syncing: VFS:'
77
78        plugin_log = tempfile.NamedTemporaryFile(mode="r+t", prefix="plugin",
79                                                 suffix=".log")
80
81        self.run_vm(kernel_path, kernel_command_line,
82                    "tests/plugin/libinsn.so", plugin_log.name,
83                    console_pattern)
84
85        with plugin_log as lf, \
86             mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s:
87
88            m = re.search(br"insns: (?P<count>\d+)", s)
89            if "count" not in m.groupdict():
90                self.fail("Failed to find instruction count")
91
92    def test_aarch64_virt_insn_icount(self):
93        """
94        :avocado: tags=accel:tcg
95        :avocado: tags=arch:aarch64
96        :avocado: tags=machine:virt
97        :avocado: tags=cpu:cortex-a53
98        """
99        kernel_path = self._grab_aarch64_kernel()
100        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
101                               'console=ttyAMA0')
102        console_pattern = 'Kernel panic - not syncing: VFS:'
103
104        plugin_log = tempfile.NamedTemporaryFile(mode="r+t", prefix="plugin",
105                                                 suffix=".log")
106
107        self.run_vm(kernel_path, kernel_command_line,
108                    "tests/plugin/libinsn.so", plugin_log.name,
109                    console_pattern,
110                    args=('-icount', 'shift=1'))
111
112        with plugin_log as lf, \
113             mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s:
114            m = re.search(br"detected repeat execution @ (?P<addr>0x[0-9A-Fa-f]+)", s)
115            if m is not None and "addr" in m.groupdict():
116                self.fail("detected repeated instructions")
117
118    def test_aarch64_virt_mem_icount(self):
119        """
120        :avocado: tags=accel:tcg
121        :avocado: tags=arch:aarch64
122        :avocado: tags=machine:virt
123        :avocado: tags=cpu:cortex-a53
124        """
125        kernel_path = self._grab_aarch64_kernel()
126        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
127                               'console=ttyAMA0')
128        console_pattern = 'Kernel panic - not syncing: VFS:'
129
130        plugin_log = tempfile.NamedTemporaryFile(mode="r+t", prefix="plugin",
131                                                 suffix=".log")
132
133        self.run_vm(kernel_path, kernel_command_line,
134                    "tests/plugin/libmem.so,inline=true,callback=true", plugin_log.name,
135                    console_pattern,
136                    args=('-icount', 'shift=1'))
137
138        with plugin_log as lf, \
139             mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s:
140            m = re.findall(br"mem accesses: (?P<count>\d+)", s)
141            if m is None or len(m) != 2:
142                self.fail("no memory access counts found")
143            else:
144                inline = int(m[0])
145                callback = int(m[1])
146                if inline != callback:
147                    self.fail("mismatched access counts")
148