]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
econet: tclinux-trx.sh make rootfs optional and move padding to kernel
authorCaleb James DeLisle <cjd@cjdns.fr>
Mon, 25 May 2026 13:40:18 +0000 (13:40 +0000)
committerJonas Jelonek <jelonek.jonas@gmail.com>
Wed, 22 Jul 2026 15:11:23 +0000 (17:11 +0200)
The TRX header contains a checksum of the full kernel and rootfs length. Vendor
OS uses a raw squashfs on the NAND and relies on the BMT to resolve bad block
issues. OpenWrt typically uses UBI on NAND and places the root squashfs inside
of that. Since UBI changes over time, checksumming over it would cause a boot
failure later on. However, vendor TRX installers typically the entire file as
uploaded, without regard for the declared kernel and rootfs lengths.

Make --rootfs optional so that a UBI rootfs can be appended but excluded from
the checksum.

Secondly, this script previously prepended padding to the rootfs in order to
move the beginning of the rootfs 4MB away from the TRX header (the max kernel
size). That prepended padding was included in the rootfs length/checksum.

There is a bug https://econet-linux.pkt.wiki/en/bootloader#a-length-bug in some
versions of the bootloader which causes the bootloader to always use the length
of the first kernel, even if it is booting the second. The impact of this is if
the second slot kernel is larger than the first, it will fail to boot. Smaller
is okay because LZMA will stop when it is done.

Move padding from rootfs to kernel and include it in the length/checksum of the
kernel so that the kernel will always register as being 4MB-minus-TRX-header in
length. Therefore if A/B upgrading is used in the future, this bug will not
occur even if an upgrade with a larger kernel is installed into slot B.

Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
Link: https://github.com/openwrt/openwrt/pull/23533
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
target/linux/econet/image/tclinux-trx.sh

index 3750e9112da4387faef86a39bceee522d61ce368..3f28ba86f93ec8dbcefbc628f614208499dde09d 100755 (executable)
@@ -3,8 +3,14 @@
 
 set -e
 
-# This is not necessary, but it makes finding the rootfs easier.
-PAD_ROOTFS_OFFSET_TO=4194304
+# Maximum kernel size
+# NOTE: We ff-pad the kernel and specify the fully padded length as the kernel
+#       size in the TRX header. This works around a bug wherein the bootloader
+#       reads the kernel length from the kernel in slot A, when it is booting
+#       slot B. By including the padding in the length, the kernel length is
+#       always the same, and the LZMA decompressor stops when it's done anyway.
+#       See: https://econet-linux.pkt.wiki/en/bootloader#a-length-bug
+PAD_ROOTFS_OFFSET_TO=$((4 * 1024 * 1024))
 
 # Constant
 HDRLEN=256
@@ -20,7 +26,7 @@ SYNTAX: $0 --kernel <file> --rootfs <file> --version <string> [options]
 
 Options:
   --kernel   Path to kernel lzma file (required)
-  --rootfs   Path to rootfs squashfs file (required)
+  --rootfs   Path to rootfs squashfs file
   --version  Version string, max 31 chars (required)
   --endian   Endianness: 'be' for big endian, 'le' for little endian (default: be)
   --model    Model/platform name, max 31 chars (default: empty)
@@ -69,7 +75,6 @@ done
 
 # Validate required arguments
 [ -n "$kernel" ] || die "Missing required argument: --kernel"
-[ -n "$rootfs" ] || die "Missing required argument: --rootfs"
 [ -n "$version" ] || die "Missing required argument: --version"
 
 # Validate endianness
@@ -81,28 +86,27 @@ esac
 
 which zytrx >/dev/null || die "zytrx not found in PATH $PATH"
 [ -f "$kernel" ] || die "Kernel file not found: $kernel"
-[ -f "$rootfs" ] || die "Rootfs file not found: $rootfs"
+[ -z "$rootfs" ] || [ -f "$rootfs" ] || die "Rootfs file not found: $rootfs"
 [ "$(echo "$version" | wc -c)" -lt 32 ] || die "Version string too long: $version"
 [ -z "$model" ] || [ "$(printf '%s' "$model" | wc -c)" -lt 32 ] || die "Model string too long: $model"
 
 kernel_len=$(stat -c '%s' "$kernel")
 header_plus_kernel_len=$(($HDRLEN + $kernel_len))
-rootfs_len=$(stat -c '%s' "$rootfs")
-
-if [ "$PAD_ROOTFS_OFFSET_TO" -gt "$header_plus_kernel_len" ]; then
-    padding_len=$(($PAD_ROOTFS_OFFSET_TO - $header_plus_kernel_len))
-else
-    padding_len=0
+rootfs_len=0
+if [ -f "$rootfs" ]; then
+    rootfs_len=$(stat -c '%s' "$rootfs")
 fi
 
+[ "$PAD_ROOTFS_OFFSET_TO" -gt "$header_plus_kernel_len" ] || die "kernel is too large"
+
+padding_len=$(($PAD_ROOTFS_OFFSET_TO - $header_plus_kernel_len))
+
 echo "endian: $endian" >&2
 echo "padding_len: $padding_len" >&2
 
-padded_rootfs_len=$(($padding_len + $rootfs_len))
+padded_kernel_len=$(($padding_len + $kernel_len))
 
-echo "padded_rootfs_len: $padded_rootfs_len" >&2
-
-total_len=$(($header_plus_kernel_len + $padded_rootfs_len))
+total_len=$(($PAD_ROOTFS_OFFSET_TO + $rootfs_len))
 
 echo "total_len: $total_len" >&2
 
@@ -135,7 +139,9 @@ trx_crc32() {
     outtmpfile=$(mktemp)
     cat "$kernel" > "$tmpfile"
     padding >> "$tmpfile"
-    cat "$rootfs" >> "$tmpfile"
+    if [ -f "$rootfs" ]; then
+        cat "$rootfs" >> "$tmpfile"
+    fi
     # We just need a CRC-32/JAMCRC of the concatnated files
     # There's no readily available tool for this, but zytrx does create one when
     # creating their TRX header, so we just use that.
@@ -174,10 +180,10 @@ tclinux_trx_hdr() {
     head -c 32 /dev/zero | to_hex
 
     # kernel length
-    hex32 "$kernel_len"
+    hex32 "$padded_kernel_len"
 
     # rootfs length
-    hex32 "$padded_rootfs_len"
+    hex32 "$rootfs_len"
 
     # romfile length (0)
     hex32 0
@@ -200,4 +206,6 @@ tclinux_trx_hdr() {
 tclinux_trx_hdr | from_hex
 cat "$kernel"
 padding
-cat "$rootfs"
+if [ -f "$rootfs" ]; then
+    cat "$rootfs"
+fi