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