| #!/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="$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_KEXEC_HANDOVER_DEBUG=y | |
| CONFIG_KEXEC_HANDOVER_DEBUGFS=y | |
| CONFIG_TEST_KEXEC_HANDOVER=y | |
| CONFIG_DEBUG_KERNEL=y | |
| CONFIG_DEBUG_VM=y | |
| CONFIG_DEBUG_VM_PGFLAGS=y | |
| CONFIG_SMP=y | |
| CONFIG_DEFERRED_STRUCT_PAGE_INIT=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 | |
| "$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" | |
| 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" | |
| } | |
| 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 "$@" |