162306a36Sopenharmony_ci#!/bin/bash
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci# Library of helpers for test scripts.
562306a36Sopenharmony_ciset -e
662306a36Sopenharmony_ci
762306a36Sopenharmony_ciDIR=/sys/devices/virtual/misc/test_firmware
862306a36Sopenharmony_ci
962306a36Sopenharmony_ciPROC_CONFIG="/proc/config.gz"
1062306a36Sopenharmony_ciTEST_DIR=$(dirname $0)
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci# We need to load a different file to test request_firmware_into_buf
1362306a36Sopenharmony_ci# I believe the issue is firmware loaded cached vs. non-cached
1462306a36Sopenharmony_ci# with same filename is bungled.
1562306a36Sopenharmony_ci# To reproduce rename this to test-firmware.bin
1662306a36Sopenharmony_ciTEST_FIRMWARE_INTO_BUF_FILENAME=test-firmware-into-buf.bin
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci# Kselftest framework requirement - SKIP code is 4.
1962306a36Sopenharmony_ciksft_skip=4
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciprint_reqs_exit()
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	echo "You must have the following enabled in your kernel:" >&2
2462306a36Sopenharmony_ci	cat $TEST_DIR/config >&2
2562306a36Sopenharmony_ci	exit $ksft_skip
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_citest_modprobe()
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	if [ ! -d $DIR ]; then
3162306a36Sopenharmony_ci		print_reqs_exit
3262306a36Sopenharmony_ci	fi
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cicheck_mods()
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	local uid=$(id -u)
3862306a36Sopenharmony_ci	if [ $uid -ne 0 ]; then
3962306a36Sopenharmony_ci		echo "skip all tests: must be run as root" >&2
4062306a36Sopenharmony_ci		exit $ksft_skip
4162306a36Sopenharmony_ci	fi
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	trap "test_modprobe" EXIT
4462306a36Sopenharmony_ci	if [ ! -d $DIR ]; then
4562306a36Sopenharmony_ci		modprobe test_firmware
4662306a36Sopenharmony_ci	fi
4762306a36Sopenharmony_ci	if [ ! -f $PROC_CONFIG ]; then
4862306a36Sopenharmony_ci		if modprobe configs 2>/dev/null; then
4962306a36Sopenharmony_ci			echo "Loaded configs module"
5062306a36Sopenharmony_ci			if [ ! -f $PROC_CONFIG ]; then
5162306a36Sopenharmony_ci				echo "You must have the following enabled in your kernel:" >&2
5262306a36Sopenharmony_ci				cat $TEST_DIR/config >&2
5362306a36Sopenharmony_ci				echo "Resorting to old heuristics" >&2
5462306a36Sopenharmony_ci			fi
5562306a36Sopenharmony_ci		else
5662306a36Sopenharmony_ci			echo "Failed to load configs module, using old heuristics" >&2
5762306a36Sopenharmony_ci		fi
5862306a36Sopenharmony_ci	fi
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cicheck_setup()
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	HAS_FW_LOADER_USER_HELPER="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER=y)"
6462306a36Sopenharmony_ci	HAS_FW_LOADER_USER_HELPER_FALLBACK="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y)"
6562306a36Sopenharmony_ci	HAS_FW_LOADER_COMPRESS_XZ="$(kconfig_has CONFIG_FW_LOADER_COMPRESS_XZ=y)"
6662306a36Sopenharmony_ci	HAS_FW_LOADER_COMPRESS_ZSTD="$(kconfig_has CONFIG_FW_LOADER_COMPRESS_ZSTD=y)"
6762306a36Sopenharmony_ci	HAS_FW_UPLOAD="$(kconfig_has CONFIG_FW_UPLOAD=y)"
6862306a36Sopenharmony_ci	PROC_FW_IGNORE_SYSFS_FALLBACK="0"
6962306a36Sopenharmony_ci	PROC_FW_FORCE_SYSFS_FALLBACK="0"
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if [ -z $PROC_SYS_DIR ]; then
7262306a36Sopenharmony_ci		PROC_SYS_DIR="/proc/sys/kernel"
7362306a36Sopenharmony_ci	fi
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	FW_PROC="${PROC_SYS_DIR}/firmware_config"
7662306a36Sopenharmony_ci	FW_FORCE_SYSFS_FALLBACK="$FW_PROC/force_sysfs_fallback"
7762306a36Sopenharmony_ci	FW_IGNORE_SYSFS_FALLBACK="$FW_PROC/ignore_sysfs_fallback"
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then
8062306a36Sopenharmony_ci		PROC_FW_FORCE_SYSFS_FALLBACK="$(cat $FW_FORCE_SYSFS_FALLBACK)"
8162306a36Sopenharmony_ci	fi
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if [ -f $FW_IGNORE_SYSFS_FALLBACK ]; then
8462306a36Sopenharmony_ci		PROC_FW_IGNORE_SYSFS_FALLBACK="$(cat $FW_IGNORE_SYSFS_FALLBACK)"
8562306a36Sopenharmony_ci	fi
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if [ "$PROC_FW_FORCE_SYSFS_FALLBACK" = "1" ]; then
8862306a36Sopenharmony_ci		HAS_FW_LOADER_USER_HELPER="yes"
8962306a36Sopenharmony_ci		HAS_FW_LOADER_USER_HELPER_FALLBACK="yes"
9062306a36Sopenharmony_ci	fi
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if [ "$PROC_FW_IGNORE_SYSFS_FALLBACK" = "1" ]; then
9362306a36Sopenharmony_ci		HAS_FW_LOADER_USER_HELPER_FALLBACK="no"
9462306a36Sopenharmony_ci		HAS_FW_LOADER_USER_HELPER="no"
9562306a36Sopenharmony_ci	fi
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
9862306a36Sopenharmony_ci	       OLD_TIMEOUT="$(cat /sys/class/firmware/timeout)"
9962306a36Sopenharmony_ci	fi
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	OLD_FWPATH="$(cat /sys/module/firmware_class/parameters/path)"
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if [ "$HAS_FW_LOADER_COMPRESS_XZ" = "yes" ]; then
10462306a36Sopenharmony_ci		if ! which xz 2> /dev/null > /dev/null; then
10562306a36Sopenharmony_ci			HAS_FW_LOADER_COMPRESS_XZ=""
10662306a36Sopenharmony_ci		fi
10762306a36Sopenharmony_ci	fi
10862306a36Sopenharmony_ci	if [ "$HAS_FW_LOADER_COMPRESS_ZSTD" = "yes" ]; then
10962306a36Sopenharmony_ci		if ! which zstd 2> /dev/null > /dev/null; then
11062306a36Sopenharmony_ci			HAS_FW_LOADER_COMPRESS_ZSTD=""
11162306a36Sopenharmony_ci		fi
11262306a36Sopenharmony_ci	fi
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_civerify_reqs()
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	if [ "$TEST_REQS_FW_SYSFS_FALLBACK" = "yes" ]; then
11862306a36Sopenharmony_ci		if [ ! "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
11962306a36Sopenharmony_ci			echo "usermode helper disabled so ignoring test"
12062306a36Sopenharmony_ci			exit 0
12162306a36Sopenharmony_ci		fi
12262306a36Sopenharmony_ci	fi
12362306a36Sopenharmony_ci	if [ "$TEST_REQS_FW_UPLOAD" = "yes" ]; then
12462306a36Sopenharmony_ci		if [ ! "$HAS_FW_UPLOAD" = "yes" ]; then
12562306a36Sopenharmony_ci			echo "firmware upload disabled so ignoring test"
12662306a36Sopenharmony_ci			exit 0
12762306a36Sopenharmony_ci		fi
12862306a36Sopenharmony_ci	fi
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cisetup_tmp_file()
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	FWPATH=$(mktemp -d)
13462306a36Sopenharmony_ci	FW="$FWPATH/test-firmware.bin"
13562306a36Sopenharmony_ci	echo "ABCD0123" >"$FW"
13662306a36Sopenharmony_ci	FW_INTO_BUF="$FWPATH/$TEST_FIRMWARE_INTO_BUF_FILENAME"
13762306a36Sopenharmony_ci	echo "EFGH4567" >"$FW_INTO_BUF"
13862306a36Sopenharmony_ci	NAME=$(basename "$FW")
13962306a36Sopenharmony_ci	if [ "$TEST_REQS_FW_SET_CUSTOM_PATH" = "yes" ]; then
14062306a36Sopenharmony_ci		echo -n "$FWPATH" >/sys/module/firmware_class/parameters/path
14162306a36Sopenharmony_ci	fi
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci__setup_random_file()
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	RANDOM_FILE_PATH="$(mktemp -p $FWPATH)"
14762306a36Sopenharmony_ci	# mktemp says dry-run -n is unsafe, so...
14862306a36Sopenharmony_ci	if [[ "$1" = "fake" ]]; then
14962306a36Sopenharmony_ci		rm -rf $RANDOM_FILE_PATH
15062306a36Sopenharmony_ci		sync
15162306a36Sopenharmony_ci	else
15262306a36Sopenharmony_ci		echo "ABCD0123" >"$RANDOM_FILE_PATH"
15362306a36Sopenharmony_ci	fi
15462306a36Sopenharmony_ci	echo $RANDOM_FILE_PATH
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cisetup_random_file()
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	echo $(__setup_random_file)
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cisetup_random_file_fake()
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	echo $(__setup_random_file fake)
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ciproc_set_force_sysfs_fallback()
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then
17062306a36Sopenharmony_ci		echo -n $1 > $FW_FORCE_SYSFS_FALLBACK
17162306a36Sopenharmony_ci		check_setup
17262306a36Sopenharmony_ci	fi
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ciproc_set_ignore_sysfs_fallback()
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	if [ -f $FW_IGNORE_SYSFS_FALLBACK ]; then
17862306a36Sopenharmony_ci		echo -n $1 > $FW_IGNORE_SYSFS_FALLBACK
17962306a36Sopenharmony_ci		check_setup
18062306a36Sopenharmony_ci	fi
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ciproc_restore_defaults()
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	proc_set_force_sysfs_fallback 0
18662306a36Sopenharmony_ci	proc_set_ignore_sysfs_fallback 0
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_citest_finish()
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
19262306a36Sopenharmony_ci		echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout
19362306a36Sopenharmony_ci	fi
19462306a36Sopenharmony_ci	if [ "$TEST_REQS_FW_SET_CUSTOM_PATH" = "yes" ]; then
19562306a36Sopenharmony_ci		if [ "$OLD_FWPATH" = "" ]; then
19662306a36Sopenharmony_ci			# A zero-length write won't work; write a null byte
19762306a36Sopenharmony_ci			printf '\000' >/sys/module/firmware_class/parameters/path
19862306a36Sopenharmony_ci		else
19962306a36Sopenharmony_ci			echo -n "$OLD_FWPATH" >/sys/module/firmware_class/parameters/path
20062306a36Sopenharmony_ci		fi
20162306a36Sopenharmony_ci	fi
20262306a36Sopenharmony_ci	if [ -f $FW ]; then
20362306a36Sopenharmony_ci		rm -f "$FW"
20462306a36Sopenharmony_ci	fi
20562306a36Sopenharmony_ci	if [ -f $FW_INTO_BUF ]; then
20662306a36Sopenharmony_ci		rm -f "$FW_INTO_BUF"
20762306a36Sopenharmony_ci	fi
20862306a36Sopenharmony_ci	if [ -d $FWPATH ]; then
20962306a36Sopenharmony_ci		rm -rf "$FWPATH"
21062306a36Sopenharmony_ci	fi
21162306a36Sopenharmony_ci	proc_restore_defaults
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cikconfig_has()
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	if [ -f $PROC_CONFIG ]; then
21762306a36Sopenharmony_ci		if zgrep -q $1 $PROC_CONFIG 2>/dev/null; then
21862306a36Sopenharmony_ci			echo "yes"
21962306a36Sopenharmony_ci		else
22062306a36Sopenharmony_ci			echo "no"
22162306a36Sopenharmony_ci		fi
22262306a36Sopenharmony_ci	else
22362306a36Sopenharmony_ci		# We currently don't have easy heuristics to infer this
22462306a36Sopenharmony_ci		# so best we can do is just try to use the kernel assuming
22562306a36Sopenharmony_ci		# you had enabled it. This matches the old behaviour.
22662306a36Sopenharmony_ci		if [ "$1" = "CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y" ]; then
22762306a36Sopenharmony_ci			echo "yes"
22862306a36Sopenharmony_ci		elif [ "$1" = "CONFIG_FW_LOADER_USER_HELPER=y" ]; then
22962306a36Sopenharmony_ci			if [ -d /sys/class/firmware/ ]; then
23062306a36Sopenharmony_ci				echo yes
23162306a36Sopenharmony_ci			else
23262306a36Sopenharmony_ci				echo no
23362306a36Sopenharmony_ci			fi
23462306a36Sopenharmony_ci		fi
23562306a36Sopenharmony_ci	fi
23662306a36Sopenharmony_ci}
237