1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4set -ue 5 6CROSS_COMPILE="${CROSS_COMPILE:-""}" 7 8test_dir=$(realpath "$(dirname "$0")") 9kernel_dir=$(realpath "$test_dir/../../../..") 10 11workspace_dir="" 12headers_dir="" 13initrd="" 14KEEP_WORKSPACE=0 15 16source "$test_dir/../kselftest/ktap_helpers.sh" 17 18function get_arch_conf() { 19 local arch=$1 20 if [[ "$arch" == "arm64" ]]; then 21 QEMU_CMD="qemu-system-aarch64 -M virt -cpu max" 22 KERNEL_IMAGE="Image" 23 KERNEL_CMDLINE="console=ttyAMA0" 24 elif [[ "$arch" == "x86" ]]; then 25 QEMU_CMD="qemu-system-x86_64" 26 KERNEL_IMAGE="bzImage" 27 KERNEL_CMDLINE="console=ttyS0" 28 else 29 echo "Unsupported architecture: $arch" 30 exit 1 31 fi 32} 33 34function usage() { 35 cat <<EOF 36$0 [-d build_dir] [-j jobs] [-t target_arch] [-T test_name] [-w workspace_dir] [-k] [-h] 37Options: 38 -d) path to the kernel build directory (default: .luo_test_build.<arch>) 39 -j) number of jobs for compilation 40 -t) run test for target_arch (aarch64, x86_64) 41 -T) test name to run (default: luo_kexec_simple) 42 -w) custom workspace directory (default: creates temp dir) 43 -k) keep workspace directory after successful test 44 -h) display this help 45EOF 46} 47 48function cleanup() { 49 if [ "$KEEP_WORKSPACE" -eq 1 ]; then 50 echo "# Workspace preserved at: $workspace_dir" 51 else 52 rm -fr "$workspace_dir" 53 fi 54 55 ktap_finished 56} 57 58function skip() { 59 local msg=${1:-""} 60 ktap_test_skip "$msg" 61 exit "$KSFT_SKIP" 62} 63 64function fail() { 65 local msg=${1:-""} 66 ktap_test_fail "$msg" 67 exit "$KSFT_FAIL" 68} 69 70function detect_cross_compile() { 71 local target=$1 72 local host=$(uname -m) 73 74 [[ "$host" == "arm64" ]] && host="aarch64" 75 [[ "$target" == "arm64" ]] && target="aarch64" 76 77 if [[ "$host" == "$target" ]]; then 78 CROSS_COMPILE="" 79 return 80 fi 81 82 if [[ -n "$CROSS_COMPILE" ]]; then 83 return 84 fi 85 86 local candidate="" 87 case "$target" in 88 aarch64) candidate="aarch64-linux-gnu-" ;; 89 x86_64) candidate="x86_64-linux-gnu-" ;; 90 *) skip "Auto-detection for target '$target' not supported. Please set CROSS_COMPILE manually." ;; 91 esac 92 93 if command -v "${candidate}gcc" &> /dev/null; then 94 CROSS_COMPILE="$candidate" 95 else 96 skip "Compiler '${candidate}gcc' not found. Please install it (e.g., 'apt install gcc-aarch64-linux-gnu') or set CROSS_COMPILE." 97 fi 98} 99 100function build_kernel() { 101 local build_dir=$1 102 local make_cmd=$2 103 local kimage=$3 104 local target_arch=$4 105 106 local luo_config="$build_dir/luo.config" 107 local kconfig="$build_dir/.config" 108 local common_conf="$test_dir/config" 109 local arch_conf="$test_dir/config.$target_arch" 110 111 echo "# Building kernel in: $build_dir" 112 113 cat "$arch_conf" "$common_conf" | tee "$kconfig" > "$luo_config" 114 $make_cmd olddefconfig 115 116 # verify that kernel confiration has all necessary options 117 while read -r opt ; do 118 grep "$opt" "$kconfig" &>/dev/null || skip "$opt is missing" 119 done < "$luo_config" 120 121 $make_cmd "$kimage" 122 $make_cmd headers_install INSTALL_HDR_PATH="$headers_dir" 123} 124 125function mkinitrd() { 126 local build_dir=$1 127 local kernel_path=$2 128 local test_name=$3 129 130 # Compile the test binary and the init process 131 "$CROSS_COMPILE"gcc -static -O2 -nostdinc -nostdlib \ 132 -I "$headers_dir/include" \ 133 -I "$kernel_dir/tools/include/nolibc" \ 134 -I "$test_dir" \ 135 -o "$workspace_dir/test_binary" \ 136 "$test_dir/$test_name.c" "$test_dir/luo_test_utils.c" 137 138 "$CROSS_COMPILE"gcc -s -static -Os -nostdinc -nostdlib \ 139 -fno-asynchronous-unwind-tables -fno-ident \ 140 -fno-stack-protector \ 141 -I "$headers_dir/include" \ 142 -I "$kernel_dir/tools/include/nolibc" \ 143 -o "$workspace_dir/init" "$test_dir/init.c" 144 145 cat > "$workspace_dir/cpio_list_inner" <<EOF 146dir /dev 0755 0 0 147dir /proc 0755 0 0 148dir /debugfs 0755 0 0 149nod /dev/console 0600 0 0 c 5 1 150file /init $workspace_dir/init 0755 0 0 151file /test_binary $workspace_dir/test_binary 0755 0 0 152EOF 153 154 # Generate inner_initrd.cpio 155 "$build_dir/usr/gen_init_cpio" "$workspace_dir/cpio_list_inner" > "$workspace_dir/inner_initrd.cpio" 156 157 cat > "$workspace_dir/cpio_list" <<EOF 158dir /dev 0755 0 0 159dir /proc 0755 0 0 160dir /debugfs 0755 0 0 161nod /dev/console 0600 0 0 c 5 1 162file /init $workspace_dir/init 0755 0 0 163file /kernel $kernel_path 0644 0 0 164file /test_binary $workspace_dir/test_binary 0755 0 0 165file /initrd.img $workspace_dir/inner_initrd.cpio 0644 0 0 166EOF 167 168 # Generate the final initrd 169 "$build_dir/usr/gen_init_cpio" "$workspace_dir/cpio_list" > "$initrd" 170} 171 172function run_qemu() { 173 local qemu_cmd=$1 174 local cmdline=$2 175 local kernel_path=$3 176 local serial="$workspace_dir/qemu.serial" 177 178 cmdline="$cmdline liveupdate=on panic=-1" 179 180 echo "# Serial Log: $serial" 181 timeout 30s \ 182 $qemu_cmd -m 1G -smp 2 -no-reboot -nographic -nodefaults \ 183 -accel tcg -accel hvf -accel kvm \ 184 -serial file:"$serial" \ 185 -append "$cmdline" \ 186 -kernel "$kernel_path" \ 187 -initrd "$initrd" 188 189 grep "TEST PASSED" "$serial" &> /dev/null || fail "Liveupdate failed" 190} 191 192function target_to_arch() { 193 local target=$1 194 case $target in 195 aarch64) echo "arm64" ;; 196 x86_64) echo "x86" ;; 197 *) skip "architecture $target is not supported" 198 esac 199} 200 201function main() { 202 local build_dir="" 203 local jobs=$(nproc) 204 local target="$(uname -m)" 205 local test_name="luo_kexec_simple" 206 local workspace_arg="" 207 208 set -o errtrace 209 trap fail ERR 210 211 while getopts 'hd:j:t:T:w:k' opt; do 212 case $opt in 213 d) build_dir="$OPTARG" ;; 214 j) jobs="$OPTARG" ;; 215 t) target="$OPTARG" ;; 216 T) test_name="$OPTARG" ;; 217 w) workspace_arg="$OPTARG" ;; 218 k) KEEP_WORKSPACE=1 ;; 219 h) usage; exit 0 ;; 220 *) echo "Unknown argument $opt"; usage; exit 1 ;; 221 esac 222 done 223 224 ktap_print_header 225 ktap_set_plan 1 226 trap cleanup EXIT 227 228 if [ -n "$workspace_arg" ]; then 229 workspace_dir="$(realpath -m "$workspace_arg")" 230 mkdir -p "$workspace_dir" 231 else 232 workspace_dir=$(mktemp -d /tmp/luo-test.XXXXXXXX) 233 fi 234 235 echo "# Workspace created at: $workspace_dir" 236 headers_dir="$workspace_dir/usr" 237 initrd="$workspace_dir/initrd.cpio" 238 239 detect_cross_compile "$target" 240 241 local arch=$(target_to_arch "$target") 242 243 if [ -z "$build_dir" ]; then 244 build_dir="$kernel_dir/.luo_test_build.$arch" 245 fi 246 247 mkdir -p "$build_dir" 248 build_dir=$(realpath "$build_dir") 249 get_arch_conf "$arch" 250 251 local make_cmd="make -s ARCH=$arch CROSS_COMPILE=$CROSS_COMPILE -j$jobs" 252 local make_cmd_build="$make_cmd -C $kernel_dir O=$build_dir" 253 254 build_kernel "$build_dir" "$make_cmd_build" "$KERNEL_IMAGE" "$target" 255 256 local final_kernel="$build_dir/arch/$arch/boot/$KERNEL_IMAGE" 257 mkinitrd "$build_dir" "$final_kernel" "$test_name" 258 259 run_qemu "$QEMU_CMD" "$KERNEL_CMDLINE" "$final_kernel" 260 ktap_test_pass "$test_name succeeded" 261} 262 263main "$@" 264