The following examples take the example of Project X projects tiny210 (s5pv210 platform, ARMV7 architecture)
[Uboot] uboot process series :
[Project X] tiny210 (s5pv210) power-on START process (BL0-BL2)
[Project X] tiny210 (s5pv210) load code from storage device to DDR
[Uboot] (chapter I) uboot process--Overview
[Uboot] (chapter II) uboot process--UBOOT-SPL compilation process
[Uboot] (chapter III) uboot process--UBOOT-SPL code flow
[Uboot] (fourth chapter) Uboot process--uboot compilation process
[Uboot] (Foreign article) Global_data Introduction
[Uboot] (foreign article) uboot Relocation Introduction
It is recommended that you look at the [Project X] tiny210 (s5pv210) power-up process (BL0-BL2) to see the BL0\BL1\BL2 phase after power-up, as well as the operating position and function of each stage.
suggestions can be and "[Uboot] (Foreign article) Global_data Introduction" and "[Uboot] (chapter) Uboot Relocation Introduction" together look.
================================================================================= One, uboot description 1, The things that uboot to do
the state at which the CPU was initially just power up. You need to be careful to set up a lot of states, including CPU status, interrupt status, MMU state, and so on. Second, it is to be based on hardware resources for board-level initialization, code redirection and so on. Finally, you go to the command line state and wait for the command to be processed.
In the ARMV7 architecture of the uboot, the main need to do the following things
Arch-level initialization shutdown interrupt, Set SVC mode disable MMU, TLB key register settings, including clock, watchdog register
The board-level initialization of the stack environment is preceded by the initialization of the board level before the code redirection, including serial ports, timers, environment variables, I2C\SPI, and so on, for board level initialization after code redirection code redirection, including initialization operations defined in board-level code, EMMC, NAND flash, network, Initialization of interrupts and so on. Enter command line status, wait for terminal input command and handle command
The above work is the core of the uboot process. 2. Questions
Although it has been stated in the previous article that the arch level has been initialized in the SPL phase, why should the arch be initialized again in the Uboot?
Answer: SPL is not required to start uboot, and in some cases uboot may start executing on ROM or flash without using SPL. These are all dependent on the platform's startup mechanism. Therefore Uboot does not consider whether SPL has initialized the arch, and Uboot will do a complete initialization of the operation to ensure that the CPU is in the required state.
And SPL in the startup process where the difference.
Answer: To tiny210, the initial process of the early arch is basically the same, and the essential difference is the beginning of board_init_f. The board_init_f of SPL is implemented by board itself, such as tiny210 in BOARD/SAMSUNG/TINY210/BOARD.C. It mainly implements the replication Uboot to the DDR, and jumps to the corresponding position of the uboot. The general SPL can do its job here. The board_init_f of Uboot is implemented under common, and its main implementation is uboot relocate pre-board initialization and relocate regional planning, which also needs to go down other initialization processes. 3. Code Entry
Project-x/u-boot/arch/arm/cpu/u-boot.lds
ENTRY (_start)
So the UBOOT-SPL code entry function is _start
Corresponds to Path project-x/u-boot/arch/arm/lib/vector. The _start of S, followed by the analysis from this function. second, the whole process of code 1, first look at the main branch of the process (including the arch level of initialization)
Initialization at arch level is exactly the same as SPL
_start ——— –>reset ———— –> off interrupt
......................... ... |
.... ———->cpu_init_cp15 ——— –> Close Mmu,tlb--------------------
......................... ... |
.... ———->cpu_init_crit ————->lowlevel_init ————-> configuration and initialization of key registers for the main register, and .....???????????.
......................... ... |
_main ———— –>board_init_f_alloc_reserve ————— > Stacks, GD, early malloc space allocation
....... |
... ————->board_init_f_init_reserve ————— > Stack, GD, and early malloc space initialization for.
....... |
.... ————->board_init_f ————— Board-level initialization and relocate area planning before the relocate of the >uboot
....... |
.... ————->relocate_code, relocate_vectors ————— > Redirection of Uboot and exception interrupt vectors table.)
....... |
... ————-> emptying of the old stack,.
....... |
... ————->board_init_r ————— The board-level initialization after the >uboot relocate
....... |
... ————->run_main_loop ————— > Enter command line status, waiting for terminal input commands and processing of commands Iii. Arch Initialization Code Analysis 1, _start
The above has shown that _start is the entrance to the entire uboot, and its code is as follows:
Arch/arm/lib/vector. S
_start:
#ifdef config_sys_dv_nor_boot_cfg
. Word config_sys_dv_nor_boot_cfg
#endif
b Reset
Will jump to reset. 2. Reset
It is recommended that you refer to [kernel startup process] (chapter II) phase one-setting up an SVC, shutting down interrupts, and understanding why you should set up an SVC, shut down interrupts, and how to do this.
The
Code is as follows:
Arch/arm/cpu/armv7/start. S
globl reset. globl save_boot_params_ret Reset:/* Allow the board to save Importa NT Registers */b save_boot_params Save_boot_params_ret:/* * Disable interrupts (FIQ and IRQ), also set th E CPU to SVC32 mode, * except if in HYP mode already */Mrs R0, CPSR and R1, R0, #0x1f @ Mask mode Bits TEQ r1, #0x1a @ test for HYP mode Bicne r0, r0, #0x1f @ Clear all mode bits Orrne r0, R0 , #0x13 @ Set svc mode Orr r0, r0, #0xc0 @ disable FIQ and IRQ msr cpsr,r0 @@ 以上 by setting the CPU to the SVC module in the CPSR register
Type, prohibit interrupt @@ 具体 operation can refer to the [kernel Start process] (chapter II) Phase one--Setup SVC, shutdown interrupt analysis/* The Mask ROM code should has a PLL and others stable *
#ifndef config_skip_lowlevel_init bl cpu_init_cp15 @@ 调用 cpu_init_cp15, initializes the coprocessor CP15, and disables the MMU and TLB. @@ 后面 will be a section behind the analysis BL Cpu_init_crit @@ 后面 Cpu_init_crit, perform some key initialization actions, that is, platform level and board level initialization @@ 后面 will be a section after analysis #endif bl _main @ @ Jump to the main function, which is the board-level initialization function @@ 下 the next section.
3, Cpu_init_cp15
It is recommended to refer to [kernel START process] (sixth chapter) phase one-open the analysis of two articles of the MMU.
The CPU_INIT_CP15 is primarily used to initialize the CP15 coprocessor, whose main purpose is to close its MMU and TLB.
The code is as follows (minus the irrelevant part of the code):
Arch/arm/cpu/armv7/start. S
ENTRY (CPU_INIT_CP15)/* * Invalidate L1 i/d */mov r0, #0 @ set up for MCR MCR P15, 0, R0, C8, C7, 0 @ invalidate tlbs mcr P15, 0, R0, C7, C5, 0 @ invalidate Icache mcr P15, 0, R0, C7, C5, 6 @ Invali Date BP array mcr p15, 0, R0, C7, C10, 4 @ DSB MCR P15, 0, R0, C7, C5, 4 @ ISB @@ 这里 only need to know is a partial deposit to the CP15 processor
can be cleared 0. @@ 将 be coprocessor c7\c8 clear 0 and so on, the meaning of each register refer to "arm's CP15 coprocessor Register"/* * Disable MMU stuff and caches */MRC P15, 0, R0, c 1, c0, 0 Bic r0, r0, #0x00002000 @ clear bits (--v-) Bic r0, R0, #0x00000007 @ clear bits 2:0 (-cam) Orr R0 , R0, #0x00000002 @ set bit 1 (--a-) Align Orr r0, R0, #0x00000800 @ set bit one (Z---) BTB #ifdef config_sys_icache_of
F Bic r0, R0, #0x00001000 @ clear bit (i) I-cache #else Orr r0, R0, #0x00001000 @ set bit (i) I-cache #endif
MCR P15, 0, R0, C1, C0, 0 @@ 通过 The introduction of the above article, we can know CP15 C1 Register is the MMU controller @@ 通过 above for some bits of the MMU to clear 0 and set position, to close the MMU and cache purposes, specific words to see the above article. Endproc (Cpu_iniT_CP15)
4, Cpu_init_crit
Cpu_init_crit, perform initialization of some key registers. Its code core is Lowlevel_init, as follows
Arch/arm/cpu/armv7/start. S
ENTRY (Cpu_init_crit)
/
* * Jump to board specific initialization ...
* The Mask ROM would have already initialized
* basic memory. Go to bump up clock rate and handle
* wake up conditions.
* /b lowlevel_init @ Go setup pll,mux,memory
endproc (Cpu_init_crit)
So Lowlevel_init is the core of this function.
Lowlevel_init is generally implemented by the board level code itself. But for some platforms, you can also use the generic lowlevel_init, which is defined in Arch/arm/cpu/lowlevel_init. S Medium
Take tiny210 as an example, in the process of porting tiny210, you need to create lowlevel_init under board/samsung/tiny210, which is the board level directory. S, implements the Lowlevel_init internally. (In fact, as long as the implementation of the lowlevel_init is good, there is no need to say where is the implementation, but usually the specification is created Lowlevel_init.) s to specifically implement the Lowlevel_init function).
In Lowlevel_init, we want to implement the following: Check for some reset state shutdown of the watchdog system clock initialization memory, DDR initialization of serial port initialization (optional) Nand Flash initialization
The following is an example of the lowlevel_init of tiny210 (this shows that when porting tiny210, it is the lowlevel_init of Kangear directly. s file for use)
This part of the code and platform is very relevant, a brief introduction can be
Board/samsung/tiny210/lowlevel_init. S
Lowlevel_init:push {LR}/* Check reset status */LDR R0, = (elfin_clock_power_base+rst_stat_offset) LDR R1, [r0] Bic R1, R1, #0xfff6ffff CMP R1, #0x10000 beq wakeup_reset_pre cmp R1, #0x80000 beq Wakeup
_reset_from_didle @@ 读取 The value of the Reset status register 0xe010_a000 to determine the reset state.
/* IO Retention Release */LDR R0, = (elfin_clock_power_base + others_offset) ldr R1, [r0] Ldr R2, =io_ret_rel
Orr R1, R1, R2 str R1, [r0] @@ 读取 The value of the mixed status register e010_e000, places some bits in it, resets it to some wakeup position 1, and I don't understand. /* Disable Watchdog */LDR R0, =elfin_watchdog_base/* 0xe2700000 */mov r1, #0 str R1, [r0] @@ 关闭 watchdog @@ 关闭
Part of the code for the external srom operation is ignored/* when we already the run in RAM, we don't need to relocate u-boot.
* and actually, memory controller must be configured before U-boot * are running in RAM. */LDR R0, =0x00ffffff Bic r1, PC, R0/* r0 <-Current Base addr of code */LDR R2, _text_base/* R1 <-original base addr in RAM*/BIC R2, R2, r0/* r0 <-Current Base addr of code */CMP r1, R2/* Compare R0, R1 */BEQ 1f/* R0 = = R1 then skip SDRAM init */@@ 判断 If it is already running on SDRAM, and if so, skip the following two to DDR initialization Step @@ 判断 Determine the method as follows: @@ 判断, get the address of the current PC pointer, shielding its low 24bit, storage and R1 @@ 判断, get _text_base (config_sys_text_base) address, that is, Uboot code snippet link address, Subsequent in the Uboot article will explain, and shield its low 24bit @@ 3, if equal, skip the DDR initialization part/* INIT system clock */BL System_clock_init @@ 3 The systems clock, subsequent time Look again at how to configure the/* Memory Initialize */BL mem_ctrl_asm_init @@ 重点 Note: Here to initialize the DDR ...
A follow-up will write an article explaining how the s5pv210 platform initializes the DDR.
@@ 其实 fact, in the TINY210 project, the DDR has been initialized in the SPL, and here is re-initialized again, from the actual test results, it does not affect the normal use.
1:/* for UART */BL uart_asm_init @@ 串口 Port initialization, here the serial port will print out an ' O ' character, followed by writing characters to the Utxh_offset register, you can output the corresponding characters on the serial port. BL tzpc_init #if defined (config_nand)/* Simple init for NAND * * BL nand_asm_init @@ 简单 initialize NAND Flash, possibly BL2 image
It's on NAND flash. #endif/* Print ' K ' */LDR r0, =elfin_uart_console_base ldr R1, =0x4b4b4b4b str R1, [R0, #UTXH_OFFSET] @@ 再 serial port to print the ' K ' character, indicating that the Lowlevel_init has completed pop {pc} @@ 再 pc Pointer, that is, return.
When the ' OK ' character is printed in the string, it indicates that Lowlevel_init has completed execution. Three, board level initialization code Analysis 1, _main
The entrance to the board-level initialization code is _main. Start the analysis here.
suggestions can be and "[Uboot] (Foreign article) Global_data Introduction" and "[Uboot] (chapter) Uboot Relocation Introduction" together look.
Code below, removing extraneous code parts
Arch/arm/lib/crt0. S
ENTRY (_main)/* * Set up initial C runtime environment and call Board_init_f (0).
*/Ldr SP, = (config_sys_init_sp_addr) Bic sp, SP, #7/* 8-byte alignment for ABI compliance */MOV r0, SP BL Board_init_f_alloc_reserve mov sp, r0/* Set up GD here, outside any C code */mov r9, r0 bl Board_ Init_f_init_reserve @@ 以上 is the stack, GD, early malloc space allocation, specific reference "[Uboot] (chapter) global_data Introduction" mov r0, #0 bl board_init_f @@ Uboot relocate before the board level initialization and relocate regional planning, the following subsections continue to explain @@ 其中 Regional planning can also refer to the "[Uboot] (chapter) Uboot Relocation Introduction"/* Set up int Ermediate Environment (new SP and GD) and call * Relocate_code (Addr_moni).
Trick Here's that we'll return * ' here ' but relocated. */Ldr SP, [R9, #GD_START_ADDR_SP]/* SP = gd->start_addr_sp */Bic SP, SP, #7/* 8-byte alignment for ABI Co
Mpliance */Ldr R9, [R9, #GD_BD]/* R9 = GD->BD */Sub R9, R9, #GD_SIZE/* New GD is below BD */ ADR LR, here LDR r0, [R9, #GD_RELOC_OFF] /* R0 = Gd->reloc_off */add LR, LR, R0 ldr r0, [R9, #GD_RELOCADDR]/* r0 = gd->relocaddr */b Relocate_code here:/* * now relocate vectors */bl relocate_vectors @@ GD, uboot, abnormal interrupt vector table relocate, can refer to the [Uboot] (external Uboot Relocation Introduction ", here is not detailed description/* Set up final (FULL) environment */BL c_runtime_cpu_setup/* We still call old Routi NE here */@@ 通过 operating the coprocessor's C7 register to close Icache LDR r0, =__bss_start/* This is auto-relocated! */LDR R3, =__bss_end/* This is auto-relocated! */MOV r1, #0x00000000/* Prepare zero to clear BSS */Subs R2, R3, r0/* r2 = memset len */bl M Emset @@ 因为 The stack segment has been relocate, so here need to empty the contents of the original stack segment bl coloured_led_init bl red_led_on @@ 因为 Light initialization, can not be realized, if you want to implement, can be in board
Re-implement a function definition. /* Call Board_init_r (gd_t *id, ULONG dest_addr) */mov r0, r9/* gd_t */LDR R1, [R9, #GD_REL OCADDR]/* DEST_ADDR */* Call Board_init_r */LDR PC, =board_init_r/* This is Auto-relocated! */* We should not return here.
*/@@ Uboot relocate after the board-level initialization, note that the uboot must be done here to complete the work, or in the inside to achieve a dead loop, should not be returned. Endproc (_main)
Through the above, there are two very important initialization functions, board_init_f and Board_init_r, which follow-up continue to illustrate. 2, Board_init_f
The code is as follows:
Common/board_f.c
void Board_init_f (ULONG boot_flags)
{
gd->flags = boot_flags;
Gd->have_console = 0;
Set some of the global_data inside the flag bit
if (initcall_run_list (init_sequence_f)) Hang
();
Call Initcall_run_list to execute the function in the Init_sequence_f function array, Initcall_run_list here.
//Once the Init_sequence_f function goes wrong, Causes Initcall_run_list to return a non-0, and from the card off
}
After opening the debug macro, you can observe which init functions are called through log, as in log:
Uboot Log has the following log:
initcall:23e005a4
According to U-boot.map can be found corresponding
. Text.print_cpuinfo
0x23e005a4 0x8 arch/arm/cpu/armv7/built-in.o
0x23e005a4 print_cpuinfo
means Print_cpuinfo was called by Initcall.
so the core of board-level initialization before uboot relocate is the function defined in Init_sequence_f.
As below, just do a simple explanation, when needed to analyze the specific:
Static init_fnc_t init_sequence_f[] = {Setup_mon_len,//calculates the length of the entire image Gd->mon_len Initf_malloc,//early malloc memory Pool settings Initf_console_record,//console log cache Arch_cpu_init,/* Basic Arch CPU Dependent Setup *//CPU some special Initialize INITF_DM, ARCH_CPU_INIT_DM, mark_bootstage,/* need timer, go after init DM */* todo:can any of This go to Arch_cpu_init ()? */env_init,/* Initialize environment *//initialization of the environment variable, followed by a special study of the contents of the environment variable init_baud_rate,/* Initialze BA Udrate settings *///Baud rate initialization serial_init,/* Serial communications Setup *///serial port initialization Console_init_f, /* Stage 1 init of console *//console initialization Print_cpuinfo,/* Display CPU info (and speed) *//print CPU information in IT_FUNC_I2C, INIT_FUNC_SPI,//I²c and SPI initialization dram_init,/* Configure available RAM banks *///DDR initialization, most importantly DD R RAM Size setting .... Gd->ram_size//If Uboot is running in ROM, Flash, then the DDR must be initialized//======================================== setup_dest_addr, reserve_round_4k, Reserve_trace, Setup_machine, Reserve_global_data, Reser VE_FDT, Reserve_arch, reserve_stacks,//= = above is the relocate area of the planning, specific reference "[Uboot] (chapter) Uboot Relocation Introduction" Setup_dra M_config, Show_dram_config, display_new_sp, RELOC_FDT, Setup_reloc,//relocation after the setting of some members of GD NULL,};
Note that the above function must be guaranteed to return a value of 0 correctly, otherwise it will cause hang. 3, Board_init_r
The code is as follows:
Common/board_r.c
void Board_init_r (gd_t *new_gd, ulong dest_addr)
{
if (initcall_run_list (init_sequence_r)) Hang
();
Call Initcall_run_list to execute the function in the Init_sequence_r function array, Initcall_run_list here.
//Once the Init_sequence_r function goes wrong, Results in a initcall_run_list return of not 0, and from the card off
/Notreached-run_main_loop () does not return *
/Hang ();
Uboot requires that all work be terminated in this function, or into a dead loop, and once the attempt is made to return, hang directly.
}
so the core of board-level initialization before uboot relocate is the function defined in Init_sequence_r.
As below, just do a simple explanation, when needed to analyze the specific:
Common/board_r.c
init_fnc_t init_sequence_r[] = {initr_trace,//trace related initialization initr_reloc,//GD settings for relocate identity Initr_reloc _global_data,///relocate, some of the members in GD reset Initr_malloc,//malloc memory pool settings Initr_console_record, Bootstage_reloca Te, initr_bootstage, #if defined (config_arm) | | Defined (CONFIG_NDS32) board_init,/* Setup chipselects *///board level own special initialization functions, as defined in BOARD/SAMSUNG/TINY210/BOARD.C Board_ Init This function #endif stdio_init_tables, initr_serial,//serial port initialization initr_announce,//print log initr_logbuff for Uboot run location Er,//logbuffer initialization power_init_board, #ifdef Config_cmd_nand Initr_nand,//If NAND flash is used, the NAND will need to be initialized #endi F #ifdef CONFIG_GENERIC_MMC Initr_mmc,//If using EMMC, then the NAND is required to initialize #endif initr_env,//Initialize environment variables Initr_seconda RY_CPU, Stdio_add_devices, initr_jumptable, Console_init_r,/* Fully init console as a device */Inter Rupt_init,//Initialize interrupt #if defined (config_arm) | | Defined (CONFIG_AVR32) initr_enable_interrupts,//enable interrupt #endif Run_main_loop,//Enter a dead loop and process terminal commands inside the dead loop. };
Eventually, Uboot runs to Run_main_loop, and the Run_main_loop enters the command line state, waiting for the terminal to enter commands and to process the commands.
Here, the uboot process is complete, and the follow-up will specifically explain how Uboot's run_main_loop works.