Flash eMMC from your host with U-Boot UMS and bmaptool
Embedded Linux

Flash eMMC From Your Host With U-Boot UMS and bmaptool

U-Boot's ums command turns your board into a USB drive. Combine it with bmaptool for fast, verified eMMC flashing — no storage removal, no network setup.

Mar 28, 2026 · 10 min read

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 index
  • mmc — the storage interface type
  • 0 (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 dd in real-world tests — because it only writes the blocks that matter
  • SHA256 verification — every mapped block range is checksummed and verified during the write. dd gives you zero integrity checking
  • Transparent decompression — bmaptool handles .gz, .xz, and .bz2 images 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:

  1. Build your image — or obtain it from your CI pipeline or a colleague.
  2. Generate the bmap file — run bmaptool create manually, or let Yocto generate it with IMAGE_FSTYPES += "wic.bmap".
  3. Connect a USB cable between the target's OTG port and your development host.
  4. Boot into U-Boot and run:
    => ums 0 mmc 0
  5. Flash from the host:
    $ sudo bmaptool copy image.wic.gz /dev/sdX
  6. Reset the board — press Ctrl+C in the U-Boot console to exit UMS mode, then reset to 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.