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