This is an old revision of the document!
This package will contain bl2, bl31 and bl33. The Secure OS (bl32) is outside the scope of this lab; even if we did bother to include it, it would just be there, doing nothing.
Following this exercise, we should be able to reach the first step of the booting sequence that can be interactive; meaning that we'll be able to interact with a shell implemented in bl33.
For this component we'll be using the Trusted Firmware-A project. Although it contains reference implementations for the other bootloaders as well, we are going to use it strictly for bl31. The other have more complete and widely recognized alternatives available.
We recommend reading the documentation moving forward. Take a close look at the build options in particular.
Following a successful build process, you should obtain a bl31.bin.
SPD=none
. make … bl31
.
With bl31 out of the way, we are going to tackle bl2 next. Remember however, that the main role of bl2 is to initialize the hardware using the proprietary firmware offered by the chip manufacturer. Without this firmware, we don't even have access to the DRAM memory.
Remember that bl1 is loaded from ROM in the first half of the available SRAM (aka. On-Chip RAM). That SRAM is just 128KB in size, so there's not much space. bl1 then loads bl2 (but not the remainder of the FIP) in the upper half of SRAM. At this point it's up to bl2 to enable the 2GB of DRAM and finish loading the rest of the FIP in main memory.
For this task, get the latest version of the firmware from here. What we're actually interested in are the following files:
For the last two components of our Firmware Package we'll be using U-Boot. Each of them has a very specific purpose.
At first, bl1 will start downloading the FIP using the Serial Download Protocol, running on top of a USB connection. Once it finishes loading bl2 (and the firmware from Task B), it cedes control to it instead. bl2 will initialize the DRAM using said firmware and then continue where bl1 left off, finishing the download of the FIP.
Since the board we are working on released, U-Boot has seen some improvements with respect to certain drivers that we can't do without. These improvements increased the size of bl2 to the point that it no longer fits in the board's SRAM (remember that bl2 must fit in 64-128KB of memory). Even with Link Time Optimizations which usually help in this regard, and with attempts at removing useless drivers, it's still a pain in the ass challenging to make everything fit. The TechNexion fork has the advantage of being slightly outdated and should give a guarantee that someone tested that the build actually works.
When bl31 runs its course, bl33 will be called upon. During this phase we'll finally have an interactive shell and multiple drivers to help interact with the board. With this, we can investigate the board's hardware, read and potentially override the partitions in the persistent storage and most importantly, boot Linux from any number of sources.
U-Boot is based on the same build system as the Linux kernel, namely Kbuild. To get an idea of what functionality it provides, try to run:
$ make help
If you check the configs/
directory, you will find a number of board-specific configuration files. These serve as templates, containing the minimal necessary configuration. By running make some_defconfig
the Kbuild system will determine what other unspecified options need to be enabled in order for these features to be functional. The result will be saved in a file called .config
.
Generate a .config
for your board. Also, don't forget the CROSS_COMPILE
variable from bl31. It's very common across such projects and Kbuild will actually complain if it believes that you're trying to use a x86 compiler.
The default configuration that you chose (correctly, hopefully) contains a few erroneous values for the USB driver. Normally these would take some time to dig up from the board's / processor's documentation; we took them from the debug prints of the firmware that was pre-configured on the eMMC :p
Open a ncurses-based interface for editing the .config
file:
$ make CROSS_COMPILE=... menuconfig
The interface should be fairly intuitive. Use the Arrow keys to navigate the entries, Space to toggle options on or off, Enter to dive into a submenu or open a prompt, and the ?
key to get more information about the currently selected entry. If you see a letter highlighted in a different color, pressing the corresponding key will take you to that option. Note that multiple options can have the same keybind; pressing it will cycle you through to the next occurrence.
The search function for a specific option (by name) is the exact same as in less or vim: /[CONFIG_]MY_OPTION <Enter>
. This will generate a list of potential matches, each bearing a numeric index. Press the key corresponding to that index in order to jump to the search result.
For now, change the following config variables and save the changes to .config
:
The three files you should obtain are:
You may be wondering what is up with the DTB file. This file contains a description of the hardware available on the board, as well as hints for determining what driver should be responsible for each component. bl33 needs at least a minimal description of the available hardware in order to function. Don't expect that U-Boot's Device Tree Sources (DTS) will contain information about the HDMI interfaces, for example. Since Linux also needs such a file, we will discuss its format and contents more in depth during the next session. If you are curious to take a look, here is how you can convert the DTB (binary format) to DTS (human-readable format):
$ dtc -I dtb -O dts ${YOUR_DTB_FILE} | less