aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/make-ras.sh196
1 files changed, 196 insertions, 0 deletions
diff --git a/scripts/make-ras.sh b/scripts/make-ras.sh
new file mode 100755
index 0000000000..ccddaa0016
--- /dev/null
+++ b/scripts/make-ras.sh
@@ -0,0 +1,196 @@
+#!/usr/bin/env bash
+#
+# --- ZyXEL header format ---
+# Original Version by Benjamin Berg <benjamin@sipsolutions.net>
+#
+# The firmware image prefixed with a header (which is written into the MTD device).
+# The header is one erase block (~64KiB) in size, but the checksum only convers the
+# first 2KiB. Padding is 0xff. All integers are in big-endian.
+#
+# The checksum is always a 16-Bit System V checksum (sum -s) stored in a 32-Bit integer.
+#
+# 4 bytes: checksum of the rootfs image
+# 4 bytes: length of the contained rootfs image file (big endian)
+# 32 bytes: Firmware Version string (NUL terminated, 0xff padded)
+# 4 bytes: checksum over the header partition (big endian - see below)
+# 32 bytes: Model (e.g. "NBG6617", NUL termiated, 0xff padded)
+# 4 bytes: checksum of the kernel partition
+# 4 bytes: length of the contained kernel image file (big endian)
+# rest: 0xff padding
+#
+# The checksums are calculated by adding up all bytes and if a 16bit
+# overflow occurs, one is added and the sum is masked to 16 bit:
+# csum = csum + databyte; if (csum > 0xffff) { csum += 1; csum &= 0xffff };
+# Should the file have an odd number of bytes then the byte len-0x800 is
+# used additionally.
+#
+# The checksum for the header is calculated over the first 2048 bytes with
+# the rootfs image checksum as the placeholder during calculation.
+#
+# The header is padded with 0xff to the erase block size of the device.
+#
+board=""
+version=""
+kernel=""
+rootfs=""
+outfile=""
+err=""
+
+while [ "$1" ]; do
+ case "$1" in
+ "--board")
+ board="$2"
+ shift
+ shift
+ continue
+ ;;
+ "--version")
+ version="$2"
+ shift
+ shift
+ continue
+ ;;
+ "--kernel")
+ kernel="$2"
+ shift
+ shift
+ continue
+ ;;
+ "--rootfs")
+ rootfs="$2"
+ shift
+ shift
+ continue
+ ;;
+ "--rootfssize")
+ rootfssize="$2"
+ shift
+ shift
+ continue
+ ;;
+ *)
+ if [ ! "$outfile" ]; then
+ outfile=$1
+ shift
+ continue
+ fi
+ ;;
+ esac
+done
+
+if [ ! -n "$board" -o ! -n "$version" -o ! -r "$kernel" -o ! -r "$rootfs" -o ! "$rootfssize" -o ! "$outfile" ]; then
+ echo "syntax: $0 [--board ras-boardname] [--version ras-version] [--kernel kernelimage] [--rootfs rootfs] out"
+ exit 1
+fi
+
+rootfs_len=$(wc -c < "$rootfs")
+
+if [ "$rootfs_len" -lt "$rootfssize" ]; then
+ dd if=$rootfs of=$rootfs.new bs=$rootfssize conv=sync
+ mv $rootfs.new $rootfs
+fi
+
+if [ ${#version} -ge 28 ]; then
+ echo "version: '$version' is too long"
+ exit 1
+fi
+
+tmpdir="$( mktemp -d 2> /dev/null )"
+if [ -z "$tmpdir" ]; then
+ # try OSX signature
+ tmpdir="$( mktemp -t 'ubitmp' -d )"
+fi
+
+if [ -z "$tmpdir" ]; then
+ exit 1
+fi
+
+to_be() {
+ local val="$1"
+ local size="$2"
+
+ case "$size" in
+ 4)
+ echo $(( "$val" >> 24 | ("$val" & 0xff0000) >> 8 | ("$val" & 0xff00) << 8 | ("$val" & 0xff) << 24 ))
+ ;;
+ 2)
+ echo $(( "$val" >> 8 | ("$val" & 0xff) << 8))
+ ;;
+ esac
+}
+
+checksum_file() {
+ local file=$1
+
+ # ZyXEL seems to use System V sum mode... Now this is classy, who would have thought?!
+ echo $(sum -s ${file} | cut -f1 -d" ")
+}
+
+append_bin() {
+ local val=$1
+ local size=$2
+ local file=$3
+
+ while [ "$size" -ne 0 ]; do
+ printf \\$(printf %o $(("$val" & 0xff))) >> "$file"
+ val=$(($val >> 8))
+ let size-=1
+ done
+ return
+}
+
+tf=${tmpdir}/out
+pad=$(printf '%0.1s' $(printf "\xff"){1..64})
+
+rootfs_header_file="$tmpdir/rootfs_header"
+rootfs_chksum=$(to_be $(checksum_file ${rootfs}) 4)
+rootfs_len=$(to_be $(wc -c < "$rootfs") 4)
+
+versionpadlen=$(( 32 - ( ${#version} + 1) ))
+
+# 4 bytes: checksum of the rootfs image
+append_bin "$rootfs_chksum" 4 "$rootfs_header_file"
+# 4 bytes: length of the contained rootfs image file (big endian)
+append_bin "$rootfs_len" 4 "$rootfs_header_file"
+# 32 bytes: Firmware Version string (NUL terminated, 0xff padded)
+printf "%s\x00%.*s" "$version" "$versionpadlen" "$pad" >> "$rootfs_header_file"
+
+kernel_header_file="$tmpdir/kernel_header"
+kernel_chksum=$(to_be $(checksum_file ${kernel}) 4)
+kernel_len=$(to_be $(wc -c < "$kernel") 4)
+
+# 4 bytes: checksum of the kernel image
+append_bin "$kernel_chksum" 4 "$kernel_header_file"
+# 4 bytes: length of the contained kernel image file (big endian)
+append_bin "$kernel_len" 4 "$kernel_header_file"
+
+board_header_file="$tmpdir/board_header"
+board_file="$tmpdir/board"
+boardpadlen=$(( 64 - ( ${#board} + 1) ))
+# 32 bytes: Model (e.g. "NBG6617", NUL termiated, 0xff padded)
+printf "%s\x00%.*s" "$board" "$boardpadlen" "$pad" > "$board_file"
+cat "$kernel_header_file" >> "$board_file"
+printf "%.12s" "$pad" >> "$board_file"
+# rest: 0xff padding
+for i in {1..511}; do
+ printf "%s%s" "$pad" "$pad" >> "$board_file"
+done
+
+tmp_board_file="$tmpdir/tmp_board_file"
+cat "$rootfs_header_file" > "$tmp_board_file"
+
+# The checksum for the header is calculated over the first 2048 bytes with
+# the rootfs image checksum as the placeholder during calculation.
+append_bin "$rootfs_chksum" 4 "$tmp_board_file"
+cat "$board_file" >> "$tmp_board_file"
+
+truncate -s 2048 $tmp_board_file
+board_chksum=$(to_be $(checksum_file ${tmp_board_file}) 4)
+
+# 4 bytes: checksum over the header partition (big endian)
+append_bin "$board_chksum" 4 "$board_header_file"
+cat "$board_file" >> "$board_header_file"
+
+cat "$rootfs_header_file" "$board_header_file" "$rootfs" "$kernel" > "$outfile"
+
+rm -rf "$tmpdir"