Back to home page

OSCL-LXR

 
 

    


0001 #!/bin/bash
0002 # SPDX-License-Identifier: GPL-2.0
0003 # This validates that the kernel will load firmware out of its list of
0004 # firmware locations on disk. Since the user helper does similar work,
0005 # we reset the custom load directory to a location the user helper doesn't
0006 # know so we can be sure we're not accidentally testing the user helper.
0007 set -e
0008 
0009 TEST_REQS_FW_SYSFS_FALLBACK="no"
0010 TEST_REQS_FW_SET_CUSTOM_PATH="yes"
0011 TEST_DIR=$(dirname $0)
0012 source $TEST_DIR/fw_lib.sh
0013 
0014 RUN_XZ="xz -C crc32 --lzma2=dict=2MiB"
0015 RUN_ZSTD="zstd -q"
0016 
0017 check_mods
0018 check_setup
0019 verify_reqs
0020 setup_tmp_file
0021 
0022 trap "test_finish" EXIT
0023 
0024 if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
0025         # Turn down the timeout so failures don't take so long.
0026         echo 1 >/sys/class/firmware/timeout
0027 fi
0028 
0029 if printf '\000' >"$DIR"/trigger_request 2> /dev/null; then
0030         echo "$0: empty filename should not succeed" >&2
0031         exit 1
0032 fi
0033 
0034 if [ ! -e "$DIR"/trigger_async_request ]; then
0035         echo "$0: empty filename: async trigger not present, ignoring test" >&2
0036         exit $ksft_skip
0037 else
0038         if printf '\000' >"$DIR"/trigger_async_request 2> /dev/null; then
0039                 echo "$0: empty filename should not succeed (async)" >&2
0040                 exit 1
0041         fi
0042 fi
0043 
0044 # Request a firmware that doesn't exist, it should fail.
0045 if echo -n "nope-$NAME" >"$DIR"/trigger_request 2> /dev/null; then
0046         echo "$0: firmware shouldn't have loaded" >&2
0047         exit 1
0048 fi
0049 if diff -q "$FW" /dev/test_firmware >/dev/null ; then
0050         echo "$0: firmware was not expected to match" >&2
0051         exit 1
0052 else
0053         if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
0054                 echo "$0: timeout works"
0055         fi
0056 fi
0057 
0058 # This should succeed via kernel load or will fail after 1 second after
0059 # being handed over to the user helper, which won't find the fw either.
0060 if ! echo -n "$NAME" >"$DIR"/trigger_request ; then
0061         echo "$0: could not trigger request" >&2
0062         exit 1
0063 fi
0064 
0065 # Verify the contents are what we expect.
0066 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
0067         echo "$0: firmware was not loaded" >&2
0068         exit 1
0069 else
0070         echo "$0: filesystem loading works"
0071 fi
0072 
0073 # Try the asynchronous version too
0074 if [ ! -e "$DIR"/trigger_async_request ]; then
0075         echo "$0: firmware loading: async trigger not present, ignoring test" >&2
0076         exit $ksft_skip
0077 else
0078         if ! echo -n "$NAME" >"$DIR"/trigger_async_request ; then
0079                 echo "$0: could not trigger async request" >&2
0080                 exit 1
0081         fi
0082 
0083         # Verify the contents are what we expect.
0084         if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
0085                 echo "$0: firmware was not loaded (async)" >&2
0086                 exit 1
0087         else
0088                 echo "$0: async filesystem loading works"
0089         fi
0090 fi
0091 
0092 # Try platform (EFI embedded fw) loading too
0093 if [ ! -e "$DIR"/trigger_request_platform ]; then
0094         echo "$0: firmware loading: platform trigger not present, ignoring test" >&2
0095 else
0096         if printf '\000' >"$DIR"/trigger_request_platform 2> /dev/null; then
0097                 echo "$0: empty filename should not succeed (platform)" >&2
0098                 exit 1
0099         fi
0100 
0101         # Note we echo a non-existing name, since files on the file-system
0102         # are preferred over firmware embedded inside the platform's firmware
0103         # The test adds a fake entry with the requested name to the platform's
0104         # fw list, so the name does not matter as long as it does not exist
0105         if ! echo -n "nope-$NAME" >"$DIR"/trigger_request_platform ; then
0106                 echo "$0: could not trigger request platform" >&2
0107                 exit 1
0108         fi
0109 
0110         # The test verifies itself that the loaded firmware contents matches
0111         # the contents for the fake platform fw entry it added.
0112         echo "$0: platform loading works"
0113 fi
0114 
0115 ### Batched requests tests
0116 test_config_present()
0117 {
0118         if [ ! -f $DIR/reset ]; then
0119                 echo "Configuration triggers not present, ignoring test"
0120                 exit $ksft_skip
0121         fi
0122 }
0123 
0124 # Defaults :
0125 #
0126 # send_uevent: 1
0127 # sync_direct: 0
0128 # name: test-firmware.bin
0129 # num_requests: 4
0130 config_reset()
0131 {
0132         echo 1 >  $DIR/reset
0133 }
0134 
0135 release_all_firmware()
0136 {
0137         echo 1 >  $DIR/release_all_firmware
0138 }
0139 
0140 config_set_name()
0141 {
0142         echo -n $1 >  $DIR/config_name
0143 }
0144 
0145 config_set_into_buf()
0146 {
0147         echo 1 >  $DIR/config_into_buf
0148 }
0149 
0150 config_unset_into_buf()
0151 {
0152         echo 0 >  $DIR/config_into_buf
0153 }
0154 
0155 config_set_buf_size()
0156 {
0157         echo $1 >  $DIR/config_buf_size
0158 }
0159 
0160 config_set_file_offset()
0161 {
0162         echo $1 >  $DIR/config_file_offset
0163 }
0164 
0165 config_set_partial()
0166 {
0167         echo 1 >  $DIR/config_partial
0168 }
0169 
0170 config_unset_partial()
0171 {
0172         echo 0 >  $DIR/config_partial
0173 }
0174 
0175 config_set_sync_direct()
0176 {
0177         echo 1 >  $DIR/config_sync_direct
0178 }
0179 
0180 config_unset_sync_direct()
0181 {
0182         echo 0 >  $DIR/config_sync_direct
0183 }
0184 
0185 config_set_uevent()
0186 {
0187         echo 1 >  $DIR/config_send_uevent
0188 }
0189 
0190 config_unset_uevent()
0191 {
0192         echo 0 >  $DIR/config_send_uevent
0193 }
0194 
0195 config_trigger_sync()
0196 {
0197         echo -n 1 > $DIR/trigger_batched_requests 2>/dev/null
0198 }
0199 
0200 config_trigger_async()
0201 {
0202         echo -n 1 > $DIR/trigger_batched_requests_async 2> /dev/null
0203 }
0204 
0205 config_set_read_fw_idx()
0206 {
0207         echo -n $1 > $DIR/config_read_fw_idx 2> /dev/null
0208 }
0209 
0210 read_firmwares()
0211 {
0212         if [ "$(cat $DIR/config_into_buf)" == "1" ]; then
0213                 fwfile="$FW_INTO_BUF"
0214         else
0215                 fwfile="$FW"
0216         fi
0217         if [ "$1" = "componly" ]; then
0218                 fwfile="${fwfile}-orig"
0219         fi
0220         for i in $(seq 0 3); do
0221                 config_set_read_fw_idx $i
0222                 # Verify the contents are what we expect.
0223                 # -Z required for now -- check for yourself, md5sum
0224                 # on $FW and DIR/read_firmware will yield the same. Even
0225                 # cmp agrees, so something is off.
0226                 if ! diff -q -Z "$fwfile" $DIR/read_firmware 2>/dev/null ; then
0227                         echo "request #$i: firmware was not loaded" >&2
0228                         exit 1
0229                 fi
0230         done
0231 }
0232 
0233 read_partial_firmwares()
0234 {
0235         if [ "$(cat $DIR/config_into_buf)" == "1" ]; then
0236                 fwfile="${FW_INTO_BUF}"
0237         else
0238                 fwfile="${FW}"
0239         fi
0240 
0241         if [ "$1" = "componly" ]; then
0242                 fwfile="${fwfile}-orig"
0243         fi
0244 
0245         # Strip fwfile down to match partial offset and length
0246         partial_data="$(cat $fwfile)"
0247         partial_data="${partial_data:$2:$3}"
0248 
0249         for i in $(seq 0 3); do
0250                 config_set_read_fw_idx $i
0251 
0252                 read_firmware="$(cat $DIR/read_firmware)"
0253 
0254                 # Verify the contents are what we expect.
0255                 if [ $read_firmware != $partial_data ]; then
0256                         echo "request #$i: partial firmware was not loaded" >&2
0257                         exit 1
0258                 fi
0259         done
0260 }
0261 
0262 read_firmwares_expect_nofile()
0263 {
0264         for i in $(seq 0 3); do
0265                 config_set_read_fw_idx $i
0266                 # Ensures contents differ
0267                 if diff -q -Z "$FW" $DIR/read_firmware 2>/dev/null ; then
0268                         echo "request $i: file was not expected to match" >&2
0269                         exit 1
0270                 fi
0271         done
0272 }
0273 
0274 test_batched_request_firmware_nofile()
0275 {
0276         echo -n "Batched request_firmware() nofile try #$1: "
0277         config_reset
0278         config_set_name nope-test-firmware.bin
0279         config_trigger_sync
0280         read_firmwares_expect_nofile
0281         release_all_firmware
0282         echo "OK"
0283 }
0284 
0285 test_batched_request_firmware_into_buf_nofile()
0286 {
0287         echo -n "Batched request_firmware_into_buf() nofile try #$1: "
0288         config_reset
0289         config_set_name nope-test-firmware.bin
0290         config_set_into_buf
0291         config_trigger_sync
0292         read_firmwares_expect_nofile
0293         release_all_firmware
0294         echo "OK"
0295 }
0296 
0297 test_request_partial_firmware_into_buf_nofile()
0298 {
0299         echo -n "Test request_partial_firmware_into_buf() off=$1 size=$2 nofile: "
0300         config_reset
0301         config_set_name nope-test-firmware.bin
0302         config_set_into_buf
0303         config_set_partial
0304         config_set_buf_size $2
0305         config_set_file_offset $1
0306         config_trigger_sync
0307         read_firmwares_expect_nofile
0308         release_all_firmware
0309         echo "OK"
0310 }
0311 
0312 test_batched_request_firmware_direct_nofile()
0313 {
0314         echo -n "Batched request_firmware_direct() nofile try #$1: "
0315         config_reset
0316         config_set_name nope-test-firmware.bin
0317         config_set_sync_direct
0318         config_trigger_sync
0319         release_all_firmware
0320         echo "OK"
0321 }
0322 
0323 test_request_firmware_nowait_uevent_nofile()
0324 {
0325         echo -n "Batched request_firmware_nowait(uevent=true) nofile try #$1: "
0326         config_reset
0327         config_set_name nope-test-firmware.bin
0328         config_trigger_async
0329         release_all_firmware
0330         echo "OK"
0331 }
0332 
0333 test_wait_and_cancel_custom_load()
0334 {
0335         if [ "$HAS_FW_LOADER_USER_HELPER" != "yes" ]; then
0336                 return
0337         fi
0338         local timeout=10
0339         name=$1
0340         while [ ! -e "$DIR"/"$name"/loading ]; do
0341                 sleep 0.1
0342                 timeout=$(( $timeout - 1 ))
0343                 if [ "$timeout" -eq 0 ]; then
0344                         echo "firmware interface never appeared:" >&2
0345                         echo "$DIR/$name/loading" >&2
0346                         exit 1
0347                 fi
0348         done
0349         echo -1 >"$DIR"/"$name"/loading
0350 }
0351 
0352 test_request_firmware_nowait_custom_nofile()
0353 {
0354         echo -n "Batched request_firmware_nowait(uevent=false) nofile try #$1: "
0355         config_reset
0356         config_unset_uevent
0357         RANDOM_FILE_PATH=$(setup_random_file_fake)
0358         RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
0359         config_set_name $RANDOM_FILE
0360         config_trigger_async &
0361         test_wait_and_cancel_custom_load $RANDOM_FILE
0362         wait
0363         release_all_firmware
0364         echo "OK"
0365 }
0366 
0367 test_batched_request_firmware()
0368 {
0369         echo -n "Batched request_firmware() $2 try #$1: "
0370         config_reset
0371         config_trigger_sync
0372         read_firmwares $2
0373         release_all_firmware
0374         echo "OK"
0375 }
0376 
0377 test_batched_request_firmware_into_buf()
0378 {
0379         echo -n "Batched request_firmware_into_buf() $2 try #$1: "
0380         config_reset
0381         config_set_name $TEST_FIRMWARE_INTO_BUF_FILENAME
0382         config_set_into_buf
0383         config_trigger_sync
0384         read_firmwares $2
0385         release_all_firmware
0386         echo "OK"
0387 }
0388 
0389 test_batched_request_firmware_direct()
0390 {
0391         echo -n "Batched request_firmware_direct() $2 try #$1: "
0392         config_reset
0393         config_set_sync_direct
0394         config_trigger_sync
0395         release_all_firmware
0396         echo "OK"
0397 }
0398 
0399 test_request_firmware_nowait_uevent()
0400 {
0401         echo -n "Batched request_firmware_nowait(uevent=true) $2 try #$1: "
0402         config_reset
0403         config_trigger_async
0404         release_all_firmware
0405         echo "OK"
0406 }
0407 
0408 test_request_firmware_nowait_custom()
0409 {
0410         echo -n "Batched request_firmware_nowait(uevent=false) $2 try #$1: "
0411         config_reset
0412         config_unset_uevent
0413         RANDOM_FILE_PATH=$(setup_random_file)
0414         RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
0415         if [ -n "$2" -a "$2" != "normal" ]; then
0416                 compress_"$2"_"$COMPRESS_FORMAT" $RANDOM_FILE_PATH
0417         fi
0418         config_set_name $RANDOM_FILE
0419         config_trigger_async
0420         release_all_firmware
0421         echo "OK"
0422 }
0423 
0424 test_request_partial_firmware_into_buf()
0425 {
0426         echo -n "Test request_partial_firmware_into_buf() off=$1 size=$2: "
0427         config_reset
0428         config_set_name $TEST_FIRMWARE_INTO_BUF_FILENAME
0429         config_set_into_buf
0430         config_set_partial
0431         config_set_buf_size $2
0432         config_set_file_offset $1
0433         config_trigger_sync
0434         read_partial_firmwares normal $1 $2
0435         release_all_firmware
0436         echo "OK"
0437 }
0438 
0439 do_tests ()
0440 {
0441         mode="$1"
0442         suffix="$2"
0443 
0444         for i in $(seq 1 5); do
0445                 test_batched_request_firmware$suffix $i $mode
0446         done
0447 
0448         for i in $(seq 1 5); do
0449                 test_batched_request_firmware_into_buf$suffix $i $mode
0450         done
0451 
0452         for i in $(seq 1 5); do
0453                 test_batched_request_firmware_direct$suffix $i $mode
0454         done
0455 
0456         for i in $(seq 1 5); do
0457                 test_request_firmware_nowait_uevent$suffix $i $mode
0458         done
0459 
0460         for i in $(seq 1 5); do
0461                 test_request_firmware_nowait_custom$suffix $i $mode
0462         done
0463 }
0464 
0465 # Only continue if batched request triggers are present on the
0466 # test-firmware driver
0467 test_config_present
0468 
0469 # test with the file present
0470 echo
0471 echo "Testing with the file present..."
0472 do_tests normal
0473 
0474 # Partial loads cannot use fallback, so do not repeat tests.
0475 test_request_partial_firmware_into_buf 0 10
0476 test_request_partial_firmware_into_buf 0 5
0477 test_request_partial_firmware_into_buf 1 6
0478 test_request_partial_firmware_into_buf 2 10
0479 
0480 # Test for file not found, errors are expected, the failure would be
0481 # a hung task, which would require a hard reset.
0482 echo
0483 echo "Testing with the file missing..."
0484 do_tests nofile _nofile
0485 
0486 # Partial loads cannot use fallback, so do not repeat tests.
0487 test_request_partial_firmware_into_buf_nofile 0 10
0488 test_request_partial_firmware_into_buf_nofile 0 5
0489 test_request_partial_firmware_into_buf_nofile 1 6
0490 test_request_partial_firmware_into_buf_nofile 2 10
0491 
0492 test_request_firmware_compressed ()
0493 {
0494         export COMPRESS_FORMAT="$1"
0495 
0496         # test with both files present
0497         compress_both_"$COMPRESS_FORMAT" $FW
0498         compress_both_"$COMPRESS_FORMAT" $FW_INTO_BUF
0499 
0500         config_set_name $NAME
0501         echo
0502         echo "Testing with both plain and $COMPRESS_FORMAT files present..."
0503         do_tests both
0504 
0505         # test with only compressed file present
0506         mv "$FW" "${FW}-orig"
0507         mv "$FW_INTO_BUF" "${FW_INTO_BUF}-orig"
0508 
0509         config_set_name $NAME
0510         echo
0511         echo "Testing with only $COMPRESS_FORMAT file present..."
0512         do_tests componly
0513 
0514         mv "${FW}-orig" "$FW"
0515         mv "${FW_INTO_BUF}-orig" "$FW_INTO_BUF"
0516 }
0517 
0518 compress_both_XZ ()
0519 {
0520         $RUN_XZ -k "$@"
0521 }
0522 
0523 compress_componly_XZ ()
0524 {
0525         $RUN_XZ "$@"
0526 }
0527 
0528 compress_both_ZSTD ()
0529 {
0530         $RUN_ZSTD -k "$@"
0531 }
0532 
0533 compress_componly_ZSTD ()
0534 {
0535         $RUN_ZSTD --rm "$@"
0536 }
0537 
0538 if test "$HAS_FW_LOADER_COMPRESS_XZ" = "yes"; then
0539         test_request_firmware_compressed XZ
0540 fi
0541 
0542 if test "$HAS_FW_LOADER_COMPRESS_ZSTD" = "yes"; then
0543         test_request_firmware_compressed ZSTD
0544 fi
0545 
0546 exit 0