The new mkits.sh is a complete new implementation to support: - multi-configuration (upto 10 with -c option). First -c used defines the default conf used. - multi-image support - multiple kernel/fdt/ramdsik image (upto 50 images) - per image configuration: Tools now reuse the option for each images - hash algorithm and generated required subnodes - compression - signature and generated required subnodes (not tested)
This allows user to generate a simple its that only has one configuration that only boot with 1 kernel + 1 fdt to 4 different boot configuration with different image combination. For an example: creating a its with 2 kernel, 1 dtb, 2 rootfs images and has the following configurations: 1: kernel0 + dtb0 + rootfs0 (default boot configuration) 2. kernel0 + dtb0 + rootfs1 3. kernel1 + dtb0 + rootfs0 4. kernel1 + dtb0 + rootfs1 5. kernel0 + dtb1 where kernel1 and rootfs0 is gzip compressed. The command to generate the its is shown as follows: $ ./mkits.sh -A arm -v 4.4 -k kernel0 -C none -c 1 -c 2 -c5 \ -k kernel1 -C gzip -c 3 -c 4 -h crc32 \ -d dtb0 -c 1 -c 2 -c 3 -c 4 -h sha1 -h crc32\ -d dtb1 -c 5 -h sha1 \ -r rootfs0 -C gzip -c 1 -c 2 \ -r rootfs1 -C none -c3 -c4 First -c option used defines the default boot configuration. The key benefit is to have more flexible ITS generation. A typical example, is to create a fitImage with 1 kernel with multiple dtb to provide different features. E.g. system boot with ramdisk or sdroot or nfsroot and etc. Signed-off-by: Jason Wu <jason.wu.m...@gmail.com> --- v2: - Fix -D use before -c options - add additional array checking to prevent undeclared array diff --git a/target/linux/zynq/image/Makefile b/target/linux/zynq/image/Makefile index 99293a6..ee4ff61 100644 --- a/target/linux/zynq/image/Makefile +++ b/target/linux/zynq/image/Makefile @@ -32,14 +32,15 @@ define Image/boot-imgs # create FIT image with rootfs ./mkits.sh \ - -D $(DEVICE_LC) -o $(KDIR)/fit-$(DEVICE_LC).its -k $(KDIR)/zImage \ - -d $(BIN_DIR)/$(IMG_PREFIX)-system.dtb \ + -o $(KDIR)/fit-$(DEVICE_LC).its -A $(ARCH) \ + -v $(LINUX_VERSION) \ + -k $(KDIR)/zImage -D $(DEVICE_LC) \ -C none -a $(KERNEL_LOADADDR) -e $(KERNEL_ENTRY_POINT) \ - -A $(ARCH) -v $(LINUX_VERSION) \ - -r $(BIN_DIR)/$(IMG_PREFIX)-rootfs.cpio.gz -z gzip + -d $(BIN_DIR)/$(IMG_PREFIX)-system.dtb \ + -r $(BIN_DIR)/$(IMG_PREFIX)-rootfs.cpio.gz \ + -C gzip PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) mkimage -f $(KDIR)/fit-$(DEVICE_LC).its $(KDIR)/fit-$(DEVICE_LC).itb $(CP) $(KDIR)/fit-$(DEVICE_LC).itb $(BIN_DIR)/$(IMG_PREFIX)-fit.itb - ln -fs $(IMG_PREFIX)-fit.itb $(BIN_DIR)/fit.itb endef diff --git a/target/linux/zynq/image/mkits.sh b/target/linux/zynq/image/mkits.sh index 2b00d0f..ff6a338 100755 --- a/target/linux/zynq/image/mkits.sh +++ b/target/linux/zynq/image/mkits.sh @@ -1,8 +1,8 @@ -#!/bin/bash +#!/usr/bin/env bash # # Licensed under the terms of the GNU GPL License version 2 or later. # -# Author: Peter Tyser <pty...@xes-inc.com> +# Author: Jason Wu <jason.hy...@gmail.com> # # U-Boot firmware supports the booting of images in the Flattened Image # Tree (FIT) format. The FIT format uses a device tree structure to @@ -13,138 +13,569 @@ # 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 + +# 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 usage() { - echo "Usage: `basename $0` -A arch -C comp -a addr -e entry" \ - "-v version -k kernel [-D name -d dtb] -o its_file" + 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-v ==> set kernel version to 'version'" - echo -e "\t-k ==> include kernel image 'kernel'" - echo -e "\t-D ==> human friendly Device Tree Blob 'name'" - echo -e "\t-d ==> include Device Tree Blob 'dtb'" - echo -e "\t-r ==> include ramdisk" - echo -e "\t-z ==> ramdisk compression type" - echo -e "\t-o ==> create output file 'its_file'" + 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 } -while getopts ":A:a:C:D:d:e:k:o:v:r:z:" OPTION -do - case $OPTION in - A ) ARCH=$OPTARG;; - a ) LOAD_ADDR=$OPTARG;; - C ) COMPRESS=$OPTARG;; - D ) DEVICE=$OPTARG;; - d ) DTB=$OPTARG;; - e ) ENTRY_ADDR=$OPTARG;; - k ) KERNEL=$OPTARG;; - o ) OUTPUT=$OPTARG;; - v ) VERSION=$OPTARG;; - r ) RAMDISK=$OPTARG;; - z ) RD_COMPRESS=$OPTARG;; - * ) echo "Invalid option passed to '$0' (options:$@)" - usage;; - esac -done +array_check() +{ + local a=999 + local max_a=0 + local max_i=0 -# Make sure user entered all required parameters -if [ -z "${ARCH}" ] || [ -z "${COMPRESS}" ] || [ -z "${LOAD_ADDR}" ] || \ - [ -z "${ENTRY_ADDR}" ] || [ -z "${VERSION}" ] || [ -z "${KERNEL}" ] || \ - [ -z "${OUTPUT}" ]; then - usage -fi - -ARCH_UPPER=`echo $ARCH | tr '[:lower:]' '[:upper:]'` - -# Conditionally create fdt information -if [ -n "${DTB}" ]; then - FDT=" - fdt@1 { - description = \"${ARCH_UPPER} OpenWrt ${DEVICE} device tree blob\"; - data = /incbin/(\"${DTB}\"); - type = \"flat_dt\"; - arch = \"${ARCH}\"; - compression = \"none\"; - hash@1 { - algo = \"crc32\"; - }; - hash@2 { - algo = \"sha1\"; - }; - }; -" - CONF=" fdt = \"fdt@1\";" -fi - -# Conditionally create ramdisk node -if [ -n "${RAMDISK}" ]; then - RD_COMPRESS=${RD_COMPRESS:-none} - RD=" - ramdisk@1 { - description = \"${ARCH_UPPER} OpenWrt ${DEVICE} ramdisk\"; - data = /incbin/(\"${RAMDISK}\"); - type = \"ramdisk\"; - arch = \"${ARCH}\"; - os = \"linux\"; - compression = \"${RD_COMPRESS}\"; - hash@1 { - algo = \"crc32\"; - }; - hash@2 { - algo = \"sha1\"; - }; - }; -" - if [ -z "${CONF}" ]; then - CONF=" ramdisk = \"ramdisk@1\";" + 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=9 + 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 - CONF="$CONF - ramdisk = \"ramdisk@1\";" + 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:" 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;; + 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 + [ -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 -fi +} -# Create a default, fully populated DTS file -DATA="/dts-v1/; +# +# 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 = \"${ARCH_UPPER} OpenWrt FIT (Flattened Image Tree)\"; + 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}\";" \ + >> ${OUTPUT};; + sectend) + echo -e "\t};" >> ${OUTPUT};; + fitend) + echo -e "};" >> ${OUTPUT};; + esac +} - images { - kernel@1 { - description = \"${ARCH_UPPER} OpenWrt Linux-${VERSION}\"; - data = /incbin/(\"${KERNEL}\"); - type = \"kernel\"; - arch = \"${ARCH}\"; - os = \"linux\"; - compression = \"${COMPRESS}\"; - load = <${LOAD_ADDR}>; - entry = <${ENTRY_ADDR}>; - hash@1 { - algo = \"crc32\"; +# +# 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} + + [ -z "${name}" ] || name=" ${name}" + cat << EOF >> ${OUTPUT} + fdt@${count} { + description = "Flattened Device Tree blob${name}"; + data = /incbin/("${image}"); + type = "flat_dt"; + arch = "${ARCH}"; + 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}"; }; - hash@2 { - algo = \"sha1\"; +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" + + 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} + conf@${1} { + 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" +} -${RD} -${FDT} +# +# 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 + + 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_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_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 + [ -n "${img_c}" ] || continue + [ -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} + 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) + emit_config "$count" "$kernel" "$fdt" "$ramdisk" "$ker_file" \ + "$fdt_file" "$rfs_file" "$ker_sign" "$fdt_sign" \ + "$rfs_sign" + 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:-""} - configurations { - default = \"config@1\"; - config@1 { - description = \"OpenWrt\"; - kernel = \"kernel@1\"; -${CONF} - }; - }; -};" +parse_args $@ -# Write .its file to disk -echo "$DATA" > ${OUTPUT} +emit_its fitstart +emit_image_nodes +emit_configuration_nodes +emit_its fitend -- 1.9.1 _______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel