1#!/bin/sh 2# This validates that the kernel will fall back to using the fallback mechanism 3# to load firmware it can't find on disk itself. We must request a firmware 4# that the kernel won't find, and any installed helper (e.g. udev) also 5# won't find so that we can do the load ourself manually. 6set -e 7 8modprobe test_firmware 9 10DIR=/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. 15HAS_FW_LOADER_USER_HELPER=$(if [ -d /sys/class/firmware/ ]; then echo yes; else echo no; fi) 16 17if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then 18 OLD_TIMEOUT=$(cat /sys/class/firmware/timeout) 19else 20 echo "usermode helper disabled so ignoring test" 21 exit 0 22fi 23 24FWPATH=$(mktemp -d) 25FW="$FWPATH/test-firmware.bin" 26 27test_finish() 28{ 29 echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout 30 rm -f "$FW" 31 rmdir "$FWPATH" 32} 33 34load_fw() 35{ 36 local name="$1" 37 local file="$2" 38 39 # This will block until our load (below) has finished. 40 echo -n "$name" >"$DIR"/trigger_request & 41 42 # Give kernel a chance to react. 43 local timeout=10 44 while [ ! -e "$DIR"/"$name"/loading ]; do 45 sleep 0.1 46 timeout=$(( $timeout - 1 )) 47 if [ "$timeout" -eq 0 ]; then 48 echo "$0: firmware interface never appeared" >&2 49 exit 1 50 fi 51 done 52 53 echo 1 >"$DIR"/"$name"/loading 54 cat "$file" >"$DIR"/"$name"/data 55 echo 0 >"$DIR"/"$name"/loading 56 57 # Wait for request to finish. 58 wait 59} 60 61load_fw_cancel() 62{ 63 local name="$1" 64 local file="$2" 65 66 # This will block until our load (below) has finished. 67 echo -n "$name" >"$DIR"/trigger_request 2>/dev/null & 68 69 # Give kernel a chance to react. 70 local timeout=10 71 while [ ! -e "$DIR"/"$name"/loading ]; do 72 sleep 0.1 73 timeout=$(( $timeout - 1 )) 74 if [ "$timeout" -eq 0 ]; then 75 echo "$0: firmware interface never appeared" >&2 76 exit 1 77 fi 78 done 79 80 echo -1 >"$DIR"/"$name"/loading 81 82 # Wait for request to finish. 83 wait 84} 85 86load_fw_custom() 87{ 88 local name="$1" 89 local file="$2" 90 91 echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & 92 93 # Give kernel a chance to react. 94 local timeout=10 95 while [ ! -e "$DIR"/"$name"/loading ]; do 96 sleep 0.1 97 timeout=$(( $timeout - 1 )) 98 if [ "$timeout" -eq 0 ]; then 99 echo "$0: firmware interface never appeared" >&2 100 exit 1 101 fi 102 done 103 104 echo 1 >"$DIR"/"$name"/loading 105 cat "$file" >"$DIR"/"$name"/data 106 echo 0 >"$DIR"/"$name"/loading 107 108 # Wait for request to finish. 109 wait 110} 111 112 113load_fw_custom_cancel() 114{ 115 local name="$1" 116 local file="$2" 117 118 echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & 119 120 # Give kernel a chance to react. 121 local timeout=10 122 while [ ! -e "$DIR"/"$name"/loading ]; do 123 sleep 0.1 124 timeout=$(( $timeout - 1 )) 125 if [ "$timeout" -eq 0 ]; then 126 echo "$0: firmware interface never appeared" >&2 127 exit 1 128 fi 129 done 130 131 echo -1 >"$DIR"/"$name"/loading 132 133 # Wait for request to finish. 134 wait 135} 136 137 138trap "test_finish" EXIT 139 140# This is an unlikely real-world firmware content. :) 141echo "ABCD0123" >"$FW" 142NAME=$(basename "$FW") 143 144DEVPATH="$DIR"/"nope-$NAME"/loading 145 146# Test failure when doing nothing (timeout works). 147echo -n 2 >/sys/class/firmware/timeout 148echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null & 149 150# Give the kernel some time to load the loading file, must be less 151# than the timeout above. 152sleep 1 153if [ ! -f $DEVPATH ]; then 154 echo "$0: fallback mechanism immediately cancelled" 155 echo "" 156 echo "The file never appeared: $DEVPATH" 157 echo "" 158 echo "This might be a distribution udev rule setup by your distribution" 159 echo "to immediately cancel all fallback requests, this must be" 160 echo "removed before running these tests. To confirm look for" 161 echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules" 162 echo "and see if you have something like this:" 163 echo "" 164 echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\"" 165 echo "" 166 echo "If you do remove this file or comment out this line before" 167 echo "proceeding with these tests." 168 exit 1 169fi 170 171if diff -q "$FW" /dev/test_firmware >/dev/null ; then 172 echo "$0: firmware was not expected to match" >&2 173 exit 1 174else 175 echo "$0: timeout works" 176fi 177 178# Put timeout high enough for us to do work but not so long that failures 179# slow down this test too much. 180echo 4 >/sys/class/firmware/timeout 181 182# Load this script instead of the desired firmware. 183load_fw "$NAME" "$0" 184if diff -q "$FW" /dev/test_firmware >/dev/null ; then 185 echo "$0: firmware was not expected to match" >&2 186 exit 1 187else 188 echo "$0: firmware comparison works" 189fi 190 191# Do a proper load, which should work correctly. 192load_fw "$NAME" "$FW" 193if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then 194 echo "$0: firmware was not loaded" >&2 195 exit 1 196else 197 echo "$0: fallback mechanism works" 198fi 199 200load_fw_cancel "nope-$NAME" "$FW" 201if diff -q "$FW" /dev/test_firmware >/dev/null ; then 202 echo "$0: firmware was expected to be cancelled" >&2 203 exit 1 204else 205 echo "$0: cancelling fallback mechanism works" 206fi 207 208load_fw_custom "$NAME" "$FW" 209if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then 210 echo "$0: firmware was not loaded" >&2 211 exit 1 212else 213 echo "$0: custom fallback loading mechanism works" 214fi 215 216load_fw_custom_cancel "nope-$NAME" "$FW" 217if diff -q "$FW" /dev/test_firmware >/dev/null ; then 218 echo "$0: firmware was expected to be cancelled" >&2 219 exit 1 220else 221 echo "$0: cancelling custom fallback mechanism works" 222fi 223 224exit 0 225