diff --git a/target/linux/mvebu/cortexa9/base-files/lib/upgrade/fortinet.sh b/target/linux/mvebu/cortexa9/base-files/lib/upgrade/fortinet.sh index a2742aa3743..3badb0583ab 100644 --- a/target/linux/mvebu/cortexa9/base-files/lib/upgrade/fortinet.sh +++ b/target/linux/mvebu/cortexa9/base-files/lib/upgrade/fortinet.sh @@ -1,31 +1,129 @@ . /lib/functions.sh -fortinet_fwinfo_blocks() { +fortinet_bswap32() { + local val="$(printf %08x $(($1)))" + + # swap and print in hex + echo "0x${val:6:2}${val:4:2}${val:2:2}${val:0:2}" +} + +fortinet_by2bl() { + local blks="$(($1 / 0x200))" + [ $(($1 % 0x200)) -gt 0 ] && blks=$((blks + 1)) + + printf "0x%08x" $blks +} + +fortinet_bl2by() { + printf "0x%08x" $(($1 * 0x200)) +} + +fortinet_build_partmap() { + local new="$1" old="$2" + local len="${old%%@*}" ofs="${old##*@}" + + case "$new" in + @*) ofs="$(fortinet_by2bl ${new##@})" ;; # "@" + + *@*) len="$(fortinet_by2bl ${new%%@*})" # "@" + ofs="$(fortinet_by2bl ${new##*@})" ;; + + "") ;; # "" (empty) + + *) len="$(fortinet_by2bl ${new%%@*})" ;; # "" + esac + + # print N blocks of length/offset in dec + echo "${len}@${ofs}" +} + +# Update firmware information in "firmware-info" partition +# +# parameters: +# $1: image index (0/1) +# $2: new image name (up to 32 characters) +# $3: length and/or offset for kernel (bytes) +# $4: length and/or offset for rootfs (bytes) +# +# Note: $3 and $4 support multiple formats: +# +# - @: set and +# - : set and keep the current offset +# - @ : set and keep the current length +# - "" (empty) : keep the current length and offset +fortinet_update_fwinfo() { local fwinfo_mtd="$(find_mtd_part firmware-info)" - local offset="$1" - local len="$2" - local blks + local index="$1" + local name="$2" + local offset + local old_kr + local old new tmp part pos + local output if [ -z "$fwinfo_mtd" ]; then - echo "WARN: MTD device \"firmware-info\" not found" + echo "ERROR: MTD device \"firmware-info\" not found" return 1 fi - blks=$((len / 0x200)) - [ $((len % 0x200)) -gt 0 ] && blks=$((blks + 1)) - blks=$(printf "%04x" $blks) - printf "fwinfo: offset-> 0x%x, blocks-> 0x%s (len: 0x%08x)\n" \ - $offset $blks $len + # Image Name + case "$index" in + 0) offset=0x10 ;; + 1) offset=0x30 ;; + *) echo "ERROR: invalid image index specified!"; return 1 ;; + esac - printf "\x${blks:2:2}\x${blks:0:2}" | \ - dd bs=2 count=1 seek=$((offset / 2)) conv=notrunc of=${fwinfo_mtd} + printf "Image Index: %d\n" $index + + old="$(dd bs=16 count=2 skip=$((offset / 16)) if=$fwinfo_mtd 2>/dev/null)" + printf "Image Name : \"%s\"\n" "$old" + if [ -n "$name" ]; then + echo -n "$name" | \ + dd bs=32 count=1 oflag=seek_bytes seek=$((offset)) \ + conv=sync,notrunc of=$fwinfo_mtd 2>/dev/null + printf " --> \"%s\"\n\n" "$name" + else + printf "\n" + fi + + # length/offset values of kernel/rootfs + case "$index" in + 0) offset=0x180 ;; + 1) offset=0x190 ;; + esac + + # + old_kr="$(hexdump -n 16 -v -s $((offset)) -e '1/4 "%08x"' $fwinfo_mtd)" + + pos=0 + for part in kernel rootfs; do + old="0x${old_kr:$((8 + pos)):8}@0x${old_kr:$((0 + pos)):8}" + new="$(fortinet_build_partmap "$3" "$old")" + shift + + printf " %s:\n" $part + printf " old: 0x%08x@0x%08x\n" \ + $(fortinet_bl2by ${old%%@*}) $(fortinet_bl2by ${old##*@}) + printf " new: 0x%08x@0x%08x\n\n" \ + $(fortinet_bl2by ${new%%@*}) $(fortinet_bl2by ${new##*@}) + + tmp="$(fortinet_bswap32 ${new%%@*})@$(fortinet_bswap32 ${new##*@})" + new="$(echo $tmp | sed 's/0x\([0-9a-f]\{8\}\)@0x\([0-9a-f]\{8\}\)/\2\1/')" + output="${output}${new}" + + pos=$((pos + 16)) + done + + data_2bin "$output" | \ + dd bs=16 count=1 seek=$((offset / 16)) conv=notrunc \ + of=$fwinfo_mtd 2>/dev/null } fortinet_do_upgrade() { local board_dir="$(tar tf "$1" | grep -m 1 '^sysupgrade-.*/$')" local kern_mtd="$(find_mtd_part kernel)" local root_mtd="$(find_mtd_part rootfs)" - local kern_len root_len + local kern_len kern_ofs root_len root_ofs + local imgname board_dir="${board_dir%/}" @@ -34,6 +132,14 @@ fortinet_do_upgrade() { umount -a reboot -f fi + kern_ofs=$(cat /sys/class/mtd/${kern_mtd//\/dev\/mtdblock/mtd}/offset) + root_ofs=$(cat /sys/class/mtd/${root_mtd//\/dev\/mtdblock/mtd}/offset) + + if [ -z "$kern_ofs" ] || [ -z "$root_ofs" ]; then + echo "ERROR: failed to get offset of kernel or rootfs" + umount -a + reboot -f + fi kern_len=$( (tar xOf "$1" "$board_dir/kernel" | wc -c) 2> /dev/null) root_len=$( (tar xOf "$1" "$board_dir/root" | wc -c) 2> /dev/null) @@ -44,8 +150,34 @@ fortinet_do_upgrade() { reboot -f fi - fortinet_fwinfo_blocks "0x184" "$kern_len" - fortinet_fwinfo_blocks "0x18c" "$root_len" + # try to load and parse /tmp/sysupgrade.meta for image name + if [ -r "/tmp/sysupgrade.meta" ]; then + local key value + + sed -e 's/, \{1,2\}\"/\n"/g' \ + -e 's/{ \{1,2\}/\n/g' \ + -e 's/ \{1,2\}}/\n/g' < /tmp/sysupgrade.meta \ + > /tmp/sysupgrade.meta.tmp + while read key value; do + key="${key//\"/}" + value="${value//\"/}" + + [ -z "$value" ] && continue + case "$key" in + dist:|\ + version:|\ + revision:) imgname="${imgname}$value " ;; + esac + done < /tmp/sysupgrade.meta.tmp + else + imgname="OpenWrt" + fi + + fortinet_update_fwinfo 0 "${imgname%% }" \ + "${kern_len}@${kern_ofs}" "${root_len}@${root_ofs}" || { + umount -a + reboot -f + } tar xOf "$1" "$board_dir/kernel" | \ mtd write - "kernel" diff --git a/target/linux/mvebu/cortexa9/base-files/lib/upgrade/platform.sh b/target/linux/mvebu/cortexa9/base-files/lib/upgrade/platform.sh index a15823d8c68..049f8eeb8c8 100755 --- a/target/linux/mvebu/cortexa9/base-files/lib/upgrade/platform.sh +++ b/target/linux/mvebu/cortexa9/base-files/lib/upgrade/platform.sh @@ -3,7 +3,7 @@ # Copyright (C) 2016 LEDE-Project.org # -RAMFS_COPY_BIN='fw_printenv fw_setenv strings' +RAMFS_COPY_BIN='fw_printenv fw_setenv seq strings' RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock' PART_NAME=firmware