September 26, 2016

How does the Debian flasher image work?

These days, "flasher" images are no longer provided as such. Apparently too many people didn't understand what they were and were running them and wiping out their eMMC. These days you get the image that runs from SD and then uncomment the following line in uEnv.txt.
##enable BBB: eMMC Flasher:
#cmdline=init=/opt/scripts/tools/eMMC/init-eMMC-flasher-v3.sh
This link shows the console output captured when I ran my favorite flasher image: And indeed, U-boot reports that is is handing this command line option to the kernel:
init=/opt/scripts/tools/eMMC/init-eMMC-flasher-v3.sh
And the linux bootparms document says that the "init=" option will "Run specified binary instead of /sbin/init as init process."

If I put the micro-SD card into a USB reader and plug it in, I see:

[root@trona tom]# fdisk /dev/sdc
Welcome to fdisk (util-linux 2.28.2).
Command (m for help): p
Disk /dev/sdc: 7.4 GiB, 7948206080 bytes, 15523840 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x1611ba27
Device     Boot Start     End Sectors  Size Id Type
/dev/sdc1  *     2048 3481599 3479552  1.7G 83 Linux

So, it has one partition. Notice the big start offset. U-boot (both parts of it) is tucked away outside of any partition at the start of the disk. Since this automounts, we can poke around inside:

[tom@trona eMMC]$ pwd
/run/media/tom/rootfs/opt/scripts/tools/eMMC
[tom@trona eMMC]$ ls -l
total 136
-rwxr-xr-x 1 1000 1000 15925 Oct 30  2015 bbb-eMMC-flasher-eewiki-12mb.sh
-rwxr-xr-x 1 1000 1000 18109 Oct 30  2015 bbb-eMMC-flasher-eewiki-ext4.sh
-rwxr-xr-x 1 1000 1000 17867 Oct 30  2015 beaglebone-black-make-microSD-flasher-from-eMMC.sh
-rwxr-xr-x 1 1000 1000 21661 Oct 30  2015 init-eMMC-flasher-from-usb-media.sh
-rwxr-xr-x 1 1000 1000  9792 Oct 30  2015 init-eMMC-flasher-v2.sh
-rwxr-xr-x 1 1000 1000 16887 Oct 30  2015 init-eMMC-flasher-v3-bbg.sh
-rwxr-xr-x 1 1000 1000 17455 Oct 30  2015 init-eMMC-flasher-v3.sh
-rw-r--r-- 1 1000 1000   936 Oct 30  2015 readme.md
Look at all those different flasher scripts! It you want to look at the one actually being used, here it is:

Where does U-boot get installed?

Let's boot up debian and look at some things.
root@beaglebone:/boot# ls -l /dev/mmc*
brw-rw---T 1 root floppy 179,  0 Jan  1  2000 /dev/mmcblk0
brw-rw---T 1 root floppy 179,  8 Jan  1  2000 /dev/mmcblk0boot0
brw-rw---T 1 root floppy 179, 16 Jan  1  2000 /dev/mmcblk0boot1
brw-rw---T 1 root floppy 179,  1 Jan  1  2000 /dev/mmcblk0p1
root@beaglebone:/boot# fdisk /dev/mmcblk0
Command (m for help): p
Disk /dev/mmcblk0: 1920 MB, 1920991232 bytes
4 heads, 16 sectors/track, 58624 cylinders, total 3751936 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

        Device Boot      Start         End      Blocks   Id  System
/dev/mmcblk0p1   *        2048     3751935     1874944   83  Linux
So we have the eMMC in its entirety as mmcblk0, and it contains one partition (which mounts up as root) as mmcblk0p1, so what the heck are the boot0 and boot1 devices? I am not sure it matters, these just seem to be red herrings and are never referenced in the flasher script. If you read from them, they each give you 1M of zeros. Much more interesting, is the following from the flasher script. Note that the name here is changed to "blk1" instead of "blk0" because when running from the SD card, the partitions on the SD card are "blk0" and the partitions on eMMC are "blk1".
-----------------------------
Writing bootloader to [/dev/mmcblk1]
dd if=/opt/backup/uboot/MLO of=/dev/mmcblk1 count=1 seek=1 conv=notrunc bs=128k
-----------------------------
0+1 records in
0+1 records out
65620 bytes (66 kB) copied, 0.360186 s, 182 kB/s
-----------------------------
dd if=/opt/backup/uboot/u-boot.img of=/dev/mmcblk1 count=2 seek=1 conv=notrunc bs=384k
-----------------------------
0+1 records in
0+1 records out
317044 bytes (317 kB) copied, 0.172383 s, 1.8 MB/s
Fetching the files from /opt/backup/uboot on the SD card, we see:
ls -l
-rw-r--r-- 1 tom tom  65620 Sep 27 17:27 MLO
-rw-r--r-- 1 tom tom 317044 Sep 27 17:27 u-boot.img
As an experiment, on the target system we do this:
cd /root
dd if=/dev/mmcblk0 of=MLO count=1 skip=1 bs=128k
dd if=/dev/mmcblk0 of=u-boot.img count=2 skip=1 bs=384k
ls -l
-rw-r--r-- 1 root root 131072 Oct 30 16:52 MLO
-rw-r--r-- 1 root root 786432 Oct 30 16:52 u-boot.img
Of course doing things this way we get some padding. To verify we have all this right, we rename these and compare them to the originals from the flasher disk:
-rw-r--r--  1 tom tom 131072 Sep 27 17:38 xMLO
-rw-r--r--  1 tom tom 786432 Sep 27 17:38 xu-boot.img
[tom@trona flasher_scripts]$ cmp MLO xMLO
cmp: EOF on MLO
[tom@trona flasher_scripts]$ cmp u-boot.img xu-boot.img 
cmp: EOF on u-boot.img

The bottom line, and how and why does U-boot work in this way.

To install a new version of U-boot, you need to do this (assuming you are doing it from a currently running system.
dd if=MLO of=/dev/mmcblk0 count=1 seek=1 conv=notrunc bs=128k
dd if=u-boot.img of=/dev/mmcblk0 count=2 seek=1 conv=notrunc bs=384k

So, how and why does this work? We need to look at Chapter 26 (page 4667) of the am3359 TRM, somewhat obscurely labelled "Initialization". It describes the operation of the bootloader that is locked into special ROM in the am3359 and that starts things going each and every time the BBB starts up. The section that discusses SD card/MMC booting states that there are two modes:

The old boot scheme that used the file named "MLO" in a FAT partition is an example of "File system mode". The current scheme is using raw mode. The details on raw mode are as follows:

In raw mode the booting image can be located at one of the four consecutive locations in the main area: offset 0x0 / 0x20000 (128KB) / 0x40000 (256KB) / 0x60000 (384KB). For this reason, a booting image shall not exceed 128KB in size

The raw mode is detected by reading sectors #0, #256, #512, #768. The content of these sectors is then verified for presence of a TOC structure.

The documentation here gets a bit sketchy. Look at the U-boot sources if you really want to get a grip on things. But some insight can be gained by looking this hex dump of the first part of "MLO" and comparing the contents with the description of the TOC structure in the TRM.

00000000 4000 0000 0c00 0000 0000 0000 0000 0000   @               
00000010 0000 0000 4348 5345 5454 494e 4753 0000       CHSETTINGS  
00000020 ffff ffff ffff ffff ffff ffff ffff ffff                   
00000030 ffff ffff ffff ffff ffff ffff ffff ffff                   
00000040 c1c0 c0c0 0001 0000 0000 0000 0000 0000             
Pursuing this in further detail is left to the reader. Note that the location of MLO (the u-boot first stage) is fixed by what the am3358 boot rom expects. The location of u-boot.img is entirely up to the code in the first stage (MLO). Also note that these files become "nameless entities" once they are copied into place using the "dd" command.

If you are wondering why U-boot has a first stage and a second stage, there are two reasons. One is the 128K size limit mentioned above. The other is the fact that the bootrom loads the first stage into on chip RAM, not external DRAM. The first stage initializes clocks and various things to get the DRAM ready. The on-chip bootrom can make no assumption about the existence or configuration of external RAM.


Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org