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:

bootargs=console=ttyS0,115200
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 Bootlin's co-owner and CEO. Thomas joined Bootlin in 2008 as a kernel and embedded Linux engineer, became CTO in 2013, and co-owner/CEO in 2021. More details...

20 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/get_default_envs.sh | mkenvimage -p 0x0 -s 0x2000 -o u-boot-env.img –

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

  5. I have strange issues using this mkenvimage tool. I am trying to generate uEnv.txt with three variables defined: var1, var2 and var3. And trying to load it into U-boot. I have done two different tests:

    Test1)
    OUT=uEnv.txt
    echo -ne “var1=1\0” > $OUT
    echo -ne “var2=1\0” >> $OUT
    echo -ne “var3=1\0” >> $OUT
    echo -ne “\0” >> $OUT

    mkenvimage -s 8000 -o uEnv_blob uEnv.txt

    => tftp 0x87000000 uEnv_blob
    Using FEC0 device
    TFTP from server 192.168.1.110; our IP address is 192.168.1.134
    Filename ‘uEnv_blob’.
    Load address: 0x87000000
    Loading: #
    1.1 MiB/s
    done
    Bytes transferred = 8000 (1f40 hex)

    => env import -b 0x87000000 8000
    => printenv
    var2=1
    var3=1
    �ue�var1=1

    Test2)
    OUT=uEnv.txt
    echo “var1=1” > $OUT
    echo “var2=1” >> $OUT
    echo “var3=1” >> $OUT
    echo “” >> $OUT

    mkenvimage -s 8000 -o uEnv_blob uEnv.txt

    => tftp 0x87000000 uEnv_blob
    Using FEC0 device
    TFTP from server 192.168.1.110; our IP address is 192.168.1.134
    Filename ‘uEnv_blob’.
    Load address: 0x87000000
    Loading: #
    976.6 KiB/s
    done
    Bytes transferred = 8000 (1f40 hex)

    => env import -b 0x87000000 8000
    => print
    UÙ„5var1=1
    var2=1
    var3=1

    As you can see, in both cases, variables are not all loaded as expected.

    This is my current u-boot version:
    => version
    U-Boot 2017.03-mx6ul+g434eba6 (Dec 06 2017 – 13:31:34 +0200)
    arm-fslc-linux-gnueabi-gcc (GCC) 7.2.0
    GNU ld (GNU Binutils) 2.29.0.20170912

    And this is u-boot-tools package installed on Ubuntu 20.04

    $ dpkg -l|grep boot-tools
    ii u-boot-tools 2019.07+dfsg-1ubuntu6 amd64 companion tools for Das U-Boot bootloader

    I am not sure if some step to clean the memory where the blob is loaded is missing before the tftp tranfer command.

    1. “env import” doesn’t require the environment to be processed by mkenvimage. “env import” just takes a simple text files, with one line per variable, like your initial uEnv.txt.

      mkenvimage aims at creating an image of the environment as it is stored on your NAND flash or MMC device, so that you can flash an environment with specific contents for example during your factory flashing process.

  6. If I write the environment generated with mkenvimage to flash Uboot reject it saying: “*** Warning – bad CRC, using default environment”

    My command is:
    $ mkenvimage -r -s 0x00010000 -o uboot-env.bin recipes-bsp/u-boot/files/uboot-env.txt

    Am I doing something wrong or can I avoid this by changing a UBoot setting to accept a uninitialized env?

    Note: Using U-Boot 2020.01-stm32mp-r2

    Thanks!

    1. It depends how your U-Boot is configured. Make sure that the -r option matches the fact that you’re using a redundant U-Boot environment, and make sure that the size 0x10000 matches your U-Boot configuration as well.

      1. Thanks for the hint, the problem was indeed a mismatch with the environment size.

        In the STM32MP official BSP the CONFIG_ENV_OFFSET is taken from the stm32mp15_basic_defconfig but the CONFIG_ENV_SIZE from the stm32mp15_trusted_defconfig.

        This happens if you select:
        UBOOT_CONFIG += “basic” but BOOTSCHEME_LABELS += “trusted” in your machine configuration.

        (didn’t check otherwise)

  7. Is it possible to use uboot default environment on every boot? i.e., uboot environment is not stored on a partition of flash. On every boot, uboot should use the default environment which is part of binary.
    or
    is it possible to append the env to end of uboot i.e., env should be part of uboot binary?
    I won’t be giving permission to edit env. Will be removing the edit env configuration

    CONFIG_ENV_SIZE=0x10000
    CONFIG_ENV_OFFSET=0x60000
    CONFIG_ENV_SECT_SIZE=0x10000
    CONFIG_ENV_OFFSET_REDUND=0x70000
    # CONFIG_ENV_VARS_UBOOT_CONFIG is not set
    # Environment commands
    # CONFIG_CMD_ASKENV is not set
    # CONFIG_CMD_EXPORTENV is not set
    # CONFIG_CMD_IMPORTENV is not set
    CONFIG_CMD_EDITENV=y
    # CONFIG_CMD_GREPENV is not set
    CONFIG_CMD_SAVEENV=y
    # CONFIG_CMD_ERASEENV is not set
    CONFIG_CMD_ENV_EXISTS=y
    # CONFIG_CMD_ENV_CALLBACK is not set
    # CONFIG_CMD_ENV_FLAGS is not set
    # Environment
    CONFIG_ENV_SUPPORT=y
    CONFIG_SAVEENV=y
    # CONFIG_ENV_OVERWRITE is not set
    # CONFIG_ENV_IS_NOWHERE is not set
    CONFIG_ENV_IS_IN_SPI_FLASH=y
    CONFIG_SYS_REDUNDAND_ENVIRONMENT=y
    CONFIG_ENV_ADDR=0x0
    # CONFIG_SYS_RELOC_GD_ENV_ADDR is not set
    # CONFIG_USE_DEFAULT_ENV_FILE is not set
    # CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG is not set
    # CONFIG_ENV_APPEND is not set
    # CONFIG_ENV_WRITEABLE_LIST is not set
    # CONFIG_ENV_ACCESS_IGNORE_FORCE is not set

Leave a Reply to Robert Berger Cancel reply