AM335x Boot Process (BootRom->MLO->Uboot) In-depth Source Code Analysis
Excellent writing, saving for study.
References:
-
AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical Reference Manual.pdf;
-
am3359.pdf;
1. Where does the AM335x CPU jump to execute after power-on?
Answer:
Chip to U-Boot boot process: ROM → MLO(SPL) → uboot.img
The bootloader in AM335x is divided into 3 parts:
First-stage bootloader: This bootloader automatically executes after the board powers on. It determines the boot method (e.g., NAND, SDcard, UART...) and then jumps to the second-stage bootloader. This code should be stored in the 176KB ROM.


Second-stage bootloader: MLO (SPL), used for hardware initialization: disabling the watchdog, disabling interrupts, setting CPU clock frequency, speed, and other operations. It then jumps to the third-stage bootloader. The MLO file should be mapped to the 64 KB Internal SRAM.

Third-stage bootloader: uboot.img, the entry point for C code.

The first-stage bootloader is hard-coded on the board, while the second and third stages are obtained by compiling U-Boot.


2. What does the second-stage bootloader: MLO (SPL) do?
MLO(SPL) memory distribution is as follows:

SPL Memory Remapping:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
< PATH : /arch/arm/cpu/armv7/omap-common/u-boot-spl``.lds >
MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
LENGTH = CONFIG_SPL_MAX_SIZE }
MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
OUTPUT_FORMAT(``"elf32-littlearm"``, "elf32-littlearm"``, "elf32-littlearm"``)
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
.text :
{
__start = .;
arch``/arm/cpu/armv7/start``.o (.text)
*(.text*)
} >.sram
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
. = ALIGN(4);
.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
. = ALIGN(4);
__image_copy_end = .;
_end = .;
.bss :
{
. = ALIGN(4);
__bss_start = .;
*(.bss*)
. = ALIGN(4);
__bss_end__ = .;
} >.sdram
}
1
2
3
4
5
6
7
<PATH : /include/configs/am335x_evm.h>
#define CONFIG_SPL_TEXT_BASE 0x402F0400
#define CONFIG_SPL_MAX_SIZE (46 * 1024)
#define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK
#define CONFIG_SPL_BSS_START_ADDR 0x80000000
#define CONFIG_SPL_BSS_MAX_SIZE 0x80000 /* 512 KB */ <span style="font-size:16px;color:#003399;"><strong></strong></span>
@1@ Save Boot Parameters bl save_boot_params
1
2
3
4
5
6
7
<PATH : /arch/arm/cpu/armv7/start``.S>
/*
* the actual reset code
*/
reset:
bl save_boot_params
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<PATH : /arch/arm/cpu/armv7/omap-common/lowlevel_init``.S>
.global save_boot_params
save_boot_params:
/*
* See if the rom code passed pointer is valid:
* It is not valid if it is not in non-secure SRAM
* This may happen if you are booting with the help of
* debugger
*/
ldr r2, =NON_SECURE_SRAM_START
cmp r2, r0
bgt 1f
ldr r2, =NON_SECURE_SRAM_END
cmp r2, r0
blt 1f
/*
* store the boot params passed from rom code or saved
* and passed by SPL
*/
cmp r0, #0
beq 1f
ldr r1, =boot_params
str r0, [r1]
1
2
3
4
5
6
7
8
/*《PATH: /arch/arm/include/asm/arch-ti81xx/omap.h》
* Non-secure SRAM Addresses
* Non-secure RAM starts at 0x40300000 for GP devices. But we keep SRAM_BASE
* at 0x40304000(EMU base) so that our code works for both EMU and GP
*/
#define NON_SECURE_SRAM_START 0x40304000
#define NON_SECURE_SRAM_END 0x4030E000
#define LOW_LEVEL_SRAM_STACK 0x4030B7FC
Question: Where are these parameters saved? What kind of parameters are they?
Answer:
These parameters are saved in the 64 KB OCM RAM at the following memory address:


Note: Downloaded Image Area: This area is used to store the MLO (SPL) file, and its maximum size can reach 109 KB.




@a2@ Set CPU to SVC32 Mode
1
2
3
4
5
6
7
8
<PATH : /arch/arm/cpu/armv7/start``.S>
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr,r0
CPSR: Current Program Status Register. It can be accessed in any processor mode. It contains condition flags, interrupt disable bits, current processor mode flags, and other control and status bits. CPSR is used to store condition codes during user-level programming.
SPSR: Saved Program Status Register. Each processor mode has an SPSR, which is used to save the state of the CPSR so that the working state at the time of an exception can be restored upon returning from the exception. When a specific exception occurs, this register is used to store the content of the current program status register. Upon exiting an exception, SPSR can be used to restore CPSR. Since User mode and System mode are not exception modes, they do not have an SPSR. Unpredictable consequences may occur if a user attempts to access SPSR in User mode or System mode.
The CPSR format is shown below. SPSR and CPSR have the same format. 31 30 29