#!/bin/sh # This validates that the kernel will fall back to using the user helper # to load firmware it can't find on disk itself. We must request a firmware # that the kernel won't find, and any installed helper (e.g. udev) also # won't find so that we can do the load ourself manually. set -e modprobe test_firmware global DIR := '/sys/devices/virtual/misc/test_firmware' # CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/ # These days no one enables CONFIG_FW_LOADER_USER_HELPER so check for that # as an indicator for CONFIG_FW_LOADER_USER_HELPER. global HAS_FW_LOADER_USER_HELPER := $[if test -d /sys/class/firmware/ { echo yes; } else { echo no; }] if test $HAS_FW_LOADER_USER_HELPER = "yes" { global OLD_TIMEOUT := $[cat /sys/class/firmware/timeout] } else { echo "usermode helper disabled so ignoring test" exit 0 } global FWPATH := $[mktemp -d] global FW := ""$FWPATH/test-firmware.bin"" proc test_finish { echo $OLD_TIMEOUT >/sys/class/firmware/timeout rm -f $FW rmdir $FWPATH } proc load_fw { var name = $1 var file = $2 # This will block until our load (below) has finished. echo -n $name >"$DIR"/trigger_request & # Give kernel a chance to react. var timeout = '10' while [ ! -e "$DIR"/"$name"/loading ] { sleep 0.1 timeout := $( $timeout - 1 ) if test $timeout -eq 0 { echo "$0: firmware interface never appeared" > !2 exit 1 } } echo 1 >"$DIR"/"$name"/loading cat $file >"$DIR"/"$name"/data echo 0 >"$DIR"/"$name"/loading # Wait for request to finish. wait } trap "test_finish" EXIT # This is an unlikely real-world firmware content. :) echo "ABCD0123" >$FW global NAME := $[basename $FW] # Test failure when doing nothing (timeout works). echo 1 >/sys/class/firmware/timeout echo -n $NAME >"$DIR"/trigger_request if diff -q $FW /dev/test_firmware >/dev/null { echo "$0: firmware was not expected to match" > !2 exit 1 } else { echo "$0: timeout works" } # Put timeout high enough for us to do work but not so long that failures # slow down this test too much. echo 4 >/sys/class/firmware/timeout # Load this script instead of the desired firmware. load_fw $NAME $0 if diff -q $FW /dev/test_firmware >/dev/null { echo "$0: firmware was not expected to match" > !2 exit 1 } else { echo "$0: firmware comparison works" } # Do a proper load, which should work correctly. load_fw $NAME $FW if ! diff -q $FW /dev/test_firmware >/dev/null { echo "$0: firmware was not loaded" > !2 exit 1 } else { echo "$0: user helper firmware loading works" } exit 0 (CommandList children: [ (C {(set)} {(-e)}) (C {(modprobe)} {(test_firmware)}) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:DIR) op: Equal rhs: {(/sys/devices/virtual/misc/test_firmware)} spids: [25] ) ] spids: [25] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:HAS_FW_LOADER_USER_HELPER) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(-d)} {(/sys/class/firmware/)} {(Lit_Other "]")}) terminator: ) ] action: [(Sentence child:(C {(echo)} {(yes)}) terminator:)] spids: [-1 51] ) ] else_action: [(Sentence child:(C {(echo)} {(no)}) terminator:)] spids: [58 65] ) ] ) left_token: spids: [39 66] ) } spids: [38] ) ] spids: [38] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$HAS_FW_LOADER_USER_HELPER"))} {(Lit_Other "=")} {(DQ (yes))} {(Lit_Other "]")} ) terminator: ) ] action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:OLD_TIMEOUT) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [(C {(cat)} {(/sys/class/firmware/timeout)})] ) left_token: spids: [90 94] ) } spids: [89] ) ] spids: [89] ) ] spids: [-1 86] ) ] else_action: [(C {(echo)} {(DQ ("usermode helper disabled so ignoring test"))}) (C {(exit)} {(0)})] spids: [96 110] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:FWPATH) op: Equal rhs: { (CommandSubPart command_list: (CommandList children:[(C {(mktemp)} {(-d)})]) left_token: spids: [114 118] ) } spids: [113] ) ] spids: [113] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:FW) op: Equal rhs: {(DQ ($ VSub_Name "$FWPATH") (/test-firmware.bin))} spids: [120] ) ] spids: [120] ) (FuncDef name: test_finish body: (BraceGroup children: [ (SimpleCommand words: [{(echo)} {(DQ ($ VSub_Name "$OLD_TIMEOUT"))}] redirects: [ (Redir op_id: Redir_Great fd: -1 arg_word: {(/sys/class/firmware/timeout)} spids: [140] ) ] ) (C {(rm)} {(-f)} {(DQ ($ VSub_Name "$FW"))}) (C {(rmdir)} {(DQ ($ VSub_Name "$FWPATH"))}) ] spids: [131] ) spids: [127 130] ) (FuncDef name: load_fw body: (BraceGroup children: [ (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:name) op: Equal rhs: {(DQ ($ VSub_Number "$1"))} spids: [171] ) ] spids: [169] ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:file) op: Equal rhs: {(DQ ($ VSub_Number "$2"))} spids: [179] ) ] spids: [177] ) (Sentence child: (SimpleCommand words: [{(echo)} {(-n)} {(DQ ($ VSub_Name "$name"))}] redirects: [ (Redir op_id: Redir_Great fd: -1 arg_word: {(DQ ($ VSub_Name "$DIR")) (/trigger_request)} spids: [198] ) ] ) terminator: ) (Assignment keyword: Assign_Local pairs: [(assign_pair lhs:(LhsName name:timeout) op:Equal rhs:{(10)} spids:[214])] spids: [212] ) (While cond: [ (Sentence child: (C {(Lit_Other "[")} {(KW_Bang "!")} {(-e)} {(DQ ($ VSub_Name "$DIR")) (/) (DQ ($ VSub_Name "$name")) (/loading)} {(Lit_Other "]")} ) terminator: ) ] body: (DoGroup children: [ (C {(sleep)} {(0.1)}) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:timeout) op: Equal rhs: { (ArithSubPart anode: (ArithBinary op_id: Arith_Minus left: (ArithWord w:{($ VSub_Name "$timeout")}) right: (ArithWord w:{(Lit_Digits 1)}) ) spids: [247 256] ) } spids: [246] ) ] spids: [246] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$timeout"))} {(-eq)} {(0)} {(Lit_Other "]")} ) terminator: ) ] action: [ (SimpleCommand words: [ {(echo)} {(DQ ($ VSub_Number "$0") (": firmware interface never appeared"))} ] redirects: [ (Redir op_id: Redir_GreatAnd fd: -1 arg_word: {(2)} spids: [284] ) ] ) (C {(exit)} {(1)}) ] spids: [-1 274] ) ] spids: [-1 293] ) ] spids: [238 296] ) ) (SimpleCommand words: [{(echo)} {(1)}] redirects: [ (Redir op_id: Redir_Great fd: -1 arg_word: {(DQ ($ VSub_Name "$DIR")) (/) (DQ ($ VSub_Name "$name")) (/loading)} spids: [304] ) ] ) (SimpleCommand words: [{(cat)} {(DQ ($ VSub_Name "$file"))}] redirects: [ (Redir op_id: Redir_Great fd: -1 arg_word: {(DQ ($ VSub_Name "$DIR")) (/) (DQ ($ VSub_Name "$name")) (/data)} spids: [321] ) ] ) (SimpleCommand words: [{(echo)} {(0)}] redirects: [ (Redir op_id: Redir_Great fd: -1 arg_word: {(DQ ($ VSub_Name "$DIR")) (/) (DQ ($ VSub_Name "$name")) (/loading)} spids: [336] ) ] ) (C {(wait)}) ] spids: [166] ) spids: [162 165] ) (C {(trap)} {(DQ (test_finish))} {(EXIT)}) (SimpleCommand words: [{(echo)} {(DQ (ABCD0123))}] redirects: [(Redir op_id:Redir_Great fd:-1 arg_word:{(DQ ($ VSub_Name "$FW"))} spids:[375])] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:NAME) op: Equal rhs: { (CommandSubPart command_list: (CommandList children:[(C {(basename)} {(DQ ($ VSub_Name "$FW"))})]) left_token: spids: [381 387] ) } spids: [380] ) ] spids: [380] ) (SimpleCommand words: [{(echo)} {(1)}] redirects: [ (Redir op_id:Redir_Great fd:-1 arg_word:{(/sys/class/firmware/timeout)} spids:[397]) ] ) (SimpleCommand words: [{(echo)} {(-n)} {(DQ ($ VSub_Name "$NAME"))}] redirects: [ (Redir op_id: Redir_Great fd: -1 arg_word: {(DQ ($ VSub_Name "$DIR")) (/trigger_request)} spids: [408] ) ] ) (If arms: [ (if_arm cond: [ (Sentence child: (SimpleCommand words: [{(diff)} {(-q)} {(DQ ($ VSub_Name "$FW"))} {(/dev/test_firmware)}] redirects: [(Redir op_id:Redir_Great fd:-1 arg_word:{(/dev/null)} spids:[426])] ) terminator: ) ] action: [ (SimpleCommand words: [{(echo)} {(DQ ($ VSub_Number "$0") (": firmware was not expected to match"))}] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[441])] ) (C {(exit)} {(1)}) ] spids: [-1 431] ) ] else_action: [(C {(echo)} {(DQ ($ VSub_Number "$0") (": timeout works"))})] spids: [449 459] ) (SimpleCommand words: [{(echo)} {(4)}] redirects: [ (Redir op_id:Redir_Great fd:-1 arg_word:{(/sys/class/firmware/timeout)} spids:[472]) ] ) (C {(load_fw)} {(DQ ($ VSub_Name "$NAME"))} {(DQ ($ VSub_Number "$0"))}) (If arms: [ (if_arm cond: [ (Sentence child: (SimpleCommand words: [{(diff)} {(-q)} {(DQ ($ VSub_Name "$FW"))} {(/dev/test_firmware)}] redirects: [(Redir op_id:Redir_Great fd:-1 arg_word:{(/dev/null)} spids:[501])] ) terminator: ) ] action: [ (SimpleCommand words: [{(echo)} {(DQ ($ VSub_Number "$0") (": firmware was not expected to match"))}] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[516])] ) (C {(exit)} {(1)}) ] spids: [-1 506] ) ] else_action: [(C {(echo)} {(DQ ($ VSub_Number "$0") (": firmware comparison works"))})] spids: [524 534] ) (C {(load_fw)} {(DQ ($ VSub_Name "$NAME"))} {(DQ ($ VSub_Name "$FW"))}) (If arms: [ (if_arm cond: [ (Sentence child: (Pipeline children: [ (SimpleCommand words: [{(diff)} {(-q)} {(DQ ($ VSub_Name "$FW"))} {(/dev/test_firmware)}] redirects: [(Redir op_id:Redir_Great fd:-1 arg_word:{(/dev/null)} spids:[564])] ) ] negated: True ) terminator: ) ] action: [ (SimpleCommand words: [{(echo)} {(DQ ($ VSub_Number "$0") (": firmware was not loaded"))}] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[579])] ) (C {(exit)} {(1)}) ] spids: [-1 569] ) ] else_action: [(C {(echo)} {(DQ ($ VSub_Number "$0") (": user helper firmware loading works"))})] spids: [587 597] ) (C {(exit)} {(0)}) ] )