diary at Telent Netowrks

Flash! (ah-ah)#

Mon, 16 Apr 2018 23:18:57 +0000

This week I successfully flashed NixWRT to my GL-MT300A, such that it runs whenever I turn the device on. And then I found it slowly fills up all RAM and the process table over about half a day then stops working.

But we'll get to that in a minute. Let's talk about the good bits first.

Graven image

Given we have a kernel and a root filesystem, how exactly should we mash them up into a flashable image such that (i) uboot will find and run the kernel, (ii) the kernel will find its filesystem? Let's look at the dmesg output from booting OpenWRT -

[    0.620000] m25p80 spi32766.0: w25q128 (16384 Kbytes)
[    0.630000] 5 ofpart partitions found on MTD device spi32766.0
[    0.630000] Creating 5 MTD partitions on "spi32766.0":
[    0.640000] 0x000000000000-0x000000030000 : "u-boot"
[    0.650000] 0x000000030000-0x000000040000 : "u-boot-env"
[    0.650000] 0x000000040000-0x000000050000 : "factory"
[    0.660000] 0x000000050000-0x000000fd0000 : "firmware"
[    0.780000] 2 uimage-fw partitions found on MTD device firmware
[    0.790000] 0x000000050000-0x000000174720 : "kernel"
[    0.790000] 0x000000174720-0x000000fd0000 : "rootfs"
[    0.800000] mtd: device 5 (rootfs) set to be root filesystem
[    0.810000] 1 squashfs-split partitions found on MTD device rootfs
[    0.810000] 0x000000890000-0x000000fd0000 : "rootfs_data"
[    0.820000] 0x000000ff0000-0x000001000000 : "art"

It has five "ofpart" partitions. I'm guessing the "of" stands for "open firmware" and indeed if we look at the DTS file (remember if you will from blog entries passim that the device tree is a representation of "what you'd get from open firmware if the hardware had open firmware") we can see five partitions defined there.

It has two "uimage-fw" partitions which further subdivide the firmware partition. Unlike the ofpart partitions these are not actually defined anywhere: they are the result of kernel code (in drivers/mtd/mtdsplit/mtdsplit{,_uimage}.c) which looks for partitions which start with a uimage, parses the image length, and then looks for a filesystem signature of some kind on the next erase block boundary. (This is very convenient magic not least because it means we don't have to update some partition table each time our kernel size changes, but it still makes me uneasy; I have a very low threshold for magic)

Hypothesis (subsequently proven): if our firmware file consists of a kernel wrapped in a uimage, plus padding to the next erase block boundary, plus the filesystem image, Linux will report an MTD uimage-fw partition that starts where the filesystem starts. We can copy this combined image into flash at offset 0x000000050000 to overwrite the existing kernel/root fs while leaving the rest of the flash undisturbed.

(To get the erase block size, we could (a) guess it's probably 128k, or (b) if we were more prudent, check in in /proc/mtd )

Short version: that half of the puzzle is solved by creative use of dd.

Flash override

So the general principle for flashing from U-Boot once you have a suitable image, is (1) download it into RAM somewhere, (2) erase an appropriate section of flash, (2.1) hope the power doesn't fail before you finish step 3, (3) copy the image from RAM into flash, (4) reboot and see whether you've bricked the device. Although unless you've done something badly wrong (like overwrite uboot itself or the ART partition) then it doesn't matter too much if the image you've uploaded doesn't actually work because you can just go back to the u-boot prompt and try again. There's an explanation of how to do this on the Yun which I had previously successfully followed, converting that to another board is just a matter of working out whereabouts in RAM the flash chip is mapped.

And the simplest way of doing this is to look at what uboot does by default when the board is powered on. If we run printenv we see i.a.

   bootcmd=bootm 0xbc050000
With 99.8% certainty, we think that this is a jump to offset 0x50000 (remember, this is the offset of the "firmware" partition) of a flash chip that starts at 0xbc000000, and this is probably all we need. So: on the build machine

$ nix-build -I nixpkgs=../nixpkgs-for-nixwrt/ backuphost.nix \
 -A firmwareImage --argstr targetBoard mt300a -o mt300a.bin
$ cp mt300a.bin /tftp

and then on the device, run these u-boot commands

setenv serverip 
setenv ipaddr 
tftp 0x80060000 /tftp/mt300a.bin
erase 0xbc050000 0xbcfd0000
cp.b 0x80060000 0xbc050000 ${filesize};

and then offer up a silent prayer because 99.8% is still less than 100%. Punch the air shortly thereafter :-)

Flash I love you but we only have 14 hours

As alluded to above, there is something weird going on in userland that makes it presently less than useful: the ntpd and syslogd processes (both actually BusyBox applets) don't write pid files when they start up, causing monit to decide they have failed to start and spawn another. One of each of them added every 30 seconds soon leads to a poorly computer.

No idea why, yet. I'd run strace but it doesn't want to build (maybe a MIPS thing, maybe a musl thing). Hopefully next week...

Completely random aside

And I mean completely random. Is it just me or does anyone else find that the taillight cluster on the new Prius reminds them of Ming the Merciless?

Maybe just me.