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 0xbc050000With 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 192.168.0.2 setenv ipaddr 192.168.0.251 tftp 0x80060000 /tftp/mt300a.bin erase 0xbc050000 0xbcfd0000 cp.b 0x80060000 0xbc050000 ${filesize}; reset
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.