linux/tools/testing/selftests/kho/vmtest.sh
Mike Rapoport (Microsoft) b753522bed kho: add test for kexec handover
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.

[rppt@kernel.org: fix section mismatch]
  Link: https://lkml.kernel.org/r/aIiRC8fXiOXKbPM_@kernel.org
Link: https://lkml.kernel.org/r/20250727083733.2590139-1-rppt@kernel.org
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Cc: Alexander Graf <graf@amazon.com>
Cc: Changyuan Lyu <changyuanl@google.com>
Cc: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Pratyush Yadav <pratyush@kernel.org>
Cc: Shuah Khan <shuah@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2025-08-02 12:01:41 -07:00

183 lines
3.8 KiB
Bash
Executable file

#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
set -ue
CROSS_COMPILE="${CROSS_COMPILE:-""}"
test_dir=$(realpath "$(dirname "$0")")
kernel_dir=$(realpath "$test_dir/../../../..")
tmp_dir=$(mktemp -d /tmp/kho-test.XXXXXXXX)
headers_dir="$tmp_dir/usr"
initrd_dir="$tmp_dir/initrd"
initrd="$tmp_dir/initrd.cpio"
source "$test_dir/../kselftest/ktap_helpers.sh"
function usage() {
cat <<EOF
$0 [-d build_dir] [-j jobs] [-t target_arch] [-h]
Options:
-d) path to the kernel build directory
-j) number of jobs for compilation, similar to -j in make
-t) run test for target_arch, requires CROSS_COMPILE set
supported targets: aarch64, x86_64
-h) display this help
EOF
}
function cleanup() {
rm -fr "$tmp_dir"
ktap_finished
}
trap cleanup EXIT
function skip() {
local msg=${1:-""}
ktap_test_skip "$msg"
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_config="$tmp_dir/kho.config"
local kconfig="$build_dir/.config"
# enable initrd, KHO and KHO test in kernel configuration
tee "$kconfig" > "$kho_config" <<EOF
CONFIG_BLK_DEV_INITRD=y
CONFIG_KEXEC_HANDOVER=y
CONFIG_TEST_KEXEC_HANDOVER=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_VM=y
$arch_kconfig
EOF
make_cmd="$make_cmd -C $kernel_dir O=$build_dir"
$make_cmd olddefconfig
# verify that kernel confiration has all necessary options
while read -r opt ; do
grep "$opt" "$kconfig" &>/dev/null || skip "$opt is missing"
done < "$kho_config"
$make_cmd "$kimage"
$make_cmd headers_install INSTALL_HDR_PATH="$headers_dir"
}
function mkinitrd() {
local kernel=$1
mkdir -p "$initrd_dir"/{dev,debugfs,proc}
sudo mknod "$initrd_dir/dev/console" c 5 1
"$CROSS_COMPILE"gcc -s -static -Os -nostdinc -I"$headers_dir/include" \
-fno-asynchronous-unwind-tables -fno-ident -nostdlib \
-include "$test_dir/../../../include/nolibc/nolibc.h" \
-o "$initrd_dir/init" "$test_dir/init.c" \
cp "$kernel" "$initrd_dir/kernel"
pushd "$initrd_dir" &>/dev/null
find . | cpio -H newc --create > "$initrd" 2>/dev/null
popd &>/dev/null
}
function run_qemu() {
local qemu_cmd=$1
local cmdline=$2
local kernel=$3
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"
}
function target_to_arch() {
local target=$1
case $target in
aarch64) echo "arm64" ;;
x86_64) echo "x86" ;;
*) skip "architecture $target is not supported"
esac
}
function main() {
local build_dir="$kernel_dir/.kho"
local jobs=$(($(nproc) * 2))
local target="$(uname -m)"
# skip the test if any of the preparation steps fails
set -o errtrace
trap skip ERR
while getopts 'hd:j:t:' opt; do
case $opt in
d)
build_dir="$OPTARG"
;;
j)
jobs="$OPTARG"
;;
t)
target="$OPTARG"
;;
h)
usage
exit 0
;;
*)
echo Unknown argument "$opt"
usage
exit 1
;;
esac
done
ktap_print_header
ktap_set_plan 1
if [[ "$target" != "$(uname -m)" ]] && [[ -z "$CROSS_COMPILE" ]]; then
skip "Cross-platform testing needs to specify CROSS_COMPILE"
fi
mkdir -p "$build_dir"
local arch=$(target_to_arch "$target")
source "$test_dir/$arch.conf"
# build the kernel and create initrd
# 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"
local kernel="$build_dir/arch/$arch/boot/$KERNEL_IMAGE"
mkinitrd "$kernel"
run_qemu "$QEMU_CMD" "$KERNEL_CMDLINE" "$kernel"
ktap_test_pass "KHO succeeded"
}
main "$@"