kernel: use bulk free in kfree_skb_list to improve performance
[oweals/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