1507806e9SBenjamin Tissoires#!/bin/bash
2507806e9SBenjamin Tissoires# SPDX-License-Identifier: GPL-2.0
3507806e9SBenjamin Tissoires
4507806e9SBenjamin Tissoiresset -u
5507806e9SBenjamin Tissoiresset -e
6507806e9SBenjamin Tissoires
7507806e9SBenjamin Tissoires# This script currently only works for x86_64
8507806e9SBenjamin TissoiresARCH="$(uname -m)"
9507806e9SBenjamin Tissoirescase "${ARCH}" in
10507806e9SBenjamin Tissoiresx86_64)
11507806e9SBenjamin Tissoires	QEMU_BINARY=qemu-system-x86_64
12507806e9SBenjamin Tissoires	BZIMAGE="arch/x86/boot/bzImage"
13507806e9SBenjamin Tissoires	;;
14507806e9SBenjamin Tissoires*)
15507806e9SBenjamin Tissoires	echo "Unsupported architecture"
16507806e9SBenjamin Tissoires	exit 1
17507806e9SBenjamin Tissoires	;;
18507806e9SBenjamin Tissoiresesac
19507806e9SBenjamin TissoiresSCRIPT_DIR="$(dirname $(realpath $0))"
20507806e9SBenjamin TissoiresOUTPUT_DIR="$SCRIPT_DIR/results"
21507806e9SBenjamin TissoiresKCONFIG_REL_PATHS=("${SCRIPT_DIR}/config" "${SCRIPT_DIR}/config.common" "${SCRIPT_DIR}/config.${ARCH}")
22507806e9SBenjamin TissoiresB2C_URL="https://gitlab.freedesktop.org/mupuf/boot2container/-/raw/master/vm2c.py"
23507806e9SBenjamin TissoiresNUM_COMPILE_JOBS="$(nproc)"
24507806e9SBenjamin TissoiresLOG_FILE_BASE="$(date +"hid_selftests.%Y-%m-%d_%H-%M-%S")"
25507806e9SBenjamin TissoiresLOG_FILE="${LOG_FILE_BASE}.log"
26507806e9SBenjamin TissoiresEXIT_STATUS_FILE="${LOG_FILE_BASE}.exit_status"
277d0b3f10SBenjamin TissoiresCONTAINER_IMAGE="registry.freedesktop.org/libevdev/hid-tools/fedora/37:2023-02-17.1"
287d0b3f10SBenjamin Tissoires
297d0b3f10SBenjamin TissoiresTARGETS="${TARGETS:=$(basename ${SCRIPT_DIR})}"
30ffb85d5cSBenjamin TissoiresDEFAULT_COMMAND="pip3 install hid-tools; make -C tools/testing/selftests TARGETS=${TARGETS} run_tests"
31507806e9SBenjamin Tissoires
32507806e9SBenjamin Tissoiresusage()
33507806e9SBenjamin Tissoires{
34507806e9SBenjamin Tissoires	cat <<EOF
35507806e9SBenjamin TissoiresUsage: $0 [-i] [-s] [-d <output_dir>] -- [<command>]
36507806e9SBenjamin Tissoires
37507806e9SBenjamin Tissoires<command> is the command you would normally run when you are in
387d0b3f10SBenjamin Tissoiresthe source kernel direcory. e.g:
39507806e9SBenjamin Tissoires
407d0b3f10SBenjamin Tissoires	$0 -- ./tools/testing/selftests/hid/hid_bpf
41507806e9SBenjamin Tissoires
42507806e9SBenjamin TissoiresIf no command is specified and a debug shell (-s) is not requested,
43507806e9SBenjamin Tissoires"${DEFAULT_COMMAND}" will be run by default.
44507806e9SBenjamin Tissoires
45507806e9SBenjamin TissoiresIf you build your kernel using KBUILD_OUTPUT= or O= options, these
46507806e9SBenjamin Tissoirescan be passed as environment variables to the script:
47507806e9SBenjamin Tissoires
487d0b3f10SBenjamin Tissoires  O=<kernel_build_path> $0 -- ./tools/testing/selftests/hid/hid_bpf
49507806e9SBenjamin Tissoires
50507806e9SBenjamin Tissoiresor
51507806e9SBenjamin Tissoires
527d0b3f10SBenjamin Tissoires  KBUILD_OUTPUT=<kernel_build_path> $0 -- ./tools/testing/selftests/hid/hid_bpf
53507806e9SBenjamin Tissoires
54507806e9SBenjamin TissoiresOptions:
55507806e9SBenjamin Tissoires
56507806e9SBenjamin Tissoires	-u)		Update the boot2container script to a newer version.
57507806e9SBenjamin Tissoires	-d)		Update the output directory (default: ${OUTPUT_DIR})
58507806e9SBenjamin Tissoires	-j)		Number of jobs for compilation, similar to -j in make
59507806e9SBenjamin Tissoires			(default: ${NUM_COMPILE_JOBS})
60507806e9SBenjamin Tissoires	-s)		Instead of powering off the VM, start an interactive
61507806e9SBenjamin Tissoires			shell. If <command> is specified, the shell runs after
62507806e9SBenjamin Tissoires			the command finishes executing
63507806e9SBenjamin TissoiresEOF
64507806e9SBenjamin Tissoires}
65507806e9SBenjamin Tissoires
66507806e9SBenjamin Tissoiresdownload()
67507806e9SBenjamin Tissoires{
68507806e9SBenjamin Tissoires	local file="$1"
69507806e9SBenjamin Tissoires
70507806e9SBenjamin Tissoires	echo "Downloading $file..." >&2
71507806e9SBenjamin Tissoires	curl -Lsf "$file" -o "${@:2}"
72507806e9SBenjamin Tissoires}
73507806e9SBenjamin Tissoires
74507806e9SBenjamin Tissoiresrecompile_kernel()
75507806e9SBenjamin Tissoires{
76507806e9SBenjamin Tissoires	local kernel_checkout="$1"
77507806e9SBenjamin Tissoires	local make_command="$2"
78507806e9SBenjamin Tissoires
79507806e9SBenjamin Tissoires	cd "${kernel_checkout}"
80507806e9SBenjamin Tissoires
81507806e9SBenjamin Tissoires	${make_command} olddefconfig
82*f9abdcc6SBenjamin Tissoires	${make_command} headers
83507806e9SBenjamin Tissoires	${make_command}
84507806e9SBenjamin Tissoires}
85507806e9SBenjamin Tissoires
86507806e9SBenjamin Tissoiresupdate_selftests()
87507806e9SBenjamin Tissoires{
88507806e9SBenjamin Tissoires	local kernel_checkout="$1"
89507806e9SBenjamin Tissoires	local selftests_dir="${kernel_checkout}/tools/testing/selftests/hid"
90507806e9SBenjamin Tissoires
91507806e9SBenjamin Tissoires	cd "${selftests_dir}"
92507806e9SBenjamin Tissoires	${make_command}
93507806e9SBenjamin Tissoires}
94507806e9SBenjamin Tissoires
95507806e9SBenjamin Tissoiresrun_vm()
96507806e9SBenjamin Tissoires{
977d0b3f10SBenjamin Tissoires	local run_dir="$1"
987d0b3f10SBenjamin Tissoires	local b2c="$2"
997d0b3f10SBenjamin Tissoires	local kernel_bzimage="$3"
1007d0b3f10SBenjamin Tissoires	local command="$4"
101507806e9SBenjamin Tissoires	local post_command=""
102507806e9SBenjamin Tissoires
1037d0b3f10SBenjamin Tissoires	cd "${run_dir}"
1047d0b3f10SBenjamin Tissoires
105507806e9SBenjamin Tissoires	if ! which "${QEMU_BINARY}" &> /dev/null; then
106507806e9SBenjamin Tissoires		cat <<EOF
107507806e9SBenjamin TissoiresCould not find ${QEMU_BINARY}
108507806e9SBenjamin TissoiresPlease install qemu or set the QEMU_BINARY environment variable.
109507806e9SBenjamin TissoiresEOF
110507806e9SBenjamin Tissoires		exit 1
111507806e9SBenjamin Tissoires	fi
112507806e9SBenjamin Tissoires
113507806e9SBenjamin Tissoires	# alpine (used in post-container requires the PATH to have /bin
114507806e9SBenjamin Tissoires	export PATH=$PATH:/bin
115507806e9SBenjamin Tissoires
116507806e9SBenjamin Tissoires	if [[ "${debug_shell}" != "yes" ]]
117507806e9SBenjamin Tissoires	then
118507806e9SBenjamin Tissoires		touch ${OUTPUT_DIR}/${LOG_FILE}
119507806e9SBenjamin Tissoires		command="mount bpffs -t bpf /sys/fs/bpf/; set -o pipefail ; ${command} 2>&1 | tee ${OUTPUT_DIR}/${LOG_FILE}"
120507806e9SBenjamin Tissoires		post_command="cat ${OUTPUT_DIR}/${LOG_FILE}"
121507806e9SBenjamin Tissoires	else
122507806e9SBenjamin Tissoires		command="mount bpffs -t bpf /sys/fs/bpf/; ${command}"
123507806e9SBenjamin Tissoires	fi
124507806e9SBenjamin Tissoires
125507806e9SBenjamin Tissoires	set +e
126507806e9SBenjamin Tissoires	$b2c --command "${command}" \
127507806e9SBenjamin Tissoires	     --kernel ${kernel_bzimage} \
128507806e9SBenjamin Tissoires	     --workdir ${OUTPUT_DIR} \
129507806e9SBenjamin Tissoires	     --image ${CONTAINER_IMAGE}
130507806e9SBenjamin Tissoires
131507806e9SBenjamin Tissoires	echo $? > ${OUTPUT_DIR}/${EXIT_STATUS_FILE}
132507806e9SBenjamin Tissoires
133507806e9SBenjamin Tissoires	set -e
134507806e9SBenjamin Tissoires
135507806e9SBenjamin Tissoires	${post_command}
136507806e9SBenjamin Tissoires}
137507806e9SBenjamin Tissoires
138507806e9SBenjamin Tissoiresis_rel_path()
139507806e9SBenjamin Tissoires{
140507806e9SBenjamin Tissoires	local path="$1"
141507806e9SBenjamin Tissoires
142507806e9SBenjamin Tissoires	[[ ${path:0:1} != "/" ]]
143507806e9SBenjamin Tissoires}
144507806e9SBenjamin Tissoires
145507806e9SBenjamin Tissoiresdo_update_kconfig()
146507806e9SBenjamin Tissoires{
147507806e9SBenjamin Tissoires	local kernel_checkout="$1"
148507806e9SBenjamin Tissoires	local kconfig_file="$2"
149507806e9SBenjamin Tissoires
150507806e9SBenjamin Tissoires	rm -f "$kconfig_file" 2> /dev/null
151507806e9SBenjamin Tissoires
152507806e9SBenjamin Tissoires	for config in "${KCONFIG_REL_PATHS[@]}"; do
153507806e9SBenjamin Tissoires		local kconfig_src="${config}"
154507806e9SBenjamin Tissoires		cat "$kconfig_src" >> "$kconfig_file"
155507806e9SBenjamin Tissoires	done
156507806e9SBenjamin Tissoires}
157507806e9SBenjamin Tissoires
158507806e9SBenjamin Tissoiresupdate_kconfig()
159507806e9SBenjamin Tissoires{
160507806e9SBenjamin Tissoires	local kernel_checkout="$1"
161507806e9SBenjamin Tissoires	local kconfig_file="$2"
162507806e9SBenjamin Tissoires
163507806e9SBenjamin Tissoires	if [[ -f "${kconfig_file}" ]]; then
164507806e9SBenjamin Tissoires		local local_modified="$(stat -c %Y "${kconfig_file}")"
165507806e9SBenjamin Tissoires
166507806e9SBenjamin Tissoires		for config in "${KCONFIG_REL_PATHS[@]}"; do
167507806e9SBenjamin Tissoires			local kconfig_src="${config}"
168507806e9SBenjamin Tissoires			local src_modified="$(stat -c %Y "${kconfig_src}")"
169507806e9SBenjamin Tissoires			# Only update the config if it has been updated after the
170507806e9SBenjamin Tissoires			# previously cached config was created. This avoids
171507806e9SBenjamin Tissoires			# unnecessarily compiling the kernel and selftests.
172507806e9SBenjamin Tissoires			if [[ "${src_modified}" -gt "${local_modified}" ]]; then
173507806e9SBenjamin Tissoires				do_update_kconfig "$kernel_checkout" "$kconfig_file"
174507806e9SBenjamin Tissoires				# Once we have found one outdated configuration
175507806e9SBenjamin Tissoires				# there is no need to check other ones.
176507806e9SBenjamin Tissoires				break
177507806e9SBenjamin Tissoires			fi
178507806e9SBenjamin Tissoires		done
179507806e9SBenjamin Tissoires	else
180507806e9SBenjamin Tissoires		do_update_kconfig "$kernel_checkout" "$kconfig_file"
181507806e9SBenjamin Tissoires	fi
182507806e9SBenjamin Tissoires}
183507806e9SBenjamin Tissoires
184507806e9SBenjamin Tissoiresmain()
185507806e9SBenjamin Tissoires{
186507806e9SBenjamin Tissoires	local script_dir="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
187507806e9SBenjamin Tissoires	local kernel_checkout=$(realpath "${script_dir}"/../../../../)
188507806e9SBenjamin Tissoires	# By default the script searches for the kernel in the checkout directory but
189507806e9SBenjamin Tissoires	# it also obeys environment variables O= and KBUILD_OUTPUT=
190507806e9SBenjamin Tissoires	local kernel_bzimage="${kernel_checkout}/${BZIMAGE}"
191507806e9SBenjamin Tissoires	local command="${DEFAULT_COMMAND}"
192507806e9SBenjamin Tissoires	local update_b2c="no"
193507806e9SBenjamin Tissoires	local debug_shell="no"
194507806e9SBenjamin Tissoires
195507806e9SBenjamin Tissoires	while getopts ':hsud:j:' opt; do
196507806e9SBenjamin Tissoires		case ${opt} in
197507806e9SBenjamin Tissoires		u)
198507806e9SBenjamin Tissoires			update_b2c="yes"
199507806e9SBenjamin Tissoires			;;
200507806e9SBenjamin Tissoires		d)
201507806e9SBenjamin Tissoires			OUTPUT_DIR="$OPTARG"
202507806e9SBenjamin Tissoires			;;
203507806e9SBenjamin Tissoires		j)
204507806e9SBenjamin Tissoires			NUM_COMPILE_JOBS="$OPTARG"
205507806e9SBenjamin Tissoires			;;
206507806e9SBenjamin Tissoires		s)
207507806e9SBenjamin Tissoires			command="/bin/sh"
208507806e9SBenjamin Tissoires			debug_shell="yes"
209507806e9SBenjamin Tissoires			;;
210507806e9SBenjamin Tissoires		h)
211507806e9SBenjamin Tissoires			usage
212507806e9SBenjamin Tissoires			exit 0
213507806e9SBenjamin Tissoires			;;
214507806e9SBenjamin Tissoires		\? )
215507806e9SBenjamin Tissoires			echo "Invalid Option: -$OPTARG"
216507806e9SBenjamin Tissoires			usage
217507806e9SBenjamin Tissoires			exit 1
218507806e9SBenjamin Tissoires			;;
219507806e9SBenjamin Tissoires		: )
220507806e9SBenjamin Tissoires			echo "Invalid Option: -$OPTARG requires an argument"
221507806e9SBenjamin Tissoires			usage
222507806e9SBenjamin Tissoires			exit 1
223507806e9SBenjamin Tissoires			;;
224507806e9SBenjamin Tissoires		esac
225507806e9SBenjamin Tissoires	done
226507806e9SBenjamin Tissoires	shift $((OPTIND -1))
227507806e9SBenjamin Tissoires
228507806e9SBenjamin Tissoires	# trap 'catch "$?"' EXIT
229507806e9SBenjamin Tissoires
230507806e9SBenjamin Tissoires	if [[ "${debug_shell}" == "no" ]]; then
231507806e9SBenjamin Tissoires		if [[ $# -eq 0 ]]; then
232507806e9SBenjamin Tissoires			echo "No command specified, will run ${DEFAULT_COMMAND} in the vm"
233507806e9SBenjamin Tissoires		else
234507806e9SBenjamin Tissoires			command="$@"
235507806e9SBenjamin Tissoires
236507806e9SBenjamin Tissoires			if [[ "${command}" == "/bin/bash" || "${command}" == "bash" ]]
237507806e9SBenjamin Tissoires			then
238507806e9SBenjamin Tissoires				debug_shell="yes"
239507806e9SBenjamin Tissoires			fi
240507806e9SBenjamin Tissoires		fi
241507806e9SBenjamin Tissoires	fi
242507806e9SBenjamin Tissoires
243507806e9SBenjamin Tissoires	local kconfig_file="${OUTPUT_DIR}/latest.config"
244507806e9SBenjamin Tissoires	local make_command="make -j ${NUM_COMPILE_JOBS} KCONFIG_CONFIG=${kconfig_file}"
245507806e9SBenjamin Tissoires
246507806e9SBenjamin Tissoires	# Figure out where the kernel is being built.
247507806e9SBenjamin Tissoires	# O takes precedence over KBUILD_OUTPUT.
248507806e9SBenjamin Tissoires	if [[ "${O:=""}" != "" ]]; then
249507806e9SBenjamin Tissoires		if is_rel_path "${O}"; then
250507806e9SBenjamin Tissoires			O="$(realpath "${PWD}/${O}")"
251507806e9SBenjamin Tissoires		fi
252507806e9SBenjamin Tissoires		kernel_bzimage="${O}/${BZIMAGE}"
253507806e9SBenjamin Tissoires		make_command="${make_command} O=${O}"
254507806e9SBenjamin Tissoires	elif [[ "${KBUILD_OUTPUT:=""}" != "" ]]; then
255507806e9SBenjamin Tissoires		if is_rel_path "${KBUILD_OUTPUT}"; then
256507806e9SBenjamin Tissoires			KBUILD_OUTPUT="$(realpath "${PWD}/${KBUILD_OUTPUT}")"
257507806e9SBenjamin Tissoires		fi
258507806e9SBenjamin Tissoires		kernel_bzimage="${KBUILD_OUTPUT}/${BZIMAGE}"
259507806e9SBenjamin Tissoires		make_command="${make_command} KBUILD_OUTPUT=${KBUILD_OUTPUT}"
260507806e9SBenjamin Tissoires	fi
261507806e9SBenjamin Tissoires
262507806e9SBenjamin Tissoires	local b2c="${OUTPUT_DIR}/vm2c.py"
263507806e9SBenjamin Tissoires
264507806e9SBenjamin Tissoires	echo "Output directory: ${OUTPUT_DIR}"
265507806e9SBenjamin Tissoires
266507806e9SBenjamin Tissoires	mkdir -p "${OUTPUT_DIR}"
267507806e9SBenjamin Tissoires	update_kconfig "${kernel_checkout}" "${kconfig_file}"
268507806e9SBenjamin Tissoires
269507806e9SBenjamin Tissoires	recompile_kernel "${kernel_checkout}" "${make_command}"
270507806e9SBenjamin Tissoires
271507806e9SBenjamin Tissoires	if [[ "${update_b2c}" == "no" && ! -f "${b2c}" ]]; then
272507806e9SBenjamin Tissoires		echo "vm2c script not found in ${b2c}"
273507806e9SBenjamin Tissoires		update_b2c="yes"
274507806e9SBenjamin Tissoires	fi
275507806e9SBenjamin Tissoires
276507806e9SBenjamin Tissoires	if [[ "${update_b2c}" == "yes" ]]; then
277507806e9SBenjamin Tissoires		download $B2C_URL $b2c
278507806e9SBenjamin Tissoires		chmod +x $b2c
279507806e9SBenjamin Tissoires	fi
280507806e9SBenjamin Tissoires
281507806e9SBenjamin Tissoires	update_selftests "${kernel_checkout}" "${make_command}"
2827d0b3f10SBenjamin Tissoires	run_vm "${kernel_checkout}" $b2c "${kernel_bzimage}" "${command}"
283507806e9SBenjamin Tissoires	if [[ "${debug_shell}" != "yes" ]]; then
284507806e9SBenjamin Tissoires		echo "Logs saved in ${OUTPUT_DIR}/${LOG_FILE}"
285507806e9SBenjamin Tissoires	fi
286507806e9SBenjamin Tissoires
287507806e9SBenjamin Tissoires	exit $(cat ${OUTPUT_DIR}/${EXIT_STATUS_FILE})
288507806e9SBenjamin Tissoires}
289507806e9SBenjamin Tissoires
290507806e9SBenjamin Tissoiresmain "$@"
291