its-maker.sh creates an .its file, given a series of arguments, which is then used to create a FIT image.
Required to support the tew827dru, but intended to support the creation of any valid .its file. Signed-off-by: jmomo <jm...@jmomo.net> --- scripts/its-maker.sh | 598 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 598 insertions(+) create mode 100644 scripts/its-maker.sh This is a new script to make ITS files, which are then used to produce a FIT image. The existing mkits.sh script was device-specific and otherwise can not produce the FIT I need. It does not support configurations, yet, but I'll add that if desired. After I wrote my script, I became aware that Jason Wu was working on fixing up mkits.sh, but there hasn't been any progress and I'm not sure he's still interested in working on it. I will make him aware of my work: https://patchwork.ozlabs.org/patch/599455/ diff --git a/scripts/its-maker.sh b/scripts/its-maker.sh new file mode 100644 index 0000000..7f4ba26 --- /dev/null +++ b/scripts/its-maker.sh @@ -0,0 +1,598 @@ +#!/bin/bash +# +# Create a u-boot FIT ITS (Image Tree Source) file given a convoluted series of arguments. +# +# Combination use of leading tabs and spaces is intentional for here-doc (<<-) and should be preserved. +# +# TODO: +# Support for Configurations not done. +# Clean up trap on interupt, etc. +# Mandatory/optional fields could be better. +# Consider harmonizing with mkimage arguments? +# +# References: +# https://casper.berkeley.edu/svn/trunk/roach/sw/uboot/doc/uImage.FIT/source_file_format.txt +# https://lxr.missinglinkelectronics.com/uboot/doc/uImage.FIT/beaglebone_vboot.txt +# http://lists.denx.de/pipermail/u-boot/2008-March/030898.html +# https://wiki.linaro.org/WorkingGroups/Security/Verified-U-boot + +VERSION=1.0 +MYNAME=$(basename $0) +declare -a ar_IMG_NAME +declare -a ar_IMG_DESCR +declare -a ar_IMG_FILE +declare -a ar_IMG_TYPE +declare -a ar_IMG_ARCH +declare -a ar_IMG_OS +declare -a ar_IMG_COMPRESSION +declare -a ar_IMG_LOAD_ADDR +declare -a ar_IMG_ENTRY_ADDR +declare -a ar_IMG_HASHES +declare -a ar_CFG_IDS + +# case +([0-9]) regex requires shopt -s extglob. +shopt -s extglob + +echoerr() { + # Print errors to stderr. + echo "$@" 1>&2; + if [[ -n "$SEEN_ERROR" ]] ; then declare -r SEEN_ERROR=1 ; fi # If we saw any errors, set SEEN_ERROR=1, for later use. +} + +echodebug() { + # Print debug messages to stderr if debugging enabled. + if [[ "$SCRIPT_DEBUG" == 1 ]] ; then + echo "DEBUG: $@" 1>&2; + fi +} + +f_printusage() { + # Print usage info. + cat <<-EOF + Usage: + + --out|-O Output file, otherwise output goes to stdout. + --device|-i Device for which we are building this ITS. + --fit-type|-T The FIT format type. Defaults to "flat_dt". + --fit-description|-D The FIT Description line. + + Image Commands: (all image commands must be followed by an integer ID. + + --img-name|-n The name of the image. + --img-descr|-d The description of the image. + --img-file|-f The image data file. + --img-type|-t The type/format of the image. + --img-arch|-a The arch of the image. + --img-os|-o The OS of the image. + --img-compression|-c The compression of the image. + --img-load-addr|-l The load address for the image. + --img-entry-addr|-e The entry address for the image. + --img-hashes|-s The image hash(es), comma-seperated. + + --debug Debug the $MYNAME script. + help|--help|-h|-H Show help info. + + Example: + + $MYNAME --device Widget5K --fit-type flat_dt --fit-description "Widget 5000 Extreme Edition Plus" --img-name 0 "upgrade-script" --img-descr 0 "Script to upgrade the firmware." --img-file 0 ~/tmp/myfile.scr --img-type 0 script --img-compression 0 none --img-name 1 "OS" --img-descr 1 "Widget 5000 Xe+ Operating System" --img-file 1 ~/tmp/myfile.bin --img-type 1 firmware --img-compression 1 none --img-arch 1 ARM --img-hashes 1 crc32,sha1 + + EOF +} + +f_help () { + # Print some helpful information. + cat <<- EOF + + $MYNAME constructs a u-boot FIT DTS file for use with mkimage. + + $MYNAME version: $VERSION + EOF + f_printusage + return 0 +} + +f_register_img_id () { + # Register the IMG_ID in our ar_IMG_IDS array if needed. + if ! [[ "${ar_IMG_IDS[$1]}" ]] ; then + ar_IMG_IDS+=("$IMG_ID") + echodebug "IMG_ID $IMG_ID added to ar_IMG_IDS" + fi +} + +f_assemble_dts_header () { + cat <<-EOF >> $DTS_BODY + /dts-v1/; + / { + description = "${HEADER_DESCR}"; + #address-cells = <1>; + EOF +} + +f_assemble_img_header () { + cat <<-EOF >> $DTS_BODY + images { + EOF +} + +f_assemble_img_body_header () { + cat <<-EOF >> $DTS_BODY + ${ar_IMG_NAME[$IMG_ID]}@${IMG_ID} { + data = /incbin/("${ar_IMG_FILE[$IMG_ID]}"); + description = "${ar_IMG_DESCR[$IMG_ID]}"; + type = "${ar_IMG_TYPE[$IMG_ID]}"; + compression = "${ar_IMG_COMPRESSION[$IMG_ID]}"; + EOF +} + +f_assemble_img_body_arch () { + cat <<-EOF >> $DTS_BODY + arch = "${ar_IMG_ARCH[$IMG_ID]}"; + EOF +} + +f_assemble_img_body_os () { + cat <<-EOF >> $DTS_BODY + os = "${ar_IMG_OS[$IMG_ID]}"; + EOF +} + +f_assemble_img_body_load-entry () { + cat <<-EOF >> $DTS_BODY + load = <${ar_IMG_LOAD_ADDR[$IMG_ID]}>; + entry = <${ar_IMG_ENTRY_ADDR[$IMG_ID]}>; + EOF +} + +f_assemble_img_body_hash () { + cat <<-EOF >> $DTS_BODY + hash@${HASH_NUM} { + algo = "${HASH_NAME}"; + }; + EOF +} + +f_assemble_img_body_footer () { + cat <<-EOF >> $DTS_BODY + }; + EOF +} + +f_assemble_img_footer () { + cat <<-EOF >> $DTS_BODY + }; + EOF +} + +f_assemble_cfg_header () { + cat <<-EOF >> $DTS_BODY + default = "config@1"; + configurations { + EOF +} + +f_assemble_cfg_body () { + # FIXME: Not done. + cat <<-EOF >> $DTS_BODY + config@1 { + description = "OpenWrt"; + kernel = "kernel@1"; + fdt = "fdt@1"; + }; + EOF +} + +f_assemble_cfg_footer () { + cat <<-EOF >> $DTS_BODY + }; + EOF +} + +f_assemble_dts_footer () { + cat <<-EOF >> $DTS_BODY + }; + EOF +} + +f_validate_in_args3 () { + # Validate $3 input argument. + if [[ -z "$ARG3" ]] ; then + echoerr -e "\nERROR: $ARG1 $IMG_ID argument missing.\n" + exit 1 + fi + if ( echo "$ARG3" | egrep "^--" &> /dev/null ) ; then + # Look out for accidental missing values. However, this does incorrectly prohibit unusual valid data. + echoerr -e "\nERROR: Suspected missing value for $ARG1 $IMG_ID.\n" + exit 1 + fi +} + +# -- + +# No input? Print usage and exit 1. +[[ "$#" -eq 0 ]] && { f_printusage ; exit 1 ; } + +while [[ "$#" -gt 0 ]] ; do case "$1" in + --debug) + SCRIPT_DEBUG=1 + # set -o functrace + # set -x + shift 1 + ;; + help|--help|-h|-H) + f_help + exit $? + ;; + --out|-O) + OUT_FILE=$2 + echodebug "Outfile set to $2" + shift 2 + ;; + --device|-i) + DEVICE=$2 + echodebug "Device set to $2" + shift 2 + ;; + --fit-type|-T) + if [[ -z "$FIT_TYPE" ]] ; then + FIT_TYPE=$2 + echodebug "FIT type set to $2" + shift 2 + else + echoerr -e "\nERROR: --fit-fype was set more than once.\n" + exit 1 + fi + ;; + --fit-description|-D) + if [[ -z "$HEADER_DESCR" ]] ; then + HEADER_DESCR=$2 + echodebug "FIT description set to \"$2\"" + shift 2 + else + echoerr -e "\nERROR: --fit-description was set more than once.\n" + exit 1 + fi + ;; + --img-name|-n) + case "$2" in + +([0-9])) + IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3 + f_validate_in_args3 + if [[ -z "${ar_IMG_NAME[$IMG_ID]}" ]] ; then + f_register_img_id $IMG_ID + ar_IMG_NAME[$IMG_ID]=$3 + echodebug "$1 $IMG_ID set to \"$3\"" + else + echoerr -e "\nERROR: --img-name $IMG_ID was set more than once.\n" + exit 1 + fi + shift 3 ; unset IMG_ID ARG1 ARG2 ARG3 + ;; + *) + echoerr -e "\nERROR: Invalid --img-name ID. Must be an integer.\n" + exit 1 + ;; + esac + ;; + --img-descr|-d) + case "$2" in + +([0-9])) + IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3 + f_validate_in_args3 + if [[ -z "${ar_IMG_DESCR[$IMG_ID]}" ]] ; then + f_register_img_id $IMG_ID + ar_IMG_DESCR[$IMG_ID]=$3 + echodebug "$1 $IMG_ID set to \"$3\"" + else + echoerr -e "\nERROR: --img-descr $IMG_ID was set more than once.\n" + exit 1 + fi + shift 3 ; unset IMG_ID ARG1 ARG2 ARG3 + ;; + *) + echoerr -e "\nERROR: Invalid --img-descr ID. Must be an integer.\n" + exit 1 + ;; + esac + ;; + --img-file|-f) + case "$2" in + +([0-9])) + IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3 + f_validate_in_args3 + if [[ -z "${ar_IMG_FILE[$IMG_ID]}" ]] ; then + f_register_img_id $IMG_ID + ar_IMG_FILE[$IMG_ID]=$3 + echodebug "$1 $IMG_ID set to \"$3\"" + else + echoerr -e "\nERROR: --img-file $IMG_ID was set more than once.\n" + exit 1 + fi + shift 3 ; unset IMG_ID ARG1 ARG2 ARG3 + ;; + *) + echoerr -e "\nERROR: Invalid --img-file ID. Must be an integer.\n" + exit 1 + ;; + esac + ;; + --img-type|-t) + case "$2" in + +([0-9])) + IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3 + f_validate_in_args3 + if [[ -z "${ar_IMG_TYPE[$IMG_ID]}" ]] ; then + f_register_img_id $IMG_ID + ar_IMG_TYPE[$IMG_ID]=$3 + echodebug "$1 $IMG_ID set to \"$3\"" + else + echoerr -e "\nERROR: --img-type $IMG_ID was set more than once.\n" + exit 1 + fi + shift 3 ; unset IMG_ID ARG1 ARG2 ARG3 + ;; + *) + echoerr -e "\nERROR: Invalid --img-type ID. Must be an integer.\n" + exit 1 + ;; + esac + ;; + --img-arch|-a) + case "$2" in + +([0-9])) + IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3 + f_validate_in_args3 + if [[ -z "${ar_IMG_ARCH[$IMG_ID]}" ]] ; then + f_register_img_id $IMG_ID + ar_IMG_ARCH[$IMG_ID]=$3 + echodebug "$1 $IMG_ID set to \"$3\"" + else + echoerr -e "\nERROR: --img-arch $IMG_ID was set more than once.\n" + exit 1 + fi + shift 3 ; unset IMG_ID ARG1 ARG2 ARG3 + ;; + *) + echoerr -e "\nERROR: Invalid --img-arch ID. Must be an integer.\n" + exit 1 + ;; + esac + ;; + --img-os|-o) + case "$2" in + +([0-9])) + IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3 + f_validate_in_args3 + if [[ -z "${ar_IMG_OS[$IMG_ID]}" ]] ; then + f_register_img_id $IMG_ID + ar_IMG_OS[$IMG_ID]=$3 + echodebug "$1 $IMG_ID set to \"$3\"" + else + echoerr -e "\nERROR: --img-os $IMG_ID was set more than once.\n" + exit 1 + fi + shift 3 ; unset IMG_ID ARG1 ARG2 ARG3 + ;; + *) + echoerr -e "\nERROR: Invalid --img-os ID. Must be an integer.\n" + exit 1 + ;; + esac + ;; + --img-compression|-c) + case "$2" in + +([0-9])) + IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3 + f_validate_in_args3 + if [[ -z "${ar_IMG_COMPRESSION[$IMG_ID]}" ]] ; then + f_register_img_id $IMG_ID + ar_IMG_COMPRESSION[$IMG_ID]=$3 + echodebug "$1 $IMG_ID set to \"$3\"" + else + echoerr -e "\nERROR: --img-compression $IMG_ID was set more than once.\n" + exit 1 + fi + shift 3 ; unset IMG_ID ARG1 ARG2 ARG3 + ;; + *) + echoerr -e "\nERROR: Invalid --img-compression ID. Must be an integer.\n" + exit 1 + ;; + esac + ;; + --img-load-addr|-l) + case "$2" in + +([0-9])) + IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3 + f_validate_in_args3 + if [[ -z "${ar_IMG_LOAD_ADDR[$IMG_ID]}" ]] ; then + f_register_img_id $IMG_ID + ar_IMG_LOAD_ADDR[$IMG_ID]=$3 + echodebug "$1 $IMG_ID set to \"$3\"" + else + echoerr -e "\nERROR: --img-load-addr $IMG_ID was set more than once.\n" + exit 1 + fi + shift 3 ; unset IMG_ID ARG1 ARG2 ARG3 + ;; + *) + echoerr -e "\nERROR: Invalid --img-load-addr ID. Must be an integer.\n" + exit 1 + ;; + esac + ;; + --img-entry-addr|-e) + case "$2" in + +([0-9])) + IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3 + f_validate_in_args3 + if [[ -z "${ar_IMG_ENTRY_ADDR[$IMG_ID]}" ]] ; then + f_register_img_id $IMG_ID + ar_IMG_ENTRY_ADDR[$IMG_ID]=$3 + echodebug "$1 $IMG_ID set to \"$3\"" + else + echoerr -e "\nERROR: --img-entry-addr $IMG_ID was set more than once.\n" + exit 1 + fi + shift 3 ; unset IMG_ID ARG1 ARG2 ARG3 + ;; + *) + echoerr -e "\nERROR: Invalid --img-entry-addr ID. Must be an integer.\n" + exit 1 + ;; + esac + ;; + --img-hashes|-s) + case "$2" in + +([0-9])) + IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3 + f_validate_in_args3 + if [[ -z "${ar_IMG_HASHES[$IMG_ID]}" ]] ; then + f_register_img_id $IMG_ID + ar_IMG_HASHES[$IMG_ID]=$3 + echodebug "$1 ${IMG_ID} set to \"$3\"" + else + echoerr -e "\nERROR: --img-hashes $IMG_ID was set more than once.\n" + exit 1 + fi + shift 3 ; unset IMG_ID ARG1 ARG2 ARG3 + ;; + *) + echoerr -e "\nERROR: Invalid --img-hashes ID. Must be an integer.\n" + exit 1 + ;; + esac + ;; + *) + echoerr -e "\nERROR: Invalid argument \"$1\".\n" + f_printusage + exit 1 + ;; +esac ; done + +# Build the ITS. +# NOTE: The ITS format is complicated. It's our job to build the ITS. It's mkimage's job to determine if the content is valid. +# We do some basic validity checking, but producing an invalid ITS is a valid scenerio. + +DTS_BODY=$(mktemp) + +# Assemble the header. +# + +# If we didn't get a FIT/header description, make one up by default. +if [[ -z "$HEADER_DESCR" ]] ; then + if [[ -z "$DEVICE" ]] ; then + HEADER_DESCR="LEDE FIT image" + else # use $DEVICE if we have it. + HEADER_DESCR="LEDE FIT image for ${DEVICE}" + fi +fi + +f_assemble_dts_header + +# At least one image entry is required by the ITS format. +if [[ -z "${ar_IMG_IDS[@]}" ]] ; then + echoerr -e "\nERROR: At least one valid image is required.\n" + exit 1 +fi + +f_assemble_img_header + +# Assemble an Image block for each. +for IMGBLOCK in ${ar_IMG_IDS[@]} ; do + IMG_ID=$IMGBLOCK + echodebug "Processing IMG_ID $IMG_ID" + # The following fields are required for all images: description, type, data, compression. + for EACH in "${ar_IMG_DESCR[$IMG_ID]}" "${ar_IMG_TYPE[$IMG_ID]}" "${ar_IMG_FILE[$IMG_ID]}" "${ar_IMG_COMPRESSION[$IMG_ID]}" ; do + if [[ -z "$EACH" ]] ; then + MISSING_IMG_REQUIRED=1 + fi + done ; unset EACH + [[ "$MISSING_IMG_REQUIRED" == 1 ]] && { + echoerr -e "\nERROR: Missing one or more required attributes for IMG_ID $IMG_ID.\n" + exit 1 ; } + f_assemble_img_body_header + case "${ar_IMG_TYPE[$IMG_ID]}" in # ARCH is conditionally mandatory for certain image types. + standalone|kernel|firmware|ramdisk|fdt) + if [[ -z "${ar_IMG_ARCH[$IMG_ID]}" ]] ; then + echoerr -e "\nERROR: --img-arch required for this image type.\n" + exit 1 + fi + ;; + esac + if [[ -n "${ar_IMG_ARCH[$IMG_ID]}" ]] ; then # Add architecture. + f_assemble_img_body_arch + fi + case "${ar_IMG_TYPE[$IMG_ID]}" in # OS is conditionally mandatory for kernels. + kernel) + if [[ -z "${ar_IMG_OS[$IMG_ID]}" ]] ; then + echoerr -e "\nERROR: --img-os required for this image type.\n" + exit 1 + fi + ;; + esac + if [[ -n "${ar_IMG_OS[$IMG_ID]}" ]] ; then # Add OS. + f_assemble_img_body_os + fi + case "${ar_IMG_TYPE[$IMG_ID]}" in # LOAD/ENTRY is conditionally mandatory for standalone kernels. + standalone|kernel) + if [[ -z "${ar_IMG_LOAD_ADDR[$IMG_ID]}" ]] || [[ -z "${ar_IMG_ENTRY_ADDR[$IMG_ID]}" ]]; then + echoerr -e "\nERROR: --img-load-addr and --img-entry-addr are required for this image type.\n" + exit 1 + fi + ;; + esac + if [[ -n "${ar_IMG_LOAD_ADDR[$IMG_ID]}" ]] && [[ -n "${ar_IMG_ENTRY_ADDR[$IMG_ID]}" ]]; then # Load and entry required together. + f_assemble_img_body_load-entry + # FIXME: Error on one but not the other. + fi + if [[ -n "${ar_IMG_HASHES[$IMG_ID]}" ]] ; then # Hashes are optional. + echodebug "IMG_ID $IMG_ID has hashes" + HASH_NUM=0 + while IFS=',' ; do + for EACH in ${ar_IMG_HASHES[$IMG_ID]} ; do + echodebug "Processing IMG_ID $IMG_ID HASH_ID $EACH" + HASH_NAME=$EACH + f_assemble_img_body_hash + HASH_NUM=$(( HASH_NUM + 1 )) + done ; unset EACH + break + done ; unset HASH_NUM HASH_NAME + fi + f_assemble_img_body_footer +done ; unset IMGBLOCK IMG_ID + +f_assemble_img_footer + +# Assemble a Configuration block for each. +# FIXME: not done. +for EACH in ${ar_CFG_IDS[@]} ; do + CFG_ID=$EACH + f_assemble_cfg_header + f_assemble_cfg_body + f_assemble_cfg_footer +done ; unset EACH CFG_ID + +# Assemble the footer. +f_assemble_dts_footer + +# If we don't have an output file, print to stdout. +if [[ -z "$OUT_FILE" ]] ; then + echodebug "Printing DTS to stdout" + cat "$DTS_BODY" && rm -f "$DTS_BODY" +else + # Make sure we are not going to clobber a file. + if [[ -f "$OUT_FILE" ]] ; then + echoerr -e "\nERROR: Output file \"OUT_FILE\" already exists!.\n" + exit 1 + fi + echodebug "Writing output file." + cat "$DTS_BODY" > $OUT_FILE ; X_WRITE_OUT=$? + if [[ "$X_WRITE_OUT" == 0 ]] ; then + echo -e "\nDTS file written to: $OUT_FILE\n" + rm -f "$DTS_BODY" + else + echoerr -e "\nERROR: Writing output file failed.\n" + exit 1 + fi +fi + -- 2.9.3 _______________________________________________ Lede-dev mailing list Lede-dev@lists.infradead.org http://lists.infradead.org/mailman/listinfo/lede-dev