summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/kho/vmtest.sh
blob: ec70a17bd476ce863f4fd42548e64c7b69277cf4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#!/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 "$@"