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