mkits-multiple-config.sh 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. #!/usr/bin/env bash
  2. # SPDX-License-Identifier: GPL-2.0-or-later
  3. #
  4. # Author: Jason Wu <[email protected]>
  5. # with modifications for multi-DTB-same-image by:
  6. # Mathew McBride <[email protected]>
  7. #
  8. # U-Boot firmware supports the booting of images in the Flattened Image
  9. # Tree (FIT) format. The FIT format uses a device tree structure to
  10. # describe a kernel image, device tree blob, ramdisk, etc. This script
  11. # creates an Image Tree Source (.its file) which can be passed to the
  12. # 'mkimage' utility to generate an Image Tree Blob (.itb file). The .itb
  13. # file can then be booted by U-Boot (or other bootloaders which support
  14. # FIT images). See doc/uImage.FIT/howto.txt in U-Boot source code for
  15. # additional information on FIT images.
  16. #
  17. # This tools supports:
  18. # - multi-configuration
  19. # - multi-image support - multiple kernel/fdt/ramdsik
  20. # - per image configuration:
  21. # - hash algorithm and generated required subnodes
  22. # - compression
  23. # - signature and generated required subnodes
  24. #
  25. set -e
  26. # image config limit
  27. MAX_IMG=50
  28. # conf config limit
  29. MAX_CONF=10
  30. # declare main data array
  31. declare -a img_array
  32. declare -a conf_array
  33. # initialize array with empty values
  34. for (( index=1; index<=$MAX_IMG; index++ )); do
  35. declare -a img$index
  36. for i in {0..13}; do
  37. eval img${index}[$i]=""
  38. done
  39. done
  40. for (( index=1; index<=$MAX_CONF; index++ )); do
  41. declare -a conf$index
  42. for i in {0..9}; do
  43. eval conf${index}[$i]=""
  44. done
  45. done
  46. # imgX array index information
  47. # 0: type of image - kernel, fdt, ramdsik
  48. # 1: image location
  49. # 2: image index
  50. # 3: loadaddr of image
  51. # 4: entrypoint of image
  52. # 5: compression
  53. # 6: hash algorithm
  54. # 7: part of the configuration
  55. # 8: Human friend name for the image
  56. # 9: key file name
  57. # 10: signature
  58. # 11: conf friendly name
  59. # confX array index information
  60. # 0: conf number
  61. # 1: kernel conf
  62. # 2: fdt conf
  63. # 3: rootfs conf
  64. # 4: kernel key file
  65. # 5: fdt key file
  66. # 6: rootfs key file
  67. # 7: kernel sign_algorithm
  68. # 8: fdt sign_algorithm
  69. # 9: rootfs sign_algorithm
  70. # 10: conf friendly name
  71. usage() {
  72. echo "Usage: `basename $0` -A arch -v version -o its_file" \
  73. "-k kernel -a addr -e entry [-C none] [-h sha1] [-c conf]"
  74. echo -e "Example1:\n\tkernel image ker_img1 with no compression +"
  75. echo -e "\tsha1 hash + fdt dtb1 with sha1 and crc32 hash for conf 1"
  76. echo -e "\t $ `basename $0` -A arm -v 4.4 \ "
  77. echo -e "\t -k ker_img1 -C none -h sha1 -e 0x8000 -a 0x8000 -c 1 \ "
  78. echo -e "\t -d dtb1 -h sha1 -h crc32 -c 1\n"
  79. echo "General settings:"
  80. echo -e "\t-A ==> set architecture to 'arch'"
  81. echo -e "\t-v ==> set kernel version to 'version'"
  82. echo -e "\t-o ==> create output file 'its_file' [optional]"
  83. echo "Input image type:"
  84. echo -e "\t-k ==> kernel image 'kernel'"
  85. echo -e "\t-d ==> Device Tree Blob 'dtb'"
  86. echo -e "\t-r ==> ramdisk image 'ramdisk"
  87. echo "Per image configurations:"
  88. echo -e "\t-C ==> set compression type 'comp'"
  89. echo -e "\t-c ==> set image config (multiple -c allowed)"
  90. echo -e "\t-a ==> set load address to 'addr' (hex)"
  91. echo -e "\t-e ==> set entry point to 'entry' (hex)"
  92. echo -e "\t-D ==> human friendly 'name' (one word only)"
  93. echo -e "\t-h ==> set hash algorithm (multiple -h allowed)"
  94. echo -e "\t-s ==> set signature for given config image"
  95. echo -e "\t-K ==> set key file for given config image"
  96. exit 1
  97. }
  98. array_check()
  99. {
  100. local a=999
  101. local max_a=0
  102. local max_i=0
  103. if echo $1 | grep -q img; then
  104. max_a=$MAX_IMG
  105. max_i=13
  106. let a=$(echo $1 | awk -F "img" '{print $2}')
  107. elif echo $1 | grep -q conf; then
  108. max_a=$MAX_CONF
  109. max_i=10
  110. let a=$(echo $1 | awk -F "conf" '{print $2}')
  111. fi
  112. if [ ${a} -lt 0 -o ${a} -gt ${max_a} -o \
  113. ${2} -lt 0 -o ${2} -gt ${max_i} ]; then
  114. echo "WARNING: Invalid array name, skipping!!!"
  115. return 255
  116. fi
  117. }
  118. #
  119. # $1: array name
  120. # $2: index
  121. # $3: value
  122. # $4: append operation
  123. #
  124. array_put()
  125. {
  126. # check if array is declared
  127. array_check $1 $2 || return 0
  128. if [ -z "$4" ]; then
  129. eval $1[$2]=$3
  130. else
  131. eval $1[$2]=\"\${$1[$2]} $3\"
  132. fi
  133. }
  134. #
  135. # $1: array name
  136. # $2: index
  137. #
  138. array_get()
  139. {
  140. local val
  141. eval val=\${$1[$2]}
  142. echo $val
  143. }
  144. parse_args() {
  145. local i=-1 k=-1 d=-1 r=-1
  146. while getopts ":A:a:C:c:D:d:e:h:k:K:o:v:r:s:n:" OPTION; do
  147. case $OPTION in
  148. A ) ARCH=$OPTARG;;
  149. a ) array_put img$i 3 $OPTARG;;
  150. C ) value_sanity_chk compression $OPTARG;
  151. array_put img$i 5 $OPTARG;;
  152. c ) array_put img$i 7 $OPTARG append;;
  153. D ) array_put img$i 8 $OPTARG;;
  154. d ) i=$(($i + 1));
  155. d=$(($d + 1));
  156. img_array[$i]=img$i;
  157. array_put img$i 0 fdt;
  158. array_put img$i 1 $OPTARG;
  159. array_put img$i 2 $d;
  160. ;;
  161. e ) array_put img$i 4 $OPTARG;;
  162. h ) value_sanity_chk hash $OPTARG;
  163. array_put img$i 6 $OPTARG append;;
  164. k ) i=$(($i + 1));
  165. k=$(($k + 1));
  166. img_array[$i]=img$i;
  167. array_put img$i 0 "kernel";
  168. array_put img$i 1 $OPTARG;
  169. array_put img$i 2 $k;
  170. ;;
  171. K ) array_put img$i 9 $OPTARG;;
  172. n ) array_put img$i 11 $OPTARG;;
  173. o ) OUTPUT=$OPTARG;;
  174. v ) VERSION=$OPTARG;;
  175. r ) i=$(($i + 1));
  176. r=$(($r + 1));
  177. img_array[$i]=img$i;
  178. array_put img$i 0 "ramdisk";
  179. array_put img$i 1 $OPTARG;
  180. array_put img$i 2 $r;
  181. ;;
  182. s ) value_sanity_chk signature $OPTARG;
  183. array_put img$i 10 $OPTARG;
  184. ;;
  185. * ) echo "Invalid option passed to '$0' (options:$@)"
  186. usage;;
  187. esac
  188. done
  189. [ -n "${OUTPUT}" ] || OUTPUT=fitimage.its
  190. [ -n "${VERSION}" ] || VERSION="Unknown"
  191. [ -n "${ARCH}" ] || ARCH=arm
  192. }
  193. #
  194. # sanity check for signature, compression and hash
  195. #
  196. value_sanity_chk()
  197. {
  198. local valid=""
  199. case $1 in
  200. signature) valid="sha-1,rsa-2048 sha-256,rsa-2048 sha-256,rsa-4096";;
  201. compression) valid="gzip bzip2 none";;
  202. hash) valid="sha1 md5 crc32";;
  203. esac
  204. if ! echo $valid | grep -q "$2"; then
  205. echo "Error: Invalid $1 provided '$2'"
  206. echo "Valid options are: $valid"
  207. exit 255
  208. fi
  209. }
  210. #
  211. # Emit the fitImage section bits
  212. #
  213. # $1: Section bit type: fitstart - its header
  214. # imagestart - image section start
  215. # confstart - configuration section start
  216. # sectend - section end
  217. # fitend - fitimage end
  218. # $2: optional variable for confstart section
  219. #
  220. emit_its() {
  221. case $1 in
  222. fitstart)
  223. cat << EOF > ${OUTPUT}
  224. /dts-v1/;
  225. / {
  226. description = "U-Boot fitImage for ${VERSION} kernel";
  227. #address-cells = <1>;
  228. EOF
  229. ;;
  230. imagestart)
  231. echo -e "\n\timages {" >> ${OUTPUT};;
  232. confstart)
  233. # echo -e "\tconfigurations {\n\t\tdefault = \"conf@${2:-0}\";" \
  234. echo -e "\tconfigurations {\n" \
  235. >> ${OUTPUT};;
  236. sectend)
  237. echo -e "\t};" >> ${OUTPUT};;
  238. fitend)
  239. echo -e "};" >> ${OUTPUT};;
  240. esac
  241. }
  242. #
  243. # Emit kernel image node
  244. #
  245. emit_kernel() {
  246. local image=${1}
  247. local count=${2:-${MAX_IMG}}
  248. local loaddaddr=${3:-0x8000}
  249. local entrypoint=${4:-0x8000}
  250. local compresson=${5:-none}
  251. local checksum=${6:-sha1}
  252. local name=${7}
  253. [ -z "${name}" ] || name=" ${name}"
  254. cat << EOF >> ${OUTPUT}
  255. kernel@${count} {
  256. description = "Linux Kernel${name}";
  257. data = /incbin/("${image}");
  258. type = "kernel";
  259. arch = "${ARCH}";
  260. os = "linux";
  261. compression = "${compresson}";
  262. load = <${loaddaddr}>;
  263. entry = <${entrypoint}>;
  264. EOF
  265. emit_cksum ${checksum}
  266. if [ -z "$SIGN_IN_CONF" ] ; then
  267. emit_signature "$9" "" "" "$8" "" ""
  268. fi
  269. echo " };" >> ${OUTPUT}
  270. }
  271. #
  272. # Emit fdt node
  273. #
  274. emit_fdt() {
  275. local image=${1}
  276. local count=${2:-${MAX_IMG}}
  277. local compresson=${3:-none}
  278. local checksum=${4:-sha1}
  279. local name=${5}
  280. local loadaddr=${6}
  281. [ -z "${name}" ] || name=" ${name}"
  282. cat << EOF >> ${OUTPUT}
  283. fdt@${count} {
  284. description = "Flattened Device Tree blob${name}";
  285. data = /incbin/("${image}");
  286. type = "flat_dt";
  287. arch = "${ARCH}";
  288. load = <${loadaddr}>;
  289. compression = "none";
  290. EOF
  291. emit_cksum ${checksum}
  292. if [ -z "$SIGN_IN_CONF" ] ; then
  293. emit_signature "" "$7" "" "" "$6" ""
  294. fi
  295. echo " };" >> ${OUTPUT}
  296. }
  297. #
  298. # Emit ramdisk node
  299. #
  300. emit_ramdisk() {
  301. local image=${1}
  302. local count=${2:-${MAX_IMG}}
  303. local compresson=${3:-none}
  304. local checksum=${4:-sha1}
  305. local name=${5}
  306. [ -z "${name}" ] || name=" ${name}"
  307. cat << EOF >> ${OUTPUT}
  308. ramdisk@${count} {
  309. description = "ramdisk${name}";
  310. data = /incbin/("${image}");
  311. type = "ramdisk";
  312. arch = "${ARCH}";
  313. os = "linux";
  314. compression = "${compresson}";
  315. EOF
  316. emit_cksum ${checksum}
  317. if [ -z "$SIGN_IN_CONF" ] ; then
  318. emit_signature "" "" "$7" "" "" "$6"
  319. fi
  320. echo " };" >> ${OUTPUT}
  321. }
  322. #
  323. # Emit check sum sub node
  324. #
  325. emit_cksum() {
  326. csum_list=$@
  327. count=1
  328. for csum in ${csum_list}; do
  329. cat << EOF >> ${OUTPUT}
  330. hash@${count} {
  331. algo = "${csum}";
  332. };
  333. EOF
  334. count=`expr ${count} + 1`
  335. done
  336. }
  337. #
  338. # Emit signature sub node
  339. #
  340. emit_signature() {
  341. local kernel=$1
  342. local fdt=$2
  343. local rootfs=$3
  344. local kernel_key=$4
  345. local fdt_key=$5
  346. local rootfs_key=$6
  347. local imgs=""
  348. local count=0
  349. local chk_list="" algo="" algos="" i=""
  350. for i in kernel fdt rootfs; do
  351. eval algo=\$$i
  352. eval key=\$${i}_key
  353. [ -n "$algo" ] || continue
  354. if ! echo "$algos" | grep -q $algo; then
  355. if [ -z "$algos" ]; then
  356. algos=$algo
  357. else
  358. algos="${algos} $algo"
  359. fi
  360. fi
  361. if ! echo "$keys" | grep -q $key; then
  362. if [ -z "$keys" ]; then
  363. keys=$key
  364. else
  365. keys="${keys} $key"
  366. fi
  367. fi
  368. done
  369. for algo in $algos; do
  370. for key in $keys; do
  371. img=""
  372. for i in kernel fdt rootfs; do
  373. eval tmp_algo=\$$i
  374. eval tmp_key=\$${i}_key
  375. [ "$tmp_algo" == "$algo" ] || continue
  376. [ "$tmp_key" == "$key" ] || continue
  377. if [ -z "$img" ]; then
  378. img=$i
  379. else
  380. img=${img},$i
  381. fi
  382. done
  383. [ -n "$img" ] || continue
  384. cat << EOF >> ${OUTPUT}
  385. signature@${count} {
  386. algo = "${algo}";
  387. key-name-hint = "${key}";
  388. EOF
  389. if [ -n "$SIGN_IN_CONF" ] ; then
  390. echo " sign-images = \"$img\";" >> ${OUTPUT}
  391. fi
  392. echo " };" >> ${OUTPUT}
  393. count=`expr ${count} + 1`
  394. done
  395. done
  396. }
  397. #
  398. # Emit config sub nodes
  399. #
  400. emit_config() {
  401. local conf_csum="sha1"
  402. config_name="conf@${1}"
  403. if [ ! -z "${11}" ]; then
  404. config_name="${11}"
  405. fi
  406. if [ -z "${2}" ]; then
  407. echo "Error: config has no kernel img, skipping conf node!"
  408. return 0
  409. fi
  410. # Test if we have any DTBs at all
  411. if [ -z "${3}" ] ; then
  412. conf_desc="Boot Linux kernel"
  413. fdt_line=""
  414. else
  415. conf_desc="Boot Linux kernel with FDT blob"
  416. fdt_line="
  417. fdt = \"fdt@${3}\";"
  418. fi
  419. # Test if we have any ROOTFS at all
  420. if [ -n "${4}" ] ; then
  421. conf_desc="$conf_desc + ramdisk"
  422. fdt_line="${fdt_line}
  423. ramdisk = \"ramdisk@${4}\";"
  424. fi
  425. kernel_line="kernel = \"kernel@${2}\";"
  426. cat << EOF >> ${OUTPUT}
  427. ${config_name} {
  428. description = "${conf_desc}";
  429. ${kernel_line}${fdt_line}
  430. hash@1 {
  431. algo = "${conf_csum}";
  432. };
  433. EOF
  434. if [ -n "$SIGN_IN_CONF" ] ; then
  435. emit_signature "$5" "$6" "$7" "$8" "$9" "${10}"
  436. fi
  437. echo " };" >> ${OUTPUT}
  438. }
  439. #
  440. # remove prefix space
  441. #
  442. remove_prefix_space()
  443. {
  444. echo "$@" | sed "s:^ ::g"
  445. }
  446. #
  447. # generate image nodes and its subnodes
  448. #
  449. emit_image_nodes()
  450. {
  451. local t img_c img_i img_index chk
  452. local img_type img_path img_count img_loadadr img_entrypoint \
  453. img_compression img_hash img_conf img_name img_key img_sign \
  454. img_index
  455. emit_its imagestart
  456. for t in "kernel" "fdt" "ramdisk"; do
  457. img_index=0
  458. for a in ${img_array[@]}; do
  459. img_type=$(array_get $a 0)
  460. img_path=$(array_get $a 1)
  461. img_count=$(array_get $a 2)
  462. img_loadadr=$(array_get $a 3)
  463. img_entrypoint=$(array_get $a 4)
  464. img_compression=$(array_get $a 5)
  465. img_hash=$(array_get $a 6)
  466. img_conf=$(array_get $a 7)
  467. img_name=$(array_get $a 8)
  468. img_key=$(array_get $a 9)
  469. img_sign=$(array_get $a 10)
  470. img_cname=$(array_get $a 11)
  471. img_conf=$(remove_prefix_space $img_conf)
  472. img_hash=$(remove_prefix_space $img_hash)
  473. [ "${img_type}" == $t ] || continue
  474. # generate sub nodes
  475. eval chk=\$DEF_$t
  476. [ -n "${chk}" ] || eval DEF_$t=$img_count
  477. case $t in
  478. kernel) emit_kernel "$img_path" "$img_count" \
  479. "$img_loadadr" "$img_entrypoint" \
  480. "$img_compression" "$img_hash" \
  481. "$img_name" "$img_key" "$img_sign";;
  482. fdt) emit_fdt "$img_path" "$img_count" \
  483. "$img_compression" "$img_hash" \
  484. "$img_name" "$img_loadadr" "$img_key" "$img_sign" ;;
  485. ramdisk) emit_ramdisk "$img_path" "$img_count" \
  486. "$img_compression" "$img_hash" \
  487. "$img_name" "$img_key" "$img_sign";;
  488. esac
  489. # set up configuration data
  490. for img_c in $img_conf; do
  491. img_i=""
  492. #set up default configuration if its not set
  493. [ -n "$DEF_CONFIG" ] || DEF_CONFIG=$img_c
  494. [ -z "${img_c}" ] || conf_array[$img_c]=conf$img_c
  495. array_put conf$img_c 0 ${img_c}
  496. case $t in
  497. kernel) img_i=1;;
  498. fdt) img_i=2;;
  499. ramdisk) img_i=3;;
  500. esac
  501. array_put conf$img_c $img_i $img_index
  502. array_put conf$img_c $(($img_i + 3)) ${img_sign}
  503. array_put conf$img_c $(($img_i + 6)) ${img_key}
  504. array_put conf$img_c 10 $img_cname
  505. done
  506. img_index=$((img_index + 1))
  507. done
  508. done
  509. emit_its sectend
  510. }
  511. #
  512. # generate configuration node and its subnodes
  513. #
  514. emit_configuration_nodes ()
  515. {
  516. local count kernel fdt ramdisk ker_file fdt_file rfs_file ker_sign \
  517. fdt_sign rfs_sign
  518. emit_its confstart $DEF_CONFIG
  519. for a in ${conf_array[@]}; do
  520. count=$(array_get $a 0)
  521. kernel=$(array_get $a 1)
  522. fdt=$(array_get $a 2)
  523. ramdisk=$(array_get $a 3)
  524. er_file=$(array_get $a 4)
  525. fdt_file=$(array_get $a 5)
  526. rfs_file=$(array_get $a 6)
  527. ker_sign=$(array_get $a 7)
  528. fdt_sign=$(array_get $a 8)
  529. rfs_sign=$(array_get $a 9)
  530. cname=$(array_get $a 10)
  531. emit_config "$count" "$kernel" "$fdt" "$ramdisk" "$ker_file" \
  532. "$fdt_file" "$rfs_file" "$ker_sign" "$fdt_sign" \
  533. "$rfs_sign" "${cname}"
  534. done
  535. if [ -z "${DEF_CONFIG}" ]; then
  536. emit_config "0" "$DEF_kernel" "$DEF_fdt" "$DEF_ramdisk"
  537. fi
  538. emit_its sectend
  539. }
  540. # Set to none empty to create signature sub node under images node
  541. SIGN_IN_CONF=${SIGN_IN_CONF:-""}
  542. # Set to default config used
  543. DEF_CONFIG=${DEF_CONFIG:-""}
  544. parse_args $@
  545. emit_its fitstart
  546. emit_image_nodes
  547. emit_configuration_nodes
  548. emit_its fitend