Nerveware


Introduction

On a device I was developing on, the previous engineer made the decision to install the kernel and device tree on MMC. The storage layout looks something like this:

+-----------+ -> (mmc) |__mmcblk0__| 0x0000 | FDT | 0x0800 | Kernel | 0x4000 +-----------+ -> (ext4) |_mmcblk0p1_| | Root fs | +-----------+ -> (ext4) |_mmcblk0p2_| | Data | +-----------+ 0xFFFF

Writing to disk

The bootloader U-Boot reads from a specific address to load the kernel. The command dd is used to write the kernel to mmcblk0. The problem is that dd doesn't use addresses, but blocks. The formula for calculating the address or offset is:

Offset = Address / 512 / block size in KB Address = Offset * 512 * block size in KB

Most of the eMMC chips have a block size of 4K, thus to get the kernel offset:

Offset = 0x4000 / 512 / 4 = 8

Thus, the command to write the kernel would be:

$ dd if=uImage of=/dev/mmcblk0 bs=1M seek=8 conv=fsync;

Reading from disk

Retrieving data from the MMC can be difficult as well. Lets say tou have an image on address 0x0800 and you want to retrieve it. The following steps are difficult without knowing how much space is reserved. However, the kernel is not conserned with rubbish at the end of the image, so take 8MB to be sure.

$ dd if=/dev/mmcblk0 of=uImage bs=1M skip=1 count=8 conv=fsync