U-Boot/Boot process
This page aims to give an overview of the code that runs when mainline U-Boot gets started on an Allwinner SoC. It helps to understand the boot flow, add support for new SoCs, find the right places to add new code, or to add debug output in case it hangs early.
For now this focuses on 64-bit SoCs, which use a slightly different boot flow from 32-bit SoCs.
General overview
Mainline U-Boot for Allwinner SoCs consists of two parts: the SPL ("secondary program loader", as opposed to the primary loader, which is the BootROM), and the main U-Boot part, called "U-Boot proper".
The reason for this split is that the BootROM can only load code into the small SRAM memories on the chip, and this in not nearly enough to hold a full U-Boot image. So the SPL's main task is to initialise the DRAM, then load U-Boot proper into there, since this has plenty of space. On top of loading the remaining U-Boot code, the SPL can also load other components, namely the DTB, the secure runtime firmware (TF-A), and potentially a management processor firmware like crust.
Conceptually the SPL uses the same code as the rest of the U-Boot, but its image is more selectively compiled, and with different configuration options to drastically limit the image size. This means it just contains the drivers it will need for loading the other images, and those drivers are potentially compiled in a cut-down or restricted version, to keep the image size down.
AArch64 boot flow
crossed out lines show generic code that is never used by sunxi
#include <boot.h> (arch/arm/include/asm/arch-sunxi/boot0.h)
| ||
---|---|---|
32/64 bit deflector (0xea00001f: tst x0, x0 vs. b #0x84 )
| ||
AArch32 (SPL initially) | AArch64 (U-Boot proper) | |
save FEL state | branch to reset: label (below) | |
load RVBAR registers with start address | ||
do RMR to switch to 64-bit, start at reset: | ||
(embedded image information data, branched over) | ||
reset: b save_boot_params (no bl here, to avoid clobbering LR)
| ||
save_boot_params: b save_boot_params_ret (returns immediately, not used for sunxi)
| ||
load exception vector address (only U-Boot proper) | ||
determine current exception level | ||
EL3 (SPL) | EL2 (proper) | EL1 (not used) |
(set VBAR_EL3) | Route SErrors to EL2 | set VBAR_EL1 |
mask interrupts, set NS bit | set VBAR_EL2 | Enable FP/SIMD |
enable FP/SIMD for EL2 | Enable FP/SIMD for EL1 | |
Unmask SError interrupts | ||
initialise CNTFRQ (SPL/EL3 only) | ||
apply ARM core specific erratas | ||
b lowlevel_init
| ||
force use of SP_ELx | ||
b _main (in arch/arm/lib/crt0_64.S)
|
set up initial stack pointer (from CONFIG_SPL_STACK )
| ||
call board_init_f_alloc_reserve (in common/init/board_init.c)
| ||
---|---|---|
subtract early malloc area (SYS_MALLOC_F_LEN == 8KB)
| ||
subtract space for global_data (~416 bytes)
| ||
re-set stack pointer to grow down from here | ||
set up gd_ptr (in fixed register x18) to use space up from here | ||
call board_init_f_init_reserve (in common/init/board_init.c)
| ||
clear global_data struct
| ||
set malloc base to point right behind global_data
| ||
debug_uart_init | ||
call board_init_f in ...
| ||
SPL: arch/arm/mach-sunxi/board.c | U-Boot proper: common/board_f.c | |
sunxi SPL specific initialisation (see below) | call every function in init_sequence_f[] array
| |
SPL | U-Boot proper | |
call spl_relocate_stack_gd() |
switch to final stack and GD location | |
relocate image (to end of DRAM) | ||
call c_runtime_cpu_setup()
| ||
clear BSS | ||
branch to board_init_r() in ...
| ||
SPL: common/spl/spl.c | U-Boot proper: common/board_r.c |