mkits-multiple-config.sh 14 KB

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