mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-21 06:50:25 +00:00

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>
183 lines
3.8 KiB
Bash
Executable file
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 "$@"
|