Extend tools/testing/selftests/kho/vmtest.sh and init.c to run a second
QEMU test verifying read-only KHO ('kho_ro=<fdt_phys>') after the
standard KHO test on both x86_64 and aarch64:

- Build a second kernel configured with CONFIG_KEXEC_HANDOVER_READONLY=y
  (and CONFIG_KEXEC_HANDOVER=n).
- Pass KHO_RO_CMDLINE ('nokaslr kho_bootmem=64M,64M,64M' on x86_64,
  'cma=116M@0x40c00000' on aarch64) to the first kernel in the read-only
  test run so KHO allocations are placed in predictable physical ranges.
- When booted with 'kho_ro_test', read /debugfs/kho/out/fdt_phys in
  init.c and kexec into the read-only kernel with 'kho_ro=<fdt_phys>'
  and architecture-specific memory parameters
  ('memmap=792M$16M memmap=24M$1000M' on x86_64,
  'mem=128M cma=12M@0x40000000' on aarch64) so the preserved pages are
  excluded from the boot memory map and mapped via kho_ro_map_folio().
- Verify 'KHO restore succeeded' from test_kho in read-only mode.

Signed-off-by: Pasha Tatashin <[email protected]>
---
 tools/testing/selftests/kho/arm64.conf |   3 +
 tools/testing/selftests/kho/init.c     |  38 ++++++++-
 tools/testing/selftests/kho/vmtest.sh  | 103 +++++++++++++++++--------
 tools/testing/selftests/kho/x86.conf   |   1 +
 4 files changed, 112 insertions(+), 33 deletions(-)

diff --git a/tools/testing/selftests/kho/arm64.conf 
b/tools/testing/selftests/kho/arm64.conf
index ee696807cd35..36dd8c46060c 100644
--- a/tools/testing/selftests/kho/arm64.conf
+++ b/tools/testing/selftests/kho/arm64.conf
@@ -4,6 +4,9 @@ CONFIG_SERIAL_AMBA_PL010=y
 CONFIG_SERIAL_AMBA_PL010_CONSOLE=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_CMA=y
+CONFIG_DMA_CMA=y
 "
 KERNEL_IMAGE="Image"
 KERNEL_CMDLINE="console=ttyAMA0"
+KHO_RO_CMDLINE="cma=116M@0x40c00000"
diff --git a/tools/testing/selftests/kho/init.c 
b/tools/testing/selftests/kho/init.c
index 88a41b6eba95..272338f186be 100644
--- a/tools/testing/selftests/kho/init.c
+++ b/tools/testing/selftests/kho/init.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
 #include <stdio.h>
+#include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/syscall.h>
@@ -12,6 +13,15 @@
 #define COMMAND_LINE_SIZE      2048
 
 #define KERNEL_IMAGE "/kernel"
+#define FDT_PHYS_PATH "/debugfs/kho/out/fdt_phys"
+
+#if defined(__x86_64__)
+#define KHO_RO_MEM_PARAM "memmap=792M$16M memmap=24M$1000M"
+#elif defined(__aarch64__)
+#define KHO_RO_MEM_PARAM "mem=128M cma=12M@0x40000000"
+#else
+#define KHO_RO_MEM_PARAM ""
+#endif
 
 static int mount_filesystems(void)
 {
@@ -32,7 +42,8 @@ static long kexec_file_load(int kernel_fd, int initrd_fd,
 static int kexec_load(void)
 {
        char cmdline[COMMAND_LINE_SIZE];
-       ssize_t len;
+       ssize_t len, fdt_len;
+       char fdt_phys[64];
        int fd, err;
 
        fd = open("/proc/cmdline", O_RDONLY);
@@ -41,11 +52,34 @@ static int kexec_load(void)
 
        len = read(fd, cmdline, sizeof(cmdline));
        close(fd);
-       if (len < 0)
+       if (len <= 0)
                return -1;
 
        /* replace \n with \0 */
        cmdline[len - 1] = 0;
+
+       if (strstr(cmdline, "kho_ro_test")) {
+               fd = open(FDT_PHYS_PATH, O_RDONLY);
+               if (fd < 0)
+                       return -1;
+
+               fdt_len = read(fd, fdt_phys, sizeof(fdt_phys) - 1);
+               close(fd);
+               if (fdt_len <= 0)
+                       return -1;
+
+               if (fdt_phys[fdt_len - 1] == '\n')
+                       fdt_len--;
+               fdt_phys[fdt_len] = 0;
+
+               len = (len - 1) + snprintf(cmdline + len - 1,
+                                          sizeof(cmdline) - (len - 1),
+                                          " kho_ro=%s " KHO_RO_MEM_PARAM,
+                                          fdt_phys) + 1;
+               if (len <= 0 || (size_t)len > sizeof(cmdline))
+                       return -1;
+       }
+
        fd = open(KERNEL_IMAGE, O_RDONLY);
        if (fd < 0)
                return -1;
diff --git a/tools/testing/selftests/kho/vmtest.sh 
b/tools/testing/selftests/kho/vmtest.sh
index 0014bd76e88d..b3659e4fd1c9 100755
--- a/tools/testing/selftests/kho/vmtest.sh
+++ b/tools/testing/selftests/kho/vmtest.sh
@@ -35,32 +35,25 @@ trap cleanup EXIT
 function skip() {
        local msg=${1:-""}
 
-       ktap_test_skip "$msg"
+       while [[ "$KTAP_TESTNO" -le "$KSFT_NUM_TESTS" ]]; do
+               ktap_test_skip "$msg"
+       done
        exit "$KSFT_SKIP"
 }
 
-function fail() {
-       local msg=${1:-""}
-
-       ktap_test_fail "$msg"
-       exit "$KSFT_FAIL"
-}
-
 function build_kernel() {
        local build_dir=$1
        local make_cmd=$2
        local arch_kconfig=$3
        local kimage=$4
+       local kho_mode=${5:-"rw"}
 
        local kho_config="$tmp_dir/kho.config"
        local kconfig="$build_dir/.config"
 
        # enable initrd, KHO and KHO test in kernel configuration
-       tee "$kconfig" > "$kho_config" <<EOF
+       cat > "$kho_config" <<EOF
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_KEXEC_HANDOVER=y
-CONFIG_KEXEC_HANDOVER_DEBUG=y
-CONFIG_KEXEC_HANDOVER_DEBUGFS=y
 CONFIG_TEST_KEXEC_HANDOVER=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_VM=y
@@ -70,20 +63,50 @@ CONFIG_DEFERRED_STRUCT_PAGE_INIT=y
 $arch_kconfig
 EOF
 
+       if [[ "$kho_mode" == "ro" ]]; then
+               cat >> "$kho_config" <<EOF
+# CONFIG_KEXEC_HANDOVER is not set
+CONFIG_KEXEC_HANDOVER_READONLY=y
+EOF
+       else
+               cat >> "$kho_config" <<EOF
+CONFIG_KEXEC_HANDOVER=y
+CONFIG_KEXEC_HANDOVER_DEBUG=y
+CONFIG_KEXEC_HANDOVER_DEBUGFS=y
+EOF
+       fi
+
        make_cmd="$make_cmd -C $kernel_dir O=$build_dir"
-       $make_cmd olddefconfig
+       local need_config=0
+       if [[ ! -f "$kconfig" ]]; then
+               need_config=1
+       else
+               while read -r opt ; do
+                       [[ -z "$opt" ]] && continue
+                       grep -q "^$opt$" "$kconfig" || need_config=1
+               done < "$kho_config"
+       fi
+
+       if [[ "$need_config" -eq 1 ]]; then
+               cp "$kho_config" "$kconfig"
+               $make_cmd olddefconfig
+       fi
 
        # verify that kernel confiration has all necessary options
        while read -r opt ; do
-               grep "$opt" "$kconfig" &>/dev/null || skip "$opt is missing"
+               [[ -z "$opt" ]] && continue
+               grep -q "^$opt$" "$kconfig" || skip "$opt is missing"
        done < "$kho_config"
 
        $make_cmd "$kimage"
-       $make_cmd headers_install INSTALL_HDR_PATH="$headers_dir"
+       if [[ "$kho_mode" != "ro" ]]; then
+               $make_cmd headers_install INSTALL_HDR_PATH="$headers_dir"
+       fi
 }
 
 function mkinitrd() {
        local kernel=$1
+       local out_initrd=$2
 
        "$CROSS_COMPILE"gcc -s -static -Os -nostdinc -nostdlib \
                        -fno-asynchronous-unwind-tables -fno-ident \
@@ -100,25 +123,31 @@ 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"
+       "$build_dir/usr/gen_init_cpio" "$tmp_dir/cpio_list" > "$out_initrd"
 }
 
 function run_qemu() {
        local qemu_cmd=$1
        local cmdline=$2
        local kernel=$3
+       local initrd_path=$4
+       local test_name=$5
        local serial="$tmp_dir/qemu.serial"
 
        cmdline="$cmdline kho=on panic=-1"
 
-       $qemu_cmd -m 1G -smp 2 -no-reboot -nographic -nodefaults \
-                 -accel kvm -accel hvf -accel tcg  \
-                 -serial file:"$serial" \
-                 -append "$cmdline" \
-                 -kernel "$kernel" \
-                 -initrd "$initrd"
-
-       grep "KHO restore succeeded" "$serial" &> /dev/null || fail "KHO failed"
+       rm -f "$serial"
+       if $qemu_cmd -m 1G -smp 2 -no-reboot -nographic -nodefaults \
+                    -accel kvm -accel hvf -accel tcg  \
+                    -serial file:"$serial" \
+                    -append "$cmdline" \
+                    -kernel "$kernel" \
+                    -initrd "$initrd_path" && \
+          grep "KHO restore succeeded" "$serial" &> /dev/null; then
+               ktap_test_pass "$test_name succeeded"
+       else
+               ktap_test_fail "$test_name failed"
+       fi
 }
 
 function target_to_arch() {
@@ -164,7 +193,7 @@ function main() {
        done
 
        ktap_print_header
-       ktap_set_plan 1
+       ktap_set_plan 2
 
        if [[ "$target" != "$(uname -m)" ]] && [[ -z "$CROSS_COMPILE" ]]; then
                skip "Cross-platform testing needs to specify CROSS_COMPILE"
@@ -174,17 +203,29 @@ function main() {
        local arch=$(target_to_arch "$target")
        source "$test_dir/$arch.conf"
 
-       # build the kernel and create initrd
+       # build the kernels and create initrds
        # initrd includes the kernel image that will be kexec'ed
        local make_cmd="make ARCH=$arch CROSS_COMPILE=$CROSS_COMPILE -j$jobs"
-       build_kernel "$build_dir" "$make_cmd" "$QEMU_KCONFIG" "$KERNEL_IMAGE"
+       build_kernel "$build_dir" "$make_cmd" "$QEMU_KCONFIG" "$KERNEL_IMAGE" 
"rw"
 
-       local kernel="$build_dir/arch/$arch/boot/$KERNEL_IMAGE"
-       mkinitrd "$kernel"
+       local kernel="$tmp_dir/$KERNEL_IMAGE"
+       cp "$build_dir/arch/$arch/boot/$KERNEL_IMAGE" "$kernel"
+       mkinitrd "$kernel" "$initrd"
+
+       local build_dir_ro="${build_dir}-ro"
+       if [[ ! -d "$build_dir_ro" ]]; then
+               cp -a "$build_dir" "$build_dir_ro"
+       fi
+       build_kernel "$build_dir_ro" "$make_cmd" "$QEMU_KCONFIG" 
"$KERNEL_IMAGE" "ro"
+       local kernel_ro="$build_dir_ro/arch/$arch/boot/$KERNEL_IMAGE"
+       local initrd_ro="$tmp_dir/initrd-ro.cpio"
+       mkinitrd "$kernel_ro" "$initrd_ro"
 
-       run_qemu "$QEMU_CMD" "$KERNEL_CMDLINE" "$kernel"
+       trap - ERR
 
-       ktap_test_pass "KHO succeeded"
+       run_qemu "$QEMU_CMD" "$KERNEL_CMDLINE" "$kernel" "$initrd" "KHO"
+       run_qemu "$QEMU_CMD" "$KERNEL_CMDLINE $KHO_RO_CMDLINE kho_ro_test" \
+                "$kernel" "$initrd_ro" "KHO read-only"
 }
 
 main "$@"
diff --git a/tools/testing/selftests/kho/x86.conf 
b/tools/testing/selftests/kho/x86.conf
index b419e610ca22..2c097c5bd6c6 100644
--- a/tools/testing/selftests/kho/x86.conf
+++ b/tools/testing/selftests/kho/x86.conf
@@ -5,3 +5,4 @@ CONFIG_SERIAL_8250_CONSOLE=y
 "
 KERNEL_IMAGE="bzImage"
 KERNEL_CMDLINE="console=ttyS0"
+KHO_RO_CMDLINE="nokaslr kho_bootmem=64M,64M,64M"
-- 
2.56.0.176.g3575e65682-goog


Reply via email to