x-boot (external boot code) serves as the first-stage boot-loader, residing in storage devices such as eMMC, NAND flash, or SD cards. It is loaded into the system SRAM by i-boot, as DRAM is not yet ready during this phase. As it operates in SRAM, its overall size, including code, data, and stack, must not exceed the capacity of the system SRAM. The primary objective of x-boot is to initialize the DDR SDRAM controller and PHY, conduct calibration on the PHY and signals, and once calibrated, make the DRAM ready for use.
Subsequently, x-boot loads the images of TF-A (BL31), OP-TEE (BL32), and U-Boot (BL33) from a storage device into DRAM. The CPU (core 0) then switches itself from 32-bit mode to 64-bit by triggering a software reset. It proceeds to awaken other cores (core 1, 2, 3) and transitions them to 64-bit mode. Finally, all cores execute TF-A.
Contents
Features
Output log at UART0 (set at 115,200 bps by i-boot).
Support loading firmware of DDR3, DDR4, or LPDDR4 from boot devices.
Support initialization of DDR controller and PHY.
Support 1D and 2D training of PHY and signals for DDR3, DDR4, and LPDDR4 SDRAM.
Support loading images of TF-A (BL31), OP-TEE (BL32), and U-Boot (BL33) from boot devices.
Support secure boot:
Verify digital signature of fip (including TF-A and OP-TEE) and U-Boot images.
Decrypt fip image.
Support warm-boot:
Switch CA55 to 64-bit mode and jump to run TF-A.
Support reading and writing OTP bits using Sunplus OTPTool through UART0.
Flow
The x-boot initiation begins with the "_start" subroutine, written in assembly code, responsible for initializing the C execution environment. The process then proceeds to execute the "xboot_main" subroutine, which serves as the main C function within x-boot.
The "xboot_main()" subroutine begins with the "init_cdata" subroutine for initializing C global data. It is followed by the "init_uart()" subroutine to initialize all UARTs and the "init_hw()" subroutine for hardware initialization. Finally, the sequence progresses to run the "boot_flow()" subroutine.
The "boot_flow()" subroutine starts by initializing the DDR SDRAM controller and PHY, followed by PHY training. It then initializes the controller of the boot device, which is recorded in the C structure g_bootinfo. Subsequently, it loads the fip (firmware image package) image and U-Boot image from the respective partitions within the boot device, storing them in DRAM. Finally, the process advances to execute the "boot_uboot()" subroutine.
The "boot_uboot()" subroutine begins by verifying the images of fip and U-Boot. Upon successful verification, it moves the TF-A and OP-TEE images from the load position to the dedicated location in DRAM. Subsequently, it executes the “go_a32_to_a64()” subroutine.
In the “go_a32_to_a64()” subroutine, it configures the CPU reset vector to the entry-point of the a64up module for all cores and triggers a warm-reset to switch itself (core 0) to 64-bit (aarch64) mode.
After the warm-reset, CPU core 0 operates in the a64up module at 64-bit mode. It then wakes up cores 1, 2, and 3, switching them to 64-bit (aarch64) mode by triggering a warm-reset (in i-boot). Following the warm-reset, cores 1, 2, and 3 operate in the a64up mode at 64-bit mode. Subsequently, all cores make a jump to TF-A (BL31).
The flow chart below illustrates the process from i-boot's reset vector to the jump to TF-A for all cores
Drivers locations and features
x-boot supports many device drivers for accessing devices. The following table shows the locations of drivers in project diretory boot/xboot/ and features of each driver.
Drivers | Folders | Features |
8-bit NAND | nand/ |
|
ADC | adc/ | |
eMMC | sdmmc/ |
|
I2C driver | i2c/ |
|
NVMEN (OTP) | otp/ |
|
SD card | sdmmc/ |
|
SPI-NAND | nand/ |
|
USB2.0 Host | usb/ |
|
USB3.0 Host | usb/ |
|
Other files
The following table shows the locations of important forlders or files of x-boot in project diretory boot/xboot/.
Type | Folders | Files | |
machine | arch/arm/sp7350/ | a64up/ | |
aboot.S | |||
boot.ld | |||
cache.c | |||
cpu/ | |||
include/ | |||
page_table/ | |||
start.S | |||
default config files | configs/ | sp7350_emmc_ev_defconfig | |
sp7350_sdcard_ev_defconfig |
All defconfig files are placed at configs/. Normally, the file name proceed with sp7350- and followed by defconfig, like sp7350_emmc_ev_defconfig, sp7350_sdcard_ev_defconfig, and etc.
SRAM Space Allocation
To facilitate program maintenance and data sharing, x-boot and i-boot utilize the same SRAM segment division and structure. Figure 4.2 illustrates the segmentation of SRAM into 9 segments, ranging from low to high addresses: xboot_buf, bootinfo, boothead, a64up, cdata, storage_buf, stack, bootcompat, and spacc_ram.
Below are explanations of each segment's purpose:
xboot_buf: x-boot program segment, where the x-boot program is loaded and executed.
bootinfo: bootinfo segment containing the g_bootinfo structure, which records boot-related information.
boothead: boothead segment holding the g_boothead array, used to store GPT data for eMMC or header data for NAND flash.
a64up: a64up segment where the a64up program resides, responsible for transitioning the CPU from 32-bit mode to 64-bit mode.
cdata: C data segment containing global variables or static variables in C.
storage_buf: Device driver data segment for boot devices such as eMMC and NAND flash. Different boot device drivers share the same space here during a single boot, as only one boot device driver is utilized per boot.
mmu_pgtbl: Page table of MMU.
stack: Stack segment where the stack for C is located.
bootcomp: CPU run control data.
reserved: warm-boot reteion data
During system boot, i-boot reads boot-related information from the boot switch and the OTP (One-Time Programmable) memory within the C chip. This information is then stored in the g_bootinfo structure. Consequently, the data in the g_bootinfo structure determines the i-boot boot mode and the subsequent boot process. x-boot directly utilizes the data in the g_bootinfo structure to determine the boot mode and process.