#!/bin/bash # SPDX-License-Identifier: GPL-2.0 set -ue CROSS_COMPILE="${CROSS_COMPILE:-""}" test_dir=$(realpath "$(dirname "$0")") kernel_dir=$(realpath "$test_dir/../../../..") workspace_dir="" headers_dir="" initrd="" KEEP_WORKSPACE=0 source "$test_dir/../kselftest/ktap_helpers.sh" function get_arch_conf() { local arch=$1 if [[ "$arch" == "arm64" ]]; then QEMU_CMD="qemu-system-aarch64 -M virt -cpu max" KERNEL_IMAGE="Image" KERNEL_CMDLINE="console=ttyAMA0" elif [[ "$arch" == "x86" ]]; then QEMU_CMD="qemu-system-x86_64" KERNEL_IMAGE="bzImage" KERNEL_CMDLINE="console=ttyS0" else echo "Unsupported architecture: $arch" exit 1 fi } function usage() { cat <) -j) number of jobs for compilation -t) run test for target_arch (aarch64, x86_64) -T) test name to run (default: luo_kexec_simple) -w) custom workspace directory (default: creates temp dir) -k) keep workspace directory after successful test -h) display this help EOF } function cleanup() { if [ "$KEEP_WORKSPACE" -eq 1 ]; then echo "# Workspace preserved at: $workspace_dir" else rm -fr "$workspace_dir" fi ktap_finished } 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 detect_cross_compile() { local target=$1 local host=$(uname -m) [[ "$host" == "arm64" ]] && host="aarch64" [[ "$target" == "arm64" ]] && target="aarch64" if [[ "$host" == "$target" ]]; then CROSS_COMPILE="" return fi if [[ -n "$CROSS_COMPILE" ]]; then return fi local candidate="" case "$target" in aarch64) candidate="aarch64-linux-gnu-" ;; x86_64) candidate="x86_64-linux-gnu-" ;; *) skip "Auto-detection for target '$target' not supported. Please set CROSS_COMPILE manually." ;; esac if command -v "${candidate}gcc" &> /dev/null; then CROSS_COMPILE="$candidate" else skip "Compiler '${candidate}gcc' not found. Please install it (e.g., 'apt install gcc-aarch64-linux-gnu') or set CROSS_COMPILE." fi } function build_kernel() { local build_dir=$1 local make_cmd=$2 local kimage=$3 local target_arch=$4 local luo_config="$build_dir/luo.config" local kconfig="$build_dir/.config" local common_conf="$test_dir/config" local arch_conf="$test_dir/config.$target_arch" echo "# Building kernel in: $build_dir" cat "$arch_conf" "$common_conf" | tee "$kconfig" > "$luo_config" $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 < "$luo_config" $make_cmd "$kimage" $make_cmd headers_install INSTALL_HDR_PATH="$headers_dir" } function mkinitrd() { local build_dir=$1 local kernel_path=$2 local test_name=$3 # Compile the test binary and the init process "$CROSS_COMPILE"gcc -static -O2 -nostdinc -nostdlib \ -I "$headers_dir/include" \ -I "$kernel_dir/tools/include/nolibc" \ -I "$test_dir/lib/include" \ -o "$workspace_dir/test_binary" \ "$test_dir/$test_name.c" "$test_dir/lib/lu_utils.c" "$CROSS_COMPILE"gcc -s -static -Os -nostdinc -nostdlib \ -fno-asynchronous-unwind-tables -fno-ident \ -fno-stack-protector \ -I "$headers_dir/include" \ -I "$kernel_dir/tools/include/nolibc" \ -o "$workspace_dir/init" "$test_dir/init.c" cat > "$workspace_dir/cpio_list_inner" < "$workspace_dir/inner_initrd.cpio" cat > "$workspace_dir/cpio_list" < "$initrd" } function run_qemu() { local qemu_cmd=$1 local cmdline=$2 local kernel_path=$3 local serial="$workspace_dir/qemu.serial" cmdline="$cmdline liveupdate=on panic=-1" echo "# Serial Log: $serial" timeout 30s \ $qemu_cmd -m 1G -smp 2 -no-reboot -nographic -nodefaults \ -accel tcg -accel hvf -accel kvm \ -serial file:"$serial" \ -append "$cmdline" \ -kernel "$kernel_path" \ -initrd "$initrd" grep "TEST PASSED" "$serial" &> /dev/null || fail "Liveupdate 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="" local jobs=$(nproc) local target="$(uname -m)" local test_name="luo_kexec_simple" local workspace_arg="" set -o errtrace trap fail ERR while getopts 'hd:j:t:T:w:k' opt; do case $opt in d) build_dir="$OPTARG" ;; j) jobs="$OPTARG" ;; t) target="$OPTARG" ;; T) test_name="$OPTARG" ;; w) workspace_arg="$OPTARG" ;; k) KEEP_WORKSPACE=1 ;; h) usage; exit 0 ;; *) echo "Unknown argument $opt"; usage; exit 1 ;; esac done ktap_print_header ktap_set_plan 1 trap cleanup EXIT if [ -n "$workspace_arg" ]; then workspace_dir="$(realpath -m "$workspace_arg")" mkdir -p "$workspace_dir" else workspace_dir=$(mktemp -d /tmp/luo-test.XXXXXXXX) fi echo "# Workspace created at: $workspace_dir" headers_dir="$workspace_dir/usr" initrd="$workspace_dir/initrd.cpio" detect_cross_compile "$target" local arch=$(target_to_arch "$target") if [ -z "$build_dir" ]; then build_dir="$kernel_dir/.luo_test_build.$arch" fi mkdir -p "$build_dir" build_dir=$(realpath "$build_dir") get_arch_conf "$arch" local make_cmd="make -s ARCH=$arch CROSS_COMPILE=$CROSS_COMPILE -j$jobs" local make_cmd_build="$make_cmd -C $kernel_dir O=$build_dir" build_kernel "$build_dir" "$make_cmd_build" "$KERNEL_IMAGE" "$target" local final_kernel="$build_dir/arch/$arch/boot/$KERNEL_IMAGE" mkinitrd "$build_dir" "$final_kernel" "$test_name" run_qemu "$QEMU_CMD" "$KERNEL_CMDLINE" "$final_kernel" ktap_test_pass "$test_name succeeded" } main "$@"