xref: /OK3568_Linux_fs/u-boot/scripts/build-tftp-firmware.sh (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1#!/bin/bash
2#
3# Copyright (c) 2021 Rockchip Electronics Co., Ltd
4# SPDX-License-Identifier: GPL-2.0
5#
6# The script to generate splited image and update.hdr for TFTP image upgrade.
7# 1. U-Boot have limited tftp download buffer, we have to split images into pieces for download
8# 2. Use FIT mechanism to record image pieces information in update.hdr: order, hash, signature, etc.
9# 3. The TFTP client download update.hdr and verify it (if need)
10# 4. The TFTP client download => verify => flash image pieces accorrding to update.hdr.
11#
12
13set -e
14
15HDR_SIZE=0x10000 # 64KB
16ARG_VERSION=0
17ARG_ROLLBACK_IDX=0
18ARG_FORCE_UPDATE=0
19SUFFIX=".part.img"
20GPT="gpt_env.txt"
21
22function help()
23{
24	echo
25	echo "Usage:"
26	echo "    $0 --image <dir> --size-MB <size> [optional args]"
27	echo
28	echo "    Mandory args:"
29	echo "        --image <dir>:    directory of image to upgrade"
30	echo "        --size-MB <size>: MB size unit for image to split into pieces. In Decimal integer: 1, 2, 3 ..."
31	echo
32	echo "    Optional args:"
33	echo "        --sign:           sign firmware with RSA key-pair in \"./keys\" directory"
34	echo "        --rollback-index <index>: rollback index in Decimal integer. It depends on \"--sign\""
35	echo "        --force-update:   enable force upgrade"
36	echo "        --config <file>:  config file"
37	echo "        --version <ver>:  firmware version in Decimal integer"
38	echo "        --clean:          clean generated files"
39	echo
40}
41
42function check_decimal()
43{
44	if [ -z $1 ]; then
45		help
46		exit 1
47	fi
48
49	DECIMAL=`echo $1 |sed 's/[0-9]//g'`
50	if [ ! -z ${DECIMAL} ]; then
51		echo "ERROR: $1 is not decimal integer"
52		help
53		exit 1
54	fi
55}
56
57function process_args()
58{
59	while [ $# -gt 0 ]; do
60		case $1 in
61			--help|-help|help|--h|-h)
62				help
63				exit
64				;;
65			--force-update)
66				ARG_FORCE_UPDATE="1"
67				shift 1
68				;;
69			--image)
70				ARG_IMAGE_DIR=$2
71				OUTPUT_DIR=${ARG_IMAGE_DIR}/output
72				shift 2
73				;;
74			--config)
75				ARG_CONFIG_FILE=$2
76				if [ ! -f ${ARG_CONFIG_FILE} ]; then
77					echo "ERROR: No ${ARG_CONFIG_FILE}"
78					exit 1
79				fi
80				shift 2
81				;;
82			--rollback-index)
83				ARG_ROLLBACK_IDX=$2
84				check_decimal $2
85				shift 2
86				;;
87			--sign)
88				ARG_SIGN="y"
89				shift 1
90				;;
91			--size-MB)
92				ARG_IMG_MB=$2
93				check_decimal $2
94				shift 2
95				;;
96			--version)
97				ARG_VERSION=$2
98				check_decimal $2
99				shift 2
100				;;
101			--clean)
102				rm -f *${SUFFIX} *.itb *.its *.dtb *.dts data2sign* *.hdr *.hash orderlist.txt
103				exit 0
104				;;
105			*)
106				echo "Invalid arg: $1"
107				help
108				exit 1
109				;;
110		esac
111	done
112
113	if [ -z ${ARG_IMG_MB} ]; then
114		help
115		exit 1
116	elif [ -z ${ARG_IMAGE_DIR} ]; then
117		help
118		exit 1
119	elif [ ! -d ${ARG_IMAGE_DIR} ]; then
120		echo "ERROR: No directory ${ARG_IMAGE_DIR}"
121		exit 1
122	fi
123
124	if [ "${ARG_SIGN}" == "y" ]; then
125		if [ ! -f keys/dev.key ]; then
126			echo "ERROR: No keys/dev.key"
127			exit 1
128		elif [ ! -f keys/dev.crt ]; then
129			echo "ERROR: No keys/dev.crt"
130			exit 1
131		fi
132	else
133		ARG_ROLLBACK_IDX=0
134	fi
135}
136
137function split_image()
138{
139	rm -rf ${OUTPUT_DIR}
140
141	if [ "${ARG_CONFIG_FILE}" ]; then
142		cp ${ARG_CONFIG_FILE} orderlist.txt
143	else
144		ls ${ARG_IMAGE_DIR} > orderlist.txt
145	fi
146
147	SEQ=0
148	cat orderlist.txt | while read IMAGE
149	do
150		if [ "${IMAGE}" == "${GPT}" ]; then
151			continue;
152		fi
153
154		NAME=`echo ${IMAGE} | awk -F "." '{ print $1 }'`
155		echo "=> split: ${IMAGE}"
156		if [ ! -f ${ARG_IMAGE_DIR}/${IMAGE} ]; then
157			echo "ERROR: No ${ARG_IMAGE_DIR}/${IMAGE}"
158			exit 1
159		fi
160
161		if [ ${SEQ} -lt 10 ]; then
162			SEQ_NAME="seq0${SEQ}-${NAME}"
163		else
164			SEQ_NAME="seq${SEQ}-${NAME}"
165		fi
166
167		split -b ${ARG_IMG_MB}M ${ARG_IMAGE_DIR}/${IMAGE} ${SEQ_NAME}- -d --additional-suffix=${SUFFIX}
168		SEQ=`expr ${SEQ} + 1`
169		ls ${SEQ_NAME}-*
170	done
171	echo
172}
173
174function gen_its()
175{
176cat > update.its << EOF
177/*
178 * Copyright (C) 2021 Rockchip Electronic Co.,Ltd
179 *
180 */
181
182/dts-v1/;
183
184/ {
185	description = "FIT Image with ATF/OP-TEE/U-Boot";
186	#address-cells = <1>;
187
188	images {
189EOF
190	if [ -f ${ARG_IMAGE_DIR}/${GPT} ]; then
191		cp ${ARG_IMAGE_DIR}/${GPT} ./
192		echo "		${GPT} {
193			data = /incbin/(\"./${GPT}\");
194			hash {
195				algo = \"sha256\";
196			};
197		};" >> update.its
198	fi
199
200	NUM=0
201	MAX=`ls -l *part* | wc -l`
202	for IMG in `ls -l *part* | awk '{ print $9 }'`
203	do
204		NAME=`echo ${IMG} | awk -F "." '{ print $1 }'`
205			echo "		${NAME} {
206			data = /incbin/(\"./${NAME}${SUFFIX}\");
207			hash {
208				algo = \"sha256\";
209			};
210		};" >> update.its
211
212		NUM=`expr ${NUM} + 1`
213		if [ ${NUM} -lt ${MAX} ]; then
214			FIRMWARES=${FIRMWARES}"\"${NAME}\", "
215		else
216			FIRMWARES=${FIRMWARES}"\"${NAME}\""
217			LAST_IMG=${NAME}
218		fi
219	done
220cat >> update.its << EOF
221	};
222
223	configurations {
224		default = "conf";
225		conf {
226			rollback-index = <${ARG_ROLLBACK_IDX}>;
227			force-update = <${ARG_FORCE_UPDATE}>;
228			image-size-MB = <${ARG_IMG_MB}>;
229			firmware = ${FIRMWARES};
230			signature {
231				algo = "sha256,rsa2048";
232				padding = "pss";
233				key-name-hint = "dev";
234				sign-images = "firmware";
235			};
236		};
237	};
238};
239EOF
240}
241
242function gen_update_hdr()
243{
244	# generate itb
245	if [ "${ARG_SIGN}" == "y" ]; then
246		# create a temporary dtb to store public-key, just for mkimage work normal.
247		SIGNED="signed"
248		cp update.its key.its
249		sed -i "/data =/d" key.its
250		dtc -I dts -O dtb key.its -o key.dtb
251
252		./mkimage -f update.its -k keys/ -K key.dtb -E -p ${HDR_SIZE} -r update.itb -v ${ARG_VERSION}
253		./fit_check_sign -f update.itb -k key.dtb
254	else
255		SIGNED="no-signed"
256		./mkimage -f update.its -E -p ${HDR_SIZE} update.itb -v ${ARG_VERSION}
257	fi
258
259	fdtdump update.itb > update.hdr.dts
260
261	# validate update.hdr
262	if [ "${ARG_SIGN}" == "y" ]; then
263		NUM=`grep "${LAST_IMG}" update.hdr.dts  | wc -l`
264		if [ ${NUM} -lt 3 ]; then
265			echo "ERROR: mkimage can't makeup full \"hashed-nodes\" property list"
266			exit 1
267		fi
268	fi
269
270	# Remove binary from update.itb
271	BYTE=`sed -n "/totalsize:/p" update.hdr.dts  | awk '{ print $4 }' | tr -d '(' | tr -d ')'`
272	dd if=update.itb of=update.hdr bs=${BYTE} count=1
273
274	# Append checksum
275	openssl dgst -sha256 -binary -out update.hash update.hdr
276	cat update.hash >> update.hdr
277
278	rm -f *.itb *.its *.dtb *.dts data2sign* *.hash orderlist.txt
279	mkdir -p ${OUTPUT_DIR}
280	ls ${GPT} >/dev/null 2>&1 && mv ${GPT} ${OUTPUT_DIR}
281	mv -f *${SUFFIX} update.hdr ${OUTPUT_DIR}
282
283	echo
284	echo "Success: [${SIGNED}] TFTP upgrade images(unit: ${ARG_IMG_MB}MB) are ready in directory: ${OUTPUT_DIR}."
285	echo
286}
287
288###############################################################
289process_args $*
290split_image
291gen_its
292gen_update_hdr
293