On 2025-08-01 13:06:30+0300, Mike Rapoport wrote:
From: "Mike Rapoport (Microsoft)" rppt@kernel.org
Testing kexec handover requires a kernel driver that will generate some data and preserve it with KHO on the first boot and then restore that data and verify it was preserved properly after kexec.
To facilitate such test, along with the kernel driver responsible for data generation, preservation and restoration add a script that runs a kernel in a VM with a minimal /init. The /init enables KHO, loads a kernel image for kexec and runs kexec reboot. After the boot of the kexeced kernel, the driver verifies that the data was properly preserved.
Signed-off-by: Mike Rapoport (Microsoft) rppt@kernel.org
Looking at it while awake brought up some more nitpicks. In any case: Reviewed-by: Thomas Weißschuh linux@weissschuh.net # for the nolibc usage
diff --git a/tools/testing/selftests/kho/init.c b/tools/testing/selftests/kho/init.c new file mode 100644 index 000000000000..8044ca56fff5 --- /dev/null +++ b/tools/testing/selftests/kho/init.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0
+#include <errno.h>
Not actually used.
+#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/syscall.h> +#include <sys/mount.h> +#include <sys/reboot.h>
+/* from arch/x86/include/asm/setup.h */ +#define COMMAND_LINE_SIZE 2048
+/* from include/linux/kexex.h */
"kexec.h"
+#define KEXEC_FILE_NO_INITRAMFS 0x00000004
This is actually part of the UAPI headers, why not use it from there?
+#define KHO_FINILIZE "/debugfs/kho/out/finalize"
KHO_FINALIZE
+#define KERNEL_IMAGE "/kernel"
+static int mount_filesystems(void) +{
- if (mount("debugfs", "/debugfs", "debugfs", 0, NULL) < 0)
return -1;
- return mount("proc", "/proc", "proc", 0, NULL);
+}
+static int kho_enable(void) +{
- const char enable[] = "1";
- int fd;
- fd = open(KHO_FINILIZE, O_RDWR);
- if (fd < 0)
return -1;
- if (write(fd, enable, sizeof(enable)) != sizeof(enable))
return 1;
- close(fd);
- return 0;
+}
+static long kexec_file_load(int kernel_fd, int initrd_fd,
unsigned long cmdline_len, const char *cmdline,
unsigned long flags)
+{
- return syscall(__NR_kexec_file_load, kernel_fd, initrd_fd, cmdline_len,
cmdline, flags);
+}
+static int kexec_load(void) +{
- char cmdline[COMMAND_LINE_SIZE];
- ssize_t len;
- int fd, err;
- fd = open("/proc/cmdline", O_RDONLY);
- if (fd < 0)
return -1;
- len = read(fd, cmdline, sizeof(cmdline));
- close(fd);
- if (len < 0)
return -1;
- /* replace \n with \0 */
- cmdline[len - 1] = 0;
- fd = open(KERNEL_IMAGE, O_RDONLY);
- if (fd < 0)
return -1;
- err = kexec_file_load(fd, -1, len, cmdline, KEXEC_FILE_NO_INITRAMFS);
- close(fd);
- return err ? : 0;
+}
+int main(int argc, char *argv[]) +{
- if (mount_filesystems())
goto err_reboot;
- if (kho_enable())
goto err_reboot;
- if (kexec_load())
goto err_reboot;
- if (reboot(RB_KEXEC))
goto err_reboot;
- return 0;
+err_reboot:
- reboot(RB_AUTOBOOT);
- return -1;
+} diff --git a/tools/testing/selftests/kho/vmtest.sh b/tools/testing/selftests/kho/vmtest.sh new file mode 100755 index 000000000000..3f6c17166846 --- /dev/null +++ b/tools/testing/selftests/kho/vmtest.sh
(...)
+function mkinitrd() {
- local kernel=$1
- "$CROSS_COMPILE"gcc -s -static -Os -nostdinc -nostdlib \
-fno-asynchronous-unwind-tables -fno-ident \
-I "$headers_dir/include" \
-I "$kernel_dir/tools/include/nolibc" \
-o "$tmp_dir/init" "$test_dir/init.c"
You could build this as a userprog as part of kbuild. Then it will also work automatically with clang.
- cat > "$tmp_dir/cpio_list" <<EOF
+dir /dev 0755 0 0 +dir /proc 0755 0 0 +dir /debugfs 0755 0 0 +nod /dev/console 0600 0 0 c 5 1 +file /init $tmp_dir/init 0755 0 0 +file /kernel $kernel 0644 0 0 +EOF
- "$build_dir/usr/gen_init_cpio" "$tmp_dir/cpio_list" > "$initrd"
This could also be hooked up to kbuild.
+}
(...)