123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600 |
- #!/usr/bin/env bash
- # SPDX-License-Identifier: GPL-2.0-or-later
- #
- # Author: Jason Wu <[email protected]>
- # with modifications for multi-DTB-same-image by:
- # Mathew McBride <[email protected]>
- #
- # U-Boot firmware supports the booting of images in the Flattened Image
- # Tree (FIT) format. The FIT format uses a device tree structure to
- # describe a kernel image, device tree blob, ramdisk, etc. This script
- # creates an Image Tree Source (.its file) which can be passed to the
- # 'mkimage' utility to generate an Image Tree Blob (.itb file). The .itb
- # file can then be booted by U-Boot (or other bootloaders which support
- # FIT images). See doc/uImage.FIT/howto.txt in U-Boot source code for
- # additional information on FIT images.
- #
- # This tools supports:
- # - multi-configuration
- # - multi-image support - multiple kernel/fdt/ramdsik
- # - per image configuration:
- # - hash algorithm and generated required subnodes
- # - compression
- # - signature and generated required subnodes
- #
- set -e
- # image config limit
- MAX_IMG=50
- # conf config limit
- MAX_CONF=10
- # declare main data array
- declare -a img_array
- declare -a conf_array
- # initialize array with empty values
- for (( index=1; index<=$MAX_IMG; index++ )); do
- declare -a img$index
- for i in {0..13}; do
- eval img${index}[$i]=""
- done
- done
- for (( index=1; index<=$MAX_CONF; index++ )); do
- declare -a conf$index
- for i in {0..9}; do
- eval conf${index}[$i]=""
- done
- done
- # imgX array index information
- # 0: type of image - kernel, fdt, ramdsik
- # 1: image location
- # 2: image index
- # 3: loadaddr of image
- # 4: entrypoint of image
- # 5: compression
- # 6: hash algorithm
- # 7: part of the configuration
- # 8: Human friend name for the image
- # 9: key file name
- # 10: signature
- # 11: conf friendly name
- # confX array index information
- # 0: conf number
- # 1: kernel conf
- # 2: fdt conf
- # 3: rootfs conf
- # 4: kernel key file
- # 5: fdt key file
- # 6: rootfs key file
- # 7: kernel sign_algorithm
- # 8: fdt sign_algorithm
- # 9: rootfs sign_algorithm
- # 10: conf friendly name
- usage() {
- echo "Usage: `basename $0` -A arch -v version -o its_file" \
- "-k kernel -a addr -e entry [-C none] [-h sha1] [-c conf]"
- echo -e "Example1:\n\tkernel image ker_img1 with no compression +"
- echo -e "\tsha1 hash + fdt dtb1 with sha1 and crc32 hash for conf 1"
- echo -e "\t $ `basename $0` -A arm -v 4.4 \ "
- echo -e "\t -k ker_img1 -C none -h sha1 -e 0x8000 -a 0x8000 -c 1 \ "
- echo -e "\t -d dtb1 -h sha1 -h crc32 -c 1\n"
- echo "General settings:"
- echo -e "\t-A ==> set architecture to 'arch'"
- echo -e "\t-v ==> set kernel version to 'version'"
- echo -e "\t-o ==> create output file 'its_file' [optional]"
- echo "Input image type:"
- echo -e "\t-k ==> kernel image 'kernel'"
- echo -e "\t-d ==> Device Tree Blob 'dtb'"
- echo -e "\t-r ==> ramdisk image 'ramdisk"
- echo "Per image configurations:"
- echo -e "\t-C ==> set compression type 'comp'"
- echo -e "\t-c ==> set image config (multiple -c allowed)"
- echo -e "\t-a ==> set load address to 'addr' (hex)"
- echo -e "\t-e ==> set entry point to 'entry' (hex)"
- echo -e "\t-D ==> human friendly 'name' (one word only)"
- echo -e "\t-h ==> set hash algorithm (multiple -h allowed)"
- echo -e "\t-s ==> set signature for given config image"
- echo -e "\t-K ==> set key file for given config image"
- exit 1
- }
- array_check()
- {
- local a=999
- local max_a=0
- local max_i=0
- if echo $1 | grep -q img; then
- max_a=$MAX_IMG
- max_i=13
- let a=$(echo $1 | awk -F "img" '{print $2}')
- elif echo $1 | grep -q conf; then
- max_a=$MAX_CONF
- max_i=10
- let a=$(echo $1 | awk -F "conf" '{print $2}')
- fi
- if [ ${a} -lt 0 -o ${a} -gt ${max_a} -o \
- ${2} -lt 0 -o ${2} -gt ${max_i} ]; then
- echo "WARNING: Invalid array name, skipping!!!"
- return 255
- fi
- }
- #
- # $1: array name
- # $2: index
- # $3: value
- # $4: append operation
- #
- array_put()
- {
- # check if array is declared
- array_check $1 $2 || return 0
- if [ -z "$4" ]; then
- eval $1[$2]=$3
- else
- eval $1[$2]=\"\${$1[$2]} $3\"
- fi
- }
- #
- # $1: array name
- # $2: index
- #
- array_get()
- {
- local val
- eval val=\${$1[$2]}
- echo $val
- }
- parse_args() {
- local i=-1 k=-1 d=-1 r=-1
- while getopts ":A:a:C:c:D:d:e:h:k:K:o:v:r:s:n:" OPTION; do
- case $OPTION in
- A ) ARCH=$OPTARG;;
- a ) array_put img$i 3 $OPTARG;;
- C ) value_sanity_chk compression $OPTARG;
- array_put img$i 5 $OPTARG;;
- c ) array_put img$i 7 $OPTARG append;;
- D ) array_put img$i 8 $OPTARG;;
- d ) i=$(($i + 1));
- d=$(($d + 1));
- img_array[$i]=img$i;
- array_put img$i 0 fdt;
- array_put img$i 1 $OPTARG;
- array_put img$i 2 $d;
- ;;
- e ) array_put img$i 4 $OPTARG;;
- h ) value_sanity_chk hash $OPTARG;
- array_put img$i 6 $OPTARG append;;
- k ) i=$(($i + 1));
- k=$(($k + 1));
- img_array[$i]=img$i;
- array_put img$i 0 "kernel";
- array_put img$i 1 $OPTARG;
- array_put img$i 2 $k;
- ;;
- K ) array_put img$i 9 $OPTARG;;
- n ) array_put img$i 11 $OPTARG;;
- o ) OUTPUT=$OPTARG;;
- v ) VERSION=$OPTARG;;
- r ) i=$(($i + 1));
- r=$(($r + 1));
- img_array[$i]=img$i;
- array_put img$i 0 "ramdisk";
- array_put img$i 1 $OPTARG;
- array_put img$i 2 $r;
- ;;
- s ) value_sanity_chk signature $OPTARG;
- array_put img$i 10 $OPTARG;
- ;;
- * ) echo "Invalid option passed to '$0' (options:$@)"
- usage;;
- esac
- done
- shift $(($OPTIND - 1))
- [ $# -gt 0 ] && {
- echo "Failed to parse all passed arguments (unrecognized: \"$@\")"
- exit 1
- }
- [ -n "${OUTPUT}" ] || OUTPUT=fitimage.its
- [ -n "${VERSION}" ] || VERSION="Unknown"
- [ -n "${ARCH}" ] || ARCH=arm
- }
- #
- # sanity check for signature, compression and hash
- #
- value_sanity_chk()
- {
- local valid=""
- case $1 in
- signature) valid="sha-1,rsa-2048 sha-256,rsa-2048 sha-256,rsa-4096";;
- compression) valid="gzip bzip2 none";;
- hash) valid="sha1 md5 crc32";;
- esac
- if ! echo $valid | grep -q "$2"; then
- echo "Error: Invalid $1 provided '$2'"
- echo "Valid options are: $valid"
- exit 255
- fi
- }
- #
- # Emit the fitImage section bits
- #
- # $1: Section bit type: fitstart - its header
- # imagestart - image section start
- # confstart - configuration section start
- # sectend - section end
- # fitend - fitimage end
- # $2: optional variable for confstart section
- #
- emit_its() {
- case $1 in
- fitstart)
- cat << EOF > ${OUTPUT}
- /dts-v1/;
- / {
- description = "U-Boot fitImage for ${VERSION} kernel";
- #address-cells = <1>;
- EOF
- ;;
- imagestart)
- echo -e "\n\timages {" >> ${OUTPUT};;
- confstart)
- # echo -e "\tconfigurations {\n\t\tdefault = \"conf@${2:-0}\";" \
- echo -e "\tconfigurations {\n" \
- >> ${OUTPUT};;
- sectend)
- echo -e "\t};" >> ${OUTPUT};;
- fitend)
- echo -e "};" >> ${OUTPUT};;
- esac
- }
- #
- # Emit kernel image node
- #
- emit_kernel() {
- local image=${1}
- local count=${2:-${MAX_IMG}}
- local loaddaddr=${3:-0x8000}
- local entrypoint=${4:-0x8000}
- local compresson=${5:-none}
- local checksum=${6:-sha1}
- local name=${7}
- [ -z "${name}" ] || name=" ${name}"
- cat << EOF >> ${OUTPUT}
- kernel@${count} {
- description = "Linux Kernel${name}";
- data = /incbin/("${image}");
- type = "kernel";
- arch = "${ARCH}";
- os = "linux";
- compression = "${compresson}";
- load = <${loaddaddr}>;
- entry = <${entrypoint}>;
- EOF
- emit_cksum ${checksum}
- if [ -z "$SIGN_IN_CONF" ] ; then
- emit_signature "$9" "" "" "$8" "" ""
- fi
- echo " };" >> ${OUTPUT}
- }
- #
- # Emit fdt node
- #
- emit_fdt() {
- local image=${1}
- local count=${2:-${MAX_IMG}}
- local compresson=${3:-none}
- local checksum=${4:-sha1}
- local name=${5}
- local loadaddr=${6}
- [ -z "${name}" ] || name=" ${name}"
- cat << EOF >> ${OUTPUT}
- fdt@${count} {
- description = "Flattened Device Tree blob${name}";
- data = /incbin/("${image}");
- type = "flat_dt";
- arch = "${ARCH}";
- load = <${loadaddr}>;
- compression = "none";
- EOF
- emit_cksum ${checksum}
- if [ -z "$SIGN_IN_CONF" ] ; then
- emit_signature "" "$7" "" "" "$6" ""
- fi
- echo " };" >> ${OUTPUT}
- }
- #
- # Emit ramdisk node
- #
- emit_ramdisk() {
- local image=${1}
- local count=${2:-${MAX_IMG}}
- local compresson=${3:-none}
- local checksum=${4:-sha1}
- local name=${5}
- [ -z "${name}" ] || name=" ${name}"
- cat << EOF >> ${OUTPUT}
- ramdisk@${count} {
- description = "ramdisk${name}";
- data = /incbin/("${image}");
- type = "ramdisk";
- arch = "${ARCH}";
- os = "linux";
- compression = "${compresson}";
- EOF
- emit_cksum ${checksum}
- if [ -z "$SIGN_IN_CONF" ] ; then
- emit_signature "" "" "$7" "" "" "$6"
- fi
- echo " };" >> ${OUTPUT}
- }
- #
- # Emit check sum sub node
- #
- emit_cksum() {
- csum_list=$@
- count=1
- for csum in ${csum_list}; do
- cat << EOF >> ${OUTPUT}
- hash@${count} {
- algo = "${csum}";
- };
- EOF
- count=`expr ${count} + 1`
- done
- }
- #
- # Emit signature sub node
- #
- emit_signature() {
- local kernel=$1
- local fdt=$2
- local rootfs=$3
- local kernel_key=$4
- local fdt_key=$5
- local rootfs_key=$6
- local imgs=""
- local count=0
- local chk_list="" algo="" algos="" i=""
- for i in kernel fdt rootfs; do
- eval algo=\$$i
- eval key=\$${i}_key
- [ -n "$algo" ] || continue
- if ! echo "$algos" | grep -q $algo; then
- if [ -z "$algos" ]; then
- algos=$algo
- else
- algos="${algos} $algo"
- fi
- fi
- if ! echo "$keys" | grep -q $key; then
- if [ -z "$keys" ]; then
- keys=$key
- else
- keys="${keys} $key"
- fi
- fi
- done
- for algo in $algos; do
- for key in $keys; do
- img=""
- for i in kernel fdt rootfs; do
- eval tmp_algo=\$$i
- eval tmp_key=\$${i}_key
- [ "$tmp_algo" == "$algo" ] || continue
- [ "$tmp_key" == "$key" ] || continue
- if [ -z "$img" ]; then
- img=$i
- else
- img=${img},$i
- fi
- done
- [ -n "$img" ] || continue
- cat << EOF >> ${OUTPUT}
- signature@${count} {
- algo = "${algo}";
- key-name-hint = "${key}";
- EOF
- if [ -n "$SIGN_IN_CONF" ] ; then
- echo " sign-images = \"$img\";" >> ${OUTPUT}
- fi
- echo " };" >> ${OUTPUT}
- count=`expr ${count} + 1`
- done
- done
- }
- #
- # Emit config sub nodes
- #
- emit_config() {
- local conf_csum="sha1"
- config_name="conf@${1}"
- if [ ! -z "${11}" ]; then
- config_name="${11}"
- fi
- if [ -z "${2}" ]; then
- echo "Error: config has no kernel img, skipping conf node!"
- return 0
- fi
- # Test if we have any DTBs at all
- if [ -z "${3}" ] ; then
- conf_desc="Boot Linux kernel"
- fdt_line=""
- else
- conf_desc="Boot Linux kernel with FDT blob"
- fdt_line="
- fdt = \"fdt@${3}\";"
- fi
- # Test if we have any ROOTFS at all
- if [ -n "${4}" ] ; then
- conf_desc="$conf_desc + ramdisk"
- fdt_line="${fdt_line}
- ramdisk = \"ramdisk@${4}\";"
- fi
- kernel_line="kernel = \"kernel@${2}\";"
- cat << EOF >> ${OUTPUT}
- ${config_name} {
- description = "${conf_desc}";
- ${kernel_line}${fdt_line}
- hash@1 {
- algo = "${conf_csum}";
- };
- EOF
- if [ -n "$SIGN_IN_CONF" ] ; then
- emit_signature "$5" "$6" "$7" "$8" "$9" "${10}"
- fi
- echo " };" >> ${OUTPUT}
- }
- #
- # remove prefix space
- #
- remove_prefix_space()
- {
- echo "$@" | sed "s:^ ::g"
- }
- #
- # generate image nodes and its subnodes
- #
- emit_image_nodes()
- {
- local t img_c img_i img_index chk
- local img_type img_path img_count img_loadadr img_entrypoint \
- img_compression img_hash img_conf img_name img_key img_sign \
- img_index
- emit_its imagestart
- for t in "kernel" "fdt" "ramdisk"; do
- img_index=0
- for a in ${img_array[@]}; do
- img_type=$(array_get $a 0)
- img_path=$(array_get $a 1)
- img_count=$(array_get $a 2)
- img_loadadr=$(array_get $a 3)
- img_entrypoint=$(array_get $a 4)
- img_compression=$(array_get $a 5)
- img_hash=$(array_get $a 6)
- img_conf=$(array_get $a 7)
- img_name=$(array_get $a 8)
- img_key=$(array_get $a 9)
- img_sign=$(array_get $a 10)
- img_cname=$(array_get $a 11)
-
- img_conf=$(remove_prefix_space $img_conf)
- img_hash=$(remove_prefix_space $img_hash)
- [ "${img_type}" == $t ] || continue
- # generate sub nodes
- eval chk=\$DEF_$t
- [ -n "${chk}" ] || eval DEF_$t=$img_count
- case $t in
- kernel) emit_kernel "$img_path" "$img_count" \
- "$img_loadadr" "$img_entrypoint" \
- "$img_compression" "$img_hash" \
- "$img_name" "$img_key" "$img_sign";;
- fdt) emit_fdt "$img_path" "$img_count" \
- "$img_compression" "$img_hash" \
- "$img_name" "$img_loadadr" "$img_key" "$img_sign" ;;
- ramdisk) emit_ramdisk "$img_path" "$img_count" \
- "$img_compression" "$img_hash" \
- "$img_name" "$img_key" "$img_sign";;
- esac
- # set up configuration data
- for img_c in $img_conf; do
- img_i=""
- #set up default configuration if its not set
- [ -n "$DEF_CONFIG" ] || DEF_CONFIG=$img_c
- [ -z "${img_c}" ] || conf_array[$img_c]=conf$img_c
- array_put conf$img_c 0 ${img_c}
- case $t in
- kernel) img_i=1;;
- fdt) img_i=2;;
- ramdisk) img_i=3;;
- esac
- array_put conf$img_c $img_i $img_index
- array_put conf$img_c $(($img_i + 3)) ${img_sign}
- array_put conf$img_c $(($img_i + 6)) ${img_key}
- array_put conf$img_c 10 $img_cname
- done
- img_index=$((img_index + 1))
- done
- done
- emit_its sectend
- }
- #
- # generate configuration node and its subnodes
- #
- emit_configuration_nodes ()
- {
- local count kernel fdt ramdisk ker_file fdt_file rfs_file ker_sign \
- fdt_sign rfs_sign
- emit_its confstart $DEF_CONFIG
- for a in ${conf_array[@]}; do
- count=$(array_get $a 0)
- kernel=$(array_get $a 1)
- fdt=$(array_get $a 2)
- ramdisk=$(array_get $a 3)
- er_file=$(array_get $a 4)
- fdt_file=$(array_get $a 5)
- rfs_file=$(array_get $a 6)
- ker_sign=$(array_get $a 7)
- fdt_sign=$(array_get $a 8)
- rfs_sign=$(array_get $a 9)
- cname=$(array_get $a 10)
- emit_config "$count" "$kernel" "$fdt" "$ramdisk" "$ker_file" \
- "$fdt_file" "$rfs_file" "$ker_sign" "$fdt_sign" \
- "$rfs_sign" "${cname}"
- done
- if [ -z "${DEF_CONFIG}" ]; then
- emit_config "0" "$DEF_kernel" "$DEF_fdt" "$DEF_ramdisk"
- fi
- emit_its sectend
- }
- # Set to none empty to create signature sub node under images node
- SIGN_IN_CONF=${SIGN_IN_CONF:-""}
- # Set to default config used
- DEF_CONFIG=${DEF_CONFIG:-""}
- parse_args $@
- emit_its fitstart
- emit_image_nodes
- emit_configuration_nodes
- emit_its fitend
|