1import os 2 3import infra.basetest 4 5 6class TestKexec(infra.basetest.BRTest): 7 8 # A specific configuration is needed for using kexec: 9 # - We use Aarch64 since it is well supported for kexec, 10 # - A kernel config fragment enables all the kexec parts, 11 # - The kernel Image is installed on target filesystem to be 12 # reloaded through kexec, 13 # - We use a ext4 rootfs image exposed as a virtio storage (rather 14 # than cpio initrd). This avoids needing to install the initrd 15 # inside the rootfs. 16 config = \ 17 """ 18 BR2_aarch64=y 19 BR2_TOOLCHAIN_EXTERNAL=y 20 BR2_TARGET_GENERIC_GETTY_PORT="ttyAMA0" 21 BR2_LINUX_KERNEL=y 22 BR2_LINUX_KERNEL_CUSTOM_VERSION=y 23 BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.1.15" 24 BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y 25 BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/qemu/aarch64-virt/linux.config" 26 BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="{}" 27 BR2_LINUX_KERNEL_DTS_SUPPORT=y 28 BR2_LINUX_KERNEL_CUSTOM_DTS_PATH="{}" 29 BR2_LINUX_KERNEL_INSTALL_TARGET=y 30 BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y 31 BR2_PACKAGE_KEXEC=y 32 BR2_TARGET_ROOTFS_EXT2=y 33 BR2_TARGET_ROOTFS_EXT2_4=y 34 # BR2_TARGET_ROOTFS_TAR is not set 35 """.format( 36 infra.filepath("tests/package/test_kexec/linux-kexec.fragment"), 37 infra.filepath("tests/package/test_kexec/qemu-aarch64-virt-5.2-machine.dts") 38 ) 39 40 def test_run(self): 41 hda = os.path.join(self.builddir, "images", "rootfs.ext4") 42 kern = os.path.join(self.builddir, "images", "Image") 43 dtb = os.path.join(self.builddir, "images", "qemu-aarch64-virt-5.2-machine.dtb") 44 # Notes: 45 # Sufficient memory is needed to load the kernel: having at 46 # least 512MB works. kexec could silently fail if not enough 47 # memory is present. KASLR needs to be disabled for the test: 48 # we pass "nokaslr" to kernel bootargs, and also pass a custom 49 # devicetree to qemu virt machine. This devicetree is based on 50 # qemu aarch64 5.2 dts with kaslr-seed set 0. 51 # With newer qemu >= 7.0 we can disable KASLR from the qemu 52 # command line using "dtb-kaslr-seed=off". 53 bootargs = ["root=/dev/vda console=ttyAMA0 nokaslr"] 54 qemu_opts = ["-M", "virt", "-dtb", dtb, "-cpu", "cortex-a57", "-m", "512M", 55 "-drive", f"file={hda},if=virtio,format=raw"] 56 self.emulator.boot(arch="aarch64", 57 kernel=kern, 58 kernel_cmdline=bootargs, 59 options=qemu_opts) 60 self.emulator.login() 61 62 # Test the program can execute 63 self.assertRunOk("kexec --version") 64 65 # Check the kexec kernel is NOT loaded: 66 self.assertRunOk("test \"$(cat /sys/kernel/kexec_loaded)\" -eq 0") 67 68 # Load the Kernel: 69 # "--append br-test" adds a dummy kernel args we'll be able to 70 # check in the second executed kernel. 71 # We use the dtb image from /sys/firmware/fdt (since we don't 72 # have the dtb file in the system) 73 self.assertRunOk("kexec -d -l --dtb=/sys/firmware/fdt --reuse-cmdline --serial=ttyAMA0 --append=br-test /boot/Image") 74 75 # Check the kexec kernel IS loaded: 76 self.assertRunOk("test \"$(cat /sys/kernel/kexec_loaded)\" -eq 1") 77 78 # Create a marker file in tmpfs which is supposed to disappear 79 # after kexec kernel restart. 80 self.assertRunOk("touch /dev/shm/br-kexec-marker") 81 82 # Execute the loaded kernel (i.e perform a kexec reboot) 83 # qemu.sendline() is used here because no exit code nor 84 # program return is expected, since kexec is like a 85 # reboot. The login is expected to be reached after the 86 # command is issued. 87 self.emulator.qemu.sendline("kexec -d -e") 88 89 # Wait for the login, and log again 90 self.emulator.login() 91 92 # Check the "br-test" dummy kernel arg is present 93 self.assertRunOk("grep br-test /proc/cmdline") 94 95 # Check the test marker file is no longer here 96 self.assertRunOk("test ! -e /dev/shm/br-kexec-marker") 97 98 # After restart, the kernel is not supposed to have a kexec 99 # loaded image: 100 self.assertRunOk("test \"$(cat /sys/kernel/kexec_loaded)\" -eq 0") 101