1 #!/bin/bash !! 1 #!/bin/sh 2 # SPDX-License-Identifier: GPL-2.0 << 3 # This validates that the kernel will fall bac 2 # This validates that the kernel will fall back to using the fallback mechanism 4 # to load firmware it can't find on disk itsel 3 # to load firmware it can't find on disk itself. We must request a firmware 5 # that the kernel won't find, and any installe 4 # that the kernel won't find, and any installed helper (e.g. udev) also 6 # won't find so that we can do the load oursel 5 # won't find so that we can do the load ourself manually. 7 set -e 6 set -e 8 7 9 TEST_REQS_FW_SYSFS_FALLBACK="yes" !! 8 modprobe test_firmware 10 TEST_REQS_FW_SET_CUSTOM_PATH="no" << 11 TEST_DIR=$(dirname $0) << 12 source $TEST_DIR/fw_lib.sh << 13 << 14 check_mods << 15 check_setup << 16 verify_reqs << 17 setup_tmp_file << 18 9 19 trap "test_finish" EXIT !! 10 DIR=/sys/devices/virtual/misc/test_firmware >> 11 >> 12 # CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/ >> 13 # These days no one enables CONFIG_FW_LOADER_USER_HELPER so check for that >> 14 # as an indicator for CONFIG_FW_LOADER_USER_HELPER. >> 15 HAS_FW_LOADER_USER_HELPER=$(if [ -d /sys/class/firmware/ ]; then echo yes; else echo no; fi) >> 16 >> 17 if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then >> 18 OLD_TIMEOUT=$(cat /sys/class/firmware/timeout) >> 19 else >> 20 echo "usermode helper disabled so ignoring test" >> 21 exit 0 >> 22 fi >> 23 >> 24 FWPATH=$(mktemp -d) >> 25 FW="$FWPATH/test-firmware.bin" >> 26 >> 27 test_finish() >> 28 { >> 29 echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout >> 30 rm -f "$FW" >> 31 rmdir "$FWPATH" >> 32 } 20 33 21 load_fw() 34 load_fw() 22 { 35 { 23 local name="$1" 36 local name="$1" 24 local file="$2" 37 local file="$2" 25 38 26 # This will block until our load (belo 39 # This will block until our load (below) has finished. 27 echo -n "$name" >"$DIR"/trigger_reques 40 echo -n "$name" >"$DIR"/trigger_request & 28 41 29 # Give kernel a chance to react. 42 # Give kernel a chance to react. 30 local timeout=10 43 local timeout=10 31 while [ ! -e "$DIR"/"$name"/loading ]; 44 while [ ! -e "$DIR"/"$name"/loading ]; do 32 sleep 0.1 45 sleep 0.1 33 timeout=$(( $timeout - 1 )) 46 timeout=$(( $timeout - 1 )) 34 if [ "$timeout" -eq 0 ]; then 47 if [ "$timeout" -eq 0 ]; then 35 echo "$0: firmware int 48 echo "$0: firmware interface never appeared" >&2 36 exit 1 49 exit 1 37 fi 50 fi 38 done 51 done 39 52 40 echo 1 >"$DIR"/"$name"/loading 53 echo 1 >"$DIR"/"$name"/loading 41 cat "$file" >"$DIR"/"$name"/data 54 cat "$file" >"$DIR"/"$name"/data 42 echo 0 >"$DIR"/"$name"/loading 55 echo 0 >"$DIR"/"$name"/loading 43 56 44 # Wait for request to finish. 57 # Wait for request to finish. 45 wait 58 wait 46 } 59 } 47 60 48 load_fw_cancel() 61 load_fw_cancel() 49 { 62 { 50 local name="$1" 63 local name="$1" 51 local file="$2" 64 local file="$2" 52 65 53 # This will block until our load (belo 66 # This will block until our load (below) has finished. 54 echo -n "$name" >"$DIR"/trigger_reques 67 echo -n "$name" >"$DIR"/trigger_request 2>/dev/null & 55 68 56 # Give kernel a chance to react. 69 # Give kernel a chance to react. 57 local timeout=10 70 local timeout=10 58 while [ ! -e "$DIR"/"$name"/loading ]; 71 while [ ! -e "$DIR"/"$name"/loading ]; do 59 sleep 0.1 72 sleep 0.1 60 timeout=$(( $timeout - 1 )) 73 timeout=$(( $timeout - 1 )) 61 if [ "$timeout" -eq 0 ]; then 74 if [ "$timeout" -eq 0 ]; then 62 echo "$0: firmware int 75 echo "$0: firmware interface never appeared" >&2 63 exit 1 76 exit 1 64 fi 77 fi 65 done 78 done 66 79 67 echo -1 >"$DIR"/"$name"/loading 80 echo -1 >"$DIR"/"$name"/loading 68 81 69 # Wait for request to finish. 82 # Wait for request to finish. 70 wait 83 wait 71 } 84 } 72 85 73 load_fw_custom() 86 load_fw_custom() 74 { 87 { 75 if [ ! -e "$DIR"/trigger_custom_fallba << 76 echo "$0: custom fallback trig << 77 exit $ksft_skip << 78 fi << 79 << 80 local name="$1" 88 local name="$1" 81 local file="$2" 89 local file="$2" 82 90 83 echo -n "$name" >"$DIR"/trigger_custom 91 echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & 84 92 85 # Give kernel a chance to react. 93 # Give kernel a chance to react. 86 local timeout=10 94 local timeout=10 87 while [ ! -e "$DIR"/"$name"/loading ]; 95 while [ ! -e "$DIR"/"$name"/loading ]; do 88 sleep 0.1 96 sleep 0.1 89 timeout=$(( $timeout - 1 )) 97 timeout=$(( $timeout - 1 )) 90 if [ "$timeout" -eq 0 ]; then 98 if [ "$timeout" -eq 0 ]; then 91 echo "$0: firmware int 99 echo "$0: firmware interface never appeared" >&2 92 exit 1 100 exit 1 93 fi 101 fi 94 done 102 done 95 103 96 echo 1 >"$DIR"/"$name"/loading 104 echo 1 >"$DIR"/"$name"/loading 97 cat "$file" >"$DIR"/"$name"/data 105 cat "$file" >"$DIR"/"$name"/data 98 echo 0 >"$DIR"/"$name"/loading 106 echo 0 >"$DIR"/"$name"/loading 99 107 100 # Wait for request to finish. 108 # Wait for request to finish. 101 wait 109 wait 102 return 0 << 103 } 110 } 104 111 105 112 106 load_fw_custom_cancel() 113 load_fw_custom_cancel() 107 { 114 { 108 if [ ! -e "$DIR"/trigger_custom_fallba << 109 echo "$0: canceling custom fal << 110 exit $ksft_skip << 111 fi << 112 << 113 local name="$1" 115 local name="$1" 114 local file="$2" 116 local file="$2" 115 117 116 echo -n "$name" >"$DIR"/trigger_custom 118 echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & 117 119 118 # Give kernel a chance to react. 120 # Give kernel a chance to react. 119 local timeout=10 121 local timeout=10 120 while [ ! -e "$DIR"/"$name"/loading ]; 122 while [ ! -e "$DIR"/"$name"/loading ]; do 121 sleep 0.1 123 sleep 0.1 122 timeout=$(( $timeout - 1 )) 124 timeout=$(( $timeout - 1 )) 123 if [ "$timeout" -eq 0 ]; then 125 if [ "$timeout" -eq 0 ]; then 124 echo "$0: firmware int 126 echo "$0: firmware interface never appeared" >&2 125 exit 1 127 exit 1 126 fi 128 fi 127 done 129 done 128 130 129 echo -1 >"$DIR"/"$name"/loading 131 echo -1 >"$DIR"/"$name"/loading 130 132 131 # Wait for request to finish. 133 # Wait for request to finish. 132 wait 134 wait 133 return 0 << 134 } 135 } 135 136 136 load_fw_fallback_with_child() << 137 { << 138 local name="$1" << 139 local file="$2" << 140 137 141 # This is the value already set but we !! 138 trap "test_finish" EXIT 142 echo 4 >/sys/class/firmware/timeout << 143 << 144 sleep 1 & << 145 SECONDS_BEFORE=$(date +%s) << 146 echo -n "$name" >"$DIR"/trigger_reques << 147 SECONDS_AFTER=$(date +%s) << 148 SECONDS_DELTA=$(($SECONDS_AFTER - $SEC << 149 if [ "$SECONDS_DELTA" -lt 4 ]; then << 150 RET=1 << 151 else << 152 RET=0 << 153 fi << 154 wait << 155 return $RET << 156 } << 157 << 158 test_syfs_timeout() << 159 { << 160 DEVPATH="$DIR"/"nope-$NAME"/loading << 161 139 162 # Test failure when doing nothing (tim !! 140 # This is an unlikely real-world firmware content. :) 163 echo -n 2 >/sys/class/firmware/timeout !! 141 echo "ABCD0123" >"$FW" 164 echo -n "nope-$NAME" >"$DIR"/trigger_r !! 142 NAME=$(basename "$FW") 165 !! 143 166 # Give the kernel some time to load th !! 144 DEVPATH="$DIR"/"nope-$NAME"/loading 167 # than the timeout above. !! 145 168 sleep 1 !! 146 # Test failure when doing nothing (timeout works). 169 if [ ! -f $DEVPATH ]; then !! 147 echo -n 2 >/sys/class/firmware/timeout 170 echo "$0: fallback mechanism i !! 148 echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null & 171 echo "" !! 149 172 echo "The file never appeared: !! 150 # Give the kernel some time to load the loading file, must be less 173 echo "" !! 151 # than the timeout above. 174 echo "This might be a distribu !! 152 sleep 1 175 echo "to immediately cancel al !! 153 if [ ! -f $DEVPATH ]; then 176 echo "removed before running t !! 154 echo "$0: fallback mechanism immediately cancelled" 177 echo "a firmware rule like /li !! 155 echo "" 178 echo "and see if you have some !! 156 echo "The file never appeared: $DEVPATH" 179 echo "" !! 157 echo "" 180 echo "SUBSYSTEM==\"firmware\", !! 158 echo "This might be a distribution udev rule setup by your distribution" 181 echo "" !! 159 echo "to immediately cancel all fallback requests, this must be" 182 echo "If you do remove this fi !! 160 echo "removed before running these tests. To confirm look for" 183 echo "proceeding with these te !! 161 echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules" 184 exit 1 !! 162 echo "and see if you have something like this:" 185 fi !! 163 echo "" 186 !! 164 echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\"" 187 if diff -q "$FW" /dev/test_firmware >/ !! 165 echo "" 188 echo "$0: firmware was not exp !! 166 echo "If you do remove this file or comment out this line before" 189 exit 1 !! 167 echo "proceeding with these tests." 190 else !! 168 exit 1 191 echo "$0: timeout works" !! 169 fi 192 fi << 193 } << 194 170 195 run_sysfs_main_tests() !! 171 if diff -q "$FW" /dev/test_firmware >/dev/null ; then 196 { !! 172 echo "$0: firmware was not expected to match" >&2 197 test_syfs_timeout !! 173 exit 1 198 # Put timeout high enough for us to do !! 174 else 199 # slow down this test too much. !! 175 echo "$0: timeout works" 200 echo 4 >/sys/class/firmware/timeout !! 176 fi 201 << 202 # Load this script instead of the desi << 203 load_fw "$NAME" "$0" << 204 if diff -q "$FW" /dev/test_firmware >/ << 205 echo "$0: firmware was not exp << 206 exit 1 << 207 else << 208 echo "$0: firmware comparison << 209 fi << 210 << 211 # Do a proper load, which should work << 212 load_fw "$NAME" "$FW" << 213 if ! diff -q "$FW" /dev/test_firmware << 214 echo "$0: firmware was not loa << 215 exit 1 << 216 else << 217 echo "$0: fallback mechanism w << 218 fi << 219 << 220 load_fw_cancel "nope-$NAME" "$FW" << 221 if diff -q "$FW" /dev/test_firmware >/ << 222 echo "$0: firmware was expecte << 223 exit 1 << 224 else << 225 echo "$0: cancelling fallback << 226 fi << 227 << 228 set +e << 229 load_fw_fallback_with_child "nope-sign << 230 if [ "$?" -eq 0 ]; then << 231 echo "$0: SIGCHLD on sync igno << 232 else << 233 echo "$0: error - sync firmwar << 234 exit 1 << 235 fi << 236 set -e << 237 } << 238 177 239 run_sysfs_custom_load_tests() !! 178 # Put timeout high enough for us to do work but not so long that failures 240 { !! 179 # slow down this test too much. 241 RANDOM_FILE_PATH=$(setup_random_file) !! 180 echo 4 >/sys/class/firmware/timeout 242 RANDOM_FILE="$(basename $RANDOM_FILE_P !! 181 243 if load_fw_custom "$RANDOM_FILE" "$RAN !! 182 # Load this script instead of the desired firmware. 244 if ! diff -q "$RANDOM_FILE_PAT !! 183 load_fw "$NAME" "$0" 245 echo "$0: firmware was !! 184 if diff -q "$FW" /dev/test_firmware >/dev/null ; then 246 exit 1 !! 185 echo "$0: firmware was not expected to match" >&2 247 else !! 186 exit 1 248 echo "$0: custom fallb !! 187 else 249 fi !! 188 echo "$0: firmware comparison works" 250 fi !! 189 fi 251 190 252 RANDOM_FILE_PATH=$(setup_random_file) !! 191 # Do a proper load, which should work correctly. 253 RANDOM_FILE="$(basename $RANDOM_FILE_P !! 192 load_fw "$NAME" "$FW" 254 if load_fw_custom "$RANDOM_FILE" "$RAN !! 193 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then 255 if ! diff -q "$RANDOM_FILE_PAT !! 194 echo "$0: firmware was not loaded" >&2 256 echo "$0: firmware was !! 195 exit 1 257 exit 1 !! 196 else 258 else !! 197 echo "$0: fallback mechanism works" 259 echo "$0: custom fallb !! 198 fi 260 fi << 261 fi << 262 199 263 RANDOM_FILE_REAL="$RANDOM_FILE_PATH" !! 200 load_fw_cancel "nope-$NAME" "$FW" 264 FAKE_RANDOM_FILE_PATH=$(setup_random_f !! 201 if diff -q "$FW" /dev/test_firmware >/dev/null ; then 265 FAKE_RANDOM_FILE="$(basename $FAKE_RAN !! 202 echo "$0: firmware was expected to be cancelled" >&2 266 !! 203 exit 1 267 if load_fw_custom_cancel "$FAKE_RANDOM !! 204 else 268 if diff -q "$RANDOM_FILE_PATH" !! 205 echo "$0: cancelling fallback mechanism works" 269 echo "$0: firmware was !! 206 fi 270 exit 1 << 271 else << 272 echo "$0: cancelling c << 273 fi << 274 fi << 275 } << 276 207 277 if [ "$HAS_FW_LOADER_USER_HELPER_FALLBACK" = " !! 208 load_fw_custom "$NAME" "$FW" 278 run_sysfs_main_tests !! 209 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then >> 210 echo "$0: firmware was not loaded" >&2 >> 211 exit 1 >> 212 else >> 213 echo "$0: custom fallback loading mechanism works" 279 fi 214 fi 280 215 281 run_sysfs_custom_load_tests !! 216 load_fw_custom_cancel "nope-$NAME" "$FW" >> 217 if diff -q "$FW" /dev/test_firmware >/dev/null ; then >> 218 echo "$0: firmware was expected to be cancelled" >&2 >> 219 exit 1 >> 220 else >> 221 echo "$0: cancelling custom fallback mechanism works" >> 222 fi 282 223 283 exit 0 224 exit 0
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.