Using Distro Boot With Xilinx U-Boot

This pages provides information related to using the industry standard "distro boot" boot flow for U-boot as it's been implemented by Xilinx. 

Table of Contents

Introduction

While x86-based platforms have a de facto standardization of how boot operates from BIOS/UEFI during initial power-on until hand-off to a robust operating system like Linux or Microsoft Windows, this is largely incidental and has much to do with the limited number of x86-based vendors in the market. By contrast, the number of Arm-based SoC platforms numbers in the dozens and virtually every SoC has some form of unique boot process.

Supporting all these unique Arm platforms can be tedious at best and at worst quickly devolves to inconsistencies in the expectations and experiences on each. These inconsistencies quickly escalate into increased development time and maintenance costs for the software teams involved. 

What is Distro Boot?

Distro boot is an embedded-focused boot methodology with the primary aim to make booting Arm-based platforms more standardized and predictable; similar to the experience on x86-based desktop and server platforms. The primary way that distro boot accomplishes this goal is by decoupling the boot-time discovery of boot media from the remainder of the bootloader and firmware stack.

For example, on a Xilinx Zynq UltraScale+ platform, the initial power-on is run via the SoC's in-built BootROM. The BootROM then discovers the primary boot medium via a sample of the SoC's MODE pins and uses this to hand-off to the Xilinx First Stage Boot Loader or FSBL.

During the runtime of the FSBL, other components such as the Xilinx-specific PMU firmware and Arm Trusted Firmware are loaded before handing off to U-Boot as the second stage bootloader. From an end-user perspective, these operations are analogous to the BIOS/UEFI experience on an x86-based platform.

That is, the first point in execution where context-aware decisions need to be made during the boot process is during the hand-off from U-Boot to the robust operating system environment. Distro boot provides a framework in which these choices can be made in a predictable and platform-independent manner.

How Distro Boot Is Implemented

The distro boot functionality is primarily implemented as an extension of the existing U-Boot bootcmd functionality in U-Boot. In a standard U-Boot boot process, the bootcmd variable contains the sequence of commands to be executed automatically after the boot countdown finishes (eg, if no key is pressed). The bootcmd variable contains a sequence of commands that are executed sequentially in order to load and hand-off to the next stage of boot.

For example, a simple TFTP-based boot is illustrated below.

Using the bootcmd Variable for Distro Boot

Distro boot extends this functionality by redirecting the call to bootcmd to a call to the distro_bootcmd variable. 

Boot Targets


How the distro_bootcmd variable is defined and used differs by vendor but it typically contains a sequence of commands that scans a pre-defined list of potential boot targets in search of boot collateral as shown below.


The command loops through the contents of the boot_targets list and scans the media in order looking for additional boot collateral. The boot_targets list is defined in the platform definition in the U-Boot source tree.


Depending on the specifics of the target platform, the distro boot infrastructure can either use the boot_targets list to explicitly find specific boot collateral (eg, hard-coded loading once a valid boot target is located) or it can be used to locate some kind of decoupled configuration information.

Using the extlinux Method


Specifically, the distro boot infrastructure will first scan for a file named extlinux.conf at the pre-defined locations (ex: /extlinux/extlinux.conf or /boot/extlinux/extlinux.conf) in the default U-Boot environment. The basic syntax of the extlinux.conf file is as show below.



Once U-Boot has found this file it will parse the fields as defined and hand-off to the components specified in the file. The syntax of this file references paths in the boot media. For example, a value of KERNEL Image will look for the file Image in the same directory of the boot media as the extlinux.conf. Conversely, a value of /boot/linux-image-5.2 will look for a file name linux-image-5.2 in the directory /boot of the filesystem.

Using the boot.scr Method


In the absence of a valid extlinux.conf file, U-Boot will scan the boot_targets list looking for a file named boot.scr.uimg or boot.scr (in that order) and run any commands located in the script file. An example of the script file syntax is seen below.  If your environment requires a different sequence of commands or behavior, you can edit the boot.scr file to suit your needs.



It's important to note that this syntax is standard U-Boot HUSH scripting syntax. The only change being made here is that this script is loaded into the environment during the boot process rather than being compiled in to the binaries.

Packaging the boot.scr File

Prior to use in a distro boot environment, the boot script must be compiled using mkimage as noted in the examples below. 

The recommended method for packaging the boot.scr image is to use the U-Boot FIT format with a script similar to:


Packaging a FIT image is similar to the legacy method in that it uses mkimage but the syntax is much simpler:


If your design does not require the additional features provided in the FIT description method seen above, the image can be packaged simply with the mkimage command directly:

Modifying an Existing boot.scr.uimg/boot.scr File

If you need to edit an existing packaged boot.scr file (or boot.scr.uimg), you can extract the plain ASCII text format using the following command line:

Remember that the boot.scr file will need be re-packaged with mkimage after the edits are complete.

How Xilinx Uses Distro Boot

Starting with the 2020.1 release, Xilinx has switched to using the distro boot infrastructure by default for all SoC platform.  The default mechanism in the Xilinx-provided software stack utilizes the boot.scr framework.  Support is still present for using extlinux.conf files and they will be used if present.  The platform files which define the boot_targets list and the Xilinx-specific default U-Boot environment are:

SoC PlatformPath in U-Boot Source Tree
Zynq-7000include/configs/zynq-common.h
Zynq UltraScale+ MPSoCinclude/configs/xilinx_zynqmp.h
Versalinclude/configs/xilinx_versal.h

On Xilinx platforms, the boot_targets list always prepends the current primary boot mode as configured on the MODE pins. Thus, it is expected to see a given target more than once in the boot_targets variable. For example, on a Zynq UltraScale+ MPSoC device booting from SD card, the boot_targets list appears as:


In addition, the Xilinx distro boot infrastructure is implemented such that if a boot script file is found, these commands are utilized to load the boot components from specific locations on the boot medium to specific locations in memory. Further, the default Xilinx workflow is to name the compiled version of the boot script boot.scr rather than boot.scr.uimg (though both will still work).

Booting from SD Card


For example, when booting from MMC devices (SD card or eMMC), the following script is run from the boot.scr file by default in the Xilinx-provided U-Boot environment.  This can be modified based on your needs. 

For additional details on the usage of the bootm and booti commands, see the U-Boot page.



Of note in this scheme is that the files must be found in the root of the filesystem and follow the naming scheme:

Component

File Name

Load Address

U-Boot combined image file (image.ub)

image.ub

0x10000000

Linux kernel image file (if image.ub is not found)

Image

0x00200000

Linux device tree file (if image.ub is not found)

system.dtb

0x00100000

Linux root filesystem image (if image.ub is not found)

rootfs.cpio.gz.u-boot

0x04000000


Booting from QSPI

When the boot mode detected is QSPI, the following script is run from the boot.scr file by default in the Xilinx-provided U-Boot environment.  This can be modified based on your needs. 


When booting from a QSPI device, care must be taken to maintain a very specific scheme for where files are located both in the nonvolatile flash device as well as where they are loaded into DDR prior to hand-off to the robust operating system.

Component

Flash Address

Load Address

U-Boot combined image file (image.ub)

0xF00000

0x10000000

Linux kernel image file (if image.ub is not found)

0xF00000

0x00200000

Linux device tree file (if image.ub is not found)

Pre-loaded by BOOT.BIN

0x00100000

Linux root filesystem image (if image.ub is not found)

0x4000000

0x04000000

Note: The table above presents default values as found in the pre-built collateral.  The PetaLinux tools will automatically adjust the flash and load addresses as appropriate to fit the relative sizes of each payload partition.

It is important to note that when booting from MMC devices, U-Boot will load all of the individual components from the boot media as files. When booting from flash devices, all of the components are loaded by U-Boot except for system.dtb. For flash devices, the system.dtb file is assumed to be pre-loaded to the correct address by FSBL from the BOOT.BIN file.

Xilinx Default Addresses

In JTAG boot mode, U-Boot will look for boot.scr.uimg in DDR at address 0x20000000.  This is set by environment variable SCRIPTADDR.  In the eMMC/SD bootmodeit U-Boot will look for a file named boot.scr.uimg in the primary FAT file system partition.  When booting from QSPI or NAND devices, U-Boot will expect boot.scr.uimg to be flashed at address 0x3E80000. This value is configurable in the CONFIG_BOOT_SCRIPT_OFFSET variable.   

Boot Method Precedence

In summary, the order of precedence for searching for boot components is as follows

  1. extlinux.conf file (located in /extlinux/ or /boot/extlinux/)
  2. boot.scr file + image.ub file
  3. boot.scr file + individual files (Image, system.dtb, etc.)

References


https://gitlab.denx.de/u-boot/u-boot/blob/master/doc/README.distro
https://www.denx.de/wiki/view/DULG/UBootEnvVariables
https://wiki.syslinux.org/wiki/index.php?title=Config
http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/