Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/firmware/fw_filesystem.sh
26285 views
1
#!/bin/bash
2
# SPDX-License-Identifier: GPL-2.0
3
# This validates that the kernel will load firmware out of its list of
4
# firmware locations on disk. Since the user helper does similar work,
5
# we reset the custom load directory to a location the user helper doesn't
6
# know so we can be sure we're not accidentally testing the user helper.
7
set -e
8
9
TEST_REQS_FW_SYSFS_FALLBACK="no"
10
TEST_REQS_FW_SET_CUSTOM_PATH="yes"
11
TEST_DIR=$(dirname $0)
12
source $TEST_DIR/fw_lib.sh
13
14
RUN_XZ="xz -C crc32 --lzma2=dict=2MiB"
15
RUN_ZSTD="zstd -q"
16
17
check_mods
18
check_setup
19
verify_reqs
20
setup_tmp_file
21
22
trap "test_finish" EXIT
23
24
if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
25
# Turn down the timeout so failures don't take so long.
26
echo 1 >/sys/class/firmware/timeout
27
fi
28
29
if printf '\000' >"$DIR"/trigger_request 2> /dev/null; then
30
echo "$0: empty filename should not succeed" >&2
31
exit 1
32
fi
33
34
if [ ! -e "$DIR"/trigger_async_request ]; then
35
echo "$0: empty filename: async trigger not present, ignoring test" >&2
36
exit $ksft_skip
37
else
38
if printf '\000' >"$DIR"/trigger_async_request 2> /dev/null; then
39
echo "$0: empty filename should not succeed (async)" >&2
40
exit 1
41
fi
42
fi
43
44
# Request a firmware that doesn't exist, it should fail.
45
if echo -n "nope-$NAME" >"$DIR"/trigger_request 2> /dev/null; then
46
echo "$0: firmware shouldn't have loaded" >&2
47
exit 1
48
fi
49
if diff -q "$FW" /dev/test_firmware >/dev/null ; then
50
echo "$0: firmware was not expected to match" >&2
51
exit 1
52
else
53
if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
54
echo "$0: timeout works"
55
fi
56
fi
57
58
# This should succeed via kernel load or will fail after 1 second after
59
# being handed over to the user helper, which won't find the fw either.
60
if ! echo -n "$NAME" >"$DIR"/trigger_request ; then
61
echo "$0: could not trigger request" >&2
62
exit 1
63
fi
64
65
# Verify the contents are what we expect.
66
if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
67
echo "$0: firmware was not loaded" >&2
68
exit 1
69
else
70
echo "$0: filesystem loading works"
71
fi
72
73
# Try the asynchronous version too
74
if [ ! -e "$DIR"/trigger_async_request ]; then
75
echo "$0: firmware loading: async trigger not present, ignoring test" >&2
76
exit $ksft_skip
77
else
78
if ! echo -n "$NAME" >"$DIR"/trigger_async_request ; then
79
echo "$0: could not trigger async request" >&2
80
exit 1
81
fi
82
83
# Verify the contents are what we expect.
84
if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
85
echo "$0: firmware was not loaded (async)" >&2
86
exit 1
87
else
88
echo "$0: async filesystem loading works"
89
fi
90
fi
91
92
# Try platform (EFI embedded fw) loading too
93
if [ ! -e "$DIR"/trigger_request_platform ]; then
94
echo "$0: firmware loading: platform trigger not present, ignoring test" >&2
95
else
96
if printf '\000' >"$DIR"/trigger_request_platform 2> /dev/null; then
97
echo "$0: empty filename should not succeed (platform)" >&2
98
exit 1
99
fi
100
101
# Note we echo a non-existing name, since files on the file-system
102
# are preferred over firmware embedded inside the platform's firmware
103
# The test adds a fake entry with the requested name to the platform's
104
# fw list, so the name does not matter as long as it does not exist
105
if ! echo -n "nope-$NAME" >"$DIR"/trigger_request_platform ; then
106
echo "$0: could not trigger request platform" >&2
107
exit 1
108
fi
109
110
# The test verifies itself that the loaded firmware contents matches
111
# the contents for the fake platform fw entry it added.
112
echo "$0: platform loading works"
113
fi
114
115
### Batched requests tests
116
test_config_present()
117
{
118
if [ ! -f $DIR/reset ]; then
119
echo "Configuration triggers not present, ignoring test"
120
exit $ksft_skip
121
fi
122
}
123
124
# Defaults :
125
#
126
# send_uevent: 1
127
# sync_direct: 0
128
# name: test-firmware.bin
129
# num_requests: 4
130
config_reset()
131
{
132
echo 1 > $DIR/reset
133
}
134
135
release_all_firmware()
136
{
137
echo 1 > $DIR/release_all_firmware
138
}
139
140
config_set_name()
141
{
142
echo -n $1 > $DIR/config_name
143
}
144
145
config_set_into_buf()
146
{
147
echo 1 > $DIR/config_into_buf
148
}
149
150
config_unset_into_buf()
151
{
152
echo 0 > $DIR/config_into_buf
153
}
154
155
config_set_buf_size()
156
{
157
echo $1 > $DIR/config_buf_size
158
}
159
160
config_set_file_offset()
161
{
162
echo $1 > $DIR/config_file_offset
163
}
164
165
config_set_partial()
166
{
167
echo 1 > $DIR/config_partial
168
}
169
170
config_unset_partial()
171
{
172
echo 0 > $DIR/config_partial
173
}
174
175
config_set_sync_direct()
176
{
177
echo 1 > $DIR/config_sync_direct
178
}
179
180
config_unset_sync_direct()
181
{
182
echo 0 > $DIR/config_sync_direct
183
}
184
185
config_set_uevent()
186
{
187
echo 1 > $DIR/config_send_uevent
188
}
189
190
config_unset_uevent()
191
{
192
echo 0 > $DIR/config_send_uevent
193
}
194
195
config_trigger_sync()
196
{
197
echo -n 1 > $DIR/trigger_batched_requests 2>/dev/null
198
}
199
200
config_trigger_async()
201
{
202
echo -n 1 > $DIR/trigger_batched_requests_async 2> /dev/null
203
}
204
205
config_set_read_fw_idx()
206
{
207
echo -n $1 > $DIR/config_read_fw_idx 2> /dev/null
208
}
209
210
read_firmwares()
211
{
212
if [ "$(cat $DIR/config_into_buf)" == "1" ]; then
213
fwfile="$FW_INTO_BUF"
214
else
215
fwfile="$FW"
216
fi
217
if [ "$1" = "componly" ]; then
218
fwfile="${fwfile}-orig"
219
fi
220
for i in $(seq 0 3); do
221
config_set_read_fw_idx $i
222
# Verify the contents are what we expect.
223
# -Z required for now -- check for yourself, md5sum
224
# on $FW and DIR/read_firmware will yield the same. Even
225
# cmp agrees, so something is off.
226
if ! diff -q -Z "$fwfile" $DIR/read_firmware 2>/dev/null ; then
227
echo "request #$i: firmware was not loaded" >&2
228
exit 1
229
fi
230
done
231
}
232
233
read_partial_firmwares()
234
{
235
if [ "$(cat $DIR/config_into_buf)" == "1" ]; then
236
fwfile="${FW_INTO_BUF}"
237
else
238
fwfile="${FW}"
239
fi
240
241
if [ "$1" = "componly" ]; then
242
fwfile="${fwfile}-orig"
243
fi
244
245
# Strip fwfile down to match partial offset and length
246
partial_data="$(cat $fwfile)"
247
partial_data="${partial_data:$2:$3}"
248
249
for i in $(seq 0 3); do
250
config_set_read_fw_idx $i
251
252
read_firmware="$(cat $DIR/read_firmware)"
253
254
# Verify the contents are what we expect.
255
if [ $read_firmware != $partial_data ]; then
256
echo "request #$i: partial firmware was not loaded" >&2
257
exit 1
258
fi
259
done
260
}
261
262
read_firmwares_expect_nofile()
263
{
264
for i in $(seq 0 3); do
265
config_set_read_fw_idx $i
266
# Ensures contents differ
267
if diff -q -Z "$FW" $DIR/read_firmware 2>/dev/null ; then
268
echo "request $i: file was not expected to match" >&2
269
exit 1
270
fi
271
done
272
}
273
274
test_batched_request_firmware_nofile()
275
{
276
echo -n "Batched request_firmware() nofile try #$1: "
277
config_reset
278
config_set_name nope-test-firmware.bin
279
config_trigger_sync
280
read_firmwares_expect_nofile
281
release_all_firmware
282
echo "OK"
283
}
284
285
test_batched_request_firmware_into_buf_nofile()
286
{
287
echo -n "Batched request_firmware_into_buf() nofile try #$1: "
288
config_reset
289
config_set_name nope-test-firmware.bin
290
config_set_into_buf
291
config_trigger_sync
292
read_firmwares_expect_nofile
293
release_all_firmware
294
echo "OK"
295
}
296
297
test_request_partial_firmware_into_buf_nofile()
298
{
299
echo -n "Test request_partial_firmware_into_buf() off=$1 size=$2 nofile: "
300
config_reset
301
config_set_name nope-test-firmware.bin
302
config_set_into_buf
303
config_set_partial
304
config_set_buf_size $2
305
config_set_file_offset $1
306
config_trigger_sync
307
read_firmwares_expect_nofile
308
release_all_firmware
309
echo "OK"
310
}
311
312
test_batched_request_firmware_direct_nofile()
313
{
314
echo -n "Batched request_firmware_direct() nofile try #$1: "
315
config_reset
316
config_set_name nope-test-firmware.bin
317
config_set_sync_direct
318
config_trigger_sync
319
release_all_firmware
320
echo "OK"
321
}
322
323
test_request_firmware_nowait_uevent_nofile()
324
{
325
echo -n "Batched request_firmware_nowait(uevent=true) nofile try #$1: "
326
config_reset
327
config_set_name nope-test-firmware.bin
328
config_trigger_async
329
release_all_firmware
330
echo "OK"
331
}
332
333
test_wait_and_cancel_custom_load()
334
{
335
if [ "$HAS_FW_LOADER_USER_HELPER" != "yes" ]; then
336
return
337
fi
338
local timeout=10
339
name=$1
340
while [ ! -e "$DIR"/"$name"/loading ]; do
341
sleep 0.1
342
timeout=$(( $timeout - 1 ))
343
if [ "$timeout" -eq 0 ]; then
344
echo "firmware interface never appeared:" >&2
345
echo "$DIR/$name/loading" >&2
346
exit 1
347
fi
348
done
349
echo -1 >"$DIR"/"$name"/loading
350
}
351
352
test_request_firmware_nowait_custom_nofile()
353
{
354
echo -n "Batched request_firmware_nowait(uevent=false) nofile try #$1: "
355
config_reset
356
config_unset_uevent
357
RANDOM_FILE_PATH=$(setup_random_file_fake)
358
RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
359
config_set_name $RANDOM_FILE
360
config_trigger_async &
361
test_wait_and_cancel_custom_load $RANDOM_FILE
362
wait
363
release_all_firmware
364
echo "OK"
365
}
366
367
test_batched_request_firmware()
368
{
369
echo -n "Batched request_firmware() $2 try #$1: "
370
config_reset
371
config_trigger_sync
372
read_firmwares $2
373
release_all_firmware
374
echo "OK"
375
}
376
377
test_batched_request_firmware_into_buf()
378
{
379
echo -n "Batched request_firmware_into_buf() $2 try #$1: "
380
config_reset
381
config_set_name $TEST_FIRMWARE_INTO_BUF_FILENAME
382
config_set_into_buf
383
config_trigger_sync
384
read_firmwares $2
385
release_all_firmware
386
echo "OK"
387
}
388
389
test_batched_request_firmware_direct()
390
{
391
echo -n "Batched request_firmware_direct() $2 try #$1: "
392
config_reset
393
config_set_sync_direct
394
config_trigger_sync
395
release_all_firmware
396
echo "OK"
397
}
398
399
test_request_firmware_nowait_uevent()
400
{
401
echo -n "Batched request_firmware_nowait(uevent=true) $2 try #$1: "
402
config_reset
403
config_trigger_async
404
release_all_firmware
405
echo "OK"
406
}
407
408
test_request_firmware_nowait_custom()
409
{
410
echo -n "Batched request_firmware_nowait(uevent=false) $2 try #$1: "
411
config_reset
412
config_unset_uevent
413
RANDOM_FILE_PATH=$(setup_random_file)
414
RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
415
if [ -n "$2" -a "$2" != "normal" ]; then
416
compress_"$2"_"$COMPRESS_FORMAT" $RANDOM_FILE_PATH
417
fi
418
config_set_name $RANDOM_FILE
419
config_trigger_async
420
release_all_firmware
421
echo "OK"
422
}
423
424
test_request_partial_firmware_into_buf()
425
{
426
echo -n "Test request_partial_firmware_into_buf() off=$1 size=$2: "
427
config_reset
428
config_set_name $TEST_FIRMWARE_INTO_BUF_FILENAME
429
config_set_into_buf
430
config_set_partial
431
config_set_buf_size $2
432
config_set_file_offset $1
433
config_trigger_sync
434
read_partial_firmwares normal $1 $2
435
release_all_firmware
436
echo "OK"
437
}
438
439
do_tests ()
440
{
441
mode="$1"
442
suffix="$2"
443
444
for i in $(seq 1 5); do
445
test_batched_request_firmware$suffix $i $mode
446
done
447
448
for i in $(seq 1 5); do
449
test_batched_request_firmware_into_buf$suffix $i $mode
450
done
451
452
for i in $(seq 1 5); do
453
test_batched_request_firmware_direct$suffix $i $mode
454
done
455
456
for i in $(seq 1 5); do
457
test_request_firmware_nowait_uevent$suffix $i $mode
458
done
459
460
for i in $(seq 1 5); do
461
test_request_firmware_nowait_custom$suffix $i $mode
462
done
463
}
464
465
# Only continue if batched request triggers are present on the
466
# test-firmware driver
467
test_config_present
468
469
# test with the file present
470
echo
471
echo "Testing with the file present..."
472
do_tests normal
473
474
# Partial loads cannot use fallback, so do not repeat tests.
475
test_request_partial_firmware_into_buf 0 10
476
test_request_partial_firmware_into_buf 0 5
477
test_request_partial_firmware_into_buf 1 6
478
test_request_partial_firmware_into_buf 2 10
479
480
# Test for file not found, errors are expected, the failure would be
481
# a hung task, which would require a hard reset.
482
echo
483
echo "Testing with the file missing..."
484
do_tests nofile _nofile
485
486
# Partial loads cannot use fallback, so do not repeat tests.
487
test_request_partial_firmware_into_buf_nofile 0 10
488
test_request_partial_firmware_into_buf_nofile 0 5
489
test_request_partial_firmware_into_buf_nofile 1 6
490
test_request_partial_firmware_into_buf_nofile 2 10
491
492
test_request_firmware_compressed ()
493
{
494
export COMPRESS_FORMAT="$1"
495
496
# test with both files present
497
compress_both_"$COMPRESS_FORMAT" $FW
498
compress_both_"$COMPRESS_FORMAT" $FW_INTO_BUF
499
500
config_set_name $NAME
501
echo
502
echo "Testing with both plain and $COMPRESS_FORMAT files present..."
503
do_tests both
504
505
# test with only compressed file present
506
mv "$FW" "${FW}-orig"
507
mv "$FW_INTO_BUF" "${FW_INTO_BUF}-orig"
508
509
config_set_name $NAME
510
echo
511
echo "Testing with only $COMPRESS_FORMAT file present..."
512
do_tests componly
513
514
mv "${FW}-orig" "$FW"
515
mv "${FW_INTO_BUF}-orig" "$FW_INTO_BUF"
516
}
517
518
compress_both_XZ ()
519
{
520
$RUN_XZ -k "$@"
521
}
522
523
compress_componly_XZ ()
524
{
525
$RUN_XZ "$@"
526
}
527
528
compress_both_ZSTD ()
529
{
530
$RUN_ZSTD -k "$@"
531
}
532
533
compress_componly_ZSTD ()
534
{
535
$RUN_ZSTD --rm "$@"
536
}
537
538
if test "$HAS_FW_LOADER_COMPRESS_XZ" = "yes"; then
539
test_request_firmware_compressed XZ
540
fi
541
542
if test "$HAS_FW_LOADER_COMPRESS_ZSTD" = "yes"; then
543
test_request_firmware_compressed ZSTD
544
fi
545
546
exit 0
547
548