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