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