Understanding sysupgrade vs. mtd

Hi, on my TL-WR1043ND I have always used the "mtd" command to re-flash the router.

mtd -r write /tmp/openwrt-18.06.4-ar71xx-generic-tl-wr1043nd-v1-squashfs-factory.bin firmware

That worked nicely and reliably. On my new Linksys EA8500 router the MTD "partitions" (?) are set differently, and I can see neither "firmware" nor "linux". That leaves me with several questions:

  1. What is the "mtd" way of flashing a Linksys EA8500?
  2. If "sysupgrade" was to be used in this case, which "partition" would it flash?
  3. Does "sysupgrade" rely on mtd at all? I was looking at that shell script, but could not find any references to "mtd".

Thank you.

root@OpenWrt:~# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00040000 00020000 "SBL1"
mtd1: 00140000 00020000 "MIBIB"
mtd2: 00140000 00020000 "SBL2"
mtd3: 00280000 00020000 "SBL3"
mtd4: 00120000 00020000 "DDRCONFIG"
mtd5: 00120000 00020000 "SSD"
mtd6: 00280000 00020000 "TZ"
mtd7: 00280000 00020000 "RPM"
mtd8: 00140000 00020000 "art"
mtd9: 00100000 00020000 "APPSBL"
mtd10: 00040000 00020000 "u_env"
mtd11: 00040000 00020000 "s_env"
mtd12: 00040000 00020000 "devinfo"
mtd13: 02800000 00020000 "kernel1"
mtd14: 02500000 00020000 "rootfs1"
mtd15: 02800000 00020000 "kernel2"
mtd16: 02500000 00020000 "rootfs2"
mtd17: 02080000 00020000 "syscfg"

mtd is a low-level flashing tool that could be directly used with the simplest old routers (like 1043) that had simple strucutre and unified kernel+rootfs image and no dual-booting.

With newer routers, with more complex flash structure, possibly dual-firmware features, and possible flashing kernel separately from the rootfs, using mtd directly is not possible.

There is none.
(or maybe: investigate the EA8500 sysupgrade steps, mimic them, and use mtd for those steps that it can do. And then do the other steps with other tools)

(kernel1 and rootfs1) or (kernel2 and rootfs2), depending which partition is active (1 or 2). And then it would toggle the active partition marker in u-boot-env etc.

For some routers, for the low-level flashing work. Depends on the target.

Summary for you:

  • you can't use mtd directly with EA8500
  • use sysupgrade
2 Likes

I had to bite the bullet and read the code... There is a shell script "/lib/upgrade/linksys.sh" which I think has the answer to my question. It turns out it checks the magic number of the image. If the magic number is "27051956", it performs an mtd flash of either "kernel1" or "kernel2" partition. If the image has the magic number of "73797375", then a more elaborate process takes place.

Any idea what "73797375" magic number represents? A google search returns nothing on this.

Thank you.

"sysu" = First 4 letters from the word "sysupgrade"...
Found at the beginning of the image, evaluated by /lib/upgrade/common.sh. Just a logic to see that it is a sysupgrade image.

If yes, then the nand_upgrade_tar routine in /lib/upgrade/nand.sh gets called to perform the actual upgrade (to write kernel and rootfs separately to the correct partitions, etc.). Note that the rootfs is ubifs formatted and needs to be written with ubifs tools.

Looking at the below function from linksys.sh, one part looks a little suspicious. "cur_boot_part" gets assigned a value, and that value is validated in the "if" statement. However, after the "if" statement, the value is reassigned again, this time without any checks. I am no shell scripting guru, but this does not look quite right to me.

linksys_get_target_firmware() {

	local cur_boot_part mtd_ubi0

	cur_boot_part=$(/usr/sbin/fw_printenv -n boot_part)
	if [ -z "${cur_boot_part}" ] ; then
		mtd_ubi0=$(cat /sys/devices/virtual/ubi/ubi0/mtd_num)
		case $(egrep ^mtd${mtd_ubi0}: /proc/mtd | cut -d '"' -f 2) in
		kernel1|rootfs1)
			cur_boot_part=1
			;;
		kernel2|rootfs2)
			cur_boot_part=2
			;;
		esac
		>&2 printf "Current boot_part='%s' selected from ubi0/mtd_num='%s'" \
			"${cur_boot_part}" "${mtd_ubi0}"
	fi

	cur_boot_part=`/usr/sbin/fw_printenv -n boot_part`

	case $cur_boot_part in
	1)
		fw_setenv -s - <<-EOF
			boot_part 2
			auto_recovery yes
		EOF
		printf "kernel2"
		return
		;;
	2)
		fw_setenv -s - <<-EOF
			boot_part 1
			auto_recovery yes
		EOF
		printf "kernel1"
		return
		;;
	*)
		return
		;;
	esac
}