For the factory recovery in the Ninja Sphere we needed a way to force a particular boot mode (NAND boot instead of SD card boot) for just exactly one boot. A useful and underused feature of U-Boot is the ability to adjust environment variables from within a Linux system to alter the details of the boot process, including overriding the default boot command to trigger a one-shot boot to an alternate medium.
A package is readily available in both Yocto/OE (u-boot-fw-utils) and Ubuntu (u-boot-tools) that package up the
fw_setenv utilities to read and update environment variables respectively.
The documentation is a little sparse on how to configure this, but if you have NAND and MTD partitions set up, then
/proc/mtd should look something like:
dev: size erasesize name mtd0: 00020000 00020000 "NAND.SPL" mtd1: 00020000 00020000 "NAND.SPL.backup1" mtd2: 00020000 00020000 "NAND.SPL.backup2" mtd3: 00020000 00020000 "NAND.SPL.backup3" mtd4: 00040000 00020000 "NAND.u-boot-spl-os" mtd5: 00100000 00020000 "NAND.u-boot" mtd6: 00020000 00020000 "NAND.u-boot-env" mtd7: 00020000 00020000 "NAND.u-boot-env.backup1" mtd8: 00800000 00020000 "NAND.kernel" mtd9: 07600000 00020000 "NAND.file-system"
Specifically, you want to take note of the mtd number for “NAND.u-boot-env” and “NAND.u-boot-env.backup1”. Construct a file
/etc/fw_env.config that looks like:
# device offset env size flash sector size /dev/mtd6 0x0000 0x20000 0x20000 /dev/mtd7 0x0000 0x20000 0x20000
Where a line exists for each of the 2 environment partitions described above, containing the path to the mtd device and the appropriate sizes/offsets. Looking at the output from
/proc/mtd above, both environments in this case have a size and sector (erase) size of
0x20000. The offset is
0x0000 in both cases because the
/dev/mtdX device is already pointing to the right part of the flash chip - the offset would only be required if you were addressing into a single mtd device covering the whole flash chip (or if the values given to the kernel were incorrect).
By design, we were not using the environment for booting, and instead relying on the default environment baked into the U-Boot flash, which would be loaded by U-Boot whenever an empty environment was discovered at boot. Unfortunately, the tools in Linux don’t know about this environment, so the following little snippet was used to set a one-shot boot that would work in this situation, even if this became the entire environment:
fw_setenv bootcmd "env default -a; saveenv; run nandboot"
This works by setting the boot command (which U-Boot first runs after setting up drivers) to a sequence of resetting to the default (built-in) environment, saving that back to flash (overwriting this one-shot), then booting to NAND. This works for situations where the environment isn’t used, but will cause any customisations to the environment to be destroyed and restored back to the U-Boot built-in environment.
In a situation where the environment was customised and used as part of the boot, one could read the existing bootcmd, save it to a backup variable, then override bootcmd to restore the original then boot a custom way, similar to above.