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 112 # See https://gitlab.com/qemu-project/qemu/-/issues/2094 113 @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'pc machine is unstable with replay') 114 def test_x86_64_pc(self): 115 """ 116 :avocado: tags=arch:x86_64 117 :avocado: tags=machine:pc 118 :avocado: tags=flaky 119 """ 120 kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' 121 '/linux/releases/29/Everything/x86_64/os/images/pxeboot' 122 '/vmlinuz') 123 kernel_hash = '23bebd2680757891cf7adedb033532163a792495' 124 kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) 125 126 kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0' 127 console_pattern = 'VFS: Cannot open root device' 128 129 self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5) 130 131 def test_x86_64_q35(self): 132 """ 133 :avocado: tags=arch:x86_64 134 :avocado: tags=machine:q35 135 """ 136 kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' 137 '/linux/releases/29/Everything/x86_64/os/images/pxeboot' 138 '/vmlinuz') 139 kernel_hash = '23bebd2680757891cf7adedb033532163a792495' 140 kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) 141 142 kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0' 143 console_pattern = 'VFS: Cannot open root device' 144 145 self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5) 146 147 def test_aarch64_virt(self): 148 """ 149 :avocado: tags=arch:aarch64 150 :avocado: tags=machine:virt 151 :avocado: tags=cpu:cortex-a53 152 """ 153 kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' 154 '/linux/releases/29/Everything/aarch64/os/images/pxeboot' 155 '/vmlinuz') 156 kernel_hash = '8c73e469fc6ea06a58dc83a628fc695b693b8493' 157 kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) 158 159 kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + 160 'console=ttyAMA0') 161 console_pattern = 'VFS: Cannot open root device' 162 163 self.run_rr(kernel_path, kernel_command_line, console_pattern) 164 165 def test_arm_virt(self): 166 """ 167 :avocado: tags=arch:arm 168 :avocado: tags=machine:virt 169 """ 170 kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' 171 '/linux/releases/29/Everything/armhfp/os/images/pxeboot' 172 '/vmlinuz') 173 kernel_hash = 'e9826d741b4fb04cadba8d4824d1ed3b7fb8b4d4' 174 kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) 175 176 kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + 177 'console=ttyAMA0') 178 console_pattern = 'VFS: Cannot open root device' 179 180 self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=1) 181 182 def test_arm_cubieboard_initrd(self): 183 """ 184 :avocado: tags=arch:arm 185 :avocado: tags=machine:cubieboard 186 """ 187 deb_url = ('https://apt.armbian.com/pool/main/l/' 188 'linux-6.6.16/linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb') 189 deb_hash = 'f7c3c8c5432f765445dc6e7eab02f3bbe668256b' 190 deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash) 191 kernel_path = self.extract_from_deb(deb_path, 192 '/boot/vmlinuz-6.6.16-current-sunxi') 193 dtb_path = '/usr/lib/linux-image-6.6.16-current-sunxi/sun4i-a10-cubieboard.dtb' 194 dtb_path = self.extract_from_deb(deb_path, dtb_path) 195 initrd_url = ('https://github.com/groeck/linux-build-test/raw/' 196 '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/' 197 'arm/rootfs-armv5.cpio.gz') 198 initrd_hash = '2b50f1873e113523967806f4da2afe385462ff9b' 199 initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash) 200 initrd_path = os.path.join(self.workdir, 'rootfs.cpio') 201 archive.gzip_uncompress(initrd_path_gz, initrd_path) 202 203 kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + 204 'console=ttyS0,115200 ' 205 'usbcore.nousb ' 206 'panic=-1 noreboot') 207 console_pattern = 'Boot successful.' 208 self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=1, 209 args=('-dtb', dtb_path, 210 '-initrd', initrd_path, 211 '-no-reboot')) 212 213 def test_s390x_s390_ccw_virtio(self): 214 """ 215 :avocado: tags=arch:s390x 216 :avocado: tags=machine:s390-ccw-virtio 217 """ 218 kernel_url = ('https://archives.fedoraproject.org/pub/archive' 219 '/fedora-secondary/releases/29/Everything/s390x/os/images' 220 '/kernel.img') 221 kernel_hash = 'e8e8439103ef8053418ef062644ffd46a7919313' 222 kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) 223 224 kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=sclp0' 225 console_pattern = 'Kernel command line: %s' % kernel_command_line 226 self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=9) 227 228 def test_alpha_clipper(self): 229 """ 230 :avocado: tags=arch:alpha 231 :avocado: tags=machine:clipper 232 """ 233 kernel_url = ('http://archive.debian.org/debian/dists/lenny/main/' 234 'installer-alpha/20090123lenny10/images/cdrom/vmlinuz') 235 kernel_hash = '3a943149335529e2ed3e74d0d787b85fb5671ba3' 236 kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) 237 238 uncompressed_kernel = archive.uncompress(kernel_path, self.workdir) 239 240 kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0' 241 console_pattern = 'Kernel command line: %s' % kernel_command_line 242 self.run_rr(uncompressed_kernel, kernel_command_line, console_pattern, shift=9, 243 args=('-nodefaults', )) 244 245 def test_ppc64_pseries(self): 246 """ 247 :avocado: tags=arch:ppc64 248 :avocado: tags=machine:pseries 249 :avocado: tags=accel:tcg 250 """ 251 kernel_url = ('https://archives.fedoraproject.org/pub/archive' 252 '/fedora-secondary/releases/29/Everything/ppc64le/os' 253 '/ppc/ppc64/vmlinuz') 254 kernel_hash = '3fe04abfc852b66653b8c3c897a59a689270bc77' 255 kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) 256 257 kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=hvc0' 258 console_pattern = 'VFS: Cannot open root device' 259 self.run_rr(kernel_path, kernel_command_line, console_pattern) 260 261 def test_ppc64_powernv(self): 262 """ 263 :avocado: tags=arch:ppc64 264 :avocado: tags=machine:powernv 265 :avocado: tags=accel:tcg 266 """ 267 kernel_url = ('https://archives.fedoraproject.org/pub/archive' 268 '/fedora-secondary/releases/29/Everything/ppc64le/os' 269 '/ppc/ppc64/vmlinuz') 270 kernel_hash = '3fe04abfc852b66653b8c3c897a59a689270bc77' 271 kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) 272 273 kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + \ 274 'console=tty0 console=hvc0' 275 console_pattern = 'VFS: Cannot open root device' 276 self.run_rr(kernel_path, kernel_command_line, console_pattern) 277 278 def test_m68k_q800(self): 279 """ 280 :avocado: tags=arch:m68k 281 :avocado: tags=machine:q800 282 """ 283 deb_url = ('https://snapshot.debian.org/archive/debian-ports' 284 '/20191021T083923Z/pool-m68k/main' 285 '/l/linux/kernel-image-5.3.0-1-m68k-di_5.3.7-1_m68k.udeb') 286 deb_hash = '044954bb9be4160a3ce81f8bc1b5e856b75cccd1' 287 deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash) 288 kernel_path = self.extract_from_deb(deb_path, 289 '/boot/vmlinux-5.3.0-1-m68k') 290 291 kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + 292 'console=ttyS0 vga=off') 293 console_pattern = 'No filesystem could mount root' 294 self.run_rr(kernel_path, kernel_command_line, console_pattern) 295 296 def do_test_advcal_2018(self, file_path, kernel_name, args=None): 297 archive.extract(file_path, self.workdir) 298 299 for entry in os.scandir(self.workdir): 300 if entry.name.startswith('day') and entry.is_dir(): 301 kernel_path = os.path.join(entry.path, kernel_name) 302 break 303 304 kernel_command_line = '' 305 console_pattern = 'QEMU advent calendar' 306 self.run_rr(kernel_path, kernel_command_line, console_pattern, 307 args=args) 308 309 def test_arm_vexpressa9(self): 310 """ 311 :avocado: tags=arch:arm 312 :avocado: tags=machine:vexpress-a9 313 """ 314 tar_hash = '32b7677ce8b6f1471fb0059865f451169934245b' 315 tar_url = ('https://qemu-advcal.gitlab.io' 316 '/qac-best-of-multiarch/download/day16.tar.xz') 317 file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) 318 dtb_path = self.workdir + '/day16/vexpress-v2p-ca9.dtb' 319 self.do_test_advcal_2018(file_path, 'winter.zImage', 320 args=('-dtb', dtb_path)) 321 322 def test_m68k_mcf5208evb(self): 323 """ 324 :avocado: tags=arch:m68k 325 :avocado: tags=machine:mcf5208evb 326 """ 327 tar_hash = 'ac688fd00561a2b6ce1359f9ff6aa2b98c9a570c' 328 tar_url = ('https://qemu-advcal.gitlab.io' 329 '/qac-best-of-multiarch/download/day07.tar.xz') 330 file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) 331 self.do_test_advcal_2018(file_path, 'sanity-clause.elf') 332 333 def test_microblaze_s3adsp1800(self): 334 """ 335 :avocado: tags=arch:microblaze 336 :avocado: tags=machine:petalogix-s3adsp1800 337 """ 338 tar_hash = '08bf3e3bfb6b6c7ce1e54ab65d54e189f2caf13f' 339 tar_url = ('https://qemu-advcal.gitlab.io' 340 '/qac-best-of-multiarch/download/day17.tar.xz') 341 file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) 342 self.do_test_advcal_2018(file_path, 'ballerina.bin') 343 344 def test_ppc64_e500(self): 345 """ 346 :avocado: tags=arch:ppc64 347 :avocado: tags=machine:ppce500 348 :avocado: tags=cpu:e5500 349 """ 350 tar_hash = '6951d86d644b302898da2fd701739c9406527fe1' 351 tar_url = ('https://qemu-advcal.gitlab.io' 352 '/qac-best-of-multiarch/download/day19.tar.xz') 353 file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) 354 self.do_test_advcal_2018(file_path, 'uImage') 355 356 def test_or1k_sim(self): 357 """ 358 :avocado: tags=arch:or1k 359 :avocado: tags=machine:or1k-sim 360 """ 361 tar_hash = '20334cdaf386108c530ff0badaecc955693027dd' 362 tar_url = ('https://qemu-advcal.gitlab.io' 363 '/qac-best-of-multiarch/download/day20.tar.xz') 364 file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) 365 self.do_test_advcal_2018(file_path, 'vmlinux') 366 367 def test_ppc_g3beige(self): 368 """ 369 :avocado: tags=arch:ppc 370 :avocado: tags=machine:g3beige 371 """ 372 tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc' 373 tar_url = ('https://qemu-advcal.gitlab.io' 374 '/qac-best-of-multiarch/download/day15.tar.xz') 375 file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) 376 self.do_test_advcal_2018(file_path, 'invaders.elf', 377 args=('-M', 'graphics=off')) 378 379 def test_ppc_mac99(self): 380 """ 381 :avocado: tags=arch:ppc 382 :avocado: tags=machine:mac99 383 """ 384 tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc' 385 tar_url = ('https://qemu-advcal.gitlab.io' 386 '/qac-best-of-multiarch/download/day15.tar.xz') 387 file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) 388 self.do_test_advcal_2018(file_path, 'invaders.elf', 389 args=('-M', 'graphics=off')) 390 391 def test_sparc_ss20(self): 392 """ 393 :avocado: tags=arch:sparc 394 :avocado: tags=machine:SS-20 395 """ 396 tar_hash = 'b18550d5d61c7615d989a06edace051017726a9f' 397 tar_url = ('https://qemu-advcal.gitlab.io' 398 '/qac-best-of-multiarch/download/day11.tar.xz') 399 file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) 400 self.do_test_advcal_2018(file_path, 'zImage.elf') 401 402 def test_xtensa_lx60(self): 403 """ 404 :avocado: tags=arch:xtensa 405 :avocado: tags=machine:lx60 406 :avocado: tags=cpu:dc233c 407 """ 408 tar_hash = '49e88d9933742f0164b60839886c9739cb7a0d34' 409 tar_url = ('https://qemu-advcal.gitlab.io' 410 '/qac-best-of-multiarch/download/day02.tar.xz') 411 file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) 412 self.do_test_advcal_2018(file_path, 'santas-sleigh-ride.elf') 413