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