1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# Library of helpers for test scripts.
5set -e
6
7DIR=/sys/devices/virtual/misc/test_firmware
8
9PROC_CONFIG="/proc/config.gz"
10TEST_DIR=$(dirname $0)
11
12print_reqs_exit()
13{
14	echo "You must have the following enabled in your kernel:" >&2
15	cat $TEST_DIR/config >&2
16	exit 1
17}
18
19test_modprobe()
20{
21	if [ ! -d $DIR ]; then
22		print_reqs_exit
23	fi
24}
25
26check_mods()
27{
28	trap "test_modprobe" EXIT
29	if [ ! -d $DIR ]; then
30		modprobe test_firmware
31	fi
32	if [ ! -f $PROC_CONFIG ]; then
33		if modprobe configs 2>/dev/null; then
34			echo "Loaded configs module"
35			if [ ! -f $PROC_CONFIG ]; then
36				echo "You must have the following enabled in your kernel:" >&2
37				cat $TEST_DIR/config >&2
38				echo "Resorting to old heuristics" >&2
39			fi
40		else
41			echo "Failed to load configs module, using old heuristics" >&2
42		fi
43	fi
44}
45
46check_setup()
47{
48	HAS_FW_LOADER_USER_HELPER="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER=y)"
49	HAS_FW_LOADER_USER_HELPER_FALLBACK="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y)"
50	PROC_FW_IGNORE_SYSFS_FALLBACK="0"
51	PROC_FW_FORCE_SYSFS_FALLBACK="0"
52
53	if [ -z $PROC_SYS_DIR ]; then
54		PROC_SYS_DIR="/proc/sys/kernel"
55	fi
56
57	FW_PROC="${PROC_SYS_DIR}/firmware_config"
58	FW_FORCE_SYSFS_FALLBACK="$FW_PROC/force_sysfs_fallback"
59	FW_IGNORE_SYSFS_FALLBACK="$FW_PROC/ignore_sysfs_fallback"
60
61	if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then
62		PROC_FW_FORCE_SYSFS_FALLBACK="$(cat $FW_FORCE_SYSFS_FALLBACK)"
63	fi
64
65	if [ -f $FW_IGNORE_SYSFS_FALLBACK ]; then
66		PROC_FW_IGNORE_SYSFS_FALLBACK="$(cat $FW_IGNORE_SYSFS_FALLBACK)"
67	fi
68
69	if [ "$PROC_FW_FORCE_SYSFS_FALLBACK" = "1" ]; then
70		HAS_FW_LOADER_USER_HELPER="yes"
71		HAS_FW_LOADER_USER_HELPER_FALLBACK="yes"
72	fi
73
74	if [ "$PROC_FW_IGNORE_SYSFS_FALLBACK" = "1" ]; then
75		HAS_FW_LOADER_USER_HELPER_FALLBACK="no"
76		HAS_FW_LOADER_USER_HELPER="no"
77	fi
78
79	if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
80	       OLD_TIMEOUT="$(cat /sys/class/firmware/timeout)"
81	fi
82
83	OLD_FWPATH="$(cat /sys/module/firmware_class/parameters/path)"
84}
85
86verify_reqs()
87{
88	if [ "$TEST_REQS_FW_SYSFS_FALLBACK" = "yes" ]; then
89		if [ ! "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
90			echo "usermode helper disabled so ignoring test"
91			exit 0
92		fi
93	fi
94}
95
96setup_tmp_file()
97{
98	FWPATH=$(mktemp -d)
99	FW="$FWPATH/test-firmware.bin"
100	echo "ABCD0123" >"$FW"
101	NAME=$(basename "$FW")
102	if [ "$TEST_REQS_FW_SET_CUSTOM_PATH" = "yes" ]; then
103		echo -n "$FWPATH" >/sys/module/firmware_class/parameters/path
104	fi
105}
106
107__setup_random_file()
108{
109	RANDOM_FILE_PATH="$(mktemp -p $FWPATH)"
110	# mktemp says dry-run -n is unsafe, so...
111	if [[ "$1" = "fake" ]]; then
112		rm -rf $RANDOM_FILE_PATH
113		sync
114	else
115		echo "ABCD0123" >"$RANDOM_FILE_PATH"
116	fi
117	echo $RANDOM_FILE_PATH
118}
119
120setup_random_file()
121{
122	echo $(__setup_random_file)
123}
124
125setup_random_file_fake()
126{
127	echo $(__setup_random_file fake)
128}
129
130proc_set_force_sysfs_fallback()
131{
132	if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then
133		echo -n $1 > $FW_FORCE_SYSFS_FALLBACK
134		check_setup
135	fi
136}
137
138proc_set_ignore_sysfs_fallback()
139{
140	if [ -f $FW_IGNORE_SYSFS_FALLBACK ]; then
141		echo -n $1 > $FW_IGNORE_SYSFS_FALLBACK
142		check_setup
143	fi
144}
145
146proc_restore_defaults()
147{
148	proc_set_force_sysfs_fallback 0
149	proc_set_ignore_sysfs_fallback 0
150}
151
152test_finish()
153{
154	if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
155		echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout
156	fi
157	if [ "$TEST_REQS_FW_SET_CUSTOM_PATH" = "yes" ]; then
158		if [ "$OLD_FWPATH" = "" ]; then
159			# A zero-length write won't work; write a null byte
160			printf '\000' >/sys/module/firmware_class/parameters/path
161		else
162			echo -n "$OLD_FWPATH" >/sys/module/firmware_class/parameters/path
163		fi
164	fi
165	if [ -f $FW ]; then
166		rm -f "$FW"
167	fi
168	if [ -d $FWPATH ]; then
169		rm -rf "$FWPATH"
170	fi
171	proc_restore_defaults
172}
173
174kconfig_has()
175{
176	if [ -f $PROC_CONFIG ]; then
177		if zgrep -q $1 $PROC_CONFIG 2>/dev/null; then
178			echo "yes"
179		else
180			echo "no"
181		fi
182	else
183		# We currently don't have easy heuristics to infer this
184		# so best we can do is just try to use the kernel assuming
185		# you had enabled it. This matches the old behaviour.
186		if [ "$1" = "CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y" ]; then
187			echo "yes"
188		elif [ "$1" = "CONFIG_FW_LOADER_USER_HELPER=y" ]; then
189			if [ -d /sys/class/firmware/ ]; then
190				echo yes
191			else
192				echo no
193			fi
194		fi
195	fi
196}
197