xref: /openbmc/linux/tools/testing/selftests/firmware/fw_upload.sh (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1*a37dddddSRuss Weight#!/bin/bash
2*a37dddddSRuss Weight# SPDX-License-Identifier: GPL-2.0
3*a37dddddSRuss Weight# This validates the user-initiated fw upload mechanism of the firmware
4*a37dddddSRuss Weight# loader. It verifies that one or more firmware devices can be created
5*a37dddddSRuss Weight# for a device driver. It also verifies the data transfer, the
6*a37dddddSRuss Weight# cancellation support, and the error flows.
7*a37dddddSRuss Weightset -e
8*a37dddddSRuss Weight
9*a37dddddSRuss WeightTEST_REQS_FW_UPLOAD="yes"
10*a37dddddSRuss WeightTEST_DIR=$(dirname $0)
11*a37dddddSRuss Weight
12*a37dddddSRuss Weightprogress_states="preparing transferring  programming"
13*a37dddddSRuss Weighterrors="hw-error
14*a37dddddSRuss Weight	timeout
15*a37dddddSRuss Weight	device-busy
16*a37dddddSRuss Weight	invalid-file-size
17*a37dddddSRuss Weight	read-write-error
18*a37dddddSRuss Weight	flash-wearout"
19*a37dddddSRuss Weighterror_abort="user-abort"
20*a37dddddSRuss Weightfwname1=fw1
21*a37dddddSRuss Weightfwname2=fw2
22*a37dddddSRuss Weightfwname3=fw3
23*a37dddddSRuss Weight
24*a37dddddSRuss Weightsource $TEST_DIR/fw_lib.sh
25*a37dddddSRuss Weight
26*a37dddddSRuss Weightcheck_mods
27*a37dddddSRuss Weightcheck_setup
28*a37dddddSRuss Weightverify_reqs
29*a37dddddSRuss Weight
30*a37dddddSRuss Weighttrap "upload_finish" EXIT
31*a37dddddSRuss Weight
32*a37dddddSRuss Weightupload_finish() {
33*a37dddddSRuss Weight	local fwdevs="$fwname1 $fwname2 $fwname3"
34*a37dddddSRuss Weight
35*a37dddddSRuss Weight	for name in $fwdevs; do
36*a37dddddSRuss Weight		if [ -e "$DIR/$name" ]; then
37*a37dddddSRuss Weight			echo -n "$name" > "$DIR"/upload_unregister
38*a37dddddSRuss Weight		fi
39*a37dddddSRuss Weight	done
40*a37dddddSRuss Weight}
41*a37dddddSRuss Weight
42*a37dddddSRuss Weightupload_fw() {
43*a37dddddSRuss Weight	local name="$1"
44*a37dddddSRuss Weight	local file="$2"
45*a37dddddSRuss Weight
46*a37dddddSRuss Weight	echo 1 > "$DIR"/"$name"/loading
47*a37dddddSRuss Weight	cat "$file" > "$DIR"/"$name"/data
48*a37dddddSRuss Weight	echo 0 > "$DIR"/"$name"/loading
49*a37dddddSRuss Weight}
50*a37dddddSRuss Weight
51*a37dddddSRuss Weightverify_fw() {
52*a37dddddSRuss Weight	local name="$1"
53*a37dddddSRuss Weight	local file="$2"
54*a37dddddSRuss Weight
55*a37dddddSRuss Weight	echo -n "$name" > "$DIR"/config_upload_name
56*a37dddddSRuss Weight	if ! cmp "$file" "$DIR"/upload_read > /dev/null 2>&1; then
57*a37dddddSRuss Weight		echo "$0: firmware compare for $name did not match" >&2
58*a37dddddSRuss Weight		exit 1
59*a37dddddSRuss Weight	fi
60*a37dddddSRuss Weight
61*a37dddddSRuss Weight	echo "$0: firmware upload for $name works" >&2
62*a37dddddSRuss Weight	return 0
63*a37dddddSRuss Weight}
64*a37dddddSRuss Weight
65*a37dddddSRuss Weightinject_error() {
66*a37dddddSRuss Weight	local name="$1"
67*a37dddddSRuss Weight	local status="$2"
68*a37dddddSRuss Weight	local error="$3"
69*a37dddddSRuss Weight
70*a37dddddSRuss Weight	echo 1 > "$DIR"/"$name"/loading
71*a37dddddSRuss Weight	echo -n "inject":"$status":"$error" > "$DIR"/"$name"/data
72*a37dddddSRuss Weight	echo 0 > "$DIR"/"$name"/loading
73*a37dddddSRuss Weight}
74*a37dddddSRuss Weight
75*a37dddddSRuss Weightawait_status() {
76*a37dddddSRuss Weight	local name="$1"
77*a37dddddSRuss Weight	local expected="$2"
78*a37dddddSRuss Weight	local status
79*a37dddddSRuss Weight	local i
80*a37dddddSRuss Weight
81*a37dddddSRuss Weight	let i=0
82*a37dddddSRuss Weight	while [ $i -lt 50 ]; do
83*a37dddddSRuss Weight		status=$(cat "$DIR"/"$name"/status)
84*a37dddddSRuss Weight		if [ "$status" = "$expected" ]; then
85*a37dddddSRuss Weight			return 0;
86*a37dddddSRuss Weight		fi
87*a37dddddSRuss Weight		sleep 1e-03
88*a37dddddSRuss Weight		let i=$i+1
89*a37dddddSRuss Weight	done
90*a37dddddSRuss Weight
91*a37dddddSRuss Weight	echo "$0: Invalid status: Expected $expected, Actual $status" >&2
92*a37dddddSRuss Weight	return 1;
93*a37dddddSRuss Weight}
94*a37dddddSRuss Weight
95*a37dddddSRuss Weightawait_idle() {
96*a37dddddSRuss Weight	local name="$1"
97*a37dddddSRuss Weight
98*a37dddddSRuss Weight	await_status "$name" "idle"
99*a37dddddSRuss Weight	return $?
100*a37dddddSRuss Weight}
101*a37dddddSRuss Weight
102*a37dddddSRuss Weightexpect_error() {
103*a37dddddSRuss Weight	local name="$1"
104*a37dddddSRuss Weight	local expected="$2"
105*a37dddddSRuss Weight	local error=$(cat "$DIR"/"$name"/error)
106*a37dddddSRuss Weight
107*a37dddddSRuss Weight	if [ "$error" != "$expected" ]; then
108*a37dddddSRuss Weight		echo "Invalid error: Expected $expected, Actual $error" >&2
109*a37dddddSRuss Weight		return 1
110*a37dddddSRuss Weight	fi
111*a37dddddSRuss Weight
112*a37dddddSRuss Weight	return 0
113*a37dddddSRuss Weight}
114*a37dddddSRuss Weight
115*a37dddddSRuss Weightrandom_firmware() {
116*a37dddddSRuss Weight	local bs="$1"
117*a37dddddSRuss Weight	local count="$2"
118*a37dddddSRuss Weight	local file=$(mktemp -p /tmp uploadfwXXX.bin)
119*a37dddddSRuss Weight
120*a37dddddSRuss Weight	dd if=/dev/urandom of="$file" bs="$bs" count="$count" > /dev/null 2>&1
121*a37dddddSRuss Weight	echo "$file"
122*a37dddddSRuss Weight}
123*a37dddddSRuss Weight
124*a37dddddSRuss Weighttest_upload_cancel() {
125*a37dddddSRuss Weight	local name="$1"
126*a37dddddSRuss Weight	local status
127*a37dddddSRuss Weight
128*a37dddddSRuss Weight	for status in $progress_states; do
129*a37dddddSRuss Weight		inject_error $name $status $error_abort
130*a37dddddSRuss Weight		if ! await_status $name $status; then
131*a37dddddSRuss Weight			exit 1
132*a37dddddSRuss Weight		fi
133*a37dddddSRuss Weight
134*a37dddddSRuss Weight		echo 1 > "$DIR"/"$name"/cancel
135*a37dddddSRuss Weight
136*a37dddddSRuss Weight		if ! await_idle $name; then
137*a37dddddSRuss Weight			exit 1
138*a37dddddSRuss Weight		fi
139*a37dddddSRuss Weight
140*a37dddddSRuss Weight		if ! expect_error $name "$status":"$error_abort"; then
141*a37dddddSRuss Weight			exit 1
142*a37dddddSRuss Weight		fi
143*a37dddddSRuss Weight	done
144*a37dddddSRuss Weight
145*a37dddddSRuss Weight	echo "$0: firmware upload cancellation works"
146*a37dddddSRuss Weight	return 0
147*a37dddddSRuss Weight}
148*a37dddddSRuss Weight
149*a37dddddSRuss Weighttest_error_handling() {
150*a37dddddSRuss Weight	local name=$1
151*a37dddddSRuss Weight	local status
152*a37dddddSRuss Weight	local error
153*a37dddddSRuss Weight
154*a37dddddSRuss Weight	for status in $progress_states; do
155*a37dddddSRuss Weight		for error in $errors; do
156*a37dddddSRuss Weight			inject_error $name $status $error
157*a37dddddSRuss Weight
158*a37dddddSRuss Weight			if ! await_idle $name; then
159*a37dddddSRuss Weight				exit 1
160*a37dddddSRuss Weight			fi
161*a37dddddSRuss Weight
162*a37dddddSRuss Weight			if ! expect_error $name "$status":"$error"; then
163*a37dddddSRuss Weight				exit 1
164*a37dddddSRuss Weight			fi
165*a37dddddSRuss Weight
166*a37dddddSRuss Weight		done
167*a37dddddSRuss Weight	done
168*a37dddddSRuss Weight	echo "$0: firmware upload error handling works"
169*a37dddddSRuss Weight}
170*a37dddddSRuss Weight
171*a37dddddSRuss Weighttest_fw_too_big() {
172*a37dddddSRuss Weight	local name=$1
173*a37dddddSRuss Weight	local fw_too_big=`random_firmware 512 5`
174*a37dddddSRuss Weight	local expected="preparing:invalid-file-size"
175*a37dddddSRuss Weight
176*a37dddddSRuss Weight	upload_fw $name $fw_too_big
177*a37dddddSRuss Weight	rm -f $fw_too_big
178*a37dddddSRuss Weight
179*a37dddddSRuss Weight	if ! await_idle $name; then
180*a37dddddSRuss Weight		exit 1
181*a37dddddSRuss Weight	fi
182*a37dddddSRuss Weight
183*a37dddddSRuss Weight	if ! expect_error $name $expected; then
184*a37dddddSRuss Weight		exit 1
185*a37dddddSRuss Weight	fi
186*a37dddddSRuss Weight
187*a37dddddSRuss Weight	echo "$0: oversized firmware error handling works"
188*a37dddddSRuss Weight}
189*a37dddddSRuss Weight
190*a37dddddSRuss Weightecho -n "$fwname1" > "$DIR"/upload_register
191*a37dddddSRuss Weightecho -n "$fwname2" > "$DIR"/upload_register
192*a37dddddSRuss Weightecho -n "$fwname3" > "$DIR"/upload_register
193*a37dddddSRuss Weight
194*a37dddddSRuss Weighttest_upload_cancel $fwname1
195*a37dddddSRuss Weighttest_error_handling $fwname1
196*a37dddddSRuss Weighttest_fw_too_big $fwname1
197*a37dddddSRuss Weight
198*a37dddddSRuss Weightfw_file1=`random_firmware 512 4`
199*a37dddddSRuss Weightfw_file2=`random_firmware 512 3`
200*a37dddddSRuss Weightfw_file3=`random_firmware 512 2`
201*a37dddddSRuss Weight
202*a37dddddSRuss Weightupload_fw $fwname1 $fw_file1
203*a37dddddSRuss Weightupload_fw $fwname2 $fw_file2
204*a37dddddSRuss Weightupload_fw $fwname3 $fw_file3
205*a37dddddSRuss Weight
206*a37dddddSRuss Weightverify_fw ${fwname1} ${fw_file1}
207*a37dddddSRuss Weightverify_fw ${fwname2} ${fw_file2}
208*a37dddddSRuss Weightverify_fw ${fwname3} ${fw_file3}
209*a37dddddSRuss Weight
210*a37dddddSRuss Weightecho -n "$fwname1" > "$DIR"/upload_unregister
211*a37dddddSRuss Weightecho -n "$fwname2" > "$DIR"/upload_unregister
212*a37dddddSRuss Weightecho -n "$fwname3" > "$DIR"/upload_unregister
213*a37dddddSRuss Weight
214*a37dddddSRuss Weightexit 0
215