1#!/usr/bin/env python3
2#
3# TCG Plugins tests
4#
5# These are a little more involved than the basic tests run by check-tcg.
6#
7# Copyright (c) 2021 Linaro
8#
9# Author:
10#  Alex Bennée <alex.bennee@linaro.org>
11#
12# SPDX-License-Identifier: GPL-2.0-or-later
13
14import tempfile
15import mmap
16import re
17
18from qemu_test import LinuxKernelTest, Asset
19
20
21class PluginKernelBase(LinuxKernelTest):
22    """
23    Boots a Linux kernel with a TCG plugin enabled.
24    """
25
26    timeout = 120
27    KERNEL_COMMON_COMMAND_LINE = 'printk.time=1 panic=-1 '
28
29    def run_vm(self, kernel_path, kernel_command_line,
30               plugin, plugin_log, console_pattern, args=None):
31
32        vm = self.get_vm()
33        vm.set_console()
34        vm.add_args('-kernel', kernel_path,
35                    '-append', kernel_command_line,
36                    '-plugin', plugin,
37                    '-d', 'plugin',
38                    '-D', plugin_log,
39                    '-net', 'none',
40                    '-no-reboot')
41        if args:
42            vm.add_args(*args)
43
44        try:
45            vm.launch()
46        except:
47            # TODO: probably fails because plugins not enabled but we
48            # can't currently probe for the feature.
49            self.cancel("TCG Plugins not enabled?")
50
51        self.wait_for_console_pattern(console_pattern, vm)
52        # ensure logs are flushed
53        vm.shutdown()
54
55
56class PluginKernelNormal(PluginKernelBase):
57
58    ASSET_KERNEL = Asset(
59        ('https://storage.tuxboot.com/20230331/arm64/Image'),
60        'ce95a7101a5fecebe0fe630deee6bd97b32ba41bc8754090e9ad8961ea8674c7')
61
62    def test_aarch64_virt_insn(self):
63        self.set_machine('virt')
64        self.cpu='cortex-a53'
65        kernel_path = self.ASSET_KERNEL.fetch()
66        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
67                               'console=ttyAMA0')
68        console_pattern = 'Kernel panic - not syncing: VFS:'
69
70        plugin_log = tempfile.NamedTemporaryFile(mode="r+t", prefix="plugin",
71                                                 suffix=".log")
72
73        self.run_vm(kernel_path, kernel_command_line,
74                    "tests/tcg/plugins/libinsn.so", plugin_log.name,
75                    console_pattern)
76
77        with plugin_log as lf, \
78             mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s:
79
80            m = re.search(br"insns: (?P<count>\d+)", s)
81            if "count" not in m.groupdict():
82                self.fail("Failed to find instruction count")
83            else:
84                count = int(m.group("count"))
85                self.log.info(f"Counted: {count} instructions")
86
87
88    def test_aarch64_virt_insn_icount(self):
89        self.set_machine('virt')
90        self.cpu='cortex-a53'
91        kernel_path = self.ASSET_KERNEL.fetch()
92        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
93                               'console=ttyAMA0')
94        console_pattern = 'Kernel panic - not syncing: VFS:'
95
96        plugin_log = tempfile.NamedTemporaryFile(mode="r+t", prefix="plugin",
97                                                 suffix=".log")
98
99        self.run_vm(kernel_path, kernel_command_line,
100                    "tests/tcg/plugins/libinsn.so", plugin_log.name,
101                    console_pattern,
102                    args=('-icount', 'shift=1'))
103
104        with plugin_log as lf, \
105             mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s:
106
107            m = re.search(br"insns: (?P<count>\d+)", s)
108            if "count" not in m.groupdict():
109                self.fail("Failed to find instruction count")
110            else:
111                count = int(m.group("count"))
112                self.log.info(f"Counted: {count} instructions")
113
114if __name__ == '__main__':
115    LinuxKernelTest.main()
116