ath79: add Senao 'failsafe' sysupgrade procedure
authorMichael Pratt <mcpratt@pm.me>
Fri, 12 Feb 2021 23:19:10 +0000 (18:19 -0500)
committerPetr Štetiar <ynezz@true.cz>
Thu, 8 Apr 2021 07:20:59 +0000 (09:20 +0200)
Use a similar upgrade method for sysupgrade.bin, like factory.bin,
for Senao boards with the tar.gz OEM upgrade platform,
and 'failsafe' image which is loaded on checksum failure.

This is inspired by the OEM upgrade script /etc/fwupgrade.sh
and the existing platforms for dual-boot Senao boards.

Previously, if the real kernel was damaged or missing
the only way to recover was with UART serial console,
because the OKLI lzma-loader is programmed to halt.

uboot did not detect cases where kernel or rootfs is damaged
and boots OKLI instead of the failsafe image,
because the checksums stored in uboot environment
did not include the real kernel and rootfs space.

Now, the stored checksums include the space for both
the lzma-loader, kernel, and rootfs.
Therefore, these boards are now practically unbrickable.

Also, the factory.bin and sysupgrade.bin are now the same,
except for image metadata.
This allows for flashing OEM image directly from openwrt
as well as flashing openwrt image directly from OEM.

Make 'loader' partition writable so that it can be updated
during a sysupgrade.

tested with
ENS202EXT v1
EAP1200H
EAP350 v1
EAP600
ECB350 v1
ECB600
ENH202 v1

Signed-off-by: Michael Pratt <mcpratt@pm.me>
target/linux/ath79/dts/ar724x_senao_loader-4k.dtsi
target/linux/ath79/dts/ar724x_senao_loader-64k.dtsi
target/linux/ath79/dts/ar934x_senao_loader.dtsi
target/linux/ath79/dts/qca955x_senao_loader.dtsi
target/linux/ath79/generic/base-files/lib/upgrade/failsafe_datachk.sh [new file with mode: 0644]
target/linux/ath79/generic/base-files/lib/upgrade/platform.sh
target/linux/ath79/image/common-senao.mk
target/linux/ath79/tiny/base-files/lib/upgrade/failsafe_datachk.sh [new file with mode: 0644]
target/linux/ath79/tiny/base-files/lib/upgrade/platform.sh

index 501ff26859fd84ed442e8031dad3ab8932833f52..0dff79eb4679a4d117e5e9698e715c1353f0819f 100644 (file)
@@ -56,7 +56,6 @@
                        partition@a0000 {
                                label = "loader";
                                reg = <0xa0000 0x1000>;
-                               read-only;
                        };
 
                        fwconcat1: partition@a1000 {
index 54dbec18b369149984455a38a2fcca74cb1323e1..831f0385a9fd33109f73210463d9da0ba8fc25a7 100644 (file)
@@ -56,7 +56,6 @@
                        partition@a0000 {
                                label = "loader";
                                reg = <0xa0000 0x10000>;
-                               read-only;
                        };
 
                        fwconcat1: partition@b0000 {
index 35e5f135350c6bf8ab6d4c189e0cb1a7a9810301..8247cc85dcd89a96dcd8ae15143d9291a13b739c 100644 (file)
@@ -60,7 +60,6 @@
                        partition@a0000 {
                                label = "loader";
                                reg = <0x0a0000 0x010000>;
-                               read-only;
                        };
 
                        fwconcat1: partition@b0000 {
index 77eabde80afad8b7f386d4816826b1d8e1716b80..846d3ed0afbfbffc2ded2a950d321d4e6e912739 100644 (file)
@@ -58,7 +58,6 @@
                        partition@a0000 {
                                label = "loader";
                                reg = <0x0a0000 0x010000>;
-                               read-only;
                        };
 
                        fwconcat1: partition@b0000 {
diff --git a/target/linux/ath79/generic/base-files/lib/upgrade/failsafe_datachk.sh b/target/linux/ath79/generic/base-files/lib/upgrade/failsafe_datachk.sh
new file mode 100644 (file)
index 0000000..de84233
--- /dev/null
@@ -0,0 +1,64 @@
+# U-Boot with the datachk patchset requires image sizes, offsets,
+# and checksums to be provided in the U-Boot environment.
+# This script is based on the dualboot version for devices that come with 2 OS partitions.
+# For Senao boards with a "failsafe" partition image, the process is almost the same.
+# Instead of booting a secondary instalation on checksum failure,
+# the failsafe image is booted instead.
+# These boards also use the OKLI lzma kernel loader and mtd-concat
+# So the kernel check is for the loader, the rootfs check is for kernel + rootfs
+
+platform_do_upgrade_failsafe_datachk() {
+       local setenv_script="/tmp/fw_env_upgrade"
+
+       local flash_base=0x9f000000
+
+       local kernel_mtd=$(find_mtd_index ${KERNEL_PART:-kernel})
+       local rootfs_mtd=$(find_mtd_index ${ROOTFS_PART:-rootfs})
+
+       local kernel_offset=$(cat /sys/class/mtd/mtd${kernel_mtd}/offset)
+       local rootfs_offset=$(cat /sys/class/mtd/mtd${rootfs_mtd}/offset)
+
+       if [ -n "$IMAGE_LIST" ]; then
+               KERNEL_FILE=$($IMAGE_LIST | grep $KERNEL_FILE)
+               ROOTFS_FILE=$($IMAGE_LIST | grep $ROOTFS_FILE)
+       fi
+
+       local kernel_size=$($IMAGE_CMD $KERNEL_FILE | wc -c)
+       local rootfs_size=$($IMAGE_CMD $ROOTFS_FILE | wc -c)
+
+       # rootfs without JFFS2
+       local rootfs_blocks=$((rootfs_size / 4096))
+       rootfs_size=$((rootfs_blocks * 4096))
+
+       local kernel_md5=$($IMAGE_CMD $KERNEL_FILE | md5sum | cut -d ' ' -f1)
+       local rootfs_md5=$($IMAGE_CMD $ROOTFS_FILE | dd bs=4k count=$rootfs_blocks iflag=fullblock | md5sum | cut -d ' ' -f1)
+
+       # prepare new u-boot-env vars
+       printf "vmlinux_start_addr 0x%08x\n" $((flash_base + kernel_offset)) >> $setenv_script
+       printf "vmlinux_size 0x%08x\n" ${kernel_size} >> $setenv_script
+       printf "vmlinux_checksum %s\n" ${kernel_md5} >> $setenv_script
+
+       printf "rootfs_start_addr 0x%08x\n" $((flash_base + rootfs_offset)) >> $setenv_script
+       printf "rootfs_size 0x%08x\n" ${rootfs_size} >> $setenv_script
+       printf "rootfs_checksum %s\n" ${rootfs_md5} >> $setenv_script
+
+       # store u-boot-env
+       mkdir -p /var/lock
+       fw_setenv -s $setenv_script || {
+               echo 'failed to update U-Boot environment'
+               exit 1
+       }
+
+       # sysupgrade
+       sleep 2
+       sync
+       echo 3 > /proc/sys/vm/drop_caches
+       $IMAGE_CMD $KERNEL_FILE | mtd $MTD_ARGS write - ${KERNEL_PART:-kernel}
+       sleep 2
+       sync
+       if [ -n "$UPGRADE_BACKUP" ]; then
+               $IMAGE_CMD $ROOTFS_FILE | mtd $MTD_ARGS $MTD_CONFIG_ARGS -j $UPGRADE_BACKUP write - ${ROOTFS_PART:-rootfs}
+       else
+               $IMAGE_CMD $ROOTFS_FILE | mtd $MTD_ARGS write - ${ROOTFS_PART:-rootfs}
+       fi
+}
index 575761d0797547a2db322b9a9a7aa6fb77c66542..19699332fc2447902a886a3980778eb36d52b4e3 100644 (file)
@@ -47,6 +47,20 @@ platform_do_upgrade() {
        adtran,bsap1840)
                redboot_fis_do_upgrade "$1" vmlinux_2
                ;;
+       engenius,eap1200h|\
+       engenius,eap300-v2|\
+       engenius,eap600|\
+       engenius,ecb600|\
+       engenius,ens202ext-v1|\
+       engenius,enstationac-v1)
+               IMAGE_LIST="tar tzf $1"
+               IMAGE_CMD="tar xzOf $1"
+               KERNEL_PART="loader"
+               ROOTFS_PART="fwconcat0"
+               KERNEL_FILE="uImage-lzma.bin"
+               ROOTFS_FILE="root.squashfs"
+               platform_do_upgrade_failsafe_datachk "$1"
+               ;;
        jjplus,ja76pf2)
                redboot_fis_do_upgrade "$1" linux
                ;;
index 9b5903d8e7ca55357edf0ad1c1cbbf41d0e212c1..6784cf9aae459ed64786fc79e7a83171614639ca 100644 (file)
@@ -36,4 +36,5 @@ define Device/senao_loader_okli
   IMAGES += factory.bin
   IMAGE/factory.bin := append-kernel | pad-to $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | \
        check-size | senao-tar-gz $$$$(SENAO_IMGNAME)
+  IMAGE/sysupgrade.bin := $$(IMAGE/factory.bin) | append-metadata
 endef
diff --git a/target/linux/ath79/tiny/base-files/lib/upgrade/failsafe_datachk.sh b/target/linux/ath79/tiny/base-files/lib/upgrade/failsafe_datachk.sh
new file mode 100644 (file)
index 0000000..de84233
--- /dev/null
@@ -0,0 +1,64 @@
+# U-Boot with the datachk patchset requires image sizes, offsets,
+# and checksums to be provided in the U-Boot environment.
+# This script is based on the dualboot version for devices that come with 2 OS partitions.
+# For Senao boards with a "failsafe" partition image, the process is almost the same.
+# Instead of booting a secondary instalation on checksum failure,
+# the failsafe image is booted instead.
+# These boards also use the OKLI lzma kernel loader and mtd-concat
+# So the kernel check is for the loader, the rootfs check is for kernel + rootfs
+
+platform_do_upgrade_failsafe_datachk() {
+       local setenv_script="/tmp/fw_env_upgrade"
+
+       local flash_base=0x9f000000
+
+       local kernel_mtd=$(find_mtd_index ${KERNEL_PART:-kernel})
+       local rootfs_mtd=$(find_mtd_index ${ROOTFS_PART:-rootfs})
+
+       local kernel_offset=$(cat /sys/class/mtd/mtd${kernel_mtd}/offset)
+       local rootfs_offset=$(cat /sys/class/mtd/mtd${rootfs_mtd}/offset)
+
+       if [ -n "$IMAGE_LIST" ]; then
+               KERNEL_FILE=$($IMAGE_LIST | grep $KERNEL_FILE)
+               ROOTFS_FILE=$($IMAGE_LIST | grep $ROOTFS_FILE)
+       fi
+
+       local kernel_size=$($IMAGE_CMD $KERNEL_FILE | wc -c)
+       local rootfs_size=$($IMAGE_CMD $ROOTFS_FILE | wc -c)
+
+       # rootfs without JFFS2
+       local rootfs_blocks=$((rootfs_size / 4096))
+       rootfs_size=$((rootfs_blocks * 4096))
+
+       local kernel_md5=$($IMAGE_CMD $KERNEL_FILE | md5sum | cut -d ' ' -f1)
+       local rootfs_md5=$($IMAGE_CMD $ROOTFS_FILE | dd bs=4k count=$rootfs_blocks iflag=fullblock | md5sum | cut -d ' ' -f1)
+
+       # prepare new u-boot-env vars
+       printf "vmlinux_start_addr 0x%08x\n" $((flash_base + kernel_offset)) >> $setenv_script
+       printf "vmlinux_size 0x%08x\n" ${kernel_size} >> $setenv_script
+       printf "vmlinux_checksum %s\n" ${kernel_md5} >> $setenv_script
+
+       printf "rootfs_start_addr 0x%08x\n" $((flash_base + rootfs_offset)) >> $setenv_script
+       printf "rootfs_size 0x%08x\n" ${rootfs_size} >> $setenv_script
+       printf "rootfs_checksum %s\n" ${rootfs_md5} >> $setenv_script
+
+       # store u-boot-env
+       mkdir -p /var/lock
+       fw_setenv -s $setenv_script || {
+               echo 'failed to update U-Boot environment'
+               exit 1
+       }
+
+       # sysupgrade
+       sleep 2
+       sync
+       echo 3 > /proc/sys/vm/drop_caches
+       $IMAGE_CMD $KERNEL_FILE | mtd $MTD_ARGS write - ${KERNEL_PART:-kernel}
+       sleep 2
+       sync
+       if [ -n "$UPGRADE_BACKUP" ]; then
+               $IMAGE_CMD $ROOTFS_FILE | mtd $MTD_ARGS $MTD_CONFIG_ARGS -j $UPGRADE_BACKUP write - ${ROOTFS_PART:-rootfs}
+       else
+               $IMAGE_CMD $ROOTFS_FILE | mtd $MTD_ARGS write - ${ROOTFS_PART:-rootfs}
+       fi
+}
index b02ab9a0805cc1ab4157dec1365cbcd8dc7eb258..6d05b88d45c660b043845dde0878a948a23bdd55 100644 (file)
@@ -5,6 +5,9 @@
 PART_NAME=firmware
 REQUIRE_IMAGE_METADATA=1
 
+RAMFS_COPY_BIN='fw_setenv'
+RAMFS_COPY_DATA='/etc/fw_env.config'
+
 platform_check_image() {
        return 0
 }
@@ -13,6 +16,17 @@ platform_do_upgrade() {
        local board=$(board_name)
 
        case "$board" in
+       engenius,eap350-v1|\
+       engenius,ecb350-v1|\
+       engenius,enh202-v1)
+               IMAGE_LIST="tar tzf $1"
+               IMAGE_CMD="tar xzOf $1"
+               KERNEL_PART="loader"
+               ROOTFS_PART="fwconcat0"
+               KERNEL_FILE="uImage-lzma.bin"
+               ROOTFS_FILE="root.squashfs"
+               platform_do_upgrade_failsafe_datachk "$1"
+               ;;
        *)
                default_do_upgrade "$1"
                ;;