mkenvimage: a tool to generate a U-Boot environment binary image

Many embedded devices these days use the U-Boot bootloader. This bootloader stores its configuration into an area of the flash called the environment that can be manipulated from within U-Boot using the printenv, setenv and saveenv commands, or from Linux using the fw_printenv and fw_setenv userspace utilities provided with the U-Boot source code.

This environment is typically stored in a specific flash location, defined in the board configuration header in U-Boot. The environment is basically stored as a sequence of null-terminated strings, with a little header containing a checksum at the beginning.

While this environment can easily be manipulated from U-Boot or from Linux using the above mentioned commands, it is sometimes desirable to be able to generate a binary image of an environment that can be directly flashed next to the bootloader, kernel and root filesystem into the device’s flash memory. For example, on AT91 devices, the SAM-BA utility provided by Atmel is capable of completely reflashing an AT91 based system connected through the serial port of the USB device port. Or, in factory, initial flashing of devices typically takes place either through specific CPU monitors, or through a JTAG interface. For all of these cases, having a binary environment image is desirable.

David Wagner, who has been an intern with us at Bootlin from April to September 2011, has written a utility called mkenvimage which just does this: generate a valid binary environment image from a text file describing the key=value pairs of the environment. This utility has been merged into the U-Boot Git repository (see the commit) and will therefore be part of the next U-Boot release.

With mkenvimage you can write a text file uboot-env.txt describing the environment, like:

bootcmd=tftp 22000000 uImage; bootm

Then use mkenvimage as follows:

./tools/mkenvimage -s 0x4200 -o uboot-env.bin uboot-env.txt

The -s option allows to specify the size of the image to create. It must match the size of the flash area reserved for the U-Boot environment. Another option worth having in mind is -r, which must be used when there are two copies of the environment stored in the flash thanks to the CONFIG_ENV_ADDR_REDUND and CONFIG_ENV_SIZE_REDUND. Unfortunately, U-Boot has chosen to have a different environment layout in those two cases, so you must tell mkenvimage whether you’re using a redundant environment or a single environment.

This utility has proven to be really useful, as it allows to automatically reflash a device with an environment know to work. It also allows to very easily generate a different environment image per-device, for example to contain the device MAC address and/or the device serial number.

Author: Thomas Petazzoni

Thomas Petazzoni is CTO and embedded Linux and kernel engineer at Bootlin. He is a lead developer of Buildroot and also a contributor to the Linux kernel. More details...

11 thoughts on “mkenvimage: a tool to generate a U-Boot environment binary image”

    1. Because making u-boot read a simple text file requires starting the board and starting U-Boot, then running some U-Boot commands. Having a pre-generated environment image flashed into NAND just seems easier to me. But of course they are multiple ways of setting the U-Boot environment, and everybody has its own preferences. I don’t think this blog post has ever claimed that this tool should replace every possible method of setting the environment. It just adds a new, simple one. If you don’t like, eh, just don’t use it 🙂

  1. Just for completeness. To generate a text file which can be flashed by u-boot with the mkimage tool you can do this:

    mkimage -T script -C none -n 'setenv-name' -d u-boot.env u-boot.env.img

    Usage: mkimage -l image
    -l ==> list image header information
    mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image
    -A ==> set architecture to 'arch'
    -O ==> set operating system to 'os'
    -T ==> set image type to 'type'
    -C ==> set compression type 'comp'
    -a ==> set load address to 'addr' (hex)
    -e ==> set entry point to 'ep' (hex)
    -n ==> set image name to 'name'
    -d ==> use image data from 'datafile'
    -x ==> set XIP (execute in place)

  2. Thanks!
    @ Robert Berger
    Your technique allows to “source” (i.e. execute using UBoot’s “source” command) a script image loaded in RAM/NOR .

    Contrary to Thomas’s solution it does not allow you to flash an environment image that gets automatically loaded and executed when UBoot starts up. Unfortunately UBoot does not use the same image format in both cases (at least the old 2010.09 version I’m working on).

  3. Hello Guys,

    I am seeting a strange problem,

    Scenario 1.
    I generated uboot-env.bin, on my target, when it comes up it says no env found, using default. All fair at this point, since I have not yet loaded the env. Now once the board booted, from linux, I did I used dd to program the env.bin to the location it needs to be. Then reseted the target, when it came up, it found the env (since I didnt see the warning). But my partition that holds the uboot script got corrupted somehow. Board cant boot into linux.

    Scenario 2.
    Booted the board, stopped bootup at uboot. Board correctly complains about no env. Did saveenv, that wrote the env to the right section. Now boot into linux take the same env.bin from Scenario 1. step and prgrammed with dd.
    Reboot the board, stop the bootup at uboot, do printenv. I am seeing what was there in env.bin. Able to successfully boot into linux.

    Observation is,
    Doing setenv before doing dd from linux helps. Can some one pls tell what may be happeing ?

    1. I think you can find the config address in the file such like this “at91.h” in “include/configs/” folder.

  4. Thanks for your contribution!
    In modern U-Boots (>= 2016.11) a handy one-liner to obtain the env image after building U-Boot image is:

    ./scripts/ | mkenvimage -p 0x0 -s 0x2000 -o u-boot-env.img –

    Of course mkenvimage parameters need to be adjusted according to the platform.

Leave a Reply