Booting from USB clone without UART and medkit

tl;dr cloning an existing installation from eMMC and booting from USB without UART and medkit


Connecting UART is a bit of pain - device stored/mounted inside a utility box that is out of easy reach, having to open/close the device, disconnecting/reconnecting cabling, fumbling with the UART connectors - I was looking for a more convenient (lazy) way to get clones of the existing and known working installation from the eMMC onto another drive for booting.

Inspired by https://doc.turris.cz/doc/en/howto/omnia_booting_from_external_storage and

First tried with the already installed mSATA SSD but that did not work since u-boot implementation in OpenWrt/TOS does not support GPT and I did not want to revert the SSD’s partition table to legacy MBR (good’ol DOS times).

As per online doc then procured a mPCIe to USB 2.0 adapter

The irony of course being that the router needed to be opened for installing the adapter…

Caveats:

  • adapter occupies a mPCIe slot (the one over the sim card slot) and with a mSATA in place the 2.4GHz Wlan card been the collateral
  • due to the design of dd the target drive/partition needs to be same size or larger, but cannot be smaller, than the eMMC partition (/dev/mmcblk0p1)
  • (s)low read speed of USB device
  • if other USB drives are connected to the router at the same time the /dev/sd* designation may change and could potentially mess things up

That out of the way, being logged into the running TOS installation on the eMMC via ssh:

  • created primary MBR partition (/dev/sdb1) on the USB drive (with fdisk, suggested reboot)
  • mkdir /mnt/sdb1
  • dd status=progress if=/dev/mmcblk0p1 of=/dev/sdb1
  • btrfstune -u /dev/sdb1
  • mount /dev/sdb1 /mnt/sdb1
  • btrfs fi resize max /mnt/sdb1
  • btrfs quota rescan -w /mnt/sdb1
  • umount /dev/sdb1
  • btrfsck /dev/sdb1

Good to go with fw_setenv -s (script file content below) & reboot from ssh

usbboot setenv bootargs "$bootargs cfg80211.freg=$regdomain"; usb start; btrload usb 0 0x01000000 boot/zImage @; btrload usb 0 0x02000000 boot/dtb @; bootz 0x01000000 - 0x02000000
bootargs earlyprintk console=ttyS0,115200 rootfstype=btrfs rootwait root=/dev/sdb1 rootflags=subvol=@,commit=5 rw
bootcmd i2c dev 1; i2c read 0x2a 0x9 1 0x00FFFFF0; setexpr.b rescue *0x00FFFFF0; if test $rescue -ge 1; then echo BOOT RESCUE; run rescueboot; else echo BOOT eMMC FS; run usbboot; fi
scsiboot setenv bootargs "$bootargs cfg80211.freg=$regdomain"; scsi scan; btrload scsi 0:1 0x01000000 boot/zImage @; btrload scsi 0:1 0x02000000 boot/dtb @; bootz 0x01000000 - 0x02000000

Then after having booted from the USB device sort schnapps

  • touch /etc/schnapps/config | echo 'ROOT_DEV="/dev/sdb1"' > /etc/schnapps/config

It is also possible to generate the USB installation with a medkit file, be that vanilla or one generated/exported by schnapps, without UART but vis ssh from a running installation on the eMMC. Which is faster in terms of speed and more independent of the target’s drive size than dd.

Caveat:

  • requires a storage medium that provides the medkit file

Steps from running router installation via ssh:

  • created primary MBR partition (/dev/sdb1) on the USB drive (with fdisk, suggested reboot)
  • mkdir /mnt/tmp /mkdir/usb
  • mkfs.btrfs /dev/sdb1
  • mount /dev/sdb1 /mnt/usb
  • btrfs su c /mnt/sdb1/@
  • mount /dev/${medium with medkit} /mnt/tmp (unless it is already mounted of course)
  • tar -C /mnt/sdb1/@ -xzvf /mnt/tmp/${medkit file} (medkit file either vanilla or from schnapps exported)
  • umount /dev/sdb1 /dev/${medium with medkit} (unless the medium with the medkit should not be demounted)
  • rm -r /mnt/tmp /mnt/usb
  • btrfsck /dev/sdb1

Proceed with the remainder of the u-boot env, reboot and schnapps conf


If the USB device contains more than one partition such needs to specified in the u-boot env -> change from usb 0 stanzas to usb 0:X with X being the partition number on the drive.