mkits-multiple-config.sh 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  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. shift $(($OPTIND - 1))
  190. [ $# -gt 0 ] && {
  191. echo "Failed to parse all passed arguments (unrecognized: \"$@\")"
  192. exit 1
  193. }
  194. [ -n "${OUTPUT}" ] || OUTPUT=fitimage.its
  195. [ -n "${VERSION}" ] || VERSION="Unknown"
  196. [ -n "${ARCH}" ] || ARCH=arm
  197. }
  198. #
  199. # sanity check for signature, compression and hash
  200. #
  201. value_sanity_chk()
  202. {
  203. local valid=""
  204. case $1 in
  205. signature) valid="sha-1,rsa-2048 sha-256,rsa-2048 sha-256,rsa-4096";;
  206. compression) valid="gzip bzip2 none";;
  207. hash) valid="sha1 md5 crc32";;
  208. esac
  209. if ! echo $valid | grep -q "$2"; then
  210. echo "Error: Invalid $1 provided '$2'"
  211. echo "Valid options are: $valid"
  212. exit 255
  213. fi
  214. }
  215. #
  216. # Emit the fitImage section bits
  217. #
  218. # $1: Section bit type: fitstart - its header
  219. # imagestart - image section start
  220. # confstart - configuration section start
  221. # sectend - section end
  222. # fitend - fitimage end
  223. # $2: optional variable for confstart section
  224. #
  225. emit_its() {
  226. case $1 in
  227. fitstart)
  228. cat << EOF > ${OUTPUT}
  229. /dts-v1/;
  230. / {
  231. description = "U-Boot fitImage for ${VERSION} kernel";
  232. #address-cells = <1>;
  233. EOF
  234. ;;
  235. imagestart)
  236. echo -e "\n\timages {" >> ${OUTPUT};;
  237. confstart)
  238. # echo -e "\tconfigurations {\n\t\tdefault = \"conf@${2:-0}\";" \
  239. echo -e "\tconfigurations {\n" \
  240. >> ${OUTPUT};;
  241. sectend)
  242. echo -e "\t};" >> ${OUTPUT};;
  243. fitend)
  244. echo -e "};" >> ${OUTPUT};;
  245. esac
  246. }
  247. #
  248. # Emit kernel image node
  249. #
  250. emit_kernel() {
  251. local image=${1}
  252. local count=${2:-${MAX_IMG}}
  253. local loaddaddr=${3:-0x8000}
  254. local entrypoint=${4:-0x8000}
  255. local compresson=${5:-none}
  256. local checksum=${6:-sha1}
  257. local name=${7}
  258. [ -z "${name}" ] || name=" ${name}"
  259. cat << EOF >> ${OUTPUT}
  260. kernel@${count} {
  261. description = "Linux Kernel${name}";
  262. data = /incbin/("${image}");
  263. type = "kernel";
  264. arch = "${ARCH}";
  265. os = "linux";
  266. compression = "${compresson}";
  267. load = <${loaddaddr}>;
  268. entry = <${entrypoint}>;
  269. EOF
  270. emit_cksum ${checksum}
  271. if [ -z "$SIGN_IN_CONF" ] ; then
  272. emit_signature "$9" "" "" "$8" "" ""
  273. fi
  274. echo " };" >> ${OUTPUT}
  275. }
  276. #
  277. # Emit fdt node
  278. #
  279. emit_fdt() {
  280. local image=${1}
  281. local count=${2:-${MAX_IMG}}
  282. local compresson=${3:-none}
  283. local checksum=${4:-sha1}
  284. local name=${5}
  285. local loadaddr=${6}
  286. [ -z "${name}" ] || name=" ${name}"
  287. cat << EOF >> ${OUTPUT}
  288. fdt@${count} {
  289. description = "Flattened Device Tree blob${name}";
  290. data = /incbin/("${image}");
  291. type = "flat_dt";
  292. arch = "${ARCH}";
  293. load = <${loadaddr}>;
  294. compression = "none";
  295. EOF
  296. emit_cksum ${checksum}
  297. if [ -z "$SIGN_IN_CONF" ] ; then
  298. emit_signature "" "$7" "" "" "$6" ""
  299. fi
  300. echo " };" >> ${OUTPUT}
  301. }
  302. #
  303. # Emit ramdisk node
  304. #
  305. emit_ramdisk() {
  306. local image=${1}
  307. local count=${2:-${MAX_IMG}}
  308. local compresson=${3:-none}
  309. local checksum=${4:-sha1}
  310. local name=${5}
  311. [ -z "${name}" ] || name=" ${name}"
  312. cat << EOF >> ${OUTPUT}
  313. ramdisk@${count} {
  314. description = "ramdisk${name}";
  315. data = /incbin/("${image}");
  316. type = "ramdisk";
  317. arch = "${ARCH}";
  318. os = "linux";
  319. compression = "${compresson}";
  320. EOF
  321. emit_cksum ${checksum}
  322. if [ -z "$SIGN_IN_CONF" ] ; then
  323. emit_signature "" "" "$7" "" "" "$6"
  324. fi
  325. echo " };" >> ${OUTPUT}
  326. }
  327. #
  328. # Emit check sum sub node
  329. #
  330. emit_cksum() {
  331. csum_list=$@
  332. count=1
  333. for csum in ${csum_list}; do
  334. cat << EOF >> ${OUTPUT}
  335. hash@${count} {
  336. algo = "${csum}";
  337. };
  338. EOF
  339. count=`expr ${count} + 1`
  340. done
  341. }
  342. #
  343. # Emit signature sub node
  344. #
  345. emit_signature() {
  346. local kernel=$1
  347. local fdt=$2
  348. local rootfs=$3
  349. local kernel_key=$4
  350. local fdt_key=$5
  351. local rootfs_key=$6
  352. local imgs=""
  353. local count=0
  354. local chk_list="" algo="" algos="" i=""
  355. for i in kernel fdt rootfs; do
  356. eval algo=\$$i
  357. eval key=\$${i}_key
  358. [ -n "$algo" ] || continue
  359. if ! echo "$algos" | grep -q $algo; then
  360. if [ -z "$algos" ]; then
  361. algos=$algo
  362. else
  363. algos="${algos} $algo"
  364. fi
  365. fi
  366. if ! echo "$keys" | grep -q $key; then
  367. if [ -z "$keys" ]; then
  368. keys=$key
  369. else
  370. keys="${keys} $key"
  371. fi
  372. fi
  373. done
  374. for algo in $algos; do
  375. for key in $keys; do
  376. img=""
  377. for i in kernel fdt rootfs; do
  378. eval tmp_algo=\$$i
  379. eval tmp_key=\$${i}_key
  380. [ "$tmp_algo" == "$algo" ] || continue
  381. [ "$tmp_key" == "$key" ] || continue
  382. if [ -z "$img" ]; then
  383. img=$i
  384. else
  385. img=${img},$i
  386. fi
  387. done
  388. [ -n "$img" ] || continue
  389. cat << EOF >> ${OUTPUT}
  390. signature@${count} {
  391. algo = "${algo}";
  392. key-name-hint = "${key}";
  393. EOF
  394. if [ -n "$SIGN_IN_CONF" ] ; then
  395. echo " sign-images = \"$img\";" >> ${OUTPUT}
  396. fi
  397. echo " };" >> ${OUTPUT}
  398. count=`expr ${count} + 1`
  399. done
  400. done
  401. }
  402. #
  403. # Emit config sub nodes
  404. #
  405. emit_config() {
  406. local conf_csum="sha1"
  407. config_name="conf@${1}"
  408. if [ ! -z "${11}" ]; then
  409. config_name="${11}"
  410. fi
  411. if [ -z "${2}" ]; then
  412. echo "Error: config has no kernel img, skipping conf node!"
  413. return 0
  414. fi
  415. # Test if we have any DTBs at all
  416. if [ -z "${3}" ] ; then
  417. conf_desc="Boot Linux kernel"
  418. fdt_line=""
  419. else
  420. conf_desc="Boot Linux kernel with FDT blob"
  421. fdt_line="
  422. fdt = \"fdt@${3}\";"
  423. fi
  424. # Test if we have any ROOTFS at all
  425. if [ -n "${4}" ] ; then
  426. conf_desc="$conf_desc + ramdisk"
  427. fdt_line="${fdt_line}
  428. ramdisk = \"ramdisk@${4}\";"
  429. fi
  430. kernel_line="kernel = \"kernel@${2}\";"
  431. cat << EOF >> ${OUTPUT}
  432. ${config_name} {
  433. description = "${conf_desc}";
  434. ${kernel_line}${fdt_line}
  435. hash@1 {
  436. algo = "${conf_csum}";
  437. };
  438. EOF
  439. if [ -n "$SIGN_IN_CONF" ] ; then
  440. emit_signature "$5" "$6" "$7" "$8" "$9" "${10}"
  441. fi
  442. echo " };" >> ${OUTPUT}
  443. }
  444. #
  445. # remove prefix space
  446. #
  447. remove_prefix_space()
  448. {
  449. echo "$@" | sed "s:^ ::g"
  450. }
  451. #
  452. # generate image nodes and its subnodes
  453. #
  454. emit_image_nodes()
  455. {
  456. local t img_c img_i img_index chk
  457. local img_type img_path img_count img_loadadr img_entrypoint \
  458. img_compression img_hash img_conf img_name img_key img_sign \
  459. img_index
  460. emit_its imagestart
  461. for t in "kernel" "fdt" "ramdisk"; do
  462. img_index=0
  463. for a in ${img_array[@]}; do
  464. img_type=$(array_get $a 0)
  465. img_path=$(array_get $a 1)
  466. img_count=$(array_get $a 2)
  467. img_loadadr=$(array_get $a 3)
  468. img_entrypoint=$(array_get $a 4)
  469. img_compression=$(array_get $a 5)
  470. img_hash=$(array_get $a 6)
  471. img_conf=$(array_get $a 7)
  472. img_name=$(array_get $a 8)
  473. img_key=$(array_get $a 9)
  474. img_sign=$(array_get $a 10)
  475. img_cname=$(array_get $a 11)
  476. img_conf=$(remove_prefix_space $img_conf)
  477. img_hash=$(remove_prefix_space $img_hash)
  478. [ "${img_type}" == $t ] || continue
  479. # generate sub nodes
  480. eval chk=\$DEF_$t
  481. [ -n "${chk}" ] || eval DEF_$t=$img_count
  482. case $t in
  483. kernel) emit_kernel "$img_path" "$img_count" \
  484. "$img_loadadr" "$img_entrypoint" \
  485. "$img_compression" "$img_hash" \
  486. "$img_name" "$img_key" "$img_sign";;
  487. fdt) emit_fdt "$img_path" "$img_count" \
  488. "$img_compression" "$img_hash" \
  489. "$img_name" "$img_loadadr" "$img_key" "$img_sign" ;;
  490. ramdisk) emit_ramdisk "$img_path" "$img_count" \
  491. "$img_compression" "$img_hash" \
  492. "$img_name" "$img_key" "$img_sign";;
  493. esac
  494. # set up configuration data
  495. for img_c in $img_conf; do
  496. img_i=""
  497. #set up default configuration if its not set
  498. [ -n "$DEF_CONFIG" ] || DEF_CONFIG=$img_c
  499. [ -z "${img_c}" ] || conf_array[$img_c]=conf$img_c
  500. array_put conf$img_c 0 ${img_c}
  501. case $t in
  502. kernel) img_i=1;;
  503. fdt) img_i=2;;
  504. ramdisk) img_i=3;;
  505. esac
  506. array_put conf$img_c $img_i $img_index
  507. array_put conf$img_c $(($img_i + 3)) ${img_sign}
  508. array_put conf$img_c $(($img_i + 6)) ${img_key}
  509. array_put conf$img_c 10 $img_cname
  510. done
  511. img_index=$((img_index + 1))
  512. done
  513. done
  514. emit_its sectend
  515. }
  516. #
  517. # generate configuration node and its subnodes
  518. #
  519. emit_configuration_nodes ()
  520. {
  521. local count kernel fdt ramdisk ker_file fdt_file rfs_file ker_sign \
  522. fdt_sign rfs_sign
  523. emit_its confstart $DEF_CONFIG
  524. for a in ${conf_array[@]}; do
  525. count=$(array_get $a 0)
  526. kernel=$(array_get $a 1)
  527. fdt=$(array_get $a 2)
  528. ramdisk=$(array_get $a 3)
  529. er_file=$(array_get $a 4)
  530. fdt_file=$(array_get $a 5)
  531. rfs_file=$(array_get $a 6)
  532. ker_sign=$(array_get $a 7)
  533. fdt_sign=$(array_get $a 8)
  534. rfs_sign=$(array_get $a 9)
  535. cname=$(array_get $a 10)
  536. emit_config "$count" "$kernel" "$fdt" "$ramdisk" "$ker_file" \
  537. "$fdt_file" "$rfs_file" "$ker_sign" "$fdt_sign" \
  538. "$rfs_sign" "${cname}"
  539. done
  540. if [ -z "${DEF_CONFIG}" ]; then
  541. emit_config "0" "$DEF_kernel" "$DEF_fdt" "$DEF_ramdisk"
  542. fi
  543. emit_its sectend
  544. }
  545. # Set to none empty to create signature sub node under images node
  546. SIGN_IN_CONF=${SIGN_IN_CONF:-""}
  547. # Set to default config used
  548. DEF_CONFIG=${DEF_CONFIG:-""}
  549. parse_args $@
  550. emit_its fitstart
  551. emit_image_nodes
  552. emit_configuration_nodes
  553. emit_its fitend