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