1. Das U-Boot[edit | edit source]
Das U-Boot ("the Universal Boot Loader" or U-Boot) is an open-source bootloader that can be used on STMicroelectronics boards to initialize the platform and load the Linux® kernel.
- Official source code is available under git repository [1] at https://source.denx.de/u-boot/u-boot, also available in https://github.com/u-boot/u-boot
- source.denx.de also hosts the Custodian git trees;
the STMicroelectronics U-Boot Custodian Tree is available in https://source.denx.de/u-boot/custodians/u-boot-stm - the fork of "U-Boot" Source Tree used in OpenSTLinux is available in ST GITHUB[2] with associated releases [3]: https://github.com/STMicroelectronics/u-boot
- source.denx.de also hosts the Custodian git trees;
- Official manual:
- https://u-boot.readthedocs.io:
it is the documentation generated from stable source code bymake htmldocs
- the documentations available in source code: README file and doc/
- https://u-boot.readthedocs.io:
Read the README file before starting using U-Boot. It covers the following topics:
- source file tree structure
- description of CONFIG defines
- instructions for building U-Boot
- brief description of the Hush shell
- list of common environment variables
2. U-Boot overview[edit | edit source]
The STM32 MPU boot chain uses Trusted Firmware-A (TF-A) as FSBL.
U-Boot is included in a TF-A FIP.
2.1. SPL[edit | edit source]
U-Boot SPL is not supported in OpenSTLinux.
2.1.1. SPL description[edit | edit source]
The U-Boot SPL or SPL is an alternate first stage bootloader (FSBL).
It is a small binary (bootstrap utility) generated from the U-Boot source and stored in the internal limited-size embedded RAM. SPL main features are the following:
- It is loaded by the ROM code.
- It performs the initial CPU and board configuration (clocks and DDR memory).
- It loads the SSBL (U-Boot) into the DDR memory.
2.1.2. SPL execution sequence[edit | edit source]
SPL executes the following main steps in SYSRAM:
- board_init_f(): driver initialization including DDR initialization (mininimal stack and heap: CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN)
- configuration of heap in DDR memory (CONFIG_SPL_SYS_MALLOC_F_LEN)
- board_init_r(): initialization of the other drivers activated in the SPL device tree
- loading and execution of U-Boot (or Kernel in Falcon mode[4]: README.falcon ).
2.2. U-Boot: SSBL[edit | edit source]
2.2.1. U-Boot description[edit | edit source]
U-Boot is the second-stage bootloader (SSBL) of boot chain for STM32 Arm® Cortex® MPUs .
SSBL main features are the following:
- It is configurable and expendable.
- It features a simple command line interface (CLI), allowing users to interact over a serial port console.
- It provides scripting capabilities.
- It loads the kernel into RAM and gives control to the kernel.
- It manages several internal and external devices such as NAND and NOR Flash memories, Ethernet and USB.
- It supports the following features and commands:
- File systems: FAT, UBI/UBIFS, JFFS
- IP stack: FTP
- Display: LCD, HDMI, BMP for splashcreen
- USB: host (mass storage) or device (DFU stack)
2.2.2. U-Boot execution sequence[edit | edit source]
U-Boot executes the following main steps in DDR memory:
- Pre-relocation initialization (common/board_f.c): minimal initialization (such as CPU, clock, reset, DDR and console) running at the CONFIG_SYS_TEXT_BASE load address.
- Relocation: copy of the code to the end of DDR memory.
- Post-relocation initialization:(common/board_r.c): initialization of all the drivers.
- Command execution through autoboot (CONFIG_AUTOBOOT) or console shell.
- Execution of the boot command (by default bootcmd=CONFIG_BOOTCOMMAND):
for example, execution of the commandbootm
to:- load and check images (such as kernel, device tree and ramdisk)
- fixup the kernel device tree
- install the secure monitor (optional) or
- pass the control to the Linux kernel (or to another target application)
- Execution of the boot command (by default bootcmd=CONFIG_BOOTCOMMAND):
3. U-Boot configuration[edit | edit source]
The U-Boot binary configuration is based on
- Kbuild infrastructure (as in Linux Kernel, you can use
make menuconfig
in U-Boot)
The configurations are based on:- options defined in Kconfig files (CONFIG_ compilation flags)
- the selected configuration file: configs/stm32mp*_defconfig
- other compilation flags defined in include/configs/stm32mp*.h (these flags are progressively migrated to Kconfig)
The file name is configured through CONFIG_SYS_CONFIG_NAME, for example on STMicroelectronics boards:- STM32MP13x lines : include/configs/stm32mp13_st_common.h
- STM32MP15x lines : include/configs/stm32mp15_st_common.h
- STM32MP25x lines : include/configs/stm32mp25_st_common.h
- DeviceTree: U-Boot binaries include a device tree blob that is parsed at runtime
All the configuration flags (prefixed by CONFIG_) are described in the source code, either in the README file or in the documentation directory .
For example, CONFIG_SPL activates the SPL compilation.
Hence to compile U-Boot, select the <target> and the device tree for the board in order to choose a predefined configuration.
Refer to #U-Boot_build for examples.
3.1. Kbuild[edit | edit source]
Like the kernel, the U-Boot build system is based on configuration symbols (defined in Kconfig files). The selected values are stored in a .config file located in the build directory, with the same makefile target. .
Proceed as follows:
- Select a predefined configuration (defconfig file in configs directory ) and generate the first .config:
make <config>_defconfig.
- Change the U-Boot compile configuration (modify .config) by using one of the following five
make
commands:
make menuconfig --> menu based program make config --> line-oriented configuration make xconfig --> QT program make gconfig --> GTK program make nconfig --> ncurse menu based program
You can then compile U-Boot with the updated .config.
Warning: the modification is performed locally in the build directory. It will be lost after a make distclean
.
Save your configuration to be able to use it as a defconfig file:
make savedefconfig
This target saves the current config as a defconfig file in the build directory. It can then be compared with the predefined configuration (configs/stm32mp*defconfig).
The other makefile targets are the following:
make help .... Configuration targets: config - Update current config utilising a line-oriented program nconfig - Update current config utilising a ncurses menu based program menuconfig - Update current config utilising a menu based program xconfig - Update current config utilising a Qt based front-end gconfig - Update current config utilising a GTK+ based front-end oldconfig - Update current config utilising a provided .config as base localmodconfig - Update current config disabling modules not loaded localyesconfig - Update current config converting local mods to core defconfig - New config with default from ARCH supplied defconfig savedefconfig - Save current config as ./defconfig (minimal config) allnoconfig - New config where all options are answered with no allyesconfig - New config where all options are accepted with yes allmodconfig - New config selecting modules when possible alldefconfig - New config with all symbols set to default randconfig - New config with random answer to all options listnewconfig - List new options olddefconfig - Same as oldconfig but sets new symbols to their default value without prompting
3.2. Device tree[edit | edit source]
Refer to U-Boot Documentation or doc/develop/devicetree/control.rst for details.
The board device tree has the same binding as the kernel. By default it is integrated within the U-Boot binaries: u-boot.bin: appended at the end of the code (CONFIG_OF_SEPARATE) or embedded in the U-Boot binary (CONFIG_OF_EMBED).
In OpenSTLinux, the U-Boot device tree (u-boot.dtb) is provided as external file loaded by FSBL=TF-A when U-Boot code is started (u-boot-nodtb.bin: code without device tree): device tree address is provided as boot parameter (in r2 register).
A default device tree is available in the defconfig file (by setting CONFIG_DEFAULT_DEVICE_TREE).
You can either select another supported device tree using the DEVICE_TREE make flag. For STM32 Arm® Cortex® MPUs boards, the corresponding file is <dts-file-name>.dts in arch/arm/dts/stm32mp*.dts , with <dts-file-name> set to the full name of the board:
make DEVICE_TREE=<dts-file-name>
or provide a device tree blob (dtb file) resulting from the dts file compilation, by using the EXT_DTB option:
make EXT_DTB=<dts-file-name>.dtb
To obtain a device tree file <dts-file-name>.dts that is identical to the Linux kernel one, these U-Boot properties are only added for ST boards in the add-on file <dts-file-name>-u-boot.dtsi. This file is automatically included in <dts-file-name>.dts during device tree compilation (the needed "#include" is added during the pre-processing phasis).
# Try these files in order to find the U-Boot-specific .dtsi include file u_boot_dtsi_options = $(strip $(wildcard $(dir $<)$(basename $(notdir $<))-u-boot.dtsi) \ $(wildcard $(dir $<)$(subst $\",,$(CONFIG_SYS_SOC))-u-boot.dtsi) \ $(wildcard $(dir $<)$(subst $\",,$(CONFIG_SYS_CPU))-u-boot.dtsi) \ $(wildcard $(dir $<)$(subst $\",,$(CONFIG_SYS_VENDOR))-u-boot.dtsi) \ $(wildcard $(dir $<)u-boot.dtsi)) ... # We use the first match u_boot_dtsi = $(strip $(u_boot_dtsi_options_debug) \ $(notdir $(firstword $(u_boot_dtsi_options)))) ... # Modified for U-Boot # Bring in any U-Boot-specific include at the end of the file # And finally any custom .dtsi fragments specified with CONFIG_DEVICE_TREE_INCLUDES cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \ (cat $<; $(if $(u_boot_dtsi),echo '$(pound)include "$(u_boot_dtsi)"')) > $(pre-tmp); \ $(foreach f,$(subst $(quote),,$(CONFIG_DEVICE_TREE_INCLUDES)), \ echo '$(pound)include "$(f)"' >> $(pre-tmp);) \ $(HOSTCC) -E $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $(pre-tmp) ; \ $(DTC) -O dtb -o $@ -b 0 \ -i $(dir $<) $(DTC_FLAGS) \ -d $(depfile).dtc.tmp $(dtc-tmp) || \ (echo "Check $(shell pwd)/$(pre-tmp) for errors" && false) \ ; \ sed "s:$(pre-tmp):$(<):" $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile); \ $(DTC) -O dts -I dtb -s $(DTC_FLAGS) -o $@-u-boot.dts $@; \ $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ $(DTC) -O dts -I dts -s $(DTC_FLAGS) -o $@-kernel.dts $(dtc-tmp)
Device tree in SPL (not used in OpenSTLinux):
The SPL device tree is also generated from this U-Boot device tree. However to reduce its size, the U-Boot makefile uses the fdtgrep tool to parse the full U-Boot DTB and identify all the drivers required by SPL.
To do this, U-Boot uses specific device-tree flags to determine if the associated driver is initialized prior to U-Boot relocation and/or if the associated node is present in SPL :
- u-boot,dm-pre-reloc => present in SPL, initialized before relocation in U-Boot
- u-boot,dm-pre-proper => initialized before relocation in U-Boot
- u-boot,dm-spl => present in SPL
In the device tree used by U-Boot, these flags need to be added in all the nodes used in SPL or in U-Boot before relocation, and for all used handles (clock, reset, pincontrol).
4. U-Boot command line interface (CLI)[edit | edit source]
Refer to U-Boot Documentation or doc/usage/cmdline.rst .
U-Boot has a command line interface, the U-Boot console, in which you work with U-Boot commands and environment variables to create a customized boot process.
4.1. Commands[edit | edit source]
U-Boot has a set of built-in commands for managing the system and booting the device.By modifying U-Boot source code, you can create your own built-in commands.
The commands are defined in cmd/*.c . They are activated through the corresponding CONFIG_CMD_* configuration flag.
Use the help
command in the U-Boot shell to list the commands available on your device:
help
The U-Boot usage is described in U-Boot Documentation but only few commands are described here.
Below the list of all commands extracted from an old U-Boot Manual] (obsolete and not-exhaustive):
- Information Commands
- bdinfo - prints Board Info structure
- coninfo - prints console devices and information
- flinfo - prints Flash memory information
- iminfo - prints header information for application image
- help - prints online help
- Memory Commands
- base - prints or sets the address offset
- crc32 - checksum calculation
- cmp - memory compare
- cp - memory copy
- md - memory display
- mm - memory modify (auto-incrementing)
- mtest - simple RAM test
- mw - memory write (fill)
- nm - memory modify (constant address)
- loop - infinite loop on address range
- Flash Memory Commands
- cp - memory copy
- flinfo - prints Flash memory information
- erase - erases Flash memory
- protect - enables or disables Flash memory write protection
- mtdparts - defines a Linux compatible MTD partition scheme
- Execution Control Commands
- source - runs a script from memory
- bootm - boots application image from memory
- go - starts application at address 'addr'
- Download Commands
- bootp - boots image via network using BOOTP/TFTP protocol
- dhcp - invokes DHCP client to obtain IP/boot params
- loadb - loads binary file over serial line (kermit mode)
- loads - loads S-Record file over serial line
- rarpboot- boots image via network using RARP/TFTP protocol
- tftpboot- boots image via network using TFTP protocol
- Environment Variables Commands
- printenv- prints environment variables
- saveenv - saves environment variables to persistent storage
- setenv - sets environment variables
- run - runs commands in an environment variable
- bootd - default boot, that is run 'bootcmd'
- Flattened Device Tree support
- fdt addr - selects the FDT to work on
- fdt list - prints one level
- fdt print - recursive printing
- fdt mknode - creates new nodes
- fdt set - sets node properties
- fdt rm - removes nodes or properties
- fdt move - moves FDT blob to new address
- fdt chosen - fixup dynamic information
- Special Commands
- i2c - I2C sub-system
- Storage devices
- Miscellaneous Commands
- echo - echoes args to console
- reset - performs a CPU reset
- sleep - delays the execution for a predefined time
- version - prints the monitor version
To add a new command, refer to U-Boot Documentation or to doc/develop/commands.rst .
4.2. U-Boot environment variables[edit | edit source]
The U-Boot behavior is configured through environment variables.
Refer to README / Environment Variables and to U-Boot Documentation.
On the first boot, U-Boot uses a default environment embedded in the U-Boot binary. You can modify it by changing the content of CONFIG_EXTRA_ENV_SETTINGS in your configuration file (for example ./include/configs/stm32mp1.h) (see README / - Default Environment).
This environment can be modified and saved in the boot device. When it is present, it is loaded during U-Boot initialization.
For STMicroelectronics the enviromnent is according the boot device:
- To boot from e•MMC/SD card (CONFIG_ENV_IS_IN_MMC): at the end of the partition indicated by config field "u-boot,mmc-env-partition" in device-tree (for ST boards: partition named "u-boot-env" in ecosystem release ≥ v4.0.0 ).
- To boot from NAND Flash memory (CONFIG_ENV_IS_IN_UBI): in the two UBI volumes "config" (CONFIG_ENV_UBI_VOLUME) and "config_r" (CONFIG_ENV_UBI_VOLUME_REDUND).
- To boot from NOR Flash memory (CONFIG_ENV_IS_IN_SPI_FLASH): the "u-boot-env" mtd partition at offset CONFIG_ENV_OFFSET.
4.2.1. env command[edit | edit source]
The env
command allows displaying, modifying and saving the environment in U-Boot console.
help env env - environment handling commands Usage: env default [-f] -a - [forcibly] reset default environment env default [-f] var [...] - [forcibly] reset variable(s) to their default values env delete [-f] var [...] - [forcibly] delete variable(s) env edit name - edit environment variable env exists name - tests for existence of variable env print [-a | name ...] - print environment env print -e [name ...] - print UEFI environment env run var [...] - run commands in an environment variable env save - save environment env set -e name [arg ...] - set UEFI variable; unset if 'arg' not specified env set [-f] name [arg ...]
See U-Boot Documentation for details.
Example: proceed as follows to restore the default environment and save it. This is useful after a U-Boot upgrade:
env default -a env save
You can also use the command activated by CONFIG_CMD_ERASEENV:
env erase
4.2.2. bootcmd[edit | edit source]
"bootcmd" variable is the autoboot command (see doc/README.autoboot ). It defines the command executed when U-Boot starts (CONFIG_BOOTCOMMAND).
For stm32mp, CONFIG_BOOTCOMMAND="run bootcmd_stm32mp":
env print bootcmd bootcmd=run bootcmd_stm32mp
"bootcmd_stm32mp" is a script that selects the command to be executed for each boot device (see files in include/configs/: stm32mp13_st_common.h, stm32mp15_st_common.h or stm32mp25_st_common.h for STMicroelectronics board), based on generic distro scripts:
- To boot from a serial/usb device: execute the
stm32prog
command. - To boot from an e•MMC, SD card: boot only on the same device (bootcmd_mmc...).
- To boot from a NAND Flash memory: boot on ubifs partition on the NAND memory (bootcmd_ubi0).
- To boot from a NOR Flash memory: use the SD card (on SDMMC 0 on ST boards with bootcmd_mmc0)
env print bootcmd_stm32mp
You can then change this configuration:
- either permanently in your board file
- default environment by CONFIG_EXTRA_ENV_SETTINGS (see ./include/configs/stm32mp1.h)
- change CONFIG_BOOTCOMMAND value in your defconfig
CONFIG_BOOTCOMMAND="run bootcmd_mmc0"
CONFIG_BOOTCOMMAND="run distro_bootcmd"
- or temporarily in the saved environment:
env set bootcmd run bootcmd_mmc0 env save
Note: To reset the environment to its default value:
env default bootcmd env save
4.3. U-Boot scripting capabilities[edit | edit source]
"Script" is made up of variables (bootcmd
for example) that contain a set of commands that are executed by the U-Boot command interpreter one after another. You run this script with the run
command, for example:
run bootcmd
"Script image" is external binary file with U-Boot header and containing a sequence of commands. It is loaded by U-Boot in memory and executed using the source
command, it allows the user to execute a set of predefined U-Boot commands automatically.
To convert an text file commands.txt into a script image for U-Boot, you have to use the mkimage tool as follows:
mkimage -T script -C none -n 'Demo Script File' -d commands.txt setenv.img
These feature are particularly useful when U-Boot use a the hush shell (similar to Bourne shell) as command interpreter; it is the default configuration in OpenSTLinux (CONFIG_HUSH_PARSER).
4.4. Autoboot[edit | edit source]
If CONFIG_AUTOBOOT is activated, you have some delay established in bootdelay
variable or CONFIG_BOOTDELAY (2s by default, 1s for ST configuration) to enter the console by pressing any key, after the line below is displayed.
Hit any key to stop autoboot: 2
If U-Boot is not interrupted, bootcmd is executed (CONFIG_BOOTCOMMAND), in other words automatic booting have the same effect that the command:
run bootcmd
or
boot
4.5. Generic Distro configuration[edit | edit source]
Refer to documentation or to doc/develop/distro.rst for details.
This feature is activated by default on ST boards (CONFIG_DISTRO_DEFAULTS):
- one boot command (bootmcd_xxx) exists for each bootable device.
- U-Boot is independent from the Linux distribution used.
- bootcmd is defined in ./include/config_distro_bootcmd.h
When DISTRO is enabled, the command that is executed by default is include/config_distro_bootcmd.h :
bootcmd=run distro_bootcmd
This script tries any device found in the 'boot_targets' variable and executes the associated bootcmd.
Example for mmc0, mmc1, mmc2, pxe and ubifs devices:
bootcmd_mmc0=setenv devnum 0; run mmc_boot bootcmd_mmc1=setenv devnum 1; run mmc_boot bootcmd_mmc2=setenv devnum 2; run mmc_boot bootcmd_pxe=run boot_net_usb_start; dhcp; if pxe get; then pxe boot; fi bootcmd_ubifs0=setenv devnum 0; run ubifs_boot
U-Boot searches for an extlinux.conf configuration file for each bootable device. This file defines the kernel configuration to be used with bootm
command:
- bootargs
- files to start the OS:
- kernel (uImage) + device tree + ramdisk files (optional)
- FIT image, including all these needed files (for details see doc/uImage.FIT/howto.txt )
5. U-Boot build[edit | edit source]
See U-Boot Documentation.
5.1. Prerequisites[edit | edit source]
- a PC with Linux and tools:
- U-Boot source code
git clone https://github.com/STMicroelectronics/u-boot
- from the Mainline U-Boot in official GIT repository [1]
git clone https://source.denx.de/u-boot/u-boot.git
5.2. ARM cross compiler[edit | edit source]
A cross compiler [5] must be installed on your Host (X86_64, i686, ...) for the ARM targeted Device architecture, AArch32 for STM32MP1 series or AArch64 for STM32MP2 series. In addition, the $PATH and $CROSS_COMPILE environment variables must be configured in your shell.
You can use gcc for ARM, available in:
- the SDK toolchain (see Cross-compile with OpenSTLinux SDK)
PATH and CROSS_COMPILE are automatically updated. - an existing package
For example, install gcc-arm-linux-gnueabihf on Ubuntu/Debian:
sudo apt-get install gcc-arm-linux-gnueabihf
- an existing toolchain:
- latest gcc toolchain provided by arm (https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads)
- Linaro also provides monthly build: (https://www.linaro.org/downloads/)
Examples for STM32MP1 series:
1. gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf.tar.xz provided by arm, extract the toolchain in $HOME and update your environment with:
export PATH=$HOME/gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf/bin:$PATH export CROSS_COMPILE=arm-none-linux-gnueabihf-
2.gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabi.tar.xz, extract the toolchain in $HOME and update your environment with:
export PATH=$HOME/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabi/bin:$PATH export CROSS_COMPILE=arm-linux-gnueabi-
5.3. Compilation[edit | edit source]
In the U-Boot source directory, select the defconfig for the <target> and the <device tree> for your board and then execute the make all
command:
make <target>_defconfig make DEVICE_TREE=<device tree> all
Use help to list other targets than all:
make help
Optionally
- KBUILD_OUTPUT can be used to change the output build directory in order to compile several targets in the source directory. For example:
export KBUILD_OUTPUT=<path>
- DEVICE_TREE can also be exported to your environment when only one board is supported. For example:
export DEVICE_TREE=<device-tree>
The result is the following:
export KBUILD_OUTPUT=<path> export DEVICE_TREE=<device tree> make <target>_defconfig make all
See examples in
5.4. Output files[edit | edit source]
The resulting U-Boot files are located in your build directory (U-Boot or KBUILD_OUTPUT).
For OpenSTLinux, two U-Boot files are used by ST boards to generate the FIP file used byTF-A BL2:
- BL33_CFG=u-boot.dtb : the U-Boot device tree, selected by DEVICE_TREE, loaded by TF-A BL2
- BL33=u-boot-nodtb.bin: the U-Boot executable, loaded by TF-A BL2 started by secure world = OP-TEE with BL33_CFG as parameter
Nota: All the compiled device tree are available in $KBUILD_OUTPUT/arch/arm/dts/*.dtb.
You can select them as BL33_CFG parameter without U-Boot recompilation.
See TF-A BL2 overview for FIP details.
The file used to debug with gdb is u-boot, the elf file for U-Boot.
The file u-boot.stm32, i.e. the U-Boot binary with STM32 header, is no more generated and used in OpenSTlinux.
This file is generated only with stm32mp15_trusted_defconfig, when CONFIG_STM32MP15x_STM32IMAGE is activated. This defconfig is kept for compatibility with upstream, it is not supported in OpenSTlinux.
The STM32 image format (*.stm32) is also managed by mkimage U-Boot tools and Signing_tool to manage this compatibility, stm32mp15_trusted_defconfig and stm32mp15_basic_defconfig.
6. References[edit | edit source]
- ↑ 1.0 1.1 https://source.denx.de/u-boot/u-boot.git or https://github.com/u-boot/u-boot
- ↑ 2.0 2.1 https://github.com/STMicroelectronics/u-boot
- ↑ 3.0 3.1 https://github.com/STMicroelectronics/u-boot/releases
- ↑ https://www.denx.de/wiki/pub/U-Boot/MiniSummitELCE2013/2013-ELCE-U-Boot-Falcon-Boot.pdf
- ↑ https://en.wikipedia.org/wiki/Cross_compiler