Yocto add U-Boot variables

Hello there,

We are currently trying to add Uboot variables during our Yocto (Torizon Minimal) build, but we are unsure how. The goal is to get the M7-core booted, so essentially these steps: How to Load Compiled Binaries into Cortex-M | Toradex Developer Center
With the TorizonCore builder we added them in a post-build script to the u-boot-initial-env-sd file, but there is surely a better way to add them directly in the yocto build? Our question is where can we add them? (we use the Verdin i.MX8MP)

Cheers
Tim

Hi, I’m the Toradex AI Assistant.

I might make mistakes or occasionally get you wrong. Our support team will step in if needed.


Adding U-Boot Environment Variables in Yocto Build

You can add U-Boot environment variables directly during your Yocto build by modifying the U-Boot configuration files. Here’s how to approach this:

Method 1: Modify Board-Specific Configuration Files

The default environment variables are set at compilation time and built into the U-Boot binary (1). You can modify these by creating a U-Boot bbappend file that patches the board-specific configuration header file.

For example, if you’re working with a Verdin iMX8M Plus, you would modify the configuration found in the board-specific header file (1). The default environment is defined using CONFIG_EXTRA_ENV_SETTINGS (1).

Here’s an example of how environment variables are defined in the configuration:

/* Initial environment variables */                                                                                                                            
#define CONFIG_EXTRA_ENV_SETTINGS \                                                                                                                            
        BOOTENV \                                                                                                                                              
        MEM_LAYOUT_ENV_SETTINGS \                                                                                                                              
"bootcmd_mfg=fastboot 0\0" \                                                                                                                           
        "boot_file=Image\0" \                                                                                                                                  
        "boot_scripts=" BOOT_SCRIPT "\0" \                                                                                                                     
        "boot_script_dhcp=" BOOT_SCRIPT "\0" \                                                                                                                 
        "console=ttymxc2\0" \                                                                                                                                  
        "fdt_board=dev\0" \                                                                                                                                    
        "initrd_addr=0x43800000\0" \                                                                                                                           
        "initrd_high=0xffffffffffffffff\0" \                                                                                                                   
        "setup=setenv setupargs console=tty1 console=${console},${baudrate} " \                                                                                
                "consoleblank=0 earlycon\0" \                                                                                                                  
"update_uboot=askenv confirm Did you load flash.bin (y/N)?; " \                                                                                        
                "if test \"$confirm\" = \"y\"; then " \                                                                                                        
                "setexpr blkcnt ${filesize} + 0x1ff && setexpr blkcnt " \                                                                                      
                "${blkcnt} / 0x200; mmc dev 2 1; mmc write ${loadaddr} 0x0 " \                                                                                 
                "${blkcnt}; fi\0"  

(1)

Method 2: Create a U-Boot bbappend

Create a bbappend file for the U-Boot recipe (e.g., u-boot-toradex_%.bbappend) in your custom meta layer. In this file, you can:

  1. Add patches to modify the board configuration header
  2. Use do_configure_prepend or do_configure_append tasks to modify configuration files
  3. Set additional environment variables through the build system

Important Considerations

When working with U-Boot environment variables, keep these best practices in mind (1):

  • Default Environment: The default environment is always present and is used when the board is first flashed (1)
  • Persistent Storage: Changes made with setenv in U-Boot only affect the RAM representation until saveenv is called (1)
  • Dynamic Variables: Some variables can be altered by U-Boot code during boot, so saving the environment can have unexpected consequences (1)

Alternative Approach: TorizonCore Builder Limitations

While TorizonCore Builder is excellent for many customizations, it has limitations. TorizonCore Builder does not support customizing the bootloader (U-Boot) (2). For U-Boot modifications like adding environment variables, you need to use the Yocto Project approach (2).

The method you mentioned using TorizonCore Builder to modify the u-boot-initial-env-sd file in a post-build script is a valid workaround, but integrating the changes directly into the Yocto build provides better maintainability and reproducibility.

Best regards, Toradex AI Assistant.


Did you like my answer? :+1: :-1:

If I answered your question, please tick the “Solution” checkbox.

For follow-up questions to me, please use @ToradexAI in your post.

Greetings @TimSiegrist,

One method to generically add any extra U-Boot environment variables is by using CFG_EXTRA_ENV_SETTINGS. In fact that is what we do in U-Boot as seen here: Making sure you're not a bot!

If you want to add it to the current list in this source file you’d probably have to create a patch in Yocto.

Best Regards,
Jeremias

Hi @jeremias.tx
Thanks for the input. I managed to add the vars via a patch. One thing I struggled with was to get the Env var bootcmd changed, because I want to add my newly added cm_boot variable to it (which essentially boots the M7). In the end I applied another patch to the env_default.h file, under CONFIG_BOOTCOMMAND. From the build output I assume it works, but I have yet to test it.
(bootcmd=run cm_boot; run distro_bootcmd in u-boot-initial-env-verdin-imx8mp-sd). This is tha patch i used:

diff --git a/include/env_default.h b/include/env_default.h
index 7f8dc1c35a7..0c06cfd0a7f 100644
--- a/include/env_default.h
+++ b/include/env_default.h
@@ -38,7 +38,7 @@ const char default_environment[] = {
 	"bootargs="	CONFIG_BOOTARGS			"\0"
 #endif
 #ifdef	CONFIG_BOOTCOMMAND
-	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"
+	"bootcmd=run cm_boot; "	CONFIG_BOOTCOMMAND		"\0"
 #endif
 #if defined(CONFIG_BOOTDELAY)
 	"bootdelay="	__stringify(CONFIG_BOOTDELAY)	"\0"

Is this the correct way to do this? Or is there another preferred way to set the bootcmd variable?

Cheers
Tim

Is this the correct way to do this? Or is there another preferred way to set the bootcmd variable?

Well that method could work. Though probably a more elegant method would just be to set the CONFIG option using a config fragment like this for example: meta-toradex-torizon/dynamic-layers/meta-imx-bsp/recipes-bsp/u-boot/imx95/bootcommand.cfg at scarthgap-7.x.y · torizon/meta-toradex-torizon · GitHub

This sets/overrides the specified CONFIG_* options. Just need to specify the *.cfg file in the u-boot recipes SRC_URI.

Another method is you could supply your own bootscript that sets and runs cm_boot. This is the default boot script for Torizon OS: meta-toradex-torizon/recipes-bsp/u-boot/u-boot-distro-boot/uEnv.txt.in at scarthgap-7.x.y · torizon/meta-toradex-torizon · GitHub

You could just basically copy this and add some lines for cm_boot. One benefit of this method is that the boot-script can be updated via an OS update if you ever need to. Otherwise any method should be fine as well.

Best Regards,
Jeremias

Hi @jeremias.tx

I had a look at the uEnv.txt.in file, since having the possibility to update them without TEZI would be very nice.
I’m not entirely sure where to append the cm_boot though.. Previously I used just the bootcmd=, where I added the M7 boot before the Linux part, where would I need to do this here, so I still have the auto-boot for it? On bootcmd_run itself maybe?

Cheers
Tim

so I still have the auto-boot for it? On bootcmd_run itself maybe?

I mean yes. If you look at the actual boot script here: meta-toradex-torizon/recipes-bsp/u-boot/u-boot-distro-boot/boot.cmd.in at scarthgap-7.x.y · torizon/meta-toradex-torizon · GitHub

You can see it loads the environment variables from uEnv.txt then it executes bootcmd_run as the final command. Therefore whatever is defined in bootcmd_run is what will get executed.

Best Regards,
Jeremias

Ok so I ended up with a u-boot-distro-boot%.bbappend file where I insert my commands into the uEnv.txt file, something like this:

addtask patch_uenv after do_compile before do_install

do_patch_uenv() {
    local uenv_file="${B}/uEnv.txt"

    // insert required commands..
    sed -i '/run bootcmd_load_k/i \            run cm_boot; \\' "${uenv_file}"

}

It works, and it’s nice to be able to update it via OS update!

Another thing I noticed though, is the following error:

Hit any key to stop autoboot:  0 
switch to partitions #0, OK
mmc1 is current device
Scanning mmc 1:1...
No EFI system partition
No EFI system partition
Failed to persist EFI variables
No EFI system partition
Failed to persist EFI variables
No EFI system partition
Failed to persist EFI variables
No EFI system partition
Failed to persist EFI variables
No EFI system partition
Failed to persist EFI variables
bad MBR sector signature 0x8052
Loading Boot0000 'mmc 2' failed
Loading Boot0001 'mmc 1' failed
EFI boot manager: Cannot load any image
switch to partitions #0, OK
mmc2(part 0) is current device
Scanning mmc 2:1...
Found U-Boot script /boot.scr
969 bytes read in 1 ms (946.3 KiB/s)
## Executing script at 50280000
8259 bytes read in 2 ms (3.9 MiB/s)
87788 bytes read in 3 ms (27.9 MiB/s)
223 bytes read in 3 ms (72.3 KiB/s)

After this log, it boots correctly, with all the DT overlays and so on. How can I avoid this?

Best Regards,
Tim

It works, and it’s nice to be able to update it via OS update!

Glad you were able to create a solution that works for you.

After this log, it boots correctly, with all the DT overlays and so on. How can I avoid this?

Which error are you referring to exactly in the log? Are you talking about this entire chunk here?:

Scanning mmc 1:1...
No EFI system partition
No EFI system partition
Failed to persist EFI variables
No EFI system partition
Failed to persist EFI variables
No EFI system partition
Failed to persist EFI variables
No EFI system partition
Failed to persist EFI variables
No EFI system partition
Failed to persist EFI variables
bad MBR sector signature 0x8052
Loading Boot0000 'mmc 2' failed
Loading Boot0001 'mmc 1' failed
EFI boot manager: Cannot load any image

Do you have an SD card of some kind attached to the device/system here?

To explain the boot method the Verdin i.MX8MP uses in this version is distro boot. This method works by iterating over a list of bootable targets until one of these targets results in a successful boot. The list of targets to iterate over is defined by the boot_targets variable in U-Boot. By default this variable has the following value:

boot_targets=mmc1 mmc2 dhcp

So you can see it starts with the device mmc1, this matches your logs. When it can’t find anything to boot in mmc1 it then goes to mmc2 where it finds a bootable system.

For the Verdin i.MX8MP mmc1 corresponds to the SD card, while mmc2 corresponds to the device’s actual internal eMMC flash. On my system when I don’t have an SD card, the boot will just “skip” over mmc1 cause there is no device there, in that case the boot logs look like so:

Hit any key to stop autoboot:  0
MMC: no card present <----- Because there is no SD card
switch to partitions #0, OK
mmc2(part 0) is current device
Scanning mmc 2:1...

Your system then must have something on the SD card interface for U-Boot to try and even scan it for bootable targets. Therefore, the solution is either remove the SD card, but I assume you probably have it there for a reason. In which case the other solution would be to modify the boot_targets variable so that mmc2 (the device’s eMMC flash) is first in the list. That way mmc1 won’t even be touched, since obviously the system can boot with mmc2 and there shouldn’t be logs about it during the boot.

Best Regards,
Jeremias

@jeremias.tx Ah makes sense, I had an SD card inserted, if I remove it I get the same log as you do. We want to use the SD Card in the end, so I will modify the variable.

Thanks for the inputs!

Best Regards,
Tim

Glad I was able to help clarify.