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