From the analysis in the previous chapter, Uboot has been copied from the SD card or Flash to 0x42c0_0000 memory and starts executing from here.
For convenience, the following will represent the root directory location of the Uboot source as/uboot-root.
First of all, find/uboot-root/u-boot.lds, this is the Uboot compile-time link file, open after focus on the following content:
ENTRY (_stext)
SECTIONS
{
. = 0x00000000;
. = ALIGN (4);
. Text:
{
* (. __image_copy_start)
arch/arm/cpu/slsiap/s5p4418/start.o (. text*)
* (. text*)
}
... #以下内容省略.
}
From the above content can be seen two information, one is the code from the _stext tag start execution, the second is that the tag is located in/uboot-root/arch/arm/cpu/slsiap/s5p4418/start. S
Open/uboot-root/arch/arm/cpu/slsiap/s5p4418/start. S and find the _stext tag. The code looks like this:
. globl _stext
_stext:
b reset
Ldr pc, _undefined_instruction
Ldr pc, _ Software_interrupt
Ldr pc, _prefetch_abort ldr pc, _data_abort
ldr pc, _not_used
Ldr pc, _irq
LDR pc, _fiq
This is s5p4418 's Exception handlers Vectors. This is provided by the chip, you can refer to the s5p4418 User manual instructions. According to the law of execution, the CPU will perform the b reset instruction first, and jump to the Reset tab to continue execution. The label is in line 78th of the same file. Starting from here is where Uboot formally began to work.
The first step is to set the CPU to SVC32 mode.
. globl Reset
Reset:
bl save_boot_params
/
* * Set the CPU to SVC32 mode
*/
Mrs R0, CPSR
Bic r0, R0, #0x1f
Orr r0, R0, #0xd3
msr cpsr,r0
The specific settings are related to the registers involved, and the CPU cores, where you can search the arm website for cortex-a9 kernel-related user manuals. You will then encounter a piece of code like this:
#ifndef config_skip_lowlevel_init
bl cpu_init_cp15
bl cpu_init_crit
#endif
Whether this code is executed depends on the definition of the CONFIG_SKIP_LOWLEVEL_INIT macro. Typically, macros for these selective switches are defined in/uboot-root/include/configs/xxx.h. Find/uboot-root/include/configs/s5p4418_nanopi2.h here. Found in this header file does not define CONFIG_SKIP_LOWLEVEL_INIT this macro, that this code is to be executed.
The first is to execute the BL CPU_INIT_CP15 this statement. Because the system stack is not initialized at this time, the call return address can only be logged by the LR register. Therefore, the contents of the current relevant register are recorded first:
LR = & (bl cpu_init_cp15) @/uboot-root/arch/arm/cpu/slsiap/s5p4418/start. S
The label CPU_INIT_CP15 the NO. 207 line in the same file. According to the comments can be seen here the main completion of two things, one is to let the first level of Icache and Dcache failure, the second is to disable the MMU and caches. After both tasks are completed, the contents of the LR register are returned. The next step is to execute the BL Cpu_init_crit statement. Also, record the contents of the current relevant register:
LR = & (bl cpu_init_crit) @/uboot-root/arch/arm/cpu/slsiap/s5p4418/start. S
The code for Cpu_init_crit is as follows:
#ifndef config_skip_lowlevel_init
/************************************************************************ * * * *
cpu_init_critical Registers
* *
Setup Important Registers
* Setup Memory Timing * *
* /
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)
#endif
As you can see from the code, the Cpu_init_crit tag only calls the Lowlevel_init tag. Because the b jump command is used, the value of the LR register does not change, thus jumping directly to the lowlevel_init tag. The label is located in/uboot-root/arch/arm/cpu/slsiap/s5p4418/low_init. S in. There are 4 main things done in this process, since these 4 things are CPU-related, and therefore not within the scope of the Uboot analysis, some of the code is omitted:
#ifndef config_skip_lowlevel_init/
*
******************************************************************
*
* cpu_init_critical
*
***************************************************************
*
/. Globl lowlevel_init
lowlevel_init:/
* Get CPU ID */
...
/* Secure SCU invalidate */
...
/* Join SMP */
...
/* Enable maintenance Broadcast */
...
mov pc, LR @ back to caller
#endif/* config_skip_lowlevel_init */
The last sentence of the procedure is to return based on the LR register. So uboot returns to the address of LR to continue execution. Back to/uboot-root/arch/arm/cpu/slsiap/s5p4418/start. S of 94 lines, the following statement appears:
#ifdef Config_reloc_to_text_base
Because macro config_reloc_to_text_base is already defined in/uboot-root/include/configs/s5p4418_nanopi2.h, the statements that are included by the macro are executed. The first is this piece of code:
Relocate_to_text:
/
* * Relocate U-boot code on memory to the text base
* for Nexell arm core (add by Jhkim) */
ADR r0, _stext/ * R0 <-Current position of code */
LDR R1, text_base/ * Test if we run From Flash or RAM */
CMP r0, r1/ * don ' t reloc during debug */
beq CLEAR_BSS
ldr R2, _bss_st Art_ofs
Add R2, r0, R2/ * R2 <-Source End Address */
This code is used to determine whether the current location of the run is on RAM. The ADR R0 in the code, _stext this statement is used to get the real address where the current _stext tag is located. Then use LDR R1, text_base to get the address of the target run. After searching, text_base this tag on line 50th of the same file:
. Globl text_base
text_base:
. Word config_sys_text_base
As you can see, the value of text_base is determined by the macro config_sys_text_base. The macro is also defined in/uboot-root/include/configs/s5p4418_nanopi2.h with a value of 0x42c0_0000. In the first chapter, when the power-up is analyzed, the uboot is copied to the 0x42c0_0000 address and executed from the _stext tag. Therefore, the _stext is the same as the value of text_base, that is, UBoot is already running on RAM. Depending on the program flow, Uboot will continue to execute the content on the CLEAR_BSS label. The following is the tag's code:
CLEAR_BSS:
ldr r0, _bss_start_ofs
ldr R1, _bss_end_ofs
ldr R4, text_base/ * TEXT addr */
add r0, R0, R4
add r1, r1, R4
mov R2, #0x00000000/ * Clear */
CLBSS_L:STR R2, [r0]/ * Clear loop ... */
add r0, R0, #4
cmp r0, R1
bne clbss_l
As can be seen from the code, this part of the function is to use 0 to fill the BSS section of the content. The BSS segment is a variable that holds uninitialized variables, and after this step, all uninitialized variables are initialized to 0. The next step is to execute a code like this:
#ifdef config_mmu_enable
bl mmu_turn_on
#endif
After searching, macro config_mmu_enable is defined in/uboot-root/include/configs/s5p4418_nanopi2.h, so Uboot executes the BL mmu_turn_on directive. Similarly, because of the use of the BL instruction to jump, the value of the relevant register is recorded first:
LR = & (bl mmu_turn_on) @/uboot-root/arch/arm/cpu/slsiap/s5p4418/start. S
The contents of the label are located in/uboot-root/arch/arm/cpu/slsiap/s5p4418/mmu_asm. S, the contents are as follows:
. Globl mmu_turn_on
mmu_turn_on:
ldr sp, = (config_sys_init_sp_addr)
mov r13, lr
bl mmu_on
mov pc, R13 @ back to Caller
This part of the code is prepared to call mmu_on. Since mmu_on is written in C, it is here to construct a running environment for C language, including setting up the system stack and so on. When calling to BL mmu_on, the contents of the relevant registers are as follows:
R13 = & (bl mmu_turn_on) @/uboot-root/arch/arm/cpu/slsiap/s5p4418/start. S
sp = 0x42c0_0000
lr = & (bl mmu_on) @/uboot-root/arch/arm/cpu/slsiap/s5p4418/mmu_asm. S
Here, we can finally explain a problem. That is, according to the chip manual, the starting address of RAM is 0x4000_0000, why Uboot is not copied to the Ram start address, but 0x42c0_0000 here. That is because 0x4000_0000 to 0x42bf_ffff this 44KB has become the uboot of the stack space. So the current content space usage allocation is as follows:
0xc000_0000
UBoot
0x42c0_0000
uboot-stack
0x4000_0000
To the mmu_on, this function is located in/UBOOT-ROOT/ARCH/ARM/CPU/SLSIAP/S5P4418/MMU.C with the following code:
void mmu_on (void)
{
//void *vector_base = (void *) 0xffff0000;
Dcache_disable ();
Arm_init_before_mmu (); /* Flush Dcache *
/* Copy vector table *
///memcpy (vector_base, (void const *) config_sys_text_base, +);
Mmu_page_table_flush (Page_table_start, page_table_size);
Make_page_table ((u32*) ptable); /* Make MMU PAGE TABLE *
/Enable_mmu (Page_table_start);
#if defined (Smp_scu_enabe)
scu_enable ((void __iomem *) mppr_reg);
#endif
}
Because I do not have in-depth research on the MMU, and this part of the code also with the Uboot implementation process has little impact. Therefore, this part of the resolution for the time being omitted, and so on after an in-depth understanding after the supplementary explanation. When the function returns, it will return to/uboot-root/arch/arm/cpu/slsiap/s5p4418/mmu_asm. S continue to execute MOV pc, R13 this one statement, here again returns again. According to the register record, this time return to/uboot-root/arch/arm/cpu/slsiap/s5p4418/start. S, and continues execution from line 134th.
Because of the reason for the space, and then the content is another small phase, so this section is finished first.