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 89 if [ ! -e "$DIR"/trigger_custom_fallback ]; then 76 echo "$0: custom fallback trig 90 echo "$0: custom fallback trigger not present, ignoring test" >&2 77 exit $ksft_skip !! 91 return 1 78 fi 92 fi 79 93 80 local name="$1" 94 local name="$1" 81 local file="$2" 95 local file="$2" 82 96 83 echo -n "$name" >"$DIR"/trigger_custom 97 echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & 84 98 85 # Give kernel a chance to react. 99 # Give kernel a chance to react. 86 local timeout=10 100 local timeout=10 87 while [ ! -e "$DIR"/"$name"/loading ]; 101 while [ ! -e "$DIR"/"$name"/loading ]; do 88 sleep 0.1 102 sleep 0.1 89 timeout=$(( $timeout - 1 )) 103 timeout=$(( $timeout - 1 )) 90 if [ "$timeout" -eq 0 ]; then 104 if [ "$timeout" -eq 0 ]; then 91 echo "$0: firmware int 105 echo "$0: firmware interface never appeared" >&2 92 exit 1 106 exit 1 93 fi 107 fi 94 done 108 done 95 109 96 echo 1 >"$DIR"/"$name"/loading 110 echo 1 >"$DIR"/"$name"/loading 97 cat "$file" >"$DIR"/"$name"/data 111 cat "$file" >"$DIR"/"$name"/data 98 echo 0 >"$DIR"/"$name"/loading 112 echo 0 >"$DIR"/"$name"/loading 99 113 100 # Wait for request to finish. 114 # Wait for request to finish. 101 wait 115 wait 102 return 0 116 return 0 103 } 117 } 104 118 105 119 106 load_fw_custom_cancel() 120 load_fw_custom_cancel() 107 { 121 { 108 if [ ! -e "$DIR"/trigger_custom_fallba 122 if [ ! -e "$DIR"/trigger_custom_fallback ]; then 109 echo "$0: canceling custom fal 123 echo "$0: canceling custom fallback trigger not present, ignoring test" >&2 110 exit $ksft_skip !! 124 return 1 111 fi 125 fi 112 126 113 local name="$1" 127 local name="$1" 114 local file="$2" 128 local file="$2" 115 129 116 echo -n "$name" >"$DIR"/trigger_custom 130 echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & 117 131 118 # Give kernel a chance to react. 132 # Give kernel a chance to react. 119 local timeout=10 133 local timeout=10 120 while [ ! -e "$DIR"/"$name"/loading ]; 134 while [ ! -e "$DIR"/"$name"/loading ]; do 121 sleep 0.1 135 sleep 0.1 122 timeout=$(( $timeout - 1 )) 136 timeout=$(( $timeout - 1 )) 123 if [ "$timeout" -eq 0 ]; then 137 if [ "$timeout" -eq 0 ]; then 124 echo "$0: firmware int 138 echo "$0: firmware interface never appeared" >&2 125 exit 1 139 exit 1 126 fi 140 fi 127 done 141 done 128 142 129 echo -1 >"$DIR"/"$name"/loading 143 echo -1 >"$DIR"/"$name"/loading 130 144 131 # Wait for request to finish. 145 # Wait for request to finish. 132 wait 146 wait 133 return 0 147 return 0 134 } 148 } 135 149 136 load_fw_fallback_with_child() 150 load_fw_fallback_with_child() 137 { 151 { 138 local name="$1" 152 local name="$1" 139 local file="$2" 153 local file="$2" 140 154 141 # This is the value already set but we 155 # This is the value already set but we want to be explicit 142 echo 4 >/sys/class/firmware/timeout 156 echo 4 >/sys/class/firmware/timeout 143 157 144 sleep 1 & 158 sleep 1 & 145 SECONDS_BEFORE=$(date +%s) 159 SECONDS_BEFORE=$(date +%s) 146 echo -n "$name" >"$DIR"/trigger_reques 160 echo -n "$name" >"$DIR"/trigger_request 2>/dev/null 147 SECONDS_AFTER=$(date +%s) 161 SECONDS_AFTER=$(date +%s) 148 SECONDS_DELTA=$(($SECONDS_AFTER - $SEC 162 SECONDS_DELTA=$(($SECONDS_AFTER - $SECONDS_BEFORE)) 149 if [ "$SECONDS_DELTA" -lt 4 ]; then 163 if [ "$SECONDS_DELTA" -lt 4 ]; then 150 RET=1 164 RET=1 151 else 165 else 152 RET=0 166 RET=0 153 fi 167 fi 154 wait 168 wait 155 return $RET 169 return $RET 156 } 170 } 157 171 158 test_syfs_timeout() !! 172 trap "test_finish" EXIT 159 { << 160 DEVPATH="$DIR"/"nope-$NAME"/loading << 161 173 162 # Test failure when doing nothing (tim !! 174 # This is an unlikely real-world firmware content. :) 163 echo -n 2 >/sys/class/firmware/timeout !! 175 echo "ABCD0123" >"$FW" 164 echo -n "nope-$NAME" >"$DIR"/trigger_r !! 176 NAME=$(basename "$FW") 165 !! 177 166 # Give the kernel some time to load th !! 178 DEVPATH="$DIR"/"nope-$NAME"/loading 167 # than the timeout above. !! 179 168 sleep 1 !! 180 # Test failure when doing nothing (timeout works). 169 if [ ! -f $DEVPATH ]; then !! 181 echo -n 2 >/sys/class/firmware/timeout 170 echo "$0: fallback mechanism i !! 182 echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null & 171 echo "" !! 183 172 echo "The file never appeared: !! 184 # Give the kernel some time to load the loading file, must be less 173 echo "" !! 185 # than the timeout above. 174 echo "This might be a distribu !! 186 sleep 1 175 echo "to immediately cancel al !! 187 if [ ! -f $DEVPATH ]; then 176 echo "removed before running t !! 188 echo "$0: fallback mechanism immediately cancelled" 177 echo "a firmware rule like /li !! 189 echo "" 178 echo "and see if you have some !! 190 echo "The file never appeared: $DEVPATH" 179 echo "" !! 191 echo "" 180 echo "SUBSYSTEM==\"firmware\", !! 192 echo "This might be a distribution udev rule setup by your distribution" 181 echo "" !! 193 echo "to immediately cancel all fallback requests, this must be" 182 echo "If you do remove this fi !! 194 echo "removed before running these tests. To confirm look for" 183 echo "proceeding with these te !! 195 echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules" 184 exit 1 !! 196 echo "and see if you have something like this:" 185 fi !! 197 echo "" >> 198 echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\"" >> 199 echo "" >> 200 echo "If you do remove this file or comment out this line before" >> 201 echo "proceeding with these tests." >> 202 exit 1 >> 203 fi 186 204 187 if diff -q "$FW" /dev/test_firmware >/ !! 205 if diff -q "$FW" /dev/test_firmware >/dev/null ; then 188 echo "$0: firmware was not exp !! 206 echo "$0: firmware was not expected to match" >&2 189 exit 1 !! 207 exit 1 190 else !! 208 else 191 echo "$0: timeout works" !! 209 echo "$0: timeout works" 192 fi !! 210 fi 193 } << 194 211 195 run_sysfs_main_tests() !! 212 # Put timeout high enough for us to do work but not so long that failures 196 { !! 213 # slow down this test too much. 197 test_syfs_timeout !! 214 echo 4 >/sys/class/firmware/timeout 198 # Put timeout high enough for us to do !! 215 199 # slow down this test too much. !! 216 # Load this script instead of the desired firmware. 200 echo 4 >/sys/class/firmware/timeout !! 217 load_fw "$NAME" "$0" >> 218 if diff -q "$FW" /dev/test_firmware >/dev/null ; then >> 219 echo "$0: firmware was not expected to match" >&2 >> 220 exit 1 >> 221 else >> 222 echo "$0: firmware comparison works" >> 223 fi 201 224 202 # Load this script instead of the desi !! 225 # Do a proper load, which should work correctly. 203 load_fw "$NAME" "$0" !! 226 load_fw "$NAME" "$FW" 204 if diff -q "$FW" /dev/test_firmware >/ !! 227 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then 205 echo "$0: firmware was not exp !! 228 echo "$0: firmware was not loaded" >&2 206 exit 1 !! 229 exit 1 207 else !! 230 else 208 echo "$0: firmware comparison !! 231 echo "$0: fallback mechanism works" 209 fi !! 232 fi 210 233 211 # Do a proper load, which should work !! 234 load_fw_cancel "nope-$NAME" "$FW" 212 load_fw "$NAME" "$FW" !! 235 if diff -q "$FW" /dev/test_firmware >/dev/null ; then >> 236 echo "$0: firmware was expected to be cancelled" >&2 >> 237 exit 1 >> 238 else >> 239 echo "$0: cancelling fallback mechanism works" >> 240 fi >> 241 >> 242 if load_fw_custom "$NAME" "$FW" ; then 213 if ! diff -q "$FW" /dev/test_firmware 243 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then 214 echo "$0: firmware was not loa 244 echo "$0: firmware was not loaded" >&2 215 exit 1 245 exit 1 216 else 246 else 217 echo "$0: fallback mechanism w !! 247 echo "$0: custom fallback loading mechanism works" 218 fi 248 fi >> 249 fi 219 250 220 load_fw_cancel "nope-$NAME" "$FW" !! 251 if load_fw_custom_cancel "nope-$NAME" "$FW" ; then 221 if diff -q "$FW" /dev/test_firmware >/ 252 if diff -q "$FW" /dev/test_firmware >/dev/null ; then 222 echo "$0: firmware was expecte 253 echo "$0: firmware was expected to be cancelled" >&2 223 exit 1 254 exit 1 224 else 255 else 225 echo "$0: cancelling fallback !! 256 echo "$0: cancelling custom fallback mechanism works" 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 << 239 run_sysfs_custom_load_tests() << 240 { << 241 RANDOM_FILE_PATH=$(setup_random_file) << 242 RANDOM_FILE="$(basename $RANDOM_FILE_P << 243 if load_fw_custom "$RANDOM_FILE" "$RAN << 244 if ! diff -q "$RANDOM_FILE_PAT << 245 echo "$0: firmware was << 246 exit 1 << 247 else << 248 echo "$0: custom fallb << 249 fi << 250 fi 257 fi 251 << 252 RANDOM_FILE_PATH=$(setup_random_file) << 253 RANDOM_FILE="$(basename $RANDOM_FILE_P << 254 if load_fw_custom "$RANDOM_FILE" "$RAN << 255 if ! diff -q "$RANDOM_FILE_PAT << 256 echo "$0: firmware was << 257 exit 1 << 258 else << 259 echo "$0: custom fallb << 260 fi << 261 fi << 262 << 263 RANDOM_FILE_REAL="$RANDOM_FILE_PATH" << 264 FAKE_RANDOM_FILE_PATH=$(setup_random_f << 265 FAKE_RANDOM_FILE="$(basename $FAKE_RAN << 266 << 267 if load_fw_custom_cancel "$FAKE_RANDOM << 268 if diff -q "$RANDOM_FILE_PATH" << 269 echo "$0: firmware was << 270 exit 1 << 271 else << 272 echo "$0: cancelling c << 273 fi << 274 fi << 275 } << 276 << 277 if [ "$HAS_FW_LOADER_USER_HELPER_FALLBACK" = " << 278 run_sysfs_main_tests << 279 fi 258 fi 280 259 281 run_sysfs_custom_load_tests !! 260 set +e >> 261 load_fw_fallback_with_child "nope-signal-$NAME" "$FW" >> 262 if [ "$?" -eq 0 ]; then >> 263 echo "$0: SIGCHLD on sync ignored as expected" >&2 >> 264 else >> 265 echo "$0: error - sync firmware request cancelled due to SIGCHLD" >&2 >> 266 exit 1 >> 267 fi >> 268 set -e 282 269 283 exit 0 270 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.