The fastest way to flash eMMC without pulling storage
Flashing eMMC on an embedded Linux board is not as simple as swapping an SD card. The eMMC is soldered
to the board — you cannot just pop it out and plug it into a reader. The usual workaround is to boot
a full Linux environment on the target, copy the image over the network, and run dd.
That works, but it is slow, error-prone, and assumes you already have a working OS on the target.
There is a better way. U-Boot's UMS (USB Mass Storage) command exposes the eMMC as a standard USB mass storage device to your development host. Pair it with bmaptool and you get fast, block-level flashing with SHA256 verification — all over a single USB cable, straight from the U-Boot prompt.
This post walks through enabling UMS in U-Boot, installing and using bmaptool, creating bmap files, integrating with Yocto, and troubleshooting common issues.
U-Boot UMS — exposing eMMC over USB
The ums command in U-Boot turns your target board into a USB mass storage device.
Once active, the eMMC (or SD card) appears as a regular block device — /dev/sdX — on
your development host. You can then read, write, or flash it just like any USB drive.
The command is straightforward:
# On the target, at the U-Boot prompt
=> ums 0 mmc 0
Breaking down the arguments:
0(first argument) — the USB controller indexmmc— the storage interface type0(last argument) — the storage device index (0 for eMMC on most boards, 1 for SD)
The key advantage: this works at the U-Boot prompt. No Linux kernel needs to be running on the target. That makes UMS invaluable during initial bring-up when there is no OS on the eMMC yet, or when you need to reflash a bricked system. All you need is a USB cable connected between the board's OTG/device port and your host.
Required U-Boot CONFIG flags
The ums command is not enabled in every U-Boot build. You need these Kconfig
options in your board's defconfig or .config:
# Core UMS support
CONFIG_CMD_USB_MASS_STORAGE=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_USB_FUNCTION_MASS_STORAGE=y
Many vendor BSPs already enable these, so check your board's defconfig before adding them
manually. Depending on your SoC, you may also need a platform-specific USB gadget driver
such as CONFIG_USB_DWC3 or CONFIG_USB_CI_UDC.
Quick verification: build U-Boot, flash it, and type ums at the prompt. If you see
Unknown command 'ums', one or more of these configs is missing.
bmaptool vs dd — why block maps matter
Once the eMMC shows up as /dev/sdX on your host, the obvious next step is
dd:
# The classic approach — writes every byte, including empty space
$ sudo dd if=image.wic of=/dev/sdX bs=4M status=progress
This works, but it writes every byte of the image — including large regions of zeros where no
actual data exists. For a typical embedded Linux image that is 2 GB in size but only contains
500 MB of real data, dd wastes time writing 1.5 GB of nothing.
bmaptool takes a smarter approach. It reads a .bmap file that describes
which blocks in the image actually contain data. It writes only those mapped blocks and skips
everything else. The result:
- 5-7x faster than
ddin real-world tests — because it only writes the blocks that matter - SHA256 verification — every mapped block range is checksummed and verified
during the write.
ddgives you zero integrity checking - Transparent decompression — bmaptool handles
.gz,.xz, and.bz2images on the fly. No need to decompress first
The two-command workflow becomes:
# On the target
=> ums 0 mmc 0
# On the host
$ sudo bmaptool copy image.wic.gz /dev/sdX
Fast, verified, and simple.
Installing bmaptool
bmaptool is maintained by the Yocto Project and available through several channels:
# pip (works on any distro)
$ pip3 install bmaptool
# Debian / Ubuntu
$ sudo apt install bmap-tools
# Fedora
$ sudo dnf install bmap-tools
# From source
$ git clone https://github.com/yoctoproject/bmaptool.git
$ cd bmaptool
$ pip3 install -e '.'
Verify the installation:
$ bmaptool --version
On Arch Linux, bmaptool is available through the AUR.
Creating bmap files with bmaptool create
bmaptool needs a .bmap file to know which blocks to write. If your build system does
not generate one automatically, create it yourself:
$ bmaptool create image.wic -o image.wic.bmap
The resulting .bmap file is a small XML document that lists every mapped block range
in the image along with its SHA256 checksum. Here is a simplified example:
<?xml version="1.0" ?>
<bmap version="2.0">
<ImageSize> 3221225472 </ImageSize>
<BlockSize> 4096 </BlockSize>
<BlocksCount> 786432 </BlocksCount>
<MappedBlocksCount> 131072 </MappedBlocksCount>
<BlockMap>
<Range chksum="a1b2c3..."> 0-1023 </Range>
<Range chksum="d4e5f6..."> 8192-9215 </Range>
<!-- ... more ranges ... -->
</BlockMap>
</bmap>
In this example, only 131,072 of 786,432 blocks are mapped — roughly 17% of the image. bmaptool
writes just those blocks while dd would write all 786,432. That is where the speed
gain comes from.
Important: the bmap file must match the exact image it was created for. If you rebuild the image, regenerate the bmap file too.
Generating bmap files automatically in Yocto
If you are using the Yocto Project or OpenEmbedded, you can have bmap files generated automatically
alongside your images. Add this to your local.conf or image recipe:
# Generate a bmap file for every wic image
IMAGE_FSTYPES += "wic.bmap"
After the build, your tmp/deploy/images/<MACHINE>/ directory will contain both
the .wic image and the matching .wic.bmap file — ready for bmaptool.
If you also compress your images, combine both types:
IMAGE_FSTYPES += "wic.xz wic.bmap"
The bmap file is generated from the uncompressed .wic image before compression
happens, so it will work correctly with the compressed file too. This is the recommended setup for
any team using Yocto — no manual bmaptool create steps needed.
Putting it all together
Here is the end-to-end workflow, step by step:
- Build your image — or obtain it from your CI pipeline or a colleague.
- Generate the bmap file — run
bmaptool createmanually, or let Yocto generate it withIMAGE_FSTYPES += "wic.bmap". - Connect a USB cable between the target's OTG port and your development host.
- Boot into U-Boot and run:
=> ums 0 mmc 0 - Flash from the host:
$ sudo bmaptool copy image.wic.gz /dev/sdX - Reset the board — press Ctrl+C in the U-Boot console to exit UMS mode,
then
resetto boot from the freshly flashed eMMC.
This workflow works for initial board bring-up when there is no OS installed yet, for rapid reflashing during development, and even for small-scale production programming. No network setup required — just one cable and two commands.
One cable, two commands
U-Boot UMS and bmaptool turn eMMC flashing from a multi-step ordeal into a two-command operation. No intermediate OS, no network transfers, no storage removal — just a USB cable between your board and your workstation.
This technique is SoC-agnostic. If your board has a USB OTG port and U-Boot supports the gadget driver, it works. Pair it with Yocto's automatic bmap generation and you have a fast, verified flashing pipeline with zero manual steps.
If you need to flash devices remotely, fernsteuerung.io supports the bmap file format out of the box — giving you the same block-level speed and verification when flashing over the network.
For more on bmaptool, see the official repository. If you are building Yocto images and want to automate the full build-flash-boot cycle, our post on flashing Yocto images to boards remotely covers the next level of automation.